aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYu Gu <guyu2876@gmail.com>2022-04-20 21:11:25 +0800
committerYixun Lan <dlan@gentoo.org>2022-04-20 21:22:29 +0800
commit07c4b52e96d933d680ba43f71849bae09abd41f2 (patch)
tree4188501340620bfdf521812e3aa910f741d9127d
parentwww-client/firefox: import ebuild from gentoo's official tree (diff)
downloadriscv-07c4b52e96d933d680ba43f71849bae09abd41f2.tar.gz
riscv-07c4b52e96d933d680ba43f71849bae09abd41f2.tar.bz2
riscv-07c4b52e96d933d680ba43f71849bae09abd41f2.zip
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@gmail.com> Signed-off-by: Yixun Lan <dlan@gentoo.org>
-rw-r--r--www-client/firefox/files/makotokato-riscv64-support-and-zenithal-backported.patch47126
-rw-r--r--www-client/firefox/firefox-98.0.2.ebuild4
2 files changed, 47129 insertions, 1 deletions
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/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":"fbda309934ad8bda689cd4fb5c0ca696fe26dedb493fe9d5a5322c3047d474fd","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":"d059861b4739c9272fa305b6dd91ebeb08530bd0e70a013dd999565d6f06fb30","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":"5eb071dd3719ea305eac21ec20596463f63790f8cd1f908a59e3f9cb0b71b5ad","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/virtualdevices/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":"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":"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":"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":"fbda309934ad8bda689cd4fb5c0ca696fe26dedb493fe9d5a5322c3047d474fd","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":"d059861b4739c9272fa305b6dd91ebeb08530bd0e70a013dd999565d6f06fb30","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":"5eb071dd3719ea305eac21ec20596463f63790f8cd1f908a59e3f9cb0b71b5ad","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/virtualdevices/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":"cc33947cb0810d3edeec7b71686f0231d06c88b4214994605de7f4fd0f6de1a1","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":"cc33947cb0810d3edeec7b71686f0231d06c88b4214994605de7f4fd0f6de1a1","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/impls/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":"2ce4235802aa4e9c96c4e77d9e31d8401ef58dcda4741325184f0764ab1fe393","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":"6fda17f7c2edfcd155314579e83d0fc8a16209e400f1f9a5ca77bd9a799041f2","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":"2cab2e987428522ca601544b516b64b858859730fbd1be0e53c828e82025319d","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":"2cab2e987428522ca601544b516b64b858859730fbd1be0e53c828e82025319d","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/epoll.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":"8a7eacfc172b55763ae32109bf9b252669ba68b72cd5122f7504eb35c0c08345","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":"c663505d6a7a7ae9d76e03fbc17e53d308ea6b1eae92212812e1d76b2bf2916f","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":"84ae63c2baa49eebeabe5bbd347b9c5417e14ba97f342719d753dc1c1c768d60","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":"0219f7bce0603f97d997fb377ca071966c90333ecc665e78a54dfeb97a9c811b","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":"1dc420d3119bf4d863a7ae0ba63efa7f1416f6e46e4100ea161003fe1c3f66ba","test/test_unistd.rs":"0325c998acca1e826e9e2b3d351d55ab9723a6cb2ca2072245978e7f5a9acee8"},"package":"3b2e0b4f3320ed72aaedb9a5ac838690a8047c7b275da22711fddff4f8a14229"}
+\ No newline at end of file
+diff --git a/third_party/rust/nix-0.15.0/CHANGELOG.md b/third_party/rust/nix-0.15.0/CHANGELOG.md
+new file mode 100644
+index 0000000000000..d93a5ce6bbfc9
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/CHANGELOG.md
+@@ -0,0 +1,742 @@
++# Change Log
++
++All notable changes to this project will be documented in this file.
++This project adheres to [Semantic Versioning](http://semver.org/).
++
++## [Unreleased] - ReleaseDate
++### Added
++### Changed
++### Fixed
++### Removed
++
++## [0.15.0] - 10 August 2019
++### Added
++- Added `MSG_WAITALL` to `MsgFlags` in `sys::socket`.
++ ([#1079](https://github.com/nix-rust/nix/pull/1079))
++- Implemented `Clone`, `Copy`, `Debug`, `Eq`, `Hash`, and `PartialEq` for most
++ types that support them. ([#1035](https://github.com/nix-rust/nix/pull/1035))
++- Added `copy_file_range` wrapper
++ ([#1069](https://github.com/nix-rust/nix/pull/1069))
++- Add `mkdirat`.
++ ([#1084](https://github.com/nix-rust/nix/pull/1084))
++- Add `posix_fadvise`.
++ ([#1089](https://github.com/nix-rust/nix/pull/1089))
++- Added `AF_VSOCK` to `AddressFamily`.
++ ([#1091](https://github.com/nix-rust/nix/pull/1091))
++- Add `unlinkat`
++ ([#1058](https://github.com/nix-rust/nix/pull/1058))
++- Add `renameat`.
++ ([#1097](https://github.com/nix-rust/nix/pull/1097))
++
++### Changed
++- Support for `ifaddrs` now present when building for Android.
++ ([#1077](https://github.com/nix-rust/nix/pull/1077))
++- Minimum supported Rust version is now 1.31.0
++ ([#1035](https://github.com/nix-rust/nix/pull/1035))
++ ([#1095](https://github.com/nix-rust/nix/pull/1095))
++- Now functions `statfs()` and `fstatfs()` return result with `Statfs` wrapper
++ ([#928](https://github.com/nix-rust/nix/pull/928))
++
++### Fixed
++- Enabled `sched_yield` for all nix hosts.
++ ([#1090](https://github.com/nix-rust/nix/pull/1090))
++
++### Removed
++
++## [0.14.1] - 2019-06-06
++### Added
++- Macros exported by `nix` may now be imported via `use` on the Rust 2018
++ edition without importing helper macros on Linux targets.
++ ([#1066](https://github.com/nix-rust/nix/pull/1066))
++
++ For example, in Rust 2018, the `ioctl_read_bad!` macro can now be imported
++ without importing the `convert_ioctl_res!` macro.
++
++ ```rust
++ use nix::ioctl_read_bad;
++
++ ioctl_read_bad!(tcgets, libc::TCGETS, libc::termios);
++ ```
++
++### Changed
++- Changed some public types from reexports of libc types like `uint32_t` to the
++ native equivalents like `u32.`
++ ([#1072](https://github.com/nix-rust/nix/pull/1072/commits))
++
++### Fixed
++- Fix the build on Android and Linux/mips with recent versions of libc.
++ ([#1072](https://github.com/nix-rust/nix/pull/1072/commits))
++
++### Removed
++
++## [0.14.0] - 2019-05-21
++### Added
++- Add IP_RECVIF & IP_RECVDSTADDR. Enable IP_PKTINFO and IP6_PKTINFO on netbsd/openbsd.
++ ([#1002](https://github.com/nix-rust/nix/pull/1002))
++- Added `inotify_init1`, `inotify_add_watch` and `inotify_rm_watch` wrappers for
++ Android and Linux. ([#1016](https://github.com/nix-rust/nix/pull/1016))
++- Add `ALG_SET_IV`, `ALG_SET_OP` and `ALG_SET_AEAD_ASSOCLEN` control messages and `AF_ALG`
++ socket types on Linux and Android ([#1031](https://github.com/nix-rust/nix/pull/1031))
++- Add killpg
++ ([#1034](https://github.com/nix-rust/nix/pull/1034))
++- Added ENOTSUP errno support for Linux and Android.
++ ([#969](https://github.com/nix-rust/nix/pull/969))
++- Add several errno constants from OpenBSD 6.2
++ ([#1036](https://github.com/nix-rust/nix/pull/1036))
++- Added `from_std` and `to_std` methods for `sys::socket::IpAddr`
++ ([#1043](https://github.com/nix-rust/nix/pull/1043))
++- Added `nix::unistd:seteuid` and `nix::unistd::setegid` for those platforms that do
++ not support `setresuid` nor `setresgid` respectively.
++ ([#1044](https://github.com/nix-rust/nix/pull/1044))
++- Added a `access` wrapper
++ ([#1045](https://github.com/nix-rust/nix/pull/1045))
++- Add `forkpty`
++ ([#1042](https://github.com/nix-rust/nix/pull/1042))
++- Add `sched_yield`
++ ([#1050](https://github.com/nix-rust/nix/pull/1050))
++
++### Changed
++- `PollFd` event flags renamed to `PollFlags` ([#1024](https://github.com/nix-rust/nix/pull/1024/))
++- `recvmsg` now returns an Iterator over `ControlMessageOwned` objects rather
++ than `ControlMessage` objects. This is sadly not backwards-compatible. Fix
++ code like this:
++ ```rust
++ if let ControlMessage::ScmRights(&fds) = cmsg {
++ ```
++
++ By replacing it with code like this:
++ ```rust
++ if let ControlMessageOwned::ScmRights(fds) = cmsg {
++ ```
++ ([#1020](https://github.com/nix-rust/nix/pull/1020))
++- Replaced `CmsgSpace` with the `cmsg_space` macro.
++ ([#1020](https://github.com/nix-rust/nix/pull/1020))
++
++### Fixed
++- Fixed multiple bugs when using `sendmsg` and `recvmsg` with ancillary control messages
++ ([#1020](https://github.com/nix-rust/nix/pull/1020))
++- Macros exported by `nix` may now be imported via `use` on the Rust 2018
++ edition without importing helper macros for BSD targets.
++ ([#1041](https://github.com/nix-rust/nix/pull/1041))
++
++ For example, in Rust 2018, the `ioctl_read_bad!` macro can now be imported
++ without importing the `convert_ioctl_res!` macro.
++
++ ```rust
++ use nix::ioctl_read_bad;
++
++ ioctl_read_bad!(tcgets, libc::TCGETS, libc::termios);
++ ```
++
++### Removed
++- `Daemon`, `NOTE_REAP`, and `NOTE_EXIT_REPARENTED` are now deprecated on OSX
++ and iOS.
++ ([#1033](https://github.com/nix-rust/nix/pull/1033))
++- `PTRACE_GETREGS`, `PTRACE_SETREGS`, `PTRACE_GETFPREGS`, and
++ `PTRACE_SETFPREGS` have been removed from some platforms where they never
++ should've been defined in the first place.
++ ([#1055](https://github.com/nix-rust/nix/pull/1055))
++
++## [0.13.0] - 2019-01-15
++### Added
++- Added PKTINFO(V4) & V6PKTINFO cmsg support - Android/FreeBSD/iOS/Linux/MacOS.
++ ([#990](https://github.com/nix-rust/nix/pull/990))
++- Added support of CString type in `setsockopt`.
++ ([#972](https://github.com/nix-rust/nix/pull/972))
++- Added option `TCP_CONGESTION` in `setsockopt`.
++ ([#972](https://github.com/nix-rust/nix/pull/972))
++- Added `symlinkat` wrapper.
++ ([#997](https://github.com/nix-rust/nix/pull/997))
++- Added `ptrace::{getregs, setregs}`.
++ ([#1010](https://github.com/nix-rust/nix/pull/1010))
++- Added `nix::sys::signal::signal`.
++ ([#817](https://github.com/nix-rust/nix/pull/817))
++- Added an `mprotect` wrapper.
++ ([#991](https://github.com/nix-rust/nix/pull/991))
++
++### Changed
++### Fixed
++- `lutimes` never worked on OpenBSD as it is not implemented on OpenBSD. It has
++ been removed. ([#1000](https://github.com/nix-rust/nix/pull/1000))
++- `fexecve` never worked on NetBSD or on OpenBSD as it is not implemented on
++ either OS. It has been removed. ([#1000](https://github.com/nix-rust/nix/pull/1000))
++
++### Removed
++
++## [0.12.0] 2018-11-28
++
++### Added
++- Added `FromStr` and `Display` impls for `nix::sys::Signal`
++ ([#884](https://github.com/nix-rust/nix/pull/884))
++- Added a `sync` wrapper.
++ ([#961](https://github.com/nix-rust/nix/pull/961))
++- Added a `sysinfo` wrapper.
++ ([#922](https://github.com/nix-rust/nix/pull/922))
++- Support the `SO_PEERCRED` socket option and the `UnixCredentials` type on all Linux and Android targets.
++ ([#921](https://github.com/nix-rust/nix/pull/921))
++- Added support for `SCM_CREDENTIALS`, allowing to send process credentials over Unix sockets.
++ ([#923](https://github.com/nix-rust/nix/pull/923))
++- Added a `dir` module for reading directories (wraps `fdopendir`, `readdir`, and `rewinddir`).
++ ([#916](https://github.com/nix-rust/nix/pull/916))
++- Added `kmod` module that allows loading and unloading kernel modules on Linux.
++ ([#930](https://github.com/nix-rust/nix/pull/930))
++- Added `futimens` and `utimesat` wrappers ([#944](https://github.com/nix-rust/nix/pull/944)),
++ an `lutimes` wrapper ([#967](https://github.com/nix-rust/nix/pull/967)),
++ and a `utimes` wrapper ([#946](https://github.com/nix-rust/nix/pull/946)).
++- Added `AF_UNSPEC` wrapper to `AddressFamily` ([#948](https://github.com/nix-rust/nix/pull/948))
++- Added the `mode_t` public alias within `sys::stat`.
++ ([#954](https://github.com/nix-rust/nix/pull/954))
++- Added a `truncate` wrapper.
++ ([#956](https://github.com/nix-rust/nix/pull/956))
++- Added a `fchownat` wrapper.
++ ([#955](https://github.com/nix-rust/nix/pull/955))
++- Added support for `ptrace` on BSD operating systems ([#949](https://github.com/nix-rust/nix/pull/949))
++- Added `ptrace` functions for reads and writes to tracee memory and ptrace kill
++ ([#949](https://github.com/nix-rust/nix/pull/949)) ([#958](https://github.com/nix-rust/nix/pull/958))
++- Added a `acct` wrapper module for enabling and disabling process accounting
++ ([#952](https://github.com/nix-rust/nix/pull/952))
++- Added the `time_t` and `suseconds_t` public aliases within `sys::time`.
++ ([#968](https://github.com/nix-rust/nix/pull/968))
++- Added `unistd::execvpe` for Haiku, Linux and OpenBSD
++ ([#975](https://github.com/nix-rust/nix/pull/975))
++- Added `Error::as_errno`.
++ ([#977](https://github.com/nix-rust/nix/pull/977))
++
++### Changed
++- Increased required Rust version to 1.24.1
++ ([#900](https://github.com/nix-rust/nix/pull/900))
++ ([#966](https://github.com/nix-rust/nix/pull/966))
++
++### Fixed
++- Made `preadv` take immutable slice of IoVec.
++ ([#914](https://github.com/nix-rust/nix/pull/914))
++- Fixed passing multiple file descriptors over Unix Sockets.
++ ([#918](https://github.com/nix-rust/nix/pull/918))
++
++### Removed
++
++## [0.11.0] 2018-06-01
++
++### Added
++- Added `sendfile` on FreeBSD and Darwin.
++ ([#901](https://github.com/nix-rust/nix/pull/901))
++- Added `pselect`
++ ([#894](https://github.com/nix-rust/nix/pull/894))
++- Exposed `preadv` and `pwritev` on the BSDs.
++ ([#883](https://github.com/nix-rust/nix/pull/883))
++- Added `mlockall` and `munlockall`
++ ([#876](https://github.com/nix-rust/nix/pull/876))
++- Added `SO_MARK` on Linux.
++ ([#873](https://github.com/nix-rust/nix/pull/873))
++- Added safe support for nearly any buffer type in the `sys::aio` module.
++ ([#872](https://github.com/nix-rust/nix/pull/872))
++- Added `sys::aio::LioCb` as a wrapper for `libc::lio_listio`.
++ ([#872](https://github.com/nix-rust/nix/pull/872))
++- Added `unistd::getsid`
++ ([#850](https://github.com/nix-rust/nix/pull/850))
++- Added `alarm`. ([#830](https://github.com/nix-rust/nix/pull/830))
++- Added interface flags `IFF_NO_PI, IFF_TUN, IFF_TAP` on linux-like systems.
++ ([#853](https://github.com/nix-rust/nix/pull/853))
++- Added `statvfs` module to all MacOS and Linux architectures.
++ ([#832](https://github.com/nix-rust/nix/pull/832))
++- Added `EVFILT_EMPTY`, `EVFILT_PROCDESC`, and `EVFILT_SENDFILE` on FreeBSD.
++ ([#825](https://github.com/nix-rust/nix/pull/825))
++- Exposed `termios::cfmakesane` on FreeBSD.
++ ([#825](https://github.com/nix-rust/nix/pull/825))
++- Exposed `MSG_CMSG_CLOEXEC` on *BSD.
++ ([#825](https://github.com/nix-rust/nix/pull/825))
++- Added `fchmod`, `fchmodat`.
++ ([#857](https://github.com/nix-rust/nix/pull/857))
++- Added `request_code_write_int!` on FreeBSD/DragonFlyBSD
++ ([#833](https://github.com/nix-rust/nix/pull/833))
++
++### Changed
++- `Display` and `Debug` for `SysControlAddr` now includes all fields.
++ ([#837](https://github.com/nix-rust/nix/pull/837))
++- `ioctl!` has been replaced with a family of `ioctl_*!` macros.
++ ([#833](https://github.com/nix-rust/nix/pull/833))
++- `io!`, `ior!`, `iow!`, and `iorw!` has been renamed to `request_code_none!`, `request_code_read!`,
++ `request_code_write!`, and `request_code_readwrite!` respectively. These have also now been exposed
++ in the documentation.
++ ([#833](https://github.com/nix-rust/nix/pull/833))
++- Enabled more `ptrace::Request` definitions for uncommon Linux platforms
++ ([#892](https://github.com/nix-rust/nix/pull/892))
++- Emulation of `FD_CLOEXEC` and `O_NONBLOCK` was removed from `socket()`, `accept4()`, and
++ `socketpair()`.
++ ([#907](https://github.com/nix-rust/nix/pull/907))
++
++### Fixed
++- Fixed possible panics when using `SigAction::flags` on Linux
++ ([#869](https://github.com/nix-rust/nix/pull/869))
++- Properly exposed 460800 and 921600 baud rates on NetBSD
++ ([#837](https://github.com/nix-rust/nix/pull/837))
++- Fixed `ioctl_write_int!` on FreeBSD/DragonFlyBSD
++ ([#833](https://github.com/nix-rust/nix/pull/833))
++- `ioctl_write_int!` now properly supports passing a `c_ulong` as the parameter on Linux non-musl targets
++ ([#833](https://github.com/nix-rust/nix/pull/833))
++
++### Removed
++- Removed explicit support for the `bytes` crate from the `sys::aio` module.
++ See `sys::aio::AioCb::from_boxed_slice` examples for alternatives.
++ ([#872](https://github.com/nix-rust/nix/pull/872))
++- Removed `sys::aio::lio_listio`. Use `sys::aio::LioCb::listio` instead.
++ ([#872](https://github.com/nix-rust/nix/pull/872))
++- Removed emulated `accept4()` from macos, ios, and netbsd targets
++ ([#907](https://github.com/nix-rust/nix/pull/907))
++- Removed `IFF_NOTRAILERS` on OpenBSD, as it has been removed in OpenBSD 6.3
++ ([#893](https://github.com/nix-rust/nix/pull/893))
++
++## [0.10.0] 2018-01-26
++
++### Added
++- Added specialized wrapper: `sys::ptrace::step`
++ ([#852](https://github.com/nix-rust/nix/pull/852))
++- Added `AioCb::from_ptr` and `AioCb::from_mut_ptr`
++ ([#820](https://github.com/nix-rust/nix/pull/820))
++- Added specialized wrappers: `sys::ptrace::{traceme, syscall, cont, attach}`. Using the matching routines
++ with `sys::ptrace::ptrace` is now deprecated.
++- Added `nix::poll` module for all platforms
++ ([#672](https://github.com/nix-rust/nix/pull/672))
++- Added `nix::ppoll` function for FreeBSD and DragonFly
++ ([#672](https://github.com/nix-rust/nix/pull/672))
++- Added protocol families in `AddressFamily` enum.
++ ([#647](https://github.com/nix-rust/nix/pull/647))
++- Added the `pid()` method to `WaitStatus` for extracting the PID.
++ ([#722](https://github.com/nix-rust/nix/pull/722))
++- Added `nix::unistd:fexecve`.
++ ([#727](https://github.com/nix-rust/nix/pull/727))
++- Expose `uname()` on all platforms.
++ ([#739](https://github.com/nix-rust/nix/pull/739))
++- Expose `signalfd` module on Android as well.
++ ([#739](https://github.com/nix-rust/nix/pull/739))
++- Added `nix::sys::ptrace::detach`.
++ ([#749](https://github.com/nix-rust/nix/pull/749))
++- Added timestamp socket control message variant:
++ `nix::sys::socket::ControlMessage::ScmTimestamp`
++ ([#663](https://github.com/nix-rust/nix/pull/663))
++- Added socket option variant that enables the timestamp socket
++ control message: `nix::sys::socket::sockopt::ReceiveTimestamp`
++ ([#663](https://github.com/nix-rust/nix/pull/663))
++- Added more accessor methods for `AioCb`
++ ([#773](https://github.com/nix-rust/nix/pull/773))
++- Add `nix::sys::fallocate`
++ ([#768](https:://github.com/nix-rust/nix/pull/768))
++- Added `nix::unistd::mkfifo`.
++ ([#602](https://github.com/nix-rust/nix/pull/774))
++- Added `ptrace::Options::PTRACE_O_EXITKILL` on Linux and Android.
++ ([#771](https://github.com/nix-rust/nix/pull/771))
++- Added `nix::sys::uio::{process_vm_readv, process_vm_writev}` on Linux
++ ([#568](https://github.com/nix-rust/nix/pull/568))
++- Added `nix::unistd::{getgroups, setgroups, getgrouplist, initgroups}`. ([#733](https://github.com/nix-rust/nix/pull/733))
++- Added `nix::sys::socket::UnixAddr::as_abstract` on Linux and Android.
++ ([#785](https://github.com/nix-rust/nix/pull/785))
++- Added `nix::unistd::execveat` on Linux and Android.
++ ([#800](https://github.com/nix-rust/nix/pull/800))
++- Added the `from_raw()` method to `WaitStatus` for converting raw status values
++ to `WaitStatus` independent of syscalls.
++ ([#741](https://github.com/nix-rust/nix/pull/741))
++- Added more standard trait implementations for various types.
++ ([#814](https://github.com/nix-rust/nix/pull/814))
++- Added `sigprocmask` to the signal module.
++ ([#826](https://github.com/nix-rust/nix/pull/826))
++- Added `nix::sys::socket::LinkAddr` on Linux and all bsdlike system.
++ ([#813](https://github.com/nix-rust/nix/pull/813))
++- Add socket options for `IP_TRANSPARENT` / `BIND_ANY`.
++ ([#835](https://github.com/nix-rust/nix/pull/835))
++
++### Changed
++- Exposed the `mqueue` module for all supported operating systems.
++ ([#834](https://github.com/nix-rust/nix/pull/834))
++- Use native `pipe2` on all BSD targets. Users should notice no difference.
++ ([#777](https://github.com/nix-rust/nix/pull/777))
++- Renamed existing `ptrace` wrappers to encourage namespacing ([#692](https://github.com/nix-rust/nix/pull/692))
++- Marked `sys::ptrace::ptrace` as `unsafe`.
++- Changed function signature of `socket()` and `socketpair()`. The `protocol` argument
++ has changed type from `c_int` to `SockProtocol`.
++ It accepts a `None` value for default protocol that was specified with zero using `c_int`.
++ ([#647](https://github.com/nix-rust/nix/pull/647))
++- Made `select` easier to use, adding the ability to automatically calculate the `nfds` parameter using the new
++ `FdSet::highest` ([#701](https://github.com/nix-rust/nix/pull/701))
++- Exposed `unistd::setresuid` and `unistd::setresgid` on FreeBSD and OpenBSD
++ ([#721](https://github.com/nix-rust/nix/pull/721))
++- Refactored the `statvfs` module removing extraneous API functions and the
++ `statvfs::vfs` module. Additionally `(f)statvfs()` now return the struct
++ directly. And the returned `Statvfs` struct now exposes its data through
++ accessor methods. ([#729](https://github.com/nix-rust/nix/pull/729))
++- The `addr` argument to `madvise` and `msync` is now `*mut` to better match the
++ libc API. ([#731](https://github.com/nix-rust/nix/pull/731))
++- `shm_open` and `shm_unlink` are no longer exposed on Android targets, where
++ they are not officially supported. ([#731](https://github.com/nix-rust/nix/pull/731))
++- `MapFlags`, `MmapAdvise`, and `MsFlags` expose some more variants and only
++ officially-supported variants are provided for each target.
++ ([#731](https://github.com/nix-rust/nix/pull/731))
++- Marked `pty::ptsname` function as `unsafe`
++ ([#744](https://github.com/nix-rust/nix/pull/744))
++- Moved constants ptrace request, event and options to enums and updated ptrace functions and argument types accordingly.
++ ([#749](https://github.com/nix-rust/nix/pull/749))
++- `AioCb::Drop` will now panic if the `AioCb` is still in-progress ([#715](https://github.com/nix-rust/nix/pull/715))
++- Restricted `nix::sys::socket::UnixAddr::new_abstract` to Linux and Android only.
++ ([#785](https://github.com/nix-rust/nix/pull/785))
++- The `ucred` struct has been removed in favor of a `UserCredentials` struct that
++ contains only getters for its fields.
++ ([#814](https://github.com/nix-rust/nix/pull/814))
++- Both `ip_mreq` and `ipv6_mreq` have been replaced with `IpMembershipRequest` and
++ `Ipv6MembershipRequest`.
++ ([#814](https://github.com/nix-rust/nix/pull/814))
++- Removed return type from `pause`.
++ ([#829](https://github.com/nix-rust/nix/pull/829))
++- Changed the termios APIs to allow for using a `u32` instead of the `BaudRate`
++ enum on BSD platforms to support arbitrary baud rates. See the module docs for
++ `nix::sys::termios` for more details.
++ ([#843](https://github.com/nix-rust/nix/pull/843))
++
++### Fixed
++- Fix compilation and tests for OpenBSD targets
++ ([#688](https://github.com/nix-rust/nix/pull/688))
++- Fixed error handling in `AioCb::fsync`, `AioCb::read`, and `AioCb::write`.
++ It is no longer an error to drop an `AioCb` that failed to enqueue in the OS.
++ ([#715](https://github.com/nix-rust/nix/pull/715))
++- Fix potential memory corruption on non-Linux platforms when using
++ `sendmsg`/`recvmsg`, caused by mismatched `msghdr` definition.
++ ([#648](https://github.com/nix-rust/nix/pull/648))
++
++### Removed
++- `AioCb::from_boxed_slice` has been removed. It was never actually safe. Use
++ `from_bytes` or `from_bytes_mut` instead.
++ ([#820](https://github.com/nix-rust/nix/pull/820))
++- The syscall module has been removed. This only exposed enough functionality for
++ `memfd_create()` and `pivot_root()`, which are still exposed as separate functions.
++ ([#747](https://github.com/nix-rust/nix/pull/747))
++- The `Errno` variants are no longer reexported from the `errno` module. `Errno` itself is no longer reexported from the
++ crate root and instead must be accessed using the `errno` module. ([#696](https://github.com/nix-rust/nix/pull/696))
++- Removed `MS_VERBOSE`, `MS_NOSEC`, and `MS_BORN` from `MsFlags`. These
++ are internal kernel flags and should never have been exposed.
++ ([#814](https://github.com/nix-rust/nix/pull/814))
++
++
++## [0.9.0] 2017-07-23
++
++### Added
++- Added `sysconf`, `pathconf`, and `fpathconf`
++ ([#630](https://github.com/nix-rust/nix/pull/630)
++- Added `sys::signal::SigAction::{ flags, mask, handler}`
++ ([#611](https://github.com/nix-rust/nix/pull/609)
++- Added `nix::sys::pthread::pthread_self`
++ ([#591](https://github.com/nix-rust/nix/pull/591)
++- Added `AioCb::from_boxed_slice`
++ ([#582](https://github.com/nix-rust/nix/pull/582)
++- Added `nix::unistd::{openat, fstatat, readlink, readlinkat}`
++ ([#551](https://github.com/nix-rust/nix/pull/551))
++- Added `nix::pty::{grantpt, posix_openpt, ptsname/ptsname_r, unlockpt}`
++ ([#556](https://github.com/nix-rust/nix/pull/556)
++- Added `nix::ptr::openpty`
++ ([#456](https://github.com/nix-rust/nix/pull/456))
++- Added `nix::ptrace::{ptrace_get_data, ptrace_getsiginfo, ptrace_setsiginfo
++ and nix::Error::UnsupportedOperation}`
++ ([#614](https://github.com/nix-rust/nix/pull/614))
++- Added `cfmakeraw`, `cfsetspeed`, and `tcgetsid`. ([#527](https://github.com/nix-rust/nix/pull/527))
++- Added "bad none", "bad write_ptr", "bad write_int", and "bad readwrite" variants to the `ioctl!`
++ macro. ([#670](https://github.com/nix-rust/nix/pull/670))
++- On Linux and Android, added support for receiving `PTRACE_O_TRACESYSGOOD`
++ events from `wait` and `waitpid` using `WaitStatus::PtraceSyscall`
++ ([#566](https://github.com/nix-rust/nix/pull/566)).
++
++### Changed
++- The `ioctl!` macro and its variants now allow the generated functions to have
++ doccomments. ([#661](https://github.com/nix-rust/nix/pull/661))
++- Changed `ioctl!(write ...)` into `ioctl!(write_ptr ...)` and `ioctl!(write_int ..)` variants
++ to more clearly separate those use cases. ([#670](https://github.com/nix-rust/nix/pull/670))
++- Marked `sys::mman::{ mmap, munmap, madvise, munlock, msync }` as unsafe.
++ ([#559](https://github.com/nix-rust/nix/pull/559))
++- Minimum supported Rust version is now 1.13.
++- Removed `revents` argument from `PollFd::new()` as it's an output argument and
++ will be overwritten regardless of value.
++ ([#542](https://github.com/nix-rust/nix/pull/542))
++- Changed type signature of `sys::select::FdSet::contains` to make `self`
++ immutable ([#564](https://github.com/nix-rust/nix/pull/564))
++- Introduced wrapper types for `gid_t`, `pid_t`, and `uid_t` as `Gid`, `Pid`, and `Uid`
++ respectively. Various functions have been changed to use these new types as
++ arguments. ([#629](https://github.com/nix-rust/nix/pull/629))
++- Fixed compilation on all Android and iOS targets ([#527](https://github.com/nix-rust/nix/pull/527))
++ and promoted them to Tier 2 support.
++- `nix::sys::statfs::{statfs,fstatfs}` uses statfs definition from `libc::statfs` instead of own linux specific type `nix::sys::Statfs`.
++ Also file system type constants like `nix::sys::statfs::ADFS_SUPER_MAGIC` were removed in favor of the libc equivalent.
++ ([#561](https://github.com/nix-rust/nix/pull/561))
++- Revised the termios API including additional tests and documentation and exposed it on iOS. ([#527](https://github.com/nix-rust/nix/pull/527))
++- `eventfd`, `signalfd`, and `pwritev`/`preadv` functionality is now included by default for all
++ supported platforms. ([#681](https://github.com/nix-rust/nix/pull/561))
++- The `ioctl!` macro's plain variants has been replaced with "bad read" to be consistent with
++ other variants. The generated functions also have more strict types for their arguments. The
++ "*_buf" variants also now calculate total array size and take slice references for improved type
++ safety. The documentation has also been dramatically improved.
++ ([#670](https://github.com/nix-rust/nix/pull/670))
++
++### Removed
++- Removed `io::Error` from `nix::Error` and the conversion from `nix::Error` to `Errno`
++ ([#614](https://github.com/nix-rust/nix/pull/614))
++- All feature flags have been removed in favor of conditional compilation on supported platforms.
++ `execvpe` is no longer supported, but this was already broken and will be added back in the next
++ release. ([#681](https://github.com/nix-rust/nix/pull/561))
++- Removed `ioc_*` functions and many helper constants and macros within the `ioctl` module. These
++ should always have been private and only the `ioctl!` should be used in public code.
++ ([#670](https://github.com/nix-rust/nix/pull/670))
++
++### Fixed
++- Fixed multiple issues compiling under different archetectures and OSes.
++ Now compiles on Linux/MIPS ([#538](https://github.com/nix-rust/nix/pull/538)),
++ `Linux/PPC` ([#553](https://github.com/nix-rust/nix/pull/553)),
++ `MacOS/x86_64,i686` ([#553](https://github.com/nix-rust/nix/pull/553)),
++ `NetBSD/x64_64` ([#538](https://github.com/nix-rust/nix/pull/538)),
++ `FreeBSD/x86_64,i686` ([#536](https://github.com/nix-rust/nix/pull/536)), and
++ `Android` ([#631](https://github.com/nix-rust/nix/pull/631)).
++- `bind` and `errno_location` now work correctly on `Android`
++ ([#631](https://github.com/nix-rust/nix/pull/631))
++- Added `nix::ptrace` on all Linux-kernel-based platforms
++ [#624](https://github.com/nix-rust/nix/pull/624). Previously it was
++ only available on x86, x86-64, and ARM, and also not on Android.
++- Fixed `sys::socket::sendmsg` with zero entry `cmsgs` parameter.
++ ([#623](https://github.com/nix-rust/nix/pull/623))
++- Multiple constants related to the termios API have now been properly defined for
++ all supported platforms. ([#527](https://github.com/nix-rust/nix/pull/527))
++- `ioctl!` macro now supports working with non-int datatypes and properly supports all platforms.
++ ([#670](https://github.com/nix-rust/nix/pull/670))
++
++## [0.8.1] 2017-04-16
++
++### Fixed
++- Fixed build on FreeBSD. (Cherry-picked
++ [a859ee3c](https://github.com/nix-rust/nix/commit/a859ee3c9396dfdb118fcc2c8ecc697e2d303467))
++
++## [0.8.0] 2017-03-02
++
++### Added
++- Added `::nix::sys::termios::BaudRate` enum to provide portable baudrate
++ values. ([#518](https://github.com/nix-rust/nix/pull/518))
++- Added a new `WaitStatus::PtraceEvent` to support ptrace events on Linux
++ and Android ([#438](https://github.com/nix-rust/nix/pull/438))
++- Added support for POSIX AIO
++ ([#483](https://github.com/nix-rust/nix/pull/483))
++ ([#506](https://github.com/nix-rust/nix/pull/506))
++- Added support for XNU system control sockets
++ ([#478](https://github.com/nix-rust/nix/pull/478))
++- Added support for `ioctl` calls on BSD platforms
++ ([#478](https://github.com/nix-rust/nix/pull/478))
++- Added struct `TimeSpec`
++ ([#475](https://github.com/nix-rust/nix/pull/475))
++ ([#483](https://github.com/nix-rust/nix/pull/483))
++- Added complete definitions for all kqueue-related constants on all supported
++ OSes
++ ([#415](https://github.com/nix-rust/nix/pull/415))
++- Added function `epoll_create1` and bitflags `EpollCreateFlags` in
++ `::nix::sys::epoll` in order to support `::libc::epoll_create1`.
++ ([#410](https://github.com/nix-rust/nix/pull/410))
++- Added `setresuid` and `setresgid` for Linux in `::nix::unistd`
++ ([#448](https://github.com/nix-rust/nix/pull/448))
++- Added `getpgid` in `::nix::unistd`
++ ([#433](https://github.com/nix-rust/nix/pull/433))
++- Added `tcgetpgrp` and `tcsetpgrp` in `::nix::unistd`
++ ([#451](https://github.com/nix-rust/nix/pull/451))
++- Added `CLONE_NEWCGROUP` in `::nix::sched`
++ ([#457](https://github.com/nix-rust/nix/pull/457))
++- Added `getpgrp` in `::nix::unistd`
++ ([#491](https://github.com/nix-rust/nix/pull/491))
++- Added `fchdir` in `::nix::unistd`
++ ([#497](https://github.com/nix-rust/nix/pull/497))
++- Added `major` and `minor` in `::nix::sys::stat` for decomposing `dev_t`
++ ([#508](https://github.com/nix-rust/nix/pull/508))
++- Fixed the style of many bitflags and use `libc` in more places.
++ ([#503](https://github.com/nix-rust/nix/pull/503))
++- Added `ppoll` in `::nix::poll`
++ ([#520](https://github.com/nix-rust/nix/pull/520))
++- Added support for getting and setting pipe size with fcntl(2) on Linux
++ ([#540](https://github.com/nix-rust/nix/pull/540))
++
++### Changed
++- `::nix::sys::termios::{cfgetispeed, cfsetispeed, cfgetospeed, cfsetospeed}`
++ switched to use `BaudRate` enum from `speed_t`.
++ ([#518](https://github.com/nix-rust/nix/pull/518))
++- `epoll_ctl` now could accept None as argument `event`
++ when op is `EpollOp::EpollCtlDel`.
++ ([#480](https://github.com/nix-rust/nix/pull/480))
++- Removed the `bad` keyword from the `ioctl!` macro
++ ([#478](https://github.com/nix-rust/nix/pull/478))
++- Changed `TimeVal` into an opaque Newtype
++ ([#475](https://github.com/nix-rust/nix/pull/475))
++- `kill`'s signature, defined in `::nix::sys::signal`, changed, so that the
++ signal parameter has type `T: Into<Option<Signal>>`. `None` as an argument
++ for that parameter will result in a 0 passed to libc's `kill`, while a
++ `Some`-argument will result in the previous behavior for the contained
++ `Signal`.
++ ([#445](https://github.com/nix-rust/nix/pull/445))
++- The minimum supported version of rustc is now 1.7.0.
++ ([#444](https://github.com/nix-rust/nix/pull/444))
++- Changed `KEvent` to an opaque structure that may only be modified by its
++ constructor and the `ev_set` method.
++ ([#415](https://github.com/nix-rust/nix/pull/415))
++ ([#442](https://github.com/nix-rust/nix/pull/442))
++ ([#463](https://github.com/nix-rust/nix/pull/463))
++- `pipe2` now calls `libc::pipe2` where available. Previously it was emulated
++ using `pipe`, which meant that setting `O_CLOEXEC` was not atomic.
++ ([#427](https://github.com/nix-rust/nix/pull/427))
++- Renamed `EpollEventKind` to `EpollFlags` in `::nix::sys::epoll` in order for
++ it to conform with our conventions.
++ ([#410](https://github.com/nix-rust/nix/pull/410))
++- `EpollEvent` in `::nix::sys::epoll` is now an opaque proxy for
++ `::libc::epoll_event`. The formerly public field `events` is now be read-only
++ accessible with the new method `events()` of `EpollEvent`. Instances of
++ `EpollEvent` can be constructed using the new method `new()` of EpollEvent.
++ ([#410](https://github.com/nix-rust/nix/pull/410))
++- `SigFlags` in `::nix::sys::signal` has be renamed to `SigmaskHow` and its type
++ has changed from `bitflags` to `enum` in order to conform to our conventions.
++ ([#460](https://github.com/nix-rust/nix/pull/460))
++- `sethostname` now takes a `&str` instead of a `&[u8]` as this provides an API
++ that makes more sense in normal, correct usage of the API.
++- `gethostname` previously did not expose the actual length of the hostname
++ written from the underlying system call at all. This has been updated to
++ return a `&CStr` within the provided buffer that is always properly
++ NUL-terminated (this is not guaranteed by the call with all platforms/libc
++ implementations).
++- Exposed all fcntl(2) operations at the module level, so they can be
++ imported direclty instead of via `FcntlArg` enum.
++ ([#541](https://github.com/nix-rust/nix/pull/541))
++
++### Fixed
++- Fixed multiple issues with Unix domain sockets on non-Linux OSes
++ ([#474](https://github.com/nix-rust/nix/pull/415))
++- Fixed using kqueue with `EVFILT_USER` on FreeBSD
++ ([#415](https://github.com/nix-rust/nix/pull/415))
++- Fixed the build on FreeBSD, and fixed the getsockopt, sendmsg, and recvmsg
++ functions on that same OS.
++ ([#397](https://github.com/nix-rust/nix/pull/397))
++- Fixed an off-by-one bug in `UnixAddr::new_abstract` in `::nix::sys::socket`.
++ ([#429](https://github.com/nix-rust/nix/pull/429))
++- Fixed clone passing a potentially unaligned stack.
++ ([#490](https://github.com/nix-rust/nix/pull/490))
++- Fixed mkdev not creating a `dev_t` the same way as libc.
++ ([#508](https://github.com/nix-rust/nix/pull/508))
++
++## [0.7.0] 2016-09-09
++
++### Added
++- Added `lseek` and `lseek64` in `::nix::unistd`
++ ([#377](https://github.com/nix-rust/nix/pull/377))
++- Added `mkdir` and `getcwd` in `::nix::unistd`
++ ([#416](https://github.com/nix-rust/nix/pull/416))
++- Added accessors `sigmask_mut` and `sigmask` to `UContext` in
++ `::nix::ucontext`.
++ ([#370](https://github.com/nix-rust/nix/pull/370))
++- Added `WUNTRACED` to `WaitPidFlag` in `::nix::sys::wait` for non-_linux_
++ targets.
++ ([#379](https://github.com/nix-rust/nix/pull/379))
++- Added new module `::nix::sys::reboot` with enumeration `RebootMode` and
++ functions `reboot` and `set_cad_enabled`. Currently for _linux_ only.
++ ([#386](https://github.com/nix-rust/nix/pull/386))
++- `FdSet` in `::nix::sys::select` now also implements `Clone`.
++ ([#405](https://github.com/nix-rust/nix/pull/405))
++- Added `F_FULLFSYNC` to `FcntlArg` in `::nix::fcntl` for _apple_ targets.
++ ([#407](https://github.com/nix-rust/nix/pull/407))
++- Added `CpuSet::unset` in `::nix::sched`.
++ ([#402](https://github.com/nix-rust/nix/pull/402))
++- Added constructor method `new()` to `PollFd` in `::nix::poll`, in order to
++ allow creation of objects, after removing public access to members.
++ ([#399](https://github.com/nix-rust/nix/pull/399))
++- Added method `revents()` to `PollFd` in `::nix::poll`, in order to provide
++ read access to formerly public member `revents`.
++ ([#399](https://github.com/nix-rust/nix/pull/399))
++- Added `MSG_CMSG_CLOEXEC` to `MsgFlags` in `::nix::sys::socket` for _linux_ only.
++ ([#422](https://github.com/nix-rust/nix/pull/422))
++
++### Changed
++- Replaced the reexported integer constants for signals by the enumeration
++ `Signal` in `::nix::sys::signal`.
++ ([#362](https://github.com/nix-rust/nix/pull/362))
++- Renamed `EventFdFlag` to `EfdFlags` in `::nix::sys::eventfd`.
++ ([#383](https://github.com/nix-rust/nix/pull/383))
++- Changed the result types of `CpuSet::is_set` and `CpuSet::set` in
++ `::nix::sched` to `Result<bool>` and `Result<()>`, respectively. They now
++ return `EINVAL`, if an invalid argument for the `field` parameter is passed.
++ ([#402](https://github.com/nix-rust/nix/pull/402))
++- `MqAttr` in `::nix::mqueue` is now an opaque proxy for `::libc::mq_attr`,
++ which has the same structure as the old `MqAttr`. The field `mq_flags` of
++ `::libc::mq_attr` is readable using the new method `flags()` of `MqAttr`.
++ `MqAttr` also no longer implements `Debug`.
++ ([#392](https://github.com/nix-rust/nix/pull/392))
++- The parameter `msq_prio` of `mq_receive` with type `u32` in `::nix::mqueue`
++ was replaced by a parameter named `msg_prio` with type `&mut u32`, so that
++ the message priority can be obtained by the caller.
++ ([#392](https://github.com/nix-rust/nix/pull/392))
++- The type alias `MQd` in `::nix::queue` was replaced by the type alias
++ `libc::mqd_t`, both of which are aliases for the same type.
++ ([#392](https://github.com/nix-rust/nix/pull/392))
++
++### Removed
++- Type alias `SigNum` from `::nix::sys::signal`.
++ ([#362](https://github.com/nix-rust/nix/pull/362))
++- Type alias `CpuMask` from `::nix::shed`.
++ ([#402](https://github.com/nix-rust/nix/pull/402))
++- Removed public fields from `PollFd` in `::nix::poll`. (See also added method
++ `revents()`.
++ ([#399](https://github.com/nix-rust/nix/pull/399))
++
++### Fixed
++- Fixed the build problem for NetBSD (Note, that we currently do not support
++ it, so it might already be broken again).
++ ([#389](https://github.com/nix-rust/nix/pull/389))
++- Fixed the build on FreeBSD, and fixed the getsockopt, sendmsg, and recvmsg
++ functions on that same OS.
++ ([#397](https://github.com/nix-rust/nix/pull/397))
++
++## [0.6.0] 2016-06-10
++
++### Added
++- Added `gettid` in `::nix::unistd` for _linux_ and _android_.
++ ([#293](https://github.com/nix-rust/nix/pull/293))
++- Some _mips_ support in `::nix::sched` and `::nix::sys::syscall`.
++ ([#301](https://github.com/nix-rust/nix/pull/301))
++- Added `SIGNALFD_SIGINFO_SIZE` in `::nix::sys::signalfd`.
++ ([#309](https://github.com/nix-rust/nix/pull/309))
++- Added new module `::nix::ucontext` with struct `UContext`. Currently for
++ _linux_ only.
++ ([#311](https://github.com/nix-rust/nix/pull/311))
++- Added `EPOLLEXCLUSIVE` to `EpollEventKind` in `::nix::sys::epoll`.
++ ([#330](https://github.com/nix-rust/nix/pull/330))
++- Added `pause` to `::nix::unistd`.
++ ([#336](https://github.com/nix-rust/nix/pull/336))
++- Added `sleep` to `::nix::unistd`.
++ ([#351](https://github.com/nix-rust/nix/pull/351))
++- Added `S_IFDIR`, `S_IFLNK`, `S_IFMT` to `SFlag` in `::nix::sys::stat`.
++ ([#359](https://github.com/nix-rust/nix/pull/359))
++- Added `clear` and `extend` functions to `SigSet`'s implementation in
++ `::nix::sys::signal`.
++ ([#347](https://github.com/nix-rust/nix/pull/347))
++- `sockaddr_storage_to_addr` in `::nix::sys::socket` now supports `sockaddr_nl`
++ on _linux_ and _android_.
++ ([#366](https://github.com/nix-rust/nix/pull/366))
++- Added support for `SO_ORIGINAL_DST` in `::nix::sys::socket` on _linux_.
++ ([#367](https://github.com/nix-rust/nix/pull/367))
++- Added `SIGINFO` in `::nix::sys::signal` for the _macos_ target as well as
++ `SIGPWR` and `SIGSTKFLT` in `::nix::sys::signal` for non-_macos_ targets.
++ ([#361](https://github.com/nix-rust/nix/pull/361))
++
++### Changed
++- Changed the structure `IoVec` in `::nix::sys::uio`.
++ ([#304](https://github.com/nix-rust/nix/pull/304))
++- Replaced `CREATE_NEW_FD` by `SIGNALFD_NEW` in `::nix::sys::signalfd`.
++ ([#309](https://github.com/nix-rust/nix/pull/309))
++- Renamed `SaFlag` to `SaFlags` and `SigFlag` to `SigFlags` in
++ `::nix::sys::signal`.
++ ([#314](https://github.com/nix-rust/nix/pull/314))
++- Renamed `Fork` to `ForkResult` and changed its fields in `::nix::unistd`.
++ ([#332](https://github.com/nix-rust/nix/pull/332))
++- Added the `signal` parameter to `clone`'s signature in `::nix::sched`.
++ ([#344](https://github.com/nix-rust/nix/pull/344))
++- `execv`, `execve`, and `execvp` now return `Result<Void>` instead of
++ `Result<()>` in `::nix::unistd`.
++ ([#357](https://github.com/nix-rust/nix/pull/357))
++
++### Fixed
++- Improved the conversion from `std::net::SocketAddr` to `InetAddr` in
++ `::nix::sys::socket::addr`.
++ ([#335](https://github.com/nix-rust/nix/pull/335))
++
++## [0.5.0] 2016-03-01
+diff --git a/third_party/rust/nix-0.15.0/CONTRIBUTING.md b/third_party/rust/nix-0.15.0/CONTRIBUTING.md
+new file mode 100644
+index 0000000000000..03a1f630dbb06
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/CONTRIBUTING.md
+@@ -0,0 +1,114 @@
++# Contributing to nix
++
++We're really glad you're interested in contributing to nix! This
++document has a few pointers and guidelines to help get you started.
++
++To have a welcoming and inclusive project, nix uses the Rust project's
++[Code of Conduct][conduct]. All contributors are expected to follow it.
++
++[conduct]: https://www.rust-lang.org/conduct.html
++
++
++# Issues
++
++We use GitHub's [issue tracker][issues].
++
++[issues]: https://github.com/nix-rust/nix/issues
++
++
++## Bug reports
++
++Before submitting a new bug report, please [search existing
++issues][issue-search] to see if there's something related. If not, just
++[open a new issue][new-issue]!
++
++As a reminder, the more information you can give in your issue, the
++easier it is to figure out how to fix it. For nix, this will likely
++include the OS and version, and the architecture.
++
++[issue-search]: https://github.com/nix-rust/nix/search?utf8=%E2%9C%93&q=is%3Aissue&type=Issues
++[new-issue]: https://github.com/nix-rust/nix/issues/new
++
++
++## Feature / API requests
++
++If you'd like a new API or feature added, please [open a new
++issue][new-issue] requesting it. As with reporting a bug, the more
++information you can provide, the better.
++
++
++## Labels
++
++We use labels to help manage issues. The structure is modeled after
++[Rust's issue labeling scheme][rust-labels]:
++- **A-**prefixed labels state which area of the project the issue
++ relates to
++- **E-**prefixed labels explain the level of experience necessary to fix the
++ issue
++- **O-**prefixed labels specify the OS for issues that are OS-specific
++- **R-**prefixed labels specify the architecture for issues that are
++ architecture-specific
++
++[rust-labels]: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#issue-triage
++
++
++# Pull requests
++
++GitHub pull requests are the primary mechanism we use to change nix. GitHub itself has
++some [great documentation][pr-docs] on using the Pull Request feature. We use the 'fork and
++pull' model described there.
++
++Please make pull requests against the `master` branch.
++
++If you change the API by way of adding, removing or changing something or if
++you fix a bug, please add an appropriate note to the [change log][cl]. We
++follow the conventions of [Keep A CHANGELOG][kacl].
++
++[cl]: https://github.com/nix-rust/nix/blob/master/CHANGELOG.md
++[kacl]: https://github.com/olivierlacan/keep-a-changelog/tree/18adb5f5be7a898d046f6a4acb93e39dcf40c4ad
++[pr-docs]: https://help.github.com/articles/using-pull-requests/
++
++## Testing
++
++nix has a test suite that you can run with `cargo test`. Ideally, we'd like pull
++requests to include tests where they make sense. For example, when fixing a bug,
++add a test that would have failed without the fix.
++
++After you've made your change, make sure the tests pass in your development
++environment. We also have [continuous integration set up on
++Travis-CI][travis-ci], which might find some issues on other platforms. The CI
++will run once you open a pull request.
++
++There is also infrastructure for running tests for other targets
++locally. More information is available in the [CI Readme][ci-readme].
++
++[travis-ci]: https://travis-ci.org/nix-rust/nix
++[ci-readme]: ci/README.md
++
++### Disabling a test in the CI environment
++
++Sometimes there are features that cannot be tested in the CI environment.
++To stop a test from running under CI, add `#[cfg_attr(travis, ignore)]`
++to it. Please include a comment describing the reason it shouldn't run
++under CI, and a link to an upstream issue if possible!
++
++## bors, the bot who merges all the PRs
++
++All pull requests are merged via [bors], an integration bot. After the
++pull request has been reviewed, the reviewer will leave a comment like
++
++> bors r+
++
++to let bors know that it was approved. Then bors will check that it passes
++tests when merged with the latest changes in the `master` branch, and
++merge if the tests succeed.
++
++[bors]: https://bors-ng.github.io/
++
++
++## API conventions
++
++If you're adding a new API, we have a [document with
++conventions][conventions] to use throughout the nix project.
++
++[conventions]: https://github.com/nix-rust/nix/blob/master/CONVENTIONS.md
+diff --git a/third_party/rust/nix-0.15.0/CONVENTIONS.md b/third_party/rust/nix-0.15.0/CONVENTIONS.md
+new file mode 100644
+index 0000000000000..48daa937345d2
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/CONVENTIONS.md
+@@ -0,0 +1,87 @@
++# Conventions
++
++In order to achieve our goal of wrapping [libc][libc] code in idiomatic rust
++constructs with minimal performance overhead, we follow the following
++conventions.
++
++Note that, thus far, not all the code follows these conventions and not all
++conventions we try to follow have been documented here. If you find an instance
++of either, feel free to remedy the flaw by opening a pull request with
++appropriate changes or additions.
++
++## Change Log
++
++We follow the conventions laid out in [Keep A CHANGELOG][kacl].
++
++[kacl]: https://github.com/olivierlacan/keep-a-changelog/tree/18adb5f5be7a898d046f6a4acb93e39dcf40c4ad
++
++## libc constants, functions and structs
++
++We do not define integer constants ourselves, but use or reexport them from the
++[libc crate][libc].
++
++We use the functions exported from [libc][libc] instead of writing our own
++`extern` declarations.
++
++We use the `struct` definitions from [libc][libc] internally instead of writing
++our own. If we want to add methods to a libc type, we use the newtype pattern.
++For example,
++
++```rust
++pub struct SigSet(libc::sigset_t);
++
++impl SigSet {
++ ...
++}
++```
++
++When creating newtypes, we use Rust's `CamelCase` type naming convention.
++
++## Bitflags
++
++Many C functions have flags parameters that are combined from constants using
++bitwise operations. We represent the types of these parameters by types defined
++using our `libc_bitflags!` macro, which is a convenience wrapper around the
++`bitflags!` macro from the [bitflags crate][bitflags] that brings in the
++constant value from `libc`.
++
++We name the type for a set of constants whose element's names start with `FOO_`
++`FooFlags`.
++
++For example,
++
++```rust
++libc_bitflags!{
++ pub struct ProtFlags: libc::c_int {
++ PROT_NONE;
++ PROT_READ;
++ PROT_WRITE;
++ PROT_EXEC;
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ PROT_GROWSDOWN;
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ PROT_GROWSUP;
++ }
++}
++```
++
++
++## Enumerations
++
++We represent sets of constants that are intended as mutually exclusive arguments
++to parameters of functions by [enumerations][enum].
++
++
++## Structures Initialized by libc Functions
++
++Whenever we need to use a [libc][libc] function to properly initialize a
++variable and said function allows us to use uninitialized memory, we use
++[`std::mem::uninitialized`][std_uninitialized] (or [`core::mem::uninitialized`][core_uninitialized])
++when defining the variable. This allows us to avoid the overhead incurred by
++zeroing or otherwise initializing the variable.
++
++[bitflags]: https://crates.io/crates/bitflags/
++[core_uninitialized]: https://doc.rust-lang.org/core/mem/fn.uninitialized.html
++[enum]: https://doc.rust-lang.org/reference.html#enumerations
++[libc]: https://crates.io/crates/libc/
++[std_uninitialized]: https://doc.rust-lang.org/std/mem/fn.uninitialized.html
+diff --git a/third_party/rust/nix-0.15.0/Cargo.toml b/third_party/rust/nix-0.15.0/Cargo.toml
+new file mode 100644
+index 0000000000000..555b99020d68f
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/Cargo.toml
+@@ -0,0 +1,71 @@
++# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
++#
++# When uploading crates to the registry Cargo will automatically
++# "normalize" Cargo.toml files for maximal compatibility
++# with all versions of Cargo and also rewrite `path` dependencies
++# to registry (e.g., crates.io) dependencies
++#
++# If you believe there's an error in this file please file an
++# issue against the rust-lang/cargo repository. If you're
++# editing this file be aware that the upstream Cargo.toml
++# will likely look very different (and much more reasonable)
++
++[package]
++name = "nix"
++version = "0.15.0"
++authors = ["The nix-rust Project Developers"]
++exclude = ["/.gitignore", "/.travis.yml", "/ci/*", "/Cross.toml", "/RELEASE_PROCEDURE.md", "/bors.toml"]
++description = "Rust friendly bindings to *nix APIs"
++categories = ["os::unix-apis"]
++license = "MIT"
++repository = "https://github.com/nix-rust/nix"
++
++[[test]]
++name = "test"
++path = "test/test.rs"
++
++[[test]]
++name = "test-aio-drop"
++path = "test/sys/test_aio_drop.rs"
++
++[[test]]
++name = "test-lio-listio-resubmit"
++path = "test/sys/test_lio_listio_resubmit.rs"
++
++[[test]]
++name = "test-mount"
++path = "test/test_mount.rs"
++harness = false
++
++[[test]]
++name = "test-ptymaster-drop"
++path = "test/test_ptymaster_drop.rs"
++[dependencies.bitflags]
++version = "1.0"
++
++[dependencies.cfg-if]
++version = "0.1.2"
++
++[dependencies.libc]
++version = "0.2.60"
++features = ["extra_traits"]
++
++[dependencies.void]
++version = "1.0.2"
++[dev-dependencies.bytes]
++version = "0.4.8"
++
++[dev-dependencies.lazy_static]
++version = "1.2"
++
++[dev-dependencies.rand]
++version = ">= 0.6, < 0.7"
++
++[dev-dependencies.tempfile]
++version = ">= 3.0.5, < 3.0.9"
++[target."cfg(any(target_os = \"android\", target_os = \"linux\"))".dev-dependencies.caps]
++version = "0.3.1"
++[target."cfg(target_os = \"dragonfly\")".build-dependencies.cc]
++version = "1"
++[target."cfg(target_os = \"freebsd\")".dev-dependencies.sysctl]
++version = "0.1"
+diff --git a/third_party/rust/nix-0.15.0/LICENSE b/third_party/rust/nix-0.15.0/LICENSE
+new file mode 100644
+index 0000000000000..aff9096fdf11d
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/LICENSE
+@@ -0,0 +1,21 @@
++The MIT License (MIT)
++
++Copyright (c) 2015 Carl Lerche + nix-rust Authors
++
++Permission is hereby granted, free of charge, to any person obtaining a copy
++of this software and associated documentation files (the "Software"), to deal
++in the Software without restriction, including without limitation the rights
++to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
++copies of the Software, and to permit persons to whom the Software is
++furnished to do so, subject to the following conditions:
++
++The above copyright notice and this permission notice shall be included in
++all copies or substantial portions of the Software.
++
++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
++OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
++THE SOFTWARE.
+diff --git a/third_party/rust/nix-0.15.0/README.md b/third_party/rust/nix-0.15.0/README.md
+new file mode 100644
+index 0000000000000..0e540ba5b968e
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/README.md
+@@ -0,0 +1,111 @@
++# Rust bindings to *nix APIs
++
++[![Build Status](https://travis-ci.org/nix-rust/nix.svg?branch=master)](https://travis-ci.org/nix-rust/nix)
++[![crates.io](http://meritbadge.herokuapp.com/nix)](https://crates.io/crates/nix)
++
++[Documentation (Releases)](https://docs.rs/nix/)
++
++Nix seeks to provide friendly bindings to various *nix platform APIs (Linux, Darwin,
++...). The goal is to not provide a 100% unified interface, but to unify
++what can be while still providing platform specific APIs.
++
++For many system APIs, Nix provides a safe alternative to the unsafe APIs
++exposed by the [libc crate](https://github.com/rust-lang/libc). This is done by
++wrapping the libc functionality with types/abstractions that enforce legal/safe
++usage.
++
++
++As an example of what Nix provides, examine the differences between what is
++exposed by libc and nix for the
++[gethostname](http://man7.org/linux/man-pages/man2/gethostname.2.html) system
++call:
++
++```rust,ignore
++// libc api (unsafe, requires handling return code/errno)
++pub unsafe extern fn gethostname(name: *mut c_char, len: size_t) -> c_int;
++
++// nix api (returns a nix::Result<CStr>)
++pub fn gethostname<'a>(buffer: &'a mut [u8]) -> Result<&'a CStr>;
++```
++
++## Supported Platforms
++
++nix target support consists of two tiers. While nix attempts to support all
++platforms supported by [libc](https://github.com/rust-lang/libc), only some
++platforms are actively supported due to either technical or manpower
++limitations. Support for platforms is split into three tiers:
++
++ * Tier 1 - Builds and tests for this target are run in CI. Failures of either
++ block the inclusion of new code.
++ * Tier 2 - Builds for this target are run in CI. Failures during the build
++ blocks the inclusion of new code. Tests may be run, but failures
++ in tests don't block the inclusion of new code.
++ * Tier 3 - Builds for this target are run in CI. Failures during the build
++ *do not* block the inclusion of new code. Testing may be run, but
++ failures in tests don't block the inclusion of new code.
++
++The following targets are supported by `nix`:
++
++Tier 1:
++ * aarch64-unknown-linux-gnu
++ * arm-unknown-linux-gnueabi
++ * armv7-unknown-linux-gnueabihf
++ * i686-apple-darwin
++ * i686-unknown-freebsd
++ * i686-unknown-linux-gnu
++ * i686-unknown-linux-musl
++ * mips-unknown-linux-gnu
++ * mips64-unknown-linux-gnuabi64
++ * mips64el-unknown-linux-gnuabi64
++ * mipsel-unknown-linux-gnu
++ * powerpc64-unknown-linux-gnu
++ * powerpc64le-unknown-linux-gnu
++ * x86_64-apple-darwin
++ * x86_64-unknown-freebsd
++ * x86_64-unknown-linux-gnu
++ * x86_64-unknown-linux-musl
++
++Tier 2:
++ * aarch64-apple-ios
++ * aarch64-linux-android
++ * arm-linux-androideabi
++ * arm-unknown-linux-musleabi
++ * armv7-apple-ios
++ * armv7-linux-androideabi
++ * armv7s-apple-ios
++ * i386-apple-ios
++ * i686-linux-android
++ * powerpc-unknown-linux-gnu
++ * s390x-unknown-linux-gnu
++ * x86_64-apple-ios
++ * x86_64-linux-android
++ * x86_64-unknown-netbsd
++
++## Usage
++
++`nix` requires Rust 1.31.0 or newer.
++
++To use `nix`, first add this to your `Cargo.toml`:
++
++```toml
++[dependencies]
++nix = "0.15.0"
++```
++
++Then, add this to your crate root:
++
++```rust,ignore
++extern crate nix;
++```
++
++## Contributing
++
++Contributions are very welcome. Please See [CONTRIBUTING](CONTRIBUTING.md) for
++additional details.
++
++Feel free to join us in [the nix-rust/nix](https://gitter.im/nix-rust/nix) channel on Gitter to
++discuss `nix` development.
++
++## License
++
++Nix is licensed under the MIT license. See [LICENSE](LICENSE) for more details.
+diff --git a/third_party/rust/nix/build.rs b/third_party/rust/nix-0.15.0/build.rs
+similarity index 100%
+rename from third_party/rust/nix/build.rs
+rename to third_party/rust/nix-0.15.0/build.rs
+diff --git a/third_party/rust/nix-0.15.0/src/dir.rs b/third_party/rust/nix-0.15.0/src/dir.rs
+new file mode 100644
+index 0000000000000..1820b5330ff60
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/dir.rs
+@@ -0,0 +1,193 @@
++use {Error, NixPath, Result};
++use errno::Errno;
++use fcntl::{self, OFlag};
++use libc;
++use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
++use std::{ffi, ptr};
++use sys;
++
++#[cfg(target_os = "linux")]
++use libc::{dirent64 as dirent, readdir64_r as readdir_r};
++
++#[cfg(not(target_os = "linux"))]
++use libc::{dirent, readdir_r};
++
++/// An open directory.
++///
++/// This is a lower-level interface than `std::fs::ReadDir`. Notable differences:
++/// * can be opened from a file descriptor (as returned by `openat`, perhaps before knowing
++/// if the path represents a file or directory).
++/// * implements `AsRawFd`, so it can be passed to `fstat`, `openat`, etc.
++/// The file descriptor continues to be owned by the `Dir`, so callers must not keep a `RawFd`
++/// after the `Dir` is dropped.
++/// * can be iterated through multiple times without closing and reopening the file
++/// descriptor. Each iteration rewinds when finished.
++/// * returns entries for `.` (current directory) and `..` (parent directory).
++/// * returns entries' names as a `CStr` (no allocation or conversion beyond whatever libc
++/// does).
++#[derive(Clone, Debug, Eq, Hash, PartialEq)]
++pub struct Dir(
++ ptr::NonNull<libc::DIR>
++);
++
++impl Dir {
++ /// Opens the given path as with `fcntl::open`.
++ pub fn open<P: ?Sized + NixPath>(path: &P, oflag: OFlag,
++ mode: sys::stat::Mode) -> Result<Self> {
++ let fd = fcntl::open(path, oflag, mode)?;
++ Dir::from_fd(fd)
++ }
++
++ /// Opens the given path as with `fcntl::openat`.
++ pub fn openat<P: ?Sized + NixPath>(dirfd: RawFd, path: &P, oflag: OFlag,
++ mode: sys::stat::Mode) -> Result<Self> {
++ let fd = fcntl::openat(dirfd, path, oflag, mode)?;
++ Dir::from_fd(fd)
++ }
++
++ /// Converts from a descriptor-based object, closing the descriptor on success or failure.
++ #[inline]
++ pub fn from<F: IntoRawFd>(fd: F) -> Result<Self> {
++ Dir::from_fd(fd.into_raw_fd())
++ }
++
++ /// Converts from a file descriptor, closing it on success or failure.
++ pub fn from_fd(fd: RawFd) -> Result<Self> {
++ let d = unsafe { libc::fdopendir(fd) };
++ if d.is_null() {
++ let e = Error::last();
++ unsafe { libc::close(fd) };
++ return Err(e);
++ };
++ // Always guaranteed to be non-null by the previous check
++ Ok(Dir(ptr::NonNull::new(d).unwrap()))
++ }
++
++ /// Returns an iterator of `Result<Entry>` which rewinds when finished.
++ pub fn iter(&mut self) -> Iter {
++ Iter(self)
++ }
++}
++
++// `Dir` is not `Sync`. With the current implementation, it could be, but according to
++// https://www.gnu.org/software/libc/manual/html_node/Reading_002fClosing-Directory.html,
++// future versions of POSIX are likely to obsolete `readdir_r` and specify that it's unsafe to
++// call `readdir` simultaneously from multiple threads.
++//
++// `Dir` is safe to pass from one thread to another, as it's not reference-counted.
++unsafe impl Send for Dir {}
++
++impl AsRawFd for Dir {
++ fn as_raw_fd(&self) -> RawFd {
++ unsafe { libc::dirfd(self.0.as_ptr()) }
++ }
++}
++
++impl Drop for Dir {
++ fn drop(&mut self) {
++ unsafe { libc::closedir(self.0.as_ptr()) };
++ }
++}
++
++#[derive(Debug, Eq, Hash, PartialEq)]
++pub struct Iter<'d>(&'d mut Dir);
++
++impl<'d> Iterator for Iter<'d> {
++ type Item = Result<Entry>;
++
++ fn next(&mut self) -> Option<Self::Item> {
++ unsafe {
++ // Note: POSIX specifies that portable applications should dynamically allocate a
++ // buffer with room for a `d_name` field of size `pathconf(..., _PC_NAME_MAX)` plus 1
++ // for the NUL byte. It doesn't look like the std library does this; it just uses
++ // fixed-sized buffers (and libc's dirent seems to be sized so this is appropriate).
++ // Probably fine here too then.
++ let mut ent: Entry = Entry(::std::mem::uninitialized());
++ let mut result = ptr::null_mut();
++ if let Err(e) = Errno::result(readdir_r((self.0).0.as_ptr(), &mut ent.0, &mut result)) {
++ return Some(Err(e));
++ }
++ if result == ptr::null_mut() {
++ return None;
++ }
++ assert_eq!(result, &mut ent.0 as *mut dirent);
++ return Some(Ok(ent));
++ }
++ }
++}
++
++impl<'d> Drop for Iter<'d> {
++ fn drop(&mut self) {
++ unsafe { libc::rewinddir((self.0).0.as_ptr()) }
++ }
++}
++
++/// A directory entry, similar to `std::fs::DirEntry`.
++///
++/// Note that unlike the std version, this may represent the `.` or `..` entries.
++#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
++pub struct Entry(dirent);
++
++#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
++pub enum Type {
++ Fifo,
++ CharacterDevice,
++ Directory,
++ BlockDevice,
++ File,
++ Symlink,
++ Socket,
++}
++
++impl Entry {
++ /// Returns the inode number (`d_ino`) of the underlying `dirent`.
++ #[cfg(any(target_os = "android",
++ target_os = "emscripten",
++ target_os = "fuchsia",
++ target_os = "haiku",
++ target_os = "ios",
++ target_os = "l4re",
++ target_os = "linux",
++ target_os = "macos",
++ target_os = "solaris"))]
++ pub fn ino(&self) -> u64 {
++ self.0.d_ino as u64
++ }
++
++ /// Returns the inode number (`d_fileno`) of the underlying `dirent`.
++ #[cfg(not(any(target_os = "android",
++ target_os = "emscripten",
++ target_os = "fuchsia",
++ target_os = "haiku",
++ target_os = "ios",
++ target_os = "l4re",
++ target_os = "linux",
++ target_os = "macos",
++ target_os = "solaris")))]
++ pub fn ino(&self) -> u64 {
++ self.0.d_fileno as u64
++ }
++
++ /// Returns the bare file name of this directory entry without any other leading path component.
++ pub fn file_name(&self) -> &ffi::CStr {
++ unsafe { ::std::ffi::CStr::from_ptr(self.0.d_name.as_ptr()) }
++ }
++
++ /// Returns the type of this directory entry, if known.
++ ///
++ /// See platform `readdir(3)` or `dirent(5)` manpage for when the file type is known;
++ /// notably, some Linux filesystems don't implement this. The caller should use `stat` or
++ /// `fstat` if this returns `None`.
++ pub fn file_type(&self) -> Option<Type> {
++ match self.0.d_type {
++ libc::DT_FIFO => Some(Type::Fifo),
++ libc::DT_CHR => Some(Type::CharacterDevice),
++ libc::DT_DIR => Some(Type::Directory),
++ libc::DT_BLK => Some(Type::BlockDevice),
++ libc::DT_REG => Some(Type::File),
++ libc::DT_LNK => Some(Type::Symlink),
++ libc::DT_SOCK => Some(Type::Socket),
++ /* libc::DT_UNKNOWN | */ _ => None,
++ }
++ }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/errno.rs b/third_party/rust/nix-0.15.0/src/errno.rs
+new file mode 100644
+index 0000000000000..6a2447bc52675
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/errno.rs
+@@ -0,0 +1,1963 @@
++#[cfg(not(target_os = "dragonfly"))]
++use libc;
++use libc::{c_int, c_void};
++use std::{fmt, io, error};
++use {Error, Result};
++
++pub use self::consts::*;
++
++cfg_if! {
++ if #[cfg(any(target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos"))] {
++ unsafe fn errno_location() -> *mut c_int {
++ libc::__error()
++ }
++ } else if #[cfg(target_os = "dragonfly")] {
++ // DragonFly uses a thread-local errno variable, but #[thread_local] is
++ // feature-gated and not available in stable Rust as of this writing
++ // (Rust 1.21.0). We have to use a C extension to access it
++ // (src/errno_dragonfly.c).
++ //
++ // Tracking issue for `thread_local` stabilization:
++ //
++ // https://github.com/rust-lang/rust/issues/29594
++ //
++ // Once this becomes stable, we can remove build.rs,
++ // src/errno_dragonfly.c, and use:
++ //
++ // extern { #[thread_local] static errno: c_int; }
++ //
++ #[link(name="errno_dragonfly", kind="static")]
++ extern {
++ pub fn errno_location() -> *mut c_int;
++ }
++ } else if #[cfg(any(target_os = "android",
++ target_os = "netbsd",
++ target_os = "openbsd"))] {
++ unsafe fn errno_location() -> *mut c_int {
++ libc::__errno()
++ }
++ } else if #[cfg(target_os = "linux")] {
++ unsafe fn errno_location() -> *mut c_int {
++ libc::__errno_location()
++ }
++ }
++}
++
++/// Sets the platform-specific errno to no-error
++unsafe fn clear() -> () {
++ *errno_location() = 0;
++}
++
++/// Returns the platform-specific value of errno
++pub fn errno() -> i32 {
++ unsafe {
++ (*errno_location()) as i32
++ }
++}
++
++impl Errno {
++ pub fn last() -> Self {
++ last()
++ }
++
++ pub fn desc(self) -> &'static str {
++ desc(self)
++ }
++
++ pub fn from_i32(err: i32) -> Errno {
++ from_i32(err)
++ }
++
++ pub unsafe fn clear() -> () {
++ clear()
++ }
++
++ /// Returns `Ok(value)` if it does not contain the sentinel value. This
++ /// should not be used when `-1` is not the errno sentinel value.
++ pub fn result<S: ErrnoSentinel + PartialEq<S>>(value: S) -> Result<S> {
++ if value == S::sentinel() {
++ Err(Error::Sys(Self::last()))
++ } else {
++ Ok(value)
++ }
++ }
++}
++
++/// The sentinel value indicates that a function failed and more detailed
++/// information about the error can be found in `errno`
++pub trait ErrnoSentinel: Sized {
++ fn sentinel() -> Self;
++}
++
++impl ErrnoSentinel for isize {
++ fn sentinel() -> Self { -1 }
++}
++
++impl ErrnoSentinel for i32 {
++ fn sentinel() -> Self { -1 }
++}
++
++impl ErrnoSentinel for i64 {
++ fn sentinel() -> Self { -1 }
++}
++
++impl ErrnoSentinel for *mut c_void {
++ fn sentinel() -> Self { (-1 as isize) as *mut c_void }
++}
++
++impl ErrnoSentinel for libc::sighandler_t {
++ fn sentinel() -> Self { libc::SIG_ERR }
++}
++
++impl error::Error for Errno {
++ fn description(&self) -> &str {
++ self.desc()
++ }
++}
++
++impl fmt::Display for Errno {
++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++ write!(f, "{:?}: {}", self, self.desc())
++ }
++}
++
++impl From<Errno> for io::Error {
++ fn from(err: Errno) -> Self {
++ io::Error::from_raw_os_error(err as i32)
++ }
++}
++
++fn last() -> Errno {
++ Errno::from_i32(errno())
++}
++
++fn desc(errno: Errno) -> &'static str {
++ use self::Errno::*;
++ match errno {
++ UnknownErrno => "Unknown errno",
++ EPERM => "Operation not permitted",
++ ENOENT => "No such file or directory",
++ ESRCH => "No such process",
++ EINTR => "Interrupted system call",
++ EIO => "I/O error",
++ ENXIO => "No such device or address",
++ E2BIG => "Argument list too long",
++ ENOEXEC => "Exec format error",
++ EBADF => "Bad file number",
++ ECHILD => "No child processes",
++ EAGAIN => "Try again",
++ ENOMEM => "Out of memory",
++ EACCES => "Permission denied",
++ EFAULT => "Bad address",
++ ENOTBLK => "Block device required",
++ EBUSY => "Device or resource busy",
++ EEXIST => "File exists",
++ EXDEV => "Cross-device link",
++ ENODEV => "No such device",
++ ENOTDIR => "Not a directory",
++ EISDIR => "Is a directory",
++ EINVAL => "Invalid argument",
++ ENFILE => "File table overflow",
++ EMFILE => "Too many open files",
++ ENOTTY => "Not a typewriter",
++ ETXTBSY => "Text file busy",
++ EFBIG => "File too large",
++ ENOSPC => "No space left on device",
++ ESPIPE => "Illegal seek",
++ EROFS => "Read-only file system",
++ EMLINK => "Too many links",
++ EPIPE => "Broken pipe",
++ EDOM => "Math argument out of domain of func",
++ ERANGE => "Math result not representable",
++ EDEADLK => "Resource deadlock would occur",
++ ENAMETOOLONG => "File name too long",
++ ENOLCK => "No record locks available",
++ ENOSYS => "Function not implemented",
++ ENOTEMPTY => "Directory not empty",
++ ELOOP => "Too many symbolic links encountered",
++ ENOMSG => "No message of desired type",
++ EIDRM => "Identifier removed",
++ EINPROGRESS => "Operation now in progress",
++ EALREADY => "Operation already in progress",
++ ENOTSOCK => "Socket operation on non-socket",
++ EDESTADDRREQ => "Destination address required",
++ EMSGSIZE => "Message too long",
++ EPROTOTYPE => "Protocol wrong type for socket",
++ ENOPROTOOPT => "Protocol not available",
++ EPROTONOSUPPORT => "Protocol not supported",
++ ESOCKTNOSUPPORT => "Socket type not supported",
++ EPFNOSUPPORT => "Protocol family not supported",
++ EAFNOSUPPORT => "Address family not supported by protocol",
++ EADDRINUSE => "Address already in use",
++ EADDRNOTAVAIL => "Cannot assign requested address",
++ ENETDOWN => "Network is down",
++ ENETUNREACH => "Network is unreachable",
++ ENETRESET => "Network dropped connection because of reset",
++ ECONNABORTED => "Software caused connection abort",
++ ECONNRESET => "Connection reset by peer",
++ ENOBUFS => "No buffer space available",
++ EISCONN => "Transport endpoint is already connected",
++ ENOTCONN => "Transport endpoint is not connected",
++ ESHUTDOWN => "Cannot send after transport endpoint shutdown",
++ ETOOMANYREFS => "Too many references: cannot splice",
++ ETIMEDOUT => "Connection timed out",
++ ECONNREFUSED => "Connection refused",
++ EHOSTDOWN => "Host is down",
++ EHOSTUNREACH => "No route to host",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ ECHRNG => "Channel number out of range",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ EL2NSYNC => "Level 2 not synchronized",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ EL3HLT => "Level 3 halted",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ EL3RST => "Level 3 reset",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ ELNRNG => "Link number out of range",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ EUNATCH => "Protocol driver not attached",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ ENOCSI => "No CSI structure available",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ EL2HLT => "Level 2 halted",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ EBADE => "Invalid exchange",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ EBADR => "Invalid request descriptor",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ EXFULL => "Exchange full",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ ENOANO => "No anode",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ EBADRQC => "Invalid request code",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ EBADSLT => "Invalid slot",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ EBFONT => "Bad font file format",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ ENOSTR => "Device not a stream",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ ENODATA => "No data available",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ ETIME => "Timer expired",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ ENOSR => "Out of streams resources",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ ENONET => "Machine is not on the network",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ ENOPKG => "Package not installed",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ EREMOTE => "Object is remote",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ ENOLINK => "Link has been severed",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ EADV => "Advertise error",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ ESRMNT => "Srmount error",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ ECOMM => "Communication error on send",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ EPROTO => "Protocol error",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ EMULTIHOP => "Multihop attempted",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ EDOTDOT => "RFS specific error",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ EBADMSG => "Not a data message",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ EOVERFLOW => "Value too large for defined data type",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ ENOTUNIQ => "Name not unique on network",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ EBADFD => "File descriptor in bad state",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ EREMCHG => "Remote address changed",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ ELIBACC => "Can not access a needed shared library",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ ELIBBAD => "Accessing a corrupted shared library",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ ELIBSCN => ".lib section in a.out corrupted",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ ELIBMAX => "Attempting to link in too many shared libraries",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ ELIBEXEC => "Cannot exec a shared library directly",
++
++ #[cfg(any(target_os = "linux", target_os = "android", target_os = "openbsd"))]
++ EILSEQ => "Illegal byte sequence",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ ERESTART => "Interrupted system call should be restarted",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ ESTRPIPE => "Streams pipe error",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ EUSERS => "Too many users",
++
++ #[cfg(any(target_os = "linux", target_os = "android", target_os = "netbsd"))]
++ EOPNOTSUPP => "Operation not supported on transport endpoint",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ ESTALE => "Stale file handle",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ EUCLEAN => "Structure needs cleaning",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ ENOTNAM => "Not a XENIX named type file",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ ENAVAIL => "No XENIX semaphores available",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ EISNAM => "Is a named type file",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ EREMOTEIO => "Remote I/O error",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ EDQUOT => "Quota exceeded",
++
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "openbsd", target_os = "dragonfly"))]
++ ENOMEDIUM => "No medium found",
++
++ #[cfg(any(target_os = "linux", target_os = "android", target_os = "openbsd"))]
++ EMEDIUMTYPE => "Wrong medium type",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ ECANCELED => "Operation canceled",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ ENOKEY => "Required key not available",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ EKEYEXPIRED => "Key has expired",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ EKEYREVOKED => "Key has been revoked",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ EKEYREJECTED => "Key was rejected by service",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ EOWNERDEAD => "Owner died",
++
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ ENOTRECOVERABLE => "State not recoverable",
++
++ #[cfg(all(target_os = "linux", not(target_arch="mips")))]
++ ERFKILL => "Operation not possible due to RF-kill",
++
++ #[cfg(all(target_os = "linux", not(target_arch="mips")))]
++ EHWPOISON => "Memory page has hardware error",
++
++ #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++ EDOOFUS => "Programming error",
++
++ #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++ EMULTIHOP => "Multihop attempted",
++
++ #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++ ENOLINK => "Link has been severed",
++
++ #[cfg(target_os = "freebsd")]
++ ENOTCAPABLE => "Capabilities insufficient",
++
++ #[cfg(target_os = "freebsd")]
++ ECAPMODE => "Not permitted in capability mode",
++
++ #[cfg(any(target_os = "macos", target_os = "freebsd",
++ target_os = "dragonfly", target_os = "ios",
++ target_os = "openbsd", target_os = "netbsd"))]
++ ENEEDAUTH => "Need authenticator",
++
++ #[cfg(any(target_os = "macos", target_os = "freebsd",
++ target_os = "dragonfly", target_os = "ios",
++ target_os = "openbsd", target_os = "netbsd"))]
++ EOVERFLOW => "Value too large to be stored in data type",
++
++ #[cfg(any(target_os = "macos", target_os = "freebsd",
++ target_os = "dragonfly", target_os = "ios",
++ target_os = "netbsd"))]
++ EILSEQ => "Illegal byte sequence",
++
++ #[cfg(any(target_os = "macos", target_os = "freebsd",
++ target_os = "dragonfly", target_os = "ios",
++ target_os = "openbsd", target_os = "netbsd"))]
++ ENOATTR => "Attribute not found",
++
++ #[cfg(any(target_os = "macos", target_os = "freebsd",
++ target_os = "dragonfly", target_os = "ios",
++ target_os = "openbsd", target_os = "netbsd"))]
++ EBADMSG => "Bad message",
++
++ #[cfg(any(target_os = "macos", target_os = "freebsd",
++ target_os = "dragonfly", target_os = "ios",
++ target_os = "openbsd", target_os = "netbsd"))]
++ EPROTO => "Protocol error",
++
++ #[cfg(any(target_os = "macos", target_os = "freebsd",
++ target_os = "ios", target_os = "openbsd", ))]
++ ENOTRECOVERABLE => "State not recoverable",
++
++ #[cfg(any(target_os = "macos", target_os = "freebsd",
++ target_os = "ios", target_os = "openbsd"))]
++ EOWNERDEAD => "Previous owner died",
++
++ #[cfg(any(target_os = "macos", target_os = "freebsd",
++ target_os = "dragonfly", target_os = "ios",
++ target_os = "openbsd", target_os = "netbsd"))]
++ ENOTSUP => "Operation not supported",
++
++ #[cfg(any(target_os = "macos", target_os = "freebsd",
++ target_os = "dragonfly", target_os = "ios",
++ target_os = "openbsd", target_os = "netbsd"))]
++ EPROCLIM => "Too many processes",
++
++ #[cfg(any(target_os = "macos", target_os = "freebsd",
++ target_os = "dragonfly", target_os = "ios",
++ target_os = "openbsd", target_os = "netbsd"))]
++ EUSERS => "Too many users",
++
++ #[cfg(any(target_os = "macos", target_os = "freebsd",
++ target_os = "dragonfly", target_os = "ios",
++ target_os = "openbsd", target_os = "netbsd"))]
++ EDQUOT => "Disc quota exceeded",
++
++ #[cfg(any(target_os = "macos", target_os = "freebsd",
++ target_os = "dragonfly", target_os = "ios",
++ target_os = "openbsd", target_os = "netbsd"))]
++ ESTALE => "Stale NFS file handle",
++
++ #[cfg(any(target_os = "macos", target_os = "freebsd",
++ target_os = "dragonfly", target_os = "ios",
++ target_os = "openbsd", target_os = "netbsd"))]
++ EREMOTE => "Too many levels of remote in path",
++
++ #[cfg(any(target_os = "macos", target_os = "freebsd",
++ target_os = "dragonfly", target_os = "ios",
++ target_os = "openbsd", target_os = "netbsd"))]
++ EBADRPC => "RPC struct is bad",
++
++ #[cfg(any(target_os = "macos", target_os = "freebsd",
++ target_os = "dragonfly", target_os = "ios",
++ target_os = "openbsd", target_os = "netbsd"))]
++ ERPCMISMATCH => "RPC version wrong",
++
++ #[cfg(any(target_os = "macos", target_os = "freebsd",
++ target_os = "dragonfly", target_os = "ios",
++ target_os = "openbsd", target_os = "netbsd"))]
++ EPROGUNAVAIL => "RPC prog. not avail",
++
++ #[cfg(any(target_os = "macos", target_os = "freebsd",
++ target_os = "dragonfly", target_os = "ios",
++ target_os = "openbsd", target_os = "netbsd"))]
++ EPROGMISMATCH => "Program version wrong",
++
++ #[cfg(any(target_os = "macos", target_os = "freebsd",
++ target_os = "dragonfly", target_os = "ios",
++ target_os = "openbsd", target_os = "netbsd"))]
++ EPROCUNAVAIL => "Bad procedure for program",
++
++ #[cfg(any(target_os = "macos", target_os = "freebsd",
++ target_os = "dragonfly", target_os = "ios",
++ target_os = "openbsd", target_os = "netbsd"))]
++ EFTYPE => "Inappropriate file type or format",
++
++ #[cfg(any(target_os = "macos", target_os = "freebsd",
++ target_os = "dragonfly", target_os = "ios",
++ target_os = "openbsd", target_os = "netbsd"))]
++ EAUTH => "Authentication error",
++
++ #[cfg(any(target_os = "macos", target_os = "freebsd",
++ target_os = "dragonfly", target_os = "ios",
++ target_os = "openbsd", target_os = "netbsd"))]
++ ECANCELED => "Operation canceled",
++
++ #[cfg(any(target_os = "macos", target_os = "ios"))]
++ EPWROFF => "Device power is off",
++
++ #[cfg(any(target_os = "macos", target_os = "ios"))]
++ EDEVERR => "Device error, e.g. paper out",
++
++ #[cfg(any(target_os = "macos", target_os = "ios"))]
++ EBADEXEC => "Bad executable",
++
++ #[cfg(any(target_os = "macos", target_os = "ios"))]
++ EBADARCH => "Bad CPU type in executable",
++
++ #[cfg(any(target_os = "macos", target_os = "ios"))]
++ ESHLIBVERS => "Shared library version mismatch",
++
++ #[cfg(any(target_os = "macos", target_os = "ios"))]
++ EBADMACHO => "Malformed Macho file",
++
++ #[cfg(any(target_os = "macos", target_os = "ios", target_os = "netbsd"))]
++ EMULTIHOP => "Reserved",
++
++ #[cfg(any(target_os = "macos", target_os = "ios", target_os = "netbsd"))]
++ ENODATA => "No message available on STREAM",
++
++ #[cfg(any(target_os = "macos", target_os = "ios", target_os = "netbsd"))]
++ ENOLINK => "Reserved",
++
++ #[cfg(any(target_os = "macos", target_os = "ios", target_os = "netbsd"))]
++ ENOSR => "No STREAM resources",
++
++ #[cfg(any(target_os = "macos", target_os = "ios", target_os = "netbsd"))]
++ ENOSTR => "Not a STREAM",
++
++ #[cfg(any(target_os = "macos", target_os = "ios", target_os = "netbsd"))]
++ ETIME => "STREAM ioctl timeout",
++
++ #[cfg(any(target_os = "macos", target_os = "ios"))]
++ EOPNOTSUPP => "Operation not supported on socket",
++
++ #[cfg(any(target_os = "macos", target_os = "ios"))]
++ ENOPOLICY => "No such policy registered",
++
++ #[cfg(any(target_os = "macos", target_os = "ios"))]
++ EQFULL => "Interface output queue is full",
++
++ #[cfg(target_os = "openbsd")]
++ EOPNOTSUPP => "Operation not supported",
++
++ #[cfg(target_os = "openbsd")]
++ EIPSEC => "IPsec processing failure",
++
++ #[cfg(target_os = "dragonfly")]
++ EASYNC => "Async",
++ }
++}
++
++#[cfg(any(target_os = "linux", target_os = "android"))]
++mod consts {
++ use libc;
++
++ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
++ #[repr(i32)]
++ pub enum Errno {
++ UnknownErrno = 0,
++ EPERM = libc::EPERM,
++ ENOENT = libc::ENOENT,
++ ESRCH = libc::ESRCH,
++ EINTR = libc::EINTR,
++ EIO = libc::EIO,
++ ENXIO = libc::ENXIO,
++ E2BIG = libc::E2BIG,
++ ENOEXEC = libc::ENOEXEC,
++ EBADF = libc::EBADF,
++ ECHILD = libc::ECHILD,
++ EAGAIN = libc::EAGAIN,
++ ENOMEM = libc::ENOMEM,
++ EACCES = libc::EACCES,
++ EFAULT = libc::EFAULT,
++ ENOTBLK = libc::ENOTBLK,
++ EBUSY = libc::EBUSY,
++ EEXIST = libc::EEXIST,
++ EXDEV = libc::EXDEV,
++ ENODEV = libc::ENODEV,
++ ENOTDIR = libc::ENOTDIR,
++ EISDIR = libc::EISDIR,
++ EINVAL = libc::EINVAL,
++ ENFILE = libc::ENFILE,
++ EMFILE = libc::EMFILE,
++ ENOTTY = libc::ENOTTY,
++ ETXTBSY = libc::ETXTBSY,
++ EFBIG = libc::EFBIG,
++ ENOSPC = libc::ENOSPC,
++ ESPIPE = libc::ESPIPE,
++ EROFS = libc::EROFS,
++ EMLINK = libc::EMLINK,
++ EPIPE = libc::EPIPE,
++ EDOM = libc::EDOM,
++ ERANGE = libc::ERANGE,
++ EDEADLK = libc::EDEADLK,
++ ENAMETOOLONG = libc::ENAMETOOLONG,
++ ENOLCK = libc::ENOLCK,
++ ENOSYS = libc::ENOSYS,
++ ENOTEMPTY = libc::ENOTEMPTY,
++ ELOOP = libc::ELOOP,
++ ENOMSG = libc::ENOMSG,
++ EIDRM = libc::EIDRM,
++ ECHRNG = libc::ECHRNG,
++ EL2NSYNC = libc::EL2NSYNC,
++ EL3HLT = libc::EL3HLT,
++ EL3RST = libc::EL3RST,
++ ELNRNG = libc::ELNRNG,
++ EUNATCH = libc::EUNATCH,
++ ENOCSI = libc::ENOCSI,
++ EL2HLT = libc::EL2HLT,
++ EBADE = libc::EBADE,
++ EBADR = libc::EBADR,
++ EXFULL = libc::EXFULL,
++ ENOANO = libc::ENOANO,
++ EBADRQC = libc::EBADRQC,
++ EBADSLT = libc::EBADSLT,
++ EBFONT = libc::EBFONT,
++ ENOSTR = libc::ENOSTR,
++ ENODATA = libc::ENODATA,
++ ETIME = libc::ETIME,
++ ENOSR = libc::ENOSR,
++ ENONET = libc::ENONET,
++ ENOPKG = libc::ENOPKG,
++ EREMOTE = libc::EREMOTE,
++ ENOLINK = libc::ENOLINK,
++ EADV = libc::EADV,
++ ESRMNT = libc::ESRMNT,
++ ECOMM = libc::ECOMM,
++ EPROTO = libc::EPROTO,
++ EMULTIHOP = libc::EMULTIHOP,
++ EDOTDOT = libc::EDOTDOT,
++ EBADMSG = libc::EBADMSG,
++ EOVERFLOW = libc::EOVERFLOW,
++ ENOTUNIQ = libc::ENOTUNIQ,
++ EBADFD = libc::EBADFD,
++ EREMCHG = libc::EREMCHG,
++ ELIBACC = libc::ELIBACC,
++ ELIBBAD = libc::ELIBBAD,
++ ELIBSCN = libc::ELIBSCN,
++ ELIBMAX = libc::ELIBMAX,
++ ELIBEXEC = libc::ELIBEXEC,
++ EILSEQ = libc::EILSEQ,
++ ERESTART = libc::ERESTART,
++ ESTRPIPE = libc::ESTRPIPE,
++ EUSERS = libc::EUSERS,
++ ENOTSOCK = libc::ENOTSOCK,
++ EDESTADDRREQ = libc::EDESTADDRREQ,
++ EMSGSIZE = libc::EMSGSIZE,
++ EPROTOTYPE = libc::EPROTOTYPE,
++ ENOPROTOOPT = libc::ENOPROTOOPT,
++ EPROTONOSUPPORT = libc::EPROTONOSUPPORT,
++ ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT,
++ EOPNOTSUPP = libc::EOPNOTSUPP,
++ EPFNOSUPPORT = libc::EPFNOSUPPORT,
++ EAFNOSUPPORT = libc::EAFNOSUPPORT,
++ EADDRINUSE = libc::EADDRINUSE,
++ EADDRNOTAVAIL = libc::EADDRNOTAVAIL,
++ ENETDOWN = libc::ENETDOWN,
++ ENETUNREACH = libc::ENETUNREACH,
++ ENETRESET = libc::ENETRESET,
++ ECONNABORTED = libc::ECONNABORTED,
++ ECONNRESET = libc::ECONNRESET,
++ ENOBUFS = libc::ENOBUFS,
++ EISCONN = libc::EISCONN,
++ ENOTCONN = libc::ENOTCONN,
++ ESHUTDOWN = libc::ESHUTDOWN,
++ ETOOMANYREFS = libc::ETOOMANYREFS,
++ ETIMEDOUT = libc::ETIMEDOUT,
++ ECONNREFUSED = libc::ECONNREFUSED,
++ EHOSTDOWN = libc::EHOSTDOWN,
++ EHOSTUNREACH = libc::EHOSTUNREACH,
++ EALREADY = libc::EALREADY,
++ EINPROGRESS = libc::EINPROGRESS,
++ ESTALE = libc::ESTALE,
++ EUCLEAN = libc::EUCLEAN,
++ ENOTNAM = libc::ENOTNAM,
++ ENAVAIL = libc::ENAVAIL,
++ EISNAM = libc::EISNAM,
++ EREMOTEIO = libc::EREMOTEIO,
++ EDQUOT = libc::EDQUOT,
++ ENOMEDIUM = libc::ENOMEDIUM,
++ EMEDIUMTYPE = libc::EMEDIUMTYPE,
++ ECANCELED = libc::ECANCELED,
++ ENOKEY = libc::ENOKEY,
++ EKEYEXPIRED = libc::EKEYEXPIRED,
++ EKEYREVOKED = libc::EKEYREVOKED,
++ EKEYREJECTED = libc::EKEYREJECTED,
++ EOWNERDEAD = libc::EOWNERDEAD,
++ ENOTRECOVERABLE = libc::ENOTRECOVERABLE,
++ #[cfg(not(any(target_os = "android", target_arch="mips")))]
++ ERFKILL = libc::ERFKILL,
++ #[cfg(not(any(target_os = "android", target_arch="mips")))]
++ EHWPOISON = libc::EHWPOISON,
++ }
++
++ pub const EWOULDBLOCK: Errno = Errno::EAGAIN;
++ pub const EDEADLOCK: Errno = Errno::EDEADLK;
++ pub const ENOTSUP: Errno = Errno::EOPNOTSUPP;
++
++ pub fn from_i32(e: i32) -> Errno {
++ use self::Errno::*;
++
++ match e {
++ libc::EPERM => EPERM,
++ libc::ENOENT => ENOENT,
++ libc::ESRCH => ESRCH,
++ libc::EINTR => EINTR,
++ libc::EIO => EIO,
++ libc::ENXIO => ENXIO,
++ libc::E2BIG => E2BIG,
++ libc::ENOEXEC => ENOEXEC,
++ libc::EBADF => EBADF,
++ libc::ECHILD => ECHILD,
++ libc::EAGAIN => EAGAIN,
++ libc::ENOMEM => ENOMEM,
++ libc::EACCES => EACCES,
++ libc::EFAULT => EFAULT,
++ libc::ENOTBLK => ENOTBLK,
++ libc::EBUSY => EBUSY,
++ libc::EEXIST => EEXIST,
++ libc::EXDEV => EXDEV,
++ libc::ENODEV => ENODEV,
++ libc::ENOTDIR => ENOTDIR,
++ libc::EISDIR => EISDIR,
++ libc::EINVAL => EINVAL,
++ libc::ENFILE => ENFILE,
++ libc::EMFILE => EMFILE,
++ libc::ENOTTY => ENOTTY,
++ libc::ETXTBSY => ETXTBSY,
++ libc::EFBIG => EFBIG,
++ libc::ENOSPC => ENOSPC,
++ libc::ESPIPE => ESPIPE,
++ libc::EROFS => EROFS,
++ libc::EMLINK => EMLINK,
++ libc::EPIPE => EPIPE,
++ libc::EDOM => EDOM,
++ libc::ERANGE => ERANGE,
++ libc::EDEADLK => EDEADLK,
++ libc::ENAMETOOLONG => ENAMETOOLONG,
++ libc::ENOLCK => ENOLCK,
++ libc::ENOSYS => ENOSYS,
++ libc::ENOTEMPTY => ENOTEMPTY,
++ libc::ELOOP => ELOOP,
++ libc::ENOMSG => ENOMSG,
++ libc::EIDRM => EIDRM,
++ libc::ECHRNG => ECHRNG,
++ libc::EL2NSYNC => EL2NSYNC,
++ libc::EL3HLT => EL3HLT,
++ libc::EL3RST => EL3RST,
++ libc::ELNRNG => ELNRNG,
++ libc::EUNATCH => EUNATCH,
++ libc::ENOCSI => ENOCSI,
++ libc::EL2HLT => EL2HLT,
++ libc::EBADE => EBADE,
++ libc::EBADR => EBADR,
++ libc::EXFULL => EXFULL,
++ libc::ENOANO => ENOANO,
++ libc::EBADRQC => EBADRQC,
++ libc::EBADSLT => EBADSLT,
++ libc::EBFONT => EBFONT,
++ libc::ENOSTR => ENOSTR,
++ libc::ENODATA => ENODATA,
++ libc::ETIME => ETIME,
++ libc::ENOSR => ENOSR,
++ libc::ENONET => ENONET,
++ libc::ENOPKG => ENOPKG,
++ libc::EREMOTE => EREMOTE,
++ libc::ENOLINK => ENOLINK,
++ libc::EADV => EADV,
++ libc::ESRMNT => ESRMNT,
++ libc::ECOMM => ECOMM,
++ libc::EPROTO => EPROTO,
++ libc::EMULTIHOP => EMULTIHOP,
++ libc::EDOTDOT => EDOTDOT,
++ libc::EBADMSG => EBADMSG,
++ libc::EOVERFLOW => EOVERFLOW,
++ libc::ENOTUNIQ => ENOTUNIQ,
++ libc::EBADFD => EBADFD,
++ libc::EREMCHG => EREMCHG,
++ libc::ELIBACC => ELIBACC,
++ libc::ELIBBAD => ELIBBAD,
++ libc::ELIBSCN => ELIBSCN,
++ libc::ELIBMAX => ELIBMAX,
++ libc::ELIBEXEC => ELIBEXEC,
++ libc::EILSEQ => EILSEQ,
++ libc::ERESTART => ERESTART,
++ libc::ESTRPIPE => ESTRPIPE,
++ libc::EUSERS => EUSERS,
++ libc::ENOTSOCK => ENOTSOCK,
++ libc::EDESTADDRREQ => EDESTADDRREQ,
++ libc::EMSGSIZE => EMSGSIZE,
++ libc::EPROTOTYPE => EPROTOTYPE,
++ libc::ENOPROTOOPT => ENOPROTOOPT,
++ libc::EPROTONOSUPPORT => EPROTONOSUPPORT,
++ libc::ESOCKTNOSUPPORT => ESOCKTNOSUPPORT,
++ libc::EOPNOTSUPP => EOPNOTSUPP,
++ libc::EPFNOSUPPORT => EPFNOSUPPORT,
++ libc::EAFNOSUPPORT => EAFNOSUPPORT,
++ libc::EADDRINUSE => EADDRINUSE,
++ libc::EADDRNOTAVAIL => EADDRNOTAVAIL,
++ libc::ENETDOWN => ENETDOWN,
++ libc::ENETUNREACH => ENETUNREACH,
++ libc::ENETRESET => ENETRESET,
++ libc::ECONNABORTED => ECONNABORTED,
++ libc::ECONNRESET => ECONNRESET,
++ libc::ENOBUFS => ENOBUFS,
++ libc::EISCONN => EISCONN,
++ libc::ENOTCONN => ENOTCONN,
++ libc::ESHUTDOWN => ESHUTDOWN,
++ libc::ETOOMANYREFS => ETOOMANYREFS,
++ libc::ETIMEDOUT => ETIMEDOUT,
++ libc::ECONNREFUSED => ECONNREFUSED,
++ libc::EHOSTDOWN => EHOSTDOWN,
++ libc::EHOSTUNREACH => EHOSTUNREACH,
++ libc::EALREADY => EALREADY,
++ libc::EINPROGRESS => EINPROGRESS,
++ libc::ESTALE => ESTALE,
++ libc::EUCLEAN => EUCLEAN,
++ libc::ENOTNAM => ENOTNAM,
++ libc::ENAVAIL => ENAVAIL,
++ libc::EISNAM => EISNAM,
++ libc::EREMOTEIO => EREMOTEIO,
++ libc::EDQUOT => EDQUOT,
++ libc::ENOMEDIUM => ENOMEDIUM,
++ libc::EMEDIUMTYPE => EMEDIUMTYPE,
++ libc::ECANCELED => ECANCELED,
++ libc::ENOKEY => ENOKEY,
++ libc::EKEYEXPIRED => EKEYEXPIRED,
++ libc::EKEYREVOKED => EKEYREVOKED,
++ libc::EKEYREJECTED => EKEYREJECTED,
++ libc::EOWNERDEAD => EOWNERDEAD,
++ libc::ENOTRECOVERABLE => ENOTRECOVERABLE,
++ #[cfg(not(any(target_os = "android", target_arch="mips")))]
++ libc::ERFKILL => ERFKILL,
++ #[cfg(not(any(target_os = "android", target_arch="mips")))]
++ libc::EHWPOISON => EHWPOISON,
++ _ => UnknownErrno,
++ }
++ }
++}
++
++#[cfg(any(target_os = "macos", target_os = "ios"))]
++mod consts {
++ use libc;
++
++ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
++ #[repr(i32)]
++ pub enum Errno {
++ UnknownErrno = 0,
++ EPERM = libc::EPERM,
++ ENOENT = libc::ENOENT,
++ ESRCH = libc::ESRCH,
++ EINTR = libc::EINTR,
++ EIO = libc::EIO,
++ ENXIO = libc::ENXIO,
++ E2BIG = libc::E2BIG,
++ ENOEXEC = libc::ENOEXEC,
++ EBADF = libc::EBADF,
++ ECHILD = libc::ECHILD,
++ EDEADLK = libc::EDEADLK,
++ ENOMEM = libc::ENOMEM,
++ EACCES = libc::EACCES,
++ EFAULT = libc::EFAULT,
++ ENOTBLK = libc::ENOTBLK,
++ EBUSY = libc::EBUSY,
++ EEXIST = libc::EEXIST,
++ EXDEV = libc::EXDEV,
++ ENODEV = libc::ENODEV,
++ ENOTDIR = libc::ENOTDIR,
++ EISDIR = libc::EISDIR,
++ EINVAL = libc::EINVAL,
++ ENFILE = libc::ENFILE,
++ EMFILE = libc::EMFILE,
++ ENOTTY = libc::ENOTTY,
++ ETXTBSY = libc::ETXTBSY,
++ EFBIG = libc::EFBIG,
++ ENOSPC = libc::ENOSPC,
++ ESPIPE = libc::ESPIPE,
++ EROFS = libc::EROFS,
++ EMLINK = libc::EMLINK,
++ EPIPE = libc::EPIPE,
++ EDOM = libc::EDOM,
++ ERANGE = libc::ERANGE,
++ EAGAIN = libc::EAGAIN,
++ EINPROGRESS = libc::EINPROGRESS,
++ EALREADY = libc::EALREADY,
++ ENOTSOCK = libc::ENOTSOCK,
++ EDESTADDRREQ = libc::EDESTADDRREQ,
++ EMSGSIZE = libc::EMSGSIZE,
++ EPROTOTYPE = libc::EPROTOTYPE,
++ ENOPROTOOPT = libc::ENOPROTOOPT,
++ EPROTONOSUPPORT = libc::EPROTONOSUPPORT,
++ ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT,
++ ENOTSUP = libc::ENOTSUP,
++ EPFNOSUPPORT = libc::EPFNOSUPPORT,
++ EAFNOSUPPORT = libc::EAFNOSUPPORT,
++ EADDRINUSE = libc::EADDRINUSE,
++ EADDRNOTAVAIL = libc::EADDRNOTAVAIL,
++ ENETDOWN = libc::ENETDOWN,
++ ENETUNREACH = libc::ENETUNREACH,
++ ENETRESET = libc::ENETRESET,
++ ECONNABORTED = libc::ECONNABORTED,
++ ECONNRESET = libc::ECONNRESET,
++ ENOBUFS = libc::ENOBUFS,
++ EISCONN = libc::EISCONN,
++ ENOTCONN = libc::ENOTCONN,
++ ESHUTDOWN = libc::ESHUTDOWN,
++ ETOOMANYREFS = libc::ETOOMANYREFS,
++ ETIMEDOUT = libc::ETIMEDOUT,
++ ECONNREFUSED = libc::ECONNREFUSED,
++ ELOOP = libc::ELOOP,
++ ENAMETOOLONG = libc::ENAMETOOLONG,
++ EHOSTDOWN = libc::EHOSTDOWN,
++ EHOSTUNREACH = libc::EHOSTUNREACH,
++ ENOTEMPTY = libc::ENOTEMPTY,
++ EPROCLIM = libc::EPROCLIM,
++ EUSERS = libc::EUSERS,
++ EDQUOT = libc::EDQUOT,
++ ESTALE = libc::ESTALE,
++ EREMOTE = libc::EREMOTE,
++ EBADRPC = libc::EBADRPC,
++ ERPCMISMATCH = libc::ERPCMISMATCH,
++ EPROGUNAVAIL = libc::EPROGUNAVAIL,
++ EPROGMISMATCH = libc::EPROGMISMATCH,
++ EPROCUNAVAIL = libc::EPROCUNAVAIL,
++ ENOLCK = libc::ENOLCK,
++ ENOSYS = libc::ENOSYS,
++ EFTYPE = libc::EFTYPE,
++ EAUTH = libc::EAUTH,
++ ENEEDAUTH = libc::ENEEDAUTH,
++ EPWROFF = libc::EPWROFF,
++ EDEVERR = libc::EDEVERR,
++ EOVERFLOW = libc::EOVERFLOW,
++ EBADEXEC = libc::EBADEXEC,
++ EBADARCH = libc::EBADARCH,
++ ESHLIBVERS = libc::ESHLIBVERS,
++ EBADMACHO = libc::EBADMACHO,
++ ECANCELED = libc::ECANCELED,
++ EIDRM = libc::EIDRM,
++ ENOMSG = libc::ENOMSG,
++ EILSEQ = libc::EILSEQ,
++ ENOATTR = libc::ENOATTR,
++ EBADMSG = libc::EBADMSG,
++ EMULTIHOP = libc::EMULTIHOP,
++ ENODATA = libc::ENODATA,
++ ENOLINK = libc::ENOLINK,
++ ENOSR = libc::ENOSR,
++ ENOSTR = libc::ENOSTR,
++ EPROTO = libc::EPROTO,
++ ETIME = libc::ETIME,
++ EOPNOTSUPP = libc::EOPNOTSUPP,
++ ENOPOLICY = libc::ENOPOLICY,
++ ENOTRECOVERABLE = libc::ENOTRECOVERABLE,
++ EOWNERDEAD = libc::EOWNERDEAD,
++ EQFULL = libc::EQFULL,
++ }
++
++ pub const ELAST: Errno = Errno::EQFULL;
++ pub const EWOULDBLOCK: Errno = Errno::EAGAIN;
++ pub const EDEADLOCK: Errno = Errno::EDEADLK;
++
++ pub const EL2NSYNC: Errno = Errno::UnknownErrno;
++
++ pub fn from_i32(e: i32) -> Errno {
++ use self::Errno::*;
++
++ match e {
++ libc::EPERM => EPERM,
++ libc::ENOENT => ENOENT,
++ libc::ESRCH => ESRCH,
++ libc::EINTR => EINTR,
++ libc::EIO => EIO,
++ libc::ENXIO => ENXIO,
++ libc::E2BIG => E2BIG,
++ libc::ENOEXEC => ENOEXEC,
++ libc::EBADF => EBADF,
++ libc::ECHILD => ECHILD,
++ libc::EDEADLK => EDEADLK,
++ libc::ENOMEM => ENOMEM,
++ libc::EACCES => EACCES,
++ libc::EFAULT => EFAULT,
++ libc::ENOTBLK => ENOTBLK,
++ libc::EBUSY => EBUSY,
++ libc::EEXIST => EEXIST,
++ libc::EXDEV => EXDEV,
++ libc::ENODEV => ENODEV,
++ libc::ENOTDIR => ENOTDIR,
++ libc::EISDIR => EISDIR,
++ libc::EINVAL => EINVAL,
++ libc::ENFILE => ENFILE,
++ libc::EMFILE => EMFILE,
++ libc::ENOTTY => ENOTTY,
++ libc::ETXTBSY => ETXTBSY,
++ libc::EFBIG => EFBIG,
++ libc::ENOSPC => ENOSPC,
++ libc::ESPIPE => ESPIPE,
++ libc::EROFS => EROFS,
++ libc::EMLINK => EMLINK,
++ libc::EPIPE => EPIPE,
++ libc::EDOM => EDOM,
++ libc::ERANGE => ERANGE,
++ libc::EAGAIN => EAGAIN,
++ libc::EINPROGRESS => EINPROGRESS,
++ libc::EALREADY => EALREADY,
++ libc::ENOTSOCK => ENOTSOCK,
++ libc::EDESTADDRREQ => EDESTADDRREQ,
++ libc::EMSGSIZE => EMSGSIZE,
++ libc::EPROTOTYPE => EPROTOTYPE,
++ libc::ENOPROTOOPT => ENOPROTOOPT,
++ libc::EPROTONOSUPPORT => EPROTONOSUPPORT,
++ libc::ESOCKTNOSUPPORT => ESOCKTNOSUPPORT,
++ libc::ENOTSUP => ENOTSUP,
++ libc::EPFNOSUPPORT => EPFNOSUPPORT,
++ libc::EAFNOSUPPORT => EAFNOSUPPORT,
++ libc::EADDRINUSE => EADDRINUSE,
++ libc::EADDRNOTAVAIL => EADDRNOTAVAIL,
++ libc::ENETDOWN => ENETDOWN,
++ libc::ENETUNREACH => ENETUNREACH,
++ libc::ENETRESET => ENETRESET,
++ libc::ECONNABORTED => ECONNABORTED,
++ libc::ECONNRESET => ECONNRESET,
++ libc::ENOBUFS => ENOBUFS,
++ libc::EISCONN => EISCONN,
++ libc::ENOTCONN => ENOTCONN,
++ libc::ESHUTDOWN => ESHUTDOWN,
++ libc::ETOOMANYREFS => ETOOMANYREFS,
++ libc::ETIMEDOUT => ETIMEDOUT,
++ libc::ECONNREFUSED => ECONNREFUSED,
++ libc::ELOOP => ELOOP,
++ libc::ENAMETOOLONG => ENAMETOOLONG,
++ libc::EHOSTDOWN => EHOSTDOWN,
++ libc::EHOSTUNREACH => EHOSTUNREACH,
++ libc::ENOTEMPTY => ENOTEMPTY,
++ libc::EPROCLIM => EPROCLIM,
++ libc::EUSERS => EUSERS,
++ libc::EDQUOT => EDQUOT,
++ libc::ESTALE => ESTALE,
++ libc::EREMOTE => EREMOTE,
++ libc::EBADRPC => EBADRPC,
++ libc::ERPCMISMATCH => ERPCMISMATCH,
++ libc::EPROGUNAVAIL => EPROGUNAVAIL,
++ libc::EPROGMISMATCH => EPROGMISMATCH,
++ libc::EPROCUNAVAIL => EPROCUNAVAIL,
++ libc::ENOLCK => ENOLCK,
++ libc::ENOSYS => ENOSYS,
++ libc::EFTYPE => EFTYPE,
++ libc::EAUTH => EAUTH,
++ libc::ENEEDAUTH => ENEEDAUTH,
++ libc::EPWROFF => EPWROFF,
++ libc::EDEVERR => EDEVERR,
++ libc::EOVERFLOW => EOVERFLOW,
++ libc::EBADEXEC => EBADEXEC,
++ libc::EBADARCH => EBADARCH,
++ libc::ESHLIBVERS => ESHLIBVERS,
++ libc::EBADMACHO => EBADMACHO,
++ libc::ECANCELED => ECANCELED,
++ libc::EIDRM => EIDRM,
++ libc::ENOMSG => ENOMSG,
++ libc::EILSEQ => EILSEQ,
++ libc::ENOATTR => ENOATTR,
++ libc::EBADMSG => EBADMSG,
++ libc::EMULTIHOP => EMULTIHOP,
++ libc::ENODATA => ENODATA,
++ libc::ENOLINK => ENOLINK,
++ libc::ENOSR => ENOSR,
++ libc::ENOSTR => ENOSTR,
++ libc::EPROTO => EPROTO,
++ libc::ETIME => ETIME,
++ libc::EOPNOTSUPP => EOPNOTSUPP,
++ libc::ENOPOLICY => ENOPOLICY,
++ libc::ENOTRECOVERABLE => ENOTRECOVERABLE,
++ libc::EOWNERDEAD => EOWNERDEAD,
++ libc::EQFULL => EQFULL,
++ _ => UnknownErrno,
++ }
++ }
++}
++
++#[cfg(target_os = "freebsd")]
++mod consts {
++ use libc;
++
++ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
++ #[repr(i32)]
++ pub enum Errno {
++ UnknownErrno = 0,
++ EPERM = libc::EPERM,
++ ENOENT = libc::ENOENT,
++ ESRCH = libc::ESRCH,
++ EINTR = libc::EINTR,
++ EIO = libc::EIO,
++ ENXIO = libc::ENXIO,
++ E2BIG = libc::E2BIG,
++ ENOEXEC = libc::ENOEXEC,
++ EBADF = libc::EBADF,
++ ECHILD = libc::ECHILD,
++ EDEADLK = libc::EDEADLK,
++ ENOMEM = libc::ENOMEM,
++ EACCES = libc::EACCES,
++ EFAULT = libc::EFAULT,
++ ENOTBLK = libc::ENOTBLK,
++ EBUSY = libc::EBUSY,
++ EEXIST = libc::EEXIST,
++ EXDEV = libc::EXDEV,
++ ENODEV = libc::ENODEV,
++ ENOTDIR = libc::ENOTDIR,
++ EISDIR = libc::EISDIR,
++ EINVAL = libc::EINVAL,
++ ENFILE = libc::ENFILE,
++ EMFILE = libc::EMFILE,
++ ENOTTY = libc::ENOTTY,
++ ETXTBSY = libc::ETXTBSY,
++ EFBIG = libc::EFBIG,
++ ENOSPC = libc::ENOSPC,
++ ESPIPE = libc::ESPIPE,
++ EROFS = libc::EROFS,
++ EMLINK = libc::EMLINK,
++ EPIPE = libc::EPIPE,
++ EDOM = libc::EDOM,
++ ERANGE = libc::ERANGE,
++ EAGAIN = libc::EAGAIN,
++ EINPROGRESS = libc::EINPROGRESS,
++ EALREADY = libc::EALREADY,
++ ENOTSOCK = libc::ENOTSOCK,
++ EDESTADDRREQ = libc::EDESTADDRREQ,
++ EMSGSIZE = libc::EMSGSIZE,
++ EPROTOTYPE = libc::EPROTOTYPE,
++ ENOPROTOOPT = libc::ENOPROTOOPT,
++ EPROTONOSUPPORT = libc::EPROTONOSUPPORT,
++ ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT,
++ ENOTSUP = libc::ENOTSUP,
++ EPFNOSUPPORT = libc::EPFNOSUPPORT,
++ EAFNOSUPPORT = libc::EAFNOSUPPORT,
++ EADDRINUSE = libc::EADDRINUSE,
++ EADDRNOTAVAIL = libc::EADDRNOTAVAIL,
++ ENETDOWN = libc::ENETDOWN,
++ ENETUNREACH = libc::ENETUNREACH,
++ ENETRESET = libc::ENETRESET,
++ ECONNABORTED = libc::ECONNABORTED,
++ ECONNRESET = libc::ECONNRESET,
++ ENOBUFS = libc::ENOBUFS,
++ EISCONN = libc::EISCONN,
++ ENOTCONN = libc::ENOTCONN,
++ ESHUTDOWN = libc::ESHUTDOWN,
++ ETOOMANYREFS = libc::ETOOMANYREFS,
++ ETIMEDOUT = libc::ETIMEDOUT,
++ ECONNREFUSED = libc::ECONNREFUSED,
++ ELOOP = libc::ELOOP,
++ ENAMETOOLONG = libc::ENAMETOOLONG,
++ EHOSTDOWN = libc::EHOSTDOWN,
++ EHOSTUNREACH = libc::EHOSTUNREACH,
++ ENOTEMPTY = libc::ENOTEMPTY,
++ EPROCLIM = libc::EPROCLIM,
++ EUSERS = libc::EUSERS,
++ EDQUOT = libc::EDQUOT,
++ ESTALE = libc::ESTALE,
++ EREMOTE = libc::EREMOTE,
++ EBADRPC = libc::EBADRPC,
++ ERPCMISMATCH = libc::ERPCMISMATCH,
++ EPROGUNAVAIL = libc::EPROGUNAVAIL,
++ EPROGMISMATCH = libc::EPROGMISMATCH,
++ EPROCUNAVAIL = libc::EPROCUNAVAIL,
++ ENOLCK = libc::ENOLCK,
++ ENOSYS = libc::ENOSYS,
++ EFTYPE = libc::EFTYPE,
++ EAUTH = libc::EAUTH,
++ ENEEDAUTH = libc::ENEEDAUTH,
++ EIDRM = libc::EIDRM,
++ ENOMSG = libc::ENOMSG,
++ EOVERFLOW = libc::EOVERFLOW,
++ ECANCELED = libc::ECANCELED,
++ EILSEQ = libc::EILSEQ,
++ ENOATTR = libc::ENOATTR,
++ EDOOFUS = libc::EDOOFUS,
++ EBADMSG = libc::EBADMSG,
++ EMULTIHOP = libc::EMULTIHOP,
++ ENOLINK = libc::ENOLINK,
++ EPROTO = libc::EPROTO,
++ ENOTCAPABLE = libc::ENOTCAPABLE,
++ ECAPMODE = libc::ECAPMODE,
++ ENOTRECOVERABLE = libc::ENOTRECOVERABLE,
++ EOWNERDEAD = libc::EOWNERDEAD,
++ }
++
++ pub const ELAST: Errno = Errno::EOWNERDEAD;
++ pub const EWOULDBLOCK: Errno = Errno::EAGAIN;
++ pub const EDEADLOCK: Errno = Errno::EDEADLK;
++
++ pub const EL2NSYNC: Errno = Errno::UnknownErrno;
++
++ pub fn from_i32(e: i32) -> Errno {
++ use self::Errno::*;
++
++ match e {
++ libc::EPERM => EPERM,
++ libc::ENOENT => ENOENT,
++ libc::ESRCH => ESRCH,
++ libc::EINTR => EINTR,
++ libc::EIO => EIO,
++ libc::ENXIO => ENXIO,
++ libc::E2BIG => E2BIG,
++ libc::ENOEXEC => ENOEXEC,
++ libc::EBADF => EBADF,
++ libc::ECHILD => ECHILD,
++ libc::EDEADLK => EDEADLK,
++ libc::ENOMEM => ENOMEM,
++ libc::EACCES => EACCES,
++ libc::EFAULT => EFAULT,
++ libc::ENOTBLK => ENOTBLK,
++ libc::EBUSY => EBUSY,
++ libc::EEXIST => EEXIST,
++ libc::EXDEV => EXDEV,
++ libc::ENODEV => ENODEV,
++ libc::ENOTDIR => ENOTDIR,
++ libc::EISDIR => EISDIR,
++ libc::EINVAL => EINVAL,
++ libc::ENFILE => ENFILE,
++ libc::EMFILE => EMFILE,
++ libc::ENOTTY => ENOTTY,
++ libc::ETXTBSY => ETXTBSY,
++ libc::EFBIG => EFBIG,
++ libc::ENOSPC => ENOSPC,
++ libc::ESPIPE => ESPIPE,
++ libc::EROFS => EROFS,
++ libc::EMLINK => EMLINK,
++ libc::EPIPE => EPIPE,
++ libc::EDOM => EDOM,
++ libc::ERANGE => ERANGE,
++ libc::EAGAIN => EAGAIN,
++ libc::EINPROGRESS => EINPROGRESS,
++ libc::EALREADY => EALREADY,
++ libc::ENOTSOCK => ENOTSOCK,
++ libc::EDESTADDRREQ => EDESTADDRREQ,
++ libc::EMSGSIZE => EMSGSIZE,
++ libc::EPROTOTYPE => EPROTOTYPE,
++ libc::ENOPROTOOPT => ENOPROTOOPT,
++ libc::EPROTONOSUPPORT => EPROTONOSUPPORT,
++ libc::ESOCKTNOSUPPORT => ESOCKTNOSUPPORT,
++ libc::ENOTSUP => ENOTSUP,
++ libc::EPFNOSUPPORT => EPFNOSUPPORT,
++ libc::EAFNOSUPPORT => EAFNOSUPPORT,
++ libc::EADDRINUSE => EADDRINUSE,
++ libc::EADDRNOTAVAIL => EADDRNOTAVAIL,
++ libc::ENETDOWN => ENETDOWN,
++ libc::ENETUNREACH => ENETUNREACH,
++ libc::ENETRESET => ENETRESET,
++ libc::ECONNABORTED => ECONNABORTED,
++ libc::ECONNRESET => ECONNRESET,
++ libc::ENOBUFS => ENOBUFS,
++ libc::EISCONN => EISCONN,
++ libc::ENOTCONN => ENOTCONN,
++ libc::ESHUTDOWN => ESHUTDOWN,
++ libc::ETOOMANYREFS => ETOOMANYREFS,
++ libc::ETIMEDOUT => ETIMEDOUT,
++ libc::ECONNREFUSED => ECONNREFUSED,
++ libc::ELOOP => ELOOP,
++ libc::ENAMETOOLONG => ENAMETOOLONG,
++ libc::EHOSTDOWN => EHOSTDOWN,
++ libc::EHOSTUNREACH => EHOSTUNREACH,
++ libc::ENOTEMPTY => ENOTEMPTY,
++ libc::EPROCLIM => EPROCLIM,
++ libc::EUSERS => EUSERS,
++ libc::EDQUOT => EDQUOT,
++ libc::ESTALE => ESTALE,
++ libc::EREMOTE => EREMOTE,
++ libc::EBADRPC => EBADRPC,
++ libc::ERPCMISMATCH => ERPCMISMATCH,
++ libc::EPROGUNAVAIL => EPROGUNAVAIL,
++ libc::EPROGMISMATCH => EPROGMISMATCH,
++ libc::EPROCUNAVAIL => EPROCUNAVAIL,
++ libc::ENOLCK => ENOLCK,
++ libc::ENOSYS => ENOSYS,
++ libc::EFTYPE => EFTYPE,
++ libc::EAUTH => EAUTH,
++ libc::ENEEDAUTH => ENEEDAUTH,
++ libc::EIDRM => EIDRM,
++ libc::ENOMSG => ENOMSG,
++ libc::EOVERFLOW => EOVERFLOW,
++ libc::ECANCELED => ECANCELED,
++ libc::EILSEQ => EILSEQ,
++ libc::ENOATTR => ENOATTR,
++ libc::EDOOFUS => EDOOFUS,
++ libc::EBADMSG => EBADMSG,
++ libc::EMULTIHOP => EMULTIHOP,
++ libc::ENOLINK => ENOLINK,
++ libc::EPROTO => EPROTO,
++ libc::ENOTCAPABLE => ENOTCAPABLE,
++ libc::ECAPMODE => ECAPMODE,
++ libc::ENOTRECOVERABLE => ENOTRECOVERABLE,
++ libc::EOWNERDEAD => EOWNERDEAD,
++ _ => UnknownErrno,
++ }
++ }
++}
++
++
++#[cfg(target_os = "dragonfly")]
++mod consts {
++ use libc;
++
++ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
++ #[repr(i32)]
++ pub enum Errno {
++ UnknownErrno = 0,
++ EPERM = libc::EPERM,
++ ENOENT = libc::ENOENT,
++ ESRCH = libc::ESRCH,
++ EINTR = libc::EINTR,
++ EIO = libc::EIO,
++ ENXIO = libc::ENXIO,
++ E2BIG = libc::E2BIG,
++ ENOEXEC = libc::ENOEXEC,
++ EBADF = libc::EBADF,
++ ECHILD = libc::ECHILD,
++ EDEADLK = libc::EDEADLK,
++ ENOMEM = libc::ENOMEM,
++ EACCES = libc::EACCES,
++ EFAULT = libc::EFAULT,
++ ENOTBLK = libc::ENOTBLK,
++ EBUSY = libc::EBUSY,
++ EEXIST = libc::EEXIST,
++ EXDEV = libc::EXDEV,
++ ENODEV = libc::ENODEV,
++ ENOTDIR = libc::ENOTDIR,
++ EISDIR = libc::EISDIR,
++ EINVAL = libc::EINVAL,
++ ENFILE = libc::ENFILE,
++ EMFILE = libc::EMFILE,
++ ENOTTY = libc::ENOTTY,
++ ETXTBSY = libc::ETXTBSY,
++ EFBIG = libc::EFBIG,
++ ENOSPC = libc::ENOSPC,
++ ESPIPE = libc::ESPIPE,
++ EROFS = libc::EROFS,
++ EMLINK = libc::EMLINK,
++ EPIPE = libc::EPIPE,
++ EDOM = libc::EDOM,
++ ERANGE = libc::ERANGE,
++ EAGAIN = libc::EAGAIN,
++ EINPROGRESS = libc::EINPROGRESS,
++ EALREADY = libc::EALREADY,
++ ENOTSOCK = libc::ENOTSOCK,
++ EDESTADDRREQ = libc::EDESTADDRREQ,
++ EMSGSIZE = libc::EMSGSIZE,
++ EPROTOTYPE = libc::EPROTOTYPE,
++ ENOPROTOOPT = libc::ENOPROTOOPT,
++ EPROTONOSUPPORT = libc::EPROTONOSUPPORT,
++ ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT,
++ ENOTSUP = libc::ENOTSUP,
++ EPFNOSUPPORT = libc::EPFNOSUPPORT,
++ EAFNOSUPPORT = libc::EAFNOSUPPORT,
++ EADDRINUSE = libc::EADDRINUSE,
++ EADDRNOTAVAIL = libc::EADDRNOTAVAIL,
++ ENETDOWN = libc::ENETDOWN,
++ ENETUNREACH = libc::ENETUNREACH,
++ ENETRESET = libc::ENETRESET,
++ ECONNABORTED = libc::ECONNABORTED,
++ ECONNRESET = libc::ECONNRESET,
++ ENOBUFS = libc::ENOBUFS,
++ EISCONN = libc::EISCONN,
++ ENOTCONN = libc::ENOTCONN,
++ ESHUTDOWN = libc::ESHUTDOWN,
++ ETOOMANYREFS = libc::ETOOMANYREFS,
++ ETIMEDOUT = libc::ETIMEDOUT,
++ ECONNREFUSED = libc::ECONNREFUSED,
++ ELOOP = libc::ELOOP,
++ ENAMETOOLONG = libc::ENAMETOOLONG,
++ EHOSTDOWN = libc::EHOSTDOWN,
++ EHOSTUNREACH = libc::EHOSTUNREACH,
++ ENOTEMPTY = libc::ENOTEMPTY,
++ EPROCLIM = libc::EPROCLIM,
++ EUSERS = libc::EUSERS,
++ EDQUOT = libc::EDQUOT,
++ ESTALE = libc::ESTALE,
++ EREMOTE = libc::EREMOTE,
++ EBADRPC = libc::EBADRPC,
++ ERPCMISMATCH = libc::ERPCMISMATCH,
++ EPROGUNAVAIL = libc::EPROGUNAVAIL,
++ EPROGMISMATCH = libc::EPROGMISMATCH,
++ EPROCUNAVAIL = libc::EPROCUNAVAIL,
++ ENOLCK = libc::ENOLCK,
++ ENOSYS = libc::ENOSYS,
++ EFTYPE = libc::EFTYPE,
++ EAUTH = libc::EAUTH,
++ ENEEDAUTH = libc::ENEEDAUTH,
++ EIDRM = libc::EIDRM,
++ ENOMSG = libc::ENOMSG,
++ EOVERFLOW = libc::EOVERFLOW,
++ ECANCELED = libc::ECANCELED,
++ EILSEQ = libc::EILSEQ,
++ ENOATTR = libc::ENOATTR,
++ EDOOFUS = libc::EDOOFUS,
++ EBADMSG = libc::EBADMSG,
++ EMULTIHOP = libc::EMULTIHOP,
++ ENOLINK = libc::ENOLINK,
++ EPROTO = libc::EPROTO,
++ ENOMEDIUM = libc::ENOMEDIUM,
++ EASYNC = libc::EASYNC,
++ }
++
++ pub const ELAST: Errno = Errno::EASYNC;
++ pub const EWOULDBLOCK: Errno = Errno::EAGAIN;
++ pub const EDEADLOCK: Errno = Errno::EDEADLK;
++ pub const EOPNOTSUPP: Errno = Errno::ENOTSUP;
++
++ pub const EL2NSYNC: Errno = Errno::UnknownErrno;
++
++ pub fn from_i32(e: i32) -> Errno {
++ use self::Errno::*;
++
++ match e {
++ libc::EPERM => EPERM,
++ libc::ENOENT => ENOENT,
++ libc::ESRCH => ESRCH,
++ libc::EINTR => EINTR,
++ libc::EIO => EIO,
++ libc::ENXIO => ENXIO,
++ libc::E2BIG => E2BIG,
++ libc::ENOEXEC => ENOEXEC,
++ libc::EBADF => EBADF,
++ libc::ECHILD => ECHILD,
++ libc::EDEADLK => EDEADLK,
++ libc::ENOMEM => ENOMEM,
++ libc::EACCES => EACCES,
++ libc::EFAULT => EFAULT,
++ libc::ENOTBLK => ENOTBLK,
++ libc::EBUSY => EBUSY,
++ libc::EEXIST => EEXIST,
++ libc::EXDEV => EXDEV,
++ libc::ENODEV => ENODEV,
++ libc::ENOTDIR => ENOTDIR,
++ libc::EISDIR=> EISDIR,
++ libc::EINVAL => EINVAL,
++ libc::ENFILE => ENFILE,
++ libc::EMFILE => EMFILE,
++ libc::ENOTTY => ENOTTY,
++ libc::ETXTBSY => ETXTBSY,
++ libc::EFBIG => EFBIG,
++ libc::ENOSPC => ENOSPC,
++ libc::ESPIPE => ESPIPE,
++ libc::EROFS => EROFS,
++ libc::EMLINK => EMLINK,
++ libc::EPIPE => EPIPE,
++ libc::EDOM => EDOM,
++ libc::ERANGE => ERANGE,
++ libc::EAGAIN => EAGAIN,
++ libc::EINPROGRESS => EINPROGRESS,
++ libc::EALREADY => EALREADY,
++ libc::ENOTSOCK => ENOTSOCK,
++ libc::EDESTADDRREQ => EDESTADDRREQ,
++ libc::EMSGSIZE => EMSGSIZE,
++ libc::EPROTOTYPE => EPROTOTYPE,
++ libc::ENOPROTOOPT => ENOPROTOOPT,
++ libc::EPROTONOSUPPORT => EPROTONOSUPPORT,
++ libc::ESOCKTNOSUPPORT => ESOCKTNOSUPPORT,
++ libc::ENOTSUP => ENOTSUP,
++ libc::EPFNOSUPPORT => EPFNOSUPPORT,
++ libc::EAFNOSUPPORT => EAFNOSUPPORT,
++ libc::EADDRINUSE => EADDRINUSE,
++ libc::EADDRNOTAVAIL => EADDRNOTAVAIL,
++ libc::ENETDOWN => ENETDOWN,
++ libc::ENETUNREACH => ENETUNREACH,
++ libc::ENETRESET => ENETRESET,
++ libc::ECONNABORTED => ECONNABORTED,
++ libc::ECONNRESET => ECONNRESET,
++ libc::ENOBUFS => ENOBUFS,
++ libc::EISCONN => EISCONN,
++ libc::ENOTCONN => ENOTCONN,
++ libc::ESHUTDOWN => ESHUTDOWN,
++ libc::ETOOMANYREFS => ETOOMANYREFS,
++ libc::ETIMEDOUT => ETIMEDOUT,
++ libc::ECONNREFUSED => ECONNREFUSED,
++ libc::ELOOP => ELOOP,
++ libc::ENAMETOOLONG => ENAMETOOLONG,
++ libc::EHOSTDOWN => EHOSTDOWN,
++ libc::EHOSTUNREACH => EHOSTUNREACH,
++ libc::ENOTEMPTY => ENOTEMPTY,
++ libc::EPROCLIM => EPROCLIM,
++ libc::EUSERS => EUSERS,
++ libc::EDQUOT => EDQUOT,
++ libc::ESTALE => ESTALE,
++ libc::EREMOTE => EREMOTE,
++ libc::EBADRPC => EBADRPC,
++ libc::ERPCMISMATCH => ERPCMISMATCH,
++ libc::EPROGUNAVAIL => EPROGUNAVAIL,
++ libc::EPROGMISMATCH => EPROGMISMATCH,
++ libc::EPROCUNAVAIL => EPROCUNAVAIL,
++ libc::ENOLCK => ENOLCK,
++ libc::ENOSYS => ENOSYS,
++ libc::EFTYPE => EFTYPE,
++ libc::EAUTH => EAUTH,
++ libc::ENEEDAUTH => ENEEDAUTH,
++ libc::EIDRM => EIDRM,
++ libc::ENOMSG => ENOMSG,
++ libc::EOVERFLOW => EOVERFLOW,
++ libc::ECANCELED => ECANCELED,
++ libc::EILSEQ => EILSEQ,
++ libc::ENOATTR => ENOATTR,
++ libc::EDOOFUS => EDOOFUS,
++ libc::EBADMSG => EBADMSG,
++ libc::EMULTIHOP => EMULTIHOP,
++ libc::ENOLINK => ENOLINK,
++ libc::EPROTO => EPROTO,
++ libc::ENOMEDIUM => ENOMEDIUM,
++ libc::EASYNC => EASYNC,
++ _ => UnknownErrno,
++ }
++ }
++}
++
++
++#[cfg(target_os = "openbsd")]
++mod consts {
++ use libc;
++
++ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
++ #[repr(i32)]
++ pub enum Errno {
++ UnknownErrno = 0,
++ EPERM = libc::EPERM,
++ ENOENT = libc::ENOENT,
++ ESRCH = libc::ESRCH,
++ EINTR = libc::EINTR,
++ EIO = libc::EIO,
++ ENXIO = libc::ENXIO,
++ E2BIG = libc::E2BIG,
++ ENOEXEC = libc::ENOEXEC,
++ EBADF = libc::EBADF,
++ ECHILD = libc::ECHILD,
++ EDEADLK = libc::EDEADLK,
++ ENOMEM = libc::ENOMEM,
++ EACCES = libc::EACCES,
++ EFAULT = libc::EFAULT,
++ ENOTBLK = libc::ENOTBLK,
++ EBUSY = libc::EBUSY,
++ EEXIST = libc::EEXIST,
++ EXDEV = libc::EXDEV,
++ ENODEV = libc::ENODEV,
++ ENOTDIR = libc::ENOTDIR,
++ EISDIR = libc::EISDIR,
++ EINVAL = libc::EINVAL,
++ ENFILE = libc::ENFILE,
++ EMFILE = libc::EMFILE,
++ ENOTTY = libc::ENOTTY,
++ ETXTBSY = libc::ETXTBSY,
++ EFBIG = libc::EFBIG,
++ ENOSPC = libc::ENOSPC,
++ ESPIPE = libc::ESPIPE,
++ EROFS = libc::EROFS,
++ EMLINK = libc::EMLINK,
++ EPIPE = libc::EPIPE,
++ EDOM = libc::EDOM,
++ ERANGE = libc::ERANGE,
++ EAGAIN = libc::EAGAIN,
++ EINPROGRESS = libc::EINPROGRESS,
++ EALREADY = libc::EALREADY,
++ ENOTSOCK = libc::ENOTSOCK,
++ EDESTADDRREQ = libc::EDESTADDRREQ,
++ EMSGSIZE = libc::EMSGSIZE,
++ EPROTOTYPE = libc::EPROTOTYPE,
++ ENOPROTOOPT = libc::ENOPROTOOPT,
++ EPROTONOSUPPORT = libc::EPROTONOSUPPORT,
++ ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT,
++ EOPNOTSUPP = libc::EOPNOTSUPP,
++ EPFNOSUPPORT = libc::EPFNOSUPPORT,
++ EAFNOSUPPORT = libc::EAFNOSUPPORT,
++ EADDRINUSE = libc::EADDRINUSE,
++ EADDRNOTAVAIL = libc::EADDRNOTAVAIL,
++ ENETDOWN = libc::ENETDOWN,
++ ENETUNREACH = libc::ENETUNREACH,
++ ENETRESET = libc::ENETRESET,
++ ECONNABORTED = libc::ECONNABORTED,
++ ECONNRESET = libc::ECONNRESET,
++ ENOBUFS = libc::ENOBUFS,
++ EISCONN = libc::EISCONN,
++ ENOTCONN = libc::ENOTCONN,
++ ESHUTDOWN = libc::ESHUTDOWN,
++ ETOOMANYREFS = libc::ETOOMANYREFS,
++ ETIMEDOUT = libc::ETIMEDOUT,
++ ECONNREFUSED = libc::ECONNREFUSED,
++ ELOOP = libc::ELOOP,
++ ENAMETOOLONG = libc::ENAMETOOLONG,
++ EHOSTDOWN = libc::EHOSTDOWN,
++ EHOSTUNREACH = libc::EHOSTUNREACH,
++ ENOTEMPTY = libc::ENOTEMPTY,
++ EPROCLIM = libc::EPROCLIM,
++ EUSERS = libc::EUSERS,
++ EDQUOT = libc::EDQUOT,
++ ESTALE = libc::ESTALE,
++ EREMOTE = libc::EREMOTE,
++ EBADRPC = libc::EBADRPC,
++ ERPCMISMATCH = libc::ERPCMISMATCH,
++ EPROGUNAVAIL = libc::EPROGUNAVAIL,
++ EPROGMISMATCH = libc::EPROGMISMATCH,
++ EPROCUNAVAIL = libc::EPROCUNAVAIL,
++ ENOLCK = libc::ENOLCK,
++ ENOSYS = libc::ENOSYS,
++ EFTYPE = libc::EFTYPE,
++ EAUTH = libc::EAUTH,
++ ENEEDAUTH = libc::ENEEDAUTH,
++ EIPSEC = libc::EIPSEC,
++ ENOATTR = libc::ENOATTR,
++ EILSEQ = libc::EILSEQ,
++ ENOMEDIUM = libc::ENOMEDIUM,
++ EMEDIUMTYPE = libc::EMEDIUMTYPE,
++ EOVERFLOW = libc::EOVERFLOW,
++ ECANCELED = libc::ECANCELED,
++ EIDRM = libc::EIDRM,
++ ENOMSG = libc::ENOMSG,
++ ENOTSUP = libc::ENOTSUP,
++ EBADMSG = libc::EBADMSG,
++ ENOTRECOVERABLE = libc::ENOTRECOVERABLE,
++ EOWNERDEAD = libc::EOWNERDEAD,
++ EPROTO = libc::EPROTO,
++ }
++
++ pub const ELAST: Errno = Errno::ENOTSUP;
++ pub const EWOULDBLOCK: Errno = Errno::EAGAIN;
++
++ pub const EL2NSYNC: Errno = Errno::UnknownErrno;
++
++ pub fn from_i32(e: i32) -> Errno {
++ use self::Errno::*;
++
++ match e {
++ libc::EPERM => EPERM,
++ libc::ENOENT => ENOENT,
++ libc::ESRCH => ESRCH,
++ libc::EINTR => EINTR,
++ libc::EIO => EIO,
++ libc::ENXIO => ENXIO,
++ libc::E2BIG => E2BIG,
++ libc::ENOEXEC => ENOEXEC,
++ libc::EBADF => EBADF,
++ libc::ECHILD => ECHILD,
++ libc::EDEADLK => EDEADLK,
++ libc::ENOMEM => ENOMEM,
++ libc::EACCES => EACCES,
++ libc::EFAULT => EFAULT,
++ libc::ENOTBLK => ENOTBLK,
++ libc::EBUSY => EBUSY,
++ libc::EEXIST => EEXIST,
++ libc::EXDEV => EXDEV,
++ libc::ENODEV => ENODEV,
++ libc::ENOTDIR => ENOTDIR,
++ libc::EISDIR => EISDIR,
++ libc::EINVAL => EINVAL,
++ libc::ENFILE => ENFILE,
++ libc::EMFILE => EMFILE,
++ libc::ENOTTY => ENOTTY,
++ libc::ETXTBSY => ETXTBSY,
++ libc::EFBIG => EFBIG,
++ libc::ENOSPC => ENOSPC,
++ libc::ESPIPE => ESPIPE,
++ libc::EROFS => EROFS,
++ libc::EMLINK => EMLINK,
++ libc::EPIPE => EPIPE,
++ libc::EDOM => EDOM,
++ libc::ERANGE => ERANGE,
++ libc::EAGAIN => EAGAIN,
++ libc::EINPROGRESS => EINPROGRESS,
++ libc::EALREADY => EALREADY,
++ libc::ENOTSOCK => ENOTSOCK,
++ libc::EDESTADDRREQ => EDESTADDRREQ,
++ libc::EMSGSIZE => EMSGSIZE,
++ libc::EPROTOTYPE => EPROTOTYPE,
++ libc::ENOPROTOOPT => ENOPROTOOPT,
++ libc::EPROTONOSUPPORT => EPROTONOSUPPORT,
++ libc::ESOCKTNOSUPPORT => ESOCKTNOSUPPORT,
++ libc::EOPNOTSUPP => EOPNOTSUPP,
++ libc::EPFNOSUPPORT => EPFNOSUPPORT,
++ libc::EAFNOSUPPORT => EAFNOSUPPORT,
++ libc::EADDRINUSE => EADDRINUSE,
++ libc::EADDRNOTAVAIL => EADDRNOTAVAIL,
++ libc::ENETDOWN => ENETDOWN,
++ libc::ENETUNREACH => ENETUNREACH,
++ libc::ENETRESET => ENETRESET,
++ libc::ECONNABORTED => ECONNABORTED,
++ libc::ECONNRESET => ECONNRESET,
++ libc::ENOBUFS => ENOBUFS,
++ libc::EISCONN => EISCONN,
++ libc::ENOTCONN => ENOTCONN,
++ libc::ESHUTDOWN => ESHUTDOWN,
++ libc::ETOOMANYREFS => ETOOMANYREFS,
++ libc::ETIMEDOUT => ETIMEDOUT,
++ libc::ECONNREFUSED => ECONNREFUSED,
++ libc::ELOOP => ELOOP,
++ libc::ENAMETOOLONG => ENAMETOOLONG,
++ libc::EHOSTDOWN => EHOSTDOWN,
++ libc::EHOSTUNREACH => EHOSTUNREACH,
++ libc::ENOTEMPTY => ENOTEMPTY,
++ libc::EPROCLIM => EPROCLIM,
++ libc::EUSERS => EUSERS,
++ libc::EDQUOT => EDQUOT,
++ libc::ESTALE => ESTALE,
++ libc::EREMOTE => EREMOTE,
++ libc::EBADRPC => EBADRPC,
++ libc::ERPCMISMATCH => ERPCMISMATCH,
++ libc::EPROGUNAVAIL => EPROGUNAVAIL,
++ libc::EPROGMISMATCH => EPROGMISMATCH,
++ libc::EPROCUNAVAIL => EPROCUNAVAIL,
++ libc::ENOLCK => ENOLCK,
++ libc::ENOSYS => ENOSYS,
++ libc::EFTYPE => EFTYPE,
++ libc::EAUTH => EAUTH,
++ libc::ENEEDAUTH => ENEEDAUTH,
++ libc::EIPSEC => EIPSEC,
++ libc::ENOATTR => ENOATTR,
++ libc::EILSEQ => EILSEQ,
++ libc::ENOMEDIUM => ENOMEDIUM,
++ libc::EMEDIUMTYPE => EMEDIUMTYPE,
++ libc::EOVERFLOW => EOVERFLOW,
++ libc::ECANCELED => ECANCELED,
++ libc::EIDRM => EIDRM,
++ libc::ENOMSG => ENOMSG,
++ libc::ENOTSUP => ENOTSUP,
++ libc::EBADMSG => EBADMSG,
++ libc::ENOTRECOVERABLE => ENOTRECOVERABLE,
++ libc::EOWNERDEAD => EOWNERDEAD,
++ libc::EPROTO => EPROTO,
++ _ => UnknownErrno,
++ }
++ }
++}
++
++#[cfg(target_os = "netbsd")]
++mod consts {
++ use libc;
++
++ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
++ #[repr(i32)]
++ pub enum Errno {
++ UnknownErrno = 0,
++ EPERM = libc::EPERM,
++ ENOENT = libc::ENOENT,
++ ESRCH = libc::ESRCH,
++ EINTR = libc::EINTR,
++ EIO = libc::EIO,
++ ENXIO = libc::ENXIO,
++ E2BIG = libc::E2BIG,
++ ENOEXEC = libc::ENOEXEC,
++ EBADF = libc::EBADF,
++ ECHILD = libc::ECHILD,
++ EDEADLK = libc::EDEADLK,
++ ENOMEM = libc::ENOMEM,
++ EACCES = libc::EACCES,
++ EFAULT = libc::EFAULT,
++ ENOTBLK = libc::ENOTBLK,
++ EBUSY = libc::EBUSY,
++ EEXIST = libc::EEXIST,
++ EXDEV = libc::EXDEV,
++ ENODEV = libc::ENODEV,
++ ENOTDIR = libc::ENOTDIR,
++ EISDIR = libc::EISDIR,
++ EINVAL = libc::EINVAL,
++ ENFILE = libc::ENFILE,
++ EMFILE = libc::EMFILE,
++ ENOTTY = libc::ENOTTY,
++ ETXTBSY = libc::ETXTBSY,
++ EFBIG = libc::EFBIG,
++ ENOSPC = libc::ENOSPC,
++ ESPIPE = libc::ESPIPE,
++ EROFS = libc::EROFS,
++ EMLINK = libc::EMLINK,
++ EPIPE = libc::EPIPE,
++ EDOM = libc::EDOM,
++ ERANGE = libc::ERANGE,
++ EAGAIN = libc::EAGAIN,
++ EINPROGRESS = libc::EINPROGRESS,
++ EALREADY = libc::EALREADY,
++ ENOTSOCK = libc::ENOTSOCK,
++ EDESTADDRREQ = libc::EDESTADDRREQ,
++ EMSGSIZE = libc::EMSGSIZE,
++ EPROTOTYPE = libc::EPROTOTYPE,
++ ENOPROTOOPT = libc::ENOPROTOOPT,
++ EPROTONOSUPPORT = libc::EPROTONOSUPPORT,
++ ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT,
++ EOPNOTSUPP = libc::EOPNOTSUPP,
++ EPFNOSUPPORT = libc::EPFNOSUPPORT,
++ EAFNOSUPPORT = libc::EAFNOSUPPORT,
++ EADDRINUSE = libc::EADDRINUSE,
++ EADDRNOTAVAIL = libc::EADDRNOTAVAIL,
++ ENETDOWN = libc::ENETDOWN,
++ ENETUNREACH = libc::ENETUNREACH,
++ ENETRESET = libc::ENETRESET,
++ ECONNABORTED = libc::ECONNABORTED,
++ ECONNRESET = libc::ECONNRESET,
++ ENOBUFS = libc::ENOBUFS,
++ EISCONN = libc::EISCONN,
++ ENOTCONN = libc::ENOTCONN,
++ ESHUTDOWN = libc::ESHUTDOWN,
++ ETOOMANYREFS = libc::ETOOMANYREFS,
++ ETIMEDOUT = libc::ETIMEDOUT,
++ ECONNREFUSED = libc::ECONNREFUSED,
++ ELOOP = libc::ELOOP,
++ ENAMETOOLONG = libc::ENAMETOOLONG,
++ EHOSTDOWN = libc::EHOSTDOWN,
++ EHOSTUNREACH = libc::EHOSTUNREACH,
++ ENOTEMPTY = libc::ENOTEMPTY,
++ EPROCLIM = libc::EPROCLIM,
++ EUSERS = libc::EUSERS,
++ EDQUOT = libc::EDQUOT,
++ ESTALE = libc::ESTALE,
++ EREMOTE = libc::EREMOTE,
++ EBADRPC = libc::EBADRPC,
++ ERPCMISMATCH = libc::ERPCMISMATCH,
++ EPROGUNAVAIL = libc::EPROGUNAVAIL,
++ EPROGMISMATCH = libc::EPROGMISMATCH,
++ EPROCUNAVAIL = libc::EPROCUNAVAIL,
++ ENOLCK = libc::ENOLCK,
++ ENOSYS = libc::ENOSYS,
++ EFTYPE = libc::EFTYPE,
++ EAUTH = libc::EAUTH,
++ ENEEDAUTH = libc::ENEEDAUTH,
++ EIDRM = libc::EIDRM,
++ ENOMSG = libc::ENOMSG,
++ EOVERFLOW = libc::EOVERFLOW,
++ EILSEQ = libc::EILSEQ,
++ ENOTSUP = libc::ENOTSUP,
++ ECANCELED = libc::ECANCELED,
++ EBADMSG = libc::EBADMSG,
++ ENODATA = libc::ENODATA,
++ ENOSR = libc::ENOSR,
++ ENOSTR = libc::ENOSTR,
++ ETIME = libc::ETIME,
++ ENOATTR = libc::ENOATTR,
++ EMULTIHOP = libc::EMULTIHOP,
++ ENOLINK = libc::ENOLINK,
++ EPROTO = libc::EPROTO,
++ }
++
++ pub const ELAST: Errno = Errno::ENOTSUP;
++ pub const EWOULDBLOCK: Errno = Errno::EAGAIN;
++
++ pub const EL2NSYNC: Errno = Errno::UnknownErrno;
++
++ pub fn from_i32(e: i32) -> Errno {
++ use self::Errno::*;
++
++ match e {
++ libc::EPERM => EPERM,
++ libc::ENOENT => ENOENT,
++ libc::ESRCH => ESRCH,
++ libc::EINTR => EINTR,
++ libc::EIO => EIO,
++ libc::ENXIO => ENXIO,
++ libc::E2BIG => E2BIG,
++ libc::ENOEXEC => ENOEXEC,
++ libc::EBADF => EBADF,
++ libc::ECHILD => ECHILD,
++ libc::EDEADLK => EDEADLK,
++ libc::ENOMEM => ENOMEM,
++ libc::EACCES => EACCES,
++ libc::EFAULT => EFAULT,
++ libc::ENOTBLK => ENOTBLK,
++ libc::EBUSY => EBUSY,
++ libc::EEXIST => EEXIST,
++ libc::EXDEV => EXDEV,
++ libc::ENODEV => ENODEV,
++ libc::ENOTDIR => ENOTDIR,
++ libc::EISDIR => EISDIR,
++ libc::EINVAL => EINVAL,
++ libc::ENFILE => ENFILE,
++ libc::EMFILE => EMFILE,
++ libc::ENOTTY => ENOTTY,
++ libc::ETXTBSY => ETXTBSY,
++ libc::EFBIG => EFBIG,
++ libc::ENOSPC => ENOSPC,
++ libc::ESPIPE => ESPIPE,
++ libc::EROFS => EROFS,
++ libc::EMLINK => EMLINK,
++ libc::EPIPE => EPIPE,
++ libc::EDOM => EDOM,
++ libc::ERANGE => ERANGE,
++ libc::EAGAIN => EAGAIN,
++ libc::EINPROGRESS => EINPROGRESS,
++ libc::EALREADY => EALREADY,
++ libc::ENOTSOCK => ENOTSOCK,
++ libc::EDESTADDRREQ => EDESTADDRREQ,
++ libc::EMSGSIZE => EMSGSIZE,
++ libc::EPROTOTYPE => EPROTOTYPE,
++ libc::ENOPROTOOPT => ENOPROTOOPT,
++ libc::EPROTONOSUPPORT => EPROTONOSUPPORT,
++ libc::ESOCKTNOSUPPORT => ESOCKTNOSUPPORT,
++ libc::EOPNOTSUPP => EOPNOTSUPP,
++ libc::EPFNOSUPPORT => EPFNOSUPPORT,
++ libc::EAFNOSUPPORT => EAFNOSUPPORT,
++ libc::EADDRINUSE => EADDRINUSE,
++ libc::EADDRNOTAVAIL => EADDRNOTAVAIL,
++ libc::ENETDOWN => ENETDOWN,
++ libc::ENETUNREACH => ENETUNREACH,
++ libc::ENETRESET => ENETRESET,
++ libc::ECONNABORTED => ECONNABORTED,
++ libc::ECONNRESET => ECONNRESET,
++ libc::ENOBUFS => ENOBUFS,
++ libc::EISCONN => EISCONN,
++ libc::ENOTCONN => ENOTCONN,
++ libc::ESHUTDOWN => ESHUTDOWN,
++ libc::ETOOMANYREFS => ETOOMANYREFS,
++ libc::ETIMEDOUT => ETIMEDOUT,
++ libc::ECONNREFUSED => ECONNREFUSED,
++ libc::ELOOP => ELOOP,
++ libc::ENAMETOOLONG => ENAMETOOLONG,
++ libc::EHOSTDOWN => EHOSTDOWN,
++ libc::EHOSTUNREACH => EHOSTUNREACH,
++ libc::ENOTEMPTY => ENOTEMPTY,
++ libc::EPROCLIM => EPROCLIM,
++ libc::EUSERS => EUSERS,
++ libc::EDQUOT => EDQUOT,
++ libc::ESTALE => ESTALE,
++ libc::EREMOTE => EREMOTE,
++ libc::EBADRPC => EBADRPC,
++ libc::ERPCMISMATCH => ERPCMISMATCH,
++ libc::EPROGUNAVAIL => EPROGUNAVAIL,
++ libc::EPROGMISMATCH => EPROGMISMATCH,
++ libc::EPROCUNAVAIL => EPROCUNAVAIL,
++ libc::ENOLCK => ENOLCK,
++ libc::ENOSYS => ENOSYS,
++ libc::EFTYPE => EFTYPE,
++ libc::EAUTH => EAUTH,
++ libc::ENEEDAUTH => ENEEDAUTH,
++ libc::EIDRM => EIDRM,
++ libc::ENOMSG => ENOMSG,
++ libc::EOVERFLOW => EOVERFLOW,
++ libc::EILSEQ => EILSEQ,
++ libc::ENOTSUP => ENOTSUP,
++ libc::ECANCELED => ECANCELED,
++ libc::EBADMSG => EBADMSG,
++ libc::ENODATA => ENODATA,
++ libc::ENOSR => ENOSR,
++ libc::ENOSTR => ENOSTR,
++ libc::ETIME => ETIME,
++ libc::ENOATTR => ENOATTR,
++ libc::EMULTIHOP => EMULTIHOP,
++ libc::ENOLINK => ENOLINK,
++ libc::EPROTO => EPROTO,
++ _ => UnknownErrno,
++ }
++ }
++}
+diff --git a/third_party/rust/nix/src/errno_dragonfly.c b/third_party/rust/nix-0.15.0/src/errno_dragonfly.c
+similarity index 100%
+rename from third_party/rust/nix/src/errno_dragonfly.c
+rename to third_party/rust/nix-0.15.0/src/errno_dragonfly.c
+diff --git a/third_party/rust/nix-0.15.0/src/fcntl.rs b/third_party/rust/nix-0.15.0/src/fcntl.rs
+new file mode 100644
+index 0000000000000..be6ee0f73a8be
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/fcntl.rs
+@@ -0,0 +1,506 @@
++use {Error, Result, NixPath};
++use errno::Errno;
++use libc::{self, c_int, c_uint, c_char, size_t, ssize_t};
++use sys::stat::Mode;
++use std::os::raw;
++use std::os::unix::io::RawFd;
++use std::ffi::OsStr;
++use std::os::unix::ffi::OsStrExt;
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++use std::ptr; // For splice and copy_file_range
++#[cfg(any(target_os = "android", target_os = "linux"))]
++use sys::uio::IoVec; // For vmsplice
++
++#[cfg(any(target_os = "linux",
++ target_os = "android",
++ target_os = "emscripten",
++ target_os = "fuchsia",
++ any(target_os = "wasi", target_env = "wasi"),
++ target_env = "uclibc",
++ target_env = "freebsd"))]
++pub use self::posix_fadvise::*;
++
++libc_bitflags!{
++ pub struct AtFlags: c_int {
++ AT_REMOVEDIR;
++ AT_SYMLINK_NOFOLLOW;
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ AT_NO_AUTOMOUNT;
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ AT_EMPTY_PATH;
++ }
++}
++
++libc_bitflags!(
++ /// Configuration options for opened files.
++ pub struct OFlag: c_int {
++ /// Mask for the access mode of the file.
++ O_ACCMODE;
++ /// Use alternate I/O semantics.
++ #[cfg(target_os = "netbsd")]
++ O_ALT_IO;
++ /// Open the file in append-only mode.
++ O_APPEND;
++ /// Generate a signal when input or output becomes possible.
++ O_ASYNC;
++ /// Closes the file descriptor once an `execve` call is made.
++ ///
++ /// Also sets the file offset to the beginning of the file.
++ O_CLOEXEC;
++ /// Create the file if it does not exist.
++ O_CREAT;
++ /// Try to minimize cache effects of the I/O for this file.
++ #[cfg(any(target_os = "android",
++ target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "linux",
++ target_os = "netbsd"))]
++ O_DIRECT;
++ /// If the specified path isn't a directory, fail.
++ O_DIRECTORY;
++ /// Implicitly follow each `write()` with an `fdatasync()`.
++ #[cfg(any(target_os = "android",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ O_DSYNC;
++ /// Error out if a file was not created.
++ O_EXCL;
++ /// Open for execute only.
++ #[cfg(target_os = "freebsd")]
++ O_EXEC;
++ /// Open with an exclusive file lock.
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ O_EXLOCK;
++ /// Same as `O_SYNC`.
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ all(target_os = "linux", not(target_env = "musl")),
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ O_FSYNC;
++ /// Allow files whose sizes can't be represented in an `off_t` to be opened.
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ O_LARGEFILE;
++ /// Do not update the file last access time during `read(2)`s.
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ O_NOATIME;
++ /// Don't attach the device as the process' controlling terminal.
++ O_NOCTTY;
++ /// Same as `O_NONBLOCK`.
++ O_NDELAY;
++ /// `open()` will fail if the given path is a symbolic link.
++ O_NOFOLLOW;
++ /// When possible, open the file in nonblocking mode.
++ O_NONBLOCK;
++ /// Don't deliver `SIGPIPE`.
++ #[cfg(target_os = "netbsd")]
++ O_NOSIGPIPE;
++ /// Obtain a file descriptor for low-level access.
++ ///
++ /// The file itself is not opened and other file operations will fail.
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ O_PATH;
++ /// Only allow reading.
++ ///
++ /// This should not be combined with `O_WRONLY` or `O_RDWR`.
++ O_RDONLY;
++ /// Allow both reading and writing.
++ ///
++ /// This should not be combined with `O_WRONLY` or `O_RDONLY`.
++ O_RDWR;
++ /// Similar to `O_DSYNC` but applies to `read`s instead.
++ #[cfg(any(target_os = "linux", target_os = "netbsd", target_os = "openbsd"))]
++ O_RSYNC;
++ /// Skip search permission checks.
++ #[cfg(target_os = "netbsd")]
++ O_SEARCH;
++ /// Open with a shared file lock.
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ O_SHLOCK;
++ /// Implicitly follow each `write()` with an `fsync()`.
++ O_SYNC;
++ /// Create an unnamed temporary file.
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ O_TMPFILE;
++ /// Truncate an existing regular file to 0 length if it allows writing.
++ O_TRUNC;
++ /// Restore default TTY attributes.
++ #[cfg(target_os = "freebsd")]
++ O_TTY_INIT;
++ /// Only allow writing.
++ ///
++ /// This should not be combined with `O_RDONLY` or `O_RDWR`.
++ O_WRONLY;
++ }
++);
++
++pub fn open<P: ?Sized + NixPath>(path: &P, oflag: OFlag, mode: Mode) -> Result<RawFd> {
++ let fd = path.with_nix_path(|cstr| {
++ unsafe { libc::open(cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint) }
++ })?;
++
++ Errno::result(fd)
++}
++
++pub fn openat<P: ?Sized + NixPath>(dirfd: RawFd, path: &P, oflag: OFlag, mode: Mode) -> Result<RawFd> {
++ let fd = path.with_nix_path(|cstr| {
++ unsafe { libc::openat(dirfd, cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint) }
++ })?;
++ Errno::result(fd)
++}
++
++pub fn renameat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(old_dirfd: Option<RawFd>, old_path: &P1,
++ new_dirfd: Option<RawFd>, new_path: &P2)
++ -> Result<()> {
++ let res = old_path.with_nix_path(|old_cstr| {
++ new_path.with_nix_path(|new_cstr| unsafe {
++ libc::renameat(at_rawfd(old_dirfd), old_cstr.as_ptr(),
++ at_rawfd(new_dirfd), new_cstr.as_ptr())
++ })
++ })??;
++ Errno::result(res).map(drop)
++}
++
++fn wrap_readlink_result(buffer: &mut[u8], res: ssize_t) -> Result<&OsStr> {
++ match Errno::result(res) {
++ Err(err) => Err(err),
++ Ok(len) => {
++ if (len as usize) >= buffer.len() {
++ Err(Error::Sys(Errno::ENAMETOOLONG))
++ } else {
++ Ok(OsStr::from_bytes(&buffer[..(len as usize)]))
++ }
++ }
++ }
++}
++
++pub fn readlink<'a, P: ?Sized + NixPath>(path: &P, buffer: &'a mut [u8]) -> Result<&'a OsStr> {
++ let res = path.with_nix_path(|cstr| {
++ unsafe { libc::readlink(cstr.as_ptr(), buffer.as_mut_ptr() as *mut c_char, buffer.len() as size_t) }
++ })?;
++
++ wrap_readlink_result(buffer, res)
++}
++
++
++pub fn readlinkat<'a, P: ?Sized + NixPath>(dirfd: RawFd, path: &P, buffer: &'a mut [u8]) -> Result<&'a OsStr> {
++ let res = path.with_nix_path(|cstr| {
++ unsafe { libc::readlinkat(dirfd, cstr.as_ptr(), buffer.as_mut_ptr() as *mut c_char, buffer.len() as size_t) }
++ })?;
++
++ wrap_readlink_result(buffer, res)
++}
++
++/// Computes the raw fd consumed by a function of the form `*at`.
++pub(crate) fn at_rawfd(fd: Option<RawFd>) -> raw::c_int {
++ match fd {
++ None => libc::AT_FDCWD,
++ Some(fd) => fd,
++ }
++}
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++libc_bitflags!(
++ /// Additional flags for file sealing, which allows for limiting operations on a file.
++ pub struct SealFlag: c_int {
++ /// Prevents further calls to `fcntl()` with `F_ADD_SEALS`.
++ F_SEAL_SEAL;
++ /// The file cannot be reduced in size.
++ F_SEAL_SHRINK;
++ /// The size of the file cannot be increased.
++ F_SEAL_GROW;
++ /// The file contents cannot be modified.
++ F_SEAL_WRITE;
++ }
++);
++
++libc_bitflags!(
++ /// Additional configuration flags for `fcntl`'s `F_SETFD`.
++ pub struct FdFlag: c_int {
++ /// The file descriptor will automatically be closed during a successful `execve(2)`.
++ FD_CLOEXEC;
++ }
++);
++
++#[derive(Debug, Eq, Hash, PartialEq)]
++pub enum FcntlArg<'a> {
++ F_DUPFD(RawFd),
++ F_DUPFD_CLOEXEC(RawFd),
++ F_GETFD,
++ F_SETFD(FdFlag), // FD_FLAGS
++ F_GETFL,
++ F_SETFL(OFlag), // O_NONBLOCK
++ F_SETLK(&'a libc::flock),
++ F_SETLKW(&'a libc::flock),
++ F_GETLK(&'a mut libc::flock),
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ F_OFD_SETLK(&'a libc::flock),
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ F_OFD_SETLKW(&'a libc::flock),
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ F_OFD_GETLK(&'a mut libc::flock),
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ F_ADD_SEALS(SealFlag),
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ F_GET_SEALS,
++ #[cfg(any(target_os = "macos", target_os = "ios"))]
++ F_FULLFSYNC,
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ F_GETPIPE_SZ,
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ F_SETPIPE_SZ(c_int),
++
++ // TODO: Rest of flags
++}
++pub use self::FcntlArg::*;
++
++// TODO: Figure out how to handle value fcntl returns
++pub fn fcntl(fd: RawFd, arg: FcntlArg) -> Result<c_int> {
++ let res = unsafe {
++ match arg {
++ F_DUPFD(rawfd) => libc::fcntl(fd, libc::F_DUPFD, rawfd),
++ F_DUPFD_CLOEXEC(rawfd) => libc::fcntl(fd, libc::F_DUPFD_CLOEXEC, rawfd),
++ F_GETFD => libc::fcntl(fd, libc::F_GETFD),
++ F_SETFD(flag) => libc::fcntl(fd, libc::F_SETFD, flag.bits()),
++ F_GETFL => libc::fcntl(fd, libc::F_GETFL),
++ F_SETFL(flag) => libc::fcntl(fd, libc::F_SETFL, flag.bits()),
++ F_SETLK(flock) => libc::fcntl(fd, libc::F_SETLK, flock),
++ F_SETLKW(flock) => libc::fcntl(fd, libc::F_SETLKW, flock),
++ F_GETLK(flock) => libc::fcntl(fd, libc::F_GETLK, flock),
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ F_ADD_SEALS(flag) => libc::fcntl(fd, libc::F_ADD_SEALS, flag.bits()),
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ F_GET_SEALS => libc::fcntl(fd, libc::F_GET_SEALS),
++ #[cfg(any(target_os = "macos", target_os = "ios"))]
++ F_FULLFSYNC => libc::fcntl(fd, libc::F_FULLFSYNC),
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ F_GETPIPE_SZ => libc::fcntl(fd, libc::F_GETPIPE_SZ),
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ F_SETPIPE_SZ(size) => libc::fcntl(fd, libc::F_SETPIPE_SZ, size),
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ _ => unimplemented!()
++ }
++ };
++
++ Errno::result(res)
++}
++
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub enum FlockArg {
++ LockShared,
++ LockExclusive,
++ Unlock,
++ LockSharedNonblock,
++ LockExclusiveNonblock,
++ UnlockNonblock,
++}
++
++pub fn flock(fd: RawFd, arg: FlockArg) -> Result<()> {
++ use self::FlockArg::*;
++
++ let res = unsafe {
++ match arg {
++ LockShared => libc::flock(fd, libc::LOCK_SH),
++ LockExclusive => libc::flock(fd, libc::LOCK_EX),
++ Unlock => libc::flock(fd, libc::LOCK_UN),
++ LockSharedNonblock => libc::flock(fd, libc::LOCK_SH | libc::LOCK_NB),
++ LockExclusiveNonblock => libc::flock(fd, libc::LOCK_EX | libc::LOCK_NB),
++ UnlockNonblock => libc::flock(fd, libc::LOCK_UN | libc::LOCK_NB),
++ }
++ };
++
++ Errno::result(res).map(drop)
++}
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++libc_bitflags! {
++ /// Additional flags to `splice` and friends.
++ pub struct SpliceFFlags: c_uint {
++ /// Request that pages be moved instead of copied.
++ ///
++ /// Not applicable to `vmsplice`.
++ SPLICE_F_MOVE;
++ /// Do not block on I/O.
++ SPLICE_F_NONBLOCK;
++ /// Hint that more data will be coming in a subsequent splice.
++ ///
++ /// Not applicable to `vmsplice`.
++ SPLICE_F_MORE;
++ /// Gift the user pages to the kernel.
++ ///
++ /// Not applicable to `splice`.
++ SPLICE_F_GIFT;
++ }
++}
++
++/// Copy a range of data from one file to another
++///
++/// The `copy_file_range` system call performs an in-kernel copy between
++/// file descriptors `fd_in` and `fd_out` without the additional cost of
++/// transferring data from the kernel to user space and then back into the
++/// kernel. It copies up to `len` bytes of data from file descriptor `fd_in` to
++/// file descriptor `fd_out`, overwriting any data that exists within the
++/// requested range of the target file.
++///
++/// If the `off_in` and/or `off_out` arguments are used, the values
++/// will be mutated to reflect the new position within the file after
++/// copying. If they are not used, the relevant filedescriptors will be seeked
++/// to the new position.
++///
++/// On successful completion the number of bytes actually copied will be
++/// returned.
++#[cfg(any(target_os = "android", target_os = "linux"))]
++pub fn copy_file_range(
++ fd_in: RawFd,
++ off_in: Option<&mut libc::loff_t>,
++ fd_out: RawFd,
++ off_out: Option<&mut libc::loff_t>,
++ len: usize,
++) -> Result<usize> {
++ let off_in = off_in
++ .map(|offset| offset as *mut libc::loff_t)
++ .unwrap_or(ptr::null_mut());
++ let off_out = off_out
++ .map(|offset| offset as *mut libc::loff_t)
++ .unwrap_or(ptr::null_mut());
++
++ let ret = unsafe {
++ libc::syscall(
++ libc::SYS_copy_file_range,
++ fd_in,
++ off_in,
++ fd_out,
++ off_out,
++ len,
++ 0,
++ )
++ };
++ Errno::result(ret).map(|r| r as usize)
++}
++
++#[cfg(any(target_os = "linux", target_os = "android"))]
++pub fn splice(
++ fd_in: RawFd,
++ off_in: Option<&mut libc::loff_t>,
++ fd_out: RawFd,
++ off_out: Option<&mut libc::loff_t>,
++ len: usize,
++ flags: SpliceFFlags,
++) -> Result<usize> {
++ let off_in = off_in
++ .map(|offset| offset as *mut libc::loff_t)
++ .unwrap_or(ptr::null_mut());
++ let off_out = off_out
++ .map(|offset| offset as *mut libc::loff_t)
++ .unwrap_or(ptr::null_mut());
++
++ let ret = unsafe {
++ libc::splice(fd_in, off_in, fd_out, off_out, len, flags.bits())
++ };
++ Errno::result(ret).map(|r| r as usize)
++}
++
++#[cfg(any(target_os = "linux", target_os = "android"))]
++pub fn tee(fd_in: RawFd, fd_out: RawFd, len: usize, flags: SpliceFFlags) -> Result<usize> {
++ let ret = unsafe { libc::tee(fd_in, fd_out, len, flags.bits()) };
++ Errno::result(ret).map(|r| r as usize)
++}
++
++#[cfg(any(target_os = "linux", target_os = "android"))]
++pub fn vmsplice(fd: RawFd, iov: &[IoVec<&[u8]>], flags: SpliceFFlags) -> Result<usize> {
++ let ret = unsafe {
++ libc::vmsplice(fd, iov.as_ptr() as *const libc::iovec, iov.len(), flags.bits())
++ };
++ Errno::result(ret).map(|r| r as usize)
++}
++
++#[cfg(any(target_os = "linux"))]
++libc_bitflags!(
++ /// Mode argument flags for fallocate determining operation performed on a given range.
++ pub struct FallocateFlags: c_int {
++ /// File size is not changed.
++ ///
++ /// offset + len can be greater than file size.
++ FALLOC_FL_KEEP_SIZE;
++ /// Deallocates space by creating a hole.
++ ///
++ /// Must be ORed with FALLOC_FL_KEEP_SIZE. Byte range starts at offset and continues for len bytes.
++ FALLOC_FL_PUNCH_HOLE;
++ /// Removes byte range from a file without leaving a hole.
++ ///
++ /// Byte range to collapse starts at offset and continues for len bytes.
++ FALLOC_FL_COLLAPSE_RANGE;
++ /// Zeroes space in specified byte range.
++ ///
++ /// Byte range starts at offset and continues for len bytes.
++ FALLOC_FL_ZERO_RANGE;
++ /// Increases file space by inserting a hole within the file size.
++ ///
++ /// Does not overwrite existing data. Hole starts at offset and continues for len bytes.
++ FALLOC_FL_INSERT_RANGE;
++ /// Shared file data extants are made private to the file.
++ ///
++ /// Gaurantees that a subsequent write will not fail due to lack of space.
++ FALLOC_FL_UNSHARE_RANGE;
++ }
++);
++
++/// Manipulates file space.
++///
++/// Allows the caller to directly manipulate the allocated disk space for the
++/// file referred to by fd.
++#[cfg(any(target_os = "linux"))]
++pub fn fallocate(fd: RawFd, mode: FallocateFlags, offset: libc::off_t, len: libc::off_t) -> Result<c_int> {
++ let res = unsafe { libc::fallocate(fd, mode.bits(), offset, len) };
++ Errno::result(res)
++}
++
++#[cfg(any(target_os = "linux",
++ target_os = "android",
++ target_os = "emscripten",
++ target_os = "fuchsia",
++ any(target_os = "wasi", target_env = "wasi"),
++ target_env = "uclibc",
++ target_env = "freebsd"))]
++mod posix_fadvise {
++ use Result;
++ use libc;
++ use errno::Errno;
++ use std::os::unix::io::RawFd;
++
++ libc_enum! {
++ #[repr(i32)]
++ pub enum PosixFadviseAdvice {
++ POSIX_FADV_NORMAL,
++ POSIX_FADV_SEQUENTIAL,
++ POSIX_FADV_RANDOM,
++ POSIX_FADV_NOREUSE,
++ POSIX_FADV_WILLNEED,
++ POSIX_FADV_DONTNEED,
++ }
++ }
++
++ pub fn posix_fadvise(fd: RawFd,
++ offset: libc::off_t,
++ len: libc::off_t,
++ advice: PosixFadviseAdvice) -> Result<libc::c_int> {
++ let res = unsafe { libc::posix_fadvise(fd, offset, len, advice as libc::c_int) };
++ Errno::result(res)
++ }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/features.rs b/third_party/rust/nix-0.15.0/src/features.rs
+new file mode 100644
+index 0000000000000..76cdfd3a1a6f1
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/features.rs
+@@ -0,0 +1,103 @@
++//! Feature tests for OS functionality
++pub use self::os::*;
++
++#[cfg(any(target_os = "linux", target_os = "android"))]
++mod os {
++ use sys::utsname::uname;
++
++ // Features:
++ // * atomic cloexec on socket: 2.6.27
++ // * pipe2: 2.6.27
++ // * accept4: 2.6.28
++
++ static VERS_UNKNOWN: usize = 1;
++ static VERS_2_6_18: usize = 2;
++ static VERS_2_6_27: usize = 3;
++ static VERS_2_6_28: usize = 4;
++ static VERS_3: usize = 5;
++
++ #[inline]
++ fn digit(dst: &mut usize, b: u8) {
++ *dst *= 10;
++ *dst += (b - b'0') as usize;
++ }
++
++ fn parse_kernel_version() -> usize {
++ let u = uname();
++
++ let mut curr: usize = 0;
++ let mut major: usize = 0;
++ let mut minor: usize = 0;
++ let mut patch: usize = 0;
++
++ for b in u.release().bytes() {
++ if curr >= 3 {
++ break;
++ }
++
++ match b {
++ b'.' | b'-' => {
++ curr += 1;
++ }
++ b'0'..=b'9' => {
++ match curr {
++ 0 => digit(&mut major, b),
++ 1 => digit(&mut minor, b),
++ _ => digit(&mut patch, b),
++ }
++ }
++ _ => break,
++ }
++ }
++
++ if major >= 3 {
++ VERS_3
++ } else if major >= 2 {
++ if minor >= 7 {
++ VERS_UNKNOWN
++ } else if minor >= 6 {
++ if patch >= 28 {
++ VERS_2_6_28
++ } else if patch >= 27 {
++ VERS_2_6_27
++ } else {
++ VERS_2_6_18
++ }
++ } else {
++ VERS_UNKNOWN
++ }
++ } else {
++ VERS_UNKNOWN
++ }
++ }
++
++ fn kernel_version() -> usize {
++ static mut KERNEL_VERS: usize = 0;
++
++ unsafe {
++ if KERNEL_VERS == 0 {
++ KERNEL_VERS = parse_kernel_version();
++ }
++
++ KERNEL_VERS
++ }
++ }
++
++ /// Check if the OS supports atomic close-on-exec for sockets
++ pub fn socket_atomic_cloexec() -> bool {
++ kernel_version() >= VERS_2_6_27
++ }
++
++ #[test]
++ pub fn test_parsing_kernel_version() {
++ assert!(kernel_version() > 0);
++ }
++}
++
++#[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "dragonfly", target_os = "ios", target_os = "openbsd", target_os = "netbsd"))]
++mod os {
++ /// Check if the OS supports atomic close-on-exec for sockets
++ pub fn socket_atomic_cloexec() -> bool {
++ false
++ }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/ifaddrs.rs b/third_party/rust/nix-0.15.0/src/ifaddrs.rs
+new file mode 100644
+index 0000000000000..12b59bcc92bef
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/ifaddrs.rs
+@@ -0,0 +1,146 @@
++//! Query network interface addresses
++//!
++//! Uses the Linux and/or BSD specific function `getifaddrs` to query the list
++//! of interfaces and their associated addresses.
++
++use std::ffi;
++use std::iter::Iterator;
++use std::mem;
++use std::option::Option;
++
++use libc;
++
++use {Result, Errno};
++use sys::socket::SockAddr;
++use net::if_::*;
++
++/// Describes a single address for an interface as returned by `getifaddrs`.
++#[derive(Clone, Debug, Eq, Hash, PartialEq)]
++pub struct InterfaceAddress {
++ /// Name of the network interface
++ pub interface_name: String,
++ /// Flags as from `SIOCGIFFLAGS` ioctl
++ pub flags: InterfaceFlags,
++ /// Network address of this interface
++ pub address: Option<SockAddr>,
++ /// Netmask of this interface
++ pub netmask: Option<SockAddr>,
++ /// Broadcast address of this interface, if applicable
++ pub broadcast: Option<SockAddr>,
++ /// Point-to-point destination address
++ pub destination: Option<SockAddr>,
++}
++
++cfg_if! {
++ if #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "fuchsia", target_os = "linux"))] {
++ fn get_ifu_from_sockaddr(info: &libc::ifaddrs) -> *const libc::sockaddr {
++ info.ifa_ifu
++ }
++ } else {
++ fn get_ifu_from_sockaddr(info: &libc::ifaddrs) -> *const libc::sockaddr {
++ info.ifa_dstaddr
++ }
++ }
++}
++
++impl InterfaceAddress {
++ /// Create an `InterfaceAddress` from the libc struct.
++ fn from_libc_ifaddrs(info: &libc::ifaddrs) -> InterfaceAddress {
++ let ifname = unsafe { ffi::CStr::from_ptr(info.ifa_name) };
++ let address = unsafe { SockAddr::from_libc_sockaddr(info.ifa_addr) };
++ let netmask = unsafe { SockAddr::from_libc_sockaddr(info.ifa_netmask) };
++ let mut addr = InterfaceAddress {
++ interface_name: ifname.to_string_lossy().to_string(),
++ flags: InterfaceFlags::from_bits_truncate(info.ifa_flags as i32),
++ address: address,
++ netmask: netmask,
++ broadcast: None,
++ destination: None,
++ };
++
++ let ifu = get_ifu_from_sockaddr(info);
++ if addr.flags.contains(InterfaceFlags::IFF_POINTOPOINT) {
++ addr.destination = unsafe { SockAddr::from_libc_sockaddr(ifu) };
++ } else if addr.flags.contains(InterfaceFlags::IFF_BROADCAST) {
++ addr.broadcast = unsafe { SockAddr::from_libc_sockaddr(ifu) };
++ }
++
++ addr
++ }
++}
++
++/// Holds the results of `getifaddrs`.
++///
++/// Use the function `getifaddrs` to create this Iterator. Note that the
++/// actual list of interfaces can be iterated once and will be freed as
++/// soon as the Iterator goes out of scope.
++#[derive(Debug, Eq, Hash, PartialEq)]
++pub struct InterfaceAddressIterator {
++ base: *mut libc::ifaddrs,
++ next: *mut libc::ifaddrs,
++}
++
++impl Drop for InterfaceAddressIterator {
++ fn drop(&mut self) {
++ unsafe { libc::freeifaddrs(self.base) };
++ }
++}
++
++impl Iterator for InterfaceAddressIterator {
++ type Item = InterfaceAddress;
++ fn next(&mut self) -> Option<<Self as Iterator>::Item> {
++ match unsafe { self.next.as_ref() } {
++ Some(ifaddr) => {
++ self.next = ifaddr.ifa_next;
++ Some(InterfaceAddress::from_libc_ifaddrs(ifaddr))
++ }
++ None => None,
++ }
++ }
++}
++
++/// Get interface addresses using libc's `getifaddrs`
++///
++/// Note that the underlying implementation differs between OSes. Only the
++/// most common address families are supported by the nix crate (due to
++/// lack of time and complexity of testing). The address family is encoded
++/// in the specific variant of `SockAddr` returned for the fields `address`,
++/// `netmask`, `broadcast`, and `destination`. For any entry not supported,
++/// the returned list will contain a `None` entry.
++///
++/// # Example
++/// ```
++/// let addrs = nix::ifaddrs::getifaddrs().unwrap();
++/// for ifaddr in addrs {
++/// match ifaddr.address {
++/// Some(address) => {
++/// println!("interface {} address {}",
++/// ifaddr.interface_name, address);
++/// },
++/// None => {
++/// println!("interface {} with unsupported address family",
++/// ifaddr.interface_name);
++/// }
++/// }
++/// }
++/// ```
++pub fn getifaddrs() -> Result<InterfaceAddressIterator> {
++ let mut addrs: *mut libc::ifaddrs = unsafe { mem::uninitialized() };
++ Errno::result(unsafe { libc::getifaddrs(&mut addrs) }).map(|_| {
++ InterfaceAddressIterator {
++ base: addrs,
++ next: addrs,
++ }
++ })
++}
++
++#[cfg(test)]
++mod tests {
++ use super::*;
++
++ // Only checks if `getifaddrs` can be invoked without panicking.
++ #[test]
++ fn test_getifaddrs() {
++ let _ = getifaddrs();
++ }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/kmod.rs b/third_party/rust/nix-0.15.0/src/kmod.rs
+new file mode 100644
+index 0000000000000..e853261b14f9d
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/kmod.rs
+@@ -0,0 +1,123 @@
++//! Load and unload kernel modules.
++//!
++//! For more details see
++
++use libc;
++use std::ffi::CStr;
++use std::os::unix::io::AsRawFd;
++
++use errno::Errno;
++use Result;
++
++/// Loads a kernel module from a buffer.
++///
++/// It loads an ELF image into kernel space,
++/// performs any necessary symbol relocations,
++/// initializes module parameters to values provided by the caller,
++/// and then runs the module's init function.
++///
++/// This function requires `CAP_SYS_MODULE` privilege.
++///
++/// The `module_image` argument points to a buffer containing the binary image
++/// to be loaded. The buffer should contain a valid ELF image
++/// built for the running kernel.
++///
++/// The `param_values` argument is a string containing space-delimited specifications
++/// of the values for module parameters.
++/// Each of the parameter specifications has the form:
++///
++/// `name[=value[,value...]]`
++///
++/// # Example
++///
++/// ```no_run
++/// use std::fs::File;
++/// use std::io::Read;
++/// use std::ffi::CString;
++/// use nix::kmod::init_module;
++///
++/// let mut f = File::open("mykernel.ko").unwrap();
++/// let mut contents: Vec<u8> = Vec::new();
++/// f.read_to_end(&mut contents).unwrap();
++/// init_module(&mut contents, &CString::new("who=Rust when=Now,12").unwrap()).unwrap();
++/// ```
++///
++/// See [`man init_module(2)`](http://man7.org/linux/man-pages/man2/init_module.2.html) for more information.
++pub fn init_module(module_image: &[u8], param_values: &CStr) -> Result<()> {
++ let res = unsafe {
++ libc::syscall(
++ libc::SYS_init_module,
++ module_image.as_ptr(),
++ module_image.len(),
++ param_values.as_ptr(),
++ )
++ };
++
++ Errno::result(res).map(drop)
++}
++
++libc_bitflags!(
++ /// Flags used by the `finit_module` function.
++ pub struct ModuleInitFlags: libc::c_uint {
++ /// Ignore symbol version hashes.
++ MODULE_INIT_IGNORE_MODVERSIONS;
++ /// Ignore kernel version magic.
++ MODULE_INIT_IGNORE_VERMAGIC;
++ }
++);
++
++/// Loads a kernel module from a given file descriptor.
++///
++/// # Example
++///
++/// ```no_run
++/// use std::fs::File;
++/// use std::ffi::CString;
++/// use nix::kmod::{finit_module, ModuleInitFlags};
++///
++/// let f = File::open("mymod.ko").unwrap();
++/// finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty()).unwrap();
++/// ```
++///
++/// See [`man init_module(2)`](http://man7.org/linux/man-pages/man2/init_module.2.html) for more information.
++pub fn finit_module<T: AsRawFd>(fd: &T, param_values: &CStr, flags: ModuleInitFlags) -> Result<()> {
++ let res = unsafe {
++ libc::syscall(
++ libc::SYS_finit_module,
++ fd.as_raw_fd(),
++ param_values.as_ptr(),
++ flags.bits(),
++ )
++ };
++
++ Errno::result(res).map(drop)
++}
++
++libc_bitflags!(
++ /// Flags used by `delete_module`.
++ ///
++ /// See [`man delete_module(2)`](http://man7.org/linux/man-pages/man2/delete_module.2.html)
++ /// for a detailed description how these flags work.
++ pub struct DeleteModuleFlags: libc::c_int {
++ O_NONBLOCK;
++ O_TRUNC;
++ }
++);
++
++/// Unloads the kernel module with the given name.
++///
++/// # Example
++///
++/// ```no_run
++/// use std::ffi::CString;
++/// use nix::kmod::{delete_module, DeleteModuleFlags};
++///
++/// delete_module(&CString::new("mymod").unwrap(), DeleteModuleFlags::O_NONBLOCK).unwrap();
++/// ```
++///
++/// See [`man delete_module(2)`](http://man7.org/linux/man-pages/man2/delete_module.2.html) for more information.
++pub fn delete_module(name: &CStr, flags: DeleteModuleFlags) -> Result<()> {
++ let res = unsafe { libc::syscall(libc::SYS_delete_module, name.as_ptr(), flags.bits()) };
++
++ Errno::result(res).map(drop)
++}
+diff --git a/third_party/rust/nix-0.15.0/src/lib.rs b/third_party/rust/nix-0.15.0/src/lib.rs
+new file mode 100644
+index 0000000000000..71485d2af1824
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/lib.rs
+@@ -0,0 +1,284 @@
++//! Rust friendly bindings to the various *nix system functions.
++//!
++//! Modules are structured according to the C header file that they would be
++//! defined in.
++#![crate_name = "nix"]
++#![cfg(unix)]
++#![allow(non_camel_case_types)]
++// latest bitflags triggers a rustc bug with cross-crate macro expansions causing dead_code
++// warnings even though the macro expands into something with allow(dead_code)
++#![allow(dead_code)]
++#![cfg_attr(test, deny(warnings))]
++#![recursion_limit = "500"]
++#![deny(unused)]
++#![deny(unstable_features)]
++#![deny(missing_copy_implementations)]
++#![deny(missing_debug_implementations)]
++// XXX Allow deprecated items until release 0.16.0. See issue #1096.
++#![allow(deprecated)]
++
++// External crates
++#[macro_use]
++extern crate bitflags;
++#[macro_use]
++extern crate cfg_if;
++extern crate void;
++
++// Re-exported external crates
++pub extern crate libc;
++
++// Private internal modules
++#[macro_use] mod macros;
++
++// Public crates
++pub mod dir;
++pub mod errno;
++#[deny(missing_docs)]
++pub mod features;
++pub mod fcntl;
++#[deny(missing_docs)]
++#[cfg(any(target_os = "android",
++ target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++pub mod ifaddrs;
++#[cfg(any(target_os = "android",
++ target_os = "linux"))]
++pub mod kmod;
++#[cfg(any(target_os = "android",
++ target_os = "linux"))]
++pub mod mount;
++#[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "fushsia",
++ target_os = "linux",
++ target_os = "netbsd"))]
++pub mod mqueue;
++#[deny(missing_docs)]
++pub mod net;
++#[deny(missing_docs)]
++pub mod poll;
++#[deny(missing_docs)]
++pub mod pty;
++pub mod sched;
++pub mod sys;
++// This can be implemented for other platforms as soon as libc
++// provides bindings for them.
++#[cfg(all(target_os = "linux",
++ any(target_arch = "x86", target_arch = "x86_64")))]
++pub mod ucontext;
++pub mod unistd;
++
++/*
++ *
++ * ===== Result / Error =====
++ *
++ */
++
++use libc::{c_char, PATH_MAX};
++
++use std::{error, fmt, ptr, result};
++use std::ffi::{CStr, OsStr};
++use std::os::unix::ffi::OsStrExt;
++use std::path::{Path, PathBuf};
++
++use errno::Errno;
++
++/// Nix Result Type
++pub type Result<T> = result::Result<T, Error>;
++
++/// Nix Error Type
++///
++/// The nix error type provides a common way of dealing with
++/// various system system/libc calls that might fail. Each
++/// error has a corresponding errno (usually the one from the
++/// underlying OS) to which it can be mapped in addition to
++/// implementing other common traits.
++#[derive(Clone, Copy, Debug, Eq, PartialEq)]
++pub enum Error {
++ Sys(Errno),
++ InvalidPath,
++ /// The operation involved a conversion to Rust's native String type, which failed because the
++ /// string did not contain all valid UTF-8.
++ InvalidUtf8,
++ /// The operation is not supported by Nix, in this instance either use the libc bindings or
++ /// consult the module documentation to see if there is a more appropriate interface available.
++ UnsupportedOperation,
++}
++
++impl Error {
++ /// Convert this `Error` to an [`Errno`](enum.Errno.html).
++ ///
++ /// # Example
++ ///
++ /// ```
++ /// # use nix::Error;
++ /// # use nix::errno::Errno;
++ /// let e = Error::from(Errno::EPERM);
++ /// assert_eq!(Some(Errno::EPERM), e.as_errno());
++ /// ```
++ pub fn as_errno(&self) -> Option<Errno> {
++ if let &Error::Sys(ref e) = self {
++ Some(*e)
++ } else {
++ None
++ }
++ }
++
++ /// Create a nix Error from a given errno
++ pub fn from_errno(errno: Errno) -> Error {
++ Error::Sys(errno)
++ }
++
++ /// Get the current errno and convert it to a nix Error
++ pub fn last() -> Error {
++ Error::Sys(Errno::last())
++ }
++
++ /// Create a new invalid argument error (`EINVAL`)
++ pub fn invalid_argument() -> Error {
++ Error::Sys(Errno::EINVAL)
++ }
++
++}
++
++impl From<Errno> for Error {
++ fn from(errno: Errno) -> Error { Error::from_errno(errno) }
++}
++
++impl From<std::string::FromUtf8Error> for Error {
++ fn from(_: std::string::FromUtf8Error) -> Error { Error::InvalidUtf8 }
++}
++
++impl error::Error for Error {
++ fn description(&self) -> &str {
++ match *self {
++ Error::InvalidPath => "Invalid path",
++ Error::InvalidUtf8 => "Invalid UTF-8 string",
++ Error::UnsupportedOperation => "Unsupported Operation",
++ Error::Sys(ref errno) => errno.desc(),
++ }
++ }
++}
++
++impl fmt::Display for Error {
++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++ match *self {
++ Error::InvalidPath => write!(f, "Invalid path"),
++ Error::InvalidUtf8 => write!(f, "Invalid UTF-8 string"),
++ Error::UnsupportedOperation => write!(f, "Unsupported Operation"),
++ Error::Sys(errno) => write!(f, "{:?}: {}", errno, errno.desc()),
++ }
++ }
++}
++
++pub trait NixPath {
++ fn len(&self) -> usize;
++
++ fn with_nix_path<T, F>(&self, f: F) -> Result<T>
++ where F: FnOnce(&CStr) -> T;
++}
++
++impl NixPath for str {
++ fn len(&self) -> usize {
++ NixPath::len(OsStr::new(self))
++ }
++
++ fn with_nix_path<T, F>(&self, f: F) -> Result<T>
++ where F: FnOnce(&CStr) -> T {
++ OsStr::new(self).with_nix_path(f)
++ }
++}
++
++impl NixPath for OsStr {
++ fn len(&self) -> usize {
++ self.as_bytes().len()
++ }
++
++ fn with_nix_path<T, F>(&self, f: F) -> Result<T>
++ where F: FnOnce(&CStr) -> T {
++ self.as_bytes().with_nix_path(f)
++ }
++}
++
++impl NixPath for CStr {
++ fn len(&self) -> usize {
++ self.to_bytes().len()
++ }
++
++ fn with_nix_path<T, F>(&self, f: F) -> Result<T>
++ where F: FnOnce(&CStr) -> T {
++ // Equivalence with the [u8] impl.
++ if self.len() >= PATH_MAX as usize {
++ return Err(Error::InvalidPath);
++ }
++
++ Ok(f(self))
++ }
++}
++
++impl NixPath for [u8] {
++ fn len(&self) -> usize {
++ self.len()
++ }
++
++ fn with_nix_path<T, F>(&self, f: F) -> Result<T>
++ where F: FnOnce(&CStr) -> T {
++ let mut buf = [0u8; PATH_MAX as usize];
++
++ if self.len() >= PATH_MAX as usize {
++ return Err(Error::InvalidPath);
++ }
++
++ match self.iter().position(|b| *b == 0) {
++ Some(_) => Err(Error::InvalidPath),
++ None => {
++ unsafe {
++ // TODO: Replace with bytes::copy_memory. rust-lang/rust#24028
++ ptr::copy_nonoverlapping(self.as_ptr(), buf.as_mut_ptr(), self.len());
++ Ok(f(CStr::from_ptr(buf.as_ptr() as *const c_char)))
++ }
++
++ }
++ }
++ }
++}
++
++impl NixPath for Path {
++ fn len(&self) -> usize {
++ NixPath::len(self.as_os_str())
++ }
++
++ fn with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T {
++ self.as_os_str().with_nix_path(f)
++ }
++}
++
++impl NixPath for PathBuf {
++ fn len(&self) -> usize {
++ NixPath::len(self.as_os_str())
++ }
++
++ fn with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T {
++ self.as_os_str().with_nix_path(f)
++ }
++}
++
++/// Treats `None` as an empty string.
++impl<'a, NP: ?Sized + NixPath> NixPath for Option<&'a NP> {
++ fn len(&self) -> usize {
++ self.map_or(0, NixPath::len)
++ }
++
++ fn with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T {
++ if let Some(nix_path) = *self {
++ nix_path.with_nix_path(f)
++ } else {
++ unsafe { CStr::from_ptr("\0".as_ptr() as *const _).with_nix_path(f) }
++ }
++ }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/macros.rs b/third_party/rust/nix-0.15.0/src/macros.rs
+new file mode 100644
+index 0000000000000..3d1b0e4b7699c
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/macros.rs
+@@ -0,0 +1,264 @@
++/// The `libc_bitflags!` macro helps with a common use case of defining a public bitflags type
++/// with values from the libc crate. It is used the same way as the `bitflags!` macro, except
++/// that only the name of the flag value has to be given.
++///
++/// The `libc` crate must be in scope with the name `libc`.
++///
++/// # Example
++/// ```
++/// libc_bitflags!{
++/// pub struct ProtFlags: libc::c_int {
++/// PROT_NONE;
++/// PROT_READ;
++/// /// PROT_WRITE enables write protect
++/// PROT_WRITE;
++/// PROT_EXEC;
++/// #[cfg(any(target_os = "linux", target_os = "android"))]
++/// PROT_GROWSDOWN;
++/// #[cfg(any(target_os = "linux", target_os = "android"))]
++/// PROT_GROWSUP;
++/// }
++/// }
++/// ```
++///
++/// Example with casting, due to a mistake in libc. In this example, the
++/// various flags have different types, so we cast the broken ones to the right
++/// type.
++///
++/// ```
++/// libc_bitflags!{
++/// pub struct SaFlags: libc::c_ulong {
++/// SA_NOCLDSTOP as libc::c_ulong;
++/// SA_NOCLDWAIT;
++/// SA_NODEFER as libc::c_ulong;
++/// SA_ONSTACK;
++/// SA_RESETHAND as libc::c_ulong;
++/// SA_RESTART as libc::c_ulong;
++/// SA_SIGINFO;
++/// }
++/// }
++/// ```
++macro_rules! libc_bitflags {
++ (
++ $(#[$outer:meta])*
++ pub struct $BitFlags:ident: $T:ty {
++ $(
++ $(#[$inner:ident $($args:tt)*])*
++ $Flag:ident $(as $cast:ty)*;
++ )+
++ }
++ ) => {
++ bitflags! {
++ $(#[$outer])*
++ pub struct $BitFlags: $T {
++ $(
++ $(#[$inner $($args)*])*
++ const $Flag = libc::$Flag $(as $cast)*;
++ )+
++ }
++ }
++ };
++}
++
++/// The `libc_enum!` macro helps with a common use case of defining an enum exclusively using
++/// values from the `libc` crate. This macro supports both `pub` and private `enum`s.
++///
++/// The `libc` crate must be in scope with the name `libc`.
++///
++/// # Example
++/// ```
++/// libc_enum!{
++/// pub enum ProtFlags {
++/// PROT_NONE,
++/// PROT_READ,
++/// PROT_WRITE,
++/// PROT_EXEC,
++/// #[cfg(any(target_os = "linux", target_os = "android"))]
++/// PROT_GROWSDOWN,
++/// #[cfg(any(target_os = "linux", target_os = "android"))]
++/// PROT_GROWSUP,
++/// }
++/// }
++/// ```
++macro_rules! libc_enum {
++ // (non-pub) Exit rule.
++ (@make_enum
++ {
++ name: $BitFlags:ident,
++ attrs: [$($attrs:tt)*],
++ entries: [$($entries:tt)*],
++ }
++ ) => {
++ $($attrs)*
++ #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
++ enum $BitFlags {
++ $($entries)*
++ }
++ };
++
++ // (pub) Exit rule.
++ (@make_enum
++ {
++ pub,
++ name: $BitFlags:ident,
++ attrs: [$($attrs:tt)*],
++ entries: [$($entries:tt)*],
++ }
++ ) => {
++ $($attrs)*
++ #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
++ pub enum $BitFlags {
++ $($entries)*
++ }
++ };
++
++ // (non-pub) Done accumulating.
++ (@accumulate_entries
++ {
++ name: $BitFlags:ident,
++ attrs: $attrs:tt,
++ },
++ $entries:tt;
++ ) => {
++ libc_enum! {
++ @make_enum
++ {
++ name: $BitFlags,
++ attrs: $attrs,
++ entries: $entries,
++ }
++ }
++ };
++
++ // (pub) Done accumulating.
++ (@accumulate_entries
++ {
++ pub,
++ name: $BitFlags:ident,
++ attrs: $attrs:tt,
++ },
++ $entries:tt;
++ ) => {
++ libc_enum! {
++ @make_enum
++ {
++ pub,
++ name: $BitFlags,
++ attrs: $attrs,
++ entries: $entries,
++ }
++ }
++ };
++
++ // Munch an attr.
++ (@accumulate_entries
++ $prefix:tt,
++ [$($entries:tt)*];
++ #[$attr:meta] $($tail:tt)*
++ ) => {
++ libc_enum! {
++ @accumulate_entries
++ $prefix,
++ [
++ $($entries)*
++ #[$attr]
++ ];
++ $($tail)*
++ }
++ };
++
++ // Munch last ident if not followed by a comma.
++ (@accumulate_entries
++ $prefix:tt,
++ [$($entries:tt)*];
++ $entry:ident
++ ) => {
++ libc_enum! {
++ @accumulate_entries
++ $prefix,
++ [
++ $($entries)*
++ $entry = libc::$entry,
++ ];
++ }
++ };
++
++ // Munch an ident; covers terminating comma case.
++ (@accumulate_entries
++ $prefix:tt,
++ [$($entries:tt)*];
++ $entry:ident, $($tail:tt)*
++ ) => {
++ libc_enum! {
++ @accumulate_entries
++ $prefix,
++ [
++ $($entries)*
++ $entry = libc::$entry,
++ ];
++ $($tail)*
++ }
++ };
++
++ // Munch an ident and cast it to the given type; covers terminating comma.
++ (@accumulate_entries
++ $prefix:tt,
++ [$($entries:tt)*];
++ $entry:ident as $ty:ty, $($tail:tt)*
++ ) => {
++ libc_enum! {
++ @accumulate_entries
++ $prefix,
++ [
++ $($entries)*
++ $entry = libc::$entry as $ty,
++ ];
++ $($tail)*
++ }
++ };
++
++ // (non-pub) Entry rule.
++ (
++ $(#[$attr:meta])*
++ enum $BitFlags:ident {
++ $($vals:tt)*
++ }
++ ) => {
++ libc_enum! {
++ @accumulate_entries
++ {
++ name: $BitFlags,
++ attrs: [$(#[$attr])*],
++ },
++ [];
++ $($vals)*
++ }
++ };
++
++ // (pub) Entry rule.
++ (
++ $(#[$attr:meta])*
++ pub enum $BitFlags:ident {
++ $($vals:tt)*
++ }
++ ) => {
++ libc_enum! {
++ @accumulate_entries
++ {
++ pub,
++ name: $BitFlags,
++ attrs: [$(#[$attr])*],
++ },
++ [];
++ $($vals)*
++ }
++ };
++}
++
++/// A Rust version of the familiar C `offset_of` macro. It returns the byte
++/// offset of `field` within struct `ty`
++macro_rules! offset_of {
++ ($ty:ty, $field:ident) => {
++ &(*(0 as *const $ty)).$field as *const _ as usize
++ }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/mount.rs b/third_party/rust/nix-0.15.0/src/mount.rs
+new file mode 100644
+index 0000000000000..a9902b170ace8
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/mount.rs
+@@ -0,0 +1,98 @@
++use libc::{self, c_ulong, c_int};
++use {Result, NixPath};
++use errno::Errno;
++
++libc_bitflags!(
++ pub struct MsFlags: c_ulong {
++ /// Mount read-only
++ MS_RDONLY;
++ /// Ignore suid and sgid bits
++ MS_NOSUID;
++ /// Disallow access to device special files
++ MS_NODEV;
++ /// Disallow program execution
++ MS_NOEXEC;
++ /// Writes are synced at once
++ MS_SYNCHRONOUS;
++ /// Alter flags of a mounted FS
++ MS_REMOUNT;
++ /// Allow mandatory locks on a FS
++ MS_MANDLOCK;
++ /// Directory modifications are synchronous
++ MS_DIRSYNC;
++ /// Do not update access times
++ MS_NOATIME;
++ /// Do not update directory access times
++ MS_NODIRATIME;
++ /// Linux 2.4.0 - Bind directory at different place
++ MS_BIND;
++ MS_MOVE;
++ MS_REC;
++ MS_SILENT;
++ MS_POSIXACL;
++ MS_UNBINDABLE;
++ MS_PRIVATE;
++ MS_SLAVE;
++ MS_SHARED;
++ MS_RELATIME;
++ MS_KERNMOUNT;
++ MS_I_VERSION;
++ MS_STRICTATIME;
++ MS_ACTIVE;
++ MS_NOUSER;
++ MS_RMT_MASK;
++ MS_MGC_VAL;
++ MS_MGC_MSK;
++ }
++);
++
++libc_bitflags!(
++ pub struct MntFlags: c_int {
++ MNT_FORCE;
++ MNT_DETACH;
++ MNT_EXPIRE;
++ }
++);
++
++pub fn mount<P1: ?Sized + NixPath, P2: ?Sized + NixPath, P3: ?Sized + NixPath, P4: ?Sized + NixPath>(
++ source: Option<&P1>,
++ target: &P2,
++ fstype: Option<&P3>,
++ flags: MsFlags,
++ data: Option<&P4>) -> Result<()> {
++
++ let res =
++ source.with_nix_path(|source| {
++ target.with_nix_path(|target| {
++ fstype.with_nix_path(|fstype| {
++ data.with_nix_path(|data| {
++ unsafe {
++ libc::mount(source.as_ptr(),
++ target.as_ptr(),
++ fstype.as_ptr(),
++ flags.bits,
++ data.as_ptr() as *const libc::c_void)
++ }
++ })
++ })
++ })
++ })????;
++
++ Errno::result(res).map(drop)
++}
++
++pub fn umount<P: ?Sized + NixPath>(target: &P) -> Result<()> {
++ let res = target.with_nix_path(|cstr| {
++ unsafe { libc::umount(cstr.as_ptr()) }
++ })?;
++
++ Errno::result(res).map(drop)
++}
++
++pub fn umount2<P: ?Sized + NixPath>(target: &P, flags: MntFlags) -> Result<()> {
++ let res = target.with_nix_path(|cstr| {
++ unsafe { libc::umount2(cstr.as_ptr(), flags.bits) }
++ })?;
++
++ Errno::result(res).map(drop)
++}
+diff --git a/third_party/rust/nix-0.15.0/src/mqueue.rs b/third_party/rust/nix-0.15.0/src/mqueue.rs
+new file mode 100644
+index 0000000000000..b958b71cddb46
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/mqueue.rs
+@@ -0,0 +1,162 @@
++//! Posix Message Queue functions
++//!
++//! [Further reading and details on the C API](http://man7.org/linux/man-pages/man7/mq_overview.7.html)
++
++use Result;
++use errno::Errno;
++
++use libc::{self, c_char, c_long, mqd_t, size_t};
++use std::ffi::CString;
++use sys::stat::Mode;
++use std::mem;
++
++libc_bitflags!{
++ pub struct MQ_OFlag: libc::c_int {
++ O_RDONLY;
++ O_WRONLY;
++ O_RDWR;
++ O_CREAT;
++ O_EXCL;
++ O_NONBLOCK;
++ O_CLOEXEC;
++ }
++}
++
++libc_bitflags!{
++ pub struct FdFlag: libc::c_int {
++ FD_CLOEXEC;
++ }
++}
++
++#[repr(C)]
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub struct MqAttr {
++ mq_attr: libc::mq_attr,
++}
++
++impl MqAttr {
++ pub fn new(mq_flags: c_long,
++ mq_maxmsg: c_long,
++ mq_msgsize: c_long,
++ mq_curmsgs: c_long)
++ -> MqAttr {
++ let mut attr = unsafe { mem::uninitialized::<libc::mq_attr>() };
++ attr.mq_flags = mq_flags;
++ attr.mq_maxmsg = mq_maxmsg;
++ attr.mq_msgsize = mq_msgsize;
++ attr.mq_curmsgs = mq_curmsgs;
++ MqAttr { mq_attr: attr }
++ }
++
++ pub fn flags(&self) -> c_long {
++ self.mq_attr.mq_flags
++ }
++}
++
++
++/// Open a message queue
++///
++/// See also [`mq_open(2)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_open.html)
++pub fn mq_open(name: &CString,
++ oflag: MQ_OFlag,
++ mode: Mode,
++ attr: Option<&MqAttr>)
++ -> Result<mqd_t> {
++ let res = match attr {
++ Some(mq_attr) => unsafe {
++ libc::mq_open(name.as_ptr(),
++ oflag.bits(),
++ mode.bits() as libc::c_int,
++ &mq_attr.mq_attr as *const libc::mq_attr)
++ },
++ None => unsafe { libc::mq_open(name.as_ptr(), oflag.bits()) },
++ };
++ Errno::result(res)
++}
++
++/// Remove a message queue
++///
++/// See also [`mq_unlink(2)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_unlink.html)
++pub fn mq_unlink(name: &CString) -> Result<()> {
++ let res = unsafe { libc::mq_unlink(name.as_ptr()) };
++ Errno::result(res).map(drop)
++}
++
++/// Close a message queue
++///
++/// See also [`mq_close(2)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_close.html)
++pub fn mq_close(mqdes: mqd_t) -> Result<()> {
++ let res = unsafe { libc::mq_close(mqdes) };
++ Errno::result(res).map(drop)
++}
++
++/// Receive a message from a message queue
++///
++/// See also [`mq_receive(2)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_receive.html)
++pub fn mq_receive(mqdes: mqd_t, message: &mut [u8], msg_prio: &mut u32) -> Result<usize> {
++ let len = message.len() as size_t;
++ let res = unsafe {
++ libc::mq_receive(mqdes,
++ message.as_mut_ptr() as *mut c_char,
++ len,
++ msg_prio as *mut u32)
++ };
++ Errno::result(res).map(|r| r as usize)
++}
++
++/// Send a message to a message queue
++///
++/// See also [`mq_send(2)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_send.html)
++pub fn mq_send(mqdes: mqd_t, message: &[u8], msq_prio: u32) -> Result<()> {
++ let res = unsafe {
++ libc::mq_send(mqdes,
++ message.as_ptr() as *const c_char,
++ message.len(),
++ msq_prio)
++ };
++ Errno::result(res).map(drop)
++}
++
++/// Get message queue attributes
++///
++/// See also [`mq_getattr(2)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_getattr.html)
++pub fn mq_getattr(mqd: mqd_t) -> Result<MqAttr> {
++ let mut attr = unsafe { mem::uninitialized::<libc::mq_attr>() };
++ let res = unsafe { libc::mq_getattr(mqd, &mut attr) };
++ Errno::result(res).map(|_| MqAttr { mq_attr: attr })
++}
++
++/// Set the attributes of the message queue. Only `O_NONBLOCK` can be set, everything else will be ignored
++/// Returns the old attributes
++/// It is recommend to use the `mq_set_nonblock()` and `mq_remove_nonblock()` convenience functions as they are easier to use
++///
++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_setattr.html)
++pub fn mq_setattr(mqd: mqd_t, newattr: &MqAttr) -> Result<MqAttr> {
++ let mut attr = unsafe { mem::uninitialized::<libc::mq_attr>() };
++ let res = unsafe { libc::mq_setattr(mqd, &newattr.mq_attr as *const libc::mq_attr, &mut attr) };
++ Errno::result(res).map(|_| MqAttr { mq_attr: attr })
++}
++
++/// Convenience function.
++/// Sets the `O_NONBLOCK` attribute for a given message queue descriptor
++/// Returns the old attributes
++pub fn mq_set_nonblock(mqd: mqd_t) -> Result<(MqAttr)> {
++ let oldattr = mq_getattr(mqd)?;
++ let newattr = MqAttr::new(MQ_OFlag::O_NONBLOCK.bits() as c_long,
++ oldattr.mq_attr.mq_maxmsg,
++ oldattr.mq_attr.mq_msgsize,
++ oldattr.mq_attr.mq_curmsgs);
++ mq_setattr(mqd, &newattr)
++}
++
++/// Convenience function.
++/// Removes `O_NONBLOCK` attribute for a given message queue descriptor
++/// Returns the old attributes
++pub fn mq_remove_nonblock(mqd: mqd_t) -> Result<(MqAttr)> {
++ let oldattr = mq_getattr(mqd)?;
++ let newattr = MqAttr::new(0,
++ oldattr.mq_attr.mq_maxmsg,
++ oldattr.mq_attr.mq_msgsize,
++ oldattr.mq_attr.mq_curmsgs);
++ mq_setattr(mqd, &newattr)
++}
+diff --git a/third_party/rust/nix-0.15.0/src/net/if_.rs b/third_party/rust/nix-0.15.0/src/net/if_.rs
+new file mode 100644
+index 0000000000000..58d677ae343d1
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/net/if_.rs
+@@ -0,0 +1,268 @@
++//! Network interface name resolution.
++//!
++//! Uses Linux and/or POSIX functions to resolve interface names like "eth0"
++//! or "socan1" into device numbers.
++
++use libc;
++use libc::c_uint;
++use {Result, Error, NixPath};
++
++/// Resolve an interface into a interface number.
++pub fn if_nametoindex<P: ?Sized + NixPath>(name: &P) -> Result<c_uint> {
++ let if_index = name.with_nix_path(|name| unsafe { libc::if_nametoindex(name.as_ptr()) })?;
++
++ if if_index == 0 {
++ Err(Error::last())
++ } else {
++ Ok(if_index)
++ }
++}
++
++libc_bitflags!(
++ /// Standard interface flags, used by `getifaddrs`
++ pub struct InterfaceFlags: libc::c_int {
++ /// Interface is running. (see
++ /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html))
++ IFF_UP;
++ /// Valid broadcast address set. (see
++ /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html))
++ IFF_BROADCAST;
++ /// Internal debugging flag. (see
++ /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html))
++ IFF_DEBUG;
++ /// Interface is a loopback interface. (see
++ /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html))
++ IFF_LOOPBACK;
++ /// Interface is a point-to-point link. (see
++ /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html))
++ IFF_POINTOPOINT;
++ /// Avoid use of trailers. (see
++ /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html))
++ #[cfg(any(target_os = "android",
++ target_os = "fuchsia",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "solaris"))]
++ IFF_NOTRAILERS;
++ /// Interface manages own routes.
++ #[cfg(any(target_os = "dragonfly"))]
++ IFF_SMART;
++ /// Resources allocated. (see
++ /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html))
++ #[cfg(any(target_os = "android",
++ target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "fuchsia",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd",
++ target_os = "solaris"))]
++ IFF_RUNNING;
++ /// No arp protocol, L2 destination address not set. (see
++ /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html))
++ IFF_NOARP;
++ /// Interface is in promiscuous mode. (see
++ /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html))
++ IFF_PROMISC;
++ /// Receive all multicast packets. (see
++ /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html))
++ IFF_ALLMULTI;
++ /// Master of a load balancing bundle. (see
++ /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html))
++ #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
++ IFF_MASTER;
++ /// transmission in progress, tx hardware queue is full
++ #[cfg(any(target_os = "freebsd",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd",
++ target_os = "ios"))]
++ IFF_OACTIVE;
++ /// Protocol code on board.
++ #[cfg(target_os = "solaris")]
++ IFF_INTELLIGENT;
++ /// Slave of a load balancing bundle. (see
++ /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html))
++ #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
++ IFF_SLAVE;
++ /// Can't hear own transmissions.
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd",
++ target_os = "osx"))]
++ IFF_SIMPLEX;
++ /// Supports multicast. (see
++ /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html))
++ IFF_MULTICAST;
++ /// Per link layer defined bit.
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd",
++ target_os = "ios"))]
++ IFF_LINK0;
++ /// Multicast using broadcast.
++ #[cfg(any(target_os = "solaris"))]
++ IFF_MULTI_BCAST;
++ /// Is able to select media type via ifmap. (see
++ /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html))
++ #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
++ IFF_PORTSEL;
++ /// Per link layer defined bit.
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd",
++ target_os = "ios"))]
++ IFF_LINK1;
++ /// Non-unique address.
++ #[cfg(any(target_os = "solaris"))]
++ IFF_UNNUMBERED;
++ /// Auto media selection active. (see
++ /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html))
++ #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
++ IFF_AUTOMEDIA;
++ /// Per link layer defined bit.
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd",
++ target_os = "ios"))]
++ IFF_LINK2;
++ /// Use alternate physical connection.
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "macos",
++ target_os = "ios"))]
++ IFF_ALTPHYS;
++ /// DHCP controlls interface.
++ #[cfg(any(target_os = "solaris"))]
++ IFF_DHCPRUNNING;
++ /// The addresses are lost when the interface goes down. (see
++ /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html))
++ #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
++ IFF_DYNAMIC;
++ /// Do not advertise.
++ #[cfg(any(target_os = "solaris"))]
++ IFF_PRIVATE;
++ /// Driver signals L1 up. Volatile.
++ #[cfg(any(target_os = "fuchsia", target_os = "linux"))]
++ IFF_LOWER_UP;
++ /// Interface is in polling mode.
++ #[cfg(any(target_os = "dragonfly"))]
++ IFF_POLLING_COMPAT;
++ /// Unconfigurable using ioctl(2).
++ #[cfg(any(target_os = "freebsd"))]
++ IFF_CANTCONFIG;
++ /// Do not transmit packets.
++ #[cfg(any(target_os = "solaris"))]
++ IFF_NOXMIT;
++ /// Driver signals dormant. Volatile.
++ #[cfg(any(target_os = "fuchsia", target_os = "linux"))]
++ IFF_DORMANT;
++ /// User-requested promisc mode.
++ #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
++ IFF_PPROMISC;
++ /// Just on-link subnet.
++ #[cfg(any(target_os = "solaris"))]
++ IFF_NOLOCAL;
++ /// Echo sent packets. Volatile.
++ #[cfg(any(target_os = "fuchsia", target_os = "linux"))]
++ IFF_ECHO;
++ /// User-requested monitor mode.
++ #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
++ IFF_MONITOR;
++ /// Address is deprecated.
++ #[cfg(any(target_os = "solaris"))]
++ IFF_DEPRECATED;
++ /// Static ARP.
++ #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
++ IFF_STATICARP;
++ /// Address from stateless addrconf.
++ #[cfg(any(target_os = "solaris"))]
++ IFF_ADDRCONF;
++ /// Interface is in polling mode.
++ #[cfg(any(target_os = "dragonfly"))]
++ IFF_NPOLLING;
++ /// Router on interface.
++ #[cfg(any(target_os = "solaris"))]
++ IFF_ROUTER;
++ /// Interface is in polling mode.
++ #[cfg(any(target_os = "dragonfly"))]
++ IFF_IDIRECT;
++ /// Interface is winding down
++ #[cfg(any(target_os = "freebsd"))]
++ IFF_DYING;
++ /// No NUD on interface.
++ #[cfg(any(target_os = "solaris"))]
++ IFF_NONUD;
++ /// Interface is being renamed
++ #[cfg(any(target_os = "freebsd"))]
++ IFF_RENAMING;
++ /// Anycast address.
++ #[cfg(any(target_os = "solaris"))]
++ IFF_ANYCAST;
++ /// Don't exchange routing info.
++ #[cfg(any(target_os = "solaris"))]
++ IFF_NORTEXCH;
++ /// Do not provide packet information
++ #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
++ IFF_NO_PI as libc::c_int;
++ /// TUN device (no Ethernet headers)
++ #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
++ IFF_TUN as libc::c_int;
++ /// TAP device
++ #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
++ IFF_TAP as libc::c_int;
++ /// IPv4 interface.
++ #[cfg(any(target_os = "solaris"))]
++ IFF_IPV4;
++ /// IPv6 interface.
++ #[cfg(any(target_os = "solaris"))]
++ IFF_IPV6;
++ /// in.mpathd test address
++ #[cfg(any(target_os = "solaris"))]
++ IFF_NOFAILOVER;
++ /// Interface has failed
++ #[cfg(any(target_os = "solaris"))]
++ IFF_FAILED;
++ /// Interface is a hot-spare
++ #[cfg(any(target_os = "solaris"))]
++ IFF_STANDBY;
++ /// Functioning but not used
++ #[cfg(any(target_os = "solaris"))]
++ IFF_INACTIVE;
++ /// Interface is offline
++ #[cfg(any(target_os = "solaris"))]
++ IFF_OFFLINE;
++ #[cfg(any(target_os = "solaris"))]
++ IFF_COS_ENABLED;
++ /// Prefer as source addr.
++ #[cfg(any(target_os = "solaris"))]
++ IFF_PREFERRED;
++ /// RFC3041
++ #[cfg(any(target_os = "solaris"))]
++ IFF_TEMPORARY;
++ /// MTU set with SIOCSLIFMTU
++ #[cfg(any(target_os = "solaris"))]
++ IFF_FIXEDMTU;
++ /// Cannot send / receive packets
++ #[cfg(any(target_os = "solaris"))]
++ IFF_VIRTUAL;
++ /// Local address in use
++ #[cfg(any(target_os = "solaris"))]
++ IFF_DUPLICATE;
++ /// IPMP IP interface
++ #[cfg(any(target_os = "solaris"))]
++ IFF_IPMP;
++ }
++);
+diff --git a/third_party/rust/nix-0.15.0/src/net/mod.rs b/third_party/rust/nix-0.15.0/src/net/mod.rs
+new file mode 100644
+index 0000000000000..079fcfde6fd44
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/net/mod.rs
+@@ -0,0 +1,4 @@
++//! Functionality involving network interfaces
++// To avoid clashing with the keyword "if", we use "if_" as the module name.
++// The original header is called "net/if.h".
++pub mod if_;
+diff --git a/third_party/rust/nix-0.15.0/src/poll.rs b/third_party/rust/nix-0.15.0/src/poll.rs
+new file mode 100644
+index 0000000000000..c603611e3176f
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/poll.rs
+@@ -0,0 +1,143 @@
++//! Wait for events to trigger on specific file descriptors
++#[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))]
++use sys::time::TimeSpec;
++#[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))]
++use sys::signal::SigSet;
++use std::os::unix::io::RawFd;
++
++use libc;
++use Result;
++use errno::Errno;
++
++/// This is a wrapper around `libc::pollfd`.
++///
++/// It's meant to be used as an argument to the [`poll`](fn.poll.html) and
++/// [`ppoll`](fn.ppoll.html) functions to specify the events of interest
++/// for a specific file descriptor.
++///
++/// After a call to `poll` or `ppoll`, the events that occured can be
++/// retrieved by calling [`revents()`](#method.revents) on the `PollFd`.
++#[repr(C)]
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub struct PollFd {
++ pollfd: libc::pollfd,
++}
++
++impl PollFd {
++ /// Creates a new `PollFd` specifying the events of interest
++ /// for a given file descriptor.
++ pub fn new(fd: RawFd, events: PollFlags) -> PollFd {
++ PollFd {
++ pollfd: libc::pollfd {
++ fd: fd,
++ events: events.bits(),
++ revents: PollFlags::empty().bits(),
++ },
++ }
++ }
++
++ /// Returns the events that occured in the last call to `poll` or `ppoll`.
++ pub fn revents(&self) -> Option<PollFlags> {
++ PollFlags::from_bits(self.pollfd.revents)
++ }
++}
++
++libc_bitflags! {
++ /// These flags define the different events that can be monitored by `poll` and `ppoll`
++ pub struct PollFlags: libc::c_short {
++ /// There is data to read.
++ POLLIN;
++ /// There is some exceptional condition on the file descriptor.
++ ///
++ /// Possibilities include:
++ ///
++ /// * There is out-of-band data on a TCP socket (see
++ /// [tcp(7)](http://man7.org/linux/man-pages/man7/tcp.7.html)).
++ /// * A pseudoterminal master in packet mode has seen a state
++ /// change on the slave (see
++ /// [ioctl_tty(2)](http://man7.org/linux/man-pages/man2/ioctl_tty.2.html)).
++ /// * A cgroup.events file has been modified (see
++ /// [cgroups(7)](http://man7.org/linux/man-pages/man7/cgroups.7.html)).
++ POLLPRI;
++ /// Writing is now possible, though a write larger that the
++ /// available space in a socket or pipe will still block (unless
++ /// `O_NONBLOCK` is set).
++ POLLOUT;
++ /// Equivalent to [`POLLIN`](constant.POLLIN.html)
++ POLLRDNORM;
++ /// Equivalent to [`POLLOUT`](constant.POLLOUT.html)
++ POLLWRNORM;
++ /// Priority band data can be read (generally unused on Linux).
++ POLLRDBAND;
++ /// Priority data may be written.
++ POLLWRBAND;
++ /// Error condition (only returned in
++ /// [`PollFd::revents`](struct.PollFd.html#method.revents);
++ /// ignored in [`PollFd::new`](struct.PollFd.html#method.new)).
++ /// This bit is also set for a file descriptor referring to the
++ /// write end of a pipe when the read end has been closed.
++ POLLERR;
++ /// Hang up (only returned in [`PollFd::revents`](struct.PollFd.html#method.revents);
++ /// ignored in [`PollFd::new`](struct.PollFd.html#method.new)).
++ /// Note that when reading from a channel such as a pipe or a stream
++ /// socket, this event merely indicates that the peer closed its
++ /// end of the channel. Subsequent reads from the channel will
++ /// return 0 (end of file) only after all outstanding data in the
++ /// channel has been consumed.
++ POLLHUP;
++ /// Invalid request: `fd` not open (only returned in
++ /// [`PollFd::revents`](struct.PollFd.html#method.revents);
++ /// ignored in [`PollFd::new`](struct.PollFd.html#method.new)).
++ POLLNVAL;
++ }
++}
++
++/// `poll` waits for one of a set of file descriptors to become ready to perform I/O.
++/// ([`poll(2)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html))
++///
++/// `fds` contains all [`PollFd`](struct.PollFd.html) to poll.
++/// The function will return as soon as any event occur for any of these `PollFd`s.
++///
++/// The `timeout` argument specifies the number of milliseconds that `poll()`
++/// should block waiting for a file descriptor to become ready. The call
++/// will block until either:
++///
++/// * a file descriptor becomes ready;
++/// * the call is interrupted by a signal handler; or
++/// * the timeout expires.
++///
++/// Note that the timeout interval will be rounded up to the system clock
++/// granularity, and kernel scheduling delays mean that the blocking
++/// interval may overrun by a small amount. Specifying a negative value
++/// in timeout means an infinite timeout. Specifying a timeout of zero
++/// causes `poll()` to return immediately, even if no file descriptors are
++/// ready.
++pub fn poll(fds: &mut [PollFd], timeout: libc::c_int) -> Result<libc::c_int> {
++ let res = unsafe {
++ libc::poll(fds.as_mut_ptr() as *mut libc::pollfd,
++ fds.len() as libc::nfds_t,
++ timeout)
++ };
++
++ Errno::result(res)
++}
++
++/// `ppoll()` allows an application to safely wait until either a file
++/// descriptor becomes ready or until a signal is caught.
++/// ([`poll(2)`](http://man7.org/linux/man-pages/man2/poll.2.html))
++///
++/// `ppoll` behaves like `poll`, but let you specify what signals may interrupt it
++/// with the `sigmask` argument.
++///
++#[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))]
++pub fn ppoll(fds: &mut [PollFd], timeout: TimeSpec, sigmask: SigSet) -> Result<libc::c_int> {
++
++
++ let res = unsafe {
++ libc::ppoll(fds.as_mut_ptr() as *mut libc::pollfd,
++ fds.len() as libc::nfds_t,
++ timeout.as_ref(),
++ sigmask.as_ref())
++ };
++ Errno::result(res)
++}
+diff --git a/third_party/rust/nix-0.15.0/src/pty.rs b/third_party/rust/nix-0.15.0/src/pty.rs
+new file mode 100644
+index 0000000000000..db012d8158c53
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/pty.rs
+@@ -0,0 +1,326 @@
++//! Create master and slave virtual pseudo-terminals (PTYs)
++
++use libc;
++
++pub use libc::pid_t as SessionId;
++pub use libc::winsize as Winsize;
++
++use std::ffi::CStr;
++use std::mem;
++use std::os::unix::prelude::*;
++
++use sys::termios::Termios;
++use unistd::ForkResult;
++use {Result, Error, fcntl};
++use errno::Errno;
++
++/// Representation of a master/slave pty pair
++///
++/// This is returned by `openpty`. Note that this type does *not* implement `Drop`, so the user
++/// must manually close the file descriptors.
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub struct OpenptyResult {
++ /// The master port in a virtual pty pair
++ pub master: RawFd,
++ /// The slave port in a virtual pty pair
++ pub slave: RawFd,
++}
++
++/// Representation of a master with a forked pty
++///
++/// This is returned by `forkpty`. Note that this type does *not* implement `Drop`, so the user
++/// must manually close the file descriptors.
++#[derive(Clone, Copy, Debug)]
++pub struct ForkptyResult {
++ /// The master port in a virtual pty pair
++ pub master: RawFd,
++ /// Metadata about forked process
++ pub fork_result: ForkResult,
++}
++
++
++/// Representation of the Master device in a master/slave pty pair
++///
++/// While this datatype is a thin wrapper around `RawFd`, it enforces that the available PTY
++/// functions are given the correct file descriptor. Additionally this type implements `Drop`,
++/// so that when it's consumed or goes out of scope, it's automatically cleaned-up.
++#[derive(Clone, Debug, Eq, Hash, PartialEq)]
++pub struct PtyMaster(RawFd);
++
++impl AsRawFd for PtyMaster {
++ fn as_raw_fd(&self) -> RawFd {
++ self.0
++ }
++}
++
++impl IntoRawFd for PtyMaster {
++ fn into_raw_fd(self) -> RawFd {
++ let fd = self.0;
++ mem::forget(self);
++ fd
++ }
++}
++
++impl Drop for PtyMaster {
++ fn drop(&mut self) {
++ // On drop, we ignore errors like EINTR and EIO because there's no clear
++ // way to handle them, we can't return anything, and (on FreeBSD at
++ // least) the file descriptor is deallocated in these cases. However,
++ // we must panic on EBADF, because it is always an error to close an
++ // invalid file descriptor. That frequently indicates a double-close
++ // condition, which can cause confusing errors for future I/O
++ // operations.
++ let e = ::unistd::close(self.0);
++ if e == Err(Error::Sys(Errno::EBADF)) {
++ panic!("Closing an invalid file descriptor!");
++ };
++ }
++}
++
++/// Grant access to a slave pseudoterminal (see
++/// [`grantpt(3)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/grantpt.html))
++///
++/// `grantpt()` changes the mode and owner of the slave pseudoterminal device corresponding to the
++/// master pseudoterminal referred to by `fd`. This is a necessary step towards opening the slave.
++#[inline]
++pub fn grantpt(fd: &PtyMaster) -> Result<()> {
++ if unsafe { libc::grantpt(fd.as_raw_fd()) } < 0 {
++ return Err(Error::last());
++ }
++
++ Ok(())
++}
++
++/// Open a pseudoterminal device (see
++/// [`posix_openpt(3)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_openpt.html))
++///
++/// `posix_openpt()` returns a file descriptor to an existing unused pseuterminal master device.
++///
++/// # Examples
++///
++/// A common use case with this function is to open both a master and slave PTY pair. This can be
++/// done as follows:
++///
++/// ```
++/// use std::path::Path;
++/// use nix::fcntl::{OFlag, open};
++/// use nix::pty::{grantpt, posix_openpt, ptsname, unlockpt};
++/// use nix::sys::stat::Mode;
++///
++/// # #[allow(dead_code)]
++/// # fn run() -> nix::Result<()> {
++/// // Open a new PTY master
++/// let master_fd = posix_openpt(OFlag::O_RDWR)?;
++///
++/// // Allow a slave to be generated for it
++/// grantpt(&master_fd)?;
++/// unlockpt(&master_fd)?;
++///
++/// // Get the name of the slave
++/// let slave_name = unsafe { ptsname(&master_fd) }?;
++///
++/// // Try to open the slave
++/// let _slave_fd = open(Path::new(&slave_name), OFlag::O_RDWR, Mode::empty())?;
++/// # Ok(())
++/// # }
++/// ```
++#[inline]
++pub fn posix_openpt(flags: fcntl::OFlag) -> Result<PtyMaster> {
++ let fd = unsafe {
++ libc::posix_openpt(flags.bits())
++ };
++
++ if fd < 0 {
++ return Err(Error::last());
++ }
++
++ Ok(PtyMaster(fd))
++}
++
++/// Get the name of the slave pseudoterminal (see
++/// [`ptsname(3)`](http://man7.org/linux/man-pages/man3/ptsname.3.html))
++///
++/// `ptsname()` returns the name of the slave pseudoterminal device corresponding to the master
++/// referred to by `fd`.
++///
++/// This value is useful for opening the slave pty once the master has already been opened with
++/// `posix_openpt()`.
++///
++/// # Safety
++///
++/// `ptsname()` mutates global variables and is *not* threadsafe.
++/// Mutating global variables is always considered `unsafe` by Rust and this
++/// function is marked as `unsafe` to reflect that.
++///
++/// For a threadsafe and non-`unsafe` alternative on Linux, see `ptsname_r()`.
++#[inline]
++pub unsafe fn ptsname(fd: &PtyMaster) -> Result<String> {
++ let name_ptr = libc::ptsname(fd.as_raw_fd());
++ if name_ptr.is_null() {
++ return Err(Error::last());
++ }
++
++ let name = CStr::from_ptr(name_ptr);
++ Ok(name.to_string_lossy().into_owned())
++}
++
++/// Get the name of the slave pseudoterminal (see
++/// [`ptsname(3)`](http://man7.org/linux/man-pages/man3/ptsname.3.html))
++///
++/// `ptsname_r()` returns the name of the slave pseudoterminal device corresponding to the master
++/// referred to by `fd`. This is the threadsafe version of `ptsname()`, but it is not part of the
++/// POSIX standard and is instead a Linux-specific extension.
++///
++/// This value is useful for opening the slave ptty once the master has already been opened with
++/// `posix_openpt()`.
++#[cfg(any(target_os = "android", target_os = "linux"))]
++#[inline]
++pub fn ptsname_r(fd: &PtyMaster) -> Result<String> {
++ let mut name_buf = vec![0u8; 64];
++ let name_buf_ptr = name_buf.as_mut_ptr() as *mut libc::c_char;
++ if unsafe { libc::ptsname_r(fd.as_raw_fd(), name_buf_ptr, name_buf.capacity()) } != 0 {
++ return Err(Error::last());
++ }
++
++ // Find the first null-character terminating this string. This is guaranteed to succeed if the
++ // return value of `libc::ptsname_r` is 0.
++ let null_index = name_buf.iter().position(|c| *c == b'\0').unwrap();
++ name_buf.truncate(null_index);
++
++ let name = String::from_utf8(name_buf)?;
++ Ok(name)
++}
++
++/// Unlock a pseudoterminal master/slave pseudoterminal pair (see
++/// [`unlockpt(3)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/unlockpt.html))
++///
++/// `unlockpt()` unlocks the slave pseudoterminal device corresponding to the master pseudoterminal
++/// referred to by `fd`. This must be called before trying to open the slave side of a
++/// pseuoterminal.
++#[inline]
++pub fn unlockpt(fd: &PtyMaster) -> Result<()> {
++ if unsafe { libc::unlockpt(fd.as_raw_fd()) } < 0 {
++ return Err(Error::last());
++ }
++
++ Ok(())
++}
++
++
++/// Create a new pseudoterminal, returning the slave and master file descriptors
++/// in `OpenptyResult`
++/// (see [`openpty`](http://man7.org/linux/man-pages/man3/openpty.3.html)).
++///
++/// If `winsize` is not `None`, the window size of the slave will be set to
++/// the values in `winsize`. If `termios` is not `None`, the pseudoterminal's
++/// terminal settings of the slave will be set to the values in `termios`.
++#[inline]
++pub fn openpty<'a, 'b, T: Into<Option<&'a Winsize>>, U: Into<Option<&'b Termios>>>(winsize: T, termios: U) -> Result<OpenptyResult> {
++ use std::ptr;
++
++ let mut slave: libc::c_int = unsafe { mem::uninitialized() };
++ let mut master: libc::c_int = unsafe { mem::uninitialized() };
++ let ret = {
++ match (termios.into(), winsize.into()) {
++ (Some(termios), Some(winsize)) => {
++ let inner_termios = termios.get_libc_termios();
++ unsafe {
++ libc::openpty(
++ &mut master,
++ &mut slave,
++ ptr::null_mut(),
++ &*inner_termios as *const libc::termios as *mut _,
++ winsize as *const Winsize as *mut _,
++ )
++ }
++ }
++ (None, Some(winsize)) => {
++ unsafe {
++ libc::openpty(
++ &mut master,
++ &mut slave,
++ ptr::null_mut(),
++ ptr::null_mut(),
++ winsize as *const Winsize as *mut _,
++ )
++ }
++ }
++ (Some(termios), None) => {
++ let inner_termios = termios.get_libc_termios();
++ unsafe {
++ libc::openpty(
++ &mut master,
++ &mut slave,
++ ptr::null_mut(),
++ &*inner_termios as *const libc::termios as *mut _,
++ ptr::null_mut(),
++ )
++ }
++ }
++ (None, None) => {
++ unsafe {
++ libc::openpty(
++ &mut master,
++ &mut slave,
++ ptr::null_mut(),
++ ptr::null_mut(),
++ ptr::null_mut(),
++ )
++ }
++ }
++ }
++ };
++
++ Errno::result(ret)?;
++
++ Ok(OpenptyResult {
++ master: master,
++ slave: slave,
++ })
++}
++
++/// Create a new pseudoterminal, returning the master file descriptor and forked pid.
++/// in `ForkptyResult`
++/// (see [`forkpty`](http://man7.org/linux/man-pages/man3/forkpty.3.html)).
++///
++/// If `winsize` is not `None`, the window size of the slave will be set to
++/// the values in `winsize`. If `termios` is not `None`, the pseudoterminal's
++/// terminal settings of the slave will be set to the values in `termios`.
++pub fn forkpty<'a, 'b, T: Into<Option<&'a Winsize>>, U: Into<Option<&'b Termios>>>(
++ winsize: T,
++ termios: U,
++) -> Result<ForkptyResult> {
++ use std::ptr;
++ use unistd::Pid;
++ use unistd::ForkResult::*;
++
++ let mut master: libc::c_int = unsafe { mem::uninitialized() };
++
++ let term = match termios.into() {
++ Some(termios) => {
++ let inner_termios = termios.get_libc_termios();
++ &*inner_termios as *const libc::termios as *mut _
++ },
++ None => ptr::null_mut(),
++ };
++
++ let win = winsize
++ .into()
++ .map(|ws| ws as *const Winsize as *mut _)
++ .unwrap_or(ptr::null_mut());
++
++ let res = unsafe {
++ libc::forkpty(&mut master, ptr::null_mut(), term, win)
++ };
++
++ let fork_result = Errno::result(res).map(|res| match res {
++ 0 => Child,
++ res => Parent { child: Pid::from_raw(res) },
++ })?;
++
++ Ok(ForkptyResult {
++ master: master,
++ fork_result: fork_result,
++ })
++}
++
+diff --git a/third_party/rust/nix-0.15.0/src/sched.rs b/third_party/rust/nix-0.15.0/src/sched.rs
+new file mode 100644
+index 0000000000000..67188c57eef7d
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sched.rs
+@@ -0,0 +1,147 @@
++use libc;
++use {Errno, Result};
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++pub use self::sched_linux_like::*;
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++mod sched_linux_like {
++ use errno::Errno;
++ use libc::{self, c_int, c_void};
++ use std::mem;
++ use std::option::Option;
++ use std::os::unix::io::RawFd;
++ use unistd::Pid;
++ use {Error, Result};
++
++ // For some functions taking with a parameter of type CloneFlags,
++ // only a subset of these flags have an effect.
++ libc_bitflags! {
++ pub struct CloneFlags: c_int {
++ CLONE_VM;
++ CLONE_FS;
++ CLONE_FILES;
++ CLONE_SIGHAND;
++ CLONE_PTRACE;
++ CLONE_VFORK;
++ CLONE_PARENT;
++ CLONE_THREAD;
++ CLONE_NEWNS;
++ CLONE_SYSVSEM;
++ CLONE_SETTLS;
++ CLONE_PARENT_SETTID;
++ CLONE_CHILD_CLEARTID;
++ CLONE_DETACHED;
++ CLONE_UNTRACED;
++ CLONE_CHILD_SETTID;
++ CLONE_NEWCGROUP;
++ CLONE_NEWUTS;
++ CLONE_NEWIPC;
++ CLONE_NEWUSER;
++ CLONE_NEWPID;
++ CLONE_NEWNET;
++ CLONE_IO;
++ }
++ }
++
++ pub type CloneCb<'a> = Box<dyn FnMut() -> isize + 'a>;
++
++ #[repr(C)]
++ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++ pub struct CpuSet {
++ cpu_set: libc::cpu_set_t,
++ }
++
++ impl CpuSet {
++ pub fn new() -> CpuSet {
++ CpuSet {
++ cpu_set: unsafe { mem::zeroed() },
++ }
++ }
++
++ pub fn is_set(&self, field: usize) -> Result<bool> {
++ if field >= 8 * mem::size_of::<libc::cpu_set_t>() {
++ Err(Error::Sys(Errno::EINVAL))
++ } else {
++ Ok(unsafe { libc::CPU_ISSET(field, &self.cpu_set) })
++ }
++ }
++
++ pub fn set(&mut self, field: usize) -> Result<()> {
++ if field >= 8 * mem::size_of::<libc::cpu_set_t>() {
++ Err(Error::Sys(Errno::EINVAL))
++ } else {
++ Ok(unsafe { libc::CPU_SET(field, &mut self.cpu_set) })
++ }
++ }
++
++ pub fn unset(&mut self, field: usize) -> Result<()> {
++ if field >= 8 * mem::size_of::<libc::cpu_set_t>() {
++ Err(Error::Sys(Errno::EINVAL))
++ } else {
++ Ok(unsafe { libc::CPU_CLR(field, &mut self.cpu_set) })
++ }
++ }
++ }
++
++ pub fn sched_setaffinity(pid: Pid, cpuset: &CpuSet) -> Result<()> {
++ let res = unsafe {
++ libc::sched_setaffinity(
++ pid.into(),
++ mem::size_of::<CpuSet>() as libc::size_t,
++ &cpuset.cpu_set,
++ )
++ };
++
++ Errno::result(res).map(drop)
++ }
++
++ pub fn clone(
++ mut cb: CloneCb,
++ stack: &mut [u8],
++ flags: CloneFlags,
++ signal: Option<c_int>,
++ ) -> Result<Pid> {
++ extern "C" fn callback(data: *mut CloneCb) -> c_int {
++ let cb: &mut CloneCb = unsafe { &mut *data };
++ (*cb)() as c_int
++ }
++
++ let res = unsafe {
++ let combined = flags.bits() | signal.unwrap_or(0);
++ let ptr = stack.as_mut_ptr().offset(stack.len() as isize);
++ let ptr_aligned = ptr.offset((ptr as usize % 16) as isize * -1);
++ libc::clone(
++ mem::transmute(
++ callback as extern "C" fn(*mut Box<dyn FnMut() -> isize>) -> i32,
++ ),
++ ptr_aligned as *mut c_void,
++ combined,
++ &mut cb as *mut _ as *mut c_void,
++ )
++ };
++
++ Errno::result(res).map(Pid::from_raw)
++ }
++
++ pub fn unshare(flags: CloneFlags) -> Result<()> {
++ let res = unsafe { libc::unshare(flags.bits()) };
++
++ Errno::result(res).map(drop)
++ }
++
++ pub fn setns(fd: RawFd, nstype: CloneFlags) -> Result<()> {
++ let res = unsafe { libc::setns(fd, nstype.bits()) };
++
++ Errno::result(res).map(drop)
++ }
++}
++
++/// Explicitly yield the processor to other threads.
++///
++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sched_yield.html)
++pub fn sched_yield() -> Result<()> {
++ let res = unsafe { libc::sched_yield() };
++
++ Errno::result(res).map(drop)
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/aio.rs b/third_party/rust/nix-0.15.0/src/sys/aio.rs
+new file mode 100644
+index 0000000000000..9258a0657cc8a
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/aio.rs
+@@ -0,0 +1,1280 @@
++// vim: tw=80
++//! POSIX Asynchronous I/O
++//!
++//! The POSIX AIO interface is used for asynchronous I/O on files and disk-like
++//! devices. It supports [`read`](struct.AioCb.html#method.read),
++//! [`write`](struct.AioCb.html#method.write), and
++//! [`fsync`](struct.AioCb.html#method.fsync) operations. Completion
++//! notifications can optionally be delivered via
++//! [signals](../signal/enum.SigevNotify.html#variant.SigevSignal), via the
++//! [`aio_suspend`](fn.aio_suspend.html) function, or via polling. Some
++//! platforms support other completion
++//! notifications, such as
++//! [kevent](../signal/enum.SigevNotify.html#variant.SigevKevent).
++//!
++//! Multiple operations may be submitted in a batch with
++//! [`lio_listio`](fn.lio_listio.html), though the standard does not guarantee
++//! that they will be executed atomically.
++//!
++//! Outstanding operations may be cancelled with
++//! [`cancel`](struct.AioCb.html#method.cancel) or
++//! [`aio_cancel_all`](fn.aio_cancel_all.html), though the operating system may
++//! not support this for all filesystems and devices.
++
++use {Error, Result};
++use errno::Errno;
++use std::os::unix::io::RawFd;
++use libc::{c_void, off_t, size_t};
++use libc;
++use std::borrow::{Borrow, BorrowMut};
++use std::fmt;
++use std::fmt::Debug;
++use std::marker::PhantomData;
++use std::mem;
++use std::ptr::{null, null_mut};
++use sys::signal::*;
++use std::thread;
++use sys::time::TimeSpec;
++
++libc_enum! {
++ /// Mode for `AioCb::fsync`. Controls whether only data or both data and
++ /// metadata are synced.
++ #[repr(i32)]
++ pub enum AioFsyncMode {
++ /// do it like `fsync`
++ O_SYNC,
++ /// on supported operating systems only, do it like `fdatasync`
++ #[cfg(any(target_os = "ios",
++ target_os = "linux",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ O_DSYNC
++ }
++}
++
++libc_enum! {
++ /// When used with [`lio_listio`](fn.lio_listio.html), determines whether a
++ /// given `aiocb` should be used for a read operation, a write operation, or
++ /// ignored. Has no effect for any other aio functions.
++ #[repr(i32)]
++ pub enum LioOpcode {
++ LIO_NOP,
++ LIO_WRITE,
++ LIO_READ,
++ }
++}
++
++libc_enum! {
++ /// Mode for [`lio_listio`](fn.lio_listio.html)
++ #[repr(i32)]
++ pub enum LioMode {
++ /// Requests that [`lio_listio`](fn.lio_listio.html) block until all
++ /// requested operations have been completed
++ LIO_WAIT,
++ /// Requests that [`lio_listio`](fn.lio_listio.html) return immediately
++ LIO_NOWAIT,
++ }
++}
++
++/// Return values for [`AioCb::cancel`](struct.AioCb.html#method.cancel) and
++/// [`aio_cancel_all`](fn.aio_cancel_all.html)
++#[repr(i32)]
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub enum AioCancelStat {
++ /// All outstanding requests were canceled
++ AioCanceled = libc::AIO_CANCELED,
++ /// Some requests were not canceled. Their status should be checked with
++ /// `AioCb::error`
++ AioNotCanceled = libc::AIO_NOTCANCELED,
++ /// All of the requests have already finished
++ AioAllDone = libc::AIO_ALLDONE,
++}
++
++/// Owns (uniquely or shared) a memory buffer to keep it from `Drop`ing while
++/// the kernel has a pointer to it.
++pub enum Buffer<'a> {
++ /// No buffer to own.
++ ///
++ /// Used for operations like `aio_fsync` that have no data, or for unsafe
++ /// operations that work with raw pointers.
++ None,
++ /// Keeps a reference to a slice
++ Phantom(PhantomData<&'a mut [u8]>),
++ /// Generic thing that keeps a buffer from dropping
++ BoxedSlice(Box<dyn Borrow<[u8]>>),
++ /// Generic thing that keeps a mutable buffer from dropping
++ BoxedMutSlice(Box<dyn BorrowMut<[u8]>>),
++}
++
++impl<'a> Debug for Buffer<'a> {
++ // Note: someday it may be possible to Derive Debug for a trait object, but
++ // not today.
++ // https://github.com/rust-lang/rust/issues/1563
++ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
++ match *self {
++ Buffer::None => write!(fmt, "None"),
++ Buffer::Phantom(p) => p.fmt(fmt),
++ Buffer::BoxedSlice(ref bs) => {
++ let borrowed : &dyn Borrow<[u8]> = bs.borrow();
++ write!(fmt, "BoxedSlice({:?})",
++ borrowed as *const dyn Borrow<[u8]>)
++ },
++ Buffer::BoxedMutSlice(ref bms) => {
++ let borrowed : &dyn BorrowMut<[u8]> = bms.borrow();
++ write!(fmt, "BoxedMutSlice({:?})",
++ borrowed as *const dyn BorrowMut<[u8]>)
++ }
++ }
++ }
++}
++
++/// AIO Control Block.
++///
++/// The basic structure used by all aio functions. Each `AioCb` represents one
++/// I/O request.
++pub struct AioCb<'a> {
++ aiocb: libc::aiocb,
++ /// Tracks whether the buffer pointed to by `libc::aiocb.aio_buf` is mutable
++ mutable: bool,
++ /// Could this `AioCb` potentially have any in-kernel state?
++ in_progress: bool,
++ /// Optionally keeps a reference to the data.
++ ///
++ /// Used to keep buffers from `Drop`'ing, and may be returned once the
++ /// `AioCb` is completed by [`buffer`](#method.buffer).
++ buffer: Buffer<'a>
++}
++
++impl<'a> AioCb<'a> {
++ /// Remove the inner `Buffer` and return it
++ ///
++ /// It is an error to call this method while the `AioCb` is still in
++ /// progress.
++ pub fn buffer(&mut self) -> Buffer<'a> {
++ assert!(!self.in_progress);
++ let mut x = Buffer::None;
++ mem::swap(&mut self.buffer, &mut x);
++ x
++ }
++
++ /// Remove the inner boxed slice, if any, and return it.
++ ///
++ /// The returned value will be the argument that was passed to
++ /// `from_boxed_slice` when this `AioCb` was created.
++ ///
++ /// It is an error to call this method while the `AioCb` is still in
++ /// progress.
++ pub fn boxed_slice(&mut self) -> Option<Box<dyn Borrow<[u8]>>> {
++ assert!(!self.in_progress, "Can't remove the buffer from an AioCb that's still in-progress. Did you forget to call aio_return?");
++ if let Buffer::BoxedSlice(_) = self.buffer {
++ let mut oldbuffer = Buffer::None;
++ mem::swap(&mut self.buffer, &mut oldbuffer);
++ if let Buffer::BoxedSlice(inner) = oldbuffer {
++ Some(inner)
++ } else {
++ unreachable!();
++ }
++ } else {
++ None
++ }
++ }
++
++ /// Remove the inner boxed mutable slice, if any, and return it.
++ ///
++ /// The returned value will be the argument that was passed to
++ /// `from_boxed_mut_slice` when this `AioCb` was created.
++ ///
++ /// It is an error to call this method while the `AioCb` is still in
++ /// progress.
++ pub fn boxed_mut_slice(&mut self) -> Option<Box<dyn BorrowMut<[u8]>>> {
++ assert!(!self.in_progress, "Can't remove the buffer from an AioCb that's still in-progress. Did you forget to call aio_return?");
++ if let Buffer::BoxedMutSlice(_) = self.buffer {
++ let mut oldbuffer = Buffer::None;
++ mem::swap(&mut self.buffer, &mut oldbuffer);
++ if let Buffer::BoxedMutSlice(inner) = oldbuffer {
++ Some(inner)
++ } else {
++ unreachable!();
++ }
++ } else {
++ None
++ }
++ }
++
++ /// Returns the underlying file descriptor associated with the `AioCb`
++ pub fn fd(&self) -> RawFd {
++ self.aiocb.aio_fildes
++ }
++
++ /// Constructs a new `AioCb` with no associated buffer.
++ ///
++ /// The resulting `AioCb` structure is suitable for use with `AioCb::fsync`.
++ ///
++ /// # Parameters
++ ///
++ /// * `fd`: File descriptor. Required for all aio functions.
++ /// * `prio`: If POSIX Prioritized IO is supported, then the
++ /// operation will be prioritized at the process's
++ /// priority level minus `prio`.
++ /// * `sigev_notify`: Determines how you will be notified of event
++ /// completion.
++ ///
++ /// # Examples
++ ///
++ /// Create an `AioCb` from a raw file descriptor and use it for an
++ /// [`fsync`](#method.fsync) operation.
++ ///
++ /// ```
++ /// # extern crate tempfile;
++ /// # extern crate nix;
++ /// # use nix::errno::Errno;
++ /// # use nix::Error;
++ /// # use nix::sys::aio::*;
++ /// # use nix::sys::signal::SigevNotify::SigevNone;
++ /// # use std::{thread, time};
++ /// # use std::os::unix::io::AsRawFd;
++ /// # use tempfile::tempfile;
++ /// # fn main() {
++ /// let f = tempfile().unwrap();
++ /// let mut aiocb = AioCb::from_fd( f.as_raw_fd(), 0, SigevNone);
++ /// aiocb.fsync(AioFsyncMode::O_SYNC).expect("aio_fsync failed early");
++ /// while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) {
++ /// thread::sleep(time::Duration::from_millis(10));
++ /// }
++ /// aiocb.aio_return().expect("aio_fsync failed late");
++ /// # }
++ /// ```
++ pub fn from_fd(fd: RawFd, prio: libc::c_int,
++ sigev_notify: SigevNotify) -> AioCb<'a> {
++ let mut a = AioCb::common_init(fd, prio, sigev_notify);
++ a.aio_offset = 0;
++ a.aio_nbytes = 0;
++ a.aio_buf = null_mut();
++
++ AioCb {
++ aiocb: a,
++ mutable: false,
++ in_progress: false,
++ buffer: Buffer::None
++ }
++ }
++
++ /// Constructs a new `AioCb` from a mutable slice.
++ ///
++ /// The resulting `AioCb` will be suitable for both read and write
++ /// operations, but only if the borrow checker can guarantee that the slice
++ /// will outlive the `AioCb`. That will usually be the case if the `AioCb`
++ /// is stack-allocated. If the borrow checker gives you trouble, try using
++ /// [`from_boxed_mut_slice`](#method.from_boxed_mut_slice) instead.
++ ///
++ /// # Parameters
++ ///
++ /// * `fd`: File descriptor. Required for all aio functions.
++ /// * `offs`: File offset
++ /// * `buf`: A memory buffer
++ /// * `prio`: If POSIX Prioritized IO is supported, then the
++ /// operation will be prioritized at the process's
++ /// priority level minus `prio`
++ /// * `sigev_notify`: Determines how you will be notified of event
++ /// completion.
++ /// * `opcode`: This field is only used for `lio_listio`. It
++ /// determines which operation to use for this individual
++ /// aiocb
++ ///
++ /// # Examples
++ ///
++ /// Create an `AioCb` from a mutable slice and read into it.
++ ///
++ /// ```
++ /// # extern crate tempfile;
++ /// # extern crate nix;
++ /// # use nix::errno::Errno;
++ /// # use nix::Error;
++ /// # use nix::sys::aio::*;
++ /// # use nix::sys::signal::SigevNotify;
++ /// # use std::{thread, time};
++ /// # use std::io::Write;
++ /// # use std::os::unix::io::AsRawFd;
++ /// # use tempfile::tempfile;
++ /// # fn main() {
++ /// const INITIAL: &[u8] = b"abcdef123456";
++ /// const LEN: usize = 4;
++ /// let mut rbuf = vec![0; LEN];
++ /// let mut f = tempfile().unwrap();
++ /// f.write_all(INITIAL).unwrap();
++ /// {
++ /// let mut aiocb = AioCb::from_mut_slice( f.as_raw_fd(),
++ /// 2, //offset
++ /// &mut rbuf,
++ /// 0, //priority
++ /// SigevNotify::SigevNone,
++ /// LioOpcode::LIO_NOP);
++ /// aiocb.read().unwrap();
++ /// while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) {
++ /// thread::sleep(time::Duration::from_millis(10));
++ /// }
++ /// assert_eq!(aiocb.aio_return().unwrap() as usize, LEN);
++ /// }
++ /// assert_eq!(rbuf, b"cdef");
++ /// # }
++ /// ```
++ pub fn from_mut_slice(fd: RawFd, offs: off_t, buf: &'a mut [u8],
++ prio: libc::c_int, sigev_notify: SigevNotify,
++ opcode: LioOpcode) -> AioCb<'a> {
++ let mut a = AioCb::common_init(fd, prio, sigev_notify);
++ a.aio_offset = offs;
++ a.aio_nbytes = buf.len() as size_t;
++ a.aio_buf = buf.as_ptr() as *mut c_void;
++ a.aio_lio_opcode = opcode as libc::c_int;
++
++ AioCb {
++ aiocb: a,
++ mutable: true,
++ in_progress: false,
++ buffer: Buffer::Phantom(PhantomData),
++ }
++ }
++
++ /// The safest and most flexible way to create an `AioCb`.
++ ///
++ /// Unlike [`from_slice`], this method returns a structure suitable for
++ /// placement on the heap. It may be used for write operations, but not
++ /// read operations. Unlike `from_ptr`, this method will ensure that the
++ /// buffer doesn't `drop` while the kernel is still processing it. Any
++ /// object that can be borrowed as a boxed slice will work.
++ ///
++ /// # Parameters
++ ///
++ /// * `fd`: File descriptor. Required for all aio functions.
++ /// * `offs`: File offset
++ /// * `buf`: A boxed slice-like object
++ /// * `prio`: If POSIX Prioritized IO is supported, then the
++ /// operation will be prioritized at the process's
++ /// priority level minus `prio`
++ /// * `sigev_notify`: Determines how you will be notified of event
++ /// completion.
++ /// * `opcode`: This field is only used for `lio_listio`. It
++ /// determines which operation to use for this individual
++ /// aiocb
++ ///
++ /// # Examples
++ ///
++ /// Create an `AioCb` from a Vector and use it for writing
++ ///
++ /// ```
++ /// # extern crate tempfile;
++ /// # extern crate nix;
++ /// # use nix::errno::Errno;
++ /// # use nix::Error;
++ /// # use nix::sys::aio::*;
++ /// # use nix::sys::signal::SigevNotify;
++ /// # use std::{thread, time};
++ /// # use std::io::Write;
++ /// # use std::os::unix::io::AsRawFd;
++ /// # use tempfile::tempfile;
++ /// # fn main() {
++ /// let wbuf = Box::new(Vec::from("CDEF"));
++ /// let expected_len = wbuf.len();
++ /// let mut f = tempfile().unwrap();
++ /// let mut aiocb = AioCb::from_boxed_slice( f.as_raw_fd(),
++ /// 2, //offset
++ /// wbuf,
++ /// 0, //priority
++ /// SigevNotify::SigevNone,
++ /// LioOpcode::LIO_NOP);
++ /// aiocb.write().unwrap();
++ /// while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) {
++ /// thread::sleep(time::Duration::from_millis(10));
++ /// }
++ /// assert_eq!(aiocb.aio_return().unwrap() as usize, expected_len);
++ /// # }
++ /// ```
++ ///
++ /// Create an `AioCb` from a `Bytes` object
++ ///
++ /// ```
++ /// # extern crate bytes;
++ /// # extern crate tempfile;
++ /// # extern crate nix;
++ /// # use bytes::Bytes;
++ /// # use nix::sys::aio::*;
++ /// # use nix::sys::signal::SigevNotify;
++ /// # use std::os::unix::io::AsRawFd;
++ /// # use tempfile::tempfile;
++ /// # fn main() {
++ /// let wbuf = Box::new(Bytes::from(&b"CDEF"[..]));
++ /// let mut f = tempfile().unwrap();
++ /// let mut aiocb = AioCb::from_boxed_slice( f.as_raw_fd(),
++ /// 2, //offset
++ /// wbuf,
++ /// 0, //priority
++ /// SigevNotify::SigevNone,
++ /// LioOpcode::LIO_NOP);
++ /// # }
++ /// ```
++ ///
++ /// If a library needs to work with buffers that aren't `Box`ed, it can
++ /// create a `Box`ed container for use with this method. Here's an example
++ /// using an un`Box`ed `Bytes` object.
++ ///
++ /// ```
++ /// # extern crate bytes;
++ /// # extern crate tempfile;
++ /// # extern crate nix;
++ /// # use bytes::Bytes;
++ /// # use nix::sys::aio::*;
++ /// # use nix::sys::signal::SigevNotify;
++ /// # use std::borrow::Borrow;
++ /// # use std::os::unix::io::AsRawFd;
++ /// # use tempfile::tempfile;
++ /// struct BytesContainer(Bytes);
++ /// impl Borrow<[u8]> for BytesContainer {
++ /// fn borrow(&self) -> &[u8] {
++ /// self.0.as_ref()
++ /// }
++ /// }
++ /// fn main() {
++ /// let wbuf = Bytes::from(&b"CDEF"[..]);
++ /// let boxed_wbuf = Box::new(BytesContainer(wbuf));
++ /// let mut f = tempfile().unwrap();
++ /// let mut aiocb = AioCb::from_boxed_slice( f.as_raw_fd(),
++ /// 2, //offset
++ /// boxed_wbuf,
++ /// 0, //priority
++ /// SigevNotify::SigevNone,
++ /// LioOpcode::LIO_NOP);
++ /// }
++ /// ```
++ ///
++ /// [`from_slice`]: #method.from_slice
++ pub fn from_boxed_slice(fd: RawFd, offs: off_t, buf: Box<dyn Borrow<[u8]>>,
++ prio: libc::c_int, sigev_notify: SigevNotify,
++ opcode: LioOpcode) -> AioCb<'a> {
++ let mut a = AioCb::common_init(fd, prio, sigev_notify);
++ {
++ let borrowed : &dyn Borrow<[u8]> = buf.borrow();
++ let slice : &[u8] = borrowed.borrow();
++ a.aio_nbytes = slice.len() as size_t;
++ a.aio_buf = slice.as_ptr() as *mut c_void;
++ }
++ a.aio_offset = offs;
++ a.aio_lio_opcode = opcode as libc::c_int;
++
++ AioCb {
++ aiocb: a,
++ mutable: false,
++ in_progress: false,
++ buffer: Buffer::BoxedSlice(buf),
++ }
++ }
++
++ /// The safest and most flexible way to create an `AioCb` for reading.
++ ///
++ /// Like [`from_boxed_slice`], but the slice is a mutable one. More
++ /// flexible than [`from_mut_slice`], because a wide range of objects can be
++ /// used.
++ ///
++ /// # Examples
++ ///
++ /// Create an `AioCb` from a Vector and use it for reading
++ ///
++ /// ```
++ /// # extern crate tempfile;
++ /// # extern crate nix;
++ /// # use nix::errno::Errno;
++ /// # use nix::Error;
++ /// # use nix::sys::aio::*;
++ /// # use nix::sys::signal::SigevNotify;
++ /// # use std::{thread, time};
++ /// # use std::io::Write;
++ /// # use std::os::unix::io::AsRawFd;
++ /// # use tempfile::tempfile;
++ /// # fn main() {
++ /// const INITIAL: &[u8] = b"abcdef123456";
++ /// const LEN: usize = 4;
++ /// let rbuf = Box::new(vec![0; LEN]);
++ /// let mut f = tempfile().unwrap();
++ /// f.write_all(INITIAL).unwrap();
++ /// let mut aiocb = AioCb::from_boxed_mut_slice( f.as_raw_fd(),
++ /// 2, //offset
++ /// rbuf,
++ /// 0, //priority
++ /// SigevNotify::SigevNone,
++ /// LioOpcode::LIO_NOP);
++ /// aiocb.read().unwrap();
++ /// while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) {
++ /// thread::sleep(time::Duration::from_millis(10));
++ /// }
++ /// assert_eq!(aiocb.aio_return().unwrap() as usize, LEN);
++ /// let mut buffer = aiocb.boxed_mut_slice().unwrap();
++ /// const EXPECT: &[u8] = b"cdef";
++ /// assert_eq!(buffer.borrow_mut(), EXPECT);
++ /// # }
++ /// ```
++ ///
++ /// [`from_boxed_slice`]: #method.from_boxed_slice
++ /// [`from_mut_slice`]: #method.from_mut_slice
++ pub fn from_boxed_mut_slice(fd: RawFd, offs: off_t,
++ mut buf: Box<dyn BorrowMut<[u8]>>,
++ prio: libc::c_int, sigev_notify: SigevNotify,
++ opcode: LioOpcode) -> AioCb<'a> {
++ let mut a = AioCb::common_init(fd, prio, sigev_notify);
++ {
++ let borrowed : &mut dyn BorrowMut<[u8]> = buf.borrow_mut();
++ let slice : &mut [u8] = borrowed.borrow_mut();
++ a.aio_nbytes = slice.len() as size_t;
++ a.aio_buf = slice.as_mut_ptr() as *mut c_void;
++ }
++ a.aio_offset = offs;
++ a.aio_lio_opcode = opcode as libc::c_int;
++
++ AioCb {
++ aiocb: a,
++ mutable: true,
++ in_progress: false,
++ buffer: Buffer::BoxedMutSlice(buf),
++ }
++ }
++
++ /// Constructs a new `AioCb` from a mutable raw pointer
++ ///
++ /// Unlike `from_mut_slice`, this method returns a structure suitable for
++ /// placement on the heap. It may be used for both reads and writes. Due
++ /// to its unsafety, this method is not recommended. It is most useful when
++ /// heap allocation is required but for some reason the data cannot be
++ /// wrapped in a `struct` that implements `BorrowMut<[u8]>`
++ ///
++ /// # Parameters
++ ///
++ /// * `fd`: File descriptor. Required for all aio functions.
++ /// * `offs`: File offset
++ /// * `buf`: Pointer to the memory buffer
++ /// * `len`: Length of the buffer pointed to by `buf`
++ /// * `prio`: If POSIX Prioritized IO is supported, then the
++ /// operation will be prioritized at the process's
++ /// priority level minus `prio`
++ /// * `sigev_notify`: Determines how you will be notified of event
++ /// completion.
++ /// * `opcode`: This field is only used for `lio_listio`. It
++ /// determines which operation to use for this individual
++ /// aiocb
++ ///
++ /// # Safety
++ ///
++ /// The caller must ensure that the storage pointed to by `buf` outlives the
++ /// `AioCb`. The lifetime checker can't help here.
++ pub unsafe fn from_mut_ptr(fd: RawFd, offs: off_t,
++ buf: *mut c_void, len: usize,
++ prio: libc::c_int, sigev_notify: SigevNotify,
++ opcode: LioOpcode) -> AioCb<'a> {
++ let mut a = AioCb::common_init(fd, prio, sigev_notify);
++ a.aio_offset = offs;
++ a.aio_nbytes = len;
++ a.aio_buf = buf;
++ a.aio_lio_opcode = opcode as libc::c_int;
++
++ AioCb {
++ aiocb: a,
++ mutable: true,
++ in_progress: false,
++ buffer: Buffer::None
++ }
++ }
++
++ /// Constructs a new `AioCb` from a raw pointer.
++ ///
++ /// Unlike `from_slice`, this method returns a structure suitable for
++ /// placement on the heap. Due to its unsafety, this method is not
++ /// recommended. It is most useful when heap allocation is required but for
++ /// some reason the data cannot be wrapped in a `struct` that implements
++ /// `Borrow<[u8]>`
++ ///
++ /// # Parameters
++ ///
++ /// * `fd`: File descriptor. Required for all aio functions.
++ /// * `offs`: File offset
++ /// * `buf`: Pointer to the memory buffer
++ /// * `len`: Length of the buffer pointed to by `buf`
++ /// * `prio`: If POSIX Prioritized IO is supported, then the
++ /// operation will be prioritized at the process's
++ /// priority level minus `prio`
++ /// * `sigev_notify`: Determines how you will be notified of event
++ /// completion.
++ /// * `opcode`: This field is only used for `lio_listio`. It
++ /// determines which operation to use for this individual
++ /// aiocb
++ ///
++ /// # Safety
++ ///
++ /// The caller must ensure that the storage pointed to by `buf` outlives the
++ /// `AioCb`. The lifetime checker can't help here.
++ pub unsafe fn from_ptr(fd: RawFd, offs: off_t,
++ buf: *const c_void, len: usize,
++ prio: libc::c_int, sigev_notify: SigevNotify,
++ opcode: LioOpcode) -> AioCb<'a> {
++ let mut a = AioCb::common_init(fd, prio, sigev_notify);
++ a.aio_offset = offs;
++ a.aio_nbytes = len;
++ // casting a const ptr to a mutable ptr here is ok, because we set the
++ // AioCb's mutable field to false
++ a.aio_buf = buf as *mut c_void;
++ a.aio_lio_opcode = opcode as libc::c_int;
++
++ AioCb {
++ aiocb: a,
++ mutable: false,
++ in_progress: false,
++ buffer: Buffer::None
++ }
++ }
++
++ /// Like `from_mut_slice`, but works on constant slices rather than
++ /// mutable slices.
++ ///
++ /// An `AioCb` created this way cannot be used with `read`, and its
++ /// `LioOpcode` cannot be set to `LIO_READ`. This method is useful when
++ /// writing a const buffer with `AioCb::write`, since `from_mut_slice` can't
++ /// work with const buffers.
++ ///
++ /// # Examples
++ ///
++ /// Construct an `AioCb` from a slice and use it for writing.
++ ///
++ /// ```
++ /// # extern crate tempfile;
++ /// # extern crate nix;
++ /// # use nix::errno::Errno;
++ /// # use nix::Error;
++ /// # use nix::sys::aio::*;
++ /// # use nix::sys::signal::SigevNotify;
++ /// # use std::{thread, time};
++ /// # use std::os::unix::io::AsRawFd;
++ /// # use tempfile::tempfile;
++ /// # fn main() {
++ /// const WBUF: &[u8] = b"abcdef123456";
++ /// let mut f = tempfile().unwrap();
++ /// let mut aiocb = AioCb::from_slice( f.as_raw_fd(),
++ /// 2, //offset
++ /// WBUF,
++ /// 0, //priority
++ /// SigevNotify::SigevNone,
++ /// LioOpcode::LIO_NOP);
++ /// aiocb.write().unwrap();
++ /// while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) {
++ /// thread::sleep(time::Duration::from_millis(10));
++ /// }
++ /// assert_eq!(aiocb.aio_return().unwrap() as usize, WBUF.len());
++ /// # }
++ /// ```
++ // Note: another solution to the problem of writing const buffers would be
++ // to genericize AioCb for both &mut [u8] and &[u8] buffers. AioCb::read
++ // could take the former and AioCb::write could take the latter. However,
++ // then lio_listio wouldn't work, because that function needs a slice of
++ // AioCb, and they must all be of the same type.
++ pub fn from_slice(fd: RawFd, offs: off_t, buf: &'a [u8],
++ prio: libc::c_int, sigev_notify: SigevNotify,
++ opcode: LioOpcode) -> AioCb {
++ let mut a = AioCb::common_init(fd, prio, sigev_notify);
++ a.aio_offset = offs;
++ a.aio_nbytes = buf.len() as size_t;
++ // casting an immutable buffer to a mutable pointer looks unsafe,
++ // but technically its only unsafe to dereference it, not to create
++ // it.
++ a.aio_buf = buf.as_ptr() as *mut c_void;
++ assert!(opcode != LioOpcode::LIO_READ, "Can't read into an immutable buffer");
++ a.aio_lio_opcode = opcode as libc::c_int;
++
++ AioCb {
++ aiocb: a,
++ mutable: false,
++ in_progress: false,
++ buffer: Buffer::None,
++ }
++ }
++
++ fn common_init(fd: RawFd, prio: libc::c_int,
++ sigev_notify: SigevNotify) -> libc::aiocb {
++ // Use mem::zeroed instead of explicitly zeroing each field, because the
++ // number and name of reserved fields is OS-dependent. On some OSes,
++ // some reserved fields are used the kernel for state, and must be
++ // explicitly zeroed when allocated.
++ let mut a = unsafe { mem::zeroed::<libc::aiocb>()};
++ a.aio_fildes = fd;
++ a.aio_reqprio = prio;
++ a.aio_sigevent = SigEvent::new(sigev_notify).sigevent();
++ a
++ }
++
++ /// Update the notification settings for an existing `aiocb`
++ pub fn set_sigev_notify(&mut self, sigev_notify: SigevNotify) {
++ self.aiocb.aio_sigevent = SigEvent::new(sigev_notify).sigevent();
++ }
++
++ /// Cancels an outstanding AIO request.
++ ///
++ /// The operating system is not required to implement cancellation for all
++ /// file and device types. Even if it does, there is no guarantee that the
++ /// operation has not already completed. So the caller must check the
++ /// result and handle operations that were not canceled or that have already
++ /// completed.
++ ///
++ /// # Examples
++ ///
++ /// Cancel an outstanding aio operation. Note that we must still call
++ /// `aio_return` to free resources, even though we don't care about the
++ /// result.
++ ///
++ /// ```
++ /// # extern crate tempfile;
++ /// # extern crate nix;
++ /// # use nix::errno::Errno;
++ /// # use nix::Error;
++ /// # use nix::sys::aio::*;
++ /// # use nix::sys::signal::SigevNotify;
++ /// # use std::{thread, time};
++ /// # use std::io::Write;
++ /// # use std::os::unix::io::AsRawFd;
++ /// # use tempfile::tempfile;
++ /// # fn main() {
++ /// let wbuf = b"CDEF";
++ /// let mut f = tempfile().unwrap();
++ /// let mut aiocb = AioCb::from_slice( f.as_raw_fd(),
++ /// 2, //offset
++ /// &wbuf[..],
++ /// 0, //priority
++ /// SigevNotify::SigevNone,
++ /// LioOpcode::LIO_NOP);
++ /// aiocb.write().unwrap();
++ /// let cs = aiocb.cancel().unwrap();
++ /// if cs == AioCancelStat::AioNotCanceled {
++ /// while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) {
++ /// thread::sleep(time::Duration::from_millis(10));
++ /// }
++ /// }
++ /// // Must call `aio_return`, but ignore the result
++ /// let _ = aiocb.aio_return();
++ /// # }
++ /// ```
++ ///
++ /// # References
++ ///
++ /// [aio_cancel](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_cancel.html)
++ pub fn cancel(&mut self) -> Result<AioCancelStat> {
++ match unsafe { libc::aio_cancel(self.aiocb.aio_fildes, &mut self.aiocb) } {
++ libc::AIO_CANCELED => Ok(AioCancelStat::AioCanceled),
++ libc::AIO_NOTCANCELED => Ok(AioCancelStat::AioNotCanceled),
++ libc::AIO_ALLDONE => Ok(AioCancelStat::AioAllDone),
++ -1 => Err(Error::last()),
++ _ => panic!("unknown aio_cancel return value")
++ }
++ }
++
++ /// Retrieve error status of an asynchronous operation.
++ ///
++ /// If the request has not yet completed, returns `EINPROGRESS`. Otherwise,
++ /// returns `Ok` or any other error.
++ ///
++ /// # Examples
++ ///
++ /// Issue an aio operation and use `error` to poll for completion. Polling
++ /// is an alternative to `aio_suspend`, used by most of the other examples.
++ ///
++ /// ```
++ /// # extern crate tempfile;
++ /// # extern crate nix;
++ /// # use nix::errno::Errno;
++ /// # use nix::Error;
++ /// # use nix::sys::aio::*;
++ /// # use nix::sys::signal::SigevNotify;
++ /// # use std::{thread, time};
++ /// # use std::os::unix::io::AsRawFd;
++ /// # use tempfile::tempfile;
++ /// # fn main() {
++ /// const WBUF: &[u8] = b"abcdef123456";
++ /// let mut f = tempfile().unwrap();
++ /// let mut aiocb = AioCb::from_slice( f.as_raw_fd(),
++ /// 2, //offset
++ /// WBUF,
++ /// 0, //priority
++ /// SigevNotify::SigevNone,
++ /// LioOpcode::LIO_NOP);
++ /// aiocb.write().unwrap();
++ /// while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) {
++ /// thread::sleep(time::Duration::from_millis(10));
++ /// }
++ /// assert_eq!(aiocb.aio_return().unwrap() as usize, WBUF.len());
++ /// # }
++ /// ```
++ ///
++ /// # References
++ ///
++ /// [aio_error](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_error.html)
++ pub fn error(&mut self) -> Result<()> {
++ match unsafe { libc::aio_error(&mut self.aiocb as *mut libc::aiocb) } {
++ 0 => Ok(()),
++ num if num > 0 => Err(Error::from_errno(Errno::from_i32(num))),
++ -1 => Err(Error::last()),
++ num => panic!("unknown aio_error return value {:?}", num)
++ }
++ }
++
++ /// An asynchronous version of `fsync(2)`.
++ ///
++ /// # References
++ ///
++ /// [aio_fsync](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_fsync.html)
++ pub fn fsync(&mut self, mode: AioFsyncMode) -> Result<()> {
++ let p: *mut libc::aiocb = &mut self.aiocb;
++ Errno::result(unsafe {
++ libc::aio_fsync(mode as libc::c_int, p)
++ }).map(|_| {
++ self.in_progress = true;
++ })
++ }
++
++ /// Returns the `aiocb`'s `LioOpcode` field
++ ///
++ /// If the value cannot be represented as an `LioOpcode`, returns `None`
++ /// instead.
++ pub fn lio_opcode(&self) -> Option<LioOpcode> {
++ match self.aiocb.aio_lio_opcode {
++ libc::LIO_READ => Some(LioOpcode::LIO_READ),
++ libc::LIO_WRITE => Some(LioOpcode::LIO_WRITE),
++ libc::LIO_NOP => Some(LioOpcode::LIO_NOP),
++ _ => None
++ }
++ }
++
++ /// Returns the requested length of the aio operation in bytes
++ ///
++ /// This method returns the *requested* length of the operation. To get the
++ /// number of bytes actually read or written by a completed operation, use
++ /// `aio_return` instead.
++ pub fn nbytes(&self) -> usize {
++ self.aiocb.aio_nbytes
++ }
++
++ /// Returns the file offset stored in the `AioCb`
++ pub fn offset(&self) -> off_t {
++ self.aiocb.aio_offset
++ }
++
++ /// Returns the priority of the `AioCb`
++ pub fn priority(&self) -> libc::c_int {
++ self.aiocb.aio_reqprio
++ }
++
++ /// Asynchronously reads from a file descriptor into a buffer
++ ///
++ /// # References
++ ///
++ /// [aio_read](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_read.html)
++ pub fn read(&mut self) -> Result<()> {
++ assert!(self.mutable, "Can't read into an immutable buffer");
++ let p: *mut libc::aiocb = &mut self.aiocb;
++ Errno::result(unsafe {
++ libc::aio_read(p)
++ }).map(|_| {
++ self.in_progress = true;
++ })
++ }
++
++ /// Returns the `SigEvent` stored in the `AioCb`
++ pub fn sigevent(&self) -> SigEvent {
++ SigEvent::from(&self.aiocb.aio_sigevent)
++ }
++
++ /// Retrieve return status of an asynchronous operation.
++ ///
++ /// Should only be called once for each `AioCb`, after `AioCb::error`
++ /// indicates that it has completed. The result is the same as for the
++ /// synchronous `read(2)`, `write(2)`, of `fsync(2)` functions.
++ ///
++ /// # References
++ ///
++ /// [aio_return](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_return.html)
++ // Note: this should be just `return`, but that's a reserved word
++ pub fn aio_return(&mut self) -> Result<isize> {
++ let p: *mut libc::aiocb = &mut self.aiocb;
++ self.in_progress = false;
++ Errno::result(unsafe { libc::aio_return(p) })
++ }
++
++ /// Asynchronously writes from a buffer to a file descriptor
++ ///
++ /// # References
++ ///
++ /// [aio_write](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_write.html)
++ pub fn write(&mut self) -> Result<()> {
++ let p: *mut libc::aiocb = &mut self.aiocb;
++ Errno::result(unsafe {
++ libc::aio_write(p)
++ }).map(|_| {
++ self.in_progress = true;
++ })
++ }
++
++}
++
++/// Cancels outstanding AIO requests for a given file descriptor.
++///
++/// # Examples
++///
++/// Issue an aio operation, then cancel all outstanding operations on that file
++/// descriptor.
++///
++/// ```
++/// # extern crate tempfile;
++/// # extern crate nix;
++/// # use nix::errno::Errno;
++/// # use nix::Error;
++/// # use nix::sys::aio::*;
++/// # use nix::sys::signal::SigevNotify;
++/// # use std::{thread, time};
++/// # use std::io::Write;
++/// # use std::os::unix::io::AsRawFd;
++/// # use tempfile::tempfile;
++/// # fn main() {
++/// let wbuf = b"CDEF";
++/// let mut f = tempfile().unwrap();
++/// let mut aiocb = AioCb::from_slice( f.as_raw_fd(),
++/// 2, //offset
++/// &wbuf[..],
++/// 0, //priority
++/// SigevNotify::SigevNone,
++/// LioOpcode::LIO_NOP);
++/// aiocb.write().unwrap();
++/// let cs = aio_cancel_all(f.as_raw_fd()).unwrap();
++/// if cs == AioCancelStat::AioNotCanceled {
++/// while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) {
++/// thread::sleep(time::Duration::from_millis(10));
++/// }
++/// }
++/// // Must call `aio_return`, but ignore the result
++/// let _ = aiocb.aio_return();
++/// # }
++/// ```
++///
++/// # References
++///
++/// [`aio_cancel`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_cancel.html)
++pub fn aio_cancel_all(fd: RawFd) -> Result<AioCancelStat> {
++ match unsafe { libc::aio_cancel(fd, null_mut()) } {
++ libc::AIO_CANCELED => Ok(AioCancelStat::AioCanceled),
++ libc::AIO_NOTCANCELED => Ok(AioCancelStat::AioNotCanceled),
++ libc::AIO_ALLDONE => Ok(AioCancelStat::AioAllDone),
++ -1 => Err(Error::last()),
++ _ => panic!("unknown aio_cancel return value")
++ }
++}
++
++/// Suspends the calling process until at least one of the specified `AioCb`s
++/// has completed, a signal is delivered, or the timeout has passed.
++///
++/// If `timeout` is `None`, `aio_suspend` will block indefinitely.
++///
++/// # Examples
++///
++/// Use `aio_suspend` to block until an aio operation completes.
++///
++// Disable doctest due to a known bug in FreeBSD's 32-bit emulation. The fix
++// will be included in release 11.2.
++// FIXME reenable the doc test when the CI machine gets upgraded to that release.
++// https://svnweb.freebsd.org/base?view=revision&revision=325018
++/// ```no_run
++/// # extern crate tempfile;
++/// # extern crate nix;
++/// # use nix::sys::aio::*;
++/// # use nix::sys::signal::SigevNotify;
++/// # use std::os::unix::io::AsRawFd;
++/// # use tempfile::tempfile;
++/// # fn main() {
++/// const WBUF: &[u8] = b"abcdef123456";
++/// let mut f = tempfile().unwrap();
++/// let mut aiocb = AioCb::from_slice( f.as_raw_fd(),
++/// 2, //offset
++/// WBUF,
++/// 0, //priority
++/// SigevNotify::SigevNone,
++/// LioOpcode::LIO_NOP);
++/// aiocb.write().unwrap();
++/// aio_suspend(&[&aiocb], None).expect("aio_suspend failed");
++/// assert_eq!(aiocb.aio_return().unwrap() as usize, WBUF.len());
++/// # }
++/// ```
++/// # References
++///
++/// [`aio_suspend`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_suspend.html)
++pub fn aio_suspend(list: &[&AioCb], timeout: Option<TimeSpec>) -> Result<()> {
++ let plist = list as *const [&AioCb] as *const [*const libc::aiocb];
++ let p = plist as *const *const libc::aiocb;
++ let timep = match timeout {
++ None => null::<libc::timespec>(),
++ Some(x) => x.as_ref() as *const libc::timespec
++ };
++ Errno::result(unsafe {
++ libc::aio_suspend(p, list.len() as i32, timep)
++ }).map(drop)
++}
++
++impl<'a> Debug for AioCb<'a> {
++ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
++ fmt.debug_struct("AioCb")
++ .field("aiocb", &self.aiocb)
++ .field("mutable", &self.mutable)
++ .field("in_progress", &self.in_progress)
++ .finish()
++ }
++}
++
++impl<'a> Drop for AioCb<'a> {
++ /// If the `AioCb` has no remaining state in the kernel, just drop it.
++ /// Otherwise, dropping constitutes a resource leak, which is an error
++ fn drop(&mut self) {
++ assert!(thread::panicking() || !self.in_progress,
++ "Dropped an in-progress AioCb");
++ }
++}
++
++/// LIO Control Block.
++///
++/// The basic structure used to issue multiple AIO operations simultaneously.
++#[cfg(not(any(target_os = "ios", target_os = "macos")))]
++pub struct LioCb<'a> {
++ /// A collection of [`AioCb`]s. All of these will be issued simultaneously
++ /// by the [`listio`] method.
++ ///
++ /// [`AioCb`]: struct.AioCb.html
++ /// [`listio`]: #method.listio
++ pub aiocbs: Vec<AioCb<'a>>,
++
++ /// The actual list passed to `libc::lio_listio`.
++ ///
++ /// It must live for as long as any of the operations are still being
++ /// processesed, because the aio subsystem uses its address as a unique
++ /// identifier.
++ list: Vec<*mut libc::aiocb>,
++
++ /// A partial set of results. This field will get populated by
++ /// `listio_resubmit` when an `LioCb` is resubmitted after an error
++ results: Vec<Option<Result<isize>>>
++}
++
++#[cfg(not(any(target_os = "ios", target_os = "macos")))]
++impl<'a> LioCb<'a> {
++ /// Initialize an empty `LioCb`
++ pub fn with_capacity(capacity: usize) -> LioCb<'a> {
++ LioCb {
++ aiocbs: Vec::with_capacity(capacity),
++ list: Vec::with_capacity(capacity),
++ results: Vec::with_capacity(capacity)
++ }
++ }
++
++ /// Submits multiple asynchronous I/O requests with a single system call.
++ ///
++ /// They are not guaranteed to complete atomically, and the order in which
++ /// the requests are carried out is not specified. Reads, writes, and
++ /// fsyncs may be freely mixed.
++ ///
++ /// This function is useful for reducing the context-switch overhead of
++ /// submitting many AIO operations. It can also be used with
++ /// `LioMode::LIO_WAIT` to block on the result of several independent
++ /// operations. Used that way, it is often useful in programs that
++ /// otherwise make little use of AIO.
++ ///
++ /// # Examples
++ ///
++ /// Use `listio` to submit an aio operation and wait for its completion. In
++ /// this case, there is no need to use [`aio_suspend`] to wait or
++ /// [`AioCb::error`] to poll.
++ ///
++ /// ```
++ /// # extern crate tempfile;
++ /// # extern crate nix;
++ /// # use nix::sys::aio::*;
++ /// # use nix::sys::signal::SigevNotify;
++ /// # use std::os::unix::io::AsRawFd;
++ /// # use tempfile::tempfile;
++ /// # fn main() {
++ /// const WBUF: &[u8] = b"abcdef123456";
++ /// let mut f = tempfile().unwrap();
++ /// let mut liocb = LioCb::with_capacity(1);
++ /// liocb.aiocbs.push(AioCb::from_slice( f.as_raw_fd(),
++ /// 2, //offset
++ /// WBUF,
++ /// 0, //priority
++ /// SigevNotify::SigevNone,
++ /// LioOpcode::LIO_WRITE));
++ /// liocb.listio(LioMode::LIO_WAIT,
++ /// SigevNotify::SigevNone).unwrap();
++ /// assert_eq!(liocb.aio_return(0).unwrap() as usize, WBUF.len());
++ /// # }
++ /// ```
++ ///
++ /// # References
++ ///
++ /// [`lio_listio`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/lio_listio.html)
++ ///
++ /// [`aio_suspend`]: fn.aio_suspend.html
++ /// [`AioCb::error`]: struct.AioCb.html#method.error
++ pub fn listio(&mut self, mode: LioMode,
++ sigev_notify: SigevNotify) -> Result<()> {
++ let sigev = SigEvent::new(sigev_notify);
++ let sigevp = &mut sigev.sigevent() as *mut libc::sigevent;
++ self.list.clear();
++ for a in &mut self.aiocbs {
++ a.in_progress = true;
++ self.list.push(a as *mut AioCb<'a>
++ as *mut libc::aiocb);
++ }
++ let p = self.list.as_ptr();
++ Errno::result(unsafe {
++ libc::lio_listio(mode as i32, p, self.list.len() as i32, sigevp)
++ }).map(drop)
++ }
++
++ /// Resubmits any incomplete operations with [`lio_listio`].
++ ///
++ /// Sometimes, due to system resource limitations, an `lio_listio` call will
++ /// return `EIO`, or `EAGAIN`. Or, if a signal is received, it may return
++ /// `EINTR`. In any of these cases, only a subset of its constituent
++ /// operations will actually have been initiated. `listio_resubmit` will
++ /// resubmit any operations that are still uninitiated.
++ ///
++ /// After calling `listio_resubmit`, results should be collected by
++ /// [`LioCb::aio_return`].
++ ///
++ /// # Examples
++ /// ```no_run
++ /// # extern crate tempfile;
++ /// # extern crate nix;
++ /// # use nix::Error;
++ /// # use nix::errno::Errno;
++ /// # use nix::sys::aio::*;
++ /// # use nix::sys::signal::SigevNotify;
++ /// # use std::os::unix::io::AsRawFd;
++ /// # use std::{thread, time};
++ /// # use tempfile::tempfile;
++ /// # fn main() {
++ /// const WBUF: &[u8] = b"abcdef123456";
++ /// let mut f = tempfile().unwrap();
++ /// let mut liocb = LioCb::with_capacity(1);
++ /// liocb.aiocbs.push(AioCb::from_slice( f.as_raw_fd(),
++ /// 2, //offset
++ /// WBUF,
++ /// 0, //priority
++ /// SigevNotify::SigevNone,
++ /// LioOpcode::LIO_WRITE));
++ /// let mut err = liocb.listio(LioMode::LIO_WAIT, SigevNotify::SigevNone);
++ /// while err == Err(Error::Sys(Errno::EIO)) ||
++ /// err == Err(Error::Sys(Errno::EAGAIN)) {
++ /// thread::sleep(time::Duration::from_millis(10));
++ /// err = liocb.listio_resubmit(LioMode::LIO_WAIT, SigevNotify::SigevNone);
++ /// }
++ /// assert_eq!(liocb.aio_return(0).unwrap() as usize, WBUF.len());
++ /// # }
++ /// ```
++ ///
++ /// # References
++ ///
++ /// [`lio_listio`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/lio_listio.html)
++ ///
++ /// [`lio_listio`]: http://pubs.opengroup.org/onlinepubs/9699919799/functions/lio_listio.html
++ /// [`LioCb::aio_return`]: struct.LioCb.html#method.aio_return
++ // Note: the addresses of any EINPROGRESS or EOK aiocbs _must_ not be
++ // changed by this method, because the kernel relies on their addresses
++ // being stable.
++ // Note: aiocbs that are Ok(()) must be finalized by aio_return, or else the
++ // sigev_notify will immediately refire.
++ pub fn listio_resubmit(&mut self, mode:LioMode,
++ sigev_notify: SigevNotify) -> Result<()> {
++ let sigev = SigEvent::new(sigev_notify);
++ let sigevp = &mut sigev.sigevent() as *mut libc::sigevent;
++ self.list.clear();
++
++ while self.results.len() < self.aiocbs.len() {
++ self.results.push(None);
++ }
++
++ for (i, a) in self.aiocbs.iter_mut().enumerate() {
++ if self.results[i].is_some() {
++ // Already collected final status for this operation
++ continue;
++ }
++ match a.error() {
++ Ok(()) => {
++ // aiocb is complete; collect its status and don't resubmit
++ self.results[i] = Some(a.aio_return());
++ },
++ Err(Error::Sys(Errno::EAGAIN)) => {
++ self.list.push(a as *mut AioCb<'a> as *mut libc::aiocb);
++ },
++ Err(Error::Sys(Errno::EINPROGRESS)) => {
++ // aiocb is was successfully queued; no need to do anything
++ ()
++ },
++ Err(Error::Sys(Errno::EINVAL)) => panic!(
++ "AioCb was never submitted, or already finalized"),
++ _ => unreachable!()
++ }
++ }
++ let p = self.list.as_ptr();
++ Errno::result(unsafe {
++ libc::lio_listio(mode as i32, p, self.list.len() as i32, sigevp)
++ }).map(drop)
++ }
++
++ /// Collect final status for an individual `AioCb` submitted as part of an
++ /// `LioCb`.
++ ///
++ /// This is just like [`AioCb::aio_return`], except it takes into account
++ /// operations that were restarted by [`LioCb::listio_resubmit`]
++ ///
++ /// [`AioCb::aio_return`]: struct.AioCb.html#method.aio_return
++ /// [`LioCb::listio_resubmit`]: #method.listio_resubmit
++ pub fn aio_return(&mut self, i: usize) -> Result<isize> {
++ if i >= self.results.len() || self.results[i].is_none() {
++ self.aiocbs[i].aio_return()
++ } else {
++ self.results[i].unwrap()
++ }
++ }
++
++ /// Retrieve error status of an individual `AioCb` submitted as part of an
++ /// `LioCb`.
++ ///
++ /// This is just like [`AioCb::error`], except it takes into account
++ /// operations that were restarted by [`LioCb::listio_resubmit`]
++ ///
++ /// [`AioCb::error`]: struct.AioCb.html#method.error
++ /// [`LioCb::listio_resubmit`]: #method.listio_resubmit
++ pub fn error(&mut self, i: usize) -> Result<()> {
++ if i >= self.results.len() || self.results[i].is_none() {
++ self.aiocbs[i].error()
++ } else {
++ Ok(())
++ }
++ }
++}
++
++#[cfg(not(any(target_os = "ios", target_os = "macos")))]
++impl<'a> Debug for LioCb<'a> {
++ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
++ fmt.debug_struct("LioCb")
++ .field("aiocbs", &self.aiocbs)
++ .finish()
++ }
++}
++
++#[cfg(not(any(target_os = "ios", target_os = "macos")))]
++impl<'a> From<Vec<AioCb<'a>>> for LioCb<'a> {
++ fn from(src: Vec<AioCb<'a>>) -> LioCb<'a> {
++ LioCb {
++ list: Vec::with_capacity(src.capacity()),
++ results: Vec::with_capacity(src.capacity()),
++ aiocbs: src,
++ }
++ }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/epoll.rs b/third_party/rust/nix-0.15.0/src/sys/epoll.rs
+new file mode 100644
+index 0000000000000..fef6f4e3ec92c
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/epoll.rs
+@@ -0,0 +1,109 @@
++use Result;
++use errno::Errno;
++use libc::{self, c_int};
++use std::os::unix::io::RawFd;
++use std::ptr;
++use std::mem;
++use ::Error;
++
++libc_bitflags!(
++ pub struct EpollFlags: c_int {
++ EPOLLIN;
++ EPOLLPRI;
++ EPOLLOUT;
++ EPOLLRDNORM;
++ EPOLLRDBAND;
++ EPOLLWRNORM;
++ EPOLLWRBAND;
++ EPOLLMSG;
++ EPOLLERR;
++ EPOLLHUP;
++ EPOLLRDHUP;
++ #[cfg(target_os = "linux")] // Added in 4.5; not in Android.
++ EPOLLEXCLUSIVE;
++ #[cfg(not(target_arch = "mips"))]
++ EPOLLWAKEUP;
++ EPOLLONESHOT;
++ EPOLLET;
++ }
++);
++
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++#[repr(i32)]
++pub enum EpollOp {
++ EpollCtlAdd = libc::EPOLL_CTL_ADD,
++ EpollCtlDel = libc::EPOLL_CTL_DEL,
++ EpollCtlMod = libc::EPOLL_CTL_MOD,
++}
++
++libc_bitflags!{
++ pub struct EpollCreateFlags: c_int {
++ EPOLL_CLOEXEC;
++ }
++}
++
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++#[repr(C)]
++pub struct EpollEvent {
++ event: libc::epoll_event,
++}
++
++impl EpollEvent {
++ pub fn new(events: EpollFlags, data: u64) -> Self {
++ EpollEvent { event: libc::epoll_event { events: events.bits() as u32, u64: data } }
++ }
++
++ pub fn empty() -> Self {
++ unsafe { mem::zeroed::<EpollEvent>() }
++ }
++
++ pub fn events(&self) -> EpollFlags {
++ EpollFlags::from_bits(self.event.events as c_int).unwrap()
++ }
++
++ pub fn data(&self) -> u64 {
++ self.event.u64
++ }
++}
++
++#[inline]
++pub fn epoll_create() -> Result<RawFd> {
++ let res = unsafe { libc::epoll_create(1024) };
++
++ Errno::result(res)
++}
++
++#[inline]
++pub fn epoll_create1(flags: EpollCreateFlags) -> Result<RawFd> {
++ let res = unsafe { libc::epoll_create1(flags.bits()) };
++
++ Errno::result(res)
++}
++
++#[inline]
++pub fn epoll_ctl<'a, T>(epfd: RawFd, op: EpollOp, fd: RawFd, event: T) -> Result<()>
++ where T: Into<Option<&'a mut EpollEvent>>
++{
++ let mut event: Option<&mut EpollEvent> = event.into();
++ if event.is_none() && op != EpollOp::EpollCtlDel {
++ Err(Error::Sys(Errno::EINVAL))
++ } else {
++ let res = unsafe {
++ if let Some(ref mut event) = event {
++ libc::epoll_ctl(epfd, op as c_int, fd, &mut event.event)
++ } else {
++ libc::epoll_ctl(epfd, op as c_int, fd, ptr::null_mut())
++ }
++ };
++ Errno::result(res).map(drop)
++ }
++}
++
++#[inline]
++pub fn epoll_wait(epfd: RawFd, events: &mut [EpollEvent], timeout_ms: isize) -> Result<usize> {
++ let res = unsafe {
++ libc::epoll_wait(epfd, events.as_mut_ptr() as *mut libc::epoll_event, events.len() as c_int, timeout_ms as c_int)
++ };
++
++ Errno::result(res).map(|r| r as usize)
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/event.rs b/third_party/rust/nix-0.15.0/src/sys/event.rs
+new file mode 100644
+index 0000000000000..8cd7372f88188
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/event.rs
+@@ -0,0 +1,351 @@
++/* TOOD: Implement for other kqueue based systems
++ */
++
++use {Errno, Result};
++#[cfg(not(target_os = "netbsd"))]
++use libc::{timespec, time_t, c_int, c_long, intptr_t, uintptr_t};
++#[cfg(target_os = "netbsd")]
++use libc::{timespec, time_t, c_long, intptr_t, uintptr_t, size_t};
++use libc;
++use std::os::unix::io::RawFd;
++use std::ptr;
++use std::mem;
++
++// Redefine kevent in terms of programmer-friendly enums and bitfields.
++#[repr(C)]
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub struct KEvent {
++ kevent: libc::kevent,
++}
++
++#[cfg(any(target_os = "dragonfly", target_os = "freebsd",
++ target_os = "ios", target_os = "macos",
++ target_os = "openbsd"))]
++type type_of_udata = *mut libc::c_void;
++#[cfg(any(target_os = "dragonfly", target_os = "freebsd",
++ target_os = "ios", target_os = "macos"))]
++type type_of_data = intptr_t;
++#[cfg(any(target_os = "netbsd"))]
++type type_of_udata = intptr_t;
++#[cfg(any(target_os = "netbsd", target_os = "openbsd"))]
++type type_of_data = libc::int64_t;
++
++#[cfg(target_os = "netbsd")]
++type type_of_event_filter = u32;
++#[cfg(not(target_os = "netbsd"))]
++type type_of_event_filter = i16;
++libc_enum! {
++ #[cfg_attr(target_os = "netbsd", repr(u32))]
++ #[cfg_attr(not(target_os = "netbsd"), repr(i16))]
++ pub enum EventFilter {
++ EVFILT_AIO,
++ /// Returns whenever there is no remaining data in the write buffer
++ #[cfg(target_os = "freebsd")]
++ EVFILT_EMPTY,
++ #[cfg(target_os = "dragonfly")]
++ EVFILT_EXCEPT,
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos"))]
++ EVFILT_FS,
++ #[cfg(target_os = "freebsd")]
++ EVFILT_LIO,
++ #[cfg(any(target_os = "ios", target_os = "macos"))]
++ EVFILT_MACHPORT,
++ EVFILT_PROC,
++ /// Returns events associated with the process referenced by a given
++ /// process descriptor, created by `pdfork()`. The events to monitor are:
++ ///
++ /// - NOTE_EXIT: the process has exited. The exit status will be stored in data.
++ #[cfg(target_os = "freebsd")]
++ EVFILT_PROCDESC,
++ EVFILT_READ,
++ /// Returns whenever an asynchronous `sendfile()` call completes.
++ #[cfg(target_os = "freebsd")]
++ EVFILT_SENDFILE,
++ EVFILT_SIGNAL,
++ EVFILT_TIMER,
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos"))]
++ EVFILT_USER,
++ #[cfg(any(target_os = "ios", target_os = "macos"))]
++ EVFILT_VM,
++ EVFILT_VNODE,
++ EVFILT_WRITE,
++ }
++}
++
++#[cfg(any(target_os = "dragonfly", target_os = "freebsd",
++ target_os = "ios", target_os = "macos",
++ target_os = "openbsd"))]
++pub type type_of_event_flag = u16;
++#[cfg(any(target_os = "netbsd"))]
++pub type type_of_event_flag = u32;
++libc_bitflags!{
++ pub struct EventFlag: type_of_event_flag {
++ EV_ADD;
++ EV_CLEAR;
++ EV_DELETE;
++ EV_DISABLE;
++ // No released version of OpenBSD supports EV_DISPATCH or EV_RECEIPT.
++ // These have been commited to the -current branch though and are
++ // expected to be part of the OpenBSD 6.2 release in Nov 2017.
++ // See: https://marc.info/?l=openbsd-tech&m=149621427511219&w=2
++ // https://github.com/rust-lang/libc/pull/613
++ #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
++ target_os = "ios", target_os = "macos",
++ target_os = "netbsd"))]
++ EV_DISPATCH;
++ #[cfg(target_os = "freebsd")]
++ EV_DROP;
++ EV_ENABLE;
++ EV_EOF;
++ EV_ERROR;
++ #[cfg(any(target_os = "macos", target_os = "ios"))]
++ EV_FLAG0;
++ EV_FLAG1;
++ #[cfg(target_os = "dragonfly")]
++ EV_NODATA;
++ EV_ONESHOT;
++ #[cfg(any(target_os = "macos", target_os = "ios"))]
++ EV_OOBAND;
++ #[cfg(any(target_os = "macos", target_os = "ios"))]
++ EV_POLL;
++ #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
++ target_os = "ios", target_os = "macos",
++ target_os = "netbsd"))]
++ EV_RECEIPT;
++ EV_SYSFLAGS;
++ }
++}
++
++libc_bitflags!(
++ pub struct FilterFlag: u32 {
++ #[cfg(any(target_os = "macos", target_os = "ios"))]
++ NOTE_ABSOLUTE;
++ NOTE_ATTRIB;
++ NOTE_CHILD;
++ NOTE_DELETE;
++ #[cfg(target_os = "openbsd")]
++ NOTE_EOF;
++ NOTE_EXEC;
++ NOTE_EXIT;
++ #[cfg(any(target_os = "macos", target_os = "ios"))]
++ #[deprecated( since="0.14.0", note="Deprecated since OSX 10.9")]
++ #[allow(deprecated)]
++ NOTE_EXIT_REPARENTED;
++ #[cfg(any(target_os = "macos", target_os = "ios"))]
++ NOTE_EXITSTATUS;
++ NOTE_EXTEND;
++ #[cfg(any(target_os = "macos",
++ target_os = "ios",
++ target_os = "freebsd",
++ target_os = "dragonfly"))]
++ NOTE_FFAND;
++ #[cfg(any(target_os = "macos",
++ target_os = "ios",
++ target_os = "freebsd",
++ target_os = "dragonfly"))]
++ NOTE_FFCOPY;
++ #[cfg(any(target_os = "macos",
++ target_os = "ios",
++ target_os = "freebsd",
++ target_os = "dragonfly"))]
++ NOTE_FFCTRLMASK;
++ #[cfg(any(target_os = "macos",
++ target_os = "ios",
++ target_os = "freebsd",
++ target_os = "dragonfly"))]
++ NOTE_FFLAGSMASK;
++ #[cfg(any(target_os = "macos",
++ target_os = "ios",
++ target_os = "freebsd",
++ target_os = "dragonfly"))]
++ NOTE_FFNOP;
++ #[cfg(any(target_os = "macos",
++ target_os = "ios",
++ target_os = "freebsd",
++ target_os = "dragonfly"))]
++ NOTE_FFOR;
++ NOTE_FORK;
++ NOTE_LINK;
++ NOTE_LOWAT;
++ #[cfg(target_os = "freebsd")]
++ NOTE_MSECONDS;
++ #[cfg(any(target_os = "macos", target_os = "ios"))]
++ NOTE_NONE;
++ #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
++ NOTE_NSECONDS;
++ #[cfg(target_os = "dragonfly")]
++ NOTE_OOB;
++ NOTE_PCTRLMASK;
++ NOTE_PDATAMASK;
++ #[cfg(any(target_os = "macos", target_os = "ios"))]
++ #[cfg(any(target_os = "macos", target_os = "ios"))]
++ #[deprecated( since="0.14.0", note="Deprecated since OSX 10.9")]
++ #[allow(deprecated)]
++ NOTE_REAP;
++ NOTE_RENAME;
++ NOTE_REVOKE;
++ #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
++ NOTE_SECONDS;
++ #[cfg(any(target_os = "macos", target_os = "ios"))]
++ NOTE_SIGNAL;
++ NOTE_TRACK;
++ NOTE_TRACKERR;
++ #[cfg(any(target_os = "macos",
++ target_os = "ios",
++ target_os = "freebsd",
++ target_os = "dragonfly"))]
++ NOTE_TRIGGER;
++ #[cfg(target_os = "openbsd")]
++ NOTE_TRUNCATE;
++ #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
++ NOTE_USECONDS;
++ #[cfg(any(target_os = "macos", target_os = "ios"))]
++ NOTE_VM_ERROR;
++ #[cfg(any(target_os = "macos", target_os = "ios"))]
++ NOTE_VM_PRESSURE;
++ #[cfg(any(target_os = "macos", target_os = "ios"))]
++ NOTE_VM_PRESSURE_SUDDEN_TERMINATE;
++ #[cfg(any(target_os = "macos", target_os = "ios"))]
++ NOTE_VM_PRESSURE_TERMINATE;
++ NOTE_WRITE;
++ }
++);
++
++pub fn kqueue() -> Result<RawFd> {
++ let res = unsafe { libc::kqueue() };
++
++ Errno::result(res)
++}
++
++
++// KEvent can't derive Send because on some operating systems, udata is defined
++// as a void*. However, KEvent's public API always treats udata as an intptr_t,
++// which is safe to Send.
++unsafe impl Send for KEvent {
++}
++
++impl KEvent {
++ pub fn new(ident: uintptr_t, filter: EventFilter, flags: EventFlag,
++ fflags:FilterFlag, data: intptr_t, udata: intptr_t) -> KEvent {
++ KEvent { kevent: libc::kevent {
++ ident: ident,
++ filter: filter as type_of_event_filter,
++ flags: flags.bits(),
++ fflags: fflags.bits(),
++ data: data as type_of_data,
++ udata: udata as type_of_udata
++ } }
++ }
++
++ pub fn ident(&self) -> uintptr_t {
++ self.kevent.ident
++ }
++
++ pub fn filter(&self) -> EventFilter {
++ unsafe { mem::transmute(self.kevent.filter as type_of_event_filter) }
++ }
++
++ pub fn flags(&self) -> EventFlag {
++ EventFlag::from_bits(self.kevent.flags).unwrap()
++ }
++
++ pub fn fflags(&self) -> FilterFlag {
++ FilterFlag::from_bits(self.kevent.fflags).unwrap()
++ }
++
++ pub fn data(&self) -> intptr_t {
++ self.kevent.data as intptr_t
++ }
++
++ pub fn udata(&self) -> intptr_t {
++ self.kevent.udata as intptr_t
++ }
++}
++
++pub fn kevent(kq: RawFd,
++ changelist: &[KEvent],
++ eventlist: &mut [KEvent],
++ timeout_ms: usize) -> Result<usize> {
++
++ // Convert ms to timespec
++ let timeout = timespec {
++ tv_sec: (timeout_ms / 1000) as time_t,
++ tv_nsec: ((timeout_ms % 1000) * 1_000_000) as c_long
++ };
++
++ kevent_ts(kq, changelist, eventlist, Some(timeout))
++}
++
++#[cfg(any(target_os = "macos",
++ target_os = "ios",
++ target_os = "freebsd",
++ target_os = "dragonfly",
++ target_os = "openbsd"))]
++type type_of_nchanges = c_int;
++#[cfg(target_os = "netbsd")]
++type type_of_nchanges = size_t;
++
++pub fn kevent_ts(kq: RawFd,
++ changelist: &[KEvent],
++ eventlist: &mut [KEvent],
++ timeout_opt: Option<timespec>) -> Result<usize> {
++
++ let res = unsafe {
++ libc::kevent(
++ kq,
++ changelist.as_ptr() as *const libc::kevent,
++ changelist.len() as type_of_nchanges,
++ eventlist.as_mut_ptr() as *mut libc::kevent,
++ eventlist.len() as type_of_nchanges,
++ if let Some(ref timeout) = timeout_opt {timeout as *const timespec} else {ptr::null()})
++ };
++
++ Errno::result(res).map(|r| r as usize)
++}
++
++#[inline]
++pub fn ev_set(ev: &mut KEvent,
++ ident: usize,
++ filter: EventFilter,
++ flags: EventFlag,
++ fflags: FilterFlag,
++ udata: intptr_t) {
++
++ ev.kevent.ident = ident as uintptr_t;
++ ev.kevent.filter = filter as type_of_event_filter;
++ ev.kevent.flags = flags.bits();
++ ev.kevent.fflags = fflags.bits();
++ ev.kevent.data = 0;
++ ev.kevent.udata = udata as type_of_udata;
++}
++
++#[test]
++fn test_struct_kevent() {
++ let udata : intptr_t = 12345;
++
++ let expected = libc::kevent{ident: 0xdead_beef,
++ filter: libc::EVFILT_READ,
++ flags: libc::EV_ONESHOT | libc::EV_ADD,
++ fflags: libc::NOTE_CHILD | libc::NOTE_EXIT,
++ data: 0x1337,
++ udata: udata as type_of_udata};
++ let actual = KEvent::new(0xdead_beef,
++ EventFilter::EVFILT_READ,
++ EventFlag::EV_ONESHOT | EventFlag::EV_ADD,
++ FilterFlag::NOTE_CHILD | FilterFlag::NOTE_EXIT,
++ 0x1337,
++ udata);
++ assert!(expected.ident == actual.ident());
++ assert!(expected.filter == actual.filter() as type_of_event_filter);
++ assert!(expected.flags == actual.flags().bits());
++ assert!(expected.fflags == actual.fflags().bits());
++ assert!(expected.data == actual.data() as type_of_data);
++ assert!(expected.udata == actual.udata() as type_of_udata);
++ assert!(mem::size_of::<libc::kevent>() == mem::size_of::<KEvent>());
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/eventfd.rs b/third_party/rust/nix-0.15.0/src/sys/eventfd.rs
+new file mode 100644
+index 0000000000000..c5a54e46a1735
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/eventfd.rs
+@@ -0,0 +1,18 @@
++use libc;
++use std::os::unix::io::RawFd;
++use Result;
++use errno::Errno;
++
++libc_bitflags! {
++ pub struct EfdFlags: libc::c_int {
++ EFD_CLOEXEC; // Since Linux 2.6.27
++ EFD_NONBLOCK; // Since Linux 2.6.27
++ EFD_SEMAPHORE; // Since Linux 2.6.30
++ }
++}
++
++pub fn eventfd(initval: libc::c_uint, flags: EfdFlags) -> Result<RawFd> {
++ let res = unsafe { libc::eventfd(initval, flags.bits()) };
++
++ Errno::result(res).map(|r| r as RawFd)
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/inotify.rs b/third_party/rust/nix-0.15.0/src/sys/inotify.rs
+new file mode 100644
+index 0000000000000..e6c2cf64d29dc
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/inotify.rs
+@@ -0,0 +1,230 @@
++//! Monitoring API for filesystem events.
++//!
++//! Inotify is a Linux-only API to monitor filesystems events.
++//!
++//! For more documentation, please read [inotify(7)](http://man7.org/linux/man-pages/man7/inotify.7.html).
++//!
++//! # Examples
++//!
++//! Monitor all events happening in directory "test":
++//! ```no_run
++//! # use nix::sys::inotify::{AddWatchFlags,InitFlags,Inotify};
++//! #
++//! // We create a new inotify instance.
++//! let instance = Inotify::init(InitFlags::empty()).unwrap();
++//!
++//! // We add a new watch on directory "test" for all events.
++//! let wd = instance.add_watch("test", AddWatchFlags::IN_ALL_EVENTS).unwrap();
++//!
++//! loop {
++//! // We read from our inotify instance for events.
++//! let events = instance.read_events().unwrap();
++//! println!("Events: {:?}", events);
++//! }
++//! ```
++
++use libc;
++use libc::{
++ c_char,
++ c_int,
++};
++use std::ffi::{OsString,OsStr,CStr};
++use std::os::unix::ffi::OsStrExt;
++use std::mem::size_of;
++use std::os::unix::io::{RawFd,AsRawFd,FromRawFd};
++use unistd::read;
++use Result;
++use NixPath;
++use errno::Errno;
++
++libc_bitflags! {
++ /// Configuration options for [`inotify_add_watch`](fn.inotify_add_watch.html).
++ pub struct AddWatchFlags: u32 {
++ IN_ACCESS;
++ IN_MODIFY;
++ IN_ATTRIB;
++ IN_CLOSE_WRITE;
++ IN_CLOSE_NOWRITE;
++ IN_OPEN;
++ IN_MOVED_FROM;
++ IN_MOVED_TO;
++ IN_CREATE;
++ IN_DELETE;
++ IN_DELETE_SELF;
++ IN_MOVE_SELF;
++
++ IN_UNMOUNT;
++ IN_Q_OVERFLOW;
++ IN_IGNORED;
++
++ IN_CLOSE;
++ IN_MOVE;
++
++ IN_ONLYDIR;
++ IN_DONT_FOLLOW;
++
++ IN_ISDIR;
++ IN_ONESHOT;
++ IN_ALL_EVENTS;
++ }
++}
++
++libc_bitflags! {
++ /// Configuration options for [`inotify_init1`](fn.inotify_init1.html).
++ pub struct InitFlags: c_int {
++ IN_CLOEXEC;
++ IN_NONBLOCK;
++ }
++}
++
++/// An inotify instance. This is also a file descriptor, you can feed it to
++/// other interfaces consuming file descriptors, epoll for example.
++#[derive(Debug, Clone, Copy)]
++pub struct Inotify {
++ fd: RawFd
++}
++
++/// This object is returned when you create a new watch on an inotify instance.
++/// It is then returned as part of an event once triggered. It allows you to
++/// know which watch triggered which event.
++#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Ord, PartialOrd)]
++pub struct WatchDescriptor {
++ wd: i32
++}
++
++/// A single inotify event.
++///
++/// For more documentation see, [inotify(7)](http://man7.org/linux/man-pages/man7/inotify.7.html).
++#[derive(Debug)]
++pub struct InotifyEvent {
++ /// Watch descriptor. This field corresponds to the watch descriptor you
++ /// were issued when calling add_watch. It allows you to know which watch
++ /// this event comes from.
++ pub wd: WatchDescriptor,
++ /// Event mask. This field is a bitfield describing the exact event that
++ /// occured.
++ pub mask: AddWatchFlags,
++ /// This cookie is a number that allows you to connect related events. For
++ /// now only IN_MOVED_FROM and IN_MOVED_TO can be connected.
++ pub cookie: u32,
++ /// Filename. This field exists only if the event was triggered for a file
++ /// inside the watched directory.
++ pub name: Option<OsString>
++}
++
++impl Inotify {
++ /// Initialize a new inotify instance.
++ ///
++ /// Returns a Result containing an inotify instance.
++ ///
++ /// For more information see, [inotify_init(2)](http://man7.org/linux/man-pages/man2/inotify_init.2.html).
++ pub fn init(flags: InitFlags) -> Result<Inotify> {
++ let res = Errno::result(unsafe {
++ libc::inotify_init1(flags.bits())
++ });
++
++ res.map(|fd| Inotify { fd })
++ }
++
++ /// Adds a new watch on the target file or directory.
++ ///
++ /// Returns a watch descriptor. This is not a File Descriptor!
++ ///
++ /// For more information see, [inotify_add_watch(2)](http://man7.org/linux/man-pages/man2/inotify_add_watch.2.html).
++ pub fn add_watch<P: ?Sized + NixPath>(&self,
++ path: &P,
++ mask: AddWatchFlags)
++ -> Result<WatchDescriptor>
++ {
++ let res = path.with_nix_path(|cstr| {
++ unsafe {
++ libc::inotify_add_watch(self.fd, cstr.as_ptr(), mask.bits())
++ }
++ })?;
++
++ Errno::result(res).map(|wd| WatchDescriptor { wd })
++ }
++
++ /// Removes an existing watch using the watch descriptor returned by
++ /// inotify_add_watch.
++ ///
++ /// Returns an EINVAL error if the watch descriptor is invalid.
++ ///
++ /// For more information see, [inotify_rm_watch(2)](http://man7.org/linux/man-pages/man2/inotify_rm_watch.2.html).
++ #[cfg(target_os = "linux")]
++ pub fn rm_watch(&self, wd: WatchDescriptor) -> Result<()> {
++ let res = unsafe { libc::inotify_rm_watch(self.fd, wd.wd) };
++
++ Errno::result(res).map(drop)
++ }
++
++ #[cfg(target_os = "android")]
++ pub fn rm_watch(&self, wd: WatchDescriptor) -> Result<()> {
++ let res = unsafe { libc::inotify_rm_watch(self.fd, wd.wd as u32) };
++
++ Errno::result(res).map(drop)
++ }
++
++ /// Reads a collection of events from the inotify file descriptor. This call
++ /// can either be blocking or non blocking depending on whether IN_NONBLOCK
++ /// was set at initialization.
++ ///
++ /// Returns as many events as available. If the call was non blocking and no
++ /// events could be read then the EAGAIN error is returned.
++ pub fn read_events(&self) -> Result<Vec<InotifyEvent>> {
++ let header_size = size_of::<libc::inotify_event>();
++ let mut buffer = [0u8; 4096];
++ let mut events = Vec::new();
++ let mut offset = 0;
++
++ let nread = read(self.fd, &mut buffer)?;
++
++ while (nread - offset) >= header_size {
++ let event = unsafe {
++ &*(
++ buffer
++ .as_ptr()
++ .offset(offset as isize) as *const libc::inotify_event
++ )
++ };
++
++ let name = match event.len {
++ 0 => None,
++ _ => {
++ let ptr = unsafe {
++ buffer
++ .as_ptr()
++ .offset(offset as isize + header_size as isize)
++ as *const c_char
++ };
++ let cstr = unsafe { CStr::from_ptr(ptr) };
++
++ Some(OsStr::from_bytes(cstr.to_bytes()).to_owned())
++ }
++ };
++
++ events.push(InotifyEvent {
++ wd: WatchDescriptor { wd: event.wd },
++ mask: AddWatchFlags::from_bits_truncate(event.mask),
++ cookie: event.cookie,
++ name
++ });
++
++ offset += header_size + event.len as usize;
++ }
++
++ Ok(events)
++ }
++}
++
++impl AsRawFd for Inotify {
++ fn as_raw_fd(&self) -> RawFd {
++ self.fd
++ }
++}
++
++impl FromRawFd for Inotify {
++ unsafe fn from_raw_fd(fd: RawFd) -> Self {
++ Inotify { fd }
++ }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/ioctl/bsd.rs b/third_party/rust/nix-0.15.0/src/sys/ioctl/bsd.rs
+new file mode 100644
+index 0000000000000..9b8b0ff1a155f
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/ioctl/bsd.rs
+@@ -0,0 +1,102 @@
++/// The datatype used for the ioctl number
++#[doc(hidden)]
++pub type ioctl_num_type = ::libc::c_ulong;
++/// The datatype used for the 3rd argument
++#[doc(hidden)]
++pub type ioctl_param_type = ::libc::c_int;
++
++mod consts {
++ use ::sys::ioctl::ioctl_num_type;
++ #[doc(hidden)]
++ pub const VOID: ioctl_num_type = 0x2000_0000;
++ #[doc(hidden)]
++ pub const OUT: ioctl_num_type = 0x4000_0000;
++ #[doc(hidden)]
++ pub const IN: ioctl_num_type = 0x8000_0000;
++ #[doc(hidden)]
++ pub const INOUT: ioctl_num_type = (IN|OUT);
++ #[doc(hidden)]
++ pub const IOCPARM_MASK: ioctl_num_type = 0x1fff;
++}
++
++pub use self::consts::*;
++
++#[macro_export]
++#[doc(hidden)]
++macro_rules! ioc {
++ ($inout:expr, $group:expr, $num:expr, $len:expr) => (
++ $inout | (($len as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::IOCPARM_MASK) << 16) | (($group as $crate::sys::ioctl::ioctl_num_type) << 8) | ($num as $crate::sys::ioctl::ioctl_num_type)
++ )
++}
++
++/// Generate an ioctl request code for a command that passes no data.
++///
++/// This is equivalent to the `_IO()` macro exposed by the C ioctl API.
++///
++/// You should only use this macro directly if the `ioctl` you're working
++/// with is "bad" and you cannot use `ioctl_none!()` directly.
++///
++/// # Example
++///
++/// ```
++/// # #[macro_use] extern crate nix;
++/// const KVMIO: u8 = 0xAE;
++/// ioctl_write_int_bad!(kvm_create_vm, request_code_none!(KVMIO, 0x03));
++/// # fn main() {}
++/// ```
++#[macro_export(local_inner_macros)]
++macro_rules! request_code_none {
++ ($g:expr, $n:expr) => (ioc!($crate::sys::ioctl::VOID, $g, $n, 0))
++}
++
++/// Generate an ioctl request code for a command that passes an integer
++///
++/// This is equivalent to the `_IOWINT()` macro exposed by the C ioctl API.
++///
++/// You should only use this macro directly if the `ioctl` you're working
++/// with is "bad" and you cannot use `ioctl_write_int!()` directly.
++#[macro_export(local_inner_macros)]
++macro_rules! request_code_write_int {
++ ($g:expr, $n:expr) => (ioc!($crate::sys::ioctl::VOID, $g, $n, ::std::mem::size_of::<$crate::libc::c_int>()))
++}
++
++/// Generate an ioctl request code for a command that reads.
++///
++/// This is equivalent to the `_IOR()` macro exposed by the C ioctl API.
++///
++/// You should only use this macro directly if the `ioctl` you're working
++/// with is "bad" and you cannot use `ioctl_read!()` directly.
++///
++/// The read/write direction is relative to userland, so this
++/// command would be userland is reading and the kernel is
++/// writing.
++#[macro_export(local_inner_macros)]
++macro_rules! request_code_read {
++ ($g:expr, $n:expr, $len:expr) => (ioc!($crate::sys::ioctl::OUT, $g, $n, $len))
++}
++
++/// Generate an ioctl request code for a command that writes.
++///
++/// This is equivalent to the `_IOW()` macro exposed by the C ioctl API.
++///
++/// You should only use this macro directly if the `ioctl` you're working
++/// with is "bad" and you cannot use `ioctl_write!()` directly.
++///
++/// The read/write direction is relative to userland, so this
++/// command would be userland is writing and the kernel is
++/// reading.
++#[macro_export(local_inner_macros)]
++macro_rules! request_code_write {
++ ($g:expr, $n:expr, $len:expr) => (ioc!($crate::sys::ioctl::IN, $g, $n, $len))
++}
++
++/// Generate an ioctl request code for a command that reads and writes.
++///
++/// This is equivalent to the `_IOWR()` macro exposed by the C ioctl API.
++///
++/// You should only use this macro directly if the `ioctl` you're working
++/// with is "bad" and you cannot use `ioctl_readwrite!()` directly.
++#[macro_export(local_inner_macros)]
++macro_rules! request_code_readwrite {
++ ($g:expr, $n:expr, $len:expr) => (ioc!($crate::sys::ioctl::INOUT, $g, $n, $len))
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/ioctl/linux.rs b/third_party/rust/nix-0.15.0/src/sys/ioctl/linux.rs
+new file mode 100644
+index 0000000000000..9cdac72a4b80b
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/ioctl/linux.rs
+@@ -0,0 +1,140 @@
++/// The datatype used for the ioctl number
++#[cfg(any(target_os = "android", target_env = "musl"))]
++#[doc(hidden)]
++pub type ioctl_num_type = ::libc::c_int;
++#[cfg(not(any(target_os = "android", target_env = "musl")))]
++#[doc(hidden)]
++pub type ioctl_num_type = ::libc::c_ulong;
++/// The datatype used for the 3rd argument
++#[doc(hidden)]
++pub type ioctl_param_type = ::libc::c_ulong;
++
++#[doc(hidden)]
++pub const NRBITS: ioctl_num_type = 8;
++#[doc(hidden)]
++pub const TYPEBITS: ioctl_num_type = 8;
++
++#[cfg(any(target_arch = "mips", target_arch = "mips64", target_arch = "powerpc", target_arch = "powerpc64", target_arch = "sparc64"))]
++mod consts {
++ #[doc(hidden)]
++ pub const NONE: u8 = 1;
++ #[doc(hidden)]
++ pub const READ: u8 = 2;
++ #[doc(hidden)]
++ pub const WRITE: u8 = 4;
++ #[doc(hidden)]
++ pub const SIZEBITS: u8 = 13;
++ #[doc(hidden)]
++ pub const DIRBITS: u8 = 3;
++}
++
++// "Generic" ioctl protocol
++#[cfg(any(target_arch = "x86",
++ target_arch = "arm",
++ target_arch = "s390x",
++ target_arch = "x86_64",
++ target_arch = "aarch64"))]
++mod consts {
++ #[doc(hidden)]
++ pub const NONE: u8 = 0;
++ #[doc(hidden)]
++ pub const READ: u8 = 2;
++ #[doc(hidden)]
++ pub const WRITE: u8 = 1;
++ #[doc(hidden)]
++ pub const SIZEBITS: u8 = 14;
++ #[doc(hidden)]
++ pub const DIRBITS: u8 = 2;
++}
++
++pub use self::consts::*;
++
++#[doc(hidden)]
++pub const NRSHIFT: ioctl_num_type = 0;
++#[doc(hidden)]
++pub const TYPESHIFT: ioctl_num_type = NRSHIFT + NRBITS as ioctl_num_type;
++#[doc(hidden)]
++pub const SIZESHIFT: ioctl_num_type = TYPESHIFT + TYPEBITS as ioctl_num_type;
++#[doc(hidden)]
++pub const DIRSHIFT: ioctl_num_type = SIZESHIFT + SIZEBITS as ioctl_num_type;
++
++#[doc(hidden)]
++pub const NRMASK: ioctl_num_type = (1 << NRBITS) - 1;
++#[doc(hidden)]
++pub const TYPEMASK: ioctl_num_type = (1 << TYPEBITS) - 1;
++#[doc(hidden)]
++pub const SIZEMASK: ioctl_num_type = (1 << SIZEBITS) - 1;
++#[doc(hidden)]
++pub const DIRMASK: ioctl_num_type = (1 << DIRBITS) - 1;
++
++/// Encode an ioctl command.
++#[macro_export]
++#[doc(hidden)]
++macro_rules! ioc {
++ ($dir:expr, $ty:expr, $nr:expr, $sz:expr) => (
++ (($dir as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::DIRMASK) << $crate::sys::ioctl::DIRSHIFT) |
++ (($ty as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::TYPEMASK) << $crate::sys::ioctl::TYPESHIFT) |
++ (($nr as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::NRMASK) << $crate::sys::ioctl::NRSHIFT) |
++ (($sz as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::SIZEMASK) << $crate::sys::ioctl::SIZESHIFT))
++}
++
++/// Generate an ioctl request code for a command that passes no data.
++///
++/// This is equivalent to the `_IO()` macro exposed by the C ioctl API.
++///
++/// You should only use this macro directly if the `ioctl` you're working
++/// with is "bad" and you cannot use `ioctl_none!()` directly.
++///
++/// # Example
++///
++/// ```
++/// # #[macro_use] extern crate nix;
++/// const KVMIO: u8 = 0xAE;
++/// ioctl_write_int_bad!(kvm_create_vm, request_code_none!(KVMIO, 0x03));
++/// # fn main() {}
++/// ```
++#[macro_export(local_inner_macros)]
++macro_rules! request_code_none {
++ ($ty:expr, $nr:expr) => (ioc!($crate::sys::ioctl::NONE, $ty, $nr, 0))
++}
++
++/// Generate an ioctl request code for a command that reads.
++///
++/// This is equivalent to the `_IOR()` macro exposed by the C ioctl API.
++///
++/// You should only use this macro directly if the `ioctl` you're working
++/// with is "bad" and you cannot use `ioctl_read!()` directly.
++///
++/// The read/write direction is relative to userland, so this
++/// command would be userland is reading and the kernel is
++/// writing.
++#[macro_export(local_inner_macros)]
++macro_rules! request_code_read {
++ ($ty:expr, $nr:expr, $sz:expr) => (ioc!($crate::sys::ioctl::READ, $ty, $nr, $sz))
++}
++
++/// Generate an ioctl request code for a command that writes.
++///
++/// This is equivalent to the `_IOW()` macro exposed by the C ioctl API.
++///
++/// You should only use this macro directly if the `ioctl` you're working
++/// with is "bad" and you cannot use `ioctl_write!()` directly.
++///
++/// The read/write direction is relative to userland, so this
++/// command would be userland is writing and the kernel is
++/// reading.
++#[macro_export(local_inner_macros)]
++macro_rules! request_code_write {
++ ($ty:expr, $nr:expr, $sz:expr) => (ioc!($crate::sys::ioctl::WRITE, $ty, $nr, $sz))
++}
++
++/// Generate an ioctl request code for a command that reads and writes.
++///
++/// This is equivalent to the `_IOWR()` macro exposed by the C ioctl API.
++///
++/// You should only use this macro directly if the `ioctl` you're working
++/// with is "bad" and you cannot use `ioctl_readwrite!()` directly.
++#[macro_export(local_inner_macros)]
++macro_rules! request_code_readwrite {
++ ($ty:expr, $nr:expr, $sz:expr) => (ioc!($crate::sys::ioctl::READ | $crate::sys::ioctl::WRITE, $ty, $nr, $sz))
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/ioctl/mod.rs b/third_party/rust/nix-0.15.0/src/sys/ioctl/mod.rs
+new file mode 100644
+index 0000000000000..4513bf877434a
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/ioctl/mod.rs
+@@ -0,0 +1,778 @@
++//! Provide helpers for making ioctl system calls.
++//!
++//! This library is pretty low-level and messy. `ioctl` is not fun.
++//!
++//! What is an `ioctl`?
++//! ===================
++//!
++//! The `ioctl` syscall is the grab-bag syscall on POSIX systems. Don't want to add a new
++//! syscall? Make it an `ioctl`! `ioctl` refers to both the syscall, and the commands that can be
++//! sent with it. `ioctl` stands for "IO control", and the commands are always sent to a file
++//! descriptor.
++//!
++//! It is common to see `ioctl`s used for the following purposes:
++//!
++//! * Provide read/write access to out-of-band data related to a device such as configuration
++//! (for instance, setting serial port options)
++//! * Provide a mechanism for performing full-duplex data transfers (for instance, xfer on SPI
++//! devices).
++//! * Provide access to control functions on a device (for example, on Linux you can send
++//! commands like pause, resume, and eject to the CDROM device.
++//! * Do whatever else the device driver creator thought made most sense.
++//!
++//! `ioctl`s are synchronous system calls and are similar to read and write calls in that regard.
++//! They operate on file descriptors and have an identifier that specifies what the ioctl is.
++//! Additionally they may read or write data and therefore need to pass along a data pointer.
++//! Besides the semantics of the ioctls being confusing, the generation of this identifer can also
++//! be difficult.
++//!
++//! Historically `ioctl` numbers were arbitrary hard-coded values. In Linux (before 2.6) and some
++//! unices this has changed to a more-ordered system where the ioctl numbers are partitioned into
++//! subcomponents (For linux this is documented in
++//! [`Documentation/ioctl/ioctl-number.txt`](http://elixir.free-electrons.com/linux/latest/source/Documentation/ioctl/ioctl-number.txt)):
++//!
++//! * Number: The actual ioctl ID
++//! * Type: A grouping of ioctls for a common purpose or driver
++//! * Size: The size in bytes of the data that will be transferred
++//! * Direction: Whether there is any data and if it's read, write, or both
++//!
++//! Newer drivers should not generate complete integer identifiers for their `ioctl`s instead
++//! preferring to use the 4 components above to generate the final ioctl identifier. Because of
++//! how old `ioctl`s are, however, there are many hard-coded `ioctl` identifiers. These are
++//! commonly referred to as "bad" in `ioctl` documentation.
++//!
++//! Defining `ioctl`s
++//! =================
++//!
++//! This library provides several `ioctl_*!` macros for binding `ioctl`s. These generate public
++//! unsafe functions that can then be used for calling the ioctl. This macro has a few different
++//! ways it can be used depending on the specific ioctl you're working with.
++//!
++//! A simple `ioctl` is `SPI_IOC_RD_MODE`. This ioctl works with the SPI interface on Linux. This
++//! specific `ioctl` reads the mode of the SPI device as a `u8`. It's declared in
++//! `/include/uapi/linux/spi/spidev.h` as `_IOR(SPI_IOC_MAGIC, 1, __u8)`. Since it uses the `_IOR`
++//! macro, we know it's a `read` ioctl and can use the `ioctl_read!` macro as follows:
++//!
++//! ```
++//! # #[macro_use] extern crate nix;
++//! const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h
++//! const SPI_IOC_TYPE_MODE: u8 = 1;
++//! ioctl_read!(spi_read_mode, SPI_IOC_MAGIC, SPI_IOC_TYPE_MODE, u8);
++//! # fn main() {}
++//! ```
++//!
++//! This generates the function:
++//!
++//! ```
++//! # #[macro_use] extern crate nix;
++//! # use std::mem;
++//! # use nix::{libc, Result};
++//! # use nix::errno::Errno;
++//! # use nix::libc::c_int as c_int;
++//! # const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h
++//! # const SPI_IOC_TYPE_MODE: u8 = 1;
++//! pub unsafe fn spi_read_mode(fd: c_int, data: *mut u8) -> Result<c_int> {
++//! let res = libc::ioctl(fd, request_code_read!(SPI_IOC_MAGIC, SPI_IOC_TYPE_MODE, mem::size_of::<u8>()), data);
++//! Errno::result(res)
++//! }
++//! # fn main() {}
++//! ```
++//!
++//! The return value for the wrapper functions generated by the `ioctl_*!` macros are `nix::Error`s.
++//! These are generated by assuming the return value of the ioctl is `-1` on error and everything
++//! else is a valid return value. If this is not the case, `Result::map` can be used to map some
++//! of the range of "good" values (-Inf..-2, 0..Inf) into a smaller range in a helper function.
++//!
++//! Writing `ioctl`s generally use pointers as their data source and these should use the
++//! `ioctl_write_ptr!`. But in some cases an `int` is passed directly. For these `ioctl`s use the
++//! `ioctl_write_int!` macro. This variant does not take a type as the last argument:
++//!
++//! ```
++//! # #[macro_use] extern crate nix;
++//! const HCI_IOC_MAGIC: u8 = b'k';
++//! const HCI_IOC_HCIDEVUP: u8 = 1;
++//! ioctl_write_int!(hci_dev_up, HCI_IOC_MAGIC, HCI_IOC_HCIDEVUP);
++//! # fn main() {}
++//! ```
++//!
++//! Some `ioctl`s don't transfer any data, and those should use `ioctl_none!`. This macro
++//! doesn't take a type and so it is declared similar to the `write_int` variant shown above.
++//!
++//! The mode for a given `ioctl` should be clear from the documentation if it has good
++//! documentation. Otherwise it will be clear based on the macro used to generate the `ioctl`
++//! number where `_IO`, `_IOR`, `_IOW`, and `_IOWR` map to "none", "read", "write_*", and "readwrite"
++//! respectively. To determine the specific `write_` variant to use you'll need to find
++//! what the argument type is supposed to be. If it's an `int`, then `write_int` should be used,
++//! otherwise it should be a pointer and `write_ptr` should be used. On Linux the
++//! [`ioctl_list` man page](http://man7.org/linux/man-pages/man2/ioctl_list.2.html) describes a
++//! large number of `ioctl`s and describes their argument data type.
++//!
++//! Using "bad" `ioctl`s
++//! --------------------
++//!
++//! As mentioned earlier, there are many old `ioctl`s that do not use the newer method of
++//! generating `ioctl` numbers and instead use hardcoded values. These can be used with the
++//! `ioctl_*_bad!` macros. This naming comes from the Linux kernel which refers to these
++//! `ioctl`s as "bad". These are a different variant as they bypass calling the macro that generates
++//! the ioctl number and instead use the defined value directly.
++//!
++//! For example the `TCGETS` `ioctl` reads a `termios` data structure for a given file descriptor.
++//! It's defined as `0x5401` in `ioctls.h` on Linux and can be implemented as:
++//!
++//! ```
++//! # #[macro_use] extern crate nix;
++//! # #[cfg(any(target_os = "android", target_os = "linux"))]
++//! # use nix::libc::TCGETS as TCGETS;
++//! # #[cfg(any(target_os = "android", target_os = "linux"))]
++//! # use nix::libc::termios as termios;
++//! # #[cfg(any(target_os = "android", target_os = "linux"))]
++//! ioctl_read_bad!(tcgets, TCGETS, termios);
++//! # fn main() {}
++//! ```
++//!
++//! The generated function has the same form as that generated by `ioctl_read!`:
++//!
++//! ```text
++//! pub unsafe fn tcgets(fd: c_int, data: *mut termios) -> Result<c_int>;
++//! ```
++//!
++//! Working with Arrays
++//! -------------------
++//!
++//! Some `ioctl`s work with entire arrays of elements. These are supported by the `ioctl_*_buf`
++//! family of macros: `ioctl_read_buf`, `ioctl_write_buf`, and `ioctl_readwrite_buf`. Note that
++//! there are no "bad" versions for working with buffers. The generated functions include a `len`
++//! argument to specify the number of elements (where the type of each element is specified in the
++//! macro).
++//!
++//! Again looking to the SPI `ioctl`s on Linux for an example, there is a `SPI_IOC_MESSAGE` `ioctl`
++//! that queues up multiple SPI messages by writing an entire array of `spi_ioc_transfer` structs.
++//! `linux/spi/spidev.h` defines a macro to calculate the `ioctl` number like:
++//!
++//! ```C
++//! #define SPI_IOC_MAGIC 'k'
++//! #define SPI_MSGSIZE(N) ...
++//! #define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)])
++//! ```
++//!
++//! The `SPI_MSGSIZE(N)` calculation is already handled by the `ioctl_*!` macros, so all that's
++//! needed to define this `ioctl` is:
++//!
++//! ```
++//! # #[macro_use] extern crate nix;
++//! const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h
++//! const SPI_IOC_TYPE_MESSAGE: u8 = 0;
++//! # pub struct spi_ioc_transfer(u64);
++//! ioctl_write_buf!(spi_transfer, SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE, spi_ioc_transfer);
++//! # fn main() {}
++//! ```
++//!
++//! This generates a function like:
++//!
++//! ```
++//! # #[macro_use] extern crate nix;
++//! # use std::mem;
++//! # use nix::{libc, Result};
++//! # use nix::errno::Errno;
++//! # use nix::libc::c_int as c_int;
++//! # const SPI_IOC_MAGIC: u8 = b'k';
++//! # const SPI_IOC_TYPE_MESSAGE: u8 = 0;
++//! # pub struct spi_ioc_transfer(u64);
++//! pub unsafe fn spi_message(fd: c_int, data: &mut [spi_ioc_transfer]) -> Result<c_int> {
++//! let res = libc::ioctl(fd,
++//! request_code_write!(SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE, data.len() * mem::size_of::<spi_ioc_transfer>()),
++//! data);
++//! Errno::result(res)
++//! }
++//! # fn main() {}
++//! ```
++//!
++//! Finding `ioctl` Documentation
++//! -----------------------------
++//!
++//! For Linux, look at your system's headers. For example, `/usr/include/linux/input.h` has a lot
++//! of lines defining macros which use `_IO`, `_IOR`, `_IOW`, `_IOC`, and `_IOWR`. Some `ioctl`s are
++//! documented directly in the headers defining their constants, but others have more extensive
++//! documentation in man pages (like termios' `ioctl`s which are in `tty_ioctl(4)`).
++//!
++//! Documenting the Generated Functions
++//! ===================================
++//!
++//! In many cases, users will wish for the functions generated by the `ioctl`
++//! macro to be public and documented. For this reason, the generated functions
++//! are public by default. If you wish to hide the ioctl, you will need to put
++//! them in a private module.
++//!
++//! For documentation, it is possible to use doc comments inside the `ioctl_*!` macros. Here is an
++//! example :
++//!
++//! ```
++//! # #[macro_use] extern crate nix;
++//! # use nix::libc::c_int;
++//! ioctl_read! {
++//! /// Make the given terminal the controlling terminal of the calling process. The calling
++//! /// process must be a session leader and not have a controlling terminal already. If the
++//! /// terminal is already the controlling terminal of a different session group then the
++//! /// ioctl will fail with **EPERM**, unless the caller is root (more precisely: has the
++//! /// **CAP_SYS_ADMIN** capability) and arg equals 1, in which case the terminal is stolen
++//! /// and all processes that had it as controlling terminal lose it.
++//! tiocsctty, b't', 19, c_int
++//! }
++//!
++//! # fn main() {}
++//! ```
++#[cfg(any(target_os = "android", target_os = "linux"))]
++#[macro_use]
++mod linux;
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++pub use self::linux::*;
++
++#[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++#[macro_use]
++mod bsd;
++
++#[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++pub use self::bsd::*;
++
++/// Convert raw ioctl return value to a Nix result
++#[macro_export]
++#[doc(hidden)]
++macro_rules! convert_ioctl_res {
++ ($w:expr) => (
++ {
++ $crate::errno::Errno::result($w)
++ }
++ );
++}
++
++/// Generates a wrapper function for an ioctl that passes no data to the kernel.
++///
++/// The arguments to this macro are:
++///
++/// * The function name
++/// * The ioctl identifier
++/// * The ioctl sequence number
++///
++/// The generated function has the following signature:
++///
++/// ```rust,ignore
++/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int) -> Result<libc::c_int>
++/// ```
++///
++/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
++///
++/// # Example
++///
++/// The `videodev2` driver on Linux defines the `log_status` `ioctl` as:
++///
++/// ```C
++/// #define VIDIOC_LOG_STATUS _IO('V', 70)
++/// ```
++///
++/// This can be implemented in Rust like:
++///
++/// ```no_run
++/// # #[macro_use] extern crate nix;
++/// ioctl_none!(log_status, b'V', 70);
++/// fn main() {}
++/// ```
++#[macro_export(local_inner_macros)]
++macro_rules! ioctl_none {
++ ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr) => (
++ $(#[$attr])*
++ pub unsafe fn $name(fd: $crate::libc::c_int)
++ -> $crate::Result<$crate::libc::c_int> {
++ convert_ioctl_res!($crate::libc::ioctl(fd, request_code_none!($ioty, $nr) as $crate::sys::ioctl::ioctl_num_type))
++ }
++ )
++}
++
++/// Generates a wrapper function for a "bad" ioctl that passes no data to the kernel.
++///
++/// The arguments to this macro are:
++///
++/// * The function name
++/// * The ioctl request code
++///
++/// The generated function has the following signature:
++///
++/// ```rust,ignore
++/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int) -> Result<libc::c_int>
++/// ```
++///
++/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
++///
++/// # Example
++///
++/// ```no_run
++/// # #[macro_use] extern crate nix;
++/// # extern crate libc;
++/// # use libc::TIOCNXCL;
++/// # use std::fs::File;
++/// # use std::os::unix::io::AsRawFd;
++/// ioctl_none_bad!(tiocnxcl, TIOCNXCL);
++/// fn main() {
++/// let file = File::open("/dev/ttyUSB0").unwrap();
++/// unsafe { tiocnxcl(file.as_raw_fd()) }.unwrap();
++/// }
++/// ```
++// TODO: add an example using request_code_*!()
++#[macro_export(local_inner_macros)]
++macro_rules! ioctl_none_bad {
++ ($(#[$attr:meta])* $name:ident, $nr:expr) => (
++ $(#[$attr])*
++ pub unsafe fn $name(fd: $crate::libc::c_int)
++ -> $crate::Result<$crate::libc::c_int> {
++ convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type))
++ }
++ )
++}
++
++/// Generates a wrapper function for an ioctl that reads data from the kernel.
++///
++/// The arguments to this macro are:
++///
++/// * The function name
++/// * The ioctl identifier
++/// * The ioctl sequence number
++/// * The data type passed by this ioctl
++///
++/// The generated function has the following signature:
++///
++/// ```rust,ignore
++/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *mut DATA_TYPE) -> Result<libc::c_int>
++/// ```
++///
++/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
++///
++/// # Example
++///
++/// ```
++/// # #[macro_use] extern crate nix;
++/// const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h
++/// const SPI_IOC_TYPE_MODE: u8 = 1;
++/// ioctl_read!(spi_read_mode, SPI_IOC_MAGIC, SPI_IOC_TYPE_MODE, u8);
++/// # fn main() {}
++/// ```
++#[macro_export(local_inner_macros)]
++macro_rules! ioctl_read {
++ ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => (
++ $(#[$attr])*
++ pub unsafe fn $name(fd: $crate::libc::c_int,
++ data: *mut $ty)
++ -> $crate::Result<$crate::libc::c_int> {
++ convert_ioctl_res!($crate::libc::ioctl(fd, request_code_read!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
++ }
++ )
++}
++
++/// Generates a wrapper function for a "bad" ioctl that reads data from the kernel.
++///
++/// The arguments to this macro are:
++///
++/// * The function name
++/// * The ioctl request code
++/// * The data type passed by this ioctl
++///
++/// The generated function has the following signature:
++///
++/// ```rust,ignore
++/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *mut DATA_TYPE) -> Result<libc::c_int>
++/// ```
++///
++/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
++///
++/// # Example
++///
++/// ```
++/// # extern crate libc;
++/// # #[macro_use] extern crate nix;
++/// # #[cfg(any(target_os = "android", target_os = "linux"))]
++/// ioctl_read_bad!(tcgets, libc::TCGETS, libc::termios);
++/// # fn main() {}
++/// ```
++#[macro_export(local_inner_macros)]
++macro_rules! ioctl_read_bad {
++ ($(#[$attr:meta])* $name:ident, $nr:expr, $ty:ty) => (
++ $(#[$attr])*
++ pub unsafe fn $name(fd: $crate::libc::c_int,
++ data: *mut $ty)
++ -> $crate::Result<$crate::libc::c_int> {
++ convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data))
++ }
++ )
++}
++
++/// Generates a wrapper function for an ioctl that writes data through a pointer to the kernel.
++///
++/// The arguments to this macro are:
++///
++/// * The function name
++/// * The ioctl identifier
++/// * The ioctl sequence number
++/// * The data type passed by this ioctl
++///
++/// The generated function has the following signature:
++///
++/// ```rust,ignore
++/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *const DATA_TYPE) -> Result<libc::c_int>
++/// ```
++///
++/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
++///
++/// # Example
++///
++/// ```
++/// # #[macro_use] extern crate nix;
++/// # pub struct v4l2_audio {}
++/// ioctl_write_ptr!(s_audio, b'V', 34, v4l2_audio);
++/// # fn main() {}
++/// ```
++#[macro_export(local_inner_macros)]
++macro_rules! ioctl_write_ptr {
++ ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => (
++ $(#[$attr])*
++ pub unsafe fn $name(fd: $crate::libc::c_int,
++ data: *const $ty)
++ -> $crate::Result<$crate::libc::c_int> {
++ convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
++ }
++ )
++}
++
++/// Generates a wrapper function for a "bad" ioctl that writes data through a pointer to the kernel.
++///
++/// The arguments to this macro are:
++///
++/// * The function name
++/// * The ioctl request code
++/// * The data type passed by this ioctl
++///
++/// The generated function has the following signature:
++///
++/// ```rust,ignore
++/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *const DATA_TYPE) -> Result<libc::c_int>
++/// ```
++///
++/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
++///
++/// # Example
++///
++/// ```
++/// # extern crate libc;
++/// # #[macro_use] extern crate nix;
++/// # #[cfg(any(target_os = "android", target_os = "linux"))]
++/// ioctl_write_ptr_bad!(tcsets, libc::TCSETS, libc::termios);
++/// # fn main() {}
++/// ```
++#[macro_export(local_inner_macros)]
++macro_rules! ioctl_write_ptr_bad {
++ ($(#[$attr:meta])* $name:ident, $nr:expr, $ty:ty) => (
++ $(#[$attr])*
++ pub unsafe fn $name(fd: $crate::libc::c_int,
++ data: *const $ty)
++ -> $crate::Result<$crate::libc::c_int> {
++ convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data))
++ }
++ )
++}
++
++cfg_if!{
++ if #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] {
++ /// Generates a wrapper function for a ioctl that writes an integer to the kernel.
++ ///
++ /// The arguments to this macro are:
++ ///
++ /// * The function name
++ /// * The ioctl identifier
++ /// * The ioctl sequence number
++ ///
++ /// The generated function has the following signature:
++ ///
++ /// ```rust,ignore
++ /// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: nix::sys::ioctl::ioctl_param_type) -> Result<libc::c_int>
++ /// ```
++ ///
++ /// `nix::sys::ioctl::ioctl_param_type` depends on the OS:
++ /// * BSD - `libc::c_int`
++ /// * Linux - `libc::c_ulong`
++ ///
++ /// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
++ ///
++ /// # Example
++ ///
++ /// ```
++ /// # #[macro_use] extern crate nix;
++ /// ioctl_write_int!(vt_activate, b'v', 4);
++ /// # fn main() {}
++ /// ```
++ #[macro_export(local_inner_macros)]
++ macro_rules! ioctl_write_int {
++ ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr) => (
++ $(#[$attr])*
++ pub unsafe fn $name(fd: $crate::libc::c_int,
++ data: $crate::sys::ioctl::ioctl_param_type)
++ -> $crate::Result<$crate::libc::c_int> {
++ convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write_int!($ioty, $nr) as $crate::sys::ioctl::ioctl_num_type, data))
++ }
++ )
++ }
++ } else {
++ /// Generates a wrapper function for a ioctl that writes an integer to the kernel.
++ ///
++ /// The arguments to this macro are:
++ ///
++ /// * The function name
++ /// * The ioctl identifier
++ /// * The ioctl sequence number
++ ///
++ /// The generated function has the following signature:
++ ///
++ /// ```rust,ignore
++ /// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: nix::sys::ioctl::ioctl_param_type) -> Result<libc::c_int>
++ /// ```
++ ///
++ /// `nix::sys::ioctl::ioctl_param_type` depends on the OS:
++ /// * BSD - `libc::c_int`
++ /// * Linux - `libc::c_ulong`
++ ///
++ /// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
++ ///
++ /// # Example
++ ///
++ /// ```
++ /// # #[macro_use] extern crate nix;
++ /// const HCI_IOC_MAGIC: u8 = b'k';
++ /// const HCI_IOC_HCIDEVUP: u8 = 1;
++ /// ioctl_write_int!(hci_dev_up, HCI_IOC_MAGIC, HCI_IOC_HCIDEVUP);
++ /// # fn main() {}
++ /// ```
++ #[macro_export(local_inner_macros)]
++ macro_rules! ioctl_write_int {
++ ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr) => (
++ $(#[$attr])*
++ pub unsafe fn $name(fd: $crate::libc::c_int,
++ data: $crate::sys::ioctl::ioctl_param_type)
++ -> $crate::Result<$crate::libc::c_int> {
++ convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of::<$crate::libc::c_int>()) as $crate::sys::ioctl::ioctl_num_type, data))
++ }
++ )
++ }
++ }
++}
++
++/// Generates a wrapper function for a "bad" ioctl that writes an integer to the kernel.
++///
++/// The arguments to this macro are:
++///
++/// * The function name
++/// * The ioctl request code
++///
++/// The generated function has the following signature:
++///
++/// ```rust,ignore
++/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: libc::c_int) -> Result<libc::c_int>
++/// ```
++///
++/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
++///
++/// # Examples
++///
++/// ```
++/// # extern crate libc;
++/// # #[macro_use] extern crate nix;
++/// # #[cfg(any(target_os = "android", target_os = "linux"))]
++/// ioctl_write_int_bad!(tcsbrk, libc::TCSBRK);
++/// # fn main() {}
++/// ```
++///
++/// ```rust
++/// # #[macro_use] extern crate nix;
++/// const KVMIO: u8 = 0xAE;
++/// ioctl_write_int_bad!(kvm_create_vm, request_code_none!(KVMIO, 0x03));
++/// # fn main() {}
++/// ```
++#[macro_export(local_inner_macros)]
++macro_rules! ioctl_write_int_bad {
++ ($(#[$attr:meta])* $name:ident, $nr:expr) => (
++ $(#[$attr])*
++ pub unsafe fn $name(fd: $crate::libc::c_int,
++ data: $crate::libc::c_int)
++ -> $crate::Result<$crate::libc::c_int> {
++ convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data))
++ }
++ )
++}
++
++/// Generates a wrapper function for an ioctl that reads and writes data to the kernel.
++///
++/// The arguments to this macro are:
++///
++/// * The function name
++/// * The ioctl identifier
++/// * The ioctl sequence number
++/// * The data type passed by this ioctl
++///
++/// The generated function has the following signature:
++///
++/// ```rust,ignore
++/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *mut DATA_TYPE) -> Result<libc::c_int>
++/// ```
++///
++/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
++///
++/// # Example
++///
++/// ```
++/// # #[macro_use] extern crate nix;
++/// # pub struct v4l2_audio {}
++/// ioctl_readwrite!(enum_audio, b'V', 65, v4l2_audio);
++/// # fn main() {}
++/// ```
++#[macro_export(local_inner_macros)]
++macro_rules! ioctl_readwrite {
++ ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => (
++ $(#[$attr])*
++ pub unsafe fn $name(fd: $crate::libc::c_int,
++ data: *mut $ty)
++ -> $crate::Result<$crate::libc::c_int> {
++ convert_ioctl_res!($crate::libc::ioctl(fd, request_code_readwrite!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
++ }
++ )
++}
++
++/// Generates a wrapper function for a "bad" ioctl that reads and writes data to the kernel.
++///
++/// The arguments to this macro are:
++///
++/// * The function name
++/// * The ioctl request code
++/// * The data type passed by this ioctl
++///
++/// The generated function has the following signature:
++///
++/// ```rust,ignore
++/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *mut DATA_TYPE) -> Result<libc::c_int>
++/// ```
++///
++/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
++// TODO: Find an example for ioctl_readwrite_bad
++#[macro_export(local_inner_macros)]
++macro_rules! ioctl_readwrite_bad {
++ ($(#[$attr:meta])* $name:ident, $nr:expr, $ty:ty) => (
++ $(#[$attr])*
++ pub unsafe fn $name(fd: $crate::libc::c_int,
++ data: *mut $ty)
++ -> $crate::Result<$crate::libc::c_int> {
++ convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data))
++ }
++ )
++}
++
++/// Generates a wrapper function for an ioctl that reads an array of elements from the kernel.
++///
++/// The arguments to this macro are:
++///
++/// * The function name
++/// * The ioctl identifier
++/// * The ioctl sequence number
++/// * The data type passed by this ioctl
++///
++/// The generated function has the following signature:
++///
++/// ```rust,ignore
++/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: &mut [DATA_TYPE]) -> Result<libc::c_int>
++/// ```
++///
++/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
++// TODO: Find an example for ioctl_read_buf
++#[macro_export(local_inner_macros)]
++macro_rules! ioctl_read_buf {
++ ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => (
++ $(#[$attr])*
++ pub unsafe fn $name(fd: $crate::libc::c_int,
++ data: &mut [$ty])
++ -> $crate::Result<$crate::libc::c_int> {
++ convert_ioctl_res!($crate::libc::ioctl(fd, request_code_read!($ioty, $nr, data.len() * ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
++ }
++ )
++}
++
++/// Generates a wrapper function for an ioctl that writes an array of elements to the kernel.
++///
++/// The arguments to this macro are:
++///
++/// * The function name
++/// * The ioctl identifier
++/// * The ioctl sequence number
++/// * The data type passed by this ioctl
++///
++/// The generated function has the following signature:
++///
++/// ```rust,ignore
++/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: &[DATA_TYPE]) -> Result<libc::c_int>
++/// ```
++///
++/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
++///
++/// # Examples
++///
++/// ```
++/// # #[macro_use] extern crate nix;
++/// const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h
++/// const SPI_IOC_TYPE_MESSAGE: u8 = 0;
++/// # pub struct spi_ioc_transfer(u64);
++/// ioctl_write_buf!(spi_transfer, SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE, spi_ioc_transfer);
++/// # fn main() {}
++/// ```
++#[macro_export(local_inner_macros)]
++macro_rules! ioctl_write_buf {
++ ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => (
++ $(#[$attr])*
++ pub unsafe fn $name(fd: $crate::libc::c_int,
++ data: &[$ty])
++ -> $crate::Result<$crate::libc::c_int> {
++ convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, data.len() * ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
++ }
++ )
++}
++
++/// Generates a wrapper function for an ioctl that reads and writes an array of elements to the kernel.
++///
++/// The arguments to this macro are:
++///
++/// * The function name
++/// * The ioctl identifier
++/// * The ioctl sequence number
++/// * The data type passed by this ioctl
++///
++/// The generated function has the following signature:
++///
++/// ```rust,ignore
++/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: &mut [DATA_TYPE]) -> Result<libc::c_int>
++/// ```
++///
++/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
++// TODO: Find an example for readwrite_buf
++#[macro_export(local_inner_macros)]
++macro_rules! ioctl_readwrite_buf {
++ ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => (
++ $(#[$attr])*
++ pub unsafe fn $name(fd: $crate::libc::c_int,
++ data: &mut [$ty])
++ -> $crate::Result<$crate::libc::c_int> {
++ convert_ioctl_res!($crate::libc::ioctl(fd, request_code_readwrite!($ioty, $nr, data.len() * ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
++ }
++ )
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/memfd.rs b/third_party/rust/nix-0.15.0/src/sys/memfd.rs
+new file mode 100644
+index 0000000000000..9672429b31e7f
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/memfd.rs
+@@ -0,0 +1,20 @@
++use libc;
++use std::os::unix::io::RawFd;
++use Result;
++use errno::Errno;
++use std::ffi::CStr;
++
++libc_bitflags!(
++ pub struct MemFdCreateFlag: libc::c_uint {
++ MFD_CLOEXEC;
++ MFD_ALLOW_SEALING;
++ }
++);
++
++pub fn memfd_create(name: &CStr, flags: MemFdCreateFlag) -> Result<RawFd> {
++ let res = unsafe {
++ libc::syscall(libc::SYS_memfd_create, name.as_ptr(), flags.bits())
++ };
++
++ Errno::result(res).map(|r| r as RawFd)
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/mman.rs b/third_party/rust/nix-0.15.0/src/sys/mman.rs
+new file mode 100644
+index 0000000000000..4e250501dd0f0
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/mman.rs
+@@ -0,0 +1,325 @@
++use {Error, Result};
++#[cfg(not(target_os = "android"))]
++use NixPath;
++use errno::Errno;
++#[cfg(not(target_os = "android"))]
++use fcntl::OFlag;
++use libc::{self, c_int, c_void, size_t, off_t};
++#[cfg(not(target_os = "android"))]
++use sys::stat::Mode;
++use std::os::unix::io::RawFd;
++
++libc_bitflags!{
++ /// Desired memory protection of a memory mapping.
++ pub struct ProtFlags: c_int {
++ /// Pages cannot be accessed.
++ PROT_NONE;
++ /// Pages can be read.
++ PROT_READ;
++ /// Pages can be written.
++ PROT_WRITE;
++ /// Pages can be executed
++ PROT_EXEC;
++ /// Apply protection up to the end of a mapping that grows upwards.
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ PROT_GROWSDOWN;
++ /// Apply protection down to the beginning of a mapping that grows downwards.
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ PROT_GROWSUP;
++ }
++}
++
++libc_bitflags!{
++ /// Additional parameters for `mmap()`.
++ pub struct MapFlags: c_int {
++ /// Compatibility flag. Ignored.
++ MAP_FILE;
++ /// Share this mapping. Mutually exclusive with `MAP_PRIVATE`.
++ MAP_SHARED;
++ /// Create a private copy-on-write mapping. Mutually exclusive with `MAP_SHARED`.
++ MAP_PRIVATE;
++ /// Place the mapping at exactly the address specified in `addr`.
++ MAP_FIXED;
++ /// Synonym for `MAP_ANONYMOUS`.
++ MAP_ANON;
++ /// The mapping is not backed by any file.
++ #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))]
++ MAP_ANONYMOUS;
++ /// Put the mapping into the first 2GB of the process address space.
++ #[cfg(any(all(any(target_os = "android", target_os = "linux"),
++ any(target_arch = "x86", target_arch = "x86_64")),
++ all(target_os = "linux", target_env = "musl", any(target_arch = "x86", target_arch = "x86_64")),
++ all(target_os = "freebsd", target_pointer_width = "64")))]
++ MAP_32BIT;
++ /// Used for stacks; indicates to the kernel that the mapping should extend downward in memory.
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ MAP_GROWSDOWN;
++ /// Compatibility flag. Ignored.
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ MAP_DENYWRITE;
++ /// Compatibility flag. Ignored.
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ MAP_EXECUTABLE;
++ /// Mark the mmaped region to be locked in the same way as `mlock(2)`.
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ MAP_LOCKED;
++ /// Do not reserve swap space for this mapping.
++ ///
++ /// This was removed in FreeBSD 11.
++ #[cfg(not(target_os = "freebsd"))]
++ MAP_NORESERVE;
++ /// Populate page tables for a mapping.
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ MAP_POPULATE;
++ /// Only meaningful when used with `MAP_POPULATE`. Don't perform read-ahead.
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ MAP_NONBLOCK;
++ /// Allocate the mapping using "huge pages."
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ MAP_HUGETLB;
++ /// Lock the mapped region into memory as with `mlock(2)`.
++ #[cfg(target_os = "netbsd")]
++ MAP_WIRED;
++ /// Causes dirtied data in the specified range to be flushed to disk only when necessary.
++ #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
++ MAP_NOSYNC;
++ /// Rename private pages to a file.
++ ///
++ /// This was removed in FreeBSD 11.
++ #[cfg(any(target_os = "dragonfly", target_os = "netbsd", target_os = "openbsd"))]
++ MAP_RENAME;
++ /// Region may contain semaphores.
++ #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
++ MAP_HASSEMAPHORE;
++ /// Region grows down, like a stack.
++ #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))]
++ MAP_STACK;
++ /// Pages in this mapping are not retained in the kernel's memory cache.
++ #[cfg(any(target_os = "ios", target_os = "macos"))]
++ MAP_NOCACHE;
++ #[cfg(any(target_os = "ios", target_os = "macos"))]
++ MAP_JIT;
++ }
++}
++
++libc_enum!{
++ /// Usage information for a range of memory to allow for performance optimizations by the kernel.
++ ///
++ /// Used by [`madvise`](./fn.madvise.html).
++ #[repr(i32)]
++ pub enum MmapAdvise {
++ /// No further special treatment. This is the default.
++ MADV_NORMAL,
++ /// Expect random page references.
++ MADV_RANDOM,
++ /// Expect sequential page references.
++ MADV_SEQUENTIAL,
++ /// Expect access in the near future.
++ MADV_WILLNEED,
++ /// Do not expect access in the near future.
++ MADV_DONTNEED,
++ /// Free up a given range of pages and its associated backing store.
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ MADV_REMOVE,
++ /// Do not make pages in this range available to the child after a `fork(2)`.
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ MADV_DONTFORK,
++ /// Undo the effect of `MADV_DONTFORK`.
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ MADV_DOFORK,
++ /// Poison the given pages.
++ ///
++ /// Subsequent references to those pages are treated like hardware memory corruption.
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ MADV_HWPOISON,
++ /// Enable Kernel Samepage Merging (KSM) for the given pages.
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ MADV_MERGEABLE,
++ /// Undo the effect of `MADV_MERGEABLE`
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ MADV_UNMERGEABLE,
++ /// Preserve the memory of each page but offline the original page.
++ #[cfg(any(target_os = "android",
++ all(target_os = "linux", any(
++ target_arch = "aarch64",
++ target_arch = "arm",
++ target_arch = "ppc",
++ target_arch = "s390x",
++ target_arch = "x86",
++ target_arch = "x86_64",
++ target_arch = "sparc64"))))]
++ MADV_SOFT_OFFLINE,
++ /// Enable Transparent Huge Pages (THP) for pages in the given range.
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ MADV_HUGEPAGE,
++ /// Undo the effect of `MADV_HUGEPAGE`.
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ MADV_NOHUGEPAGE,
++ /// Exclude the given range from a core dump.
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ MADV_DONTDUMP,
++ /// Undo the effect of an earlier `MADV_DONTDUMP`.
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ MADV_DODUMP,
++ /// Specify that the application no longer needs the pages in the given range.
++ MADV_FREE,
++ /// Request that the system not flush the current range to disk unless it needs to.
++ #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
++ MADV_NOSYNC,
++ /// Undoes the effects of `MADV_NOSYNC` for any future pages dirtied within the given range.
++ #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
++ MADV_AUTOSYNC,
++ /// Region is not included in a core file.
++ #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
++ MADV_NOCORE,
++ /// Include region in a core file
++ #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
++ MADV_CORE,
++ #[cfg(any(target_os = "freebsd"))]
++ MADV_PROTECT,
++ /// Invalidate the hardware page table for the given region.
++ #[cfg(target_os = "dragonfly")]
++ MADV_INVAL,
++ /// Set the offset of the page directory page to `value` for the virtual page table.
++ #[cfg(target_os = "dragonfly")]
++ MADV_SETMAP,
++ /// Indicates that the application will not need the data in the given range.
++ #[cfg(any(target_os = "ios", target_os = "macos"))]
++ MADV_ZERO_WIRED_PAGES,
++ #[cfg(any(target_os = "ios", target_os = "macos"))]
++ MADV_FREE_REUSABLE,
++ #[cfg(any(target_os = "ios", target_os = "macos"))]
++ MADV_FREE_REUSE,
++ #[cfg(any(target_os = "ios", target_os = "macos"))]
++ MADV_CAN_REUSE,
++ }
++}
++
++libc_bitflags!{
++ /// Configuration flags for `msync`.
++ pub struct MsFlags: c_int {
++ /// Schedule an update but return immediately.
++ MS_ASYNC;
++ /// Invalidate all cached data.
++ MS_INVALIDATE;
++ /// Invalidate pages, but leave them mapped.
++ #[cfg(any(target_os = "ios", target_os = "macos"))]
++ MS_KILLPAGES;
++ /// Deactivate pages, but leave them mapped.
++ #[cfg(any(target_os = "ios", target_os = "macos"))]
++ MS_DEACTIVATE;
++ /// Perform an update and wait for it to complete.
++ MS_SYNC;
++ }
++}
++
++libc_bitflags!{
++ /// Flags for `mlockall`.
++ pub struct MlockAllFlags: c_int {
++ /// Lock pages that are currently mapped into the address space of the process.
++ MCL_CURRENT;
++ /// Lock pages which will become mapped into the address space of the process in the future.
++ MCL_FUTURE;
++ }
++}
++
++/// Locks all memory pages that contain part of the address range with `length` bytes starting at
++/// `addr`. Locked pages never move to the swap area.
++pub unsafe fn mlock(addr: *const c_void, length: size_t) -> Result<()> {
++ Errno::result(libc::mlock(addr, length)).map(drop)
++}
++
++/// Unlocks all memory pages that contain part of the address range with `length` bytes starting at
++/// `addr`.
++pub unsafe fn munlock(addr: *const c_void, length: size_t) -> Result<()> {
++ Errno::result(libc::munlock(addr, length)).map(drop)
++}
++
++/// Locks all memory pages mapped into this process' address space. Locked pages never move to the
++/// swap area.
++pub fn mlockall(flags: MlockAllFlags) -> Result<()> {
++ unsafe { Errno::result(libc::mlockall(flags.bits())) }.map(drop)
++}
++
++/// Unlocks all memory pages mapped into this process' address space.
++pub fn munlockall() -> Result<()> {
++ unsafe { Errno::result(libc::munlockall()) }.map(drop)
++}
++
++/// Calls to mmap are inherently unsafe, so they must be made in an unsafe block. Typically
++/// a higher-level abstraction will hide the unsafe interactions with the mmap'd region.
++pub unsafe fn mmap(addr: *mut c_void, length: size_t, prot: ProtFlags, flags: MapFlags, fd: RawFd, offset: off_t) -> Result<*mut c_void> {
++ let ret = libc::mmap(addr, length, prot.bits(), flags.bits(), fd, offset);
++
++ if ret == libc::MAP_FAILED {
++ Err(Error::Sys(Errno::last()))
++ } else {
++ Ok(ret)
++ }
++}
++
++pub unsafe fn munmap(addr: *mut c_void, len: size_t) -> Result<()> {
++ Errno::result(libc::munmap(addr, len)).map(drop)
++}
++
++pub unsafe fn madvise(addr: *mut c_void, length: size_t, advise: MmapAdvise) -> Result<()> {
++ Errno::result(libc::madvise(addr, length, advise as i32)).map(drop)
++}
++
++/// Set protection of memory mapping.
++///
++/// See [`mprotect(3)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mprotect.html) for
++/// details.
++///
++/// # Safety
++///
++/// Calls to `mprotect` are inherently unsafe, as changes to memory protections can lead to
++/// SIGSEGVs.
++///
++/// ```
++/// # use nix::libc::size_t;
++/// # use nix::sys::mman::{mmap, mprotect, MapFlags, ProtFlags};
++/// # use std::ptr;
++/// const ONE_K: size_t = 1024;
++/// let mut slice: &mut [u8] = unsafe {
++/// let mem = mmap(ptr::null_mut(), ONE_K, ProtFlags::PROT_NONE,
++/// MapFlags::MAP_ANON | MapFlags::MAP_PRIVATE, -1, 0).unwrap();
++/// mprotect(mem, ONE_K, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE).unwrap();
++/// std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K)
++/// };
++/// assert_eq!(slice[0], 0x00);
++/// slice[0] = 0xFF;
++/// assert_eq!(slice[0], 0xFF);
++/// ```
++pub unsafe fn mprotect(addr: *mut c_void, length: size_t, prot: ProtFlags) -> Result<()> {
++ Errno::result(libc::mprotect(addr, length, prot.bits())).map(drop)
++}
++
++pub unsafe fn msync(addr: *mut c_void, length: size_t, flags: MsFlags) -> Result<()> {
++ Errno::result(libc::msync(addr, length, flags.bits())).map(drop)
++}
++
++#[cfg(not(target_os = "android"))]
++pub fn shm_open<P: ?Sized + NixPath>(name: &P, flag: OFlag, mode: Mode) -> Result<RawFd> {
++ let ret = name.with_nix_path(|cstr| {
++ #[cfg(any(target_os = "macos", target_os = "ios"))]
++ unsafe {
++ libc::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as libc::c_uint)
++ }
++ #[cfg(not(any(target_os = "macos", target_os = "ios")))]
++ unsafe {
++ libc::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as libc::mode_t)
++ }
++ })?;
++
++ Errno::result(ret)
++}
++
++#[cfg(not(target_os = "android"))]
++pub fn shm_unlink<P: ?Sized + NixPath>(name: &P) -> Result<()> {
++ let ret = name.with_nix_path(|cstr| {
++ unsafe { libc::shm_unlink(cstr.as_ptr()) }
++ })?;
++
++ Errno::result(ret).map(drop)
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/mod.rs b/third_party/rust/nix-0.15.0/src/sys/mod.rs
+new file mode 100644
+index 0000000000000..d3c2f92bbaaea
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/mod.rs
+@@ -0,0 +1,100 @@
++#[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos",
++ target_os = "netbsd"))]
++pub mod aio;
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++pub mod epoll;
++
++#[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++pub mod event;
++
++#[cfg(target_os = "linux")]
++pub mod eventfd;
++
++#[cfg(any(target_os = "android",
++ target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++#[macro_use]
++pub mod ioctl;
++
++#[cfg(target_os = "linux")]
++pub mod memfd;
++
++pub mod mman;
++
++pub mod pthread;
++
++#[cfg(any(target_os = "android",
++ target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "linux",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++pub mod ptrace;
++
++#[cfg(target_os = "linux")]
++pub mod quota;
++
++#[cfg(any(target_os = "linux"))]
++pub mod reboot;
++
++pub mod select;
++
++#[cfg(any(target_os = "android",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos"))]
++pub mod sendfile;
++
++pub mod signal;
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++pub mod signalfd;
++
++pub mod socket;
++
++pub mod stat;
++
++#[cfg(any(target_os = "android",
++ target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos",
++ target_os = "openbsd"
++))]
++pub mod statfs;
++
++pub mod statvfs;
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++pub mod sysinfo;
++
++pub mod termios;
++
++pub mod time;
++
++pub mod uio;
++
++pub mod utsname;
++
++pub mod wait;
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++pub mod inotify;
+diff --git a/third_party/rust/nix-0.15.0/src/sys/pthread.rs b/third_party/rust/nix-0.15.0/src/sys/pthread.rs
+new file mode 100644
+index 0000000000000..a4d98250f2b8b
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/pthread.rs
+@@ -0,0 +1,13 @@
++use libc::{self, pthread_t};
++
++pub type Pthread = pthread_t;
++
++/// Obtain ID of the calling thread (see
++/// [`pthread_self(3)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_self.html)
++///
++/// The thread ID returned by `pthread_self()` is not the same thing as
++/// the kernel thread ID returned by a call to `gettid(2)`.
++#[inline]
++pub fn pthread_self() -> Pthread {
++ unsafe { libc::pthread_self() }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/ptrace/bsd.rs b/third_party/rust/nix-0.15.0/src/sys/ptrace/bsd.rs
+new file mode 100644
+index 0000000000000..7797d10647ef4
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/ptrace/bsd.rs
+@@ -0,0 +1,170 @@
++use errno::Errno;
++use libc::{self, c_int};
++use std::ptr;
++use sys::signal::Signal;
++use unistd::Pid;
++use Result;
++
++pub type RequestType = c_int;
++
++cfg_if! {
++ if #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "macos",
++ target_os = "openbsd"))] {
++ #[doc(hidden)]
++ pub type AddressType = *mut ::libc::c_char;
++ } else {
++ #[doc(hidden)]
++ pub type AddressType = *mut ::libc::c_void;
++ }
++}
++
++libc_enum! {
++ #[repr(i32)]
++ /// Ptrace Request enum defining the action to be taken.
++ pub enum Request {
++ PT_TRACE_ME,
++ PT_READ_I,
++ PT_READ_D,
++ #[cfg(target_os = "macos")]
++ PT_READ_U,
++ PT_WRITE_I,
++ PT_WRITE_D,
++ #[cfg(target_os = "macos")]
++ PT_WRITE_U,
++ PT_CONTINUE,
++ PT_KILL,
++ #[cfg(any(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "macos"),
++ all(target_os = "openbsd", target_arch = "x86_64"),
++ all(target_os = "netbsd", any(target_arch = "x86_64",
++ target_arch = "powerpc"))))]
++ PT_STEP,
++ PT_ATTACH,
++ PT_DETACH,
++ #[cfg(target_os = "macos")]
++ PT_SIGEXC,
++ #[cfg(target_os = "macos")]
++ PT_THUPDATE,
++ #[cfg(target_os = "macos")]
++ PT_ATTACHEXC
++ }
++}
++
++unsafe fn ptrace_other(
++ request: Request,
++ pid: Pid,
++ addr: AddressType,
++ data: c_int,
++) -> Result<c_int> {
++ Errno::result(libc::ptrace(
++ request as RequestType,
++ libc::pid_t::from(pid),
++ addr,
++ data,
++ )).map(|_| 0)
++}
++
++/// Sets the process as traceable, as with `ptrace(PT_TRACEME, ...)`
++///
++/// Indicates that this process is to be traced by its parent.
++/// This is the only ptrace request to be issued by the tracee.
++pub fn traceme() -> Result<()> {
++ unsafe { ptrace_other(Request::PT_TRACE_ME, Pid::from_raw(0), ptr::null_mut(), 0).map(drop) }
++}
++
++/// Attach to a running process, as with `ptrace(PT_ATTACH, ...)`
++///
++/// Attaches to the process specified in pid, making it a tracee of the calling process.
++pub fn attach(pid: Pid) -> Result<()> {
++ unsafe { ptrace_other(Request::PT_ATTACH, pid, ptr::null_mut(), 0).map(drop) }
++}
++
++/// Detaches the current running process, as with `ptrace(PT_DETACH, ...)`
++///
++/// Detaches from the process specified in pid allowing it to run freely
++pub fn detach(pid: Pid) -> Result<()> {
++ unsafe { ptrace_other(Request::PT_DETACH, pid, ptr::null_mut(), 0).map(drop) }
++}
++
++/// Restart the stopped tracee process, as with `ptrace(PTRACE_CONT, ...)`
++///
++/// Continues the execution of the process with PID `pid`, optionally
++/// delivering a signal specified by `sig`.
++pub fn cont<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
++ let data = match sig.into() {
++ Some(s) => s as c_int,
++ None => 0,
++ };
++ unsafe {
++ // Ignore the useless return value
++ ptrace_other(Request::PT_CONTINUE, pid, 1 as AddressType, data).map(drop)
++ }
++}
++
++/// Issues a kill request as with `ptrace(PT_KILL, ...)`
++///
++/// This request is equivalent to `ptrace(PT_CONTINUE, ..., SIGKILL);`
++pub fn kill(pid: Pid) -> Result<()> {
++ unsafe {
++ ptrace_other(Request::PT_KILL, pid, 0 as AddressType, 0).map(drop)
++ }
++}
++
++/// Move the stopped tracee process forward by a single step as with
++/// `ptrace(PT_STEP, ...)`
++///
++/// Advances the execution of the process with PID `pid` by a single step optionally delivering a
++/// signal specified by `sig`.
++///
++/// # Example
++/// ```rust
++/// extern crate nix;
++/// use nix::sys::ptrace::step;
++/// use nix::unistd::Pid;
++/// use nix::sys::signal::Signal;
++/// use nix::sys::wait::*;
++/// fn main() {
++/// // If a process changes state to the stopped state because of a SIGUSR1
++/// // signal, this will step the process forward and forward the user
++/// // signal to the stopped process
++/// match waitpid(Pid::from_raw(-1), None) {
++/// Ok(WaitStatus::Stopped(pid, Signal::SIGUSR1)) => {
++/// let _ = step(pid, Signal::SIGUSR1);
++/// }
++/// _ => {},
++/// }
++/// }
++/// ```
++#[cfg(
++ any(
++ any(target_os = "dragonfly", target_os = "freebsd", target_os = "macos"),
++ all(target_os = "openbsd", target_arch = "x86_64"),
++ all(target_os = "netbsd",
++ any(target_arch = "x86_64", target_arch = "powerpc")
++ )
++ )
++)]
++pub fn step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
++ let data = match sig.into() {
++ Some(s) => s as c_int,
++ None => 0,
++ };
++ unsafe { ptrace_other(Request::PT_STEP, pid, ptr::null_mut(), data).map(drop) }
++}
++
++/// Reads a word from a processes memory at the given address
++pub fn read(pid: Pid, addr: AddressType) -> Result<c_int> {
++ unsafe {
++ // Traditionally there was a difference between reading data or
++ // instruction memory but not in modern systems.
++ ptrace_other(Request::PT_READ_D, pid, addr, 0)
++ }
++}
++
++/// Writes a word into the processes memory at the given address
++pub fn write(pid: Pid, addr: AddressType, data: c_int) -> Result<()> {
++ unsafe { ptrace_other(Request::PT_WRITE_D, pid, addr, data).map(drop) }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/ptrace/linux.rs b/third_party/rust/nix-0.15.0/src/sys/ptrace/linux.rs
+new file mode 100644
+index 0000000000000..df15e66527562
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/ptrace/linux.rs
+@@ -0,0 +1,402 @@
++//! For detailed description of the ptrace requests, consult `man ptrace`.
++
++use std::{mem, ptr};
++use {Error, Result};
++use errno::Errno;
++use libc::{self, c_void, c_long, siginfo_t};
++use ::unistd::Pid;
++use sys::signal::Signal;
++
++pub type AddressType = *mut ::libc::c_void;
++
++#[cfg(all(target_os = "linux",
++ any(target_arch = "x86_64",
++ target_arch = "x86"),
++ target_env = "gnu"))]
++use libc::user_regs_struct;
++
++cfg_if! {
++ if #[cfg(any(all(target_os = "linux", target_arch = "s390x"),
++ all(target_os = "linux", target_env = "gnu")))] {
++ #[doc(hidden)]
++ pub type RequestType = ::libc::c_uint;
++ } else {
++ #[doc(hidden)]
++ pub type RequestType = ::libc::c_int;
++ }
++}
++
++libc_enum!{
++ #[cfg_attr(not(any(target_env = "musl", target_os = "android")), repr(u32))]
++ #[cfg_attr(any(target_env = "musl", target_os = "android"), repr(i32))]
++ /// Ptrace Request enum defining the action to be taken.
++ pub enum Request {
++ PTRACE_TRACEME,
++ PTRACE_PEEKTEXT,
++ PTRACE_PEEKDATA,
++ PTRACE_PEEKUSER,
++ PTRACE_POKETEXT,
++ PTRACE_POKEDATA,
++ PTRACE_POKEUSER,
++ PTRACE_CONT,
++ PTRACE_KILL,
++ PTRACE_SINGLESTEP,
++ #[cfg(any(all(target_os = "android", target_pointer_width = "32"),
++ all(target_os = "linux", any(target_env = "musl",
++ target_arch = "mips",
++ target_arch = "mips64",
++ target_arch = "x86_64",
++ target_pointer_width = "32"))))]
++ PTRACE_GETREGS,
++ #[cfg(any(all(target_os = "android", target_pointer_width = "32"),
++ all(target_os = "linux", any(target_env = "musl",
++ target_arch = "mips",
++ target_arch = "mips64",
++ target_arch = "x86_64",
++ target_pointer_width = "32"))))]
++ PTRACE_SETREGS,
++ #[cfg(any(all(target_os = "android", target_pointer_width = "32"),
++ all(target_os = "linux", any(target_env = "musl",
++ target_arch = "mips",
++ target_arch = "mips64",
++ target_arch = "x86_64",
++ target_pointer_width = "32"))))]
++ PTRACE_GETFPREGS,
++ #[cfg(any(all(target_os = "android", target_pointer_width = "32"),
++ all(target_os = "linux", any(target_env = "musl",
++ target_arch = "mips",
++ target_arch = "mips64",
++ target_arch = "x86_64",
++ target_pointer_width = "32"))))]
++ PTRACE_SETFPREGS,
++ PTRACE_ATTACH,
++ PTRACE_DETACH,
++ #[cfg(all(target_os = "linux", any(target_env = "musl",
++ target_arch = "mips",
++ target_arch = "mips64",
++ target_arch = "x86",
++ target_arch = "x86_64")))]
++ PTRACE_GETFPXREGS,
++ #[cfg(all(target_os = "linux", any(target_env = "musl",
++ target_arch = "mips",
++ target_arch = "mips64",
++ target_arch = "x86",
++ target_arch = "x86_64")))]
++ PTRACE_SETFPXREGS,
++ PTRACE_SYSCALL,
++ PTRACE_SETOPTIONS,
++ PTRACE_GETEVENTMSG,
++ PTRACE_GETSIGINFO,
++ PTRACE_SETSIGINFO,
++ #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
++ target_arch = "mips64"))))]
++ PTRACE_GETREGSET,
++ #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
++ target_arch = "mips64"))))]
++ PTRACE_SETREGSET,
++ #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
++ target_arch = "mips64"))))]
++ PTRACE_SEIZE,
++ #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
++ target_arch = "mips64"))))]
++ PTRACE_INTERRUPT,
++ #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
++ target_arch = "mips64"))))]
++ PTRACE_LISTEN,
++ #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
++ target_arch = "mips64"))))]
++ PTRACE_PEEKSIGINFO,
++ }
++}
++
++libc_enum!{
++ #[repr(i32)]
++ /// Using the ptrace options the tracer can configure the tracee to stop
++ /// at certain events. This enum is used to define those events as defined
++ /// in `man ptrace`.
++ pub enum Event {
++ /// Event that stops before a return from fork or clone.
++ PTRACE_EVENT_FORK,
++ /// Event that stops before a return from vfork or clone.
++ PTRACE_EVENT_VFORK,
++ /// Event that stops before a return from clone.
++ PTRACE_EVENT_CLONE,
++ /// Event that stops before a return from execve.
++ PTRACE_EVENT_EXEC,
++ /// Event for a return from vfork.
++ PTRACE_EVENT_VFORK_DONE,
++ /// Event for a stop before an exit. Unlike the waitpid Exit status program.
++ /// registers can still be examined
++ PTRACE_EVENT_EXIT,
++ /// STop triggered by a seccomp rule on a tracee.
++ PTRACE_EVENT_SECCOMP,
++ // PTRACE_EVENT_STOP not provided by libc because it's defined in glibc 2.26
++ }
++}
++
++libc_bitflags! {
++ /// Ptrace options used in conjunction with the PTRACE_SETOPTIONS request.
++ /// See `man ptrace` for more details.
++ pub struct Options: libc::c_int {
++ /// When delivering system call traps set a bit to allow tracer to
++ /// distinguish between normal stops or syscall stops. May not work on
++ /// all systems.
++ PTRACE_O_TRACESYSGOOD;
++ /// Stop tracee at next fork and start tracing the forked process.
++ PTRACE_O_TRACEFORK;
++ /// Stop tracee at next vfork call and trace the vforked process.
++ PTRACE_O_TRACEVFORK;
++ /// Stop tracee at next clone call and trace the cloned process.
++ PTRACE_O_TRACECLONE;
++ /// Stop tracee at next execve call.
++ PTRACE_O_TRACEEXEC;
++ /// Stop tracee at vfork completion.
++ PTRACE_O_TRACEVFORKDONE;
++ /// Stop tracee at next exit call. Stops before exit commences allowing
++ /// tracer to see location of exit and register states.
++ PTRACE_O_TRACEEXIT;
++ /// Stop tracee when a SECCOMP_RET_TRACE rule is triggered. See `man seccomp` for more
++ /// details.
++ PTRACE_O_TRACESECCOMP;
++ /// Send a SIGKILL to the tracee if the tracer exits. This is useful
++ /// for ptrace jailers to prevent tracees from escaping their control.
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ PTRACE_O_EXITKILL;
++ }
++}
++
++/// Performs a ptrace request. If the request in question is provided by a specialised function
++/// this function will return an unsupported operation error.
++#[deprecated(
++ since="0.10.0",
++ note="usages of `ptrace()` should be replaced with the specialized helper functions instead"
++)]
++pub unsafe fn ptrace(request: Request, pid: Pid, addr: AddressType, data: *mut c_void) -> Result<c_long> {
++ use self::Request::*;
++ match request {
++ PTRACE_PEEKTEXT | PTRACE_PEEKDATA | PTRACE_GETSIGINFO |
++ PTRACE_GETEVENTMSG | PTRACE_SETSIGINFO | PTRACE_SETOPTIONS |
++ PTRACE_POKETEXT | PTRACE_POKEDATA | PTRACE_KILL => Err(Error::UnsupportedOperation),
++ _ => ptrace_other(request, pid, addr, data)
++ }
++}
++
++fn ptrace_peek(request: Request, pid: Pid, addr: AddressType, data: *mut c_void) -> Result<c_long> {
++ let ret = unsafe {
++ Errno::clear();
++ libc::ptrace(request as RequestType, libc::pid_t::from(pid), addr, data)
++ };
++ match Errno::result(ret) {
++ Ok(..) | Err(Error::Sys(Errno::UnknownErrno)) => Ok(ret),
++ err @ Err(..) => err,
++ }
++}
++
++/// Get user registers, as with `ptrace(PTRACE_GETREGS, ...)`
++#[cfg(all(target_os = "linux",
++ any(target_arch = "x86_64",
++ target_arch = "x86"),
++ target_env = "gnu"))]
++pub fn getregs(pid: Pid) -> Result<user_regs_struct> {
++ ptrace_get_data::<user_regs_struct>(Request::PTRACE_GETREGS, pid)
++}
++
++/// Set user registers, as with `ptrace(PTRACE_SETREGS, ...)`
++#[cfg(all(target_os = "linux",
++ any(target_arch = "x86_64",
++ target_arch = "x86"),
++ target_env = "gnu"))]
++pub fn setregs(pid: Pid, regs: user_regs_struct) -> Result<()> {
++ let res = unsafe {
++ libc::ptrace(Request::PTRACE_SETREGS as RequestType,
++ libc::pid_t::from(pid),
++ ptr::null_mut::<c_void>(),
++ &regs as *const _ as *const c_void)
++ };
++ Errno::result(res).map(drop)
++}
++
++/// Function for ptrace requests that return values from the data field.
++/// Some ptrace get requests populate structs or larger elements than `c_long`
++/// and therefore use the data field to return values. This function handles these
++/// requests.
++fn ptrace_get_data<T>(request: Request, pid: Pid) -> Result<T> {
++ // Creates an uninitialized pointer to store result in
++ let data: T = unsafe { mem::uninitialized() };
++ let res = unsafe {
++ libc::ptrace(request as RequestType,
++ libc::pid_t::from(pid),
++ ptr::null_mut::<T>(),
++ &data as *const _ as *const c_void)
++ };
++ Errno::result(res)?;
++ Ok(data)
++}
++
++unsafe fn ptrace_other(request: Request, pid: Pid, addr: AddressType, data: *mut c_void) -> Result<c_long> {
++ Errno::result(libc::ptrace(request as RequestType, libc::pid_t::from(pid), addr, data)).map(|_| 0)
++}
++
++/// Set options, as with `ptrace(PTRACE_SETOPTIONS,...)`.
++pub fn setoptions(pid: Pid, options: Options) -> Result<()> {
++ let res = unsafe {
++ libc::ptrace(Request::PTRACE_SETOPTIONS as RequestType,
++ libc::pid_t::from(pid),
++ ptr::null_mut::<c_void>(),
++ options.bits() as *mut c_void)
++ };
++ Errno::result(res).map(drop)
++}
++
++/// Gets a ptrace event as described by `ptrace(PTRACE_GETEVENTMSG,...)`
++pub fn getevent(pid: Pid) -> Result<c_long> {
++ ptrace_get_data::<c_long>(Request::PTRACE_GETEVENTMSG, pid)
++}
++
++/// Get siginfo as with `ptrace(PTRACE_GETSIGINFO,...)`
++pub fn getsiginfo(pid: Pid) -> Result<siginfo_t> {
++ ptrace_get_data::<siginfo_t>(Request::PTRACE_GETSIGINFO, pid)
++}
++
++/// Set siginfo as with `ptrace(PTRACE_SETSIGINFO,...)`
++pub fn setsiginfo(pid: Pid, sig: &siginfo_t) -> Result<()> {
++ let ret = unsafe{
++ Errno::clear();
++ libc::ptrace(Request::PTRACE_SETSIGINFO as RequestType,
++ libc::pid_t::from(pid),
++ ptr::null_mut::<c_void>(),
++ sig as *const _ as *const c_void)
++ };
++ match Errno::result(ret) {
++ Ok(_) => Ok(()),
++ Err(e) => Err(e),
++ }
++}
++
++/// Sets the process as traceable, as with `ptrace(PTRACE_TRACEME, ...)`
++///
++/// Indicates that this process is to be traced by its parent.
++/// This is the only ptrace request to be issued by the tracee.
++pub fn traceme() -> Result<()> {
++ unsafe {
++ ptrace_other(
++ Request::PTRACE_TRACEME,
++ Pid::from_raw(0),
++ ptr::null_mut(),
++ ptr::null_mut(),
++ ).map(drop) // ignore the useless return value
++ }
++}
++
++/// Ask for next syscall, as with `ptrace(PTRACE_SYSCALL, ...)`
++///
++/// Arranges for the tracee to be stopped at the next entry to or exit from a system call.
++pub fn syscall(pid: Pid) -> Result<()> {
++ unsafe {
++ ptrace_other(
++ Request::PTRACE_SYSCALL,
++ pid,
++ ptr::null_mut(),
++ ptr::null_mut(),
++ ).map(drop) // ignore the useless return value
++ }
++}
++
++/// Attach to a running process, as with `ptrace(PTRACE_ATTACH, ...)`
++///
++/// Attaches to the process specified in pid, making it a tracee of the calling process.
++pub fn attach(pid: Pid) -> Result<()> {
++ unsafe {
++ ptrace_other(
++ Request::PTRACE_ATTACH,
++ pid,
++ ptr::null_mut(),
++ ptr::null_mut(),
++ ).map(drop) // ignore the useless return value
++ }
++}
++
++/// Detaches the current running process, as with `ptrace(PTRACE_DETACH, ...)`
++///
++/// Detaches from the process specified in pid allowing it to run freely
++pub fn detach(pid: Pid) -> Result<()> {
++ unsafe {
++ ptrace_other(
++ Request::PTRACE_DETACH,
++ pid,
++ ptr::null_mut(),
++ ptr::null_mut()
++ ).map(drop)
++ }
++}
++
++/// Restart the stopped tracee process, as with `ptrace(PTRACE_CONT, ...)`
++///
++/// Continues the execution of the process with PID `pid`, optionally
++/// delivering a signal specified by `sig`.
++pub fn cont<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
++ let data = match sig.into() {
++ Some(s) => s as i32 as *mut c_void,
++ None => ptr::null_mut(),
++ };
++ unsafe {
++ ptrace_other(Request::PTRACE_CONT, pid, ptr::null_mut(), data).map(drop) // ignore the useless return value
++ }
++}
++
++/// Issues a kill request as with `ptrace(PTRACE_KILL, ...)`
++///
++/// This request is equivalent to `ptrace(PTRACE_CONT, ..., SIGKILL);`
++pub fn kill(pid: Pid) -> Result<()> {
++ unsafe {
++ ptrace_other(Request::PTRACE_KILL, pid, ptr::null_mut(), ptr::null_mut()).map(drop)
++ }
++}
++
++/// Move the stopped tracee process forward by a single step as with
++/// `ptrace(PTRACE_SINGLESTEP, ...)`
++///
++/// Advances the execution of the process with PID `pid` by a single step optionally delivering a
++/// signal specified by `sig`.
++///
++/// # Example
++/// ```rust
++/// extern crate nix;
++/// use nix::sys::ptrace::step;
++/// use nix::unistd::Pid;
++/// use nix::sys::signal::Signal;
++/// use nix::sys::wait::*;
++/// fn main() {
++/// // If a process changes state to the stopped state because of a SIGUSR1
++/// // signal, this will step the process forward and forward the user
++/// // signal to the stopped process
++/// match waitpid(Pid::from_raw(-1), None) {
++/// Ok(WaitStatus::Stopped(pid, Signal::SIGUSR1)) => {
++/// let _ = step(pid, Signal::SIGUSR1);
++/// }
++/// _ => {},
++/// }
++/// }
++/// ```
++pub fn step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
++ let data = match sig.into() {
++ Some(s) => s as i32 as *mut c_void,
++ None => ptr::null_mut(),
++ };
++ unsafe {
++ ptrace_other(Request::PTRACE_SINGLESTEP, pid, ptr::null_mut(), data).map(drop)
++ }
++}
++
++
++/// Reads a word from a processes memory at the given address
++pub fn read(pid: Pid, addr: AddressType) -> Result<c_long> {
++ ptrace_peek(Request::PTRACE_PEEKDATA, pid, addr, ptr::null_mut())
++}
++
++/// Writes a word into the processes memory at the given address
++pub fn write(pid: Pid, addr: AddressType, data: *mut c_void) -> Result<()> {
++ unsafe {
++ ptrace_other(Request::PTRACE_POKEDATA, pid, addr, data).map(drop)
++ }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/ptrace/mod.rs b/third_party/rust/nix-0.15.0/src/sys/ptrace/mod.rs
+new file mode 100644
+index 0000000000000..782c30409bc12
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/ptrace/mod.rs
+@@ -0,0 +1,22 @@
++///! Provides helpers for making ptrace system calls
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++mod linux;
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++pub use self::linux::*;
++
++#[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++mod bsd;
++
++#[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"
++ ))]
++pub use self::bsd::*;
+diff --git a/third_party/rust/nix-0.15.0/src/sys/quota.rs b/third_party/rust/nix-0.15.0/src/sys/quota.rs
+new file mode 100644
+index 0000000000000..8946fca2213c8
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/quota.rs
+@@ -0,0 +1,273 @@
++//! Set and configure disk quotas for users, groups, or projects.
++//!
++//! # Examples
++//!
++//! Enabling and setting a quota:
++//!
++//! ```rust,no_run
++//! # use nix::sys::quota::{Dqblk, quotactl_on, quotactl_set, QuotaFmt, QuotaType, QuotaValidFlags};
++//! quotactl_on(QuotaType::USRQUOTA, "/dev/sda1", QuotaFmt::QFMT_VFS_V1, "aquota.user");
++//! let mut dqblk: Dqblk = Default::default();
++//! dqblk.set_blocks_hard_limit(10000);
++//! dqblk.set_blocks_soft_limit(8000);
++//! quotactl_set(QuotaType::USRQUOTA, "/dev/sda1", 50, &dqblk, QuotaValidFlags::QIF_BLIMITS);
++//! ```
++use std::default::Default;
++use std::{mem, ptr};
++use libc::{self, c_int, c_char};
++use {Result, NixPath};
++use errno::Errno;
++
++struct QuotaCmd(QuotaSubCmd, QuotaType);
++
++impl QuotaCmd {
++ fn as_int(&self) -> c_int {
++ unsafe { libc::QCMD(self.0 as i32, self.1 as i32) }
++ }
++}
++
++// linux quota version >= 2
++libc_enum!{
++ #[repr(i32)]
++ enum QuotaSubCmd {
++ Q_SYNC,
++ Q_QUOTAON,
++ Q_QUOTAOFF,
++ Q_GETQUOTA,
++ Q_SETQUOTA,
++ }
++}
++
++libc_enum!{
++ /// The scope of the quota.
++ #[repr(i32)]
++ pub enum QuotaType {
++ /// Specify a user quota
++ USRQUOTA,
++ /// Specify a group quota
++ GRPQUOTA,
++ }
++}
++
++libc_enum!{
++ /// The type of quota format to use.
++ #[repr(i32)]
++ pub enum QuotaFmt {
++ /// Use the original quota format.
++ QFMT_VFS_OLD,
++ /// Use the standard VFS v0 quota format.
++ ///
++ /// Handles 32-bit UIDs/GIDs and quota limits up to 2<sup>32</sup> bytes/2<sup>32</sup> inodes.
++ QFMT_VFS_V0,
++ /// Use the VFS v1 quota format.
++ ///
++ /// Handles 32-bit UIDs/GIDs and quota limits of 2<sup>64</sup> bytes/2<sup>64</sup> inodes.
++ QFMT_VFS_V1,
++ }
++}
++
++libc_bitflags!(
++ /// Indicates the quota fields that are valid to read from.
++ #[derive(Default)]
++ pub struct QuotaValidFlags: u32 {
++ /// The block hard & soft limit fields.
++ QIF_BLIMITS;
++ /// The current space field.
++ QIF_SPACE;
++ /// The inode hard & soft limit fields.
++ QIF_ILIMITS;
++ /// The current inodes field.
++ QIF_INODES;
++ /// The disk use time limit field.
++ QIF_BTIME;
++ /// The file quote time limit field.
++ QIF_ITIME;
++ /// All block & inode limits.
++ QIF_LIMITS;
++ /// The space & inodes usage fields.
++ QIF_USAGE;
++ /// The time limit fields.
++ QIF_TIMES;
++ /// All fields.
++ QIF_ALL;
++ }
++);
++
++/// Wrapper type for `if_dqblk`
++// FIXME: Change to repr(transparent)
++#[repr(C)]
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub struct Dqblk(libc::dqblk);
++
++impl Default for Dqblk {
++ fn default() -> Dqblk {
++ Dqblk(libc::dqblk {
++ dqb_bhardlimit: 0,
++ dqb_bsoftlimit: 0,
++ dqb_curspace: 0,
++ dqb_ihardlimit: 0,
++ dqb_isoftlimit: 0,
++ dqb_curinodes: 0,
++ dqb_btime: 0,
++ dqb_itime: 0,
++ dqb_valid: 0,
++ })
++ }
++}
++
++impl Dqblk {
++ /// The absolute limit on disk quota blocks allocated.
++ pub fn blocks_hard_limit(&self) -> Option<u64> {
++ let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
++ if valid_fields.contains(QuotaValidFlags::QIF_BLIMITS) {
++ Some(self.0.dqb_bhardlimit)
++ } else {
++ None
++ }
++ }
++
++ /// Set the absolute limit on disk quota blocks allocated.
++ pub fn set_blocks_hard_limit(&mut self, limit: u64) {
++ self.0.dqb_bhardlimit = limit;
++ }
++
++ /// Preferred limit on disk quota blocks
++ pub fn blocks_soft_limit(&self) -> Option<u64> {
++ let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
++ if valid_fields.contains(QuotaValidFlags::QIF_BLIMITS) {
++ Some(self.0.dqb_bsoftlimit)
++ } else {
++ None
++ }
++ }
++
++ /// Set the preferred limit on disk quota blocks allocated.
++ pub fn set_blocks_soft_limit(&mut self, limit: u64) {
++ self.0.dqb_bsoftlimit = limit;
++ }
++
++ /// Current occupied space (bytes).
++ pub fn occupied_space(&self) -> Option<u64> {
++ let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
++ if valid_fields.contains(QuotaValidFlags::QIF_SPACE) {
++ Some(self.0.dqb_curspace)
++ } else {
++ None
++ }
++ }
++
++ /// Maximum number of allocated inodes.
++ pub fn inodes_hard_limit(&self) -> Option<u64> {
++ let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
++ if valid_fields.contains(QuotaValidFlags::QIF_ILIMITS) {
++ Some(self.0.dqb_ihardlimit)
++ } else {
++ None
++ }
++ }
++
++ /// Set the maximum number of allocated inodes.
++ pub fn set_inodes_hard_limit(&mut self, limit: u64) {
++ self.0.dqb_ihardlimit = limit;
++ }
++
++ /// Preferred inode limit
++ pub fn inodes_soft_limit(&self) -> Option<u64> {
++ let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
++ if valid_fields.contains(QuotaValidFlags::QIF_ILIMITS) {
++ Some(self.0.dqb_isoftlimit)
++ } else {
++ None
++ }
++ }
++
++ /// Set the preferred limit of allocated inodes.
++ pub fn set_inodes_soft_limit(&mut self, limit: u64) {
++ self.0.dqb_isoftlimit = limit;
++ }
++
++ /// Current number of allocated inodes.
++ pub fn allocated_inodes(&self) -> Option<u64> {
++ let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
++ if valid_fields.contains(QuotaValidFlags::QIF_INODES) {
++ Some(self.0.dqb_curinodes)
++ } else {
++ None
++ }
++ }
++
++ /// Time limit for excessive disk use.
++ pub fn block_time_limit(&self) -> Option<u64> {
++ let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
++ if valid_fields.contains(QuotaValidFlags::QIF_BTIME) {
++ Some(self.0.dqb_btime)
++ } else {
++ None
++ }
++ }
++
++ /// Set the time limit for excessive disk use.
++ pub fn set_block_time_limit(&mut self, limit: u64) {
++ self.0.dqb_btime = limit;
++ }
++
++ /// Time limit for excessive files.
++ pub fn inode_time_limit(&self) -> Option<u64> {
++ let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
++ if valid_fields.contains(QuotaValidFlags::QIF_ITIME) {
++ Some(self.0.dqb_itime)
++ } else {
++ None
++ }
++ }
++
++ /// Set the time limit for excessive files.
++ pub fn set_inode_time_limit(&mut self, limit: u64) {
++ self.0.dqb_itime = limit;
++ }
++}
++
++fn quotactl<P: ?Sized + NixPath>(cmd: QuotaCmd, special: Option<&P>, id: c_int, addr: *mut c_char) -> Result<()> {
++ unsafe {
++ Errno::clear();
++ let res = match special {
++ Some(dev) => dev.with_nix_path(|path| libc::quotactl(cmd.as_int(), path.as_ptr(), id, addr)),
++ None => Ok(libc::quotactl(cmd.as_int(), ptr::null(), id, addr)),
++ }?;
++
++ Errno::result(res).map(drop)
++ }
++}
++
++/// Turn on disk quotas for a block device.
++pub fn quotactl_on<P: ?Sized + NixPath>(which: QuotaType, special: &P, format: QuotaFmt, quota_file: &P) -> Result<()> {
++ quota_file.with_nix_path(|path| {
++ let mut path_copy = path.to_bytes_with_nul().to_owned();
++ let p: *mut c_char = path_copy.as_mut_ptr() as *mut c_char;
++ quotactl(QuotaCmd(QuotaSubCmd::Q_QUOTAON, which), Some(special), format as c_int, p)
++ })?
++}
++
++/// Disable disk quotas for a block device.
++pub fn quotactl_off<P: ?Sized + NixPath>(which: QuotaType, special: &P) -> Result<()> {
++ quotactl(QuotaCmd(QuotaSubCmd::Q_QUOTAOFF, which), Some(special), 0, ptr::null_mut())
++}
++
++/// Update the on-disk copy of quota usages for a filesystem.
++pub fn quotactl_sync<P: ?Sized + NixPath>(which: QuotaType, special: Option<&P>) -> Result<()> {
++ quotactl(QuotaCmd(QuotaSubCmd::Q_SYNC, which), special, 0, ptr::null_mut())
++}
++
++/// Get disk quota limits and current usage for the given user/group id.
++pub fn quotactl_get<P: ?Sized + NixPath>(which: QuotaType, special: &P, id: c_int) -> Result<Dqblk> {
++ let mut dqblk = unsafe { mem::uninitialized() };
++ quotactl(QuotaCmd(QuotaSubCmd::Q_GETQUOTA, which), Some(special), id, &mut dqblk as *mut _ as *mut c_char)?;
++ dqblk
++}
++
++/// Configure quota values for the specified fields for a given user/group id.
++pub fn quotactl_set<P: ?Sized + NixPath>(which: QuotaType, special: &P, id: c_int, dqblk: &Dqblk, fields: QuotaValidFlags) -> Result<()> {
++ let mut dqblk_copy = *dqblk;
++ dqblk_copy.0.dqb_valid = fields.bits();
++ quotactl(QuotaCmd(QuotaSubCmd::Q_SETQUOTA, which), Some(special), id, &mut dqblk_copy as *mut _ as *mut c_char)
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/reboot.rs b/third_party/rust/nix-0.15.0/src/sys/reboot.rs
+new file mode 100644
+index 0000000000000..bafa8fc11996d
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/reboot.rs
+@@ -0,0 +1,45 @@
++//! Reboot/shutdown or enable/disable Ctrl-Alt-Delete.
++
++use {Error, Result};
++use errno::Errno;
++use libc;
++use void::Void;
++use std::mem::drop;
++
++libc_enum! {
++ /// How exactly should the system be rebooted.
++ ///
++ /// See [`set_cad_enabled()`](fn.set_cad_enabled.html) for
++ /// enabling/disabling Ctrl-Alt-Delete.
++ #[repr(i32)]
++ pub enum RebootMode {
++ RB_HALT_SYSTEM,
++ RB_KEXEC,
++ RB_POWER_OFF,
++ RB_AUTOBOOT,
++ // we do not support Restart2,
++ RB_SW_SUSPEND,
++ }
++}
++
++pub fn reboot(how: RebootMode) -> Result<Void> {
++ unsafe {
++ libc::reboot(how as libc::c_int)
++ };
++ Err(Error::Sys(Errno::last()))
++}
++
++/// Enable or disable the reboot keystroke (Ctrl-Alt-Delete).
++///
++/// Corresponds to calling `reboot(RB_ENABLE_CAD)` or `reboot(RB_DISABLE_CAD)` in C.
++pub fn set_cad_enabled(enable: bool) -> Result<()> {
++ let cmd = if enable {
++ libc::RB_ENABLE_CAD
++ } else {
++ libc::RB_DISABLE_CAD
++ };
++ let res = unsafe {
++ libc::reboot(cmd)
++ };
++ Errno::result(res).map(drop)
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/select.rs b/third_party/rust/nix-0.15.0/src/sys/select.rs
+new file mode 100644
+index 0000000000000..1b518e29f67a6
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/select.rs
+@@ -0,0 +1,334 @@
++use std::mem;
++use std::os::unix::io::RawFd;
++use std::ptr::{null, null_mut};
++use libc::{self, c_int};
++use Result;
++use errno::Errno;
++use sys::signal::SigSet;
++use sys::time::{TimeSpec, TimeVal};
++
++pub use libc::FD_SETSIZE;
++
++// FIXME: Change to repr(transparent) once it's stable
++#[repr(C)]
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub struct FdSet(libc::fd_set);
++
++impl FdSet {
++ pub fn new() -> FdSet {
++ let mut fdset = unsafe { mem::uninitialized() };
++ unsafe { libc::FD_ZERO(&mut fdset) };
++ FdSet(fdset)
++ }
++
++ pub fn insert(&mut self, fd: RawFd) {
++ unsafe { libc::FD_SET(fd, &mut self.0) };
++ }
++
++ pub fn remove(&mut self, fd: RawFd) {
++ unsafe { libc::FD_CLR(fd, &mut self.0) };
++ }
++
++ pub fn contains(&mut self, fd: RawFd) -> bool {
++ unsafe { libc::FD_ISSET(fd, &mut self.0) }
++ }
++
++ pub fn clear(&mut self) {
++ unsafe { libc::FD_ZERO(&mut self.0) };
++ }
++
++ /// Finds the highest file descriptor in the set.
++ ///
++ /// Returns `None` if the set is empty.
++ ///
++ /// This can be used to calculate the `nfds` parameter of the [`select`] function.
++ ///
++ /// # Example
++ ///
++ /// ```
++ /// # extern crate nix;
++ /// # use nix::sys::select::FdSet;
++ /// # fn main() {
++ /// let mut set = FdSet::new();
++ /// set.insert(4);
++ /// set.insert(9);
++ /// assert_eq!(set.highest(), Some(9));
++ /// # }
++ /// ```
++ ///
++ /// [`select`]: fn.select.html
++ pub fn highest(&mut self) -> Option<RawFd> {
++ for i in (0..FD_SETSIZE).rev() {
++ let i = i as RawFd;
++ if unsafe { libc::FD_ISSET(i, self as *mut _ as *mut libc::fd_set) } {
++ return Some(i)
++ }
++ }
++
++ None
++ }
++}
++
++/// Monitors file descriptors for readiness
++///
++/// Returns the total number of ready file descriptors in all sets. The sets are changed so that all
++/// file descriptors that are ready for the given operation are set.
++///
++/// When this function returns, `timeout` has an implementation-defined value.
++///
++/// # Parameters
++///
++/// * `nfds`: The highest file descriptor set in any of the passed `FdSet`s, plus 1. If `None`, this
++/// is calculated automatically by calling [`FdSet::highest`] on all descriptor sets and adding 1
++/// to the maximum of that.
++/// * `readfds`: File descriptors to check for being ready to read.
++/// * `writefds`: File descriptors to check for being ready to write.
++/// * `errorfds`: File descriptors to check for pending error conditions.
++/// * `timeout`: Maximum time to wait for descriptors to become ready (`None` to block
++/// indefinitely).
++///
++/// # References
++///
++/// [select(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/select.html)
++///
++/// [`FdSet::highest`]: struct.FdSet.html#method.highest
++pub fn select<'a, N, R, W, E, T>(nfds: N,
++ readfds: R,
++ writefds: W,
++ errorfds: E,
++ timeout: T) -> Result<c_int>
++where
++ N: Into<Option<c_int>>,
++ R: Into<Option<&'a mut FdSet>>,
++ W: Into<Option<&'a mut FdSet>>,
++ E: Into<Option<&'a mut FdSet>>,
++ T: Into<Option<&'a mut TimeVal>>,
++{
++ let mut readfds = readfds.into();
++ let mut writefds = writefds.into();
++ let mut errorfds = errorfds.into();
++ let timeout = timeout.into();
++
++ let nfds = nfds.into().unwrap_or_else(|| {
++ readfds.iter_mut()
++ .chain(writefds.iter_mut())
++ .chain(errorfds.iter_mut())
++ .map(|set| set.highest().unwrap_or(-1))
++ .max()
++ .unwrap_or(-1) + 1
++ });
++
++ let readfds = readfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
++ let writefds = writefds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
++ let errorfds = errorfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
++ let timeout = timeout.map(|tv| tv as *mut _ as *mut libc::timeval)
++ .unwrap_or(null_mut());
++
++ let res = unsafe {
++ libc::select(nfds, readfds, writefds, errorfds, timeout)
++ };
++
++ Errno::result(res)
++}
++
++/// Monitors file descriptors for readiness with an altered signal mask.
++///
++/// Returns the total number of ready file descriptors in all sets. The sets are changed so that all
++/// file descriptors that are ready for the given operation are set.
++///
++/// When this function returns, the original signal mask is restored.
++///
++/// Unlike [`select`](#fn.select), `pselect` does not mutate the `timeout` value.
++///
++/// # Parameters
++///
++/// * `nfds`: The highest file descriptor set in any of the passed `FdSet`s, plus 1. If `None`, this
++/// is calculated automatically by calling [`FdSet::highest`] on all descriptor sets and adding 1
++/// to the maximum of that.
++/// * `readfds`: File descriptors to check for read readiness
++/// * `writefds`: File descriptors to check for write readiness
++/// * `errorfds`: File descriptors to check for pending error conditions.
++/// * `timeout`: Maximum time to wait for descriptors to become ready (`None` to block
++/// indefinitely).
++/// * `sigmask`: Signal mask to activate while waiting for file descriptors to turn
++/// ready (`None` to set no alternative signal mask).
++///
++/// # References
++///
++/// [pselect(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pselect.html)
++///
++/// [The new pselect() system call](https://lwn.net/Articles/176911/)
++///
++/// [`FdSet::highest`]: struct.FdSet.html#method.highest
++pub fn pselect<'a, N, R, W, E, T, S>(nfds: N,
++ readfds: R,
++ writefds: W,
++ errorfds: E,
++ timeout: T,
++ sigmask: S) -> Result<c_int>
++where
++ N: Into<Option<c_int>>,
++ R: Into<Option<&'a mut FdSet>>,
++ W: Into<Option<&'a mut FdSet>>,
++ E: Into<Option<&'a mut FdSet>>,
++ T: Into<Option<&'a TimeSpec>>,
++ S: Into<Option<&'a SigSet>>,
++{
++ let mut readfds = readfds.into();
++ let mut writefds = writefds.into();
++ let mut errorfds = errorfds.into();
++ let sigmask = sigmask.into();
++ let timeout = timeout.into();
++
++ let nfds = nfds.into().unwrap_or_else(|| {
++ readfds.iter_mut()
++ .chain(writefds.iter_mut())
++ .chain(errorfds.iter_mut())
++ .map(|set| set.highest().unwrap_or(-1))
++ .max()
++ .unwrap_or(-1) + 1
++ });
++
++ let readfds = readfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
++ let writefds = writefds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
++ let errorfds = errorfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
++ let timeout = timeout.map(|ts| ts.as_ref() as *const libc::timespec).unwrap_or(null());
++ let sigmask = sigmask.map(|sm| sm.as_ref() as *const libc::sigset_t).unwrap_or(null());
++
++ let res = unsafe {
++ libc::pselect(nfds, readfds, writefds, errorfds, timeout, sigmask)
++ };
++
++ Errno::result(res)
++}
++
++
++#[cfg(test)]
++mod tests {
++ use super::*;
++ use std::os::unix::io::RawFd;
++ use sys::time::{TimeVal, TimeValLike};
++ use unistd::{write, pipe};
++
++ #[test]
++ fn fdset_insert() {
++ let mut fd_set = FdSet::new();
++
++ for i in 0..FD_SETSIZE {
++ assert!(!fd_set.contains(i as RawFd));
++ }
++
++ fd_set.insert(7);
++
++ assert!(fd_set.contains(7));
++ }
++
++ #[test]
++ fn fdset_remove() {
++ let mut fd_set = FdSet::new();
++
++ for i in 0..FD_SETSIZE {
++ assert!(!fd_set.contains(i as RawFd));
++ }
++
++ fd_set.insert(7);
++ fd_set.remove(7);
++
++ for i in 0..FD_SETSIZE {
++ assert!(!fd_set.contains(i as RawFd));
++ }
++ }
++
++ #[test]
++ fn fdset_clear() {
++ let mut fd_set = FdSet::new();
++ fd_set.insert(1);
++ fd_set.insert((FD_SETSIZE / 2) as RawFd);
++ fd_set.insert((FD_SETSIZE - 1) as RawFd);
++
++ fd_set.clear();
++
++ for i in 0..FD_SETSIZE {
++ assert!(!fd_set.contains(i as RawFd));
++ }
++ }
++
++ #[test]
++ fn fdset_highest() {
++ let mut set = FdSet::new();
++ assert_eq!(set.highest(), None);
++ set.insert(0);
++ assert_eq!(set.highest(), Some(0));
++ set.insert(90);
++ assert_eq!(set.highest(), Some(90));
++ set.remove(0);
++ assert_eq!(set.highest(), Some(90));
++ set.remove(90);
++ assert_eq!(set.highest(), None);
++
++ set.insert(4);
++ set.insert(5);
++ set.insert(7);
++ assert_eq!(set.highest(), Some(7));
++ }
++
++ #[test]
++ fn test_select() {
++ let (r1, w1) = pipe().unwrap();
++ write(w1, b"hi!").unwrap();
++ let (r2, _w2) = pipe().unwrap();
++
++ let mut fd_set = FdSet::new();
++ fd_set.insert(r1);
++ fd_set.insert(r2);
++
++ let mut timeout = TimeVal::seconds(10);
++ assert_eq!(1, select(None,
++ &mut fd_set,
++ None,
++ None,
++ &mut timeout).unwrap());
++ assert!(fd_set.contains(r1));
++ assert!(!fd_set.contains(r2));
++ }
++
++ #[test]
++ fn test_select_nfds() {
++ let (r1, w1) = pipe().unwrap();
++ write(w1, b"hi!").unwrap();
++ let (r2, _w2) = pipe().unwrap();
++
++ let mut fd_set = FdSet::new();
++ fd_set.insert(r1);
++ fd_set.insert(r2);
++
++ let mut timeout = TimeVal::seconds(10);
++ assert_eq!(1, select(Some(fd_set.highest().unwrap() + 1),
++ &mut fd_set,
++ None,
++ None,
++ &mut timeout).unwrap());
++ assert!(fd_set.contains(r1));
++ assert!(!fd_set.contains(r2));
++ }
++
++ #[test]
++ fn test_select_nfds2() {
++ let (r1, w1) = pipe().unwrap();
++ write(w1, b"hi!").unwrap();
++ let (r2, _w2) = pipe().unwrap();
++
++ let mut fd_set = FdSet::new();
++ fd_set.insert(r1);
++ fd_set.insert(r2);
++
++ let mut timeout = TimeVal::seconds(10);
++ assert_eq!(1, select(::std::cmp::max(r1, r2) + 1,
++ &mut fd_set,
++ None,
++ None,
++ &mut timeout).unwrap());
++ assert!(fd_set.contains(r1));
++ assert!(!fd_set.contains(r2));
++ }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/sendfile.rs b/third_party/rust/nix-0.15.0/src/sys/sendfile.rs
+new file mode 100644
+index 0000000000000..a47d8962f73fb
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/sendfile.rs
+@@ -0,0 +1,200 @@
++use std::os::unix::io::RawFd;
++use std::ptr;
++
++use libc::{self, off_t};
++
++use Result;
++use errno::Errno;
++
++/// Copy up to `count` bytes to `out_fd` from `in_fd` starting at `offset`.
++///
++/// Returns a `Result` with the number of bytes written.
++///
++/// If `offset` is `None`, `sendfile` will begin reading at the current offset of `in_fd`and will
++/// update the offset of `in_fd`. If `offset` is `Some`, `sendfile` will begin at the specified
++/// offset and will not update the offset of `in_fd`. Instead, it will mutate `offset` to point to
++/// the byte after the last byte copied.
++///
++/// `in_fd` must support `mmap`-like operations and therefore cannot be a socket.
++///
++/// For more information, see [the sendfile(2) man page.](http://man7.org/linux/man-pages/man2/sendfile.2.html)
++#[cfg(any(target_os = "android", target_os = "linux"))]
++pub fn sendfile(
++ out_fd: RawFd,
++ in_fd: RawFd,
++ offset: Option<&mut off_t>,
++ count: usize,
++) -> Result<usize> {
++ let offset = offset
++ .map(|offset| offset as *mut _)
++ .unwrap_or(ptr::null_mut());
++ let ret = unsafe { libc::sendfile(out_fd, in_fd, offset, count) };
++ Errno::result(ret).map(|r| r as usize)
++}
++
++cfg_if! {
++ if #[cfg(any(target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos"))] {
++ use sys::uio::IoVec;
++
++ #[derive(Clone, Debug, Eq, Hash, PartialEq)]
++ struct SendfileHeaderTrailer<'a>(
++ libc::sf_hdtr,
++ Option<Vec<IoVec<&'a [u8]>>>,
++ Option<Vec<IoVec<&'a [u8]>>>,
++ );
++
++ impl<'a> SendfileHeaderTrailer<'a> {
++ fn new(
++ headers: Option<&'a [&'a [u8]]>,
++ trailers: Option<&'a [&'a [u8]]>
++ ) -> SendfileHeaderTrailer<'a> {
++ let header_iovecs: Option<Vec<IoVec<&[u8]>>> =
++ headers.map(|s| s.iter().map(|b| IoVec::from_slice(b)).collect());
++ let trailer_iovecs: Option<Vec<IoVec<&[u8]>>> =
++ trailers.map(|s| s.iter().map(|b| IoVec::from_slice(b)).collect());
++ SendfileHeaderTrailer(
++ libc::sf_hdtr {
++ headers: {
++ header_iovecs
++ .as_ref()
++ .map_or(ptr::null(), |v| v.as_ptr()) as *mut libc::iovec
++ },
++ hdr_cnt: header_iovecs.as_ref().map(|v| v.len()).unwrap_or(0) as i32,
++ trailers: {
++ trailer_iovecs
++ .as_ref()
++ .map_or(ptr::null(), |v| v.as_ptr()) as *mut libc::iovec
++ },
++ trl_cnt: trailer_iovecs.as_ref().map(|v| v.len()).unwrap_or(0) as i32
++ },
++ header_iovecs,
++ trailer_iovecs,
++ )
++ }
++ }
++ }
++}
++
++cfg_if! {
++ if #[cfg(target_os = "freebsd")] {
++ use libc::c_int;
++
++ libc_bitflags!{
++ /// Configuration options for [`sendfile`.](fn.sendfile.html)
++ pub struct SfFlags: c_int {
++ /// Causes `sendfile` to return EBUSY instead of blocking when attempting to read a
++ /// busy page.
++ SF_NODISKIO;
++ /// Causes `sendfile` to sleep until the network stack releases its reference to the
++ /// VM pages read. When `sendfile` returns, the data is not guaranteed to have been
++ /// sent, but it is safe to modify the file.
++ SF_SYNC;
++ /// Causes `sendfile` to cache exactly the number of pages specified in the
++ /// `readahead` parameter, disabling caching heuristics.
++ SF_USER_READAHEAD;
++ /// Causes `sendfile` not to cache the data read.
++ SF_NOCACHE;
++ }
++ }
++
++ /// Read up to `count` bytes from `in_fd` starting at `offset` and write to `out_sock`.
++ ///
++ /// Returns a `Result` and a count of bytes written. Bytes written may be non-zero even if
++ /// an error occurs.
++ ///
++ /// `in_fd` must describe a regular file or shared memory object. `out_sock` must describe a
++ /// stream socket.
++ ///
++ /// If `offset` falls past the end of the file, the function returns success and zero bytes
++ /// written.
++ ///
++ /// If `count` is `None` or 0, bytes will be read from `in_fd` until reaching the end of
++ /// file (EOF).
++ ///
++ /// `headers` and `trailers` specify optional slices of byte slices to be sent before and
++ /// after the data read from `in_fd`, respectively. The length of headers and trailers sent
++ /// is included in the returned count of bytes written. The values of `offset` and `count`
++ /// do not apply to headers or trailers.
++ ///
++ /// `readahead` specifies the minimum number of pages to cache in memory ahead of the page
++ /// currently being sent.
++ ///
++ /// For more information, see
++ /// [the sendfile(2) man page.](https://www.freebsd.org/cgi/man.cgi?query=sendfile&sektion=2)
++ pub fn sendfile(
++ in_fd: RawFd,
++ out_sock: RawFd,
++ offset: off_t,
++ count: Option<usize>,
++ headers: Option<&[&[u8]]>,
++ trailers: Option<&[&[u8]]>,
++ flags: SfFlags,
++ readahead: u16
++ ) -> (Result<()>, off_t) {
++ // Readahead goes in upper 16 bits
++ // Flags goes in lower 16 bits
++ // see `man 2 sendfile`
++ let flags: u32 = ((readahead as u32) << 16) | (flags.bits() as u32);
++ let mut bytes_sent: off_t = 0;
++ let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers));
++ let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr);
++ let return_code = unsafe {
++ libc::sendfile(in_fd,
++ out_sock,
++ offset,
++ count.unwrap_or(0),
++ hdtr_ptr as *mut libc::sf_hdtr,
++ &mut bytes_sent as *mut off_t,
++ flags as c_int)
++ };
++ (Errno::result(return_code).and(Ok(())), bytes_sent)
++ }
++ } else if #[cfg(any(target_os = "ios", target_os = "macos"))] {
++ /// Read bytes from `in_fd` starting at `offset` and write up to `count` bytes to
++ /// `out_sock`.
++ ///
++ /// Returns a `Result` and a count of bytes written. Bytes written may be non-zero even if
++ /// an error occurs.
++ ///
++ /// `in_fd` must describe a regular file. `out_sock` must describe a stream socket.
++ ///
++ /// If `offset` falls past the end of the file, the function returns success and zero bytes
++ /// written.
++ ///
++ /// If `count` is `None` or 0, bytes will be read from `in_fd` until reaching the end of
++ /// file (EOF).
++ ///
++ /// `hdtr` specifies an optional list of headers and trailers to be sent before and after
++ /// the data read from `in_fd`, respectively. The length of headers and trailers sent is
++ /// included in the returned count of bytes written. If any headers are specified and
++ /// `count` is non-zero, the length of the headers will be counted in the limit of total
++ /// bytes sent. Trailers do not count toward the limit of bytes sent and will always be sent
++ /// regardless. The value of `offset` does not affect headers or trailers.
++ ///
++ /// For more information, see
++ /// [the sendfile(2) man page.](https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man2/sendfile.2.html)
++ pub fn sendfile(
++ in_fd: RawFd,
++ out_sock: RawFd,
++ offset: off_t,
++ count: Option<off_t>,
++ headers: Option<&[&[u8]]>,
++ trailers: Option<&[&[u8]]>
++ ) -> (Result<()>, off_t) {
++ let mut len = count.unwrap_or(0);
++ let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers));
++ let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr);
++ let return_code = unsafe {
++ libc::sendfile(in_fd,
++ out_sock,
++ offset,
++ &mut len as *mut off_t,
++ hdtr_ptr as *mut libc::sf_hdtr,
++ 0)
++ };
++ (Errno::result(return_code).and(Ok(())), len)
++ }
++ }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/signal.rs b/third_party/rust/nix-0.15.0/src/sys/signal.rs
+new file mode 100644
+index 0000000000000..1013a77fd4b40
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/signal.rs
+@@ -0,0 +1,966 @@
++// Portions of this file are Copyright 2014 The Rust Project Developers.
++// See http://rust-lang.org/COPYRIGHT.
++
++///! Operating system signals.
++
++use libc;
++use {Error, Result};
++use errno::Errno;
++use std::mem;
++use std::fmt;
++use std::str::FromStr;
++#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
++use std::os::unix::io::RawFd;
++use std::ptr;
++
++#[cfg(not(target_os = "openbsd"))]
++pub use self::sigevent::*;
++
++libc_enum!{
++ // Currently there is only one definition of c_int in libc, as well as only one
++ // type for signal constants.
++ // We would prefer to use the libc::c_int alias in the repr attribute. Unfortunately
++ // this is not (yet) possible.
++ #[repr(i32)]
++ pub enum Signal {
++ SIGHUP,
++ SIGINT,
++ SIGQUIT,
++ SIGILL,
++ SIGTRAP,
++ SIGABRT,
++ SIGBUS,
++ SIGFPE,
++ SIGKILL,
++ SIGUSR1,
++ SIGSEGV,
++ SIGUSR2,
++ SIGPIPE,
++ SIGALRM,
++ SIGTERM,
++ #[cfg(all(any(target_os = "android", target_os = "emscripten", target_os = "linux"),
++ not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
++ SIGSTKFLT,
++ SIGCHLD,
++ SIGCONT,
++ SIGSTOP,
++ SIGTSTP,
++ SIGTTIN,
++ SIGTTOU,
++ SIGURG,
++ SIGXCPU,
++ SIGXFSZ,
++ SIGVTALRM,
++ SIGPROF,
++ SIGWINCH,
++ SIGIO,
++ #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))]
++ SIGPWR,
++ SIGSYS,
++ #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
++ SIGEMT,
++ #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
++ SIGINFO,
++ }
++}
++
++impl FromStr for Signal {
++ type Err = Error;
++ fn from_str(s: &str) -> Result<Signal> {
++ Ok(match s {
++ "SIGHUP" => Signal::SIGHUP,
++ "SIGINT" => Signal::SIGINT,
++ "SIGQUIT" => Signal::SIGQUIT,
++ "SIGILL" => Signal::SIGILL,
++ "SIGTRAP" => Signal::SIGTRAP,
++ "SIGABRT" => Signal::SIGABRT,
++ "SIGBUS" => Signal::SIGBUS,
++ "SIGFPE" => Signal::SIGFPE,
++ "SIGKILL" => Signal::SIGKILL,
++ "SIGUSR1" => Signal::SIGUSR1,
++ "SIGSEGV" => Signal::SIGSEGV,
++ "SIGUSR2" => Signal::SIGUSR2,
++ "SIGPIPE" => Signal::SIGPIPE,
++ "SIGALRM" => Signal::SIGALRM,
++ "SIGTERM" => Signal::SIGTERM,
++ #[cfg(all(any(target_os = "android", target_os = "emscripten", target_os = "linux"),
++ not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
++ "SIGSTKFLT" => Signal::SIGSTKFLT,
++ "SIGCHLD" => Signal::SIGCHLD,
++ "SIGCONT" => Signal::SIGCONT,
++ "SIGSTOP" => Signal::SIGSTOP,
++ "SIGTSTP" => Signal::SIGTSTP,
++ "SIGTTIN" => Signal::SIGTTIN,
++ "SIGTTOU" => Signal::SIGTTOU,
++ "SIGURG" => Signal::SIGURG,
++ "SIGXCPU" => Signal::SIGXCPU,
++ "SIGXFSZ" => Signal::SIGXFSZ,
++ "SIGVTALRM" => Signal::SIGVTALRM,
++ "SIGPROF" => Signal::SIGPROF,
++ "SIGWINCH" => Signal::SIGWINCH,
++ "SIGIO" => Signal::SIGIO,
++ #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))]
++ "SIGPWR" => Signal::SIGPWR,
++ "SIGSYS" => Signal::SIGSYS,
++ #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
++ "SIGEMT" => Signal::SIGEMT,
++ #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
++ "SIGINFO" => Signal::SIGINFO,
++ _ => return Err(Error::invalid_argument()),
++ })
++ }
++}
++
++impl AsRef<str> for Signal {
++ fn as_ref(&self) -> &str {
++ match *self {
++ Signal::SIGHUP => "SIGHUP",
++ Signal::SIGINT => "SIGINT",
++ Signal::SIGQUIT => "SIGQUIT",
++ Signal::SIGILL => "SIGILL",
++ Signal::SIGTRAP => "SIGTRAP",
++ Signal::SIGABRT => "SIGABRT",
++ Signal::SIGBUS => "SIGBUS",
++ Signal::SIGFPE => "SIGFPE",
++ Signal::SIGKILL => "SIGKILL",
++ Signal::SIGUSR1 => "SIGUSR1",
++ Signal::SIGSEGV => "SIGSEGV",
++ Signal::SIGUSR2 => "SIGUSR2",
++ Signal::SIGPIPE => "SIGPIPE",
++ Signal::SIGALRM => "SIGALRM",
++ Signal::SIGTERM => "SIGTERM",
++ #[cfg(all(any(target_os = "android", target_os = "emscripten", target_os = "linux"),
++ not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
++ Signal::SIGSTKFLT => "SIGSTKFLT",
++ Signal::SIGCHLD => "SIGCHLD",
++ Signal::SIGCONT => "SIGCONT",
++ Signal::SIGSTOP => "SIGSTOP",
++ Signal::SIGTSTP => "SIGTSTP",
++ Signal::SIGTTIN => "SIGTTIN",
++ Signal::SIGTTOU => "SIGTTOU",
++ Signal::SIGURG => "SIGURG",
++ Signal::SIGXCPU => "SIGXCPU",
++ Signal::SIGXFSZ => "SIGXFSZ",
++ Signal::SIGVTALRM => "SIGVTALRM",
++ Signal::SIGPROF => "SIGPROF",
++ Signal::SIGWINCH => "SIGWINCH",
++ Signal::SIGIO => "SIGIO",
++ #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))]
++ Signal::SIGPWR => "SIGPWR",
++ Signal::SIGSYS => "SIGSYS",
++ #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
++ Signal::SIGEMT => "SIGEMT",
++ #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
++ Signal::SIGINFO => "SIGINFO",
++ }
++ }
++}
++
++impl fmt::Display for Signal {
++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++ f.write_str(self.as_ref())
++ }
++}
++
++pub use self::Signal::*;
++
++#[cfg(all(any(target_os = "linux", target_os = "android", target_os = "emscripten"), not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
++const SIGNALS: [Signal; 31] = [
++ SIGHUP,
++ SIGINT,
++ SIGQUIT,
++ SIGILL,
++ SIGTRAP,
++ SIGABRT,
++ SIGBUS,
++ SIGFPE,
++ SIGKILL,
++ SIGUSR1,
++ SIGSEGV,
++ SIGUSR2,
++ SIGPIPE,
++ SIGALRM,
++ SIGTERM,
++ SIGSTKFLT,
++ SIGCHLD,
++ SIGCONT,
++ SIGSTOP,
++ SIGTSTP,
++ SIGTTIN,
++ SIGTTOU,
++ SIGURG,
++ SIGXCPU,
++ SIGXFSZ,
++ SIGVTALRM,
++ SIGPROF,
++ SIGWINCH,
++ SIGIO,
++ SIGPWR,
++ SIGSYS];
++#[cfg(all(any(target_os = "linux", target_os = "android", target_os = "emscripten"), any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64")))]
++const SIGNALS: [Signal; 30] = [
++ SIGHUP,
++ SIGINT,
++ SIGQUIT,
++ SIGILL,
++ SIGTRAP,
++ SIGABRT,
++ SIGBUS,
++ SIGFPE,
++ SIGKILL,
++ SIGUSR1,
++ SIGSEGV,
++ SIGUSR2,
++ SIGPIPE,
++ SIGALRM,
++ SIGTERM,
++ SIGCHLD,
++ SIGCONT,
++ SIGSTOP,
++ SIGTSTP,
++ SIGTTIN,
++ SIGTTOU,
++ SIGURG,
++ SIGXCPU,
++ SIGXFSZ,
++ SIGVTALRM,
++ SIGPROF,
++ SIGWINCH,
++ SIGIO,
++ SIGPWR,
++ SIGSYS];
++#[cfg(not(any(target_os = "linux", target_os = "android", target_os = "emscripten")))]
++const SIGNALS: [Signal; 31] = [
++ SIGHUP,
++ SIGINT,
++ SIGQUIT,
++ SIGILL,
++ SIGTRAP,
++ SIGABRT,
++ SIGBUS,
++ SIGFPE,
++ SIGKILL,
++ SIGUSR1,
++ SIGSEGV,
++ SIGUSR2,
++ SIGPIPE,
++ SIGALRM,
++ SIGTERM,
++ SIGCHLD,
++ SIGCONT,
++ SIGSTOP,
++ SIGTSTP,
++ SIGTTIN,
++ SIGTTOU,
++ SIGURG,
++ SIGXCPU,
++ SIGXFSZ,
++ SIGVTALRM,
++ SIGPROF,
++ SIGWINCH,
++ SIGIO,
++ SIGSYS,
++ SIGEMT,
++ SIGINFO];
++
++pub const NSIG: libc::c_int = 32;
++
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub struct SignalIterator {
++ next: usize,
++}
++
++impl Iterator for SignalIterator {
++ type Item = Signal;
++
++ fn next(&mut self) -> Option<Signal> {
++ if self.next < SIGNALS.len() {
++ let next_signal = SIGNALS[self.next];
++ self.next += 1;
++ Some(next_signal)
++ } else {
++ None
++ }
++ }
++}
++
++impl Signal {
++ pub fn iterator() -> SignalIterator {
++ SignalIterator{next: 0}
++ }
++
++ // We do not implement the From trait, because it is supposed to be infallible.
++ // With Rust RFC 1542 comes the appropriate trait TryFrom. Once it is
++ // implemented, we'll replace this function.
++ #[inline]
++ pub fn from_c_int(signum: libc::c_int) -> Result<Signal> {
++ if 0 < signum && signum < NSIG {
++ Ok(unsafe { mem::transmute(signum) })
++ } else {
++ Err(Error::invalid_argument())
++ }
++ }
++}
++
++pub const SIGIOT : Signal = SIGABRT;
++pub const SIGPOLL : Signal = SIGIO;
++pub const SIGUNUSED : Signal = SIGSYS;
++
++libc_bitflags!{
++ pub struct SaFlags: libc::c_int {
++ SA_NOCLDSTOP;
++ SA_NOCLDWAIT;
++ SA_NODEFER;
++ SA_ONSTACK;
++ SA_RESETHAND;
++ SA_RESTART;
++ SA_SIGINFO;
++ }
++}
++
++libc_enum! {
++ #[repr(i32)]
++ pub enum SigmaskHow {
++ SIG_BLOCK,
++ SIG_UNBLOCK,
++ SIG_SETMASK,
++ }
++}
++
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub struct SigSet {
++ sigset: libc::sigset_t
++}
++
++
++impl SigSet {
++ pub fn all() -> SigSet {
++ let mut sigset: libc::sigset_t = unsafe { mem::uninitialized() };
++ let _ = unsafe { libc::sigfillset(&mut sigset as *mut libc::sigset_t) };
++
++ SigSet { sigset: sigset }
++ }
++
++ pub fn empty() -> SigSet {
++ let mut sigset: libc::sigset_t = unsafe { mem::uninitialized() };
++ let _ = unsafe { libc::sigemptyset(&mut sigset as *mut libc::sigset_t) };
++
++ SigSet { sigset: sigset }
++ }
++
++ pub fn add(&mut self, signal: Signal) {
++ unsafe { libc::sigaddset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) };
++ }
++
++ pub fn clear(&mut self) {
++ unsafe { libc::sigemptyset(&mut self.sigset as *mut libc::sigset_t) };
++ }
++
++ pub fn remove(&mut self, signal: Signal) {
++ unsafe { libc::sigdelset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) };
++ }
++
++ pub fn contains(&self, signal: Signal) -> bool {
++ let res = unsafe { libc::sigismember(&self.sigset as *const libc::sigset_t, signal as libc::c_int) };
++
++ match res {
++ 1 => true,
++ 0 => false,
++ _ => unreachable!("unexpected value from sigismember"),
++ }
++ }
++
++ pub fn extend(&mut self, other: &SigSet) {
++ for signal in Signal::iterator() {
++ if other.contains(signal) {
++ self.add(signal);
++ }
++ }
++ }
++
++ /// Gets the currently blocked (masked) set of signals for the calling thread.
++ pub fn thread_get_mask() -> Result<SigSet> {
++ let mut oldmask: SigSet = unsafe { mem::uninitialized() };
++ pthread_sigmask(SigmaskHow::SIG_SETMASK, None, Some(&mut oldmask))?;
++ Ok(oldmask)
++ }
++
++ /// Sets the set of signals as the signal mask for the calling thread.
++ pub fn thread_set_mask(&self) -> Result<()> {
++ pthread_sigmask(SigmaskHow::SIG_SETMASK, Some(self), None)
++ }
++
++ /// Adds the set of signals to the signal mask for the calling thread.
++ pub fn thread_block(&self) -> Result<()> {
++ pthread_sigmask(SigmaskHow::SIG_BLOCK, Some(self), None)
++ }
++
++ /// Removes the set of signals from the signal mask for the calling thread.
++ pub fn thread_unblock(&self) -> Result<()> {
++ pthread_sigmask(SigmaskHow::SIG_UNBLOCK, Some(self), None)
++ }
++
++ /// Sets the set of signals as the signal mask, and returns the old mask.
++ pub fn thread_swap_mask(&self, how: SigmaskHow) -> Result<SigSet> {
++ let mut oldmask: SigSet = unsafe { mem::uninitialized() };
++ pthread_sigmask(how, Some(self), Some(&mut oldmask))?;
++ Ok(oldmask)
++ }
++
++ /// Suspends execution of the calling thread until one of the signals in the
++ /// signal mask becomes pending, and returns the accepted signal.
++ pub fn wait(&self) -> Result<Signal> {
++ let mut signum: libc::c_int = unsafe { mem::uninitialized() };
++ let res = unsafe { libc::sigwait(&self.sigset as *const libc::sigset_t, &mut signum) };
++
++ Errno::result(res).map(|_| Signal::from_c_int(signum).unwrap())
++ }
++}
++
++impl AsRef<libc::sigset_t> for SigSet {
++ fn as_ref(&self) -> &libc::sigset_t {
++ &self.sigset
++ }
++}
++
++/// A signal handler.
++#[allow(unknown_lints)]
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub enum SigHandler {
++ /// Default signal handling.
++ SigDfl,
++ /// Request that the signal be ignored.
++ SigIgn,
++ /// Use the given signal-catching function, which takes in the signal.
++ Handler(extern fn(libc::c_int)),
++ /// Use the given signal-catching function, which takes in the signal, information about how
++ /// the signal was generated, and a pointer to the threads `ucontext_t`.
++ SigAction(extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void))
++}
++
++/// Action to take on receipt of a signal. Corresponds to `sigaction`.
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub struct SigAction {
++ sigaction: libc::sigaction
++}
++
++impl SigAction {
++ /// Creates a new action.
++ ///
++ /// The `SA_SIGINFO` bit in the `flags` argument is ignored (it will be set only if `handler`
++ /// is the `SigAction` variant). `mask` specifies other signals to block during execution of
++ /// the signal-catching function.
++ pub fn new(handler: SigHandler, flags: SaFlags, mask: SigSet) -> SigAction {
++ let mut s = unsafe { mem::uninitialized::<libc::sigaction>() };
++ s.sa_sigaction = match handler {
++ SigHandler::SigDfl => libc::SIG_DFL,
++ SigHandler::SigIgn => libc::SIG_IGN,
++ SigHandler::Handler(f) => f as *const extern fn(libc::c_int) as usize,
++ SigHandler::SigAction(f) => f as *const extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void) as usize,
++ };
++ s.sa_flags = match handler {
++ SigHandler::SigAction(_) => (flags | SaFlags::SA_SIGINFO).bits(),
++ _ => (flags - SaFlags::SA_SIGINFO).bits(),
++ };
++ s.sa_mask = mask.sigset;
++
++ SigAction { sigaction: s }
++ }
++
++ /// Returns the flags set on the action.
++ pub fn flags(&self) -> SaFlags {
++ SaFlags::from_bits_truncate(self.sigaction.sa_flags)
++ }
++
++ /// Returns the set of signals that are blocked during execution of the action's
++ /// signal-catching function.
++ pub fn mask(&self) -> SigSet {
++ SigSet { sigset: self.sigaction.sa_mask }
++ }
++
++ /// Returns the action's handler.
++ pub fn handler(&self) -> SigHandler {
++ match self.sigaction.sa_sigaction {
++ libc::SIG_DFL => SigHandler::SigDfl,
++ libc::SIG_IGN => SigHandler::SigIgn,
++ f if self.flags().contains(SaFlags::SA_SIGINFO) =>
++ SigHandler::SigAction( unsafe { mem::transmute(f) } ),
++ f => SigHandler::Handler( unsafe { mem::transmute(f) } ),
++ }
++ }
++}
++
++/// Changes the action taken by a process on receipt of a specific signal.
++///
++/// `signal` can be any signal except `SIGKILL` or `SIGSTOP`. On success, it returns the previous
++/// action for the given signal. If `sigaction` fails, no new signal handler is installed.
++///
++/// # Safety
++///
++/// Signal handlers may be called at any point during execution, which limits what is safe to do in
++/// the body of the signal-catching function. Be certain to only make syscalls that are explicitly
++/// marked safe for signal handlers and only share global data using atomics.
++pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigAction> {
++ let mut oldact = mem::uninitialized::<libc::sigaction>();
++
++ let res =
++ libc::sigaction(signal as libc::c_int, &sigaction.sigaction as *const libc::sigaction, &mut oldact as *mut libc::sigaction);
++
++ Errno::result(res).map(|_| SigAction { sigaction: oldact })
++}
++
++/// Signal management (see [signal(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/signal.html))
++///
++/// Installs `handler` for the given `signal`, returning the previous signal
++/// handler. `signal` should only be used following another call to `signal` or
++/// if the current handler is the default. The return value of `signal` is
++/// undefined after setting the handler with [`sigaction`][SigActionFn].
++///
++/// # Safety
++///
++/// If the pointer to the previous signal handler is invalid, undefined
++/// behavior could be invoked when casting it back to a [`SigAction`][SigActionStruct].
++///
++/// # Examples
++///
++/// Ignore `SIGINT`:
++///
++/// ```no_run
++/// # use nix::sys::signal::{self, Signal, SigHandler};
++/// unsafe { signal::signal(Signal::SIGINT, SigHandler::SigIgn) }.unwrap();
++/// ```
++///
++/// Use a signal handler to set a flag variable:
++///
++/// ```no_run
++/// # #[macro_use] extern crate lazy_static;
++/// # extern crate libc;
++/// # extern crate nix;
++/// # use std::sync::atomic::{AtomicBool, Ordering};
++/// # use nix::sys::signal::{self, Signal, SigHandler};
++/// lazy_static! {
++/// static ref SIGNALED: AtomicBool = AtomicBool::new(false);
++/// }
++///
++/// extern fn handle_sigint(signal: libc::c_int) {
++/// let signal = Signal::from_c_int(signal).unwrap();
++/// SIGNALED.store(signal == Signal::SIGINT, Ordering::Relaxed);
++/// }
++///
++/// fn main() {
++/// let handler = SigHandler::Handler(handle_sigint);
++/// unsafe { signal::signal(Signal::SIGINT, handler) }.unwrap();
++/// }
++/// ```
++///
++/// # Errors
++///
++/// Returns [`Error::UnsupportedOperation`] if `handler` is
++/// [`SigAction`][SigActionStruct]. Use [`sigaction`][SigActionFn] instead.
++///
++/// `signal` also returns any error from `libc::signal`, such as when an attempt
++/// is made to catch a signal that cannot be caught or to ignore a signal that
++/// cannot be ignored.
++///
++/// [`Error::UnsupportedOperation`]: ../../enum.Error.html#variant.UnsupportedOperation
++/// [SigActionStruct]: struct.SigAction.html
++/// [sigactionFn]: fn.sigaction.html
++pub unsafe fn signal(signal: Signal, handler: SigHandler) -> Result<SigHandler> {
++ let signal = signal as libc::c_int;
++ let res = match handler {
++ SigHandler::SigDfl => libc::signal(signal, libc::SIG_DFL),
++ SigHandler::SigIgn => libc::signal(signal, libc::SIG_IGN),
++ SigHandler::Handler(handler) => libc::signal(signal, handler as libc::sighandler_t),
++ SigHandler::SigAction(_) => return Err(Error::UnsupportedOperation),
++ };
++ Errno::result(res).map(|oldhandler| {
++ match oldhandler {
++ libc::SIG_DFL => SigHandler::SigDfl,
++ libc::SIG_IGN => SigHandler::SigIgn,
++ f => SigHandler::Handler(mem::transmute(f)),
++ }
++ })
++}
++
++/// Manages the signal mask (set of blocked signals) for the calling thread.
++///
++/// If the `set` parameter is `Some(..)`, then the signal mask will be updated with the signal set.
++/// The `how` flag decides the type of update. If `set` is `None`, `how` will be ignored,
++/// and no modification will take place.
++///
++/// If the 'oldset' parameter is `Some(..)` then the current signal mask will be written into it.
++///
++/// If both `set` and `oldset` is `Some(..)`, the current signal mask will be written into oldset,
++/// and then it will be updated with `set`.
++///
++/// If both `set` and `oldset` is None, this function is a no-op.
++///
++/// For more information, visit the [`pthread_sigmask`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_sigmask.html),
++/// or [`sigprocmask`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html) man pages.
++pub fn pthread_sigmask(how: SigmaskHow,
++ set: Option<&SigSet>,
++ oldset: Option<&mut SigSet>) -> Result<()> {
++ if set.is_none() && oldset.is_none() {
++ return Ok(())
++ }
++
++ let res = unsafe {
++ // if set or oldset is None, pass in null pointers instead
++ libc::pthread_sigmask(how as libc::c_int,
++ set.map_or_else(ptr::null::<libc::sigset_t>,
++ |s| &s.sigset as *const libc::sigset_t),
++ oldset.map_or_else(ptr::null_mut::<libc::sigset_t>,
++ |os| &mut os.sigset as *mut libc::sigset_t))
++ };
++
++ Errno::result(res).map(drop)
++}
++
++/// Examine and change blocked signals.
++///
++/// For more informations see the [`sigprocmask` man
++/// pages](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html).
++pub fn sigprocmask(how: SigmaskHow, set: Option<&SigSet>, oldset: Option<&mut SigSet>) -> Result<()> {
++ if set.is_none() && oldset.is_none() {
++ return Ok(())
++ }
++
++ let res = unsafe {
++ // if set or oldset is None, pass in null pointers instead
++ libc::sigprocmask(how as libc::c_int,
++ set.map_or_else(ptr::null::<libc::sigset_t>,
++ |s| &s.sigset as *const libc::sigset_t),
++ oldset.map_or_else(ptr::null_mut::<libc::sigset_t>,
++ |os| &mut os.sigset as *mut libc::sigset_t))
++ };
++
++ Errno::result(res).map(drop)
++}
++
++pub fn kill<T: Into<Option<Signal>>>(pid: ::unistd::Pid, signal: T) -> Result<()> {
++ let res = unsafe { libc::kill(pid.into(),
++ match signal.into() {
++ Some(s) => s as libc::c_int,
++ None => 0,
++ }) };
++
++ Errno::result(res).map(drop)
++}
++
++/// Send a signal to a process group [(see
++/// killpg(3))](http://pubs.opengroup.org/onlinepubs/9699919799/functions/killpg.html).
++///
++/// If `pgrp` less then or equal 1, the behavior is platform-specific.
++/// If `signal` is `None`, `killpg` will only preform error checking and won't
++/// send any signal.
++pub fn killpg<T: Into<Option<Signal>>>(pgrp: ::unistd::Pid, signal: T) -> Result<()> {
++ let res = unsafe { libc::killpg(pgrp.into(),
++ match signal.into() {
++ Some(s) => s as libc::c_int,
++ None => 0,
++ }) };
++
++ Errno::result(res).map(drop)
++}
++
++pub fn raise(signal: Signal) -> Result<()> {
++ let res = unsafe { libc::raise(signal as libc::c_int) };
++
++ Errno::result(res).map(drop)
++}
++
++
++#[cfg(target_os = "freebsd")]
++pub type type_of_thread_id = libc::lwpid_t;
++#[cfg(target_os = "linux")]
++pub type type_of_thread_id = libc::pid_t;
++
++/// Used to request asynchronous notification of certain events, for example,
++/// with POSIX AIO, POSIX message queues, and POSIX timers.
++// sigval is actually a union of a int and a void*. But it's never really used
++// as a pointer, because neither libc nor the kernel ever dereference it. nix
++// therefore presents it as an intptr_t, which is how kevent uses it.
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub enum SigevNotify {
++ /// No notification will be delivered
++ SigevNone,
++ /// The signal given by `signal` will be delivered to the process. The
++ /// value in `si_value` will be present in the `si_value` field of the
++ /// `siginfo_t` structure of the queued signal.
++ SigevSignal { signal: Signal, si_value: libc::intptr_t },
++ // Note: SIGEV_THREAD is not implemented because libc::sigevent does not
++ // expose a way to set the union members needed by SIGEV_THREAD.
++ /// A new `kevent` is posted to the kqueue `kq`. The `kevent`'s `udata`
++ /// field will contain the value in `udata`.
++ #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
++ SigevKevent { kq: RawFd, udata: libc::intptr_t },
++ /// The signal `signal` is queued to the thread whose LWP ID is given in
++ /// `thread_id`. The value stored in `si_value` will be present in the
++ /// `si_value` of the `siginfo_t` structure of the queued signal.
++ #[cfg(any(target_os = "freebsd", target_os = "linux"))]
++ SigevThreadId { signal: Signal, thread_id: type_of_thread_id,
++ si_value: libc::intptr_t },
++}
++
++#[cfg(not(target_os = "openbsd"))]
++mod sigevent {
++ use libc;
++ use std::mem;
++ use std::ptr;
++ use super::SigevNotify;
++ #[cfg(any(target_os = "freebsd", target_os = "linux"))]
++ use super::type_of_thread_id;
++
++ /// Used to request asynchronous notification of the completion of certain
++ /// events, such as POSIX AIO and timers.
++ #[repr(C)]
++ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++ pub struct SigEvent {
++ sigevent: libc::sigevent
++ }
++
++ impl SigEvent {
++ /// **Note:** this constructor does not allow the user to set the
++ /// `sigev_notify_kevent_flags` field. That's considered ok because on FreeBSD
++ /// at least those flags don't do anything useful. That field is part of a
++ /// union that shares space with the more genuinely useful fields.
++ ///
++ /// **Note:** This constructor also doesn't allow the caller to set the
++ /// `sigev_notify_function` or `sigev_notify_attributes` fields, which are
++ /// required for `SIGEV_THREAD`. That's considered ok because on no operating
++ /// system is `SIGEV_THREAD` the most efficient way to deliver AIO
++ /// notification. FreeBSD and DragonFly BSD programs should prefer `SIGEV_KEVENT`.
++ /// Linux, Solaris, and portable programs should prefer `SIGEV_THREAD_ID` or
++ /// `SIGEV_SIGNAL`. That field is part of a union that shares space with the
++ /// more genuinely useful `sigev_notify_thread_id`
++ pub fn new(sigev_notify: SigevNotify) -> SigEvent {
++ let mut sev = unsafe { mem::zeroed::<libc::sigevent>()};
++ sev.sigev_notify = match sigev_notify {
++ SigevNotify::SigevNone => libc::SIGEV_NONE,
++ SigevNotify::SigevSignal{..} => libc::SIGEV_SIGNAL,
++ #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
++ SigevNotify::SigevKevent{..} => libc::SIGEV_KEVENT,
++ #[cfg(target_os = "freebsd")]
++ SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID,
++ #[cfg(all(target_os = "linux", target_env = "gnu", not(target_arch = "mips")))]
++ SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID,
++ #[cfg(any(all(target_os = "linux", target_env = "musl"), target_arch = "mips"))]
++ SigevNotify::SigevThreadId{..} => 4 // No SIGEV_THREAD_ID defined
++ };
++ sev.sigev_signo = match sigev_notify {
++ SigevNotify::SigevSignal{ signal, .. } => signal as libc::c_int,
++ #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
++ SigevNotify::SigevKevent{ kq, ..} => kq,
++ #[cfg(any(target_os = "linux", target_os = "freebsd"))]
++ SigevNotify::SigevThreadId{ signal, .. } => signal as libc::c_int,
++ _ => 0
++ };
++ sev.sigev_value.sival_ptr = match sigev_notify {
++ SigevNotify::SigevNone => ptr::null_mut::<libc::c_void>(),
++ SigevNotify::SigevSignal{ si_value, .. } => si_value as *mut libc::c_void,
++ #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
++ SigevNotify::SigevKevent{ udata, .. } => udata as *mut libc::c_void,
++ #[cfg(any(target_os = "freebsd", target_os = "linux"))]
++ SigevNotify::SigevThreadId{ si_value, .. } => si_value as *mut libc::c_void,
++ };
++ SigEvent::set_tid(&mut sev, &sigev_notify);
++ SigEvent{sigevent: sev}
++ }
++
++ #[cfg(any(target_os = "freebsd", target_os = "linux"))]
++ fn set_tid(sev: &mut libc::sigevent, sigev_notify: &SigevNotify) {
++ sev.sigev_notify_thread_id = match *sigev_notify {
++ SigevNotify::SigevThreadId { thread_id, .. } => thread_id,
++ _ => 0 as type_of_thread_id
++ };
++ }
++
++ #[cfg(not(any(target_os = "freebsd", target_os = "linux")))]
++ fn set_tid(_sev: &mut libc::sigevent, _sigev_notify: &SigevNotify) {
++ }
++
++ pub fn sigevent(&self) -> libc::sigevent {
++ self.sigevent
++ }
++ }
++
++ impl<'a> From<&'a libc::sigevent> for SigEvent {
++ fn from(sigevent: &libc::sigevent) -> Self {
++ SigEvent{ sigevent: *sigevent }
++ }
++ }
++}
++
++#[cfg(test)]
++mod tests {
++ use std::thread;
++ use super::*;
++
++ #[test]
++ fn test_contains() {
++ let mut mask = SigSet::empty();
++ mask.add(SIGUSR1);
++
++ assert!(mask.contains(SIGUSR1));
++ assert!(!mask.contains(SIGUSR2));
++
++ let all = SigSet::all();
++ assert!(all.contains(SIGUSR1));
++ assert!(all.contains(SIGUSR2));
++ }
++
++ #[test]
++ fn test_clear() {
++ let mut set = SigSet::all();
++ set.clear();
++ for signal in Signal::iterator() {
++ assert!(!set.contains(signal));
++ }
++ }
++
++ #[test]
++ fn test_from_str_round_trips() {
++ for signal in Signal::iterator() {
++ assert_eq!(signal.as_ref().parse::<Signal>().unwrap(), signal);
++ assert_eq!(signal.to_string().parse::<Signal>().unwrap(), signal);
++ }
++ }
++
++ #[test]
++ fn test_from_str_invalid_value() {
++ let errval = Err(Error::Sys(Errno::EINVAL));
++ assert_eq!("NOSIGNAL".parse::<Signal>(), errval);
++ assert_eq!("kill".parse::<Signal>(), errval);
++ assert_eq!("9".parse::<Signal>(), errval);
++ }
++
++ #[test]
++ fn test_extend() {
++ let mut one_signal = SigSet::empty();
++ one_signal.add(SIGUSR1);
++
++ let mut two_signals = SigSet::empty();
++ two_signals.add(SIGUSR2);
++ two_signals.extend(&one_signal);
++
++ assert!(two_signals.contains(SIGUSR1));
++ assert!(two_signals.contains(SIGUSR2));
++ }
++
++ #[test]
++ fn test_thread_signal_set_mask() {
++ thread::spawn(|| {
++ let prev_mask = SigSet::thread_get_mask()
++ .expect("Failed to get existing signal mask!");
++
++ let mut test_mask = prev_mask;
++ test_mask.add(SIGUSR1);
++
++ assert!(test_mask.thread_set_mask().is_ok());
++ let new_mask = SigSet::thread_get_mask()
++ .expect("Failed to get new mask!");
++
++ assert!(new_mask.contains(SIGUSR1));
++ assert!(!new_mask.contains(SIGUSR2));
++
++ prev_mask.thread_set_mask().expect("Failed to revert signal mask!");
++ }).join().unwrap();
++ }
++
++ #[test]
++ fn test_thread_signal_block() {
++ thread::spawn(|| {
++ let mut mask = SigSet::empty();
++ mask.add(SIGUSR1);
++
++ assert!(mask.thread_block().is_ok());
++
++ assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
++ }).join().unwrap();
++ }
++
++ #[test]
++ fn test_thread_signal_unblock() {
++ thread::spawn(|| {
++ let mut mask = SigSet::empty();
++ mask.add(SIGUSR1);
++
++ assert!(mask.thread_unblock().is_ok());
++
++ assert!(!SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
++ }).join().unwrap();
++ }
++
++ #[test]
++ fn test_thread_signal_swap() {
++ thread::spawn(|| {
++ let mut mask = SigSet::empty();
++ mask.add(SIGUSR1);
++ mask.thread_block().unwrap();
++
++ assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
++
++ let mut mask2 = SigSet::empty();
++ mask2.add(SIGUSR2);
++
++ let oldmask = mask2.thread_swap_mask(SigmaskHow::SIG_SETMASK)
++ .unwrap();
++
++ assert!(oldmask.contains(SIGUSR1));
++ assert!(!oldmask.contains(SIGUSR2));
++
++ assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR2));
++ }).join().unwrap();
++ }
++
++ #[test]
++ fn test_sigaction() {
++ use libc;
++ thread::spawn(|| {
++ extern fn test_sigaction_handler(_: libc::c_int) {}
++ extern fn test_sigaction_action(_: libc::c_int,
++ _: *mut libc::siginfo_t, _: *mut libc::c_void) {}
++
++ let handler_sig = SigHandler::Handler(test_sigaction_handler);
++
++ let flags = SaFlags::SA_ONSTACK | SaFlags::SA_RESTART |
++ SaFlags::SA_SIGINFO;
++
++ let mut mask = SigSet::empty();
++ mask.add(SIGUSR1);
++
++ let action_sig = SigAction::new(handler_sig, flags, mask);
++
++ assert_eq!(action_sig.flags(),
++ SaFlags::SA_ONSTACK | SaFlags::SA_RESTART);
++ assert_eq!(action_sig.handler(), handler_sig);
++
++ mask = action_sig.mask();
++ assert!(mask.contains(SIGUSR1));
++ assert!(!mask.contains(SIGUSR2));
++
++ let handler_act = SigHandler::SigAction(test_sigaction_action);
++ let action_act = SigAction::new(handler_act, flags, mask);
++ assert_eq!(action_act.handler(), handler_act);
++
++ let action_dfl = SigAction::new(SigHandler::SigDfl, flags, mask);
++ assert_eq!(action_dfl.handler(), SigHandler::SigDfl);
++
++ let action_ign = SigAction::new(SigHandler::SigIgn, flags, mask);
++ assert_eq!(action_ign.handler(), SigHandler::SigIgn);
++ }).join().unwrap();
++ }
++
++ #[test]
++ fn test_sigwait() {
++ thread::spawn(|| {
++ let mut mask = SigSet::empty();
++ mask.add(SIGUSR1);
++ mask.add(SIGUSR2);
++ mask.thread_block().unwrap();
++
++ raise(SIGUSR1).unwrap();
++ assert_eq!(mask.wait().unwrap(), SIGUSR1);
++ }).join().unwrap();
++ }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/signalfd.rs b/third_party/rust/nix-0.15.0/src/sys/signalfd.rs
+new file mode 100644
+index 0000000000000..5425a27be9e52
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/signalfd.rs
+@@ -0,0 +1,170 @@
++//! Interface for the `signalfd` syscall.
++//!
++//! # Signal discarding
++//! When a signal can't be delivered to a process (or thread), it will become a pending signal.
++//! Failure to deliver could happen if the signal is blocked by every thread in the process or if
++//! the signal handler is still handling a previous signal.
++//!
++//! If a signal is sent to a process (or thread) that already has a pending signal of the same
++//! type, it will be discarded. This means that if signals of the same type are received faster than
++//! they are processed, some of those signals will be dropped. Because of this limitation,
++//! `signalfd` in itself cannot be used for reliable communication between processes or threads.
++//!
++//! Once the signal is unblocked, or the signal handler is finished, and a signal is still pending
++//! (ie. not consumed from a signalfd) it will be delivered to the signal handler.
++//!
++//! Please note that signal discarding is not specific to `signalfd`, but also happens with regular
++//! signal handlers.
++use libc;
++use unistd;
++use {Error, Result};
++use errno::Errno;
++pub use sys::signal::{self, SigSet};
++pub use libc::signalfd_siginfo as siginfo;
++
++use std::os::unix::io::{RawFd, AsRawFd};
++use std::mem;
++
++
++libc_bitflags!{
++ pub struct SfdFlags: libc::c_int {
++ SFD_NONBLOCK;
++ SFD_CLOEXEC;
++ }
++}
++
++pub const SIGNALFD_NEW: RawFd = -1;
++pub const SIGNALFD_SIGINFO_SIZE: usize = 128;
++
++/// Creates a new file descriptor for reading signals.
++///
++/// **Important:** please read the module level documentation about signal discarding before using
++/// this function!
++///
++/// The `mask` parameter specifies the set of signals that can be accepted via this file descriptor.
++///
++/// A signal must be blocked on every thread in a process, otherwise it won't be visible from
++/// signalfd (the default handler will be invoked instead).
++///
++/// See [the signalfd man page for more information](http://man7.org/linux/man-pages/man2/signalfd.2.html)
++pub fn signalfd(fd: RawFd, mask: &SigSet, flags: SfdFlags) -> Result<RawFd> {
++ unsafe {
++ Errno::result(libc::signalfd(fd as libc::c_int, mask.as_ref(), flags.bits()))
++ }
++}
++
++/// A helper struct for creating, reading and closing a `signalfd` instance.
++///
++/// **Important:** please read the module level documentation about signal discarding before using
++/// this struct!
++///
++/// # Examples
++///
++/// ```
++/// # use nix::sys::signalfd::*;
++/// // Set the thread to block the SIGUSR1 signal, otherwise the default handler will be used
++/// let mut mask = SigSet::empty();
++/// mask.add(signal::SIGUSR1);
++/// mask.thread_block().unwrap();
++///
++/// // Signals are queued up on the file descriptor
++/// let mut sfd = SignalFd::with_flags(&mask, SfdFlags::SFD_NONBLOCK).unwrap();
++///
++/// match sfd.read_signal() {
++/// // we caught a signal
++/// Ok(Some(sig)) => (),
++/// // there were no signals waiting (only happens when the SFD_NONBLOCK flag is set,
++/// // otherwise the read_signal call blocks)
++/// Ok(None) => (),
++/// Err(err) => (), // some error happend
++/// }
++/// ```
++#[derive(Clone, Debug, Eq, Hash, PartialEq)]
++pub struct SignalFd(RawFd);
++
++impl SignalFd {
++ pub fn new(mask: &SigSet) -> Result<SignalFd> {
++ Self::with_flags(mask, SfdFlags::empty())
++ }
++
++ pub fn with_flags(mask: &SigSet, flags: SfdFlags) -> Result<SignalFd> {
++ let fd = signalfd(SIGNALFD_NEW, mask, flags)?;
++
++ Ok(SignalFd(fd))
++ }
++
++ pub fn set_mask(&mut self, mask: &SigSet) -> Result<()> {
++ signalfd(self.0, mask, SfdFlags::empty()).map(drop)
++ }
++
++ pub fn read_signal(&mut self) -> Result<Option<siginfo>> {
++ let mut buffer: [u8; SIGNALFD_SIGINFO_SIZE] = unsafe { mem::uninitialized() };
++
++ match unistd::read(self.0, &mut buffer) {
++ Ok(SIGNALFD_SIGINFO_SIZE) => Ok(Some(unsafe { mem::transmute(buffer) })),
++ Ok(_) => unreachable!("partial read on signalfd"),
++ Err(Error::Sys(Errno::EAGAIN)) => Ok(None),
++ Err(error) => Err(error)
++ }
++ }
++}
++
++impl Drop for SignalFd {
++ fn drop(&mut self) {
++ let _ = unistd::close(self.0);
++ }
++}
++
++impl AsRawFd for SignalFd {
++ fn as_raw_fd(&self) -> RawFd {
++ self.0
++ }
++}
++
++impl Iterator for SignalFd {
++ type Item = siginfo;
++
++ fn next(&mut self) -> Option<Self::Item> {
++ match self.read_signal() {
++ Ok(Some(sig)) => Some(sig),
++ Ok(None) | Err(_) => None,
++ }
++ }
++}
++
++
++#[cfg(test)]
++mod tests {
++ use super::*;
++ use std::mem;
++ use libc;
++
++
++ #[test]
++ fn check_siginfo_size() {
++ assert_eq!(mem::size_of::<libc::signalfd_siginfo>(), SIGNALFD_SIGINFO_SIZE);
++ }
++
++ #[test]
++ fn create_signalfd() {
++ let mask = SigSet::empty();
++ let fd = SignalFd::new(&mask);
++ assert!(fd.is_ok());
++ }
++
++ #[test]
++ fn create_signalfd_with_opts() {
++ let mask = SigSet::empty();
++ let fd = SignalFd::with_flags(&mask, SfdFlags::SFD_CLOEXEC | SfdFlags::SFD_NONBLOCK);
++ assert!(fd.is_ok());
++ }
++
++ #[test]
++ fn read_empty_signalfd() {
++ let mask = SigSet::empty();
++ let mut fd = SignalFd::with_flags(&mask, SfdFlags::SFD_NONBLOCK).unwrap();
++
++ let res = fd.read_signal();
++ assert!(res.unwrap().is_none());
++ }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/socket/addr.rs b/third_party/rust/nix-0.15.0/src/sys/socket/addr.rs
+new file mode 100644
+index 0000000000000..ed41441155361
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/socket/addr.rs
+@@ -0,0 +1,1278 @@
++use super::sa_family_t;
++use {Error, Result, NixPath};
++use errno::Errno;
++use libc;
++use std::{fmt, mem, net, ptr, slice};
++use std::ffi::OsStr;
++use std::hash::{Hash, Hasher};
++use std::path::Path;
++use std::os::unix::ffi::OsStrExt;
++#[cfg(any(target_os = "android", target_os = "linux"))]
++use ::sys::socket::addr::netlink::NetlinkAddr;
++#[cfg(any(target_os = "android", target_os = "linux"))]
++use ::sys::socket::addr::alg::AlgAddr;
++#[cfg(any(target_os = "ios", target_os = "macos"))]
++use std::os::unix::io::RawFd;
++#[cfg(any(target_os = "ios", target_os = "macos"))]
++use ::sys::socket::addr::sys_control::SysControlAddr;
++#[cfg(any(target_os = "android",
++ target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++pub use self::datalink::LinkAddr;
++#[cfg(target_os = "linux")]
++pub use self::vsock::VsockAddr;
++
++/// These constants specify the protocol family to be used
++/// in [`socket`](fn.socket.html) and [`socketpair`](fn.socketpair.html)
++#[repr(i32)]
++#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
++pub enum AddressFamily {
++ /// Local communication (see [`unix(7)`](http://man7.org/linux/man-pages/man7/unix.7.html))
++ Unix = libc::AF_UNIX,
++ /// IPv4 Internet protocols (see [`ip(7)`](http://man7.org/linux/man-pages/man7/ip.7.html))
++ Inet = libc::AF_INET,
++ /// IPv6 Internet protocols (see [`ipv6(7)`](http://man7.org/linux/man-pages/man7/ipv6.7.html))
++ Inet6 = libc::AF_INET6,
++ /// Kernel user interface device (see [`netlink(7)`](http://man7.org/linux/man-pages/man7/netlink.7.html))
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ Netlink = libc::AF_NETLINK,
++ /// Low level packet interface (see [`packet(7)`](http://man7.org/linux/man-pages/man7/packet.7.html))
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ Packet = libc::AF_PACKET,
++ /// KEXT Controls and Notifications
++ #[cfg(any(target_os = "ios", target_os = "macos"))]
++ System = libc::AF_SYSTEM,
++ /// Amateur radio AX.25 protocol
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ Ax25 = libc::AF_AX25,
++ /// IPX - Novell protocols
++ Ipx = libc::AF_IPX,
++ /// AppleTalk
++ AppleTalk = libc::AF_APPLETALK,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ NetRom = libc::AF_NETROM,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ Bridge = libc::AF_BRIDGE,
++ /// Access to raw ATM PVCs
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ AtmPvc = libc::AF_ATMPVC,
++ /// ITU-T X.25 / ISO-8208 protocol (see [`x25(7)`](http://man7.org/linux/man-pages/man7/x25.7.html))
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ X25 = libc::AF_X25,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ Rose = libc::AF_ROSE,
++ Decnet = libc::AF_DECnet,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ NetBeui = libc::AF_NETBEUI,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ Security = libc::AF_SECURITY,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ Key = libc::AF_KEY,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ Ash = libc::AF_ASH,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ Econet = libc::AF_ECONET,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ AtmSvc = libc::AF_ATMSVC,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ Rds = libc::AF_RDS,
++ Sna = libc::AF_SNA,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ Irda = libc::AF_IRDA,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ Pppox = libc::AF_PPPOX,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ Wanpipe = libc::AF_WANPIPE,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ Llc = libc::AF_LLC,
++ #[cfg(target_os = "linux")]
++ Ib = libc::AF_IB,
++ #[cfg(target_os = "linux")]
++ Mpls = libc::AF_MPLS,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ Can = libc::AF_CAN,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ Tipc = libc::AF_TIPC,
++ #[cfg(not(any(target_os = "ios", target_os = "macos")))]
++ Bluetooth = libc::AF_BLUETOOTH,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ Iucv = libc::AF_IUCV,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ RxRpc = libc::AF_RXRPC,
++ Isdn = libc::AF_ISDN,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ Phonet = libc::AF_PHONET,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ Ieee802154 = libc::AF_IEEE802154,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ Caif = libc::AF_CAIF,
++ /// Interface to kernel crypto API
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ Alg = libc::AF_ALG,
++ #[cfg(target_os = "linux")]
++ Nfc = libc::AF_NFC,
++ #[cfg(target_os = "linux")]
++ Vsock = libc::AF_VSOCK,
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ ImpLink = libc::AF_IMPLINK,
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ Pup = libc::AF_PUP,
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ Chaos = libc::AF_CHAOS,
++ #[cfg(any(target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ Ns = libc::AF_NS,
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ Iso = libc::AF_ISO,
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ Datakit = libc::AF_DATAKIT,
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ Ccitt = libc::AF_CCITT,
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ Dli = libc::AF_DLI,
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ Lat = libc::AF_LAT,
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ Hylink = libc::AF_HYLINK,
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ Link = libc::AF_LINK,
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ Coip = libc::AF_COIP,
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ Cnt = libc::AF_CNT,
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ Natm = libc::AF_NATM,
++ /// Unspecified address family, (see [`getaddrinfo(3)`](http://man7.org/linux/man-pages/man3/getaddrinfo.3.html))
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ Unspec = libc::AF_UNSPEC,
++}
++
++impl AddressFamily {
++ /// Create a new `AddressFamily` from an integer value retrieved from `libc`, usually from
++ /// the `sa_family` field of a `sockaddr`.
++ ///
++ /// Currently only supports these address families: Unix, Inet (v4 & v6), Netlink, Link/Packet
++ /// and System. Returns None for unsupported or unknown address families.
++ pub fn from_i32(family: i32) -> Option<AddressFamily> {
++ match family {
++ libc::AF_UNIX => Some(AddressFamily::Unix),
++ libc::AF_INET => Some(AddressFamily::Inet),
++ libc::AF_INET6 => Some(AddressFamily::Inet6),
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ libc::AF_NETLINK => Some(AddressFamily::Netlink),
++ #[cfg(any(target_os = "macos", target_os = "macos"))]
++ libc::AF_SYSTEM => Some(AddressFamily::System),
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ libc::AF_PACKET => Some(AddressFamily::Packet),
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ libc::AF_LINK => Some(AddressFamily::Link),
++ #[cfg(target_os = "linux")]
++ libc::AF_VSOCK => Some(AddressFamily::Vsock),
++ _ => None
++ }
++ }
++}
++
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub enum InetAddr {
++ V4(libc::sockaddr_in),
++ V6(libc::sockaddr_in6),
++}
++
++impl InetAddr {
++ pub fn from_std(std: &net::SocketAddr) -> InetAddr {
++ match *std {
++ net::SocketAddr::V4(ref addr) => {
++ InetAddr::V4(libc::sockaddr_in {
++ sin_family: AddressFamily::Inet as sa_family_t,
++ sin_port: addr.port().to_be(), // network byte order
++ sin_addr: Ipv4Addr::from_std(addr.ip()).0,
++ .. unsafe { mem::zeroed() }
++ })
++ }
++ net::SocketAddr::V6(ref addr) => {
++ InetAddr::V6(libc::sockaddr_in6 {
++ sin6_family: AddressFamily::Inet6 as sa_family_t,
++ sin6_port: addr.port().to_be(), // network byte order
++ sin6_addr: Ipv6Addr::from_std(addr.ip()).0,
++ sin6_flowinfo: addr.flowinfo(), // host byte order
++ sin6_scope_id: addr.scope_id(), // host byte order
++ .. unsafe { mem::zeroed() }
++ })
++ }
++ }
++ }
++
++ pub fn new(ip: IpAddr, port: u16) -> InetAddr {
++ match ip {
++ IpAddr::V4(ref ip) => {
++ InetAddr::V4(libc::sockaddr_in {
++ sin_family: AddressFamily::Inet as sa_family_t,
++ sin_port: port.to_be(),
++ sin_addr: ip.0,
++ .. unsafe { mem::zeroed() }
++ })
++ }
++ IpAddr::V6(ref ip) => {
++ InetAddr::V6(libc::sockaddr_in6 {
++ sin6_family: AddressFamily::Inet6 as sa_family_t,
++ sin6_port: port.to_be(),
++ sin6_addr: ip.0,
++ .. unsafe { mem::zeroed() }
++ })
++ }
++ }
++ }
++ /// Gets the IP address associated with this socket address.
++ pub fn ip(&self) -> IpAddr {
++ match *self {
++ InetAddr::V4(ref sa) => IpAddr::V4(Ipv4Addr(sa.sin_addr)),
++ InetAddr::V6(ref sa) => IpAddr::V6(Ipv6Addr(sa.sin6_addr)),
++ }
++ }
++
++ /// Gets the port number associated with this socket address
++ pub fn port(&self) -> u16 {
++ match *self {
++ InetAddr::V6(ref sa) => u16::from_be(sa.sin6_port),
++ InetAddr::V4(ref sa) => u16::from_be(sa.sin_port),
++ }
++ }
++
++ pub fn to_std(&self) -> net::SocketAddr {
++ match *self {
++ InetAddr::V4(ref sa) => net::SocketAddr::V4(
++ net::SocketAddrV4::new(
++ Ipv4Addr(sa.sin_addr).to_std(),
++ self.port())),
++ InetAddr::V6(ref sa) => net::SocketAddr::V6(
++ net::SocketAddrV6::new(
++ Ipv6Addr(sa.sin6_addr).to_std(),
++ self.port(),
++ sa.sin6_flowinfo,
++ sa.sin6_scope_id)),
++ }
++ }
++
++ pub fn to_str(&self) -> String {
++ format!("{}", self)
++ }
++}
++
++impl fmt::Display for InetAddr {
++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++ match *self {
++ InetAddr::V4(_) => write!(f, "{}:{}", self.ip(), self.port()),
++ InetAddr::V6(_) => write!(f, "[{}]:{}", self.ip(), self.port()),
++ }
++ }
++}
++
++/*
++ *
++ * ===== IpAddr =====
++ *
++ */
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub enum IpAddr {
++ V4(Ipv4Addr),
++ V6(Ipv6Addr),
++}
++
++impl IpAddr {
++ /// Create a new IpAddr that contains an IPv4 address.
++ ///
++ /// The result will represent the IP address a.b.c.d
++ pub fn new_v4(a: u8, b: u8, c: u8, d: u8) -> IpAddr {
++ IpAddr::V4(Ipv4Addr::new(a, b, c, d))
++ }
++
++ /// Create a new IpAddr that contains an IPv6 address.
++ ///
++ /// The result will represent the IP address a:b:c:d:e:f
++ pub fn new_v6(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> IpAddr {
++ IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g, h))
++ }
++
++ pub fn from_std(std: &net::IpAddr) -> IpAddr {
++ match *std {
++ net::IpAddr::V4(ref std) => IpAddr::V4(Ipv4Addr::from_std(std)),
++ net::IpAddr::V6(ref std) => IpAddr::V6(Ipv6Addr::from_std(std)),
++ }
++ }
++
++ pub fn to_std(&self) -> net::IpAddr {
++ match *self {
++ IpAddr::V4(ref ip) => net::IpAddr::V4(ip.to_std()),
++ IpAddr::V6(ref ip) => net::IpAddr::V6(ip.to_std()),
++ }
++ }
++}
++
++impl fmt::Display for IpAddr {
++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++ match *self {
++ IpAddr::V4(ref v4) => v4.fmt(f),
++ IpAddr::V6(ref v6) => v6.fmt(f)
++ }
++ }
++}
++
++/*
++ *
++ * ===== Ipv4Addr =====
++ *
++ */
++
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub struct Ipv4Addr(pub libc::in_addr);
++
++impl Ipv4Addr {
++ pub fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr {
++ let ip = (((a as u32) << 24) |
++ ((b as u32) << 16) |
++ ((c as u32) << 8) |
++ ((d as u32) << 0)).to_be();
++
++ Ipv4Addr(libc::in_addr { s_addr: ip })
++ }
++
++ pub fn from_std(std: &net::Ipv4Addr) -> Ipv4Addr {
++ let bits = std.octets();
++ Ipv4Addr::new(bits[0], bits[1], bits[2], bits[3])
++ }
++
++ pub fn any() -> Ipv4Addr {
++ Ipv4Addr(libc::in_addr { s_addr: libc::INADDR_ANY })
++ }
++
++ pub fn octets(&self) -> [u8; 4] {
++ let bits = u32::from_be(self.0.s_addr);
++ [(bits >> 24) as u8, (bits >> 16) as u8, (bits >> 8) as u8, bits as u8]
++ }
++
++ pub fn to_std(&self) -> net::Ipv4Addr {
++ let bits = self.octets();
++ net::Ipv4Addr::new(bits[0], bits[1], bits[2], bits[3])
++ }
++}
++
++impl fmt::Display for Ipv4Addr {
++ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
++ let octets = self.octets();
++ write!(fmt, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3])
++ }
++}
++
++/*
++ *
++ * ===== Ipv6Addr =====
++ *
++ */
++
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub struct Ipv6Addr(pub libc::in6_addr);
++
++// Note that IPv6 addresses are stored in big endian order on all architectures.
++// See https://tools.ietf.org/html/rfc1700 or consult your favorite search
++// engine.
++
++macro_rules! to_u8_array {
++ ($($num:ident),*) => {
++ [ $(($num>>8) as u8, ($num&0xff) as u8,)* ]
++ }
++}
++
++macro_rules! to_u16_array {
++ ($slf:ident, $($first:expr, $second:expr),*) => {
++ [$( (($slf.0.s6_addr[$first] as u16) << 8) + $slf.0.s6_addr[$second] as u16,)*]
++ }
++}
++
++impl Ipv6Addr {
++ pub fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr {
++ let mut in6_addr_var: libc::in6_addr = unsafe{mem::uninitialized()};
++ in6_addr_var.s6_addr = to_u8_array!(a,b,c,d,e,f,g,h);
++ Ipv6Addr(in6_addr_var)
++ }
++
++ pub fn from_std(std: &net::Ipv6Addr) -> Ipv6Addr {
++ let s = std.segments();
++ Ipv6Addr::new(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7])
++ }
++
++ /// Return the eight 16-bit segments that make up this address
++ pub fn segments(&self) -> [u16; 8] {
++ to_u16_array!(self, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15)
++ }
++
++ pub fn to_std(&self) -> net::Ipv6Addr {
++ let s = self.segments();
++ net::Ipv6Addr::new(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7])
++ }
++}
++
++impl fmt::Display for Ipv6Addr {
++ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
++ self.to_std().fmt(fmt)
++ }
++}
++
++/// A wrapper around `sockaddr_un`.
++///
++/// This also tracks the length of `sun_path` address (excluding
++/// a terminating null), because it may not be null-terminated. For example,
++/// unconnected and Linux abstract sockets are never null-terminated, and POSIX
++/// does not require that `sun_len` include the terminating null even for normal
++/// sockets. Note that the actual sockaddr length is greater by
++/// `offset_of!(libc::sockaddr_un, sun_path)`
++#[derive(Clone, Copy, Debug)]
++pub struct UnixAddr(pub libc::sockaddr_un, pub usize);
++
++impl UnixAddr {
++ /// Create a new sockaddr_un representing a filesystem path.
++ pub fn new<P: ?Sized + NixPath>(path: &P) -> Result<UnixAddr> {
++ path.with_nix_path(|cstr| {
++ unsafe {
++ let mut ret = libc::sockaddr_un {
++ sun_family: AddressFamily::Unix as sa_family_t,
++ .. mem::zeroed()
++ };
++
++ let bytes = cstr.to_bytes();
++
++ if bytes.len() > ret.sun_path.len() {
++ return Err(Error::Sys(Errno::ENAMETOOLONG));
++ }
++
++ ptr::copy_nonoverlapping(bytes.as_ptr(),
++ ret.sun_path.as_mut_ptr() as *mut u8,
++ bytes.len());
++
++ Ok(UnixAddr(ret, bytes.len()))
++ }
++ })?
++ }
++
++ /// Create a new `sockaddr_un` representing an address in the "abstract namespace".
++ ///
++ /// The leading null byte for the abstract namespace is automatically added;
++ /// thus the input `path` is expected to be the bare name, not null-prefixed.
++ /// This is a Linux-specific extension, primarily used to allow chrooted
++ /// processes to communicate with processes having a different filesystem view.
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ pub fn new_abstract(path: &[u8]) -> Result<UnixAddr> {
++ unsafe {
++ let mut ret = libc::sockaddr_un {
++ sun_family: AddressFamily::Unix as sa_family_t,
++ .. mem::zeroed()
++ };
++
++ if path.len() + 1 > ret.sun_path.len() {
++ return Err(Error::Sys(Errno::ENAMETOOLONG));
++ }
++
++ // Abstract addresses are represented by sun_path[0] ==
++ // b'\0', so copy starting one byte in.
++ ptr::copy_nonoverlapping(path.as_ptr(),
++ ret.sun_path.as_mut_ptr().offset(1) as *mut u8,
++ path.len());
++
++ Ok(UnixAddr(ret, ret.sun_path.len()))
++ }
++ }
++
++ fn sun_path(&self) -> &[u8] {
++ unsafe { slice::from_raw_parts(self.0.sun_path.as_ptr() as *const u8, self.1) }
++ }
++
++ /// If this address represents a filesystem path, return that path.
++ pub fn path(&self) -> Option<&Path> {
++ if self.1 == 0 || self.0.sun_path[0] == 0 {
++ // unnamed or abstract
++ None
++ } else {
++ let p = self.sun_path();
++ // POSIX only requires that `sun_len` be at least long enough to
++ // contain the pathname, and it need not be null-terminated. So we
++ // need to create a string that is the shorter of the
++ // null-terminated length or the full length.
++ let ptr = &self.0.sun_path as *const libc::c_char;
++ let reallen = unsafe { libc::strnlen(ptr, p.len()) };
++ Some(Path::new(<OsStr as OsStrExt>::from_bytes(&p[..reallen])))
++ }
++ }
++
++ /// If this address represents an abstract socket, return its name.
++ ///
++ /// For abstract sockets only the bare name is returned, without the
++ /// leading null byte. `None` is returned for unnamed or path-backed sockets.
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ pub fn as_abstract(&self) -> Option<&[u8]> {
++ if self.1 >= 1 && self.0.sun_path[0] == 0 {
++ Some(&self.sun_path()[1..])
++ } else {
++ // unnamed or filesystem path
++ None
++ }
++ }
++}
++
++impl fmt::Display for UnixAddr {
++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++ if self.1 == 0 {
++ f.write_str("<unbound UNIX socket>")
++ } else if let Some(path) = self.path() {
++ path.display().fmt(f)
++ } else {
++ let display = String::from_utf8_lossy(&self.sun_path()[1..]);
++ write!(f, "@{}", display)
++ }
++ }
++}
++
++impl PartialEq for UnixAddr {
++ fn eq(&self, other: &UnixAddr) -> bool {
++ self.sun_path() == other.sun_path()
++ }
++}
++
++impl Eq for UnixAddr {}
++
++impl Hash for UnixAddr {
++ fn hash<H: Hasher>(&self, s: &mut H) {
++ ( self.0.sun_family, self.sun_path() ).hash(s)
++ }
++}
++
++/// Represents a socket address
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub enum SockAddr {
++ Inet(InetAddr),
++ Unix(UnixAddr),
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ Netlink(NetlinkAddr),
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ Alg(AlgAddr),
++ #[cfg(any(target_os = "ios", target_os = "macos"))]
++ SysControl(SysControlAddr),
++ /// Datalink address (MAC)
++ #[cfg(any(target_os = "android",
++ target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ Link(LinkAddr),
++ #[cfg(target_os = "linux")]
++ Vsock(VsockAddr),
++}
++
++impl SockAddr {
++ pub fn new_inet(addr: InetAddr) -> SockAddr {
++ SockAddr::Inet(addr)
++ }
++
++ pub fn new_unix<P: ?Sized + NixPath>(path: &P) -> Result<SockAddr> {
++ Ok(SockAddr::Unix(UnixAddr::new(path)?))
++ }
++
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ pub fn new_netlink(pid: u32, groups: u32) -> SockAddr {
++ SockAddr::Netlink(NetlinkAddr::new(pid, groups))
++ }
++
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ pub fn new_alg(alg_type: &str, alg_name: &str) -> SockAddr {
++ SockAddr::Alg(AlgAddr::new(alg_type, alg_name))
++ }
++
++ #[cfg(any(target_os = "ios", target_os = "macos"))]
++ pub fn new_sys_control(sockfd: RawFd, name: &str, unit: u32) -> Result<SockAddr> {
++ SysControlAddr::from_name(sockfd, name, unit).map(|a| SockAddr::SysControl(a))
++ }
++
++ #[cfg(target_os = "linux")]
++ pub fn new_vsock(cid: u32, port: u32) -> SockAddr {
++ SockAddr::Vsock(VsockAddr::new(cid, port))
++ }
++
++ pub fn family(&self) -> AddressFamily {
++ match *self {
++ SockAddr::Inet(InetAddr::V4(..)) => AddressFamily::Inet,
++ SockAddr::Inet(InetAddr::V6(..)) => AddressFamily::Inet6,
++ SockAddr::Unix(..) => AddressFamily::Unix,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ SockAddr::Netlink(..) => AddressFamily::Netlink,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ SockAddr::Alg(..) => AddressFamily::Alg,
++ #[cfg(any(target_os = "ios", target_os = "macos"))]
++ SockAddr::SysControl(..) => AddressFamily::System,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ SockAddr::Link(..) => AddressFamily::Packet,
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ SockAddr::Link(..) => AddressFamily::Link,
++ #[cfg(target_os = "linux")]
++ SockAddr::Vsock(..) => AddressFamily::Vsock,
++ }
++ }
++
++ pub fn to_str(&self) -> String {
++ format!("{}", self)
++ }
++
++ /// Creates a `SockAddr` struct from libc's sockaddr.
++ ///
++ /// Supports only the following address families: Unix, Inet (v4 & v6), Netlink and System.
++ /// Returns None for unsupported families.
++ pub unsafe fn from_libc_sockaddr(addr: *const libc::sockaddr) -> Option<SockAddr> {
++ if addr.is_null() {
++ None
++ } else {
++ match AddressFamily::from_i32((*addr).sa_family as i32) {
++ Some(AddressFamily::Unix) => None,
++ Some(AddressFamily::Inet) => Some(SockAddr::Inet(
++ InetAddr::V4(*(addr as *const libc::sockaddr_in)))),
++ Some(AddressFamily::Inet6) => Some(SockAddr::Inet(
++ InetAddr::V6(*(addr as *const libc::sockaddr_in6)))),
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ Some(AddressFamily::Netlink) => Some(SockAddr::Netlink(
++ NetlinkAddr(*(addr as *const libc::sockaddr_nl)))),
++ #[cfg(any(target_os = "ios", target_os = "macos"))]
++ Some(AddressFamily::System) => Some(SockAddr::SysControl(
++ SysControlAddr(*(addr as *const libc::sockaddr_ctl)))),
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ Some(AddressFamily::Packet) => Some(SockAddr::Link(
++ LinkAddr(*(addr as *const libc::sockaddr_ll)))),
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ Some(AddressFamily::Link) => {
++ let ether_addr = LinkAddr(*(addr as *const libc::sockaddr_dl));
++ if ether_addr.is_empty() {
++ None
++ } else {
++ Some(SockAddr::Link(ether_addr))
++ }
++ },
++ #[cfg(target_os = "linux")]
++ Some(AddressFamily::Vsock) => Some(SockAddr::Vsock(
++ VsockAddr(*(addr as *const libc::sockaddr_vm)))),
++ // Other address families are currently not supported and simply yield a None
++ // entry instead of a proper conversion to a `SockAddr`.
++ Some(_) | None => None,
++ }
++ }
++ }
++
++ /// Conversion from nix's SockAddr type to the underlying libc sockaddr type.
++ ///
++ /// This is useful for interfacing with other libc functions that don't yet have nix wrappers.
++ /// Returns a reference to the underlying data type (as a sockaddr reference) along
++ /// with the size of the actual data type. sockaddr is commonly used as a proxy for
++ /// a superclass as C doesn't support inheritance, so many functions that take
++ /// a sockaddr * need to take the size of the underlying type as well and then internally cast it back.
++ pub unsafe fn as_ffi_pair(&self) -> (&libc::sockaddr, libc::socklen_t) {
++ match *self {
++ SockAddr::Inet(InetAddr::V4(ref addr)) => (mem::transmute(addr), mem::size_of::<libc::sockaddr_in>() as libc::socklen_t),
++ SockAddr::Inet(InetAddr::V6(ref addr)) => (mem::transmute(addr), mem::size_of::<libc::sockaddr_in6>() as libc::socklen_t),
++ SockAddr::Unix(UnixAddr(ref addr, len)) => (mem::transmute(addr), (len + offset_of!(libc::sockaddr_un, sun_path)) as libc::socklen_t),
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ SockAddr::Netlink(NetlinkAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<libc::sockaddr_nl>() as libc::socklen_t),
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ SockAddr::Alg(AlgAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<libc::sockaddr_alg>() as libc::socklen_t),
++ #[cfg(any(target_os = "ios", target_os = "macos"))]
++ SockAddr::SysControl(SysControlAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<libc::sockaddr_ctl>() as libc::socklen_t),
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ SockAddr::Link(LinkAddr(ref ether_addr)) => (mem::transmute(ether_addr), mem::size_of::<libc::sockaddr_ll>() as libc::socklen_t),
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ SockAddr::Link(LinkAddr(ref ether_addr)) => (mem::transmute(ether_addr), mem::size_of::<libc::sockaddr_dl>() as libc::socklen_t),
++ #[cfg(target_os = "linux")]
++ SockAddr::Vsock(VsockAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<libc::sockaddr_vm>() as libc::socklen_t),
++ }
++ }
++}
++
++impl fmt::Display for SockAddr {
++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++ match *self {
++ SockAddr::Inet(ref inet) => inet.fmt(f),
++ SockAddr::Unix(ref unix) => unix.fmt(f),
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ SockAddr::Netlink(ref nl) => nl.fmt(f),
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ SockAddr::Alg(ref nl) => nl.fmt(f),
++ #[cfg(any(target_os = "ios", target_os = "macos"))]
++ SockAddr::SysControl(ref sc) => sc.fmt(f),
++ #[cfg(any(target_os = "android",
++ target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ SockAddr::Link(ref ether_addr) => ether_addr.fmt(f),
++ #[cfg(target_os = "linux")]
++ SockAddr::Vsock(ref svm) => svm.fmt(f),
++ }
++ }
++}
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++pub mod netlink {
++ use ::sys::socket::addr::AddressFamily;
++ use libc::{sa_family_t, sockaddr_nl};
++ use std::{fmt, mem};
++
++ #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
++ pub struct NetlinkAddr(pub sockaddr_nl);
++
++ impl NetlinkAddr {
++ pub fn new(pid: u32, groups: u32) -> NetlinkAddr {
++ let mut addr: sockaddr_nl = unsafe { mem::zeroed() };
++ addr.nl_family = AddressFamily::Netlink as sa_family_t;
++ addr.nl_pid = pid;
++ addr.nl_groups = groups;
++
++ NetlinkAddr(addr)
++ }
++
++ pub fn pid(&self) -> u32 {
++ self.0.nl_pid
++ }
++
++ pub fn groups(&self) -> u32 {
++ self.0.nl_groups
++ }
++ }
++
++ impl fmt::Display for NetlinkAddr {
++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++ write!(f, "pid: {} groups: {}", self.pid(), self.groups())
++ }
++ }
++}
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++pub mod alg {
++ use libc::{AF_ALG, sockaddr_alg, c_char};
++ use std::{fmt, mem, str};
++ use std::hash::{Hash, Hasher};
++ use std::ffi::CStr;
++
++ #[derive(Copy, Clone)]
++ pub struct AlgAddr(pub sockaddr_alg);
++
++ // , PartialEq, Eq, Debug, Hash
++ impl PartialEq for AlgAddr {
++ fn eq(&self, other: &Self) -> bool {
++ let (inner, other) = (self.0, other.0);
++ (inner.salg_family, &inner.salg_type[..], inner.salg_feat, inner.salg_mask, &inner.salg_name[..]) ==
++ (other.salg_family, &other.salg_type[..], other.salg_feat, other.salg_mask, &other.salg_name[..])
++ }
++ }
++
++ impl Eq for AlgAddr {}
++
++ impl Hash for AlgAddr {
++ fn hash<H: Hasher>(&self, s: &mut H) {
++ let inner = self.0;
++ (inner.salg_family, &inner.salg_type[..], inner.salg_feat, inner.salg_mask, &inner.salg_name[..]).hash(s);
++ }
++ }
++
++ impl AlgAddr {
++ pub fn new(alg_type: &str, alg_name: &str) -> AlgAddr {
++ let mut addr: sockaddr_alg = unsafe { mem::zeroed() };
++ addr.salg_family = AF_ALG as u16;
++ addr.salg_type[..alg_type.len()].copy_from_slice(alg_type.to_string().as_bytes());
++ addr.salg_name[..alg_name.len()].copy_from_slice(alg_name.to_string().as_bytes());
++
++ AlgAddr(addr)
++ }
++
++
++ pub fn alg_type(&self) -> &CStr {
++ unsafe { CStr::from_ptr(self.0.salg_type.as_ptr() as *const c_char) }
++ }
++
++ pub fn alg_name(&self) -> &CStr {
++ unsafe { CStr::from_ptr(self.0.salg_name.as_ptr() as *const c_char) }
++ }
++ }
++
++ impl fmt::Display for AlgAddr {
++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++ write!(f, "type: {} alg: {}",
++ self.alg_name().to_string_lossy(),
++ self.alg_type().to_string_lossy())
++ }
++ }
++
++ impl fmt::Debug for AlgAddr {
++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++ fmt::Display::fmt(self, f)
++ }
++ }
++}
++
++#[cfg(any(target_os = "ios", target_os = "macos"))]
++pub mod sys_control {
++ use ::sys::socket::addr::AddressFamily;
++ use libc::{self, c_uchar};
++ use std::{fmt, mem};
++ use std::os::unix::io::RawFd;
++ use {Errno, Error, Result};
++
++ // FIXME: Move type into `libc`
++ #[repr(C)]
++ #[derive(Clone, Copy)]
++ #[allow(missing_debug_implementations)]
++ pub struct ctl_ioc_info {
++ pub ctl_id: u32,
++ pub ctl_name: [c_uchar; MAX_KCTL_NAME],
++ }
++
++ const CTL_IOC_MAGIC: u8 = 'N' as u8;
++ const CTL_IOC_INFO: u8 = 3;
++ const MAX_KCTL_NAME: usize = 96;
++
++ ioctl_readwrite!(ctl_info, CTL_IOC_MAGIC, CTL_IOC_INFO, ctl_ioc_info);
++
++ #[repr(C)]
++ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++ pub struct SysControlAddr(pub libc::sockaddr_ctl);
++
++ impl SysControlAddr {
++ pub fn new(id: u32, unit: u32) -> SysControlAddr {
++ let addr = libc::sockaddr_ctl {
++ sc_len: mem::size_of::<libc::sockaddr_ctl>() as c_uchar,
++ sc_family: AddressFamily::System as c_uchar,
++ ss_sysaddr: libc::AF_SYS_CONTROL as u16,
++ sc_id: id,
++ sc_unit: unit,
++ sc_reserved: [0; 5]
++ };
++
++ SysControlAddr(addr)
++ }
++
++ pub fn from_name(sockfd: RawFd, name: &str, unit: u32) -> Result<SysControlAddr> {
++ if name.len() > MAX_KCTL_NAME {
++ return Err(Error::Sys(Errno::ENAMETOOLONG));
++ }
++
++ let mut ctl_name = [0; MAX_KCTL_NAME];
++ ctl_name[..name.len()].clone_from_slice(name.as_bytes());
++ let mut info = ctl_ioc_info { ctl_id: 0, ctl_name: ctl_name };
++
++ unsafe { ctl_info(sockfd, &mut info)?; }
++
++ Ok(SysControlAddr::new(info.ctl_id, unit))
++ }
++
++ pub fn id(&self) -> u32 {
++ self.0.sc_id
++ }
++
++ pub fn unit(&self) -> u32 {
++ self.0.sc_unit
++ }
++ }
++
++ impl fmt::Display for SysControlAddr {
++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++ fmt::Debug::fmt(self, f)
++ }
++ }
++}
++
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++mod datalink {
++ use super::{libc, fmt, AddressFamily};
++
++ /// Hardware Address
++ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++ pub struct LinkAddr(pub libc::sockaddr_ll);
++
++ impl LinkAddr {
++ /// Always AF_PACKET
++ pub fn family(&self) -> AddressFamily {
++ assert_eq!(self.0.sll_family as i32, libc::AF_PACKET);
++ AddressFamily::Packet
++ }
++
++ /// Physical-layer protocol
++ pub fn protocol(&self) -> u16 {
++ self.0.sll_protocol
++ }
++
++ /// Interface number
++ pub fn ifindex(&self) -> usize {
++ self.0.sll_ifindex as usize
++ }
++
++ /// ARP hardware type
++ pub fn hatype(&self) -> u16 {
++ self.0.sll_hatype
++ }
++
++ /// Packet type
++ pub fn pkttype(&self) -> u8 {
++ self.0.sll_pkttype
++ }
++
++ /// Length of MAC address
++ pub fn halen(&self) -> usize {
++ self.0.sll_halen as usize
++ }
++
++ /// Physical-layer address (MAC)
++ pub fn addr(&self) -> [u8; 6] {
++ let a = self.0.sll_addr[0] as u8;
++ let b = self.0.sll_addr[1] as u8;
++ let c = self.0.sll_addr[2] as u8;
++ let d = self.0.sll_addr[3] as u8;
++ let e = self.0.sll_addr[4] as u8;
++ let f = self.0.sll_addr[5] as u8;
++
++ [a, b, c, d, e, f]
++ }
++ }
++
++ impl fmt::Display for LinkAddr {
++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++ let addr = self.addr();
++ write!(f, "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
++ addr[0],
++ addr[1],
++ addr[2],
++ addr[3],
++ addr[4],
++ addr[5])
++ }
++ }
++}
++
++#[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++mod datalink {
++ use super::{libc, fmt, AddressFamily};
++
++ /// Hardware Address
++ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++ pub struct LinkAddr(pub libc::sockaddr_dl);
++
++ impl LinkAddr {
++ /// Total length of sockaddr
++ pub fn len(&self) -> usize {
++ self.0.sdl_len as usize
++ }
++
++ /// always == AF_LINK
++ pub fn family(&self) -> AddressFamily {
++ assert_eq!(self.0.sdl_family as i32, libc::AF_LINK);
++ AddressFamily::Link
++ }
++
++ /// interface index, if != 0, system given index for interface
++ pub fn ifindex(&self) -> usize {
++ self.0.sdl_index as usize
++ }
++
++ /// Datalink type
++ pub fn datalink_type(&self) -> u8 {
++ self.0.sdl_type
++ }
++
++ // MAC address start position
++ pub fn nlen(&self) -> usize {
++ self.0.sdl_nlen as usize
++ }
++
++ /// link level address length
++ pub fn alen(&self) -> usize {
++ self.0.sdl_alen as usize
++ }
++
++ /// link layer selector length
++ pub fn slen(&self) -> usize {
++ self.0.sdl_slen as usize
++ }
++
++ /// if link level address length == 0,
++ /// or `sdl_data` not be larger.
++ pub fn is_empty(&self) -> bool {
++ let nlen = self.nlen();
++ let alen = self.alen();
++ let data_len = self.0.sdl_data.len();
++
++ if alen > 0 && nlen + alen < data_len {
++ false
++ } else {
++ true
++ }
++ }
++
++ /// Physical-layer address (MAC)
++ pub fn addr(&self) -> [u8; 6] {
++ let nlen = self.nlen();
++ let data = self.0.sdl_data;
++
++ assert!(!self.is_empty());
++
++ let a = data[nlen] as u8;
++ let b = data[nlen + 1] as u8;
++ let c = data[nlen + 2] as u8;
++ let d = data[nlen + 3] as u8;
++ let e = data[nlen + 4] as u8;
++ let f = data[nlen + 5] as u8;
++
++ [a, b, c, d, e, f]
++ }
++ }
++
++ impl fmt::Display for LinkAddr {
++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++ let addr = self.addr();
++ write!(f, "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
++ addr[0],
++ addr[1],
++ addr[2],
++ addr[3],
++ addr[4],
++ addr[5])
++ }
++ }
++}
++
++#[cfg(target_os = "linux")]
++pub mod vsock {
++ use ::sys::socket::addr::AddressFamily;
++ use libc::{sa_family_t, sockaddr_vm};
++ use std::{fmt, mem};
++ use std::hash::{Hash, Hasher};
++
++ #[derive(Copy, Clone)]
++ pub struct VsockAddr(pub sockaddr_vm);
++
++ impl PartialEq for VsockAddr {
++ fn eq(&self, other: &Self) -> bool {
++ let (inner, other) = (self.0, other.0);
++ (inner.svm_family, inner.svm_cid, inner.svm_port) ==
++ (other.svm_family, other.svm_cid, other.svm_port)
++ }
++ }
++
++ impl Eq for VsockAddr {}
++
++ impl Hash for VsockAddr {
++ fn hash<H: Hasher>(&self, s: &mut H) {
++ let inner = self.0;
++ (inner.svm_family, inner.svm_cid, inner.svm_port).hash(s);
++ }
++ }
++
++ /// VSOCK Address
++ ///
++ /// The address for AF_VSOCK socket is defined as a combination of a
++ /// 32-bit Context Identifier (CID) and a 32-bit port number.
++ impl VsockAddr {
++ pub fn new(cid: u32, port: u32) -> VsockAddr {
++ let mut addr: sockaddr_vm = unsafe { mem::zeroed() };
++ addr.svm_family = AddressFamily::Vsock as sa_family_t;
++ addr.svm_cid = cid;
++ addr.svm_port = port;
++
++ VsockAddr(addr)
++ }
++
++ /// Context Identifier (CID)
++ pub fn cid(&self) -> u32 {
++ self.0.svm_cid
++ }
++
++ /// Port number
++ pub fn port(&self) -> u32 {
++ self.0.svm_port
++ }
++ }
++
++ impl fmt::Display for VsockAddr {
++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++ write!(f, "cid: {} port: {}", self.cid(), self.port())
++ }
++ }
++
++ impl fmt::Debug for VsockAddr {
++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++ fmt::Display::fmt(self, f)
++ }
++ }
++}
++
++#[cfg(test)]
++mod tests {
++ #[cfg(any(target_os = "android",
++ target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ use super::*;
++
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ #[test]
++ fn test_macos_loopback_datalink_addr() {
++ let bytes = [20i8, 18, 1, 0, 24, 3, 0, 0, 108, 111, 48, 0, 0, 0, 0, 0];
++ let sa = bytes.as_ptr() as *const libc::sockaddr;
++ let _sock_addr = unsafe { SockAddr::from_libc_sockaddr(sa) };
++ assert!(_sock_addr.is_none());
++ }
++
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ #[test]
++ fn test_macos_tap_datalink_addr() {
++ let bytes = [20i8, 18, 7, 0, 6, 3, 6, 0, 101, 110, 48, 24, 101, -112, -35, 76, -80];
++ let ptr = bytes.as_ptr();
++ let sa = ptr as *const libc::sockaddr;
++ let _sock_addr = unsafe { SockAddr::from_libc_sockaddr(sa) };
++
++ assert!(_sock_addr.is_some());
++
++ let sock_addr = _sock_addr.unwrap();
++
++ assert_eq!(sock_addr.family(), AddressFamily::Link);
++
++ match sock_addr {
++ SockAddr::Link(ether_addr) => {
++ assert_eq!(ether_addr.addr(), [24u8, 101, 144, 221, 76, 176]);
++ },
++ _ => { unreachable!() }
++ };
++ }
++
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ #[test]
++ fn test_abstract_sun_path() {
++ let name = String::from("nix\0abstract\0test");
++ let addr = UnixAddr::new_abstract(name.as_bytes()).unwrap();
++
++ let sun_path1 = addr.sun_path();
++ let sun_path2 = [0u8, 110, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, 116, 101, 115, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
++ assert_eq!(sun_path1.len(), sun_path2.len());
++ for i in 0..sun_path1.len() {
++ assert_eq!(sun_path1[i], sun_path2[i]);
++ }
++ }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/socket/mod.rs b/third_party/rust/nix-0.15.0/src/sys/socket/mod.rs
+new file mode 100644
+index 0000000000000..1c12c5f851734
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/socket/mod.rs
+@@ -0,0 +1,1294 @@
++//! Socket interface functions
++//!
++//! [Further reading](http://man7.org/linux/man-pages/man7/socket.7.html)
++use {Error, Result};
++use errno::Errno;
++use libc::{self, c_void, c_int, iovec, socklen_t, size_t,
++ CMSG_FIRSTHDR, CMSG_NXTHDR, CMSG_DATA, CMSG_LEN};
++use std::{mem, ptr, slice};
++use std::os::unix::io::RawFd;
++use sys::time::TimeVal;
++use sys::uio::IoVec;
++
++mod addr;
++pub mod sockopt;
++
++/*
++ *
++ * ===== Re-exports =====
++ *
++ */
++
++pub use self::addr::{
++ AddressFamily,
++ SockAddr,
++ InetAddr,
++ UnixAddr,
++ IpAddr,
++ Ipv4Addr,
++ Ipv6Addr,
++ LinkAddr,
++};
++#[cfg(any(target_os = "android", target_os = "linux"))]
++pub use ::sys::socket::addr::netlink::NetlinkAddr;
++#[cfg(any(target_os = "android", target_os = "linux"))]
++pub use sys::socket::addr::alg::AlgAddr;
++#[cfg(target_os = "linux")]
++pub use sys::socket::addr::vsock::VsockAddr;
++
++pub use libc::{
++ cmsghdr,
++ msghdr,
++ sa_family_t,
++ sockaddr,
++ sockaddr_in,
++ sockaddr_in6,
++ sockaddr_storage,
++ sockaddr_un,
++};
++
++// Needed by the cmsg_space macro
++#[doc(hidden)]
++pub use libc::{c_uint, CMSG_SPACE};
++
++/// These constants are used to specify the communication semantics
++/// when creating a socket with [`socket()`](fn.socket.html)
++#[derive(Clone, Copy, PartialEq, Eq, Debug)]
++#[repr(i32)]
++pub enum SockType {
++ /// Provides sequenced, reliable, two-way, connection-
++ /// based byte streams. An out-of-band data transmission
++ /// mechanism may be supported.
++ Stream = libc::SOCK_STREAM,
++ /// Supports datagrams (connectionless, unreliable
++ /// messages of a fixed maximum length).
++ Datagram = libc::SOCK_DGRAM,
++ /// Provides a sequenced, reliable, two-way connection-
++ /// based data transmission path for datagrams of fixed
++ /// maximum length; a consumer is required to read an
++ /// entire packet with each input system call.
++ SeqPacket = libc::SOCK_SEQPACKET,
++ /// Provides raw network protocol access.
++ Raw = libc::SOCK_RAW,
++ /// Provides a reliable datagram layer that does not
++ /// guarantee ordering.
++ Rdm = libc::SOCK_RDM,
++}
++
++/// Constants used in [`socket`](fn.socket.html) and [`socketpair`](fn.socketpair.html)
++/// to specify the protocol to use.
++#[repr(i32)]
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub enum SockProtocol {
++ /// TCP protocol ([ip(7)](http://man7.org/linux/man-pages/man7/ip.7.html))
++ Tcp = libc::IPPROTO_TCP,
++ /// UDP protocol ([ip(7)](http://man7.org/linux/man-pages/man7/ip.7.html))
++ Udp = libc::IPPROTO_UDP,
++ /// Allows applications and other KEXTs to be notified when certain kernel events occur
++ /// ([ref](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/control/control.html))
++ #[cfg(any(target_os = "ios", target_os = "macos"))]
++ KextEvent = libc::SYSPROTO_EVENT,
++ /// Allows applications to configure and control a KEXT
++ /// ([ref](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/control/control.html))
++ #[cfg(any(target_os = "ios", target_os = "macos"))]
++ KextControl = libc::SYSPROTO_CONTROL,
++}
++
++libc_bitflags!{
++ /// Additional socket options
++ pub struct SockFlag: c_int {
++ /// Set non-blocking mode on the new socket
++ #[cfg(any(target_os = "android",
++ target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "linux",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ SOCK_NONBLOCK;
++ /// Set close-on-exec on the new descriptor
++ #[cfg(any(target_os = "android",
++ target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "linux",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ SOCK_CLOEXEC;
++ /// Return `EPIPE` instead of raising `SIGPIPE`
++ #[cfg(target_os = "netbsd")]
++ SOCK_NOSIGPIPE;
++ /// For domains `AF_INET(6)`, only allow `connect(2)`, `sendto(2)`, or `sendmsg(2)`
++ /// to the DNS port (typically 53)
++ #[cfg(target_os = "openbsd")]
++ SOCK_DNS;
++ }
++}
++
++libc_bitflags!{
++ /// Flags for send/recv and their relatives
++ pub struct MsgFlags: c_int {
++ /// Sends or requests out-of-band data on sockets that support this notion
++ /// (e.g., of type [`Stream`](enum.SockType.html)); the underlying protocol must also
++ /// support out-of-band data.
++ MSG_OOB;
++ /// Peeks at an incoming message. The data is treated as unread and the next
++ /// [`recv()`](fn.recv.html)
++ /// or similar function shall still return this data.
++ MSG_PEEK;
++ /// Receive operation blocks until the full amount of data can be
++ /// returned. The function may return smaller amount of data if a signal
++ /// is caught, an error or disconnect occurs.
++ MSG_WAITALL;
++ /// Enables nonblocking operation; if the operation would block,
++ /// `EAGAIN` or `EWOULDBLOCK` is returned. This provides similar
++ /// behavior to setting the `O_NONBLOCK` flag
++ /// (via the [`fcntl`](../../fcntl/fn.fcntl.html)
++ /// `F_SETFL` operation), but differs in that `MSG_DONTWAIT` is a per-
++ /// call option, whereas `O_NONBLOCK` is a setting on the open file
++ /// description (see [open(2)](http://man7.org/linux/man-pages/man2/open.2.html)),
++ /// which will affect all threads in
++ /// the calling process and as well as other processes that hold
++ /// file descriptors referring to the same open file description.
++ MSG_DONTWAIT;
++ /// Receive flags: Control Data was discarded (buffer too small)
++ MSG_CTRUNC;
++ /// For raw ([`Packet`](addr/enum.AddressFamily.html)), Internet datagram
++ /// (since Linux 2.4.27/2.6.8),
++ /// netlink (since Linux 2.6.22) and UNIX datagram (since Linux 3.4)
++ /// sockets: return the real length of the packet or datagram, even
++ /// when it was longer than the passed buffer. Not implemented for UNIX
++ /// domain ([unix(7)](https://linux.die.net/man/7/unix)) sockets.
++ ///
++ /// For use with Internet stream sockets, see [tcp(7)](https://linux.die.net/man/7/tcp).
++ MSG_TRUNC;
++ /// Terminates a record (when this notion is supported, as for
++ /// sockets of type [`SeqPacket`](enum.SockType.html)).
++ MSG_EOR;
++ /// This flag specifies that queued errors should be received from
++ /// the socket error queue. (For more details, see
++ /// [recvfrom(2)](https://linux.die.net/man/2/recvfrom))
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ MSG_ERRQUEUE;
++ /// Set the `close-on-exec` flag for the file descriptor received via a UNIX domain
++ /// file descriptor using the `SCM_RIGHTS` operation (described in
++ /// [unix(7)](https://linux.die.net/man/7/unix)).
++ /// This flag is useful for the same reasons as the `O_CLOEXEC` flag of
++ /// [open(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html).
++ ///
++ /// Only used in [`recvmsg`](fn.recvmsg.html) function.
++ #[cfg(any(target_os = "android",
++ target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "linux",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ MSG_CMSG_CLOEXEC;
++ }
++}
++
++cfg_if! {
++ if #[cfg(any(target_os = "android", target_os = "linux"))] {
++ /// Unix credentials of the sending process.
++ ///
++ /// This struct is used with the `SO_PEERCRED` ancillary message for UNIX sockets.
++ #[repr(C)]
++ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
++ pub struct UnixCredentials(libc::ucred);
++
++ impl UnixCredentials {
++ /// Returns the process identifier
++ pub fn pid(&self) -> libc::pid_t {
++ self.0.pid
++ }
++
++ /// Returns the user identifier
++ pub fn uid(&self) -> libc::uid_t {
++ self.0.uid
++ }
++
++ /// Returns the group identifier
++ pub fn gid(&self) -> libc::gid_t {
++ self.0.gid
++ }
++ }
++
++ impl From<libc::ucred> for UnixCredentials {
++ fn from(cred: libc::ucred) -> Self {
++ UnixCredentials(cred)
++ }
++ }
++
++ impl Into<libc::ucred> for UnixCredentials {
++ fn into(self) -> libc::ucred {
++ self.0
++ }
++ }
++ }
++}
++
++/// Request for multicast socket operations
++///
++/// This is a wrapper type around `ip_mreq`.
++#[repr(C)]
++#[derive(Clone, Copy, Debug, Eq, PartialEq)]
++pub struct IpMembershipRequest(libc::ip_mreq);
++
++impl IpMembershipRequest {
++ /// Instantiate a new `IpMembershipRequest`
++ ///
++ /// If `interface` is `None`, then `Ipv4Addr::any()` will be used for the interface.
++ pub fn new(group: Ipv4Addr, interface: Option<Ipv4Addr>) -> Self {
++ IpMembershipRequest(libc::ip_mreq {
++ imr_multiaddr: group.0,
++ imr_interface: interface.unwrap_or_else(Ipv4Addr::any).0,
++ })
++ }
++}
++
++/// Request for ipv6 multicast socket operations
++///
++/// This is a wrapper type around `ipv6_mreq`.
++#[repr(C)]
++#[derive(Clone, Copy, Debug, Eq, PartialEq)]
++pub struct Ipv6MembershipRequest(libc::ipv6_mreq);
++
++impl Ipv6MembershipRequest {
++ /// Instantiate a new `Ipv6MembershipRequest`
++ pub fn new(group: Ipv6Addr) -> Self {
++ Ipv6MembershipRequest(libc::ipv6_mreq {
++ ipv6mr_multiaddr: group.0,
++ ipv6mr_interface: 0,
++ })
++ }
++}
++
++cfg_if! {
++ // Darwin and DragonFly BSD always align struct cmsghdr to 32-bit only.
++ if #[cfg(any(target_os = "dragonfly", target_os = "ios", target_os = "macos"))] {
++ type align_of_cmsg_data = u32;
++ } else {
++ type align_of_cmsg_data = size_t;
++ }
++}
++
++/// A type that can be used to store ancillary data received by
++/// [`recvmsg`](fn.recvmsg.html)
++pub trait CmsgBuffer {
++ fn as_bytes_mut(&mut self) -> &mut [u8];
++}
++
++/// Create a buffer large enough for storing some control messages as returned
++/// by [`recvmsg`](fn.recvmsg.html).
++///
++/// # Examples
++///
++/// ```
++/// # #[macro_use] extern crate nix;
++/// # use nix::sys::time::TimeVal;
++/// # use std::os::unix::io::RawFd;
++/// # fn main() {
++/// // Create a buffer for a `ControlMessageOwned::ScmTimestamp` message
++/// let _ = cmsg_space!(TimeVal);
++/// // Create a buffer big enough for a `ControlMessageOwned::ScmRights` message
++/// // with two file descriptors
++/// let _ = cmsg_space!([RawFd; 2]);
++/// // Create a buffer big enough for a `ControlMessageOwned::ScmRights` message
++/// // and a `ControlMessageOwned::ScmTimestamp` message
++/// let _ = cmsg_space!(RawFd, TimeVal);
++/// # }
++/// ```
++// Unfortunately, CMSG_SPACE isn't a const_fn, or else we could return a
++// stack-allocated array.
++#[macro_export]
++macro_rules! cmsg_space {
++ ( $( $x:ty ),* ) => {
++ {
++ use nix::sys::socket::{c_uint, CMSG_SPACE};
++ use std::mem;
++ let mut space = 0;
++ $(
++ // CMSG_SPACE is always safe
++ space += unsafe {
++ CMSG_SPACE(mem::size_of::<$x>() as c_uint)
++ } as usize;
++ )*
++ let mut v = Vec::<u8>::with_capacity(space);
++ // safe because any bit pattern is a valid u8
++ unsafe {v.set_len(space)};
++ v
++ }
++ }
++}
++
++/// A structure used to make room in a cmsghdr passed to recvmsg. The
++/// size and alignment match that of a cmsghdr followed by a T, but the
++/// fields are not accessible, as the actual types will change on a call
++/// to recvmsg.
++///
++/// To make room for multiple messages, nest the type parameter with
++/// tuples:
++///
++/// ```
++/// use std::os::unix::io::RawFd;
++/// use nix::sys::socket::CmsgSpace;
++/// let cmsg: CmsgSpace<([RawFd; 3], CmsgSpace<[RawFd; 2]>)> = CmsgSpace::new();
++/// ```
++#[repr(C)]
++#[derive(Clone, Copy, Debug, Eq, PartialEq)]
++pub struct CmsgSpace<T> {
++ _hdr: cmsghdr,
++ _pad: [align_of_cmsg_data; 0],
++ _data: T,
++}
++
++impl<T> CmsgSpace<T> {
++ /// Create a CmsgSpace<T>. The structure is used only for space, so
++ /// the fields are uninitialized.
++ #[deprecated( since="0.14.0", note="Use the cmsg_space! macro instead")]
++ pub fn new() -> Self {
++ // Safe because the fields themselves aren't accessible.
++ unsafe { mem::uninitialized() }
++ }
++}
++
++impl<T> CmsgBuffer for CmsgSpace<T> {
++ fn as_bytes_mut(&mut self) -> &mut [u8] {
++ // Safe because nothing ever attempts to access CmsgSpace's fields
++ unsafe {
++ slice::from_raw_parts_mut(self as *mut CmsgSpace<T> as *mut u8,
++ mem::size_of::<Self>())
++ }
++ }
++}
++
++impl CmsgBuffer for Vec<u8> {
++ fn as_bytes_mut(&mut self) -> &mut [u8] {
++ &mut self[..]
++ }
++}
++
++#[derive(Clone, Copy, Debug, Eq, PartialEq)]
++pub struct RecvMsg<'a> {
++ pub bytes: usize,
++ cmsghdr: Option<&'a cmsghdr>,
++ pub address: Option<SockAddr>,
++ pub flags: MsgFlags,
++ mhdr: msghdr,
++}
++
++impl<'a> RecvMsg<'a> {
++ /// Iterate over the valid control messages pointed to by this
++ /// msghdr.
++ pub fn cmsgs(&self) -> CmsgIterator {
++ CmsgIterator {
++ cmsghdr: self.cmsghdr,
++ mhdr: &self.mhdr
++ }
++ }
++}
++
++#[derive(Clone, Copy, Debug, Eq, PartialEq)]
++pub struct CmsgIterator<'a> {
++ /// Control message buffer to decode from. Must adhere to cmsg alignment.
++ cmsghdr: Option<&'a cmsghdr>,
++ mhdr: &'a msghdr
++}
++
++impl<'a> Iterator for CmsgIterator<'a> {
++ type Item = ControlMessageOwned;
++
++ fn next(&mut self) -> Option<ControlMessageOwned> {
++ match self.cmsghdr {
++ None => None, // No more messages
++ Some(hdr) => {
++ // Get the data.
++ // Safe if cmsghdr points to valid data returned by recvmsg(2)
++ let cm = unsafe { Some(ControlMessageOwned::decode_from(hdr))};
++ // Advance the internal pointer. Safe if mhdr and cmsghdr point
++ // to valid data returned by recvmsg(2)
++ self.cmsghdr = unsafe {
++ let p = CMSG_NXTHDR(self.mhdr as *const _, hdr as *const _);
++ p.as_ref()
++ };
++ cm
++ }
++ }
++ }
++}
++
++/// A type-safe wrapper around a single control message, as used with
++/// [`recvmsg`](#fn.recvmsg).
++///
++/// [Further reading](http://man7.org/linux/man-pages/man3/cmsg.3.html)
++// Nix version 0.13.0 and earlier used ControlMessage for both recvmsg and
++// sendmsg. However, on some platforms the messages returned by recvmsg may be
++// unaligned. ControlMessageOwned takes those messages by copy, obviating any
++// alignment issues.
++//
++// See https://github.com/nix-rust/nix/issues/999
++#[derive(Clone, Debug, Eq, PartialEq)]
++pub enum ControlMessageOwned {
++ /// Received version of
++ /// [`ControlMessage::ScmRights`][#enum.ControlMessage.html#variant.ScmRights]
++ ScmRights(Vec<RawFd>),
++ /// Received version of
++ /// [`ControlMessage::ScmCredentials`][#enum.ControlMessage.html#variant.ScmCredentials]
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ ScmCredentials(libc::ucred),
++ /// A message of type `SCM_TIMESTAMP`, containing the time the
++ /// packet was received by the kernel.
++ ///
++ /// See the kernel's explanation in "SO_TIMESTAMP" of
++ /// [networking/timestamping](https://www.kernel.org/doc/Documentation/networking/timestamping.txt).
++ ///
++ /// # Examples
++ ///
++ // Disable this test on FreeBSD i386
++ // https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=222039
++ #[cfg_attr(not(all(target_os = "freebsd", target_arch = "x86")), doc = " ```")]
++ #[cfg_attr(all(target_os = "freebsd", target_arch = "x86"), doc = " ```no_run")]
++ /// # #[macro_use] extern crate nix;
++ /// # use nix::sys::socket::*;
++ /// # use nix::sys::uio::IoVec;
++ /// # use nix::sys::time::*;
++ /// # use std::time::*;
++ /// # fn main() {
++ /// // Set up
++ /// let message = "Ohayō!".as_bytes();
++ /// let in_socket = socket(
++ /// AddressFamily::Inet,
++ /// SockType::Datagram,
++ /// SockFlag::empty(),
++ /// None).unwrap();
++ /// setsockopt(in_socket, sockopt::ReceiveTimestamp, &true).unwrap();
++ /// let localhost = InetAddr::new(IpAddr::new_v4(127, 0, 0, 1), 0);
++ /// bind(in_socket, &SockAddr::new_inet(localhost)).unwrap();
++ /// let address = getsockname(in_socket).unwrap();
++ /// // Get initial time
++ /// let time0 = SystemTime::now();
++ /// // Send the message
++ /// let iov = [IoVec::from_slice(message)];
++ /// let flags = MsgFlags::empty();
++ /// let l = sendmsg(in_socket, &iov, &[], flags, Some(&address)).unwrap();
++ /// assert_eq!(message.len(), l);
++ /// // Receive the message
++ /// let mut buffer = vec![0u8; message.len()];
++ /// let mut cmsgspace = cmsg_space!(TimeVal);
++ /// let iov = [IoVec::from_mut_slice(&mut buffer)];
++ /// let r = recvmsg(in_socket, &iov, Some(&mut cmsgspace), flags).unwrap();
++ /// let rtime = match r.cmsgs().next() {
++ /// Some(ControlMessageOwned::ScmTimestamp(rtime)) => rtime,
++ /// Some(_) => panic!("Unexpected control message"),
++ /// None => panic!("No control message")
++ /// };
++ /// // Check the final time
++ /// let time1 = SystemTime::now();
++ /// // the packet's received timestamp should lie in-between the two system
++ /// // times, unless the system clock was adjusted in the meantime.
++ /// let rduration = Duration::new(rtime.tv_sec() as u64,
++ /// rtime.tv_usec() as u32 * 1000);
++ /// assert!(time0.duration_since(UNIX_EPOCH).unwrap() <= rduration);
++ /// assert!(rduration <= time1.duration_since(UNIX_EPOCH).unwrap());
++ /// // Close socket
++ /// nix::unistd::close(in_socket).unwrap();
++ /// # }
++ /// ```
++ ScmTimestamp(TimeVal),
++ #[cfg(any(
++ target_os = "android",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos",
++ target_os = "netbsd",
++ ))]
++ Ipv4PacketInfo(libc::in_pktinfo),
++ #[cfg(any(
++ target_os = "android",
++ target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos",
++ target_os = "openbsd",
++ target_os = "netbsd",
++ ))]
++ Ipv6PacketInfo(libc::in6_pktinfo),
++ #[cfg(any(
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd",
++ ))]
++ Ipv4RecvIf(libc::sockaddr_dl),
++ #[cfg(any(
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd",
++ ))]
++ Ipv4RecvDstAddr(libc::in_addr),
++ /// Catch-all variant for unimplemented cmsg types.
++ #[doc(hidden)]
++ Unknown(UnknownCmsg),
++}
++
++impl ControlMessageOwned {
++ /// Decodes a `ControlMessageOwned` from raw bytes.
++ ///
++ /// This is only safe to call if the data is correct for the message type
++ /// specified in the header. Normally, the kernel ensures that this is the
++ /// case. "Correct" in this case includes correct length, alignment and
++ /// actual content.
++ ///
++ /// Returns `None` if the data may be unaligned. In that case use
++ /// `ControlMessageOwned::decode_from`.
++ unsafe fn decode_from(header: &cmsghdr) -> ControlMessageOwned
++ {
++ let p = CMSG_DATA(header);
++ let len = header as *const _ as usize + header.cmsg_len as usize
++ - p as usize;
++ match (header.cmsg_level, header.cmsg_type) {
++ (libc::SOL_SOCKET, libc::SCM_RIGHTS) => {
++ let n = len / mem::size_of::<RawFd>();
++ let mut fds = Vec::with_capacity(n);
++ for i in 0..n {
++ let fdp = (p as *const RawFd).offset(i as isize);
++ fds.push(ptr::read_unaligned(fdp));
++ }
++ let cmo = ControlMessageOwned::ScmRights(fds);
++ cmo
++ },
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ (libc::SOL_SOCKET, libc::SCM_CREDENTIALS) => {
++ let cred: libc::ucred = ptr::read_unaligned(p as *const _);
++ ControlMessageOwned::ScmCredentials(cred)
++ }
++ (libc::SOL_SOCKET, libc::SCM_TIMESTAMP) => {
++ let tv: libc::timeval = ptr::read_unaligned(p as *const _);
++ ControlMessageOwned::ScmTimestamp(TimeVal::from(tv))
++ },
++ #[cfg(any(
++ target_os = "android",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos"
++ ))]
++ (libc::IPPROTO_IPV6, libc::IPV6_PKTINFO) => {
++ let info = ptr::read_unaligned(p as *const libc::in6_pktinfo);
++ ControlMessageOwned::Ipv6PacketInfo(info)
++ }
++ #[cfg(any(
++ target_os = "android",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos",
++ target_os = "netbsd",
++ ))]
++ (libc::IPPROTO_IP, libc::IP_PKTINFO) => {
++ let info = ptr::read_unaligned(p as *const libc::in_pktinfo);
++ ControlMessageOwned::Ipv4PacketInfo(info)
++ }
++ #[cfg(any(
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd",
++ ))]
++ (libc::IPPROTO_IP, libc::IP_RECVIF) => {
++ let dl = ptr::read_unaligned(p as *const libc::sockaddr_dl);
++ ControlMessageOwned::Ipv4RecvIf(dl)
++ },
++ #[cfg(any(
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd",
++ ))]
++ (libc::IPPROTO_IP, libc::IP_RECVDSTADDR) => {
++ let dl = ptr::read_unaligned(p as *const libc::in_addr);
++ ControlMessageOwned::Ipv4RecvDstAddr(dl)
++ },
++ (_, _) => {
++ let sl = slice::from_raw_parts(p, len);
++ let ucmsg = UnknownCmsg(*header, Vec::<u8>::from(&sl[..]));
++ ControlMessageOwned::Unknown(ucmsg)
++ }
++ }
++ }
++}
++
++/// A type-safe zero-copy wrapper around a single control message, as used wih
++/// [`sendmsg`](#fn.sendmsg). More types may be added to this enum; do not
++/// exhaustively pattern-match it.
++///
++/// [Further reading](http://man7.org/linux/man-pages/man3/cmsg.3.html)
++#[derive(Clone, Copy, Debug, Eq, PartialEq)]
++pub enum ControlMessage<'a> {
++ /// A message of type `SCM_RIGHTS`, containing an array of file
++ /// descriptors passed between processes.
++ ///
++ /// See the description in the "Ancillary messages" section of the
++ /// [unix(7) man page](http://man7.org/linux/man-pages/man7/unix.7.html).
++ ///
++ /// Using multiple `ScmRights` messages for a single `sendmsg` call isn't
++ /// recommended since it causes platform-dependent behaviour: It might
++ /// swallow all but the first `ScmRights` message or fail with `EINVAL`.
++ /// Instead, you can put all fds to be passed into a single `ScmRights`
++ /// message.
++ ScmRights(&'a [RawFd]),
++ /// A message of type `SCM_CREDENTIALS`, containing the pid, uid and gid of
++ /// a process connected to the socket.
++ ///
++ /// This is similar to the socket option `SO_PEERCRED`, but requires a
++ /// process to explicitly send its credentials. A process running as root is
++ /// allowed to specify any credentials, while credentials sent by other
++ /// processes are verified by the kernel.
++ ///
++ /// For further information, please refer to the
++ /// [`unix(7)`](http://man7.org/linux/man-pages/man7/unix.7.html) man page.
++ // FIXME: When `#[repr(transparent)]` is stable, use it on `UnixCredentials`
++ // and put that in here instead of a raw ucred.
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ ScmCredentials(&'a libc::ucred),
++
++ /// Set IV for `AF_ALG` crypto API.
++ ///
++ /// For further information, please refer to the
++ /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html)
++ #[cfg(any(
++ target_os = "android",
++ target_os = "linux",
++ ))]
++ AlgSetIv(&'a [u8]),
++ /// Set crypto operation for `AF_ALG` crypto API. It may be one of
++ /// `ALG_OP_ENCRYPT` or `ALG_OP_DECRYPT`
++ ///
++ /// For further information, please refer to the
++ /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html)
++ #[cfg(any(
++ target_os = "android",
++ target_os = "linux",
++ ))]
++ AlgSetOp(&'a libc::c_int),
++ /// Set the length of associated authentication data (AAD) (applicable only to AEAD algorithms)
++ /// for `AF_ALG` crypto API.
++ ///
++ /// For further information, please refer to the
++ /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html)
++ #[cfg(any(
++ target_os = "android",
++ target_os = "linux",
++ ))]
++ AlgSetAeadAssoclen(&'a u32),
++
++}
++
++// An opaque structure used to prevent cmsghdr from being a public type
++#[doc(hidden)]
++#[derive(Clone, Debug, Eq, PartialEq)]
++pub struct UnknownCmsg(cmsghdr, Vec<u8>);
++
++impl<'a> ControlMessage<'a> {
++ /// The value of CMSG_SPACE on this message.
++ /// Safe because CMSG_SPACE is always safe
++ fn space(&self) -> usize {
++ unsafe{CMSG_SPACE(self.len() as libc::c_uint) as usize}
++ }
++
++ /// The value of CMSG_LEN on this message.
++ /// Safe because CMSG_LEN is always safe
++ #[cfg(any(target_os = "android",
++ all(target_os = "linux", not(target_env = "musl"))))]
++ fn cmsg_len(&self) -> usize {
++ unsafe{CMSG_LEN(self.len() as libc::c_uint) as usize}
++ }
++
++ #[cfg(not(any(target_os = "android",
++ all(target_os = "linux", not(target_env = "musl")))))]
++ fn cmsg_len(&self) -> libc::c_uint {
++ unsafe{CMSG_LEN(self.len() as libc::c_uint)}
++ }
++
++ /// Return a reference to the payload data as a byte pointer
++ fn copy_to_cmsg_data(&self, cmsg_data: *mut u8) {
++ let data_ptr = match self {
++ &ControlMessage::ScmRights(fds) => {
++ fds as *const _ as *const u8
++ },
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ &ControlMessage::ScmCredentials(creds) => {
++ creds as *const libc::ucred as *const u8
++ }
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ &ControlMessage::AlgSetIv(iv) => {
++ unsafe {
++ let alg_iv = cmsg_data as *mut libc::af_alg_iv;
++ (*alg_iv).ivlen = iv.len() as u32;
++ ptr::copy_nonoverlapping(
++ iv.as_ptr(),
++ (*alg_iv).iv.as_mut_ptr(),
++ iv.len()
++ );
++ };
++ return
++ },
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ &ControlMessage::AlgSetOp(op) => {
++ op as *const _ as *const u8
++ },
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ &ControlMessage::AlgSetAeadAssoclen(len) => {
++ len as *const _ as *const u8
++ },
++ };
++ unsafe {
++ ptr::copy_nonoverlapping(
++ data_ptr,
++ cmsg_data,
++ self.len()
++ )
++ };
++ }
++
++ /// The size of the payload, excluding its cmsghdr
++ fn len(&self) -> usize {
++ match self {
++ &ControlMessage::ScmRights(fds) => {
++ mem::size_of_val(fds)
++ },
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ &ControlMessage::ScmCredentials(creds) => {
++ mem::size_of_val(creds)
++ }
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ &ControlMessage::AlgSetIv(iv) => {
++ mem::size_of::<libc::af_alg_iv>() + iv.len()
++ },
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ &ControlMessage::AlgSetOp(op) => {
++ mem::size_of_val(op)
++ },
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ &ControlMessage::AlgSetAeadAssoclen(len) => {
++ mem::size_of_val(len)
++ },
++ }
++ }
++
++ /// Returns the value to put into the `cmsg_level` field of the header.
++ fn cmsg_level(&self) -> libc::c_int {
++ match self {
++ &ControlMessage::ScmRights(_) => libc::SOL_SOCKET,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ &ControlMessage::ScmCredentials(_) => libc::SOL_SOCKET,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ &ControlMessage::AlgSetIv(_) | &ControlMessage::AlgSetOp(_) | &ControlMessage::AlgSetAeadAssoclen(_) => {
++ libc::SOL_ALG
++ },
++ }
++ }
++
++ /// Returns the value to put into the `cmsg_type` field of the header.
++ fn cmsg_type(&self) -> libc::c_int {
++ match self {
++ &ControlMessage::ScmRights(_) => libc::SCM_RIGHTS,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ &ControlMessage::ScmCredentials(_) => libc::SCM_CREDENTIALS,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ &ControlMessage::AlgSetIv(_) => {
++ libc::ALG_SET_IV
++ },
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ &ControlMessage::AlgSetOp(_) => {
++ libc::ALG_SET_OP
++ },
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ &ControlMessage::AlgSetAeadAssoclen(_) => {
++ libc::ALG_SET_AEAD_ASSOCLEN
++ },
++ }
++ }
++
++ // Unsafe: cmsg must point to a valid cmsghdr with enough space to
++ // encode self.
++ unsafe fn encode_into(&self, cmsg: *mut cmsghdr) {
++ (*cmsg).cmsg_level = self.cmsg_level();
++ (*cmsg).cmsg_type = self.cmsg_type();
++ (*cmsg).cmsg_len = self.cmsg_len();
++ self.copy_to_cmsg_data(CMSG_DATA(cmsg));
++ }
++}
++
++
++/// Send data in scatter-gather vectors to a socket, possibly accompanied
++/// by ancillary data. Optionally direct the message at the given address,
++/// as with sendto.
++///
++/// Allocates if cmsgs is nonempty.
++pub fn sendmsg(fd: RawFd, iov: &[IoVec<&[u8]>], cmsgs: &[ControlMessage],
++ flags: MsgFlags, addr: Option<&SockAddr>) -> Result<usize>
++{
++ let capacity = cmsgs.iter().map(|c| c.space()).sum();
++
++ // First size the buffer needed to hold the cmsgs. It must be zeroed,
++ // because subsequent code will not clear the padding bytes.
++ let cmsg_buffer = vec![0u8; capacity];
++
++ // Next encode the sending address, if provided
++ let (name, namelen) = match addr {
++ Some(addr) => {
++ let (x, y) = unsafe { addr.as_ffi_pair() };
++ (x as *const _, y)
++ },
++ None => (ptr::null(), 0),
++ };
++
++ // The message header must be initialized before the individual cmsgs.
++ let cmsg_ptr = if capacity > 0 {
++ cmsg_buffer.as_ptr() as *mut c_void
++ } else {
++ ptr::null_mut()
++ };
++
++ let mhdr = {
++ // Musl's msghdr has private fields, so this is the only way to
++ // initialize it.
++ let mut mhdr: msghdr = unsafe{mem::uninitialized()};
++ mhdr.msg_name = name as *mut _;
++ mhdr.msg_namelen = namelen;
++ // transmute iov into a mutable pointer. sendmsg doesn't really mutate
++ // the buffer, but the standard says that it takes a mutable pointer
++ mhdr.msg_iov = iov.as_ptr() as *mut _;
++ mhdr.msg_iovlen = iov.len() as _;
++ mhdr.msg_control = cmsg_ptr;
++ mhdr.msg_controllen = capacity as _;
++ mhdr.msg_flags = 0;
++ mhdr
++ };
++
++ // Encode each cmsg. This must happen after initializing the header because
++ // CMSG_NEXT_HDR and friends read the msg_control and msg_controllen fields.
++ // CMSG_FIRSTHDR is always safe
++ let mut pmhdr: *mut cmsghdr = unsafe{CMSG_FIRSTHDR(&mhdr as *const msghdr)};
++ for cmsg in cmsgs {
++ assert_ne!(pmhdr, ptr::null_mut());
++ // Safe because we know that pmhdr is valid, and we initialized it with
++ // sufficient space
++ unsafe { cmsg.encode_into(pmhdr) };
++ // Safe because mhdr is valid
++ pmhdr = unsafe{CMSG_NXTHDR(&mhdr as *const msghdr, pmhdr)};
++ }
++
++ let ret = unsafe { libc::sendmsg(fd, &mhdr, flags.bits()) };
++
++ Errno::result(ret).map(|r| r as usize)
++}
++
++/// Receive message in scatter-gather vectors from a socket, and
++/// optionally receive ancillary data into the provided buffer.
++/// If no ancillary data is desired, use () as the type parameter.
++///
++/// # References
++/// [recvmsg(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html)
++pub fn recvmsg<'a>(fd: RawFd, iov: &[IoVec<&mut [u8]>],
++ cmsg_buffer: Option<&'a mut dyn CmsgBuffer>,
++ flags: MsgFlags) -> Result<RecvMsg<'a>>
++{
++ let mut address: sockaddr_storage = unsafe { mem::uninitialized() };
++ let (msg_control, msg_controllen) = match cmsg_buffer {
++ Some(cmsgspace) => {
++ let msg_buf = cmsgspace.as_bytes_mut();
++ (msg_buf.as_mut_ptr(), msg_buf.len())
++ },
++ None => (ptr::null_mut(), 0),
++ };
++ let mut mhdr = {
++ // Musl's msghdr has private fields, so this is the only way to
++ // initialize it.
++ let mut mhdr: msghdr = unsafe{mem::uninitialized()};
++ mhdr.msg_name = &mut address as *mut sockaddr_storage as *mut c_void;
++ mhdr.msg_namelen = mem::size_of::<sockaddr_storage>() as socklen_t;
++ mhdr.msg_iov = iov.as_ptr() as *mut iovec;
++ mhdr.msg_iovlen = iov.len() as _;
++ mhdr.msg_control = msg_control as *mut c_void;
++ mhdr.msg_controllen = msg_controllen as _;
++ mhdr.msg_flags = 0;
++ mhdr
++ };
++
++ let ret = unsafe { libc::recvmsg(fd, &mut mhdr, flags.bits()) };
++
++ Errno::result(ret).map(|r| {
++ let cmsghdr = unsafe {
++ if mhdr.msg_controllen > 0 {
++ // got control message(s)
++ debug_assert!(!mhdr.msg_control.is_null());
++ debug_assert!(msg_controllen >= mhdr.msg_controllen as usize);
++ CMSG_FIRSTHDR(&mhdr as *const msghdr)
++ } else {
++ ptr::null()
++ }.as_ref()
++ };
++
++ let address = unsafe {
++ sockaddr_storage_to_addr(&address, mhdr.msg_namelen as usize).ok()
++ };
++ RecvMsg {
++ bytes: r as usize,
++ cmsghdr,
++ address,
++ flags: MsgFlags::from_bits_truncate(mhdr.msg_flags),
++ mhdr,
++ }
++ })
++}
++
++
++/// Create an endpoint for communication
++///
++/// The `protocol` specifies a particular protocol to be used with the
++/// socket. Normally only a single protocol exists to support a
++/// particular socket type within a given protocol family, in which case
++/// protocol can be specified as `None`. However, it is possible that many
++/// protocols may exist, in which case a particular protocol must be
++/// specified in this manner.
++///
++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html)
++pub fn socket<T: Into<Option<SockProtocol>>>(domain: AddressFamily, ty: SockType, flags: SockFlag, protocol: T) -> Result<RawFd> {
++ let protocol = match protocol.into() {
++ None => 0,
++ Some(p) => p as c_int,
++ };
++
++ // SockFlags are usually embedded into `ty`, but we don't do that in `nix` because it's a
++ // little easier to understand by separating it out. So we have to merge these bitfields
++ // here.
++ let mut ty = ty as c_int;
++ ty |= flags.bits();
++
++ let res = unsafe { libc::socket(domain as c_int, ty, protocol) };
++
++ Errno::result(res)
++}
++
++/// Create a pair of connected sockets
++///
++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/socketpair.html)
++pub fn socketpair<T: Into<Option<SockProtocol>>>(domain: AddressFamily, ty: SockType, protocol: T,
++ flags: SockFlag) -> Result<(RawFd, RawFd)> {
++ let protocol = match protocol.into() {
++ None => 0,
++ Some(p) => p as c_int,
++ };
++
++ // SockFlags are usually embedded into `ty`, but we don't do that in `nix` because it's a
++ // little easier to understand by separating it out. So we have to merge these bitfields
++ // here.
++ let mut ty = ty as c_int;
++ ty |= flags.bits();
++
++ let mut fds = [-1, -1];
++
++ let res = unsafe { libc::socketpair(domain as c_int, ty, protocol, fds.as_mut_ptr()) };
++ Errno::result(res)?;
++
++ Ok((fds[0], fds[1]))
++}
++
++/// Listen for connections on a socket
++///
++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html)
++pub fn listen(sockfd: RawFd, backlog: usize) -> Result<()> {
++ let res = unsafe { libc::listen(sockfd, backlog as c_int) };
++
++ Errno::result(res).map(drop)
++}
++
++/// Bind a name to a socket
++///
++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html)
++pub fn bind(fd: RawFd, addr: &SockAddr) -> Result<()> {
++ let res = unsafe {
++ let (ptr, len) = addr.as_ffi_pair();
++ libc::bind(fd, ptr, len)
++ };
++
++ Errno::result(res).map(drop)
++}
++
++/// Accept a connection on a socket
++///
++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.html)
++pub fn accept(sockfd: RawFd) -> Result<RawFd> {
++ let res = unsafe { libc::accept(sockfd, ptr::null_mut(), ptr::null_mut()) };
++
++ Errno::result(res)
++}
++
++/// Accept a connection on a socket
++///
++/// [Further reading](http://man7.org/linux/man-pages/man2/accept.2.html)
++#[cfg(any(target_os = "android",
++ target_os = "freebsd",
++ target_os = "linux",
++ target_os = "openbsd"))]
++pub fn accept4(sockfd: RawFd, flags: SockFlag) -> Result<RawFd> {
++ let res = unsafe { libc::accept4(sockfd, ptr::null_mut(), ptr::null_mut(), flags.bits()) };
++
++ Errno::result(res)
++}
++
++/// Initiate a connection on a socket
++///
++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html)
++pub fn connect(fd: RawFd, addr: &SockAddr) -> Result<()> {
++ let res = unsafe {
++ let (ptr, len) = addr.as_ffi_pair();
++ libc::connect(fd, ptr, len)
++ };
++
++ Errno::result(res).map(drop)
++}
++
++/// Receive data from a connection-oriented socket. Returns the number of
++/// bytes read
++///
++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/recv.html)
++pub fn recv(sockfd: RawFd, buf: &mut [u8], flags: MsgFlags) -> Result<usize> {
++ unsafe {
++ let ret = libc::recv(
++ sockfd,
++ buf.as_ptr() as *mut c_void,
++ buf.len() as size_t,
++ flags.bits());
++
++ Errno::result(ret).map(|r| r as usize)
++ }
++}
++
++/// Receive data from a connectionless or connection-oriented socket. Returns
++/// the number of bytes read and the socket address of the sender.
++///
++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/recvfrom.html)
++pub fn recvfrom(sockfd: RawFd, buf: &mut [u8]) -> Result<(usize, SockAddr)> {
++ unsafe {
++ let addr: sockaddr_storage = mem::zeroed();
++ let mut len = mem::size_of::<sockaddr_storage>() as socklen_t;
++
++ let ret = Errno::result(libc::recvfrom(
++ sockfd,
++ buf.as_ptr() as *mut c_void,
++ buf.len() as size_t,
++ 0,
++ mem::transmute(&addr),
++ &mut len as *mut socklen_t))?;
++
++ sockaddr_storage_to_addr(&addr, len as usize)
++ .map(|addr| (ret as usize, addr))
++ }
++}
++
++/// Send a message to a socket
++///
++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html)
++pub fn sendto(fd: RawFd, buf: &[u8], addr: &SockAddr, flags: MsgFlags) -> Result<usize> {
++ let ret = unsafe {
++ let (ptr, len) = addr.as_ffi_pair();
++ libc::sendto(fd, buf.as_ptr() as *const c_void, buf.len() as size_t, flags.bits(), ptr, len)
++ };
++
++ Errno::result(ret).map(|r| r as usize)
++}
++
++/// Send data to a connection-oriented socket. Returns the number of bytes read
++///
++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/send.html)
++pub fn send(fd: RawFd, buf: &[u8], flags: MsgFlags) -> Result<usize> {
++ let ret = unsafe {
++ libc::send(fd, buf.as_ptr() as *const c_void, buf.len() as size_t, flags.bits())
++ };
++
++ Errno::result(ret).map(|r| r as usize)
++}
++
++/*
++ *
++ * ===== Socket Options =====
++ *
++ */
++
++/// The protocol level at which to get / set socket options. Used as an
++/// argument to `getsockopt` and `setsockopt`.
++///
++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html)
++#[repr(i32)]
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub enum SockLevel {
++ Socket = libc::SOL_SOCKET,
++ Tcp = libc::IPPROTO_TCP,
++ Ip = libc::IPPROTO_IP,
++ Ipv6 = libc::IPPROTO_IPV6,
++ Udp = libc::IPPROTO_UDP,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ Netlink = libc::SOL_NETLINK,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ Alg = libc::SOL_ALG,
++}
++
++/// Represents a socket option that can be accessed or set. Used as an argument
++/// to `getsockopt`
++pub trait GetSockOpt : Copy {
++ type Val;
++
++ #[doc(hidden)]
++ fn get(&self, fd: RawFd) -> Result<Self::Val>;
++}
++
++/// Represents a socket option that can be accessed or set. Used as an argument
++/// to `setsockopt`
++pub trait SetSockOpt : Clone {
++ type Val;
++
++ #[doc(hidden)]
++ fn set(&self, fd: RawFd, val: &Self::Val) -> Result<()>;
++}
++
++/// Get the current value for the requested socket option
++///
++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html)
++pub fn getsockopt<O: GetSockOpt>(fd: RawFd, opt: O) -> Result<O::Val> {
++ opt.get(fd)
++}
++
++/// Sets the value for the requested socket option
++///
++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html)
++///
++/// # Examples
++///
++/// ```
++/// use nix::sys::socket::setsockopt;
++/// use nix::sys::socket::sockopt::KeepAlive;
++/// use std::net::TcpListener;
++/// use std::os::unix::io::AsRawFd;
++///
++/// let listener = TcpListener::bind("0.0.0.0:0").unwrap();
++/// let fd = listener.as_raw_fd();
++/// let res = setsockopt(fd, KeepAlive, &true);
++/// assert!(res.is_ok());
++/// ```
++pub fn setsockopt<O: SetSockOpt>(fd: RawFd, opt: O, val: &O::Val) -> Result<()> {
++ opt.set(fd, val)
++}
++
++/// Get the address of the peer connected to the socket `fd`.
++///
++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpeername.html)
++pub fn getpeername(fd: RawFd) -> Result<SockAddr> {
++ unsafe {
++ let addr: sockaddr_storage = mem::uninitialized();
++ let mut len = mem::size_of::<sockaddr_storage>() as socklen_t;
++
++ let ret = libc::getpeername(fd, mem::transmute(&addr), &mut len);
++
++ Errno::result(ret)?;
++
++ sockaddr_storage_to_addr(&addr, len as usize)
++ }
++}
++
++/// Get the current address to which the socket `fd` is bound.
++///
++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockname.html)
++pub fn getsockname(fd: RawFd) -> Result<SockAddr> {
++ unsafe {
++ let addr: sockaddr_storage = mem::uninitialized();
++ let mut len = mem::size_of::<sockaddr_storage>() as socklen_t;
++
++ let ret = libc::getsockname(fd, mem::transmute(&addr), &mut len);
++
++ Errno::result(ret)?;
++
++ sockaddr_storage_to_addr(&addr, len as usize)
++ }
++}
++
++/// Return the appropriate `SockAddr` type from a `sockaddr_storage` of a certain
++/// size. In C this would usually be done by casting. The `len` argument
++/// should be the number of bytes in the `sockaddr_storage` that are actually
++/// allocated and valid. It must be at least as large as all the useful parts
++/// of the structure. Note that in the case of a `sockaddr_un`, `len` need not
++/// include the terminating null.
++pub unsafe fn sockaddr_storage_to_addr(
++ addr: &sockaddr_storage,
++ len: usize) -> Result<SockAddr> {
++
++ if len < mem::size_of_val(&addr.ss_family) {
++ return Err(Error::Sys(Errno::ENOTCONN));
++ }
++
++ match addr.ss_family as c_int {
++ libc::AF_INET => {
++ assert!(len as usize == mem::size_of::<sockaddr_in>());
++ let ret = *(addr as *const _ as *const sockaddr_in);
++ Ok(SockAddr::Inet(InetAddr::V4(ret)))
++ }
++ libc::AF_INET6 => {
++ assert!(len as usize == mem::size_of::<sockaddr_in6>());
++ Ok(SockAddr::Inet(InetAddr::V6(*(addr as *const _ as *const sockaddr_in6))))
++ }
++ libc::AF_UNIX => {
++ let sun = *(addr as *const _ as *const sockaddr_un);
++ let pathlen = len - offset_of!(sockaddr_un, sun_path);
++ Ok(SockAddr::Unix(UnixAddr(sun, pathlen)))
++ }
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ libc::AF_NETLINK => {
++ use libc::sockaddr_nl;
++ Ok(SockAddr::Netlink(NetlinkAddr(*(addr as *const _ as *const sockaddr_nl))))
++ }
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ libc::AF_ALG => {
++ use libc::sockaddr_alg;
++ Ok(SockAddr::Alg(AlgAddr(*(addr as *const _ as *const sockaddr_alg))))
++ }
++ #[cfg(target_os = "linux")]
++ libc::AF_VSOCK => {
++ use libc::sockaddr_vm;
++ Ok(SockAddr::Vsock(VsockAddr(*(addr as *const _ as *const sockaddr_vm))))
++ }
++ af => panic!("unexpected address family {}", af),
++ }
++}
++
++
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub enum Shutdown {
++ /// Further receptions will be disallowed.
++ Read,
++ /// Further transmissions will be disallowed.
++ Write,
++ /// Further receptions and transmissions will be disallowed.
++ Both,
++}
++
++/// Shut down part of a full-duplex connection.
++///
++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/shutdown.html)
++pub fn shutdown(df: RawFd, how: Shutdown) -> Result<()> {
++ unsafe {
++ use libc::shutdown;
++
++ let how = match how {
++ Shutdown::Read => libc::SHUT_RD,
++ Shutdown::Write => libc::SHUT_WR,
++ Shutdown::Both => libc::SHUT_RDWR,
++ };
++
++ Errno::result(shutdown(df, how)).map(drop)
++ }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/socket/sockopt.rs b/third_party/rust/nix-0.15.0/src/sys/socket/sockopt.rs
+new file mode 100644
+index 0000000000000..a996010018d5b
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/socket/sockopt.rs
+@@ -0,0 +1,680 @@
++use super::{GetSockOpt, SetSockOpt};
++use Result;
++use errno::Errno;
++use sys::time::TimeVal;
++use libc::{self, c_int, c_void, socklen_t};
++use std::mem;
++use std::os::unix::io::RawFd;
++use std::ffi::{OsStr, OsString};
++#[cfg(target_family = "unix")]
++use std::os::unix::ffi::OsStrExt;
++
++// Constants
++// TCP_CA_NAME_MAX isn't defined in user space include files
++#[cfg(any(target_os = "freebsd", target_os = "linux"))]
++const TCP_CA_NAME_MAX: usize = 16;
++
++/// Helper for implementing `SetSockOpt` for a given socket option. See
++/// [`::sys::socket::SetSockOpt`](sys/socket/trait.SetSockOpt.html).
++///
++/// This macro aims to help implementing `SetSockOpt` for different socket options that accept
++/// different kinds of data to be used with `setsockopt`.
++///
++/// Instead of using this macro directly consider using `sockopt_impl!`, especially if the option
++/// you are implementing represents a simple type.
++///
++/// # Arguments
++///
++/// * `$name:ident`: name of the type you want to implement `SetSockOpt` for.
++/// * `$level:path` : socket layer, or a `protocol level`: could be *raw sockets*
++/// (`libc::SOL_SOCKET`), *ip protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`),
++/// and more. Please refer to your system manual for more options. Will be passed as the second
++/// argument (`level`) to the `setsockopt` call.
++/// * `$flag:path`: a flag name to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`,
++/// `libc::IP_ADD_MEMBERSHIP` and others. Will be passed as the third argument (`option_name`)
++/// to the `setsockopt` call.
++/// * Type of the value that you are going to set.
++/// * Type that implements the `Set` trait for the type from the previous item (like `SetBool` for
++/// `bool`, `SetUsize` for `usize`, etc.).
++macro_rules! setsockopt_impl {
++ ($name:ident, $level:path, $flag:path, $ty:ty, $setter:ty) => {
++ impl SetSockOpt for $name {
++ type Val = $ty;
++
++ fn set(&self, fd: RawFd, val: &$ty) -> Result<()> {
++ unsafe {
++ let setter: $setter = Set::new(val);
++
++ let res = libc::setsockopt(fd, $level, $flag,
++ setter.ffi_ptr(),
++ setter.ffi_len());
++ Errno::result(res).map(drop)
++ }
++ }
++ }
++ }
++}
++
++/// Helper for implementing `GetSockOpt` for a given socket option. See
++/// [`::sys::socket::GetSockOpt`](sys/socket/trait.GetSockOpt.html).
++///
++/// This macro aims to help implementing `GetSockOpt` for different socket options that accept
++/// different kinds of data to be use with `getsockopt`.
++///
++/// Instead of using this macro directly consider using `sockopt_impl!`, especially if the option
++/// you are implementing represents a simple type.
++///
++/// # Arguments
++///
++/// * Name of the type you want to implement `GetSockOpt` for.
++/// * Socket layer, or a `protocol level`: could be *raw sockets* (`lic::SOL_SOCKET`), *ip
++/// protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`), and more. Please refer
++/// to your system manual for more options. Will be passed as the second argument (`level`) to
++/// the `getsockopt` call.
++/// * A flag to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`,
++/// `libc::SO_ORIGINAL_DST` and others. Will be passed as the third argument (`option_name`) to
++/// the `getsockopt` call.
++/// * Type of the value that you are going to get.
++/// * Type that implements the `Get` trait for the type from the previous item (`GetBool` for
++/// `bool`, `GetUsize` for `usize`, etc.).
++macro_rules! getsockopt_impl {
++ ($name:ident, $level:path, $flag:path, $ty:ty, $getter:ty) => {
++ impl GetSockOpt for $name {
++ type Val = $ty;
++
++ fn get(&self, fd: RawFd) -> Result<$ty> {
++ unsafe {
++ let mut getter: $getter = Get::blank();
++
++ let res = libc::getsockopt(fd, $level, $flag,
++ getter.ffi_ptr(),
++ getter.ffi_len());
++ Errno::result(res)?;
++
++ Ok(getter.unwrap())
++ }
++ }
++ }
++ }
++}
++
++/// Helper to generate the sockopt accessors. See
++/// [`::sys::socket::GetSockOpt`](sys/socket/trait.GetSockOpt.html) and
++/// [`::sys::socket::SetSockOpt`](sys/socket/trait.SetSockOpt.html).
++///
++/// This macro aims to help implementing `GetSockOpt` and `SetSockOpt` for different socket options
++/// that accept different kinds of data to be use with `getsockopt` and `setsockopt` respectively.
++///
++/// Basically this macro wraps up the [`getsockopt_impl!`](macro.getsockopt_impl.html) and
++/// [`setsockopt_impl!`](macro.setsockopt_impl.html) macros.
++///
++/// # Arguments
++///
++/// * `GetOnly`, `SetOnly` or `Both`: whether you want to implement only getter, only setter or
++/// both of them.
++/// * `$name:ident`: name of type `GetSockOpt`/`SetSockOpt` will be implemented for.
++/// * `$level:path` : socket layer, or a `protocol level`: could be *raw sockets*
++/// (`lic::SOL_SOCKET`), *ip protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`),
++/// and more. Please refer to your system manual for more options. Will be passed as the second
++/// argument (`level`) to the `getsockopt`/`setsockopt` call.
++/// * `$flag:path`: a flag name to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`,
++/// `libc::IP_ADD_MEMBERSHIP` and others. Will be passed as the third argument (`option_name`)
++/// to the `setsockopt`/`getsockopt` call.
++/// * `$ty:ty`: type of the value that will be get/set.
++/// * `$getter:ty`: `Get` implementation; optional; only for `GetOnly` and `Both`.
++/// * `$setter:ty`: `Set` implementation; optional; only for `SetOnly` and `Both`.
++macro_rules! sockopt_impl {
++ (GetOnly, $name:ident, $level:path, $flag:path, bool) => {
++ sockopt_impl!(GetOnly, $name, $level, $flag, bool, GetBool);
++ };
++
++ (GetOnly, $name:ident, $level:path, $flag:path, u8) => {
++ sockopt_impl!(GetOnly, $name, $level, $flag, u8, GetU8);
++ };
++
++ (GetOnly, $name:ident, $level:path, $flag:path, usize) => {
++ sockopt_impl!(GetOnly, $name, $level, $flag, usize, GetUsize);
++ };
++
++ (SetOnly, $name:ident, $level:path, $flag:path, bool) => {
++ sockopt_impl!(SetOnly, $name, $level, $flag, bool, SetBool);
++ };
++
++ (SetOnly, $name:ident, $level:path, $flag:path, u8) => {
++ sockopt_impl!(SetOnly, $name, $level, $flag, u8, SetU8);
++ };
++
++ (SetOnly, $name:ident, $level:path, $flag:path, usize) => {
++ sockopt_impl!(SetOnly, $name, $level, $flag, usize, SetUsize);
++ };
++
++ (Both, $name:ident, $level:path, $flag:path, bool) => {
++ sockopt_impl!(Both, $name, $level, $flag, bool, GetBool, SetBool);
++ };
++
++ (Both, $name:ident, $level:path, $flag:path, u8) => {
++ sockopt_impl!(Both, $name, $level, $flag, u8, GetU8, SetU8);
++ };
++
++ (Both, $name:ident, $level:path, $flag:path, usize) => {
++ sockopt_impl!(Both, $name, $level, $flag, usize, GetUsize, SetUsize);
++ };
++
++ (Both, $name:ident, $level:path, $flag:path, OsString<$array:ty>) => {
++ sockopt_impl!(Both, $name, $level, $flag, OsString, GetOsString<$array>, SetOsString);
++ };
++
++ /*
++ * Matchers with generic getter types must be placed at the end, so
++ * they'll only match _after_ specialized matchers fail
++ */
++ (GetOnly, $name:ident, $level:path, $flag:path, $ty:ty) => {
++ sockopt_impl!(GetOnly, $name, $level, $flag, $ty, GetStruct<$ty>);
++ };
++
++ (GetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty) => {
++ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++ pub struct $name;
++
++ getsockopt_impl!($name, $level, $flag, $ty, $getter);
++ };
++
++ (SetOnly, $name:ident, $level:path, $flag:path, $ty:ty) => {
++ sockopt_impl!(SetOnly, $name, $level, $flag, $ty, SetStruct<$ty>);
++ };
++
++ (SetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $setter:ty) => {
++ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++ pub struct $name;
++
++ setsockopt_impl!($name, $level, $flag, $ty, $setter);
++ };
++
++ (Both, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty, $setter:ty) => {
++ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++ pub struct $name;
++
++ setsockopt_impl!($name, $level, $flag, $ty, $setter);
++ getsockopt_impl!($name, $level, $flag, $ty, $getter);
++ };
++
++ (Both, $name:ident, $level:path, $flag:path, $ty:ty) => {
++ sockopt_impl!(Both, $name, $level, $flag, $ty, GetStruct<$ty>, SetStruct<$ty>);
++ };
++}
++
++/*
++ *
++ * ===== Define sockopts =====
++ *
++ */
++
++sockopt_impl!(Both, ReuseAddr, libc::SOL_SOCKET, libc::SO_REUSEADDR, bool);
++sockopt_impl!(Both, ReusePort, libc::SOL_SOCKET, libc::SO_REUSEPORT, bool);
++sockopt_impl!(Both, TcpNoDelay, libc::IPPROTO_TCP, libc::TCP_NODELAY, bool);
++sockopt_impl!(Both, Linger, libc::SOL_SOCKET, libc::SO_LINGER, libc::linger);
++sockopt_impl!(SetOnly, IpAddMembership, libc::IPPROTO_IP, libc::IP_ADD_MEMBERSHIP, super::IpMembershipRequest);
++sockopt_impl!(SetOnly, IpDropMembership, libc::IPPROTO_IP, libc::IP_DROP_MEMBERSHIP, super::IpMembershipRequest);
++cfg_if! {
++ if #[cfg(any(target_os = "android", target_os = "linux"))] {
++ sockopt_impl!(SetOnly, Ipv6AddMembership, libc::IPPROTO_IPV6, libc::IPV6_ADD_MEMBERSHIP, super::Ipv6MembershipRequest);
++ sockopt_impl!(SetOnly, Ipv6DropMembership, libc::IPPROTO_IPV6, libc::IPV6_DROP_MEMBERSHIP, super::Ipv6MembershipRequest);
++ } else if #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))] {
++ sockopt_impl!(SetOnly, Ipv6AddMembership, libc::IPPROTO_IPV6, libc::IPV6_JOIN_GROUP, super::Ipv6MembershipRequest);
++ sockopt_impl!(SetOnly, Ipv6DropMembership, libc::IPPROTO_IPV6, libc::IPV6_LEAVE_GROUP, super::Ipv6MembershipRequest);
++ }
++}
++sockopt_impl!(Both, IpMulticastTtl, libc::IPPROTO_IP, libc::IP_MULTICAST_TTL, u8);
++sockopt_impl!(Both, IpMulticastLoop, libc::IPPROTO_IP, libc::IP_MULTICAST_LOOP, bool);
++sockopt_impl!(Both, ReceiveTimeout, libc::SOL_SOCKET, libc::SO_RCVTIMEO, TimeVal);
++sockopt_impl!(Both, SendTimeout, libc::SOL_SOCKET, libc::SO_SNDTIMEO, TimeVal);
++sockopt_impl!(Both, Broadcast, libc::SOL_SOCKET, libc::SO_BROADCAST, bool);
++sockopt_impl!(Both, OobInline, libc::SOL_SOCKET, libc::SO_OOBINLINE, bool);
++sockopt_impl!(GetOnly, SocketError, libc::SOL_SOCKET, libc::SO_ERROR, i32);
++sockopt_impl!(Both, KeepAlive, libc::SOL_SOCKET, libc::SO_KEEPALIVE, bool);
++#[cfg(any(target_os = "android", target_os = "linux"))]
++sockopt_impl!(GetOnly, PeerCredentials, libc::SOL_SOCKET, libc::SO_PEERCRED, super::UnixCredentials);
++#[cfg(any(target_os = "ios",
++ target_os = "macos"))]
++sockopt_impl!(Both, TcpKeepAlive, libc::IPPROTO_TCP, libc::TCP_KEEPALIVE, u32);
++#[cfg(any(target_os = "android",
++ target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "linux",
++ target_os = "nacl"))]
++sockopt_impl!(Both, TcpKeepIdle, libc::IPPROTO_TCP, libc::TCP_KEEPIDLE, u32);
++sockopt_impl!(Both, RcvBuf, libc::SOL_SOCKET, libc::SO_RCVBUF, usize);
++sockopt_impl!(Both, SndBuf, libc::SOL_SOCKET, libc::SO_SNDBUF, usize);
++#[cfg(any(target_os = "android", target_os = "linux"))]
++sockopt_impl!(SetOnly, RcvBufForce, libc::SOL_SOCKET, libc::SO_RCVBUFFORCE, usize);
++#[cfg(any(target_os = "android", target_os = "linux"))]
++sockopt_impl!(SetOnly, SndBufForce, libc::SOL_SOCKET, libc::SO_SNDBUFFORCE, usize);
++sockopt_impl!(GetOnly, SockType, libc::SOL_SOCKET, libc::SO_TYPE, super::SockType);
++sockopt_impl!(GetOnly, AcceptConn, libc::SOL_SOCKET, libc::SO_ACCEPTCONN, bool);
++#[cfg(any(target_os = "android", target_os = "linux"))]
++sockopt_impl!(GetOnly, OriginalDst, libc::SOL_IP, libc::SO_ORIGINAL_DST, libc::sockaddr_in);
++sockopt_impl!(Both, ReceiveTimestamp, libc::SOL_SOCKET, libc::SO_TIMESTAMP, bool);
++#[cfg(any(target_os = "android", target_os = "linux"))]
++sockopt_impl!(Both, IpTransparent, libc::SOL_IP, libc::IP_TRANSPARENT, bool);
++#[cfg(target_os = "openbsd")]
++sockopt_impl!(Both, BindAny, libc::SOL_SOCKET, libc::SO_BINDANY, bool);
++#[cfg(target_os = "freebsd")]
++sockopt_impl!(Both, BindAny, libc::IPPROTO_IP, libc::IP_BINDANY, bool);
++#[cfg(target_os = "linux")]
++sockopt_impl!(Both, Mark, libc::SOL_SOCKET, libc::SO_MARK, u32);
++#[cfg(any(target_os = "android", target_os = "linux"))]
++sockopt_impl!(Both, PassCred, libc::SOL_SOCKET, libc::SO_PASSCRED, bool);
++#[cfg(any(target_os = "freebsd", target_os = "linux"))]
++sockopt_impl!(Both, TcpCongestion, libc::IPPROTO_TCP, libc::TCP_CONGESTION, OsString<[u8; TCP_CA_NAME_MAX]>);
++#[cfg(any(
++ target_os = "android",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos",
++ target_os = "netbsd",
++))]
++sockopt_impl!(Both, Ipv4PacketInfo, libc::IPPROTO_IP, libc::IP_PKTINFO, bool);
++#[cfg(any(
++ target_os = "android",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd",
++))]
++sockopt_impl!(Both, Ipv6RecvPacketInfo, libc::IPPROTO_IPV6, libc::IPV6_RECVPKTINFO, bool);
++#[cfg(any(
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd",
++))]
++sockopt_impl!(Both, Ipv4RecvIf, libc::IPPROTO_IP, libc::IP_RECVIF, bool);
++#[cfg(any(
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd",
++))]
++sockopt_impl!(Both, Ipv4RecvDstAddr, libc::IPPROTO_IP, libc::IP_RECVDSTADDR, bool);
++
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++#[derive(Copy, Clone, Debug)]
++pub struct AlgSetAeadAuthSize;
++
++// ALG_SET_AEAD_AUTH_SIZE read the length from passed `option_len`
++// See https://elixir.bootlin.com/linux/v4.4/source/crypto/af_alg.c#L222
++#[cfg(any(target_os = "android", target_os = "linux"))]
++impl SetSockOpt for AlgSetAeadAuthSize {
++ type Val = usize;
++
++ fn set(&self, fd: RawFd, val: &usize) -> Result<()> {
++ unsafe {
++ let res = libc::setsockopt(fd,
++ libc::SOL_ALG,
++ libc::ALG_SET_AEAD_AUTHSIZE,
++ ::std::ptr::null(),
++ *val as libc::socklen_t);
++ Errno::result(res).map(drop)
++ }
++ }
++}
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++#[derive(Clone, Debug)]
++pub struct AlgSetKey<T>(::std::marker::PhantomData<T>);
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++impl<T> Default for AlgSetKey<T> {
++ fn default() -> Self {
++ AlgSetKey(Default::default())
++ }
++}
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++impl<T> SetSockOpt for AlgSetKey<T> where T: AsRef<[u8]> + Clone {
++ type Val = T;
++
++ fn set(&self, fd: RawFd, val: &T) -> Result<()> {
++ unsafe {
++ let res = libc::setsockopt(fd,
++ libc::SOL_ALG,
++ libc::ALG_SET_KEY,
++ val.as_ref().as_ptr() as *const _,
++ val.as_ref().len() as libc::socklen_t);
++ Errno::result(res).map(drop)
++ }
++ }
++}
++
++/*
++ *
++ * ===== Accessor helpers =====
++ *
++ */
++
++/// Helper trait that describes what is expected from a `GetSockOpt` getter.
++unsafe trait Get<T> {
++ /// Returns an empty value.
++ unsafe fn blank() -> Self;
++ /// Returns a pointer to the stored value. This pointer will be passed to the system's
++ /// `getsockopt` call (`man 3p getsockopt`, argument `option_value`).
++ fn ffi_ptr(&mut self) -> *mut c_void;
++ /// Returns length of the stored value. This pointer will be passed to the system's
++ /// `getsockopt` call (`man 3p getsockopt`, argument `option_len`).
++ fn ffi_len(&mut self) -> *mut socklen_t;
++ /// Returns the stored value.
++ unsafe fn unwrap(self) -> T;
++}
++
++/// Helper trait that describes what is expected from a `SetSockOpt` setter.
++unsafe trait Set<'a, T> {
++ /// Initialize the setter with a given value.
++ fn new(val: &'a T) -> Self;
++ /// Returns a pointer to the stored value. This pointer will be passed to the system's
++ /// `setsockopt` call (`man 3p setsockopt`, argument `option_value`).
++ fn ffi_ptr(&self) -> *const c_void;
++ /// Returns length of the stored value. This pointer will be passed to the system's
++ /// `setsockopt` call (`man 3p setsockopt`, argument `option_len`).
++ fn ffi_len(&self) -> socklen_t;
++}
++
++/// Getter for an arbitrary `struct`.
++struct GetStruct<T> {
++ len: socklen_t,
++ val: T,
++}
++
++unsafe impl<T> Get<T> for GetStruct<T> {
++ unsafe fn blank() -> Self {
++ GetStruct {
++ len: mem::size_of::<T>() as socklen_t,
++ val: mem::zeroed(),
++ }
++ }
++
++ fn ffi_ptr(&mut self) -> *mut c_void {
++ &mut self.val as *mut T as *mut c_void
++ }
++
++ fn ffi_len(&mut self) -> *mut socklen_t {
++ &mut self.len
++ }
++
++ unsafe fn unwrap(self) -> T {
++ assert!(self.len as usize == mem::size_of::<T>(), "invalid getsockopt implementation");
++ self.val
++ }
++}
++
++/// Setter for an arbitrary `struct`.
++struct SetStruct<'a, T: 'static> {
++ ptr: &'a T,
++}
++
++unsafe impl<'a, T> Set<'a, T> for SetStruct<'a, T> {
++ fn new(ptr: &'a T) -> SetStruct<'a, T> {
++ SetStruct { ptr: ptr }
++ }
++
++ fn ffi_ptr(&self) -> *const c_void {
++ self.ptr as *const T as *const c_void
++ }
++
++ fn ffi_len(&self) -> socklen_t {
++ mem::size_of::<T>() as socklen_t
++ }
++}
++
++/// Getter for a boolean value.
++struct GetBool {
++ len: socklen_t,
++ val: c_int,
++}
++
++unsafe impl Get<bool> for GetBool {
++ unsafe fn blank() -> Self {
++ GetBool {
++ len: mem::size_of::<c_int>() as socklen_t,
++ val: mem::zeroed(),
++ }
++ }
++
++ fn ffi_ptr(&mut self) -> *mut c_void {
++ &mut self.val as *mut c_int as *mut c_void
++ }
++
++ fn ffi_len(&mut self) -> *mut socklen_t {
++ &mut self.len
++ }
++
++ unsafe fn unwrap(self) -> bool {
++ assert!(self.len as usize == mem::size_of::<c_int>(), "invalid getsockopt implementation");
++ self.val != 0
++ }
++}
++
++/// Setter for a boolean value.
++struct SetBool {
++ val: c_int,
++}
++
++unsafe impl<'a> Set<'a, bool> for SetBool {
++ fn new(val: &'a bool) -> SetBool {
++ SetBool { val: if *val { 1 } else { 0 } }
++ }
++
++ fn ffi_ptr(&self) -> *const c_void {
++ &self.val as *const c_int as *const c_void
++ }
++
++ fn ffi_len(&self) -> socklen_t {
++ mem::size_of::<c_int>() as socklen_t
++ }
++}
++
++/// Getter for an `u8` value.
++struct GetU8 {
++ len: socklen_t,
++ val: u8,
++}
++
++unsafe impl Get<u8> for GetU8 {
++ unsafe fn blank() -> Self {
++ GetU8 {
++ len: mem::size_of::<u8>() as socklen_t,
++ val: mem::zeroed(),
++ }
++ }
++
++ fn ffi_ptr(&mut self) -> *mut c_void {
++ &mut self.val as *mut u8 as *mut c_void
++ }
++
++ fn ffi_len(&mut self) -> *mut socklen_t {
++ &mut self.len
++ }
++
++ unsafe fn unwrap(self) -> u8 {
++ assert!(self.len as usize == mem::size_of::<u8>(), "invalid getsockopt implementation");
++ self.val as u8
++ }
++}
++
++/// Setter for an `u8` value.
++struct SetU8 {
++ val: u8,
++}
++
++unsafe impl<'a> Set<'a, u8> for SetU8 {
++ fn new(val: &'a u8) -> SetU8 {
++ SetU8 { val: *val as u8 }
++ }
++
++ fn ffi_ptr(&self) -> *const c_void {
++ &self.val as *const u8 as *const c_void
++ }
++
++ fn ffi_len(&self) -> socklen_t {
++ mem::size_of::<c_int>() as socklen_t
++ }
++}
++
++/// Getter for an `usize` value.
++struct GetUsize {
++ len: socklen_t,
++ val: c_int,
++}
++
++unsafe impl Get<usize> for GetUsize {
++ unsafe fn blank() -> Self {
++ GetUsize {
++ len: mem::size_of::<c_int>() as socklen_t,
++ val: mem::zeroed(),
++ }
++ }
++
++ fn ffi_ptr(&mut self) -> *mut c_void {
++ &mut self.val as *mut c_int as *mut c_void
++ }
++
++ fn ffi_len(&mut self) -> *mut socklen_t {
++ &mut self.len
++ }
++
++ unsafe fn unwrap(self) -> usize {
++ assert!(self.len as usize == mem::size_of::<c_int>(), "invalid getsockopt implementation");
++ self.val as usize
++ }
++}
++
++/// Setter for an `usize` value.
++struct SetUsize {
++ val: c_int,
++}
++
++unsafe impl<'a> Set<'a, usize> for SetUsize {
++ fn new(val: &'a usize) -> SetUsize {
++ SetUsize { val: *val as c_int }
++ }
++
++ fn ffi_ptr(&self) -> *const c_void {
++ &self.val as *const c_int as *const c_void
++ }
++
++ fn ffi_len(&self) -> socklen_t {
++ mem::size_of::<c_int>() as socklen_t
++ }
++}
++
++/// Getter for a `OsString` value.
++struct GetOsString<T: AsMut<[u8]>> {
++ len: socklen_t,
++ val: T,
++}
++
++unsafe impl<T: AsMut<[u8]>> Get<OsString> for GetOsString<T> {
++ unsafe fn blank() -> Self {
++ GetOsString {
++ len: mem::size_of::<T>() as socklen_t,
++ val: mem::zeroed(),
++ }
++ }
++
++ fn ffi_ptr(&mut self) -> *mut c_void {
++ &mut self.val as *mut T as *mut c_void
++ }
++
++ fn ffi_len(&mut self) -> *mut socklen_t {
++ &mut self.len
++ }
++
++ unsafe fn unwrap(mut self) -> OsString {
++ OsStr::from_bytes(self.val.as_mut()).to_owned()
++ }
++}
++
++/// Setter for a `OsString` value.
++struct SetOsString<'a> {
++ val: &'a OsStr,
++}
++
++unsafe impl<'a> Set<'a, OsString> for SetOsString<'a> {
++ fn new(val: &'a OsString) -> SetOsString {
++ SetOsString { val: val.as_os_str() }
++ }
++
++ fn ffi_ptr(&self) -> *const c_void {
++ self.val.as_bytes().as_ptr() as *const c_void
++ }
++
++ fn ffi_len(&self) -> socklen_t {
++ self.val.len() as socklen_t
++ }
++}
++
++
++#[cfg(test)]
++mod test {
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ #[test]
++ fn can_get_peercred_on_unix_socket() {
++ use super::super::*;
++
++ let (a, b) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()).unwrap();
++ let a_cred = getsockopt(a, super::PeerCredentials).unwrap();
++ let b_cred = getsockopt(b, super::PeerCredentials).unwrap();
++ assert_eq!(a_cred, b_cred);
++ assert!(a_cred.pid() != 0);
++ }
++
++ #[test]
++ fn is_socket_type_unix() {
++ use super::super::*;
++ use ::unistd::close;
++
++ let (a, b) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()).unwrap();
++ let a_type = getsockopt(a, super::SockType).unwrap();
++ assert!(a_type == SockType::Stream);
++ close(a).unwrap();
++ close(b).unwrap();
++ }
++
++ #[test]
++ fn is_socket_type_dgram() {
++ use super::super::*;
++ use ::unistd::close;
++
++ let s = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), None).unwrap();
++ let s_type = getsockopt(s, super::SockType).unwrap();
++ assert!(s_type == SockType::Datagram);
++ close(s).unwrap();
++ }
++
++ #[cfg(any(target_os = "freebsd",
++ target_os = "linux",
++ target_os = "nacl"))]
++ #[test]
++ fn can_get_listen_on_tcp_socket() {
++ use super::super::*;
++ use ::unistd::close;
++
++ let s = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap();
++ let s_listening = getsockopt(s, super::AcceptConn).unwrap();
++ assert!(!s_listening);
++ listen(s, 10).unwrap();
++ let s_listening2 = getsockopt(s, super::AcceptConn).unwrap();
++ assert!(s_listening2);
++ close(s).unwrap();
++ }
++
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/stat.rs b/third_party/rust/nix-0.15.0/src/sys/stat.rs
+new file mode 100644
+index 0000000000000..66c8c9dd1b720
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/stat.rs
+@@ -0,0 +1,294 @@
++pub use libc::{dev_t, mode_t};
++pub use libc::stat as FileStat;
++
++use {Result, NixPath};
++use errno::Errno;
++use fcntl::{AtFlags, at_rawfd};
++use libc;
++use std::mem;
++use std::os::unix::io::RawFd;
++use sys::time::{TimeSpec, TimeVal};
++
++libc_bitflags!(
++ pub struct SFlag: mode_t {
++ S_IFIFO;
++ S_IFCHR;
++ S_IFDIR;
++ S_IFBLK;
++ S_IFREG;
++ S_IFLNK;
++ S_IFSOCK;
++ S_IFMT;
++ }
++);
++
++libc_bitflags! {
++ pub struct Mode: mode_t {
++ S_IRWXU;
++ S_IRUSR;
++ S_IWUSR;
++ S_IXUSR;
++ S_IRWXG;
++ S_IRGRP;
++ S_IWGRP;
++ S_IXGRP;
++ S_IRWXO;
++ S_IROTH;
++ S_IWOTH;
++ S_IXOTH;
++ S_ISUID as mode_t;
++ S_ISGID as mode_t;
++ S_ISVTX as mode_t;
++ }
++}
++
++pub fn mknod<P: ?Sized + NixPath>(path: &P, kind: SFlag, perm: Mode, dev: dev_t) -> Result<()> {
++ let res = path.with_nix_path(|cstr| {
++ unsafe {
++ libc::mknod(cstr.as_ptr(), kind.bits | perm.bits() as mode_t, dev)
++ }
++ })?;
++
++ Errno::result(res).map(drop)
++}
++
++#[cfg(target_os = "linux")]
++pub fn major(dev: dev_t) -> u64 {
++ ((dev >> 32) & 0xffff_f000) |
++ ((dev >> 8) & 0x0000_0fff)
++}
++
++#[cfg(target_os = "linux")]
++pub fn minor(dev: dev_t) -> u64 {
++ ((dev >> 12) & 0xffff_ff00) |
++ ((dev ) & 0x0000_00ff)
++}
++
++#[cfg(target_os = "linux")]
++pub fn makedev(major: u64, minor: u64) -> dev_t {
++ ((major & 0xffff_f000) << 32) |
++ ((major & 0x0000_0fff) << 8) |
++ ((minor & 0xffff_ff00) << 12) |
++ (minor & 0x0000_00ff)
++}
++
++pub fn umask(mode: Mode) -> Mode {
++ let prev = unsafe { libc::umask(mode.bits() as mode_t) };
++ Mode::from_bits(prev).expect("[BUG] umask returned invalid Mode")
++}
++
++pub fn stat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> {
++ let mut dst = unsafe { mem::uninitialized() };
++ let res = path.with_nix_path(|cstr| {
++ unsafe {
++ libc::stat(cstr.as_ptr(), &mut dst as *mut FileStat)
++ }
++ })?;
++
++ Errno::result(res)?;
++
++ Ok(dst)
++}
++
++pub fn lstat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> {
++ let mut dst = unsafe { mem::uninitialized() };
++ let res = path.with_nix_path(|cstr| {
++ unsafe {
++ libc::lstat(cstr.as_ptr(), &mut dst as *mut FileStat)
++ }
++ })?;
++
++ Errno::result(res)?;
++
++ Ok(dst)
++}
++
++pub fn fstat(fd: RawFd) -> Result<FileStat> {
++ let mut dst = unsafe { mem::uninitialized() };
++ let res = unsafe { libc::fstat(fd, &mut dst as *mut FileStat) };
++
++ Errno::result(res)?;
++
++ Ok(dst)
++}
++
++pub fn fstatat<P: ?Sized + NixPath>(dirfd: RawFd, pathname: &P, f: AtFlags) -> Result<FileStat> {
++ let mut dst = unsafe { mem::uninitialized() };
++ let res = pathname.with_nix_path(|cstr| {
++ unsafe { libc::fstatat(dirfd, cstr.as_ptr(), &mut dst as *mut FileStat, f.bits() as libc::c_int) }
++ })?;
++
++ Errno::result(res)?;
++
++ Ok(dst)
++}
++
++/// Change the file permission bits of the file specified by a file descriptor.
++///
++/// # References
++///
++/// [fchmod(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmod.html).
++pub fn fchmod(fd: RawFd, mode: Mode) -> Result<()> {
++ let res = unsafe { libc::fchmod(fd, mode.bits() as mode_t) };
++
++ Errno::result(res).map(drop)
++}
++
++/// Flags for `fchmodat` function.
++#[derive(Clone, Copy, Debug)]
++pub enum FchmodatFlags {
++ FollowSymlink,
++ NoFollowSymlink,
++}
++
++/// Change the file permission bits.
++///
++/// The file to be changed is determined relative to the directory associated
++/// with the file descriptor `dirfd` or the current working directory
++/// if `dirfd` is `None`.
++///
++/// If `flag` is `FchmodatFlags::NoFollowSymlink` and `path` names a symbolic link,
++/// then the mode of the symbolic link is changed.
++///
++/// `fchmod(None, path, mode, FchmodatFlags::FollowSymlink)` is identical to
++/// a call `libc::chmod(path, mode)`. That's why `chmod` is unimplemented
++/// in the `nix` crate.
++///
++/// # References
++///
++/// [fchmodat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmodat.html).
++pub fn fchmodat<P: ?Sized + NixPath>(
++ dirfd: Option<RawFd>,
++ path: &P,
++ mode: Mode,
++ flag: FchmodatFlags,
++) -> Result<()> {
++ let atflag =
++ match flag {
++ FchmodatFlags::FollowSymlink => AtFlags::empty(),
++ FchmodatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW,
++ };
++ let res = path.with_nix_path(|cstr| unsafe {
++ libc::fchmodat(
++ at_rawfd(dirfd),
++ cstr.as_ptr(),
++ mode.bits() as mode_t,
++ atflag.bits() as libc::c_int,
++ )
++ })?;
++
++ Errno::result(res).map(drop)
++}
++
++/// Change the access and modification times of a file.
++///
++/// `utimes(path, times)` is identical to
++/// `utimensat(None, path, times, UtimensatFlags::FollowSymlink)`. The former
++/// is a deprecated API so prefer using the latter if the platforms you care
++/// about support it.
++///
++/// # References
++///
++/// [utimes(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/utimes.html).
++pub fn utimes<P: ?Sized + NixPath>(path: &P, atime: &TimeVal, mtime: &TimeVal) -> Result<()> {
++ let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()];
++ let res = path.with_nix_path(|cstr| unsafe {
++ libc::utimes(cstr.as_ptr(), &times[0])
++ })?;
++
++ Errno::result(res).map(drop)
++}
++
++/// Change the access and modification times of a file without following symlinks.
++///
++/// `lutimes(path, times)` is identical to
++/// `utimensat(None, path, times, UtimensatFlags::NoFollowSymlink)`. The former
++/// is a deprecated API so prefer using the latter if the platforms you care
++/// about support it.
++///
++/// # References
++///
++/// [lutimes(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/lutimes.html).
++#[cfg(any(target_os = "linux",
++ target_os = "haiku",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "freebsd",
++ target_os = "netbsd"))]
++pub fn lutimes<P: ?Sized + NixPath>(path: &P, atime: &TimeVal, mtime: &TimeVal) -> Result<()> {
++ let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()];
++ let res = path.with_nix_path(|cstr| unsafe {
++ libc::lutimes(cstr.as_ptr(), &times[0])
++ })?;
++
++ Errno::result(res).map(drop)
++}
++
++/// Change the access and modification times of the file specified by a file descriptor.
++///
++/// # References
++///
++/// [futimens(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html).
++#[inline]
++pub fn futimens(fd: RawFd, atime: &TimeSpec, mtime: &TimeSpec) -> Result<()> {
++ let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()];
++ let res = unsafe { libc::futimens(fd, &times[0]) };
++
++ Errno::result(res).map(drop)
++}
++
++/// Flags for `utimensat` function.
++#[derive(Clone, Copy, Debug)]
++pub enum UtimensatFlags {
++ FollowSymlink,
++ NoFollowSymlink,
++}
++
++/// Change the access and modification times of a file.
++///
++/// The file to be changed is determined relative to the directory associated
++/// with the file descriptor `dirfd` or the current working directory
++/// if `dirfd` is `None`.
++///
++/// If `flag` is `UtimensatFlags::NoFollowSymlink` and `path` names a symbolic link,
++/// then the mode of the symbolic link is changed.
++///
++/// `utimensat(None, path, times, UtimensatFlags::FollowSymlink)` is identical to
++/// `utimes(path, times)`. The latter is a deprecated API so prefer using the
++/// former if the platforms you care about support it.
++///
++/// # References
++///
++/// [utimensat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/utimens.html).
++pub fn utimensat<P: ?Sized + NixPath>(
++ dirfd: Option<RawFd>,
++ path: &P,
++ atime: &TimeSpec,
++ mtime: &TimeSpec,
++ flag: UtimensatFlags
++) -> Result<()> {
++ let atflag =
++ match flag {
++ UtimensatFlags::FollowSymlink => AtFlags::empty(),
++ UtimensatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW,
++ };
++ let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()];
++ let res = path.with_nix_path(|cstr| unsafe {
++ libc::utimensat(
++ at_rawfd(dirfd),
++ cstr.as_ptr(),
++ &times[0],
++ atflag.bits() as libc::c_int,
++ )
++ })?;
++
++ Errno::result(res).map(drop)
++}
++
++pub fn mkdirat<P: ?Sized + NixPath>(fd: RawFd, path: &P, mode: Mode) -> Result<()> {
++ let res = path.with_nix_path(|cstr| {
++ unsafe { libc::mkdirat(fd, cstr.as_ptr(), mode.bits() as mode_t) }
++ })?;
++
++ Errno::result(res).map(drop)
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/statfs.rs b/third_party/rust/nix-0.15.0/src/sys/statfs.rs
+new file mode 100644
+index 0000000000000..d4596bf336958
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/statfs.rs
+@@ -0,0 +1,548 @@
++use std::fmt::{self, Debug};
++use std::mem;
++use std::os::unix::io::AsRawFd;
++#[cfg(not(any(target_os = "linux", target_os = "android")))]
++use std::ffi::CStr;
++
++use libc;
++
++use {NixPath, Result};
++use errno::Errno;
++
++#[cfg(target_os = "android")]
++pub type fsid_t = libc::__fsid_t;
++#[cfg(not(target_os = "android"))]
++pub type fsid_t = libc::fsid_t;
++
++#[derive(Clone, Copy)]
++pub struct Statfs(libc::statfs);
++
++#[cfg(target_os = "freebsd")]
++#[derive(Eq, Copy, Clone, PartialEq, Debug)]
++pub struct FsType(u32);
++#[cfg(target_os = "android")]
++#[derive(Eq, Copy, Clone, PartialEq, Debug)]
++pub struct FsType(libc::c_ulong);
++#[cfg(all(target_os = "linux", target_arch = "s390x"))]
++#[derive(Eq, Copy, Clone, PartialEq, Debug)]
++pub struct FsType(u32);
++#[cfg(all(target_os = "linux", target_env = "musl"))]
++#[derive(Eq, Copy, Clone, PartialEq, Debug)]
++pub struct FsType(libc::c_ulong);
++#[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))]
++#[derive(Eq, Copy, Clone, PartialEq, Debug)]
++pub struct FsType(libc::c_long);
++
++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
++pub const ADFS_SUPER_MAGIC: FsType = FsType(libc::ADFS_SUPER_MAGIC);
++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
++pub const AFFS_SUPER_MAGIC: FsType = FsType(libc::AFFS_SUPER_MAGIC);
++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
++pub const CODA_SUPER_MAGIC: FsType = FsType(libc::CODA_SUPER_MAGIC);
++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
++pub const CRAMFS_MAGIC: FsType = FsType(libc::CRAMFS_MAGIC);
++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
++pub const EFS_SUPER_MAGIC: FsType = FsType(libc::EFS_SUPER_MAGIC);
++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
++pub const EXT2_SUPER_MAGIC: FsType = FsType(libc::EXT2_SUPER_MAGIC);
++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
++pub const EXT3_SUPER_MAGIC: FsType = FsType(libc::EXT3_SUPER_MAGIC);
++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
++pub const EXT4_SUPER_MAGIC: FsType = FsType(libc::EXT4_SUPER_MAGIC);
++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
++pub const HPFS_SUPER_MAGIC: FsType = FsType(libc::HPFS_SUPER_MAGIC);
++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
++pub const HUGETLBFS_MAGIC: FsType = FsType(libc::HUGETLBFS_MAGIC);
++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
++pub const ISOFS_SUPER_MAGIC: FsType = FsType(libc::ISOFS_SUPER_MAGIC);
++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
++pub const JFFS2_SUPER_MAGIC: FsType = FsType(libc::JFFS2_SUPER_MAGIC);
++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
++pub const MINIX_SUPER_MAGIC: FsType = FsType(libc::MINIX_SUPER_MAGIC);
++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
++pub const MINIX_SUPER_MAGIC2: FsType = FsType(libc::MINIX_SUPER_MAGIC2);
++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
++pub const MINIX2_SUPER_MAGIC: FsType = FsType(libc::MINIX2_SUPER_MAGIC);
++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
++pub const MINIX2_SUPER_MAGIC2: FsType = FsType(libc::MINIX2_SUPER_MAGIC2);
++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
++pub const MSDOS_SUPER_MAGIC: FsType = FsType(libc::MSDOS_SUPER_MAGIC);
++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
++pub const NCP_SUPER_MAGIC: FsType = FsType(libc::NCP_SUPER_MAGIC);
++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
++pub const NFS_SUPER_MAGIC: FsType = FsType(libc::NFS_SUPER_MAGIC);
++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
++pub const OPENPROM_SUPER_MAGIC: FsType = FsType(libc::OPENPROM_SUPER_MAGIC);
++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
++pub const PROC_SUPER_MAGIC: FsType = FsType(libc::PROC_SUPER_MAGIC);
++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
++pub const QNX4_SUPER_MAGIC: FsType = FsType(libc::QNX4_SUPER_MAGIC);
++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
++pub const REISERFS_SUPER_MAGIC: FsType = FsType(libc::REISERFS_SUPER_MAGIC);
++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
++pub const SMB_SUPER_MAGIC: FsType = FsType(libc::SMB_SUPER_MAGIC);
++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
++pub const TMPFS_MAGIC: FsType = FsType(libc::TMPFS_MAGIC);
++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
++pub const USBDEVICE_SUPER_MAGIC: FsType = FsType(libc::USBDEVICE_SUPER_MAGIC);
++
++impl Statfs {
++ /// Magic code defining system type
++ #[cfg(not(any(
++ target_os = "openbsd",
++ target_os = "ios",
++ target_os = "macos"
++ )))]
++ pub fn filesystem_type(&self) -> FsType {
++ FsType(self.0.f_type)
++ }
++
++ /// Magic code defining system type
++ #[cfg(not(any(target_os = "linux", target_os = "android")))]
++ pub fn filesystem_type_name(&self) -> &str {
++ let c_str = unsafe { CStr::from_ptr(self.0.f_fstypename.as_ptr()) };
++ c_str.to_str().unwrap()
++ }
++
++ /// Optimal transfer block size
++ #[cfg(any(target_os = "ios", target_os = "macos", target_os = "openbsd"))]
++ pub fn optimal_transfer_size(&self) -> i32 {
++ self.0.f_iosize
++ }
++
++ /// Optimal transfer block size
++ #[cfg(all(target_os = "linux", target_arch = "s390x"))]
++ pub fn optimal_transfer_size(&self) -> u32 {
++ self.0.f_bsize
++ }
++
++ /// Optimal transfer block size
++ #[cfg(all(target_os = "linux", target_env = "musl"))]
++ pub fn optimal_transfer_size(&self) -> libc::c_ulong {
++ self.0.f_bsize
++ }
++
++ /// Optimal transfer block size
++ #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))]
++ pub fn optimal_transfer_size(&self) -> libc::c_long {
++ self.0.f_bsize
++ }
++
++ /// Optimal transfer block size
++ #[cfg(target_os = "android")]
++ pub fn optimal_transfer_size(&self) -> libc::c_ulong {
++ self.0.f_bsize
++ }
++
++ /// Optimal transfer block size
++ #[cfg(target_os = "dragonfly")]
++ pub fn optimal_transfer_size(&self) -> libc::c_long {
++ self.0.f_iosize
++ }
++
++ /// Optimal transfer block size
++ #[cfg(target_os = "freebsd")]
++ pub fn optimal_transfer_size(&self) -> u64 {
++ self.0.f_iosize
++ }
++
++ /// Size of a block
++ #[cfg(any(target_os = "ios", target_os = "macos", target_os = "openbsd"))]
++ pub fn block_size(&self) -> u32 {
++ self.0.f_bsize
++ }
++
++ /// Size of a block
++ // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471
++ #[cfg(all(target_os = "linux", target_arch = "s390x"))]
++ pub fn block_size(&self) -> u32 {
++ self.0.f_bsize
++ }
++
++ /// Size of a block
++ // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471
++ #[cfg(all(target_os = "linux", target_env = "musl"))]
++ pub fn block_size(&self) -> libc::c_ulong {
++ self.0.f_bsize
++ }
++
++ /// Size of a block
++ // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471
++ #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))]
++ pub fn block_size(&self) -> libc::c_long {
++ self.0.f_bsize
++ }
++
++ /// Size of a block
++ #[cfg(target_os = "freebsd")]
++ pub fn block_size(&self) -> u64 {
++ self.0.f_bsize
++ }
++
++ /// Size of a block
++ #[cfg(target_os = "android")]
++ pub fn block_size(&self) -> libc::c_ulong {
++ self.0.f_bsize
++ }
++
++ /// Size of a block
++ #[cfg(target_os = "dragonfly")]
++ pub fn block_size(&self) -> libc::c_long {
++ self.0.f_bsize
++ }
++
++ /// Maximum length of filenames
++ #[cfg(any(target_os = "freebsd", target_os = "openbsd"))]
++ pub fn maximum_name_length(&self) -> u32 {
++ self.0.f_namemax
++ }
++
++ /// Maximum length of filenames
++ #[cfg(all(target_os = "linux", target_arch = "s390x"))]
++ pub fn maximum_name_length(&self) -> u32 {
++ self.0.f_namelen
++ }
++
++ /// Maximum length of filenames
++ #[cfg(all(target_os = "linux", target_env = "musl"))]
++ pub fn maximum_name_length(&self) -> libc::c_ulong {
++ self.0.f_namelen
++ }
++
++ /// Maximum length of filenames
++ #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))]
++ pub fn maximum_name_length(&self) -> libc::c_long {
++ self.0.f_namelen
++ }
++
++ /// Maximum length of filenames
++ #[cfg(target_os = "android")]
++ pub fn maximum_name_length(&self) -> libc::c_ulong {
++ self.0.f_namelen
++ }
++
++ /// Total data blocks in filesystem
++ #[cfg(any(
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "android",
++ target_os = "freebsd",
++ target_os = "openbsd",
++ ))]
++ pub fn blocks(&self) -> u64 {
++ self.0.f_blocks
++ }
++
++ /// Total data blocks in filesystem
++ #[cfg(target_os = "dragonfly")]
++ pub fn blocks(&self) -> libc::c_long {
++ self.0.f_blocks
++ }
++
++ /// Total data blocks in filesystem
++ #[cfg(all(target_os = "linux", target_env = "musl"))]
++ pub fn blocks(&self) -> u64 {
++ self.0.f_blocks
++ }
++
++ /// Total data blocks in filesystem
++ #[cfg(not(any(
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "android",
++ target_os = "freebsd",
++ target_os = "openbsd",
++ target_os = "dragonfly",
++ all(target_os = "linux", target_env = "musl")
++ )))]
++ pub fn blocks(&self) -> libc::c_ulong {
++ self.0.f_blocks
++ }
++
++ /// Free blocks in filesystem
++ #[cfg(any(
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "android",
++ target_os = "freebsd",
++ target_os = "openbsd",
++ ))]
++ pub fn blocks_free(&self) -> u64 {
++ self.0.f_bfree
++ }
++
++ /// Free blocks in filesystem
++ #[cfg(target_os = "dragonfly")]
++ pub fn blocks_free(&self) -> libc::c_long {
++ self.0.f_bfree
++ }
++
++ /// Free blocks in filesystem
++ #[cfg(all(target_os = "linux", target_env = "musl"))]
++ pub fn blocks_free(&self) -> u64 {
++ self.0.f_bfree
++ }
++
++ /// Free blocks in filesystem
++ #[cfg(not(any(
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "android",
++ target_os = "freebsd",
++ target_os = "openbsd",
++ target_os = "dragonfly",
++ all(target_os = "linux", target_env = "musl")
++ )))]
++ pub fn blocks_free(&self) -> libc::c_ulong {
++ self.0.f_bfree
++ }
++
++ /// Free blocks available to unprivileged user
++ #[cfg(any(target_os = "ios", target_os = "macos", target_os = "android"))]
++ pub fn blocks_available(&self) -> u64 {
++ self.0.f_bavail
++ }
++
++ /// Free blocks available to unprivileged user
++ #[cfg(target_os = "dragonfly")]
++ pub fn blocks_available(&self) -> libc::c_long {
++ self.0.f_bavail
++ }
++
++ /// Free blocks available to unprivileged user
++ #[cfg(any(target_os = "freebsd", target_os = "openbsd"))]
++ pub fn blocks_available(&self) -> i64 {
++ self.0.f_bavail
++ }
++
++ /// Free blocks available to unprivileged user
++ #[cfg(all(target_os = "linux", target_env = "musl"))]
++ pub fn blocks_available(&self) -> u64 {
++ self.0.f_bavail
++ }
++
++ /// Free blocks available to unprivileged user
++ #[cfg(not(any(
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "android",
++ target_os = "freebsd",
++ target_os = "openbsd",
++ target_os = "dragonfly",
++ all(target_os = "linux", target_env = "musl")
++ )))]
++ pub fn blocks_available(&self) -> libc::c_ulong {
++ self.0.f_bavail
++ }
++
++ /// Total file nodes in filesystem
++ #[cfg(any(
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "android",
++ target_os = "freebsd",
++ target_os = "openbsd",
++ ))]
++ pub fn files(&self) -> u64 {
++ self.0.f_files
++ }
++
++ /// Total file nodes in filesystem
++ #[cfg(target_os = "dragonfly")]
++ pub fn files(&self) -> libc::c_long {
++ self.0.f_files
++ }
++
++ /// Total file nodes in filesystem
++ #[cfg(all(target_os = "linux", target_env = "musl"))]
++ pub fn files(&self) -> u64 {
++ self.0.f_files
++ }
++
++ /// Total file nodes in filesystem
++ #[cfg(not(any(
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "android",
++ target_os = "freebsd",
++ target_os = "openbsd",
++ target_os = "dragonfly",
++ all(target_os = "linux", target_env = "musl")
++ )))]
++ pub fn files(&self) -> libc::c_ulong {
++ self.0.f_files
++ }
++
++ /// Free file nodes in filesystem
++ #[cfg(any(target_os = "ios", target_os = "macos", target_os = "android"))]
++ pub fn files_free(&self) -> u64 {
++ self.0.f_ffree
++ }
++
++ /// Free file nodes in filesystem
++ #[cfg(target_os = "dragonfly")]
++ pub fn files_free(&self) -> libc::c_long {
++ self.0.f_ffree
++ }
++
++ /// Free file nodes in filesystem
++ #[cfg(any(target_os = "freebsd", target_os = "openbsd"))]
++ pub fn files_free(&self) -> i64 {
++ self.0.f_ffree
++ }
++
++ /// Free file nodes in filesystem
++ #[cfg(all(target_os = "linux", target_env = "musl"))]
++ pub fn files_free(&self) -> u64 {
++ self.0.f_ffree
++ }
++
++ /// Free file nodes in filesystem
++ #[cfg(not(any(
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "android",
++ target_os = "freebsd",
++ target_os = "openbsd",
++ target_os = "dragonfly",
++ all(target_os = "linux", target_env = "musl")
++ )))]
++ pub fn files_free(&self) -> libc::c_ulong {
++ self.0.f_ffree
++ }
++
++ /// Filesystem ID
++ pub fn filesystem_id(&self) -> fsid_t {
++ self.0.f_fsid
++ }
++}
++
++impl Debug for Statfs {
++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++ f.debug_struct("Statfs")
++ .field("optimal_transfer_size", &self.optimal_transfer_size())
++ .field("block_size", &self.block_size())
++ .field("blocks", &self.blocks())
++ .field("blocks_free", &self.blocks_free())
++ .field("blocks_available", &self.blocks_available())
++ .field("files", &self.files())
++ .field("files_free", &self.files_free())
++ .field("filesystem_id", &self.filesystem_id())
++ .finish()
++ }
++}
++
++pub fn statfs<P: ?Sized + NixPath>(path: &P) -> Result<Statfs> {
++ unsafe {
++ let mut stat: Statfs = mem::uninitialized();
++ let res = path.with_nix_path(|path| libc::statfs(path.as_ptr(), &mut stat.0))?;
++ Errno::result(res).map(|_| stat)
++ }
++}
++
++pub fn fstatfs<T: AsRawFd>(fd: &T) -> Result<Statfs> {
++ unsafe {
++ let mut stat: Statfs = mem::uninitialized();
++ Errno::result(libc::fstatfs(fd.as_raw_fd(), &mut stat.0)).map(|_| stat)
++ }
++}
++
++#[cfg(test)]
++mod test {
++ use std::fs::File;
++
++ use sys::statfs::*;
++ use sys::statvfs::*;
++ use std::path::Path;
++
++ #[test]
++ fn statfs_call() {
++ check_statfs("/tmp");
++ check_statfs("/dev");
++ check_statfs("/run");
++ check_statfs("/");
++ }
++
++ #[test]
++ fn fstatfs_call() {
++ check_fstatfs("/tmp");
++ check_fstatfs("/dev");
++ check_fstatfs("/run");
++ check_fstatfs("/");
++ }
++
++ fn check_fstatfs(path: &str) {
++ if !Path::new(path).exists() {
++ return;
++ }
++ let vfs = statvfs(path.as_bytes()).unwrap();
++ let file = File::open(path).unwrap();
++ let fs = fstatfs(&file).unwrap();
++ assert_fs_equals(fs, vfs);
++ }
++
++ fn check_statfs(path: &str) {
++ if !Path::new(path).exists() {
++ return;
++ }
++ let vfs = statvfs(path.as_bytes()).unwrap();
++ let fs = statfs(path.as_bytes()).unwrap();
++ assert_fs_equals(fs, vfs);
++ }
++
++ fn assert_fs_equals(fs: Statfs, vfs: Statvfs) {
++ assert_eq!(fs.files() as u64, vfs.files() as u64);
++ assert_eq!(fs.blocks() as u64, vfs.blocks() as u64);
++ assert_eq!(fs.block_size() as u64, vfs.fragment_size() as u64);
++ }
++
++ // This test is ignored because files_free/blocks_free can change after statvfs call and before
++ // statfs call.
++ #[test]
++ #[ignore]
++ fn statfs_call_strict() {
++ check_statfs_strict("/tmp");
++ check_statfs_strict("/dev");
++ check_statfs_strict("/run");
++ check_statfs_strict("/");
++ }
++
++ // This test is ignored because files_free/blocks_free can change after statvfs call and before
++ // fstatfs call.
++ #[test]
++ #[ignore]
++ fn fstatfs_call_strict() {
++ check_fstatfs_strict("/tmp");
++ check_fstatfs_strict("/dev");
++ check_fstatfs_strict("/run");
++ check_fstatfs_strict("/");
++ }
++
++ fn check_fstatfs_strict(path: &str) {
++ if !Path::new(path).exists() {
++ return;
++ }
++ let vfs = statvfs(path.as_bytes());
++ let file = File::open(path).unwrap();
++ let fs = fstatfs(&file);
++ assert_fs_equals_strict(fs.unwrap(), vfs.unwrap())
++ }
++
++ fn check_statfs_strict(path: &str) {
++ if !Path::new(path).exists() {
++ return;
++ }
++ let vfs = statvfs(path.as_bytes());
++ let fs = statfs(path.as_bytes());
++ assert_fs_equals_strict(fs.unwrap(), vfs.unwrap())
++ }
++
++ fn assert_fs_equals_strict(fs: Statfs, vfs: Statvfs) {
++ assert_eq!(fs.files_free() as u64, vfs.files_free() as u64);
++ assert_eq!(fs.blocks_free() as u64, vfs.blocks_free() as u64);
++ assert_eq!(fs.blocks_available() as u64, vfs.blocks_available() as u64);
++ assert_eq!(fs.files() as u64, vfs.files() as u64);
++ assert_eq!(fs.blocks() as u64, vfs.blocks() as u64);
++ assert_eq!(fs.block_size() as u64, vfs.fragment_size() as u64);
++ }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/statvfs.rs b/third_party/rust/nix-0.15.0/src/sys/statvfs.rs
+new file mode 100644
+index 0000000000000..e5980369d5119
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/statvfs.rs
+@@ -0,0 +1,160 @@
++//! Get filesystem statistics
++//!
++//! See [the man pages](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fstatvfs.html)
++//! for more details.
++use std::mem;
++use std::os::unix::io::AsRawFd;
++
++use libc::{self, c_ulong};
++
++use {Result, NixPath};
++use errno::Errno;
++
++libc_bitflags!(
++ /// File system mount Flags
++ #[repr(C)]
++ #[derive(Default)]
++ pub struct FsFlags: c_ulong {
++ /// Read Only
++ ST_RDONLY;
++ /// Do not allow the set-uid bits to have an effect
++ ST_NOSUID;
++ /// Do not interpret character or block-special devices
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ ST_NODEV;
++ /// Do not allow execution of binaries on the filesystem
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ ST_NOEXEC;
++ /// All IO should be done synchronously
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ ST_SYNCHRONOUS;
++ /// Allow mandatory locks on the filesystem
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ ST_MANDLOCK;
++ /// Write on file/directory/symlink
++ #[cfg(target_os = "linux")]
++ ST_WRITE;
++ /// Append-only file
++ #[cfg(target_os = "linux")]
++ ST_APPEND;
++ /// Immutable file
++ #[cfg(target_os = "linux")]
++ ST_IMMUTABLE;
++ /// Do not update access times on files
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ ST_NOATIME;
++ /// Do not update access times on files
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ ST_NODIRATIME;
++ /// Update access time relative to modify/change time
++ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_env = "musl"))))]
++ ST_RELATIME;
++ }
++);
++
++/// Wrapper around the POSIX `statvfs` struct
++///
++/// For more information see the [`statvfs(3)` man pages](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_statvfs.h.html).
++// FIXME: Replace with repr(transparent)
++#[repr(C)]
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub struct Statvfs(libc::statvfs);
++
++impl Statvfs {
++ /// get the file system block size
++ pub fn block_size(&self) -> c_ulong {
++ self.0.f_bsize
++ }
++
++ /// Get the fundamental file system block size
++ pub fn fragment_size(&self) -> c_ulong {
++ self.0.f_frsize
++ }
++
++ /// Get the number of blocks.
++ ///
++ /// Units are in units of `fragment_size()`
++ pub fn blocks(&self) -> libc::fsblkcnt_t {
++ self.0.f_blocks
++ }
++
++ /// Get the number of free blocks in the file system
++ pub fn blocks_free(&self) -> libc::fsblkcnt_t {
++ self.0.f_bfree
++ }
++
++ /// Get the number of free blocks for unprivileged users
++ pub fn blocks_available(&self) -> libc::fsblkcnt_t {
++ self.0.f_bavail
++ }
++
++ /// Get the total number of file inodes
++ pub fn files(&self) -> libc::fsfilcnt_t {
++ self.0.f_files
++ }
++
++ /// Get the number of free file inodes
++ pub fn files_free(&self) -> libc::fsfilcnt_t {
++ self.0.f_ffree
++ }
++
++ /// Get the number of free file inodes for unprivileged users
++ pub fn files_available(&self) -> libc::fsfilcnt_t {
++ self.0.f_favail
++ }
++
++ /// Get the file system id
++ pub fn filesystem_id(&self) -> c_ulong {
++ self.0.f_fsid
++ }
++
++ /// Get the mount flags
++ pub fn flags(&self) -> FsFlags {
++ FsFlags::from_bits_truncate(self.0.f_flag)
++ }
++
++ /// Get the maximum filename length
++ pub fn name_max(&self) -> c_ulong {
++ self.0.f_namemax
++ }
++
++}
++
++/// Return a `Statvfs` object with information about the `path`
++pub fn statvfs<P: ?Sized + NixPath>(path: &P) -> Result<Statvfs> {
++ unsafe {
++ Errno::clear();
++ let mut stat: Statvfs = mem::uninitialized();
++ let res = path.with_nix_path(|path|
++ libc::statvfs(path.as_ptr(), &mut stat.0)
++ )?;
++
++ Errno::result(res).map(|_| stat)
++ }
++}
++
++/// Return a `Statvfs` object with information about `fd`
++pub fn fstatvfs<T: AsRawFd>(fd: &T) -> Result<Statvfs> {
++ unsafe {
++ Errno::clear();
++ let mut stat: Statvfs = mem::uninitialized();
++ Errno::result(libc::fstatvfs(fd.as_raw_fd(), &mut stat.0)).map(|_| stat)
++ }
++}
++
++#[cfg(test)]
++mod test {
++ use std::fs::File;
++ use sys::statvfs::*;
++
++ #[test]
++ fn statvfs_call() {
++ statvfs("/".as_bytes()).unwrap();
++ }
++
++ #[test]
++ fn fstatvfs_call() {
++ let root = File::open("/").unwrap();
++ fstatvfs(&root).unwrap();
++ }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/sysinfo.rs b/third_party/rust/nix-0.15.0/src/sys/sysinfo.rs
+new file mode 100644
+index 0000000000000..4c8e38988886d
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/sysinfo.rs
+@@ -0,0 +1,72 @@
++use libc::{self, SI_LOAD_SHIFT};
++use std::{cmp, mem};
++use std::time::Duration;
++
++use Result;
++use errno::Errno;
++
++/// System info structure returned by `sysinfo`.
++#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
++pub struct SysInfo(libc::sysinfo);
++
++impl SysInfo {
++ /// Returns the load average tuple.
++ ///
++ /// The returned values represent the load average over time intervals of
++ /// 1, 5, and 15 minutes, respectively.
++ pub fn load_average(&self) -> (f64, f64, f64) {
++ (
++ self.0.loads[0] as f64 / (1 << SI_LOAD_SHIFT) as f64,
++ self.0.loads[1] as f64 / (1 << SI_LOAD_SHIFT) as f64,
++ self.0.loads[2] as f64 / (1 << SI_LOAD_SHIFT) as f64,
++ )
++ }
++
++ /// Returns the time since system boot.
++ pub fn uptime(&self) -> Duration {
++ // Truncate negative values to 0
++ Duration::from_secs(cmp::max(self.0.uptime, 0) as u64)
++ }
++
++ /// Current number of processes.
++ pub fn process_count(&self) -> u16 {
++ self.0.procs
++ }
++
++ /// Returns the amount of swap memory in Bytes.
++ pub fn swap_total(&self) -> u64 {
++ self.scale_mem(self.0.totalswap)
++ }
++
++ /// Returns the amount of unused swap memory in Bytes.
++ pub fn swap_free(&self) -> u64 {
++ self.scale_mem(self.0.freeswap)
++ }
++
++ /// Returns the total amount of installed RAM in Bytes.
++ pub fn ram_total(&self) -> u64 {
++ self.scale_mem(self.0.totalram)
++ }
++
++ /// Returns the amount of completely unused RAM in Bytes.
++ ///
++ /// "Unused" in this context means that the RAM in neither actively used by
++ /// programs, nor by the operating system as disk cache or buffer. It is
++ /// "wasted" RAM since it currently serves no purpose.
++ pub fn ram_unused(&self) -> u64 {
++ self.scale_mem(self.0.freeram)
++ }
++
++ fn scale_mem(&self, units: libc::c_ulong) -> u64 {
++ units as u64 * self.0.mem_unit as u64
++ }
++}
++
++/// Returns system information.
++///
++/// [See `sysinfo(2)`](http://man7.org/linux/man-pages/man2/sysinfo.2.html).
++pub fn sysinfo() -> Result<SysInfo> {
++ let mut info: libc::sysinfo = unsafe { mem::uninitialized() };
++ let res = unsafe { libc::sysinfo(&mut info) };
++ Errno::result(res).map(|_| SysInfo(info))
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/termios.rs b/third_party/rust/nix-0.15.0/src/sys/termios.rs
+new file mode 100644
+index 0000000000000..c7cdf10b461c1
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/termios.rs
+@@ -0,0 +1,1107 @@
++//! An interface for controlling asynchronous communication ports
++//!
++//! This interface provides a safe wrapper around the termios subsystem defined by POSIX. The
++//! underlying types are all implemented in libc for most platforms and either wrapped in safer
++//! types here or exported directly.
++//!
++//! If you are unfamiliar with the `termios` API, you should first read the
++//! [API documentation](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/termios.h.html) and
++//! then come back to understand how `nix` safely wraps it.
++//!
++//! It should be noted that this API incurs some runtime overhead above the base `libc` definitions.
++//! As this interface is not used with high-bandwidth information, this should be fine in most
++//! cases. The primary cost when using this API is that the `Termios` datatype here duplicates the
++//! standard fields of the underlying `termios` struct and uses safe type wrappers for those fields.
++//! This means that when crossing the FFI interface to the underlying C library, data is first
++//! copied into the underlying `termios` struct, then the operation is done, and the data is copied
++//! back (with additional sanity checking) into the safe wrapper types. The `termios` struct is
++//! relatively small across all platforms (on the order of 32-64 bytes).
++//!
++//! The following examples highlight some of the API use cases such that users coming from using C
++//! or reading the standard documentation will understand how to use the safe API exposed here.
++//!
++//! Example disabling processing of the end-of-file control character:
++//!
++//! ```
++//! # use self::nix::sys::termios::SpecialCharacterIndices::VEOF;
++//! # use self::nix::sys::termios::{_POSIX_VDISABLE, Termios};
++//! # let mut termios = unsafe { Termios::default_uninit() };
++//! termios.control_chars[VEOF as usize] = _POSIX_VDISABLE;
++//! ```
++//!
++//! The flags within `Termios` are defined as bitfields using the `bitflags` crate. This provides
++//! an interface for working with bitfields that is similar to working with the raw unsigned
++//! integer types but offers type safety because of the internal checking that values will always
++//! be a valid combination of the defined flags.
++//!
++//! An example showing some of the basic operations for interacting with the control flags:
++//!
++//! ```
++//! # use self::nix::sys::termios::{ControlFlags, Termios};
++//! # let mut termios = unsafe { Termios::default_uninit() };
++//! termios.control_flags & ControlFlags::CSIZE == ControlFlags::CS5;
++//! termios.control_flags |= ControlFlags::CS5;
++//! ```
++//!
++//! # Baud rates
++//!
++//! This API is not consistent across platforms when it comes to `BaudRate`: Android and Linux both
++//! only support the rates specified by the `BaudRate` enum through their termios API while the BSDs
++//! support arbitrary baud rates as the values of the `BaudRate` enum constants are the same integer
++//! value of the constant (`B9600` == `9600`). Therefore the `nix::termios` API uses the following
++//! conventions:
++//!
++//! * `cfgetispeed()` - Returns `u32` on BSDs, `BaudRate` on Android/Linux
++//! * `cfgetospeed()` - Returns `u32` on BSDs, `BaudRate` on Android/Linux
++//! * `cfsetispeed()` - Takes `u32` or `BaudRate` on BSDs, `BaudRate` on Android/Linux
++//! * `cfsetospeed()` - Takes `u32` or `BaudRate` on BSDs, `BaudRate` on Android/Linux
++//! * `cfsetspeed()` - Takes `u32` or `BaudRate` on BSDs, `BaudRate` on Android/Linux
++//!
++//! The most common use case of specifying a baud rate using the enum will work the same across
++//! platforms:
++//!
++//! ```rust
++//! # #[macro_use] extern crate nix;
++//! # use nix::sys::termios::{BaudRate, cfsetispeed, cfsetospeed, cfsetspeed, Termios};
++//! # fn main() {
++//! # let mut t = unsafe { Termios::default_uninit() };
++//! cfsetispeed(&mut t, BaudRate::B9600);
++//! cfsetospeed(&mut t, BaudRate::B9600);
++//! cfsetspeed(&mut t, BaudRate::B9600);
++//! # }
++//! ```
++//!
++//! Additionally round-tripping baud rates is consistent across platforms:
++//!
++//! ```rust
++//! # extern crate nix;
++//! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetispeed, cfsetspeed, Termios};
++//! # fn main() {
++//! # let mut t = unsafe { Termios::default_uninit() };
++//! # cfsetspeed(&mut t, BaudRate::B9600);
++//! let speed = cfgetispeed(&t);
++//! assert!(speed == cfgetospeed(&t));
++//! cfsetispeed(&mut t, speed);
++//! # }
++//! ```
++//!
++//! On non-BSDs, `cfgetispeed()` and `cfgetospeed()` both return a `BaudRate`:
++//!
++// FIXME: Replace `ignore` with `compile_fail` once 1.22 is the minimum support Rust version
++#![cfg_attr(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
++ target_os = "macos", target_os = "netbsd", target_os = "openbsd"),
++ doc = " ```rust,ignore")]
++#![cfg_attr(not(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
++ target_os = "macos", target_os = "netbsd", target_os = "openbsd")),
++ doc = " ```rust")]
++//! # extern crate nix;
++//! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetspeed, Termios};
++//! # fn main() {
++//! # let mut t = unsafe { Termios::default_uninit() };
++//! # cfsetspeed(&mut t, BaudRate::B9600);
++//! assert!(cfgetispeed(&t) == BaudRate::B9600);
++//! assert!(cfgetospeed(&t) == BaudRate::B9600);
++//! # }
++//! ```
++//!
++//! But on the BSDs, `cfgetispeed()` and `cfgetospeed()` both return `u32`s:
++//!
++// FIXME: Replace `ignore` with `compile_fail` once 1.22 is the minimum support Rust version
++#![cfg_attr(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
++ target_os = "macos", target_os = "netbsd", target_os = "openbsd"),
++ doc = " ```rust")]
++#![cfg_attr(not(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
++ target_os = "macos", target_os = "netbsd", target_os = "openbsd")),
++ doc = " ```rust,ignore")]
++//! # extern crate nix;
++//! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetspeed, Termios};
++//! # fn main() {
++//! # let mut t = unsafe { Termios::default_uninit() };
++//! # cfsetspeed(&mut t, 9600u32);
++//! assert!(cfgetispeed(&t) == 9600u32);
++//! assert!(cfgetospeed(&t) == 9600u32);
++//! # }
++//! ```
++//!
++//! It's trivial to convert from a `BaudRate` to a `u32` on BSDs:
++//!
++// FIXME: Replace `ignore` with `compile_fail` once 1.22 is the minimum support Rust version
++#![cfg_attr(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
++ target_os = "macos", target_os = "netbsd", target_os = "openbsd"),
++ doc = " ```rust")]
++#![cfg_attr(not(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
++ target_os = "macos", target_os = "netbsd", target_os = "openbsd")),
++ doc = " ```rust,ignore")]
++//! # extern crate nix;
++//! # use nix::sys::termios::{BaudRate, cfgetispeed, cfsetspeed, Termios};
++//! # fn main() {
++//! # let mut t = unsafe { Termios::default_uninit() };
++//! # cfsetspeed(&mut t, 9600u32);
++//! assert!(cfgetispeed(&t) == BaudRate::B9600.into());
++//! assert!(u32::from(BaudRate::B9600) == 9600u32);
++//! # }
++//! ```
++//!
++//! And on BSDs you can specify arbitrary baud rates (**note** this depends on hardware support)
++//! by specifying baud rates directly using `u32`s:
++//!
++// FIXME: Replace `ignore` with `compile_fail` once 1.22 is the minimum support Rust version
++#![cfg_attr(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
++ target_os = "macos", target_os = "netbsd", target_os = "openbsd"),
++ doc = " ```rust")]
++#![cfg_attr(not(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
++ target_os = "macos", target_os = "netbsd", target_os = "openbsd")),
++ doc = " ```rust,ignore")]
++//! # extern crate nix;
++//! # use nix::sys::termios::{cfsetispeed, cfsetospeed, cfsetspeed, Termios};
++//! # fn main() {
++//! # let mut t = unsafe { Termios::default_uninit() };
++//! cfsetispeed(&mut t, 9600u32);
++//! cfsetospeed(&mut t, 9600u32);
++//! cfsetspeed(&mut t, 9600u32);
++//! # }
++//! ```
++use Result;
++use errno::Errno;
++use libc::{self, c_int, tcflag_t};
++use std::cell::{Ref, RefCell};
++use std::convert::From;
++use std::mem;
++use std::os::unix::io::RawFd;
++
++use ::unistd::Pid;
++
++/// Stores settings for the termios API
++///
++/// This is a wrapper around the `libc::termios` struct that provides a safe interface for the
++/// standard fields. The only safe way to obtain an instance of this struct is to extract it from
++/// an open port using `tcgetattr()`.
++#[derive(Clone, Debug, Eq, PartialEq)]
++pub struct Termios {
++ inner: RefCell<libc::termios>,
++ /// Input mode flags (see `termios.c_iflag` documentation)
++ pub input_flags: InputFlags,
++ /// Output mode flags (see `termios.c_oflag` documentation)
++ pub output_flags: OutputFlags,
++ /// Control mode flags (see `termios.c_cflag` documentation)
++ pub control_flags: ControlFlags,
++ /// Local mode flags (see `termios.c_lflag` documentation)
++ pub local_flags: LocalFlags,
++ /// Control characters (see `termios.c_cc` documentation)
++ pub control_chars: [libc::cc_t; NCCS],
++}
++
++impl Termios {
++ /// Exposes an immutable reference to the underlying `libc::termios` data structure.
++ ///
++ /// This can be used for interfacing with other FFI functions like:
++ ///
++ /// ```rust
++ /// # extern crate libc;
++ /// # extern crate nix;
++ /// # fn main() {
++ /// # use nix::sys::termios::Termios;
++ /// # let mut termios = unsafe { Termios::default_uninit() };
++ /// let inner_termios = termios.get_libc_termios();
++ /// unsafe { libc::cfgetispeed(&*inner_termios) };
++ /// # }
++ /// ```
++ ///
++ /// There is no public API exposed for functions that modify the underlying `libc::termios`
++ /// data because it requires additional work to maintain type safety.
++ // FIXME: Switch this over to use pub(crate)
++ #[doc(hidden)]
++ pub fn get_libc_termios(&self) -> Ref<libc::termios> {
++ {
++ let mut termios = self.inner.borrow_mut();
++ termios.c_iflag = self.input_flags.bits();
++ termios.c_oflag = self.output_flags.bits();
++ termios.c_cflag = self.control_flags.bits();
++ termios.c_lflag = self.local_flags.bits();
++ termios.c_cc = self.control_chars;
++ }
++ self.inner.borrow()
++ }
++
++ /// Exposes the inner `libc::termios` datastore within `Termios`.
++ ///
++ /// This is unsafe because if this is used to modify the inner libc::termios struct, it will not
++ /// automatically update the safe wrapper type around it. Therefore we disable docs to
++ /// effectively limit its use to nix internals. In this case it should also be paired with a
++ /// call to `update_wrapper()` so that the wrapper-type and internal representation stay
++ /// consistent.
++ unsafe fn get_libc_termios_mut(&mut self) -> *mut libc::termios {
++ {
++ let mut termios = self.inner.borrow_mut();
++ termios.c_iflag = self.input_flags.bits();
++ termios.c_oflag = self.output_flags.bits();
++ termios.c_cflag = self.control_flags.bits();
++ termios.c_lflag = self.local_flags.bits();
++ termios.c_cc = self.control_chars;
++ }
++ self.inner.as_ptr()
++ }
++
++ /// Allows for easily creating new `Termios` structs that will be overwritten with real data.
++ ///
++ /// This should only be used when the inner libc::termios struct will be overwritten before it's
++ /// read.
++ // FIXME: Switch this over to use pub(crate)
++ #[doc(hidden)]
++ pub unsafe fn default_uninit() -> Self {
++ Termios {
++ inner: RefCell::new(mem::uninitialized()),
++ input_flags: InputFlags::empty(),
++ output_flags: OutputFlags::empty(),
++ control_flags: ControlFlags::empty(),
++ local_flags: LocalFlags::empty(),
++ control_chars: [0 as libc::cc_t; NCCS],
++ }
++ }
++
++ /// Updates the wrapper values from the internal `libc::termios` data structure.
++ #[doc(hidden)]
++ pub fn update_wrapper(&mut self) {
++ let termios = *self.inner.borrow_mut();
++ self.input_flags = InputFlags::from_bits_truncate(termios.c_iflag);
++ self.output_flags = OutputFlags::from_bits_truncate(termios.c_oflag);
++ self.control_flags = ControlFlags::from_bits_truncate(termios.c_cflag);
++ self.local_flags = LocalFlags::from_bits_truncate(termios.c_lflag);
++ self.control_chars = termios.c_cc;
++ }
++}
++
++impl From<libc::termios> for Termios {
++ fn from(termios: libc::termios) -> Self {
++ Termios {
++ inner: RefCell::new(termios),
++ input_flags: InputFlags::from_bits_truncate(termios.c_iflag),
++ output_flags: OutputFlags::from_bits_truncate(termios.c_oflag),
++ control_flags: ControlFlags::from_bits_truncate(termios.c_cflag),
++ local_flags: LocalFlags::from_bits_truncate(termios.c_lflag),
++ control_chars: termios.c_cc,
++ }
++ }
++}
++
++impl From<Termios> for libc::termios {
++ fn from(termios: Termios) -> Self {
++ termios.inner.into_inner()
++ }
++}
++
++libc_enum!{
++ /// Baud rates supported by the system.
++ ///
++ /// For the BSDs, arbitrary baud rates can be specified by using `u32`s directly instead of this
++ /// enum.
++ ///
++ /// B0 is special and will disable the port.
++ #[cfg_attr(all(any(target_os = "ios", target_os = "macos"), target_pointer_width = "64"), repr(u64))]
++ #[cfg_attr(not(all(any(target_os = "ios", target_os = "macos"), target_pointer_width = "64")), repr(u32))]
++ pub enum BaudRate {
++ B0,
++ B50,
++ B75,
++ B110,
++ B134,
++ B150,
++ B200,
++ B300,
++ B600,
++ B1200,
++ B1800,
++ B2400,
++ B4800,
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ B7200,
++ B9600,
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ B14400,
++ B19200,
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ B28800,
++ B38400,
++ B57600,
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ B76800,
++ B115200,
++ B230400,
++ #[cfg(any(target_os = "android",
++ target_os = "freebsd",
++ target_os = "linux",
++ target_os = "netbsd"))]
++ B460800,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ B500000,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ B576000,
++ #[cfg(any(target_os = "android",
++ target_os = "freebsd",
++ target_os = "linux",
++ target_os = "netbsd"))]
++ B921600,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ B1000000,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ B1152000,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ B1500000,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ B2000000,
++ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
++ B2500000,
++ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
++ B3000000,
++ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
++ B3500000,
++ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
++ B4000000,
++ }
++}
++
++impl From<libc::speed_t> for BaudRate {
++ fn from(s: libc::speed_t) -> BaudRate {
++
++ use libc::{B0, B50, B75, B110, B134, B150, B200, B300, B600, B1200, B1800, B2400, B4800,
++ B9600, B19200, B38400, B57600, B115200, B230400};
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ use libc::{B500000, B576000, B1000000, B1152000, B1500000, B2000000};
++ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
++ use libc::{B2500000, B3000000, B3500000, B4000000};
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ use libc::{B7200, B14400, B28800, B76800};
++ #[cfg(any(target_os = "android",
++ target_os = "freebsd",
++ target_os = "linux",
++ target_os = "netbsd"))]
++ use libc::{B460800, B921600};
++
++ match s {
++ B0 => BaudRate::B0,
++ B50 => BaudRate::B50,
++ B75 => BaudRate::B75,
++ B110 => BaudRate::B110,
++ B134 => BaudRate::B134,
++ B150 => BaudRate::B150,
++ B200 => BaudRate::B200,
++ B300 => BaudRate::B300,
++ B600 => BaudRate::B600,
++ B1200 => BaudRate::B1200,
++ B1800 => BaudRate::B1800,
++ B2400 => BaudRate::B2400,
++ B4800 => BaudRate::B4800,
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ B7200 => BaudRate::B7200,
++ B9600 => BaudRate::B9600,
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ B14400 => BaudRate::B14400,
++ B19200 => BaudRate::B19200,
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ B28800 => BaudRate::B28800,
++ B38400 => BaudRate::B38400,
++ B57600 => BaudRate::B57600,
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ B76800 => BaudRate::B76800,
++ B115200 => BaudRate::B115200,
++ B230400 => BaudRate::B230400,
++ #[cfg(any(target_os = "android",
++ target_os = "freebsd",
++ target_os = "linux",
++ target_os = "netbsd"))]
++ B460800 => BaudRate::B460800,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ B500000 => BaudRate::B500000,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ B576000 => BaudRate::B576000,
++ #[cfg(any(target_os = "android",
++ target_os = "freebsd",
++ target_os = "linux",
++ target_os = "netbsd"))]
++ B921600 => BaudRate::B921600,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ B1000000 => BaudRate::B1000000,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ B1152000 => BaudRate::B1152000,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ B1500000 => BaudRate::B1500000,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ B2000000 => BaudRate::B2000000,
++ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
++ B2500000 => BaudRate::B2500000,
++ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
++ B3000000 => BaudRate::B3000000,
++ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
++ B3500000 => BaudRate::B3500000,
++ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
++ B4000000 => BaudRate::B4000000,
++ b => unreachable!("Invalid baud constant: {}", b),
++ }
++ }
++}
++
++// TODO: Include `TryFrom<u32> for BaudRate` once that API stabilizes
++#[cfg(any(target_os = "freebsd",
++ target_os = "dragonfly",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++impl From<BaudRate> for u32 {
++ fn from(b: BaudRate) -> u32 {
++ b as u32
++ }
++}
++
++// TODO: Add TCSASOFT, which will require treating this as a bitfield.
++libc_enum! {
++ /// Specify when a port configuration change should occur.
++ ///
++ /// Used as an argument to `tcsetattr()`
++ #[repr(i32)]
++ pub enum SetArg {
++ /// The change will occur immediately
++ TCSANOW,
++ /// The change occurs after all output has been written
++ TCSADRAIN,
++ /// Same as `TCSADRAIN`, but will also flush the input buffer
++ TCSAFLUSH,
++ }
++}
++
++libc_enum! {
++ /// Specify a combination of the input and output buffers to flush
++ ///
++ /// Used as an argument to `tcflush()`.
++ #[repr(i32)]
++ pub enum FlushArg {
++ /// Flush data that was received but not read
++ TCIFLUSH,
++ /// Flush data written but not transmitted
++ TCOFLUSH,
++ /// Flush both received data not read and written data not transmitted
++ TCIOFLUSH,
++ }
++}
++
++libc_enum! {
++ /// Specify how transmission flow should be altered
++ ///
++ /// Used as an argument to `tcflow()`.
++ #[repr(i32)]
++ pub enum FlowArg {
++ /// Suspend transmission
++ TCOOFF,
++ /// Resume transmission
++ TCOON,
++ /// Transmit a STOP character, which should disable a connected terminal device
++ TCIOFF,
++ /// Transmit a START character, which should re-enable a connected terminal device
++ TCION,
++ }
++}
++
++// TODO: Make this usable directly as a slice index.
++libc_enum! {
++ /// Indices into the `termios.c_cc` array for special characters.
++ #[repr(usize)]
++ pub enum SpecialCharacterIndices {
++ VDISCARD,
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ VDSUSP,
++ VEOF,
++ VEOL,
++ VEOL2,
++ VERASE,
++ #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
++ VERASE2,
++ VINTR,
++ VKILL,
++ VLNEXT,
++ #[cfg(not(all(target_os = "linux", target_arch = "sparc64")))]
++ VMIN,
++ VQUIT,
++ VREPRINT,
++ VSTART,
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ VSTATUS,
++ VSTOP,
++ VSUSP,
++ #[cfg(target_os = "linux")]
++ VSWTC,
++ #[cfg(target_os = "haiku")]
++ VSWTCH,
++ #[cfg(not(all(target_os = "linux", target_arch = "sparc64")))]
++ VTIME,
++ VWERASE,
++ #[cfg(target_os = "dragonfly")]
++ VCHECKPT,
++ }
++}
++
++pub use libc::NCCS;
++#[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "linux",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++pub use libc::_POSIX_VDISABLE;
++
++libc_bitflags! {
++ /// Flags for configuring the input mode of a terminal
++ pub struct InputFlags: tcflag_t {
++ IGNBRK;
++ BRKINT;
++ IGNPAR;
++ PARMRK;
++ INPCK;
++ ISTRIP;
++ INLCR;
++ IGNCR;
++ ICRNL;
++ IXON;
++ IXOFF;
++ IXANY;
++ IMAXBEL;
++ #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))]
++ IUTF8;
++ }
++}
++
++libc_bitflags! {
++ /// Flags for configuring the output mode of a terminal
++ pub struct OutputFlags: tcflag_t {
++ OPOST;
++ #[cfg(any(target_os = "android",
++ target_os = "haiku",
++ target_os = "linux",
++ target_os = "openbsd"))]
++ OLCUC;
++ ONLCR;
++ OCRNL as tcflag_t;
++ ONOCR as tcflag_t;
++ ONLRET as tcflag_t;
++ #[cfg(any(target_os = "android",
++ target_os = "haiku",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos"))]
++ OFILL as tcflag_t;
++ #[cfg(any(target_os = "android",
++ target_os = "haiku",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos"))]
++ OFDEL as tcflag_t;
++ #[cfg(any(target_os = "android",
++ target_os = "haiku",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos"))]
++ NL0 as tcflag_t;
++ #[cfg(any(target_os = "android",
++ target_os = "haiku",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos"))]
++ NL1 as tcflag_t;
++ #[cfg(any(target_os = "android",
++ target_os = "haiku",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos"))]
++ CR0 as tcflag_t;
++ #[cfg(any(target_os = "android",
++ target_os = "haiku",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos"))]
++ CR1 as tcflag_t;
++ #[cfg(any(target_os = "android",
++ target_os = "haiku",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos"))]
++ CR2 as tcflag_t;
++ #[cfg(any(target_os = "android",
++ target_os = "haiku",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos"))]
++ CR3 as tcflag_t;
++ #[cfg(any(target_os = "android",
++ target_os = "freebsd",
++ target_os = "haiku",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos"))]
++ TAB0 as tcflag_t;
++ #[cfg(any(target_os = "android",
++ target_os = "haiku",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos"))]
++ TAB1 as tcflag_t;
++ #[cfg(any(target_os = "android",
++ target_os = "haiku",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos"))]
++ TAB2 as tcflag_t;
++ #[cfg(any(target_os = "android",
++ target_os = "freebsd",
++ target_os = "haiku",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos"))]
++ TAB3 as tcflag_t;
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ XTABS;
++ #[cfg(any(target_os = "android",
++ target_os = "haiku",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos"))]
++ BS0 as tcflag_t;
++ #[cfg(any(target_os = "android",
++ target_os = "haiku",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos"))]
++ BS1 as tcflag_t;
++ #[cfg(any(target_os = "android",
++ target_os = "haiku",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos"))]
++ VT0 as tcflag_t;
++ #[cfg(any(target_os = "android",
++ target_os = "haiku",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos"))]
++ VT1 as tcflag_t;
++ #[cfg(any(target_os = "android",
++ target_os = "haiku",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos"))]
++ FF0 as tcflag_t;
++ #[cfg(any(target_os = "android",
++ target_os = "haiku",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos"))]
++ FF1 as tcflag_t;
++ #[cfg(any(target_os = "freebsd",
++ target_os = "dragonfly",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ OXTABS;
++ #[cfg(any(target_os = "freebsd",
++ target_os = "dragonfly",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ ONOEOT as tcflag_t;
++
++ // Bitmasks for use with OutputFlags to select specific settings
++ // These should be moved to be a mask once https://github.com/rust-lang-nursery/bitflags/issues/110
++ // is resolved.
++
++ #[cfg(any(target_os = "android",
++ target_os = "haiku",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos"))]
++ NLDLY as tcflag_t; // FIXME: Datatype needs to be corrected in libc for mac
++ #[cfg(any(target_os = "android",
++ target_os = "haiku",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos"))]
++ CRDLY as tcflag_t;
++ #[cfg(any(target_os = "android",
++ target_os = "freebsd",
++ target_os = "haiku",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos"))]
++ TABDLY as tcflag_t;
++ #[cfg(any(target_os = "android",
++ target_os = "haiku",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos"))]
++ BSDLY as tcflag_t;
++ #[cfg(any(target_os = "android",
++ target_os = "haiku",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos"))]
++ VTDLY as tcflag_t;
++ #[cfg(any(target_os = "android",
++ target_os = "haiku",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos"))]
++ FFDLY as tcflag_t;
++ }
++}
++
++libc_bitflags! {
++ /// Flags for setting the control mode of a terminal
++ pub struct ControlFlags: tcflag_t {
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ CIGNORE;
++ CS5;
++ CS6;
++ CS7;
++ CS8;
++ CSTOPB;
++ CREAD;
++ PARENB;
++ PARODD;
++ HUPCL;
++ CLOCAL;
++ CRTSCTS;
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ CBAUD;
++ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "mips"))))]
++ CMSPAR;
++ #[cfg(any(target_os = "android",
++ all(target_os = "linux",
++ not(any(target_arch = "powerpc", target_arch = "powerpc64")))))]
++ CIBAUD;
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ CBAUDEX;
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ MDMBUF;
++ #[cfg(any(target_os = "netbsd", target_os = "openbsd"))]
++ CHWFLOW;
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ CCTS_OFLOW;
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ CRTS_IFLOW;
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd"))]
++ CDTR_IFLOW;
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd"))]
++ CDSR_OFLOW;
++ #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd"))]
++ CCAR_OFLOW;
++
++ // Bitmasks for use with ControlFlags to select specific settings
++ // These should be moved to be a mask once https://github.com/rust-lang-nursery/bitflags/issues/110
++ // is resolved.
++
++ CSIZE;
++ }
++}
++
++libc_bitflags! {
++ /// Flags for setting any local modes
++ pub struct LocalFlags: tcflag_t {
++ ECHOKE;
++ ECHOE;
++ ECHOK;
++ ECHO;
++ ECHONL;
++ ECHOPRT;
++ ECHOCTL;
++ ISIG;
++ ICANON;
++ #[cfg(any(target_os = "freebsd",
++ target_os = "dragonfly",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ ALTWERASE;
++ IEXTEN;
++ EXTPROC;
++ TOSTOP;
++ FLUSHO;
++ #[cfg(any(target_os = "freebsd",
++ target_os = "dragonfly",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++ NOKERNINFO;
++ PENDIN;
++ NOFLSH;
++ }
++}
++
++cfg_if!{
++ if #[cfg(any(target_os = "freebsd",
++ target_os = "dragonfly",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))] {
++ /// Get input baud rate (see
++ /// [cfgetispeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetispeed.html)).
++ ///
++ /// `cfgetispeed()` extracts the input baud rate from the given `Termios` structure.
++ pub fn cfgetispeed(termios: &Termios) -> u32 {
++ let inner_termios = termios.get_libc_termios();
++ unsafe { libc::cfgetispeed(&*inner_termios) as u32 }
++ }
++
++ /// Get output baud rate (see
++ /// [cfgetospeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetospeed.html)).
++ ///
++ /// `cfgetospeed()` extracts the output baud rate from the given `Termios` structure.
++ pub fn cfgetospeed(termios: &Termios) -> u32 {
++ let inner_termios = termios.get_libc_termios();
++ unsafe { libc::cfgetospeed(&*inner_termios) as u32 }
++ }
++
++ /// Set input baud rate (see
++ /// [cfsetispeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetispeed.html)).
++ ///
++ /// `cfsetispeed()` sets the intput baud rate in the given `Termios` structure.
++ pub fn cfsetispeed<T: Into<u32>>(termios: &mut Termios, baud: T) -> Result<()> {
++ let inner_termios = unsafe { termios.get_libc_termios_mut() };
++ let res = unsafe { libc::cfsetispeed(inner_termios, baud.into() as libc::speed_t) };
++ termios.update_wrapper();
++ Errno::result(res).map(drop)
++ }
++
++ /// Set output baud rate (see
++ /// [cfsetospeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetospeed.html)).
++ ///
++ /// `cfsetospeed()` sets the output baud rate in the given termios structure.
++ pub fn cfsetospeed<T: Into<u32>>(termios: &mut Termios, baud: T) -> Result<()> {
++ let inner_termios = unsafe { termios.get_libc_termios_mut() };
++ let res = unsafe { libc::cfsetospeed(inner_termios, baud.into() as libc::speed_t) };
++ termios.update_wrapper();
++ Errno::result(res).map(drop)
++ }
++
++ /// Set both the input and output baud rates (see
++ /// [termios(3)](https://www.freebsd.org/cgi/man.cgi?query=cfsetspeed)).
++ ///
++ /// `cfsetspeed()` sets the input and output baud rate in the given termios structure. Note that
++ /// this is part of the 4.4BSD standard and not part of POSIX.
++ pub fn cfsetspeed<T: Into<u32>>(termios: &mut Termios, baud: T) -> Result<()> {
++ let inner_termios = unsafe { termios.get_libc_termios_mut() };
++ let res = unsafe { libc::cfsetspeed(inner_termios, baud.into() as libc::speed_t) };
++ termios.update_wrapper();
++ Errno::result(res).map(drop)
++ }
++ } else {
++ /// Get input baud rate (see
++ /// [cfgetispeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetispeed.html)).
++ ///
++ /// `cfgetispeed()` extracts the input baud rate from the given `Termios` structure.
++ pub fn cfgetispeed(termios: &Termios) -> BaudRate {
++ let inner_termios = termios.get_libc_termios();
++ unsafe { libc::cfgetispeed(&*inner_termios) }.into()
++ }
++
++ /// Get output baud rate (see
++ /// [cfgetospeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetospeed.html)).
++ ///
++ /// `cfgetospeed()` extracts the output baud rate from the given `Termios` structure.
++ pub fn cfgetospeed(termios: &Termios) -> BaudRate {
++ let inner_termios = termios.get_libc_termios();
++ unsafe { libc::cfgetospeed(&*inner_termios) }.into()
++ }
++
++ /// Set input baud rate (see
++ /// [cfsetispeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetispeed.html)).
++ ///
++ /// `cfsetispeed()` sets the intput baud rate in the given `Termios` structure.
++ pub fn cfsetispeed(termios: &mut Termios, baud: BaudRate) -> Result<()> {
++ let inner_termios = unsafe { termios.get_libc_termios_mut() };
++ let res = unsafe { libc::cfsetispeed(inner_termios, baud as libc::speed_t) };
++ termios.update_wrapper();
++ Errno::result(res).map(drop)
++ }
++
++ /// Set output baud rate (see
++ /// [cfsetospeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetospeed.html)).
++ ///
++ /// `cfsetospeed()` sets the output baud rate in the given `Termios` structure.
++ pub fn cfsetospeed(termios: &mut Termios, baud: BaudRate) -> Result<()> {
++ let inner_termios = unsafe { termios.get_libc_termios_mut() };
++ let res = unsafe { libc::cfsetospeed(inner_termios, baud as libc::speed_t) };
++ termios.update_wrapper();
++ Errno::result(res).map(drop)
++ }
++
++ /// Set both the input and output baud rates (see
++ /// [termios(3)](https://www.freebsd.org/cgi/man.cgi?query=cfsetspeed)).
++ ///
++ /// `cfsetspeed()` sets the input and output baud rate in the given `Termios` structure. Note that
++ /// this is part of the 4.4BSD standard and not part of POSIX.
++ pub fn cfsetspeed(termios: &mut Termios, baud: BaudRate) -> Result<()> {
++ let inner_termios = unsafe { termios.get_libc_termios_mut() };
++ let res = unsafe { libc::cfsetspeed(inner_termios, baud as libc::speed_t) };
++ termios.update_wrapper();
++ Errno::result(res).map(drop)
++ }
++ }
++}
++
++/// Configures the port to something like the "raw" mode of the old Version 7 terminal driver (see
++/// [termios(3)](http://man7.org/linux/man-pages/man3/termios.3.html)).
++///
++/// `cfmakeraw()` configures the termios structure such that input is available character-by-
++/// character, echoing is disabled, and all special input and output processing is disabled. Note
++/// that this is a non-standard function, but is available on Linux and BSDs.
++pub fn cfmakeraw(termios: &mut Termios) {
++ let inner_termios = unsafe { termios.get_libc_termios_mut() };
++ unsafe {
++ libc::cfmakeraw(inner_termios);
++ }
++ termios.update_wrapper();
++}
++
++/// Configures the port to "sane" mode (like the configuration of a newly created terminal) (see
++/// [tcsetattr(3)](https://www.freebsd.org/cgi/man.cgi?query=tcsetattr)).
++///
++/// Note that this is a non-standard function, available on FreeBSD.
++#[cfg(target_os = "freebsd")]
++pub fn cfmakesane(termios: &mut Termios) {
++ let inner_termios = unsafe { termios.get_libc_termios_mut() };
++ unsafe {
++ libc::cfmakesane(inner_termios);
++ }
++ termios.update_wrapper();
++}
++
++/// Return the configuration of a port
++/// [tcgetattr(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetattr.html)).
++///
++/// `tcgetattr()` returns a `Termios` structure with the current configuration for a port. Modifying
++/// this structure *will not* reconfigure the port, instead the modifications should be done to
++/// the `Termios` structure and then the port should be reconfigured using `tcsetattr()`.
++pub fn tcgetattr(fd: RawFd) -> Result<Termios> {
++ let mut termios: libc::termios = unsafe { mem::uninitialized() };
++
++ let res = unsafe { libc::tcgetattr(fd, &mut termios) };
++
++ Errno::result(res)?;
++
++ Ok(termios.into())
++}
++
++/// Set the configuration for a terminal (see
++/// [tcsetattr(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsetattr.html)).
++///
++/// `tcsetattr()` reconfigures the given port based on a given `Termios` structure. This change
++/// takes affect at a time specified by `actions`. Note that this function may return success if
++/// *any* of the parameters were successfully set, not only if all were set successfully.
++pub fn tcsetattr(fd: RawFd, actions: SetArg, termios: &Termios) -> Result<()> {
++ let inner_termios = termios.get_libc_termios();
++ Errno::result(unsafe { libc::tcsetattr(fd, actions as c_int, &*inner_termios) }).map(drop)
++}
++
++/// Block until all output data is written (see
++/// [tcdrain(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcdrain.html)).
++pub fn tcdrain(fd: RawFd) -> Result<()> {
++ Errno::result(unsafe { libc::tcdrain(fd) }).map(drop)
++}
++
++/// Suspend or resume the transmission or reception of data (see
++/// [tcflow(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcflow.html)).
++///
++/// `tcflow()` suspends of resumes the transmission or reception of data for the given port
++/// depending on the value of `action`.
++pub fn tcflow(fd: RawFd, action: FlowArg) -> Result<()> {
++ Errno::result(unsafe { libc::tcflow(fd, action as c_int) }).map(drop)
++}
++
++/// Discard data in the output or input queue (see
++/// [tcflush(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcflush.html)).
++///
++/// `tcflush()` will discard data for a terminal port in the input queue, output queue, or both
++/// depending on the value of `action`.
++pub fn tcflush(fd: RawFd, action: FlushArg) -> Result<()> {
++ Errno::result(unsafe { libc::tcflush(fd, action as c_int) }).map(drop)
++}
++
++/// Send a break for a specific duration (see
++/// [tcsendbreak(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsendbreak.html)).
++///
++/// When using asynchronous data transmission `tcsendbreak()` will transmit a continuous stream
++/// of zero-valued bits for an implementation-defined duration.
++pub fn tcsendbreak(fd: RawFd, duration: c_int) -> Result<()> {
++ Errno::result(unsafe { libc::tcsendbreak(fd, duration) }).map(drop)
++}
++
++/// Get the session controlled by the given terminal (see
++/// [tcgetsid(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetsid.html)).
++pub fn tcgetsid(fd: RawFd) -> Result<Pid> {
++ let res = unsafe { libc::tcgetsid(fd) };
++
++ Errno::result(res).map(Pid::from_raw)
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/time.rs b/third_party/rust/nix-0.15.0/src/sys/time.rs
+new file mode 100644
+index 0000000000000..3ad57543b18a7
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/time.rs
+@@ -0,0 +1,542 @@
++use std::{cmp, fmt, ops};
++use std::convert::From;
++use libc::{c_long, timespec, timeval};
++pub use libc::{time_t, suseconds_t};
++
++pub trait TimeValLike: Sized {
++ #[inline]
++ fn zero() -> Self {
++ Self::seconds(0)
++ }
++
++ #[inline]
++ fn hours(hours: i64) -> Self {
++ let secs = hours.checked_mul(SECS_PER_HOUR)
++ .expect("TimeValLike::hours ouf of bounds");
++ Self::seconds(secs)
++ }
++
++ #[inline]
++ fn minutes(minutes: i64) -> Self {
++ let secs = minutes.checked_mul(SECS_PER_MINUTE)
++ .expect("TimeValLike::minutes out of bounds");
++ Self::seconds(secs)
++ }
++
++ fn seconds(seconds: i64) -> Self;
++ fn milliseconds(milliseconds: i64) -> Self;
++ fn microseconds(microseconds: i64) -> Self;
++ fn nanoseconds(nanoseconds: i64) -> Self;
++
++ #[inline]
++ fn num_hours(&self) -> i64 {
++ self.num_seconds() / 3600
++ }
++
++ #[inline]
++ fn num_minutes(&self) -> i64 {
++ self.num_seconds() / 60
++ }
++
++ fn num_seconds(&self) -> i64;
++ fn num_milliseconds(&self) -> i64;
++ fn num_microseconds(&self) -> i64;
++ fn num_nanoseconds(&self) -> i64;
++}
++
++#[repr(C)]
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub struct TimeSpec(timespec);
++
++const NANOS_PER_SEC: i64 = 1_000_000_000;
++const SECS_PER_MINUTE: i64 = 60;
++const SECS_PER_HOUR: i64 = 3600;
++
++#[cfg(target_pointer_width = "64")]
++const TS_MAX_SECONDS: i64 = (::std::i64::MAX / NANOS_PER_SEC) - 1;
++
++#[cfg(target_pointer_width = "32")]
++const TS_MAX_SECONDS: i64 = ::std::isize::MAX as i64;
++
++const TS_MIN_SECONDS: i64 = -TS_MAX_SECONDS;
++
++
++impl AsRef<timespec> for TimeSpec {
++ fn as_ref(&self) -> &timespec {
++ &self.0
++ }
++}
++
++impl Ord for TimeSpec {
++ // The implementation of cmp is simplified by assuming that the struct is
++ // normalized. That is, tv_nsec must always be within [0, 1_000_000_000)
++ fn cmp(&self, other: &TimeSpec) -> cmp::Ordering {
++ if self.tv_sec() == other.tv_sec() {
++ self.tv_nsec().cmp(&other.tv_nsec())
++ } else {
++ self.tv_sec().cmp(&other.tv_sec())
++ }
++ }
++}
++
++impl PartialOrd for TimeSpec {
++ fn partial_cmp(&self, other: &TimeSpec) -> Option<cmp::Ordering> {
++ Some(self.cmp(other))
++ }
++}
++
++impl TimeValLike for TimeSpec {
++ #[inline]
++ fn seconds(seconds: i64) -> TimeSpec {
++ assert!(seconds >= TS_MIN_SECONDS && seconds <= TS_MAX_SECONDS,
++ "TimeSpec out of bounds; seconds={}", seconds);
++ TimeSpec(timespec {tv_sec: seconds as time_t, tv_nsec: 0 })
++ }
++
++ #[inline]
++ fn milliseconds(milliseconds: i64) -> TimeSpec {
++ let nanoseconds = milliseconds.checked_mul(1_000_000)
++ .expect("TimeSpec::milliseconds out of bounds");
++
++ TimeSpec::nanoseconds(nanoseconds)
++ }
++
++ /// Makes a new `TimeSpec` with given number of microseconds.
++ #[inline]
++ fn microseconds(microseconds: i64) -> TimeSpec {
++ let nanoseconds = microseconds.checked_mul(1_000)
++ .expect("TimeSpec::milliseconds out of bounds");
++
++ TimeSpec::nanoseconds(nanoseconds)
++ }
++
++ /// Makes a new `TimeSpec` with given number of nanoseconds.
++ #[inline]
++ fn nanoseconds(nanoseconds: i64) -> TimeSpec {
++ let (secs, nanos) = div_mod_floor_64(nanoseconds, NANOS_PER_SEC);
++ assert!(secs >= TS_MIN_SECONDS && secs <= TS_MAX_SECONDS,
++ "TimeSpec out of bounds");
++ TimeSpec(timespec {tv_sec: secs as time_t,
++ tv_nsec: nanos as c_long })
++ }
++
++ fn num_seconds(&self) -> i64 {
++ if self.tv_sec() < 0 && self.tv_nsec() > 0 {
++ (self.tv_sec() + 1) as i64
++ } else {
++ self.tv_sec() as i64
++ }
++ }
++
++ fn num_milliseconds(&self) -> i64 {
++ self.num_nanoseconds() / 1_000_000
++ }
++
++ fn num_microseconds(&self) -> i64 {
++ self.num_nanoseconds() / 1_000_000_000
++ }
++
++ fn num_nanoseconds(&self) -> i64 {
++ let secs = self.num_seconds() * 1_000_000_000;
++ let nsec = self.nanos_mod_sec();
++ secs + nsec as i64
++ }
++}
++
++impl TimeSpec {
++ fn nanos_mod_sec(&self) -> c_long {
++ if self.tv_sec() < 0 && self.tv_nsec() > 0 {
++ self.tv_nsec() - NANOS_PER_SEC as c_long
++ } else {
++ self.tv_nsec()
++ }
++ }
++
++ pub fn tv_sec(&self) -> time_t {
++ self.0.tv_sec
++ }
++
++ pub fn tv_nsec(&self) -> c_long {
++ self.0.tv_nsec
++ }
++}
++
++impl ops::Neg for TimeSpec {
++ type Output = TimeSpec;
++
++ fn neg(self) -> TimeSpec {
++ TimeSpec::nanoseconds(-self.num_nanoseconds())
++ }
++}
++
++impl ops::Add for TimeSpec {
++ type Output = TimeSpec;
++
++ fn add(self, rhs: TimeSpec) -> TimeSpec {
++ TimeSpec::nanoseconds(
++ self.num_nanoseconds() + rhs.num_nanoseconds())
++ }
++}
++
++impl ops::Sub for TimeSpec {
++ type Output = TimeSpec;
++
++ fn sub(self, rhs: TimeSpec) -> TimeSpec {
++ TimeSpec::nanoseconds(
++ self.num_nanoseconds() - rhs.num_nanoseconds())
++ }
++}
++
++impl ops::Mul<i32> for TimeSpec {
++ type Output = TimeSpec;
++
++ fn mul(self, rhs: i32) -> TimeSpec {
++ let usec = self.num_nanoseconds().checked_mul(rhs as i64)
++ .expect("TimeSpec multiply out of bounds");
++
++ TimeSpec::nanoseconds(usec)
++ }
++}
++
++impl ops::Div<i32> for TimeSpec {
++ type Output = TimeSpec;
++
++ fn div(self, rhs: i32) -> TimeSpec {
++ let usec = self.num_nanoseconds() / rhs as i64;
++ TimeSpec::nanoseconds(usec)
++ }
++}
++
++impl fmt::Display for TimeSpec {
++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++ let (abs, sign) = if self.tv_sec() < 0 {
++ (-*self, "-")
++ } else {
++ (*self, "")
++ };
++
++ let sec = abs.tv_sec();
++
++ write!(f, "{}", sign)?;
++
++ if abs.tv_nsec() == 0 {
++ if abs.tv_sec() == 1 {
++ write!(f, "{} second", sec)?;
++ } else {
++ write!(f, "{} seconds", sec)?;
++ }
++ } else if abs.tv_nsec() % 1_000_000 == 0 {
++ write!(f, "{}.{:03} seconds", sec, abs.tv_nsec() / 1_000_000)?;
++ } else if abs.tv_nsec() % 1_000 == 0 {
++ write!(f, "{}.{:06} seconds", sec, abs.tv_nsec() / 1_000)?;
++ } else {
++ write!(f, "{}.{:09} seconds", sec, abs.tv_nsec())?;
++ }
++
++ Ok(())
++ }
++}
++
++
++
++#[repr(C)]
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub struct TimeVal(timeval);
++
++const MICROS_PER_SEC: i64 = 1_000_000;
++
++#[cfg(target_pointer_width = "64")]
++const TV_MAX_SECONDS: i64 = (::std::i64::MAX / MICROS_PER_SEC) - 1;
++
++#[cfg(target_pointer_width = "32")]
++const TV_MAX_SECONDS: i64 = ::std::isize::MAX as i64;
++
++const TV_MIN_SECONDS: i64 = -TV_MAX_SECONDS;
++
++impl AsRef<timeval> for TimeVal {
++ fn as_ref(&self) -> &timeval {
++ &self.0
++ }
++}
++
++impl Ord for TimeVal {
++ // The implementation of cmp is simplified by assuming that the struct is
++ // normalized. That is, tv_usec must always be within [0, 1_000_000)
++ fn cmp(&self, other: &TimeVal) -> cmp::Ordering {
++ if self.tv_sec() == other.tv_sec() {
++ self.tv_usec().cmp(&other.tv_usec())
++ } else {
++ self.tv_sec().cmp(&other.tv_sec())
++ }
++ }
++}
++
++impl PartialOrd for TimeVal {
++ fn partial_cmp(&self, other: &TimeVal) -> Option<cmp::Ordering> {
++ Some(self.cmp(other))
++ }
++}
++
++impl TimeValLike for TimeVal {
++ #[inline]
++ fn seconds(seconds: i64) -> TimeVal {
++ assert!(seconds >= TV_MIN_SECONDS && seconds <= TV_MAX_SECONDS,
++ "TimeVal out of bounds; seconds={}", seconds);
++ TimeVal(timeval {tv_sec: seconds as time_t, tv_usec: 0 })
++ }
++
++ #[inline]
++ fn milliseconds(milliseconds: i64) -> TimeVal {
++ let microseconds = milliseconds.checked_mul(1_000)
++ .expect("TimeVal::milliseconds out of bounds");
++
++ TimeVal::microseconds(microseconds)
++ }
++
++ /// Makes a new `TimeVal` with given number of microseconds.
++ #[inline]
++ fn microseconds(microseconds: i64) -> TimeVal {
++ let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
++ assert!(secs >= TV_MIN_SECONDS && secs <= TV_MAX_SECONDS,
++ "TimeVal out of bounds");
++ TimeVal(timeval {tv_sec: secs as time_t,
++ tv_usec: micros as suseconds_t })
++ }
++
++ /// Makes a new `TimeVal` with given number of nanoseconds. Some precision
++ /// will be lost
++ #[inline]
++ fn nanoseconds(nanoseconds: i64) -> TimeVal {
++ let microseconds = nanoseconds / 1000;
++ let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
++ assert!(secs >= TV_MIN_SECONDS && secs <= TV_MAX_SECONDS,
++ "TimeVal out of bounds");
++ TimeVal(timeval {tv_sec: secs as time_t,
++ tv_usec: micros as suseconds_t })
++ }
++
++ fn num_seconds(&self) -> i64 {
++ if self.tv_sec() < 0 && self.tv_usec() > 0 {
++ (self.tv_sec() + 1) as i64
++ } else {
++ self.tv_sec() as i64
++ }
++ }
++
++ fn num_milliseconds(&self) -> i64 {
++ self.num_microseconds() / 1_000
++ }
++
++ fn num_microseconds(&self) -> i64 {
++ let secs = self.num_seconds() * 1_000_000;
++ let usec = self.micros_mod_sec();
++ secs + usec as i64
++ }
++
++ fn num_nanoseconds(&self) -> i64 {
++ self.num_microseconds() * 1_000
++ }
++}
++
++impl TimeVal {
++ fn micros_mod_sec(&self) -> suseconds_t {
++ if self.tv_sec() < 0 && self.tv_usec() > 0 {
++ self.tv_usec() - MICROS_PER_SEC as suseconds_t
++ } else {
++ self.tv_usec()
++ }
++ }
++
++ pub fn tv_sec(&self) -> time_t {
++ self.0.tv_sec
++ }
++
++ pub fn tv_usec(&self) -> suseconds_t {
++ self.0.tv_usec
++ }
++}
++
++impl ops::Neg for TimeVal {
++ type Output = TimeVal;
++
++ fn neg(self) -> TimeVal {
++ TimeVal::microseconds(-self.num_microseconds())
++ }
++}
++
++impl ops::Add for TimeVal {
++ type Output = TimeVal;
++
++ fn add(self, rhs: TimeVal) -> TimeVal {
++ TimeVal::microseconds(
++ self.num_microseconds() + rhs.num_microseconds())
++ }
++}
++
++impl ops::Sub for TimeVal {
++ type Output = TimeVal;
++
++ fn sub(self, rhs: TimeVal) -> TimeVal {
++ TimeVal::microseconds(
++ self.num_microseconds() - rhs.num_microseconds())
++ }
++}
++
++impl ops::Mul<i32> for TimeVal {
++ type Output = TimeVal;
++
++ fn mul(self, rhs: i32) -> TimeVal {
++ let usec = self.num_microseconds().checked_mul(rhs as i64)
++ .expect("TimeVal multiply out of bounds");
++
++ TimeVal::microseconds(usec)
++ }
++}
++
++impl ops::Div<i32> for TimeVal {
++ type Output = TimeVal;
++
++ fn div(self, rhs: i32) -> TimeVal {
++ let usec = self.num_microseconds() / rhs as i64;
++ TimeVal::microseconds(usec)
++ }
++}
++
++impl fmt::Display for TimeVal {
++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++ let (abs, sign) = if self.tv_sec() < 0 {
++ (-*self, "-")
++ } else {
++ (*self, "")
++ };
++
++ let sec = abs.tv_sec();
++
++ write!(f, "{}", sign)?;
++
++ if abs.tv_usec() == 0 {
++ if abs.tv_sec() == 1 {
++ write!(f, "{} second", sec)?;
++ } else {
++ write!(f, "{} seconds", sec)?;
++ }
++ } else if abs.tv_usec() % 1000 == 0 {
++ write!(f, "{}.{:03} seconds", sec, abs.tv_usec() / 1000)?;
++ } else {
++ write!(f, "{}.{:06} seconds", sec, abs.tv_usec())?;
++ }
++
++ Ok(())
++ }
++}
++
++impl From<timeval> for TimeVal {
++ fn from(tv: timeval) -> Self {
++ TimeVal(tv)
++ }
++}
++
++#[inline]
++fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) {
++ (div_floor_64(this, other), mod_floor_64(this, other))
++}
++
++#[inline]
++fn div_floor_64(this: i64, other: i64) -> i64 {
++ match div_rem_64(this, other) {
++ (d, r) if (r > 0 && other < 0)
++ || (r < 0 && other > 0) => d - 1,
++ (d, _) => d,
++ }
++}
++
++#[inline]
++fn mod_floor_64(this: i64, other: i64) -> i64 {
++ match this % other {
++ r if (r > 0 && other < 0)
++ || (r < 0 && other > 0) => r + other,
++ r => r,
++ }
++}
++
++#[inline]
++fn div_rem_64(this: i64, other: i64) -> (i64, i64) {
++ (this / other, this % other)
++}
++
++#[cfg(test)]
++mod test {
++ use super::{TimeSpec, TimeVal, TimeValLike};
++
++ #[test]
++ pub fn test_timespec() {
++ assert!(TimeSpec::seconds(1) != TimeSpec::zero());
++ assert_eq!(TimeSpec::seconds(1) + TimeSpec::seconds(2),
++ TimeSpec::seconds(3));
++ assert_eq!(TimeSpec::minutes(3) + TimeSpec::seconds(2),
++ TimeSpec::seconds(182));
++ }
++
++ #[test]
++ pub fn test_timespec_neg() {
++ let a = TimeSpec::seconds(1) + TimeSpec::nanoseconds(123);
++ let b = TimeSpec::seconds(-1) + TimeSpec::nanoseconds(-123);
++
++ assert_eq!(a, -b);
++ }
++
++ #[test]
++ pub fn test_timespec_ord() {
++ assert!(TimeSpec::seconds(1) == TimeSpec::nanoseconds(1_000_000_000));
++ assert!(TimeSpec::seconds(1) < TimeSpec::nanoseconds(1_000_000_001));
++ assert!(TimeSpec::seconds(1) > TimeSpec::nanoseconds(999_999_999));
++ assert!(TimeSpec::seconds(-1) < TimeSpec::nanoseconds(-999_999_999));
++ assert!(TimeSpec::seconds(-1) > TimeSpec::nanoseconds(-1_000_000_001));
++ }
++
++ #[test]
++ pub fn test_timespec_fmt() {
++ assert_eq!(TimeSpec::zero().to_string(), "0 seconds");
++ assert_eq!(TimeSpec::seconds(42).to_string(), "42 seconds");
++ assert_eq!(TimeSpec::milliseconds(42).to_string(), "0.042 seconds");
++ assert_eq!(TimeSpec::microseconds(42).to_string(), "0.000042 seconds");
++ assert_eq!(TimeSpec::nanoseconds(42).to_string(), "0.000000042 seconds");
++ assert_eq!(TimeSpec::seconds(-86401).to_string(), "-86401 seconds");
++ }
++
++ #[test]
++ pub fn test_timeval() {
++ assert!(TimeVal::seconds(1) != TimeVal::zero());
++ assert_eq!(TimeVal::seconds(1) + TimeVal::seconds(2),
++ TimeVal::seconds(3));
++ assert_eq!(TimeVal::minutes(3) + TimeVal::seconds(2),
++ TimeVal::seconds(182));
++ }
++
++ #[test]
++ pub fn test_timeval_ord() {
++ assert!(TimeVal::seconds(1) == TimeVal::microseconds(1_000_000));
++ assert!(TimeVal::seconds(1) < TimeVal::microseconds(1_000_001));
++ assert!(TimeVal::seconds(1) > TimeVal::microseconds(999_999));
++ assert!(TimeVal::seconds(-1) < TimeVal::microseconds(-999_999));
++ assert!(TimeVal::seconds(-1) > TimeVal::microseconds(-1_000_001));
++ }
++
++ #[test]
++ pub fn test_timeval_neg() {
++ let a = TimeVal::seconds(1) + TimeVal::microseconds(123);
++ let b = TimeVal::seconds(-1) + TimeVal::microseconds(-123);
++
++ assert_eq!(a, -b);
++ }
++
++ #[test]
++ pub fn test_timeval_fmt() {
++ assert_eq!(TimeVal::zero().to_string(), "0 seconds");
++ assert_eq!(TimeVal::seconds(42).to_string(), "42 seconds");
++ assert_eq!(TimeVal::milliseconds(42).to_string(), "0.042 seconds");
++ assert_eq!(TimeVal::microseconds(42).to_string(), "0.000042 seconds");
++ assert_eq!(TimeVal::nanoseconds(1402).to_string(), "0.000001 seconds");
++ assert_eq!(TimeVal::seconds(-86401).to_string(), "-86401 seconds");
++ }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/uio.rs b/third_party/rust/nix-0.15.0/src/sys/uio.rs
+new file mode 100644
+index 0000000000000..d089084eed711
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/uio.rs
+@@ -0,0 +1,194 @@
++// Silence invalid warnings due to rust-lang/rust#16719
++#![allow(improper_ctypes)]
++
++use Result;
++use errno::Errno;
++use libc::{self, c_int, c_void, size_t, off_t};
++use std::marker::PhantomData;
++use std::os::unix::io::RawFd;
++
++pub fn writev(fd: RawFd, iov: &[IoVec<&[u8]>]) -> Result<usize> {
++ let res = unsafe { libc::writev(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int) };
++
++ Errno::result(res).map(|r| r as usize)
++}
++
++pub fn readv(fd: RawFd, iov: &mut [IoVec<&mut [u8]>]) -> Result<usize> {
++ let res = unsafe { libc::readv(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int) };
++
++ Errno::result(res).map(|r| r as usize)
++}
++
++/// Write to `fd` at `offset` from buffers in `iov`.
++///
++/// Buffers in `iov` will be written in order until all buffers have been written
++/// or an error occurs. The file offset is not changed.
++///
++/// See also: [`writev`](fn.writev.html) and [`pwrite`](fn.pwrite.html)
++#[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "linux",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++pub fn pwritev(fd: RawFd, iov: &[IoVec<&[u8]>],
++ offset: off_t) -> Result<usize> {
++ let res = unsafe {
++ libc::pwritev(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int, offset)
++ };
++
++ Errno::result(res).map(|r| r as usize)
++}
++
++/// Read from `fd` at `offset` filling buffers in `iov`.
++///
++/// Buffers in `iov` will be filled in order until all buffers have been filled,
++/// no more bytes are available, or an error occurs. The file offset is not
++/// changed.
++///
++/// See also: [`readv`](fn.readv.html) and [`pread`](fn.pread.html)
++#[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "linux",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++pub fn preadv(fd: RawFd, iov: &[IoVec<&mut [u8]>],
++ offset: off_t) -> Result<usize> {
++ let res = unsafe {
++ libc::preadv(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int, offset)
++ };
++
++ Errno::result(res).map(|r| r as usize)
++}
++
++pub fn pwrite(fd: RawFd, buf: &[u8], offset: off_t) -> Result<usize> {
++ let res = unsafe {
++ libc::pwrite(fd, buf.as_ptr() as *const c_void, buf.len() as size_t,
++ offset)
++ };
++
++ Errno::result(res).map(|r| r as usize)
++}
++
++pub fn pread(fd: RawFd, buf: &mut [u8], offset: off_t) -> Result<usize>{
++ let res = unsafe {
++ libc::pread(fd, buf.as_mut_ptr() as *mut c_void, buf.len() as size_t,
++ offset)
++ };
++
++ Errno::result(res).map(|r| r as usize)
++}
++
++/// A slice of memory in a remote process, starting at address `base`
++/// and consisting of `len` bytes.
++///
++/// This is the same underlying C structure as [`IoVec`](struct.IoVec.html),
++/// except that it refers to memory in some other process, and is
++/// therefore not represented in Rust by an actual slice as `IoVec` is. It
++/// is used with [`process_vm_readv`](fn.process_vm_readv.html)
++/// and [`process_vm_writev`](fn.process_vm_writev.html).
++#[cfg(target_os = "linux")]
++#[repr(C)]
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub struct RemoteIoVec {
++ /// The starting address of this slice (`iov_base`).
++ pub base: usize,
++ /// The number of bytes in this slice (`iov_len`).
++ pub len: usize,
++}
++
++/// Write data directly to another process's virtual memory
++/// (see [`process_vm_writev`(2)]).
++///
++/// `local_iov` is a list of [`IoVec`]s containing the data to be written,
++/// and `remote_iov` is a list of [`RemoteIoVec`]s identifying where the
++/// data should be written in the target process. On success, returns the
++/// number of bytes written, which will always be a whole
++/// number of `remote_iov` chunks.
++///
++/// This requires the same permissions as debugging the process using
++/// [ptrace]: you must either be a privileged process (with
++/// `CAP_SYS_PTRACE`), or you must be running as the same user as the
++/// target process and the OS must have unprivileged debugging enabled.
++///
++/// This function is only available on Linux.
++///
++/// [`process_vm_writev`(2)]: http://man7.org/linux/man-pages/man2/process_vm_writev.2.html
++/// [ptrace]: ../ptrace/index.html
++/// [`IoVec`]: struct.IoVec.html
++/// [`RemoteIoVec`]: struct.RemoteIoVec.html
++#[cfg(target_os = "linux")]
++pub fn process_vm_writev(pid: ::unistd::Pid, local_iov: &[IoVec<&[u8]>], remote_iov: &[RemoteIoVec]) -> Result<usize> {
++ let res = unsafe {
++ libc::process_vm_writev(pid.into(),
++ local_iov.as_ptr() as *const libc::iovec, local_iov.len() as libc::c_ulong,
++ remote_iov.as_ptr() as *const libc::iovec, remote_iov.len() as libc::c_ulong, 0)
++ };
++
++ Errno::result(res).map(|r| r as usize)
++}
++
++/// Read data directly from another process's virtual memory
++/// (see [`process_vm_readv`(2)]).
++///
++/// `local_iov` is a list of [`IoVec`]s containing the buffer to copy
++/// data into, and `remote_iov` is a list of [`RemoteIoVec`]s identifying
++/// where the source data is in the target process. On success,
++/// returns the number of bytes written, which will always be a whole
++/// number of `remote_iov` chunks.
++///
++/// This requires the same permissions as debugging the process using
++/// [`ptrace`]: you must either be a privileged process (with
++/// `CAP_SYS_PTRACE`), or you must be running as the same user as the
++/// target process and the OS must have unprivileged debugging enabled.
++///
++/// This function is only available on Linux.
++///
++/// [`process_vm_readv`(2)]: http://man7.org/linux/man-pages/man2/process_vm_readv.2.html
++/// [`ptrace`]: ../ptrace/index.html
++/// [`IoVec`]: struct.IoVec.html
++/// [`RemoteIoVec`]: struct.RemoteIoVec.html
++#[cfg(any(target_os = "linux"))]
++pub fn process_vm_readv(pid: ::unistd::Pid, local_iov: &[IoVec<&mut [u8]>], remote_iov: &[RemoteIoVec]) -> Result<usize> {
++ let res = unsafe {
++ libc::process_vm_readv(pid.into(),
++ local_iov.as_ptr() as *const libc::iovec, local_iov.len() as libc::c_ulong,
++ remote_iov.as_ptr() as *const libc::iovec, remote_iov.len() as libc::c_ulong, 0)
++ };
++
++ Errno::result(res).map(|r| r as usize)
++}
++
++#[repr(C)]
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub struct IoVec<T>(libc::iovec, PhantomData<T>);
++
++impl<T> IoVec<T> {
++ #[inline]
++ pub fn as_slice(&self) -> &[u8] {
++ use std::slice;
++
++ unsafe {
++ slice::from_raw_parts(
++ self.0.iov_base as *const u8,
++ self.0.iov_len as usize)
++ }
++ }
++}
++
++impl<'a> IoVec<&'a [u8]> {
++ pub fn from_slice(buf: &'a [u8]) -> IoVec<&'a [u8]> {
++ IoVec(libc::iovec {
++ iov_base: buf.as_ptr() as *mut c_void,
++ iov_len: buf.len() as size_t,
++ }, PhantomData)
++ }
++}
++
++impl<'a> IoVec<&'a mut [u8]> {
++ pub fn from_mut_slice(buf: &'a mut [u8]) -> IoVec<&'a mut [u8]> {
++ IoVec(libc::iovec {
++ iov_base: buf.as_ptr() as *mut c_void,
++ iov_len: buf.len() as size_t,
++ }, PhantomData)
++ }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/utsname.rs b/third_party/rust/nix-0.15.0/src/sys/utsname.rs
+new file mode 100644
+index 0000000000000..ab09c7d23232a
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/utsname.rs
+@@ -0,0 +1,67 @@
++use std::mem;
++use libc::{self, c_char};
++use std::ffi::CStr;
++use std::str::from_utf8_unchecked;
++
++#[repr(C)]
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub struct UtsName(libc::utsname);
++
++impl UtsName {
++ pub fn sysname(&self) -> &str {
++ to_str(&(&self.0.sysname as *const c_char ) as *const *const c_char)
++ }
++
++ pub fn nodename(&self) -> &str {
++ to_str(&(&self.0.nodename as *const c_char ) as *const *const c_char)
++ }
++
++ pub fn release(&self) -> &str {
++ to_str(&(&self.0.release as *const c_char ) as *const *const c_char)
++ }
++
++ pub fn version(&self) -> &str {
++ to_str(&(&self.0.version as *const c_char ) as *const *const c_char)
++ }
++
++ pub fn machine(&self) -> &str {
++ to_str(&(&self.0.machine as *const c_char ) as *const *const c_char)
++ }
++}
++
++pub fn uname() -> UtsName {
++ unsafe {
++ let mut ret: UtsName = mem::uninitialized();
++ libc::uname(&mut ret.0);
++ ret
++ }
++}
++
++#[inline]
++fn to_str<'a>(s: *const *const c_char) -> &'a str {
++ unsafe {
++ let res = CStr::from_ptr(*s).to_bytes();
++ from_utf8_unchecked(res)
++ }
++}
++
++#[cfg(test)]
++mod test {
++ #[cfg(target_os = "linux")]
++ #[test]
++ pub fn test_uname_linux() {
++ assert_eq!(super::uname().sysname(), "Linux");
++ }
++
++ #[cfg(any(target_os = "macos", target_os = "ios"))]
++ #[test]
++ pub fn test_uname_darwin() {
++ assert_eq!(super::uname().sysname(), "Darwin");
++ }
++
++ #[cfg(target_os = "freebsd")]
++ #[test]
++ pub fn test_uname_freebsd() {
++ assert_eq!(super::uname().sysname(), "FreeBSD");
++ }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/wait.rs b/third_party/rust/nix-0.15.0/src/sys/wait.rs
+new file mode 100644
+index 0000000000000..c54f7ec579667
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/wait.rs
+@@ -0,0 +1,239 @@
++use libc::{self, c_int};
++use Result;
++use errno::Errno;
++use unistd::Pid;
++
++use sys::signal::Signal;
++
++libc_bitflags!(
++ pub struct WaitPidFlag: c_int {
++ WNOHANG;
++ WUNTRACED;
++ #[cfg(any(target_os = "android",
++ target_os = "freebsd",
++ target_os = "haiku",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos",
++ target_os = "netbsd"))]
++ WEXITED;
++ WCONTINUED;
++ #[cfg(any(target_os = "android",
++ target_os = "freebsd",
++ target_os = "haiku",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos",
++ target_os = "netbsd"))]
++ WSTOPPED;
++ /// Don't reap, just poll status.
++ #[cfg(any(target_os = "android",
++ target_os = "freebsd",
++ target_os = "haiku",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos",
++ target_os = "netbsd"))]
++ WNOWAIT;
++ /// Don't wait on children of other threads in this group
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ __WNOTHREAD;
++ /// Wait on all children, regardless of type
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ __WALL;
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ __WCLONE;
++ }
++);
++
++/// Possible return values from `wait()` or `waitpid()`.
++///
++/// Each status (other than `StillAlive`) describes a state transition
++/// in a child process `Pid`, such as the process exiting or stopping,
++/// plus additional data about the transition if any.
++///
++/// Note that there are two Linux-specific enum variants, `PtraceEvent`
++/// and `PtraceSyscall`. Portable code should avoid exhaustively
++/// matching on `WaitStatus`.
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub enum WaitStatus {
++ /// The process exited normally (as with `exit()` or returning from
++ /// `main`) with the given exit code. This case matches the C macro
++ /// `WIFEXITED(status)`; the second field is `WEXITSTATUS(status)`.
++ Exited(Pid, i32),
++ /// The process was killed by the given signal. The third field
++ /// indicates whether the signal generated a core dump. This case
++ /// matches the C macro `WIFSIGNALED(status)`; the last two fields
++ /// correspond to `WTERMSIG(status)` and `WCOREDUMP(status)`.
++ Signaled(Pid, Signal, bool),
++ /// The process is alive, but was stopped by the given signal. This
++ /// is only reported if `WaitPidFlag::WUNTRACED` was passed. This
++ /// case matches the C macro `WIFSTOPPED(status)`; the second field
++ /// is `WSTOPSIG(status)`.
++ Stopped(Pid, Signal),
++ /// The traced process was stopped by a `PTRACE_EVENT_*` event. See
++ /// [`nix::sys::ptrace`] and [`ptrace`(2)] for more information. All
++ /// currently-defined events use `SIGTRAP` as the signal; the third
++ /// field is the `PTRACE_EVENT_*` value of the event.
++ ///
++ /// [`nix::sys::ptrace`]: ../ptrace/index.html
++ /// [`ptrace`(2)]: http://man7.org/linux/man-pages/man2/ptrace.2.html
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ PtraceEvent(Pid, Signal, c_int),
++ /// The traced process was stopped by execution of a system call,
++ /// and `PTRACE_O_TRACESYSGOOD` is in effect. See [`ptrace`(2)] for
++ /// more information.
++ ///
++ /// [`ptrace`(2)]: http://man7.org/linux/man-pages/man2/ptrace.2.html
++ #[cfg(any(target_os = "linux", target_os = "android"))]
++ PtraceSyscall(Pid),
++ /// The process was previously stopped but has resumed execution
++ /// after receiving a `SIGCONT` signal. This is only reported if
++ /// `WaitPidFlag::WCONTINUED` was passed. This case matches the C
++ /// macro `WIFCONTINUED(status)`.
++ Continued(Pid),
++ /// There are currently no state changes to report in any awaited
++ /// child process. This is only returned if `WaitPidFlag::WNOHANG`
++ /// was used (otherwise `wait()` or `waitpid()` would block until
++ /// there was something to report).
++ StillAlive,
++}
++
++impl WaitStatus {
++ /// Extracts the PID from the WaitStatus unless it equals StillAlive.
++ pub fn pid(&self) -> Option<Pid> {
++ use self::WaitStatus::*;
++ match *self {
++ Exited(p, _) | Signaled(p, _, _) |
++ Stopped(p, _) | Continued(p) => Some(p),
++ StillAlive => None,
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ PtraceEvent(p, _, _) | PtraceSyscall(p) => Some(p),
++ }
++ }
++}
++
++fn exited(status: i32) -> bool {
++ unsafe { libc::WIFEXITED(status) }
++}
++
++fn exit_status(status: i32) -> i32 {
++ unsafe { libc::WEXITSTATUS(status) }
++}
++
++fn signaled(status: i32) -> bool {
++ unsafe { libc::WIFSIGNALED(status) }
++}
++
++fn term_signal(status: i32) -> Result<Signal> {
++ Signal::from_c_int(unsafe { libc::WTERMSIG(status) })
++}
++
++fn dumped_core(status: i32) -> bool {
++ unsafe { libc::WCOREDUMP(status) }
++}
++
++fn stopped(status: i32) -> bool {
++ unsafe { libc::WIFSTOPPED(status) }
++}
++
++fn stop_signal(status: i32) -> Result<Signal> {
++ Signal::from_c_int(unsafe { libc::WSTOPSIG(status) })
++}
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++fn syscall_stop(status: i32) -> bool {
++ // From ptrace(2), setting PTRACE_O_TRACESYSGOOD has the effect
++ // of delivering SIGTRAP | 0x80 as the signal number for syscall
++ // stops. This allows easily distinguishing syscall stops from
++ // genuine SIGTRAP signals.
++ unsafe { libc::WSTOPSIG(status) == libc::SIGTRAP | 0x80 }
++}
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++fn stop_additional(status: i32) -> c_int {
++ (status >> 16) as c_int
++}
++
++fn continued(status: i32) -> bool {
++ unsafe { libc::WIFCONTINUED(status) }
++}
++
++impl WaitStatus {
++ /// Convert a raw `wstatus` as returned by `waitpid`/`wait` into a `WaitStatus`
++ ///
++ /// # Errors
++ ///
++ /// Returns an `Error` corresponding to `EINVAL` for invalid status values.
++ ///
++ /// # Examples
++ ///
++ /// Convert a `wstatus` obtained from `libc::waitpid` into a `WaitStatus`:
++ ///
++ /// ```
++ /// use nix::sys::wait::WaitStatus;
++ /// use nix::sys::signal::Signal;
++ /// let pid = nix::unistd::Pid::from_raw(1);
++ /// let status = WaitStatus::from_raw(pid, 0x0002);
++ /// assert_eq!(status, Ok(WaitStatus::Signaled(pid, Signal::SIGINT, false)));
++ /// ```
++ pub fn from_raw(pid: Pid, status: i32) -> Result<WaitStatus> {
++ Ok(if exited(status) {
++ WaitStatus::Exited(pid, exit_status(status))
++ } else if signaled(status) {
++ WaitStatus::Signaled(pid, term_signal(status)?, dumped_core(status))
++ } else if stopped(status) {
++ cfg_if! {
++ if #[cfg(any(target_os = "android", target_os = "linux"))] {
++ fn decode_stopped(pid: Pid, status: i32) -> Result<WaitStatus> {
++ let status_additional = stop_additional(status);
++ Ok(if syscall_stop(status) {
++ WaitStatus::PtraceSyscall(pid)
++ } else if status_additional == 0 {
++ WaitStatus::Stopped(pid, stop_signal(status)?)
++ } else {
++ WaitStatus::PtraceEvent(pid, stop_signal(status)?,
++ stop_additional(status))
++ })
++ }
++ } else {
++ fn decode_stopped(pid: Pid, status: i32) -> Result<WaitStatus> {
++ Ok(WaitStatus::Stopped(pid, stop_signal(status)?))
++ }
++ }
++ }
++ return decode_stopped(pid, status);
++ } else {
++ assert!(continued(status));
++ WaitStatus::Continued(pid)
++ })
++ }
++}
++
++pub fn waitpid<P: Into<Option<Pid>>>(pid: P, options: Option<WaitPidFlag>) -> Result<WaitStatus> {
++ use self::WaitStatus::*;
++
++ let mut status: i32 = 0;
++
++ let option_bits = match options {
++ Some(bits) => bits.bits(),
++ None => 0,
++ };
++
++ let res = unsafe {
++ libc::waitpid(
++ pid.into().unwrap_or(Pid::from_raw(-1)).into(),
++ &mut status as *mut c_int,
++ option_bits,
++ )
++ };
++
++ match Errno::result(res)? {
++ 0 => Ok(StillAlive),
++ res => WaitStatus::from_raw(Pid::from_raw(res), status),
++ }
++}
++
++pub fn wait() -> Result<WaitStatus> {
++ waitpid(None, None)
++}
+diff --git a/third_party/rust/nix-0.15.0/src/ucontext.rs b/third_party/rust/nix-0.15.0/src/ucontext.rs
+new file mode 100644
+index 0000000000000..5e10e7d1f8934
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/ucontext.rs
+@@ -0,0 +1,39 @@
++use libc;
++#[cfg(not(target_env = "musl"))]
++use Result;
++#[cfg(not(target_env = "musl"))]
++use errno::Errno;
++use std::mem;
++use sys::signal::SigSet;
++
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub struct UContext {
++ context: libc::ucontext_t,
++}
++
++impl UContext {
++ #[cfg(not(target_env = "musl"))]
++ pub fn get() -> Result<UContext> {
++ let mut context: libc::ucontext_t = unsafe { mem::uninitialized() };
++ let res = unsafe {
++ libc::getcontext(&mut context as *mut libc::ucontext_t)
++ };
++ Errno::result(res).map(|_| UContext { context: context })
++ }
++
++ #[cfg(not(target_env = "musl"))]
++ pub fn set(&self) -> Result<()> {
++ let res = unsafe {
++ libc::setcontext(&self.context as *const libc::ucontext_t)
++ };
++ Errno::result(res).map(drop)
++ }
++
++ pub fn sigmask_mut(&mut self) -> &mut SigSet {
++ unsafe { mem::transmute(&mut self.context.uc_sigmask) }
++ }
++
++ pub fn sigmask(&self) -> &SigSet {
++ unsafe { mem::transmute(&self.context.uc_sigmask) }
++ }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/unistd.rs b/third_party/rust/nix-0.15.0/src/unistd.rs
+new file mode 100644
+index 0000000000000..f422f09198655
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/unistd.rs
+@@ -0,0 +1,2394 @@
++//! Safe wrappers around functions found in libc "unistd.h" header
++
++use errno::{self, Errno};
++use {Error, Result, NixPath};
++use fcntl::{AtFlags, at_rawfd, fcntl, FdFlag, OFlag};
++use fcntl::FcntlArg::F_SETFD;
++use libc::{self, c_char, c_void, c_int, c_long, c_uint, size_t, pid_t, off_t,
++ uid_t, gid_t, mode_t};
++use std::{fmt, mem, ptr};
++use std::ffi::{CString, CStr, OsString, OsStr};
++use std::os::unix::ffi::{OsStringExt, OsStrExt};
++use std::os::unix::io::RawFd;
++use std::path::PathBuf;
++use void::Void;
++use sys::stat::Mode;
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++pub use self::pivot_root::*;
++
++#[cfg(any(target_os = "android", target_os = "freebsd",
++ target_os = "linux", target_os = "openbsd"))]
++pub use self::setres::*;
++
++/// User identifier
++///
++/// Newtype pattern around `uid_t` (which is just alias). It prevents bugs caused by accidentally
++/// passing wrong value.
++#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
++pub struct Uid(uid_t);
++
++impl Uid {
++ /// Creates `Uid` from raw `uid_t`.
++ pub fn from_raw(uid: uid_t) -> Self {
++ Uid(uid)
++ }
++
++ /// Returns Uid of calling process. This is practically a more Rusty alias for `getuid`.
++ pub fn current() -> Self {
++ getuid()
++ }
++
++ /// Returns effective Uid of calling process. This is practically a more Rusty alias for `geteuid`.
++ pub fn effective() -> Self {
++ geteuid()
++ }
++
++ /// Returns true if the `Uid` represents privileged user - root. (If it equals zero.)
++ pub fn is_root(&self) -> bool {
++ *self == ROOT
++ }
++
++ /// Get the raw `uid_t` wrapped by `self`.
++ pub fn as_raw(&self) -> uid_t {
++ self.0
++ }
++}
++
++impl From<Uid> for uid_t {
++ fn from(uid: Uid) -> Self {
++ uid.0
++ }
++}
++
++impl fmt::Display for Uid {
++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++ fmt::Display::fmt(&self.0, f)
++ }
++}
++
++/// Constant for UID = 0
++pub const ROOT: Uid = Uid(0);
++
++/// Group identifier
++///
++/// Newtype pattern around `gid_t` (which is just alias). It prevents bugs caused by accidentally
++/// passing wrong value.
++#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
++pub struct Gid(gid_t);
++
++impl Gid {
++ /// Creates `Gid` from raw `gid_t`.
++ pub fn from_raw(gid: gid_t) -> Self {
++ Gid(gid)
++ }
++
++ /// Returns Gid of calling process. This is practically a more Rusty alias for `getgid`.
++ pub fn current() -> Self {
++ getgid()
++ }
++
++ /// Returns effective Gid of calling process. This is practically a more Rusty alias for `getgid`.
++ pub fn effective() -> Self {
++ getegid()
++ }
++
++ /// Get the raw `gid_t` wrapped by `self`.
++ pub fn as_raw(&self) -> gid_t {
++ self.0
++ }
++}
++
++impl From<Gid> for gid_t {
++ fn from(gid: Gid) -> Self {
++ gid.0
++ }
++}
++
++impl fmt::Display for Gid {
++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++ fmt::Display::fmt(&self.0, f)
++ }
++}
++
++/// Process identifier
++///
++/// Newtype pattern around `pid_t` (which is just alias). It prevents bugs caused by accidentally
++/// passing wrong value.
++#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
++pub struct Pid(pid_t);
++
++impl Pid {
++ /// Creates `Pid` from raw `pid_t`.
++ pub fn from_raw(pid: pid_t) -> Self {
++ Pid(pid)
++ }
++
++ /// Returns PID of calling process
++ pub fn this() -> Self {
++ getpid()
++ }
++
++ /// Returns PID of parent of calling process
++ pub fn parent() -> Self {
++ getppid()
++ }
++
++ /// Get the raw `pid_t` wrapped by `self`.
++ pub fn as_raw(&self) -> pid_t {
++ self.0
++ }
++}
++
++impl From<Pid> for pid_t {
++ fn from(pid: Pid) -> Self {
++ pid.0
++ }
++}
++
++impl fmt::Display for Pid {
++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++ fmt::Display::fmt(&self.0, f)
++ }
++}
++
++
++/// Represents the successful result of calling `fork`
++///
++/// When `fork` is called, the process continues execution in the parent process
++/// and in the new child. This return type can be examined to determine whether
++/// you are now executing in the parent process or in the child.
++#[derive(Clone, Copy, Debug)]
++pub enum ForkResult {
++ Parent { child: Pid },
++ Child,
++}
++
++impl ForkResult {
++
++ /// Return `true` if this is the child process of the `fork()`
++ #[inline]
++ pub fn is_child(&self) -> bool {
++ match *self {
++ ForkResult::Child => true,
++ _ => false
++ }
++ }
++
++ /// Returns `true` if this is the parent process of the `fork()`
++ #[inline]
++ pub fn is_parent(&self) -> bool {
++ !self.is_child()
++ }
++}
++
++/// Create a new child process duplicating the parent process ([see
++/// fork(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html)).
++///
++/// After calling the fork system call (successfully) two processes will
++/// be created that are identical with the exception of their pid and the
++/// return value of this function. As an example:
++///
++/// ```no_run
++/// use nix::unistd::{fork, ForkResult};
++///
++/// match fork() {
++/// Ok(ForkResult::Parent { child, .. }) => {
++/// println!("Continuing execution in parent process, new child has pid: {}", child);
++/// }
++/// Ok(ForkResult::Child) => println!("I'm a new child process"),
++/// Err(_) => println!("Fork failed"),
++/// }
++/// ```
++///
++/// This will print something like the following (order indeterministic). The
++/// thing to note is that you end up with two processes continuing execution
++/// immediately after the fork call but with different match arms.
++///
++/// ```text
++/// Continuing execution in parent process, new child has pid: 1234
++/// I'm a new child process
++/// ```
++///
++/// # Safety
++///
++/// In a multithreaded program, only [async-signal-safe] functions like `pause`
++/// and `_exit` may be called by the child (the parent isn't restricted). Note
++/// that memory allocation may **not** be async-signal-safe and thus must be
++/// prevented.
++///
++/// Those functions are only a small subset of your operating system's API, so
++/// special care must be taken to only invoke code you can control and audit.
++///
++/// [async-signal-safe]: http://man7.org/linux/man-pages/man7/signal-safety.7.html
++#[inline]
++pub fn fork() -> Result<ForkResult> {
++ use self::ForkResult::*;
++ let res = unsafe { libc::fork() };
++
++ Errno::result(res).map(|res| match res {
++ 0 => Child,
++ res => Parent { child: Pid(res) },
++ })
++}
++
++/// Get the pid of this process (see
++/// [getpid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpid.html)).
++///
++/// Since you are running code, there is always a pid to return, so there
++/// is no error case that needs to be handled.
++#[inline]
++pub fn getpid() -> Pid {
++ Pid(unsafe { libc::getpid() })
++}
++
++/// Get the pid of this processes' parent (see
++/// [getpid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getppid.html)).
++///
++/// There is always a parent pid to return, so there is no error case that needs
++/// to be handled.
++#[inline]
++pub fn getppid() -> Pid {
++ Pid(unsafe { libc::getppid() }) // no error handling, according to man page: "These functions are always successful."
++}
++
++/// Set a process group ID (see
++/// [setpgid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setpgid.html)).
++///
++/// Set the process group id (PGID) of a particular process. If a pid of zero
++/// is specified, then the pid of the calling process is used. Process groups
++/// may be used to group together a set of processes in order for the OS to
++/// apply some operations across the group.
++///
++/// `setsid()` may be used to create a new process group.
++#[inline]
++pub fn setpgid(pid: Pid, pgid: Pid) -> Result<()> {
++ let res = unsafe { libc::setpgid(pid.into(), pgid.into()) };
++ Errno::result(res).map(drop)
++}
++#[inline]
++pub fn getpgid(pid: Option<Pid>) -> Result<Pid> {
++ let res = unsafe { libc::getpgid(pid.unwrap_or(Pid(0)).into()) };
++ Errno::result(res).map(Pid)
++}
++
++/// Create new session and set process group id (see
++/// [setsid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setsid.html)).
++#[inline]
++pub fn setsid() -> Result<Pid> {
++ Errno::result(unsafe { libc::setsid() }).map(Pid)
++}
++
++/// Get the process group ID of a session leader
++/// [getsid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getsid.html).
++///
++/// Obtain the process group ID of the process that is the session leader of the process specified
++/// by pid. If pid is zero, it specifies the calling process.
++#[inline]
++pub fn getsid(pid: Option<Pid>) -> Result<Pid> {
++ let res = unsafe { libc::getsid(pid.unwrap_or(Pid(0)).into()) };
++ Errno::result(res).map(Pid)
++}
++
++
++/// Get the terminal foreground process group (see
++/// [tcgetpgrp(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetpgrp.html)).
++///
++/// Get the group process id (GPID) of the foreground process group on the
++/// terminal associated to file descriptor (FD).
++#[inline]
++pub fn tcgetpgrp(fd: c_int) -> Result<Pid> {
++ let res = unsafe { libc::tcgetpgrp(fd) };
++ Errno::result(res).map(Pid)
++}
++/// Set the terminal foreground process group (see
++/// [tcgetpgrp(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsetpgrp.html)).
++///
++/// Get the group process id (PGID) to the foreground process group on the
++/// terminal associated to file descriptor (FD).
++#[inline]
++pub fn tcsetpgrp(fd: c_int, pgrp: Pid) -> Result<()> {
++ let res = unsafe { libc::tcsetpgrp(fd, pgrp.into()) };
++ Errno::result(res).map(drop)
++}
++
++
++/// Get the group id of the calling process (see
++///[getpgrp(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpgrp.html)).
++///
++/// Get the process group id (PGID) of the calling process.
++/// According to the man page it is always successful.
++#[inline]
++pub fn getpgrp() -> Pid {
++ Pid(unsafe { libc::getpgrp() })
++}
++
++/// Get the caller's thread ID (see
++/// [gettid(2)](http://man7.org/linux/man-pages/man2/gettid.2.html).
++///
++/// This function is only available on Linux based systems. In a single
++/// threaded process, the main thread will have the same ID as the process. In
++/// a multithreaded process, each thread will have a unique thread id but the
++/// same process ID.
++///
++/// No error handling is required as a thread id should always exist for any
++/// process, even if threads are not being used.
++#[cfg(any(target_os = "linux", target_os = "android"))]
++#[inline]
++pub fn gettid() -> Pid {
++ Pid(unsafe { libc::syscall(libc::SYS_gettid) as pid_t })
++}
++
++/// Create a copy of the specified file descriptor (see
++/// [dup(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/dup.html)).
++///
++/// The new file descriptor will be have a new index but refer to the same
++/// resource as the old file descriptor and the old and new file descriptors may
++/// be used interchangeably. The new and old file descriptor share the same
++/// underlying resource, offset, and file status flags. The actual index used
++/// for the file descriptor will be the lowest fd index that is available.
++///
++/// The two file descriptors do not share file descriptor flags (e.g. `OFlag::FD_CLOEXEC`).
++#[inline]
++pub fn dup(oldfd: RawFd) -> Result<RawFd> {
++ let res = unsafe { libc::dup(oldfd) };
++
++ Errno::result(res)
++}
++
++/// Create a copy of the specified file descriptor using the specified fd (see
++/// [dup(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/dup.html)).
++///
++/// This function behaves similar to `dup()` except that it will try to use the
++/// specified fd instead of allocating a new one. See the man pages for more
++/// detail on the exact behavior of this function.
++#[inline]
++pub fn dup2(oldfd: RawFd, newfd: RawFd) -> Result<RawFd> {
++ let res = unsafe { libc::dup2(oldfd, newfd) };
++
++ Errno::result(res)
++}
++
++/// Create a new copy of the specified file descriptor using the specified fd
++/// and flags (see [dup(2)](http://man7.org/linux/man-pages/man2/dup.2.html)).
++///
++/// This function behaves similar to `dup2()` but allows for flags to be
++/// specified.
++pub fn dup3(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd> {
++ dup3_polyfill(oldfd, newfd, flags)
++}
++
++#[inline]
++fn dup3_polyfill(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd> {
++ if oldfd == newfd {
++ return Err(Error::Sys(Errno::EINVAL));
++ }
++
++ let fd = dup2(oldfd, newfd)?;
++
++ if flags.contains(OFlag::O_CLOEXEC) {
++ if let Err(e) = fcntl(fd, F_SETFD(FdFlag::FD_CLOEXEC)) {
++ let _ = close(fd);
++ return Err(e);
++ }
++ }
++
++ Ok(fd)
++}
++
++/// Change the current working directory of the calling process (see
++/// [chdir(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/chdir.html)).
++///
++/// This function may fail in a number of different scenarios. See the man
++/// pages for additional details on possible failure cases.
++#[inline]
++pub fn chdir<P: ?Sized + NixPath>(path: &P) -> Result<()> {
++ let res = path.with_nix_path(|cstr| {
++ unsafe { libc::chdir(cstr.as_ptr()) }
++ })?;
++
++ Errno::result(res).map(drop)
++}
++
++/// Change the current working directory of the process to the one
++/// given as an open file descriptor (see
++/// [fchdir(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fchdir.html)).
++///
++/// This function may fail in a number of different scenarios. See the man
++/// pages for additional details on possible failure cases.
++#[inline]
++pub fn fchdir(dirfd: RawFd) -> Result<()> {
++ let res = unsafe { libc::fchdir(dirfd) };
++
++ Errno::result(res).map(drop)
++}
++
++/// Creates new directory `path` with access rights `mode`. (see [mkdir(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mkdir.html))
++///
++/// # Errors
++///
++/// There are several situations where mkdir might fail:
++///
++/// - current user has insufficient rights in the parent directory
++/// - the path already exists
++/// - the path name is too long (longer than `PATH_MAX`, usually 4096 on linux, 1024 on OS X)
++///
++/// # Example
++///
++/// ```rust
++/// extern crate tempfile;
++/// extern crate nix;
++///
++/// use nix::unistd;
++/// use nix::sys::stat;
++/// use tempfile::tempdir;
++///
++/// fn main() {
++/// let tmp_dir1 = tempdir().unwrap();
++/// let tmp_dir2 = tmp_dir1.path().join("new_dir");
++///
++/// // create new directory and give read, write and execute rights to the owner
++/// match unistd::mkdir(&tmp_dir2, stat::Mode::S_IRWXU) {
++/// Ok(_) => println!("created {:?}", tmp_dir2),
++/// Err(err) => println!("Error creating directory: {}", err),
++/// }
++/// }
++/// ```
++#[inline]
++pub fn mkdir<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> {
++ let res = path.with_nix_path(|cstr| {
++ unsafe { libc::mkdir(cstr.as_ptr(), mode.bits() as mode_t) }
++ })?;
++
++ Errno::result(res).map(drop)
++}
++
++/// Creates new fifo special file (named pipe) with path `path` and access rights `mode`.
++///
++/// # Errors
++///
++/// There are several situations where mkfifo might fail:
++///
++/// - current user has insufficient rights in the parent directory
++/// - the path already exists
++/// - the path name is too long (longer than `PATH_MAX`, usually 4096 on linux, 1024 on OS X)
++///
++/// For a full list consult
++/// [posix specification](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mkfifo.html)
++///
++/// # Example
++///
++/// ```rust
++/// extern crate tempfile;
++/// extern crate nix;
++///
++/// use nix::unistd;
++/// use nix::sys::stat;
++/// use tempfile::tempdir;
++///
++/// fn main() {
++/// let tmp_dir = tempdir().unwrap();
++/// let fifo_path = tmp_dir.path().join("foo.pipe");
++///
++/// // create new fifo and give read, write and execute rights to the owner
++/// match unistd::mkfifo(&fifo_path, stat::Mode::S_IRWXU) {
++/// Ok(_) => println!("created {:?}", fifo_path),
++/// Err(err) => println!("Error creating fifo: {}", err),
++/// }
++/// }
++/// ```
++#[inline]
++pub fn mkfifo<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> {
++ let res = path.with_nix_path(|cstr| {
++ unsafe { libc::mkfifo(cstr.as_ptr(), mode.bits() as mode_t) }
++ })?;
++
++ Errno::result(res).map(drop)
++}
++
++/// Creates a symbolic link at `path2` which points to `path1`.
++///
++/// If `dirfd` has a value, then `path2` is relative to directory associated
++/// with the file descriptor.
++///
++/// If `dirfd` is `None`, then `path2` is relative to the current working
++/// directory. This is identical to `libc::symlink(path1, path2)`.
++///
++/// See also [symlinkat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/symlinkat.html).
++pub fn symlinkat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(
++ path1: &P1,
++ dirfd: Option<RawFd>,
++ path2: &P2) -> Result<()> {
++ let res =
++ path1.with_nix_path(|path1| {
++ path2.with_nix_path(|path2| {
++ unsafe {
++ libc::symlinkat(
++ path1.as_ptr(),
++ dirfd.unwrap_or(libc::AT_FDCWD),
++ path2.as_ptr()
++ )
++ }
++ })
++ })??;
++ Errno::result(res).map(drop)
++}
++
++/// Returns the current directory as a `PathBuf`
++///
++/// Err is returned if the current user doesn't have the permission to read or search a component
++/// of the current path.
++///
++/// # Example
++///
++/// ```rust
++/// extern crate nix;
++///
++/// use nix::unistd;
++///
++/// fn main() {
++/// // assume that we are allowed to get current directory
++/// let dir = unistd::getcwd().unwrap();
++/// println!("The current directory is {:?}", dir);
++/// }
++/// ```
++#[inline]
++pub fn getcwd() -> Result<PathBuf> {
++ let mut buf = Vec::with_capacity(512);
++ loop {
++ unsafe {
++ let ptr = buf.as_mut_ptr() as *mut c_char;
++
++ // The buffer must be large enough to store the absolute pathname plus
++ // a terminating null byte, or else null is returned.
++ // To safely handle this we start with a reasonable size (512 bytes)
++ // and double the buffer size upon every error
++ if !libc::getcwd(ptr, buf.capacity()).is_null() {
++ let len = CStr::from_ptr(buf.as_ptr() as *const c_char).to_bytes().len();
++ buf.set_len(len);
++ buf.shrink_to_fit();
++ return Ok(PathBuf::from(OsString::from_vec(buf)));
++ } else {
++ let error = Errno::last();
++ // ERANGE means buffer was too small to store directory name
++ if error != Errno::ERANGE {
++ return Err(Error::Sys(error));
++ }
++ }
++
++ // Trigger the internal buffer resizing logic of `Vec` by requiring
++ // more space than the current capacity.
++ let cap = buf.capacity();
++ buf.set_len(cap);
++ buf.reserve(1);
++ }
++ }
++}
++
++/// Computes the raw UID and GID values to pass to a `*chown` call.
++fn chown_raw_ids(owner: Option<Uid>, group: Option<Gid>) -> (libc::uid_t, libc::gid_t) {
++ // According to the POSIX specification, -1 is used to indicate that owner and group
++ // are not to be changed. Since uid_t and gid_t are unsigned types, we have to wrap
++ // around to get -1.
++ let uid = owner.map(Into::into).unwrap_or((0 as uid_t).wrapping_sub(1));
++ let gid = group.map(Into::into).unwrap_or((0 as gid_t).wrapping_sub(1));
++ (uid, gid)
++}
++
++/// Change the ownership of the file at `path` to be owned by the specified
++/// `owner` (user) and `group` (see
++/// [chown(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/chown.html)).
++///
++/// The owner/group for the provided path name will not be modified if `None` is
++/// provided for that argument. Ownership change will be attempted for the path
++/// only if `Some` owner/group is provided.
++#[inline]
++pub fn chown<P: ?Sized + NixPath>(path: &P, owner: Option<Uid>, group: Option<Gid>) -> Result<()> {
++ let res = path.with_nix_path(|cstr| {
++ let (uid, gid) = chown_raw_ids(owner, group);
++ unsafe { libc::chown(cstr.as_ptr(), uid, gid) }
++ })?;
++
++ Errno::result(res).map(drop)
++}
++
++/// Flags for `fchownat` function.
++#[derive(Clone, Copy, Debug)]
++pub enum FchownatFlags {
++ FollowSymlink,
++ NoFollowSymlink,
++}
++
++/// Change the ownership of the file at `path` to be owned by the specified
++/// `owner` (user) and `group`.
++///
++/// The owner/group for the provided path name will not be modified if `None` is
++/// provided for that argument. Ownership change will be attempted for the path
++/// only if `Some` owner/group is provided.
++///
++/// The file to be changed is determined relative to the directory associated
++/// with the file descriptor `dirfd` or the current working directory
++/// if `dirfd` is `None`.
++///
++/// If `flag` is `FchownatFlags::NoFollowSymlink` and `path` names a symbolic link,
++/// then the mode of the symbolic link is changed.
++///
++/// `fchownat(None, path, mode, FchownatFlags::NoFollowSymlink)` is identical to
++/// a call `libc::lchown(path, mode)`. That's why `lchmod` is unimplemented in
++/// the `nix` crate.
++///
++/// # References
++///
++/// [fchownat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fchownat.html).
++pub fn fchownat<P: ?Sized + NixPath>(
++ dirfd: Option<RawFd>,
++ path: &P,
++ owner: Option<Uid>,
++ group: Option<Gid>,
++ flag: FchownatFlags,
++) -> Result<()> {
++ let atflag =
++ match flag {
++ FchownatFlags::FollowSymlink => AtFlags::empty(),
++ FchownatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW,
++ };
++ let res = path.with_nix_path(|cstr| unsafe {
++ let (uid, gid) = chown_raw_ids(owner, group);
++ libc::fchownat(at_rawfd(dirfd), cstr.as_ptr(), uid, gid,
++ atflag.bits() as libc::c_int)
++ })?;
++
++ Errno::result(res).map(drop)
++}
++
++fn to_exec_array(args: &[CString]) -> Vec<*const c_char> {
++ let mut args_p: Vec<*const c_char> = args.iter().map(|s| s.as_ptr()).collect();
++ args_p.push(ptr::null());
++ args_p
++}
++
++/// Replace the current process image with a new one (see
++/// [exec(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html)).
++///
++/// See the `::nix::unistd::execve` system call for additional details. `execv`
++/// performs the same action but does not allow for customization of the
++/// environment for the new process.
++#[inline]
++pub fn execv(path: &CString, argv: &[CString]) -> Result<Void> {
++ let args_p = to_exec_array(argv);
++
++ unsafe {
++ libc::execv(path.as_ptr(), args_p.as_ptr())
++ };
++
++ Err(Error::Sys(Errno::last()))
++}
++
++
++/// Replace the current process image with a new one (see
++/// [execve(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html)).
++///
++/// The execve system call allows for another process to be "called" which will
++/// replace the current process image. That is, this process becomes the new
++/// command that is run. On success, this function will not return. Instead,
++/// the new program will run until it exits.
++///
++/// `::nix::unistd::execv` and `::nix::unistd::execve` take as arguments a slice
++/// of `::std::ffi::CString`s for `args` and `env` (for `execve`). Each element
++/// in the `args` list is an argument to the new process. Each element in the
++/// `env` list should be a string in the form "key=value".
++#[inline]
++pub fn execve(path: &CString, args: &[CString], env: &[CString]) -> Result<Void> {
++ let args_p = to_exec_array(args);
++ let env_p = to_exec_array(env);
++
++ unsafe {
++ libc::execve(path.as_ptr(), args_p.as_ptr(), env_p.as_ptr())
++ };
++
++ Err(Error::Sys(Errno::last()))
++}
++
++/// Replace the current process image with a new one and replicate shell `PATH`
++/// searching behavior (see
++/// [exec(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html)).
++///
++/// See `::nix::unistd::execve` for additional details. `execvp` behaves the
++/// same as execv except that it will examine the `PATH` environment variables
++/// for file names not specified with a leading slash. For example, `execv`
++/// would not work if "bash" was specified for the path argument, but `execvp`
++/// would assuming that a bash executable was on the system `PATH`.
++#[inline]
++pub fn execvp(filename: &CString, args: &[CString]) -> Result<Void> {
++ let args_p = to_exec_array(args);
++
++ unsafe {
++ libc::execvp(filename.as_ptr(), args_p.as_ptr())
++ };
++
++ Err(Error::Sys(Errno::last()))
++}
++
++/// Replace the current process image with a new one and replicate shell `PATH`
++/// searching behavior (see
++/// [`execvpe(3)`](http://man7.org/linux/man-pages/man3/exec.3.html)).
++///
++/// This functions like a combination of `execvp(2)` and `execve(2)` to pass an
++/// environment and have a search path. See these two for additional
++/// information.
++#[cfg(any(target_os = "haiku",
++ target_os = "linux",
++ target_os = "openbsd"))]
++pub fn execvpe(filename: &CString, args: &[CString], env: &[CString]) -> Result<Void> {
++ let args_p = to_exec_array(args);
++ let env_p = to_exec_array(env);
++
++ unsafe {
++ libc::execvpe(filename.as_ptr(), args_p.as_ptr(), env_p.as_ptr())
++ };
++
++ Err(Error::Sys(Errno::last()))
++}
++
++/// Replace the current process image with a new one (see
++/// [fexecve(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fexecve.html)).
++///
++/// The `fexecve` function allows for another process to be "called" which will
++/// replace the current process image. That is, this process becomes the new
++/// command that is run. On success, this function will not return. Instead,
++/// the new program will run until it exits.
++///
++/// This function is similar to `execve`, except that the program to be executed
++/// is referenced as a file descriptor instead of a path.
++// Note for NetBSD and OpenBSD: although rust-lang/libc includes it (under
++// unix/bsd/netbsdlike/) fexecve is not currently implemented on NetBSD nor on
++// OpenBSD.
++#[cfg(any(target_os = "android",
++ target_os = "linux",
++ target_os = "freebsd"))]
++#[inline]
++pub fn fexecve(fd: RawFd, args: &[CString], env: &[CString]) -> Result<Void> {
++ let args_p = to_exec_array(args);
++ let env_p = to_exec_array(env);
++
++ unsafe {
++ libc::fexecve(fd, args_p.as_ptr(), env_p.as_ptr())
++ };
++
++ Err(Error::Sys(Errno::last()))
++}
++
++/// Execute program relative to a directory file descriptor (see
++/// [execveat(2)](http://man7.org/linux/man-pages/man2/execveat.2.html)).
++///
++/// The `execveat` function allows for another process to be "called" which will
++/// replace the current process image. That is, this process becomes the new
++/// command that is run. On success, this function will not return. Instead,
++/// the new program will run until it exits.
++///
++/// This function is similar to `execve`, except that the program to be executed
++/// is referenced as a file descriptor to the base directory plus a path.
++#[cfg(any(target_os = "android", target_os = "linux"))]
++#[inline]
++pub fn execveat(dirfd: RawFd, pathname: &CString, args: &[CString],
++ env: &[CString], flags: super::fcntl::AtFlags) -> Result<Void> {
++ let args_p = to_exec_array(args);
++ let env_p = to_exec_array(env);
++
++ unsafe {
++ libc::syscall(libc::SYS_execveat, dirfd, pathname.as_ptr(),
++ args_p.as_ptr(), env_p.as_ptr(), flags);
++ };
++
++ Err(Error::Sys(Errno::last()))
++}
++
++/// Daemonize this process by detaching from the controlling terminal (see
++/// [daemon(3)](http://man7.org/linux/man-pages/man3/daemon.3.html)).
++///
++/// When a process is launched it is typically associated with a parent and it,
++/// in turn, by its controlling terminal/process. In order for a process to run
++/// in the "background" it must daemonize itself by detaching itself. Under
++/// posix, this is done by doing the following:
++///
++/// 1. Parent process (this one) forks
++/// 2. Parent process exits
++/// 3. Child process continues to run.
++///
++/// `nochdir`:
++///
++/// * `nochdir = true`: The current working directory after daemonizing will
++/// be the current working directory.
++/// * `nochdir = false`: The current working directory after daemonizing will
++/// be the root direcory, `/`.
++///
++/// `noclose`:
++///
++/// * `noclose = true`: The process' current stdin, stdout, and stderr file
++/// descriptors will remain identical after daemonizing.
++/// * `noclose = false`: The process' stdin, stdout, and stderr will point to
++/// `/dev/null` after daemonizing.
++#[cfg_attr(any(target_os = "macos", target_os = "ios"), deprecated(
++ since="0.14.0",
++ note="Deprecated in MacOSX 10.5"
++))]
++#[cfg_attr(any(target_os = "macos", target_os = "ios"), allow(deprecated))]
++pub fn daemon(nochdir: bool, noclose: bool) -> Result<()> {
++ let res = unsafe { libc::daemon(nochdir as c_int, noclose as c_int) };
++ Errno::result(res).map(drop)
++}
++
++/// Set the system host name (see
++/// [sethostname(2)](http://man7.org/linux/man-pages/man2/gethostname.2.html)).
++///
++/// Given a name, attempt to update the system host name to the given string.
++/// On some systems, the host name is limited to as few as 64 bytes. An error
++/// will be return if the name is not valid or the current process does not have
++/// permissions to update the host name.
++pub fn sethostname<S: AsRef<OsStr>>(name: S) -> Result<()> {
++ // Handle some differences in type of the len arg across platforms.
++ cfg_if! {
++ if #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos", ))] {
++ type sethostname_len_t = c_int;
++ } else {
++ type sethostname_len_t = size_t;
++ }
++ }
++ let ptr = name.as_ref().as_bytes().as_ptr() as *const c_char;
++ let len = name.as_ref().len() as sethostname_len_t;
++
++ let res = unsafe { libc::sethostname(ptr, len) };
++ Errno::result(res).map(drop)
++}
++
++/// Get the host name and store it in the provided buffer, returning a pointer
++/// the `CStr` in that buffer on success (see
++/// [gethostname(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/gethostname.html)).
++///
++/// This function call attempts to get the host name for the running system and
++/// store it in a provided buffer. The buffer will be populated with bytes up
++/// to the length of the provided slice including a NUL terminating byte. If
++/// the hostname is longer than the length provided, no error will be provided.
++/// The posix specification does not specify whether implementations will
++/// null-terminate in this case, but the nix implementation will ensure that the
++/// buffer is null terminated in this case.
++///
++/// ```no_run
++/// use nix::unistd;
++///
++/// let mut buf = [0u8; 64];
++/// let hostname_cstr = unistd::gethostname(&mut buf).expect("Failed getting hostname");
++/// let hostname = hostname_cstr.to_str().expect("Hostname wasn't valid UTF-8");
++/// println!("Hostname: {}", hostname);
++/// ```
++pub fn gethostname(buffer: &mut [u8]) -> Result<&CStr> {
++ let ptr = buffer.as_mut_ptr() as *mut c_char;
++ let len = buffer.len() as size_t;
++
++ let res = unsafe { libc::gethostname(ptr, len) };
++ Errno::result(res).map(|_| {
++ buffer[len - 1] = 0; // ensure always null-terminated
++ unsafe { CStr::from_ptr(buffer.as_ptr() as *const c_char) }
++ })
++}
++
++/// Close a raw file descriptor
++///
++/// Be aware that many Rust types implicitly close-on-drop, including
++/// `std::fs::File`. Explicitly closing them with this method too can result in
++/// a double-close condition, which can cause confusing `EBADF` errors in
++/// seemingly unrelated code. Caveat programmer. See also
++/// [close(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html).
++///
++/// # Examples
++///
++/// ```no_run
++/// extern crate tempfile;
++/// extern crate nix;
++///
++/// use std::os::unix::io::AsRawFd;
++/// use nix::unistd::close;
++///
++/// fn main() {
++/// let f = tempfile::tempfile().unwrap();
++/// close(f.as_raw_fd()).unwrap(); // Bad! f will also close on drop!
++/// }
++/// ```
++///
++/// ```rust
++/// extern crate tempfile;
++/// extern crate nix;
++///
++/// use std::os::unix::io::IntoRawFd;
++/// use nix::unistd::close;
++///
++/// fn main() {
++/// let f = tempfile::tempfile().unwrap();
++/// close(f.into_raw_fd()).unwrap(); // Good. into_raw_fd consumes f
++/// }
++/// ```
++pub fn close(fd: RawFd) -> Result<()> {
++ let res = unsafe { libc::close(fd) };
++ Errno::result(res).map(drop)
++}
++
++/// Read from a raw file descriptor.
++///
++/// See also [read(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html)
++pub fn read(fd: RawFd, buf: &mut [u8]) -> Result<usize> {
++ let res = unsafe { libc::read(fd, buf.as_mut_ptr() as *mut c_void, buf.len() as size_t) };
++
++ Errno::result(res).map(|r| r as usize)
++}
++
++/// Write to a raw file descriptor.
++///
++/// See also [write(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html)
++pub fn write(fd: RawFd, buf: &[u8]) -> Result<usize> {
++ let res = unsafe { libc::write(fd, buf.as_ptr() as *const c_void, buf.len() as size_t) };
++
++ Errno::result(res).map(|r| r as usize)
++}
++
++/// Directive that tells [`lseek`] and [`lseek64`] what the offset is relative to.
++///
++/// [`lseek`]: ./fn.lseek.html
++/// [`lseek64`]: ./fn.lseek64.html
++#[repr(i32)]
++#[derive(Clone, Copy, Debug)]
++pub enum Whence {
++ /// Specify an offset relative to the start of the file.
++ SeekSet = libc::SEEK_SET,
++ /// Specify an offset relative to the current file location.
++ SeekCur = libc::SEEK_CUR,
++ /// Specify an offset relative to the end of the file.
++ SeekEnd = libc::SEEK_END,
++ /// Specify an offset relative to the next location in the file greater than or
++ /// equal to offset that contains some data. If offset points to
++ /// some data, then the file offset is set to offset.
++ #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
++ all(target_os = "linux", not(any(target_env = "musl",
++ target_arch = "mips",
++ target_arch = "mips64")))))]
++ SeekData = libc::SEEK_DATA,
++ /// Specify an offset relative to the next hole in the file greater than
++ /// or equal to offset. If offset points into the middle of a hole, then
++ /// the file offset should be set to offset. If there is no hole past offset,
++ /// then the file offset should be adjusted to the end of the file (i.e., there
++ /// is an implicit hole at the end of any file).
++ #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
++ all(target_os = "linux", not(any(target_env = "musl",
++ target_arch = "mips",
++ target_arch = "mips64")))))]
++ SeekHole = libc::SEEK_HOLE
++}
++
++/// Move the read/write file offset.
++///
++/// See also [lseek(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/lseek.html)
++pub fn lseek(fd: RawFd, offset: off_t, whence: Whence) -> Result<off_t> {
++ let res = unsafe { libc::lseek(fd, offset, whence as i32) };
++
++ Errno::result(res).map(|r| r as off_t)
++}
++
++#[cfg(any(target_os = "linux", target_os = "android"))]
++pub fn lseek64(fd: RawFd, offset: libc::off64_t, whence: Whence) -> Result<libc::off64_t> {
++ let res = unsafe { libc::lseek64(fd, offset, whence as i32) };
++
++ Errno::result(res).map(|r| r as libc::off64_t)
++}
++
++/// Create an interprocess channel.
++///
++/// See also [pipe(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pipe.html)
++pub fn pipe() -> Result<(RawFd, RawFd)> {
++ unsafe {
++ let mut fds: [c_int; 2] = mem::uninitialized();
++
++ let res = libc::pipe(fds.as_mut_ptr());
++
++ Errno::result(res)?;
++
++ Ok((fds[0], fds[1]))
++ }
++}
++
++/// Like `pipe`, but allows setting certain file descriptor flags.
++///
++/// The following flags are supported, and will be set atomically as the pipe is
++/// created:
++///
++/// `O_CLOEXEC`: Set the close-on-exec flag for the new file descriptors.
++/// `O_NONBLOCK`: Set the non-blocking flag for the ends of the pipe.
++///
++/// See also [pipe(2)](http://man7.org/linux/man-pages/man2/pipe.2.html)
++#[cfg(any(target_os = "android",
++ target_os = "dragonfly",
++ target_os = "emscripten",
++ target_os = "freebsd",
++ target_os = "linux",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> {
++ let mut fds: [c_int; 2] = unsafe { mem::uninitialized() };
++
++ let res = unsafe { libc::pipe2(fds.as_mut_ptr(), flags.bits()) };
++
++ Errno::result(res)?;
++
++ Ok((fds[0], fds[1]))
++}
++
++/// Like `pipe`, but allows setting certain file descriptor flags.
++///
++/// The following flags are supported, and will be set after the pipe is
++/// created:
++///
++/// `O_CLOEXEC`: Set the close-on-exec flag for the new file descriptors.
++/// `O_NONBLOCK`: Set the non-blocking flag for the ends of the pipe.
++#[cfg(any(target_os = "ios", target_os = "macos"))]
++#[deprecated(
++ since="0.10.0",
++ note="pipe2(2) is not actually atomic on these platforms. Use pipe(2) and fcntl(2) instead"
++)]
++pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> {
++ let mut fds: [c_int; 2] = unsafe { mem::uninitialized() };
++
++ let res = unsafe { libc::pipe(fds.as_mut_ptr()) };
++
++ Errno::result(res)?;
++
++ pipe2_setflags(fds[0], fds[1], flags)?;
++
++ Ok((fds[0], fds[1]))
++}
++
++#[cfg(any(target_os = "ios", target_os = "macos"))]
++fn pipe2_setflags(fd1: RawFd, fd2: RawFd, flags: OFlag) -> Result<()> {
++ use fcntl::FcntlArg::F_SETFL;
++
++ let mut res = Ok(0);
++
++ if flags.contains(OFlag::O_CLOEXEC) {
++ res = res
++ .and_then(|_| fcntl(fd1, F_SETFD(FdFlag::FD_CLOEXEC)))
++ .and_then(|_| fcntl(fd2, F_SETFD(FdFlag::FD_CLOEXEC)));
++ }
++
++ if flags.contains(OFlag::O_NONBLOCK) {
++ res = res
++ .and_then(|_| fcntl(fd1, F_SETFL(OFlag::O_NONBLOCK)))
++ .and_then(|_| fcntl(fd2, F_SETFL(OFlag::O_NONBLOCK)));
++ }
++
++ match res {
++ Ok(_) => Ok(()),
++ Err(e) => {
++ let _ = close(fd1);
++ let _ = close(fd2);
++ Err(e)
++ }
++ }
++}
++
++/// Truncate a file to a specified length
++///
++/// See also
++/// [truncate(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/truncate.html)
++pub fn truncate<P: ?Sized + NixPath>(path: &P, len: off_t) -> Result<()> {
++ let res = path.with_nix_path(|cstr| {
++ unsafe {
++ libc::truncate(cstr.as_ptr(), len)
++ }
++ })?;
++
++ Errno::result(res).map(drop)
++}
++
++/// Truncate a file to a specified length
++///
++/// See also
++/// [ftruncate(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html)
++pub fn ftruncate(fd: RawFd, len: off_t) -> Result<()> {
++ Errno::result(unsafe { libc::ftruncate(fd, len) }).map(drop)
++}
++
++pub fn isatty(fd: RawFd) -> Result<bool> {
++ unsafe {
++ // ENOTTY means `fd` is a valid file descriptor, but not a TTY, so
++ // we return `Ok(false)`
++ if libc::isatty(fd) == 1 {
++ Ok(true)
++ } else {
++ match Errno::last() {
++ Errno::ENOTTY => Ok(false),
++ err => Err(Error::Sys(err)),
++ }
++ }
++ }
++}
++
++/// Remove a directory entry
++///
++/// See also [unlink(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/unlink.html)
++pub fn unlink<P: ?Sized + NixPath>(path: &P) -> Result<()> {
++ let res = path.with_nix_path(|cstr| {
++ unsafe {
++ libc::unlink(cstr.as_ptr())
++ }
++ })?;
++ Errno::result(res).map(drop)
++}
++
++/// Flags for `unlinkat` function.
++#[derive(Clone, Copy, Debug)]
++pub enum UnlinkatFlags {
++ RemoveDir,
++ NoRemoveDir,
++}
++
++/// Remove a directory entry
++///
++/// In the case of a relative path, the directory entry to be removed is determined relative to
++/// the directory associated with the file descriptor `dirfd` or the current working directory
++/// if `dirfd` is `None`. In the case of an absolute `path` `dirfd` is ignored. If `flag` is
++/// `UnlinkatFlags::RemoveDir` then removal of the directory entry specified by `dirfd` and `path`
++/// is performed.
++///
++/// # References
++/// See also [unlinkat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/unlinkat.html)
++pub fn unlinkat<P: ?Sized + NixPath>(
++ dirfd: Option<RawFd>,
++ path: &P,
++ flag: UnlinkatFlags,
++) -> Result<()> {
++ let atflag =
++ match flag {
++ UnlinkatFlags::RemoveDir => AtFlags::AT_REMOVEDIR,
++ UnlinkatFlags::NoRemoveDir => AtFlags::empty(),
++ };
++ let res = path.with_nix_path(|cstr| {
++ unsafe {
++ libc::unlinkat(at_rawfd(dirfd), cstr.as_ptr(), atflag.bits() as libc::c_int)
++ }
++ })?;
++ Errno::result(res).map(drop)
++}
++
++
++#[inline]
++pub fn chroot<P: ?Sized + NixPath>(path: &P) -> Result<()> {
++ let res = path.with_nix_path(|cstr| {
++ unsafe { libc::chroot(cstr.as_ptr()) }
++ })?;
++
++ Errno::result(res).map(drop)
++}
++
++/// Commit filesystem caches to disk
++///
++/// See also [sync(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sync.html)
++#[cfg(any(
++ target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "linux",
++ target_os = "netbsd",
++ target_os = "openbsd"
++))]
++pub fn sync() -> () {
++ unsafe { libc::sync() };
++}
++
++/// Synchronize changes to a file
++///
++/// See also [fsync(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html)
++#[inline]
++pub fn fsync(fd: RawFd) -> Result<()> {
++ let res = unsafe { libc::fsync(fd) };
++
++ Errno::result(res).map(drop)
++}
++
++/// Synchronize the data of a file
++///
++/// See also
++/// [fdatasync(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fdatasync.html)
++// `fdatasync(2) is in POSIX, but in libc it is only defined in `libc::notbsd`.
++// TODO: exclude only Apple systems after https://github.com/rust-lang/libc/pull/211
++#[cfg(any(target_os = "linux",
++ target_os = "android",
++ target_os = "emscripten"))]
++#[inline]
++pub fn fdatasync(fd: RawFd) -> Result<()> {
++ let res = unsafe { libc::fdatasync(fd) };
++
++ Errno::result(res).map(drop)
++}
++
++/// Get a real user ID
++///
++/// See also [getuid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getuid.html)
++// POSIX requires that getuid is always successful, so no need to check return
++// value or errno.
++#[inline]
++pub fn getuid() -> Uid {
++ Uid(unsafe { libc::getuid() })
++}
++
++/// Get the effective user ID
++///
++/// See also [geteuid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/geteuid.html)
++// POSIX requires that geteuid is always successful, so no need to check return
++// value or errno.
++#[inline]
++pub fn geteuid() -> Uid {
++ Uid(unsafe { libc::geteuid() })
++}
++
++/// Get the real group ID
++///
++/// See also [getgid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getgid.html)
++// POSIX requires that getgid is always successful, so no need to check return
++// value or errno.
++#[inline]
++pub fn getgid() -> Gid {
++ Gid(unsafe { libc::getgid() })
++}
++
++/// Get the effective group ID
++///
++/// See also [getegid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getegid.html)
++// POSIX requires that getegid is always successful, so no need to check return
++// value or errno.
++#[inline]
++pub fn getegid() -> Gid {
++ Gid(unsafe { libc::getegid() })
++}
++
++/// Set the effective user ID
++///
++/// See also [seteuid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/seteuid.html)
++#[inline]
++pub fn seteuid(euid: Uid) -> Result<()> {
++ let res = unsafe { libc::seteuid(euid.into()) };
++
++ Errno::result(res).map(drop)
++}
++
++/// Set the effective group ID
++///
++/// See also [setegid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setegid.html)
++#[inline]
++pub fn setegid(egid: Gid) -> Result<()> {
++ let res = unsafe { libc::setegid(egid.into()) };
++
++ Errno::result(res).map(drop)
++}
++
++/// Set the user ID
++///
++/// See also [setuid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setuid.html)
++#[inline]
++pub fn setuid(uid: Uid) -> Result<()> {
++ let res = unsafe { libc::setuid(uid.into()) };
++
++ Errno::result(res).map(drop)
++}
++
++/// Set the group ID
++///
++/// See also [setgid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setgid.html)
++#[inline]
++pub fn setgid(gid: Gid) -> Result<()> {
++ let res = unsafe { libc::setgid(gid.into()) };
++
++ Errno::result(res).map(drop)
++}
++
++/// Get the list of supplementary group IDs of the calling process.
++///
++/// [Further reading](http://pubs.opengroup.org/onlinepubs/009695399/functions/getgroups.html)
++///
++/// **Note:** This function is not available for Apple platforms. On those
++/// platforms, checking group membership should be achieved via communication
++/// with the `opendirectoryd` service.
++#[cfg(not(any(target_os = "ios", target_os = "macos")))]
++pub fn getgroups() -> Result<Vec<Gid>> {
++ // First get the number of groups so we can size our Vec
++ let ret = unsafe { libc::getgroups(0, ptr::null_mut()) };
++
++ // Now actually get the groups. We try multiple times in case the number of
++ // groups has changed since the first call to getgroups() and the buffer is
++ // now too small.
++ let mut groups = Vec::<Gid>::with_capacity(Errno::result(ret)? as usize);
++ loop {
++ // FIXME: On the platforms we currently support, the `Gid` struct has
++ // the same representation in memory as a bare `gid_t`. This is not
++ // necessarily the case on all Rust platforms, though. See RFC 1785.
++ let ret = unsafe {
++ libc::getgroups(groups.capacity() as c_int, groups.as_mut_ptr() as *mut gid_t)
++ };
++
++ match Errno::result(ret) {
++ Ok(s) => {
++ unsafe { groups.set_len(s as usize) };
++ return Ok(groups);
++ },
++ Err(Error::Sys(Errno::EINVAL)) => {
++ // EINVAL indicates that the buffer size was too small. Trigger
++ // the internal buffer resizing logic of `Vec` by requiring
++ // more space than the current capacity.
++ let cap = groups.capacity();
++ unsafe { groups.set_len(cap) };
++ groups.reserve(1);
++ },
++ Err(e) => return Err(e)
++ }
++ }
++}
++
++/// Set the list of supplementary group IDs for the calling process.
++///
++/// [Further reading](http://man7.org/linux/man-pages/man2/getgroups.2.html)
++///
++/// **Note:** This function is not available for Apple platforms. On those
++/// platforms, group membership management should be achieved via communication
++/// with the `opendirectoryd` service.
++///
++/// # Examples
++///
++/// `setgroups` can be used when dropping privileges from the root user to a
++/// specific user and group. For example, given the user `www-data` with UID
++/// `33` and the group `backup` with the GID `34`, one could switch the user as
++/// follows:
++///
++/// ```rust,no_run
++/// # use std::error::Error;
++/// # use nix::unistd::*;
++/// #
++/// # fn try_main() -> Result<(), Box<Error>> {
++/// let uid = Uid::from_raw(33);
++/// let gid = Gid::from_raw(34);
++/// setgroups(&[gid])?;
++/// setgid(gid)?;
++/// setuid(uid)?;
++/// #
++/// # Ok(())
++/// # }
++/// #
++/// # fn main() {
++/// # try_main().unwrap();
++/// # }
++/// ```
++#[cfg(not(any(target_os = "ios", target_os = "macos")))]
++pub fn setgroups(groups: &[Gid]) -> Result<()> {
++ cfg_if! {
++ if #[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))] {
++ type setgroups_ngroups_t = c_int;
++ } else {
++ type setgroups_ngroups_t = size_t;
++ }
++ }
++ // FIXME: On the platforms we currently support, the `Gid` struct has the
++ // same representation in memory as a bare `gid_t`. This is not necessarily
++ // the case on all Rust platforms, though. See RFC 1785.
++ let res = unsafe {
++ libc::setgroups(groups.len() as setgroups_ngroups_t, groups.as_ptr() as *const gid_t)
++ };
++
++ Errno::result(res).map(drop)
++}
++
++/// Calculate the supplementary group access list.
++///
++/// Gets the group IDs of all groups that `user` is a member of. The additional
++/// group `group` is also added to the list.
++///
++/// [Further reading](http://man7.org/linux/man-pages/man3/getgrouplist.3.html)
++///
++/// **Note:** This function is not available for Apple platforms. On those
++/// platforms, checking group membership should be achieved via communication
++/// with the `opendirectoryd` service.
++///
++/// # Errors
++///
++/// Although the `getgrouplist()` call does not return any specific
++/// errors on any known platforms, this implementation will return a system
++/// error of `EINVAL` if the number of groups to be fetched exceeds the
++/// `NGROUPS_MAX` sysconf value. This mimics the behaviour of `getgroups()`
++/// and `setgroups()`. Additionally, while some implementations will return a
++/// partial list of groups when `NGROUPS_MAX` is exceeded, this implementation
++/// will only ever return the complete list or else an error.
++#[cfg(not(any(target_os = "ios", target_os = "macos")))]
++pub fn getgrouplist(user: &CStr, group: Gid) -> Result<Vec<Gid>> {
++ let ngroups_max = match sysconf(SysconfVar::NGROUPS_MAX) {
++ Ok(Some(n)) => n as c_int,
++ Ok(None) | Err(_) => <c_int>::max_value(),
++ };
++ use std::cmp::min;
++ let mut ngroups = min(ngroups_max, 8);
++ let mut groups = Vec::<Gid>::with_capacity(ngroups as usize);
++ cfg_if! {
++ if #[cfg(any(target_os = "ios", target_os = "macos"))] {
++ type getgrouplist_group_t = c_int;
++ } else {
++ type getgrouplist_group_t = gid_t;
++ }
++ }
++ let gid: gid_t = group.into();
++ loop {
++ let ret = unsafe {
++ libc::getgrouplist(user.as_ptr(),
++ gid as getgrouplist_group_t,
++ groups.as_mut_ptr() as *mut getgrouplist_group_t,
++ &mut ngroups)
++ };
++
++ // BSD systems only return 0 or -1, Linux returns ngroups on success.
++ if ret >= 0 {
++ unsafe { groups.set_len(ngroups as usize) };
++ return Ok(groups);
++ } else if ret == -1 {
++ // Returns -1 if ngroups is too small, but does not set errno.
++ // BSD systems will still fill the groups buffer with as many
++ // groups as possible, but Linux manpages do not mention this
++ // behavior.
++
++ let cap = groups.capacity();
++ if cap >= ngroups_max as usize {
++ // We already have the largest capacity we can, give up
++ return Err(Error::invalid_argument());
++ }
++
++ // Reserve space for at least ngroups
++ groups.reserve(ngroups as usize);
++
++ // Even if the buffer gets resized to bigger than ngroups_max,
++ // don't ever ask for more than ngroups_max groups
++ ngroups = min(ngroups_max, groups.capacity() as c_int);
++ }
++ }
++}
++
++/// Initialize the supplementary group access list.
++///
++/// Sets the supplementary group IDs for the calling process using all groups
++/// that `user` is a member of. The additional group `group` is also added to
++/// the list.
++///
++/// [Further reading](http://man7.org/linux/man-pages/man3/initgroups.3.html)
++///
++/// **Note:** This function is not available for Apple platforms. On those
++/// platforms, group membership management should be achieved via communication
++/// with the `opendirectoryd` service.
++///
++/// # Examples
++///
++/// `initgroups` can be used when dropping privileges from the root user to
++/// another user. For example, given the user `www-data`, we could look up the
++/// UID and GID for the user in the system's password database (usually found
++/// in `/etc/passwd`). If the `www-data` user's UID and GID were `33` and `33`,
++/// respectively, one could switch the user as follows:
++///
++/// ```rust,no_run
++/// # use std::error::Error;
++/// # use std::ffi::CString;
++/// # use nix::unistd::*;
++/// #
++/// # fn try_main() -> Result<(), Box<Error>> {
++/// let user = CString::new("www-data").unwrap();
++/// let uid = Uid::from_raw(33);
++/// let gid = Gid::from_raw(33);
++/// initgroups(&user, gid)?;
++/// setgid(gid)?;
++/// setuid(uid)?;
++/// #
++/// # Ok(())
++/// # }
++/// #
++/// # fn main() {
++/// # try_main().unwrap();
++/// # }
++/// ```
++#[cfg(not(any(target_os = "ios", target_os = "macos")))]
++pub fn initgroups(user: &CStr, group: Gid) -> Result<()> {
++ cfg_if! {
++ if #[cfg(any(target_os = "ios", target_os = "macos"))] {
++ type initgroups_group_t = c_int;
++ } else {
++ type initgroups_group_t = gid_t;
++ }
++ }
++ let gid: gid_t = group.into();
++ let res = unsafe { libc::initgroups(user.as_ptr(), gid as initgroups_group_t) };
++
++ Errno::result(res).map(drop)
++}
++
++/// Suspend the thread until a signal is received.
++///
++/// See also [pause(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pause.html).
++#[inline]
++pub fn pause() {
++ unsafe { libc::pause() };
++}
++
++pub mod alarm {
++ //! Alarm signal scheduling.
++ //!
++ //! Scheduling an alarm will trigger a `SIGALRM` signal when the time has
++ //! elapsed, which has to be caught, because the default action for the
++ //! signal is to terminate the program. This signal also can't be ignored
++ //! because the system calls like `pause` will not be interrupted, see the
++ //! second example below.
++ //!
++ //! # Examples
++ //!
++ //! Canceling an alarm:
++ //!
++ //! ```
++ //! use nix::unistd::alarm;
++ //!
++ //! // Set an alarm for 60 seconds from now.
++ //! alarm::set(60);
++ //!
++ //! // Cancel the above set alarm, which returns the number of seconds left
++ //! // of the previously set alarm.
++ //! assert_eq!(alarm::cancel(), Some(60));
++ //! ```
++ //!
++ //! Scheduling an alarm and waiting for the signal:
++ //!
++ //! ```
++ //! use std::time::{Duration, Instant};
++ //!
++ //! use nix::unistd::{alarm, pause};
++ //! use nix::sys::signal::*;
++ //!
++ //! // We need to setup an empty signal handler to catch the alarm signal,
++ //! // otherwise the program will be terminated once the signal is delivered.
++ //! extern fn signal_handler(_: nix::libc::c_int) { }
++ //! unsafe { sigaction(Signal::SIGALRM, &SigAction::new(SigHandler::Handler(signal_handler), SaFlags::empty(), SigSet::empty())); }
++ //!
++ //! // Set an alarm for 1 second from now.
++ //! alarm::set(1);
++ //!
++ //! let start = Instant::now();
++ //! // Pause the process until the alarm signal is received.
++ //! pause();
++ //!
++ //! assert!(start.elapsed() >= Duration::from_secs(1));
++ //! ```
++ //!
++ //! # References
++ //!
++ //! See also [alarm(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/alarm.html).
++
++ use libc;
++
++ /// Schedule an alarm signal.
++ ///
++ /// This will cause the system to generate a `SIGALRM` signal for the
++ /// process after the specified number of seconds have elapsed.
++ ///
++ /// Returns the leftover time of a previously set alarm if there was one.
++ pub fn set(secs: libc::c_uint) -> Option<libc::c_uint> {
++ assert!(secs != 0, "passing 0 to `alarm::set` is not allowed, to cancel an alarm use `alarm::cancel`");
++ alarm(secs)
++ }
++
++ /// Cancel an previously set alarm signal.
++ ///
++ /// Returns the leftover time of a previously set alarm if there was one.
++ pub fn cancel() -> Option<libc::c_uint> {
++ alarm(0)
++ }
++
++ fn alarm(secs: libc::c_uint) -> Option<libc::c_uint> {
++ match unsafe { libc::alarm(secs) } {
++ 0 => None,
++ secs => Some(secs),
++ }
++ }
++}
++
++/// Suspend execution for an interval of time
++///
++/// See also [sleep(2)](http://pubs.opengroup.org/onlinepubs/009695399/functions/sleep.html#tag_03_705_05)
++// Per POSIX, does not fail
++#[inline]
++pub fn sleep(seconds: c_uint) -> c_uint {
++ unsafe { libc::sleep(seconds) }
++}
++
++pub mod acct {
++ use libc;
++ use {Result, NixPath};
++ use errno::Errno;
++ use std::ptr;
++
++ /// Enable process accounting
++ ///
++ /// See also [acct(2)](https://linux.die.net/man/2/acct)
++ pub fn enable<P: ?Sized + NixPath>(filename: &P) -> Result<()> {
++ let res = filename.with_nix_path(|cstr| {
++ unsafe { libc::acct(cstr.as_ptr()) }
++ })?;
++
++ Errno::result(res).map(drop)
++ }
++
++ /// Disable process accounting
++ pub fn disable() -> Result<()> {
++ let res = unsafe { libc::acct(ptr::null()) };
++
++ Errno::result(res).map(drop)
++ }
++}
++
++/// Creates a regular file which persists even after process termination
++///
++/// * `template`: a path whose 6 rightmost characters must be X, e.g. `/tmp/tmpfile_XXXXXX`
++/// * returns: tuple of file descriptor and filename
++///
++/// Err is returned either if no temporary filename could be created or the template doesn't
++/// end with XXXXXX
++///
++/// See also [mkstemp(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mkstemp.html)
++///
++/// # Example
++///
++/// ```rust
++/// use nix::unistd;
++///
++/// let _ = match unistd::mkstemp("/tmp/tempfile_XXXXXX") {
++/// Ok((fd, path)) => {
++/// unistd::unlink(path.as_path()).unwrap(); // flag file to be deleted at app termination
++/// fd
++/// }
++/// Err(e) => panic!("mkstemp failed: {}", e)
++/// };
++/// // do something with fd
++/// ```
++#[inline]
++pub fn mkstemp<P: ?Sized + NixPath>(template: &P) -> Result<(RawFd, PathBuf)> {
++ let mut path = template.with_nix_path(|path| {path.to_bytes_with_nul().to_owned()})?;
++ let p = path.as_mut_ptr() as *mut _;
++ let fd = unsafe { libc::mkstemp(p) };
++ let last = path.pop(); // drop the trailing nul
++ debug_assert!(last == Some(b'\0'));
++ let pathname = OsString::from_vec(path);
++ Errno::result(fd)?;
++ Ok((fd, PathBuf::from(pathname)))
++}
++
++/// Variable names for `pathconf`
++///
++/// Nix uses the same naming convention for these variables as the
++/// [getconf(1)](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/getconf.html) utility.
++/// That is, `PathconfVar` variables have the same name as the abstract
++/// variables shown in the `pathconf(2)` man page. Usually, it's the same as
++/// the C variable name without the leading `_PC_`.
++///
++/// POSIX 1003.1-2008 standardizes all of these variables, but some OSes choose
++/// not to implement variables that cannot change at runtime.
++///
++/// # References
++///
++/// - [pathconf(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html)
++/// - [limits.h](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html)
++/// - [unistd.h](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/unistd.h.html)
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++#[repr(i32)]
++pub enum PathconfVar {
++ #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "linux",
++ target_os = "netbsd", target_os = "openbsd"))]
++ /// Minimum number of bits needed to represent, as a signed integer value,
++ /// the maximum size of a regular file allowed in the specified directory.
++ FILESIZEBITS = libc::_PC_FILESIZEBITS,
++ /// Maximum number of links to a single file.
++ LINK_MAX = libc::_PC_LINK_MAX,
++ /// Maximum number of bytes in a terminal canonical input line.
++ MAX_CANON = libc::_PC_MAX_CANON,
++ /// Minimum number of bytes for which space is available in a terminal input
++ /// queue; therefore, the maximum number of bytes a conforming application
++ /// may require to be typed as input before reading them.
++ MAX_INPUT = libc::_PC_MAX_INPUT,
++ /// Maximum number of bytes in a filename (not including the terminating
++ /// null of a filename string).
++ NAME_MAX = libc::_PC_NAME_MAX,
++ /// Maximum number of bytes the implementation will store as a pathname in a
++ /// user-supplied buffer of unspecified size, including the terminating null
++ /// character. Minimum number the implementation will accept as the maximum
++ /// number of bytes in a pathname.
++ PATH_MAX = libc::_PC_PATH_MAX,
++ /// Maximum number of bytes that is guaranteed to be atomic when writing to
++ /// a pipe.
++ PIPE_BUF = libc::_PC_PIPE_BUF,
++ #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "linux",
++ target_os = "netbsd", target_os = "openbsd"))]
++ /// Symbolic links can be created.
++ POSIX2_SYMLINKS = libc::_PC_2_SYMLINKS,
++ #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
++ target_os = "linux", target_os = "openbsd"))]
++ /// Minimum number of bytes of storage actually allocated for any portion of
++ /// a file.
++ POSIX_ALLOC_SIZE_MIN = libc::_PC_ALLOC_SIZE_MIN,
++ #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
++ target_os = "linux", target_os = "openbsd"))]
++ /// Recommended increment for file transfer sizes between the
++ /// `POSIX_REC_MIN_XFER_SIZE` and `POSIX_REC_MAX_XFER_SIZE` values.
++ POSIX_REC_INCR_XFER_SIZE = libc::_PC_REC_INCR_XFER_SIZE,
++ #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
++ target_os = "linux", target_os = "openbsd"))]
++ /// Maximum recommended file transfer size.
++ POSIX_REC_MAX_XFER_SIZE = libc::_PC_REC_MAX_XFER_SIZE,
++ #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
++ target_os = "linux", target_os = "openbsd"))]
++ /// Minimum recommended file transfer size.
++ POSIX_REC_MIN_XFER_SIZE = libc::_PC_REC_MIN_XFER_SIZE,
++ #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
++ target_os = "linux", target_os = "openbsd"))]
++ /// Recommended file transfer buffer alignment.
++ POSIX_REC_XFER_ALIGN = libc::_PC_REC_XFER_ALIGN,
++ #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
++ target_os = "linux", target_os = "netbsd", target_os = "openbsd"))]
++ /// Maximum number of bytes in a symbolic link.
++ SYMLINK_MAX = libc::_PC_SYMLINK_MAX,
++ /// The use of `chown` and `fchown` is restricted to a process with
++ /// appropriate privileges, and to changing the group ID of a file only to
++ /// the effective group ID of the process or to one of its supplementary
++ /// group IDs.
++ _POSIX_CHOWN_RESTRICTED = libc::_PC_CHOWN_RESTRICTED,
++ /// Pathname components longer than {NAME_MAX} generate an error.
++ _POSIX_NO_TRUNC = libc::_PC_NO_TRUNC,
++ /// This symbol shall be defined to be the value of a character that shall
++ /// disable terminal special character handling.
++ _POSIX_VDISABLE = libc::_PC_VDISABLE,
++ #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
++ target_os = "linux", target_os = "openbsd"))]
++ /// Asynchronous input or output operations may be performed for the
++ /// associated file.
++ _POSIX_ASYNC_IO = libc::_PC_ASYNC_IO,
++ #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
++ target_os = "linux", target_os = "openbsd"))]
++ /// Prioritized input or output operations may be performed for the
++ /// associated file.
++ _POSIX_PRIO_IO = libc::_PC_PRIO_IO,
++ #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
++ target_os = "linux", target_os = "netbsd", target_os = "openbsd"))]
++ /// Synchronized input or output operations may be performed for the
++ /// associated file.
++ _POSIX_SYNC_IO = libc::_PC_SYNC_IO,
++ #[cfg(any(target_os = "dragonfly", target_os = "openbsd"))]
++ /// The resolution in nanoseconds for all file timestamps.
++ _POSIX_TIMESTAMP_RESOLUTION = libc::_PC_TIMESTAMP_RESOLUTION
++}
++
++/// Like `pathconf`, but works with file descriptors instead of paths (see
++/// [fpathconf(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html))
++///
++/// # Parameters
++///
++/// - `fd`: The file descriptor whose variable should be interrogated
++/// - `var`: The pathconf variable to lookup
++///
++/// # Returns
++///
++/// - `Ok(Some(x))`: the variable's limit (for limit variables) or its
++/// implementation level (for option variables). Implementation levels are
++/// usually a decimal-coded date, such as 200112 for POSIX 2001.12
++/// - `Ok(None)`: the variable has no limit (for limit variables) or is
++/// unsupported (for option variables)
++/// - `Err(x)`: an error occurred
++pub fn fpathconf(fd: RawFd, var: PathconfVar) -> Result<Option<c_long>> {
++ let raw = unsafe {
++ Errno::clear();
++ libc::fpathconf(fd, var as c_int)
++ };
++ if raw == -1 {
++ if errno::errno() == 0 {
++ Ok(None)
++ } else {
++ Err(Error::Sys(Errno::last()))
++ }
++ } else {
++ Ok(Some(raw))
++ }
++}
++
++/// Get path-dependent configurable system variables (see
++/// [pathconf(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html))
++///
++/// Returns the value of a path-dependent configurable system variable. Most
++/// supported variables also have associated compile-time constants, but POSIX
++/// allows their values to change at runtime. There are generally two types of
++/// `pathconf` variables: options and limits. See [pathconf(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html) for more details.
++///
++/// # Parameters
++///
++/// - `path`: Lookup the value of `var` for this file or directory
++/// - `var`: The `pathconf` variable to lookup
++///
++/// # Returns
++///
++/// - `Ok(Some(x))`: the variable's limit (for limit variables) or its
++/// implementation level (for option variables). Implementation levels are
++/// usually a decimal-coded date, such as 200112 for POSIX 2001.12
++/// - `Ok(None)`: the variable has no limit (for limit variables) or is
++/// unsupported (for option variables)
++/// - `Err(x)`: an error occurred
++pub fn pathconf<P: ?Sized + NixPath>(path: &P, var: PathconfVar) -> Result<Option<c_long>> {
++ let raw = path.with_nix_path(|cstr| {
++ unsafe {
++ Errno::clear();
++ libc::pathconf(cstr.as_ptr(), var as c_int)
++ }
++ })?;
++ if raw == -1 {
++ if errno::errno() == 0 {
++ Ok(None)
++ } else {
++ Err(Error::Sys(Errno::last()))
++ }
++ } else {
++ Ok(Some(raw))
++ }
++}
++
++/// Variable names for `sysconf`
++///
++/// Nix uses the same naming convention for these variables as the
++/// [getconf(1)](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/getconf.html) utility.
++/// That is, `SysconfVar` variables have the same name as the abstract variables
++/// shown in the `sysconf(3)` man page. Usually, it's the same as the C
++/// variable name without the leading `_SC_`.
++///
++/// All of these symbols are standardized by POSIX 1003.1-2008, but haven't been
++/// implemented by all platforms.
++///
++/// # References
++///
++/// - [sysconf(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sysconf.html)
++/// - [unistd.h](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/unistd.h.html)
++/// - [limits.h](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html)
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++#[repr(i32)]
++pub enum SysconfVar {
++ /// Maximum number of I/O operations in a single list I/O call supported by
++ /// the implementation.
++ AIO_LISTIO_MAX = libc::_SC_AIO_LISTIO_MAX,
++ /// Maximum number of outstanding asynchronous I/O operations supported by
++ /// the implementation.
++ AIO_MAX = libc::_SC_AIO_MAX,
++ #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
++ target_os = "ios", target_os="linux", target_os = "macos",
++ target_os="openbsd"))]
++ /// The maximum amount by which a process can decrease its asynchronous I/O
++ /// priority level from its own scheduling priority.
++ AIO_PRIO_DELTA_MAX = libc::_SC_AIO_PRIO_DELTA_MAX,
++ /// Maximum length of argument to the exec functions including environment data.
++ ARG_MAX = libc::_SC_ARG_MAX,
++ /// Maximum number of functions that may be registered with `atexit`.
++ ATEXIT_MAX = libc::_SC_ATEXIT_MAX,
++ /// Maximum obase values allowed by the bc utility.
++ BC_BASE_MAX = libc::_SC_BC_BASE_MAX,
++ /// Maximum number of elements permitted in an array by the bc utility.
++ BC_DIM_MAX = libc::_SC_BC_DIM_MAX,
++ /// Maximum scale value allowed by the bc utility.
++ BC_SCALE_MAX = libc::_SC_BC_SCALE_MAX,
++ /// Maximum length of a string constant accepted by the bc utility.
++ BC_STRING_MAX = libc::_SC_BC_STRING_MAX,
++ /// Maximum number of simultaneous processes per real user ID.
++ CHILD_MAX = libc::_SC_CHILD_MAX,
++ // _SC_CLK_TCK is obsolete
++ /// Maximum number of weights that can be assigned to an entry of the
++ /// LC_COLLATE order keyword in the locale definition file
++ COLL_WEIGHTS_MAX = libc::_SC_COLL_WEIGHTS_MAX,
++ /// Maximum number of timer expiration overruns.
++ DELAYTIMER_MAX = libc::_SC_DELAYTIMER_MAX,
++ /// Maximum number of expressions that can be nested within parentheses by
++ /// the expr utility.
++ EXPR_NEST_MAX = libc::_SC_EXPR_NEST_MAX,
++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++ target_os="linux", target_os = "macos", target_os="netbsd",
++ target_os="openbsd"))]
++ /// Maximum length of a host name (not including the terminating null) as
++ /// returned from the `gethostname` function
++ HOST_NAME_MAX = libc::_SC_HOST_NAME_MAX,
++ /// Maximum number of iovec structures that one process has available for
++ /// use with `readv` or `writev`.
++ IOV_MAX = libc::_SC_IOV_MAX,
++ /// Unless otherwise noted, the maximum length, in bytes, of a utility's
++ /// input line (either standard input or another file), when the utility is
++ /// described as processing text files. The length includes room for the
++ /// trailing <newline>.
++ LINE_MAX = libc::_SC_LINE_MAX,
++ /// Maximum length of a login name.
++ LOGIN_NAME_MAX = libc::_SC_LOGIN_NAME_MAX,
++ /// Maximum number of simultaneous supplementary group IDs per process.
++ NGROUPS_MAX = libc::_SC_NGROUPS_MAX,
++ /// Initial size of `getgrgid_r` and `getgrnam_r` data buffers
++ GETGR_R_SIZE_MAX = libc::_SC_GETGR_R_SIZE_MAX,
++ /// Initial size of `getpwuid_r` and `getpwnam_r` data buffers
++ GETPW_R_SIZE_MAX = libc::_SC_GETPW_R_SIZE_MAX,
++ /// The maximum number of open message queue descriptors a process may hold.
++ MQ_OPEN_MAX = libc::_SC_MQ_OPEN_MAX,
++ /// The maximum number of message priorities supported by the implementation.
++ MQ_PRIO_MAX = libc::_SC_MQ_PRIO_MAX,
++ /// A value one greater than the maximum value that the system may assign to
++ /// a newly-created file descriptor.
++ OPEN_MAX = libc::_SC_OPEN_MAX,
++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++ target_os="linux", target_os = "macos", target_os="openbsd"))]
++ /// The implementation supports the Advisory Information option.
++ _POSIX_ADVISORY_INFO = libc::_SC_ADVISORY_INFO,
++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++ target_os="linux", target_os = "macos", target_os="netbsd",
++ target_os="openbsd"))]
++ /// The implementation supports barriers.
++ _POSIX_BARRIERS = libc::_SC_BARRIERS,
++ /// The implementation supports asynchronous input and output.
++ _POSIX_ASYNCHRONOUS_IO = libc::_SC_ASYNCHRONOUS_IO,
++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++ target_os="linux", target_os = "macos", target_os="netbsd",
++ target_os="openbsd"))]
++ /// The implementation supports clock selection.
++ _POSIX_CLOCK_SELECTION = libc::_SC_CLOCK_SELECTION,
++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++ target_os="linux", target_os = "macos", target_os="netbsd",
++ target_os="openbsd"))]
++ /// The implementation supports the Process CPU-Time Clocks option.
++ _POSIX_CPUTIME = libc::_SC_CPUTIME,
++ /// The implementation supports the File Synchronization option.
++ _POSIX_FSYNC = libc::_SC_FSYNC,
++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++ target_os="linux", target_os = "macos", target_os="openbsd"))]
++ /// The implementation supports the IPv6 option.
++ _POSIX_IPV6 = libc::_SC_IPV6,
++ /// The implementation supports job control.
++ _POSIX_JOB_CONTROL = libc::_SC_JOB_CONTROL,
++ /// The implementation supports memory mapped Files.
++ _POSIX_MAPPED_FILES = libc::_SC_MAPPED_FILES,
++ /// The implementation supports the Process Memory Locking option.
++ _POSIX_MEMLOCK = libc::_SC_MEMLOCK,
++ /// The implementation supports the Range Memory Locking option.
++ _POSIX_MEMLOCK_RANGE = libc::_SC_MEMLOCK_RANGE,
++ /// The implementation supports memory protection.
++ _POSIX_MEMORY_PROTECTION = libc::_SC_MEMORY_PROTECTION,
++ /// The implementation supports the Message Passing option.
++ _POSIX_MESSAGE_PASSING = libc::_SC_MESSAGE_PASSING,
++ /// The implementation supports the Monotonic Clock option.
++ _POSIX_MONOTONIC_CLOCK = libc::_SC_MONOTONIC_CLOCK,
++ #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
++ target_os = "ios", target_os="linux", target_os = "macos",
++ target_os="openbsd"))]
++ /// The implementation supports the Prioritized Input and Output option.
++ _POSIX_PRIORITIZED_IO = libc::_SC_PRIORITIZED_IO,
++ /// The implementation supports the Process Scheduling option.
++ _POSIX_PRIORITY_SCHEDULING = libc::_SC_PRIORITY_SCHEDULING,
++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++ target_os="linux", target_os = "macos", target_os="openbsd"))]
++ /// The implementation supports the Raw Sockets option.
++ _POSIX_RAW_SOCKETS = libc::_SC_RAW_SOCKETS,
++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++ target_os="linux", target_os = "macos", target_os="netbsd",
++ target_os="openbsd"))]
++ /// The implementation supports read-write locks.
++ _POSIX_READER_WRITER_LOCKS = libc::_SC_READER_WRITER_LOCKS,
++ #[cfg(any(target_os = "android", target_os="dragonfly", target_os="freebsd",
++ target_os = "ios", target_os="linux", target_os = "macos",
++ target_os = "openbsd"))]
++ /// The implementation supports realtime signals.
++ _POSIX_REALTIME_SIGNALS = libc::_SC_REALTIME_SIGNALS,
++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++ target_os="linux", target_os = "macos", target_os="netbsd",
++ target_os="openbsd"))]
++ /// The implementation supports the Regular Expression Handling option.
++ _POSIX_REGEXP = libc::_SC_REGEXP,
++ /// Each process has a saved set-user-ID and a saved set-group-ID.
++ _POSIX_SAVED_IDS = libc::_SC_SAVED_IDS,
++ /// The implementation supports semaphores.
++ _POSIX_SEMAPHORES = libc::_SC_SEMAPHORES,
++ /// The implementation supports the Shared Memory Objects option.
++ _POSIX_SHARED_MEMORY_OBJECTS = libc::_SC_SHARED_MEMORY_OBJECTS,
++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++ target_os="linux", target_os = "macos", target_os="netbsd",
++ target_os="openbsd"))]
++ /// The implementation supports the POSIX shell.
++ _POSIX_SHELL = libc::_SC_SHELL,
++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++ target_os="linux", target_os = "macos", target_os="netbsd",
++ target_os="openbsd"))]
++ /// The implementation supports the Spawn option.
++ _POSIX_SPAWN = libc::_SC_SPAWN,
++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++ target_os="linux", target_os = "macos", target_os="netbsd",
++ target_os="openbsd"))]
++ /// The implementation supports spin locks.
++ _POSIX_SPIN_LOCKS = libc::_SC_SPIN_LOCKS,
++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++ target_os="linux", target_os = "macos", target_os="openbsd"))]
++ /// The implementation supports the Process Sporadic Server option.
++ _POSIX_SPORADIC_SERVER = libc::_SC_SPORADIC_SERVER,
++ #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos",
++ target_os="openbsd"))]
++ _POSIX_SS_REPL_MAX = libc::_SC_SS_REPL_MAX,
++ /// The implementation supports the Synchronized Input and Output option.
++ _POSIX_SYNCHRONIZED_IO = libc::_SC_SYNCHRONIZED_IO,
++ /// The implementation supports the Thread Stack Address Attribute option.
++ _POSIX_THREAD_ATTR_STACKADDR = libc::_SC_THREAD_ATTR_STACKADDR,
++ /// The implementation supports the Thread Stack Size Attribute option.
++ _POSIX_THREAD_ATTR_STACKSIZE = libc::_SC_THREAD_ATTR_STACKSIZE,
++ #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos",
++ target_os="netbsd", target_os="openbsd"))]
++ /// The implementation supports the Thread CPU-Time Clocks option.
++ _POSIX_THREAD_CPUTIME = libc::_SC_THREAD_CPUTIME,
++ /// The implementation supports the Non-Robust Mutex Priority Inheritance
++ /// option.
++ _POSIX_THREAD_PRIO_INHERIT = libc::_SC_THREAD_PRIO_INHERIT,
++ /// The implementation supports the Non-Robust Mutex Priority Protection option.
++ _POSIX_THREAD_PRIO_PROTECT = libc::_SC_THREAD_PRIO_PROTECT,
++ /// The implementation supports the Thread Execution Scheduling option.
++ _POSIX_THREAD_PRIORITY_SCHEDULING = libc::_SC_THREAD_PRIORITY_SCHEDULING,
++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++ target_os="linux", target_os = "macos", target_os="netbsd",
++ target_os="openbsd"))]
++ /// The implementation supports the Thread Process-Shared Synchronization
++ /// option.
++ _POSIX_THREAD_PROCESS_SHARED = libc::_SC_THREAD_PROCESS_SHARED,
++ #[cfg(any(target_os="dragonfly", target_os="linux", target_os="openbsd"))]
++ /// The implementation supports the Robust Mutex Priority Inheritance option.
++ _POSIX_THREAD_ROBUST_PRIO_INHERIT = libc::_SC_THREAD_ROBUST_PRIO_INHERIT,
++ #[cfg(any(target_os="dragonfly", target_os="linux", target_os="openbsd"))]
++ /// The implementation supports the Robust Mutex Priority Protection option.
++ _POSIX_THREAD_ROBUST_PRIO_PROTECT = libc::_SC_THREAD_ROBUST_PRIO_PROTECT,
++ /// The implementation supports thread-safe functions.
++ _POSIX_THREAD_SAFE_FUNCTIONS = libc::_SC_THREAD_SAFE_FUNCTIONS,
++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++ target_os="linux", target_os = "macos", target_os="openbsd"))]
++ /// The implementation supports the Thread Sporadic Server option.
++ _POSIX_THREAD_SPORADIC_SERVER = libc::_SC_THREAD_SPORADIC_SERVER,
++ /// The implementation supports threads.
++ _POSIX_THREADS = libc::_SC_THREADS,
++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++ target_os="linux", target_os = "macos", target_os="openbsd"))]
++ /// The implementation supports timeouts.
++ _POSIX_TIMEOUTS = libc::_SC_TIMEOUTS,
++ /// The implementation supports timers.
++ _POSIX_TIMERS = libc::_SC_TIMERS,
++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++ target_os="linux", target_os = "macos", target_os="openbsd"))]
++ /// The implementation supports the Trace option.
++ _POSIX_TRACE = libc::_SC_TRACE,
++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++ target_os="linux", target_os = "macos", target_os="openbsd"))]
++ /// The implementation supports the Trace Event Filter option.
++ _POSIX_TRACE_EVENT_FILTER = libc::_SC_TRACE_EVENT_FILTER,
++ #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos",
++ target_os="openbsd"))]
++ _POSIX_TRACE_EVENT_NAME_MAX = libc::_SC_TRACE_EVENT_NAME_MAX,
++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++ target_os="linux", target_os = "macos", target_os="openbsd"))]
++ /// The implementation supports the Trace Inherit option.
++ _POSIX_TRACE_INHERIT = libc::_SC_TRACE_INHERIT,
++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++ target_os="linux", target_os = "macos", target_os="openbsd"))]
++ /// The implementation supports the Trace Log option.
++ _POSIX_TRACE_LOG = libc::_SC_TRACE_LOG,
++ #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos",
++ target_os="openbsd"))]
++ _POSIX_TRACE_NAME_MAX = libc::_SC_TRACE_NAME_MAX,
++ #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos",
++ target_os="openbsd"))]
++ _POSIX_TRACE_SYS_MAX = libc::_SC_TRACE_SYS_MAX,
++ #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos",
++ target_os="openbsd"))]
++ _POSIX_TRACE_USER_EVENT_MAX = libc::_SC_TRACE_USER_EVENT_MAX,
++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++ target_os="linux", target_os = "macos", target_os="openbsd"))]
++ /// The implementation supports the Typed Memory Objects option.
++ _POSIX_TYPED_MEMORY_OBJECTS = libc::_SC_TYPED_MEMORY_OBJECTS,
++ /// Integer value indicating version of this standard (C-language binding)
++ /// to which the implementation conforms. For implementations conforming to
++ /// POSIX.1-2008, the value shall be 200809L.
++ _POSIX_VERSION = libc::_SC_VERSION,
++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++ target_os="linux", target_os = "macos", target_os="netbsd",
++ target_os="openbsd"))]
++ /// The implementation provides a C-language compilation environment with
++ /// 32-bit `int`, `long`, `pointer`, and `off_t` types.
++ _POSIX_V6_ILP32_OFF32 = libc::_SC_V6_ILP32_OFF32,
++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++ target_os="linux", target_os = "macos", target_os="netbsd",
++ target_os="openbsd"))]
++ /// The implementation provides a C-language compilation environment with
++ /// 32-bit `int`, `long`, and pointer types and an `off_t` type using at
++ /// least 64 bits.
++ _POSIX_V6_ILP32_OFFBIG = libc::_SC_V6_ILP32_OFFBIG,
++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++ target_os="linux", target_os = "macos", target_os="netbsd",
++ target_os="openbsd"))]
++ /// The implementation provides a C-language compilation environment with
++ /// 32-bit `int` and 64-bit `long`, `pointer`, and `off_t` types.
++ _POSIX_V6_LP64_OFF64 = libc::_SC_V6_LP64_OFF64,
++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++ target_os="linux", target_os = "macos", target_os="netbsd",
++ target_os="openbsd"))]
++ /// The implementation provides a C-language compilation environment with an
++ /// `int` type using at least 32 bits and `long`, pointer, and `off_t` types
++ /// using at least 64 bits.
++ _POSIX_V6_LPBIG_OFFBIG = libc::_SC_V6_LPBIG_OFFBIG,
++ /// The implementation supports the C-Language Binding option.
++ _POSIX2_C_BIND = libc::_SC_2_C_BIND,
++ /// The implementation supports the C-Language Development Utilities option.
++ _POSIX2_C_DEV = libc::_SC_2_C_DEV,
++ /// The implementation supports the Terminal Characteristics option.
++ _POSIX2_CHAR_TERM = libc::_SC_2_CHAR_TERM,
++ /// The implementation supports the FORTRAN Development Utilities option.
++ _POSIX2_FORT_DEV = libc::_SC_2_FORT_DEV,
++ /// The implementation supports the FORTRAN Runtime Utilities option.
++ _POSIX2_FORT_RUN = libc::_SC_2_FORT_RUN,
++ /// The implementation supports the creation of locales by the localedef
++ /// utility.
++ _POSIX2_LOCALEDEF = libc::_SC_2_LOCALEDEF,
++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++ target_os="linux", target_os = "macos", target_os="netbsd",
++ target_os="openbsd"))]
++ /// The implementation supports the Batch Environment Services and Utilities
++ /// option.
++ _POSIX2_PBS = libc::_SC_2_PBS,
++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++ target_os="linux", target_os = "macos", target_os="netbsd",
++ target_os="openbsd"))]
++ /// The implementation supports the Batch Accounting option.
++ _POSIX2_PBS_ACCOUNTING = libc::_SC_2_PBS_ACCOUNTING,
++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++ target_os="linux", target_os = "macos", target_os="netbsd",
++ target_os="openbsd"))]
++ /// The implementation supports the Batch Checkpoint/Restart option.
++ _POSIX2_PBS_CHECKPOINT = libc::_SC_2_PBS_CHECKPOINT,
++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++ target_os="linux", target_os = "macos", target_os="netbsd",
++ target_os="openbsd"))]
++ /// The implementation supports the Locate Batch Job Request option.
++ _POSIX2_PBS_LOCATE = libc::_SC_2_PBS_LOCATE,
++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++ target_os="linux", target_os = "macos", target_os="netbsd",
++ target_os="openbsd"))]
++ /// The implementation supports the Batch Job Message Request option.
++ _POSIX2_PBS_MESSAGE = libc::_SC_2_PBS_MESSAGE,
++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++ target_os="linux", target_os = "macos", target_os="netbsd",
++ target_os="openbsd"))]
++ /// The implementation supports the Track Batch Job Request option.
++ _POSIX2_PBS_TRACK = libc::_SC_2_PBS_TRACK,
++ /// The implementation supports the Software Development Utilities option.
++ _POSIX2_SW_DEV = libc::_SC_2_SW_DEV,
++ /// The implementation supports the User Portability Utilities option.
++ _POSIX2_UPE = libc::_SC_2_UPE,
++ /// Integer value indicating version of the Shell and Utilities volume of
++ /// POSIX.1 to which the implementation conforms.
++ _POSIX2_VERSION = libc::_SC_2_VERSION,
++ /// The size of a system page in bytes.
++ ///
++ /// POSIX also defines an alias named `PAGESIZE`, but Rust does not allow two
++ /// enum constants to have the same value, so nix omits `PAGESIZE`.
++ PAGE_SIZE = libc::_SC_PAGE_SIZE,
++ PTHREAD_DESTRUCTOR_ITERATIONS = libc::_SC_THREAD_DESTRUCTOR_ITERATIONS,
++ PTHREAD_KEYS_MAX = libc::_SC_THREAD_KEYS_MAX,
++ PTHREAD_STACK_MIN = libc::_SC_THREAD_STACK_MIN,
++ PTHREAD_THREADS_MAX = libc::_SC_THREAD_THREADS_MAX,
++ RE_DUP_MAX = libc::_SC_RE_DUP_MAX,
++ #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
++ target_os = "ios", target_os="linux", target_os = "macos",
++ target_os="openbsd"))]
++ RTSIG_MAX = libc::_SC_RTSIG_MAX,
++ SEM_NSEMS_MAX = libc::_SC_SEM_NSEMS_MAX,
++ #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
++ target_os = "ios", target_os="linux", target_os = "macos",
++ target_os="openbsd"))]
++ SEM_VALUE_MAX = libc::_SC_SEM_VALUE_MAX,
++ #[cfg(any(target_os = "android", target_os="dragonfly", target_os="freebsd",
++ target_os = "ios", target_os="linux", target_os = "macos",
++ target_os = "openbsd"))]
++ SIGQUEUE_MAX = libc::_SC_SIGQUEUE_MAX,
++ STREAM_MAX = libc::_SC_STREAM_MAX,
++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++ target_os="linux", target_os = "macos", target_os="netbsd",
++ target_os="openbsd"))]
++ SYMLOOP_MAX = libc::_SC_SYMLOOP_MAX,
++ TIMER_MAX = libc::_SC_TIMER_MAX,
++ TTY_NAME_MAX = libc::_SC_TTY_NAME_MAX,
++ TZNAME_MAX = libc::_SC_TZNAME_MAX,
++ #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
++ target_os = "ios", target_os="linux", target_os = "macos",
++ target_os="openbsd"))]
++ /// The implementation supports the X/Open Encryption Option Group.
++ _XOPEN_CRYPT = libc::_SC_XOPEN_CRYPT,
++ #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
++ target_os = "ios", target_os="linux", target_os = "macos",
++ target_os="openbsd"))]
++ /// The implementation supports the Issue 4, Version 2 Enhanced
++ /// Internationalization Option Group.
++ _XOPEN_ENH_I18N = libc::_SC_XOPEN_ENH_I18N,
++ #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
++ target_os = "ios", target_os="linux", target_os = "macos",
++ target_os="openbsd"))]
++ _XOPEN_LEGACY = libc::_SC_XOPEN_LEGACY,
++ #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
++ target_os = "ios", target_os="linux", target_os = "macos",
++ target_os="openbsd"))]
++ /// The implementation supports the X/Open Realtime Option Group.
++ _XOPEN_REALTIME = libc::_SC_XOPEN_REALTIME,
++ #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
++ target_os = "ios", target_os="linux", target_os = "macos",
++ target_os="openbsd"))]
++ /// The implementation supports the X/Open Realtime Threads Option Group.
++ _XOPEN_REALTIME_THREADS = libc::_SC_XOPEN_REALTIME_THREADS,
++ /// The implementation supports the Issue 4, Version 2 Shared Memory Option
++ /// Group.
++ _XOPEN_SHM = libc::_SC_XOPEN_SHM,
++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++ target_os="linux", target_os = "macos", target_os="openbsd"))]
++ /// The implementation supports the XSI STREAMS Option Group.
++ _XOPEN_STREAMS = libc::_SC_XOPEN_STREAMS,
++ #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
++ target_os = "ios", target_os="linux", target_os = "macos",
++ target_os="openbsd"))]
++ /// The implementation supports the XSI option
++ _XOPEN_UNIX = libc::_SC_XOPEN_UNIX,
++ #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
++ target_os = "ios", target_os="linux", target_os = "macos",
++ target_os="openbsd"))]
++ /// Integer value indicating version of the X/Open Portability Guide to
++ /// which the implementation conforms.
++ _XOPEN_VERSION = libc::_SC_XOPEN_VERSION,
++}
++
++/// Get configurable system variables (see
++/// [sysconf(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sysconf.html))
++///
++/// Returns the value of a configurable system variable. Most supported
++/// variables also have associated compile-time constants, but POSIX
++/// allows their values to change at runtime. There are generally two types of
++/// sysconf variables: options and limits. See sysconf(3) for more details.
++///
++/// # Returns
++///
++/// - `Ok(Some(x))`: the variable's limit (for limit variables) or its
++/// implementation level (for option variables). Implementation levels are
++/// usually a decimal-coded date, such as 200112 for POSIX 2001.12
++/// - `Ok(None)`: the variable has no limit (for limit variables) or is
++/// unsupported (for option variables)
++/// - `Err(x)`: an error occurred
++pub fn sysconf(var: SysconfVar) -> Result<Option<c_long>> {
++ let raw = unsafe {
++ Errno::clear();
++ libc::sysconf(var as c_int)
++ };
++ if raw == -1 {
++ if errno::errno() == 0 {
++ Ok(None)
++ } else {
++ Err(Error::Sys(Errno::last()))
++ }
++ } else {
++ Ok(Some(raw))
++ }
++}
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++mod pivot_root {
++ use libc;
++ use {Result, NixPath};
++ use errno::Errno;
++
++ pub fn pivot_root<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(
++ new_root: &P1, put_old: &P2) -> Result<()> {
++ let res = new_root.with_nix_path(|new_root| {
++ put_old.with_nix_path(|put_old| {
++ unsafe {
++ libc::syscall(libc::SYS_pivot_root, new_root.as_ptr(), put_old.as_ptr())
++ }
++ })
++ })??;
++
++ Errno::result(res).map(drop)
++ }
++}
++
++#[cfg(any(target_os = "android", target_os = "freebsd",
++ target_os = "linux", target_os = "openbsd"))]
++mod setres {
++ use libc;
++ use Result;
++ use errno::Errno;
++ use super::{Uid, Gid};
++
++ /// Sets the real, effective, and saved uid.
++ /// ([see setresuid(2)](http://man7.org/linux/man-pages/man2/setresuid.2.html))
++ ///
++ /// * `ruid`: real user id
++ /// * `euid`: effective user id
++ /// * `suid`: saved user id
++ /// * returns: Ok or libc error code.
++ ///
++ /// Err is returned if the user doesn't have permission to set this UID.
++ #[inline]
++ pub fn setresuid(ruid: Uid, euid: Uid, suid: Uid) -> Result<()> {
++ let res = unsafe { libc::setresuid(ruid.into(), euid.into(), suid.into()) };
++
++ Errno::result(res).map(drop)
++ }
++
++ /// Sets the real, effective, and saved gid.
++ /// ([see setresuid(2)](http://man7.org/linux/man-pages/man2/setresuid.2.html))
++ ///
++ /// * `rgid`: real group id
++ /// * `egid`: effective group id
++ /// * `sgid`: saved group id
++ /// * returns: Ok or libc error code.
++ ///
++ /// Err is returned if the user doesn't have permission to set this GID.
++ #[inline]
++ pub fn setresgid(rgid: Gid, egid: Gid, sgid: Gid) -> Result<()> {
++ let res = unsafe { libc::setresgid(rgid.into(), egid.into(), sgid.into()) };
++
++ Errno::result(res).map(drop)
++ }
++}
++
++libc_bitflags!{
++ /// Options for access()
++ pub struct AccessFlags : c_int {
++ /// Test for existence of file.
++ F_OK;
++ /// Test for read permission.
++ R_OK;
++ /// Test for write permission.
++ W_OK;
++ /// Test for execute (search) permission.
++ X_OK;
++ }
++}
++
++/// Checks the file named by `path` for accessibility according to the flags given by `amode`
++/// See [access(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/access.html)
++pub fn access<P: ?Sized + NixPath>(path: &P, amode: AccessFlags) -> Result<()> {
++ let res = path.with_nix_path(|cstr| {
++ unsafe {
++ libc::access(cstr.as_ptr(), amode.bits)
++ }
++ })?;
++ Errno::result(res).map(drop)
++}
+diff --git a/third_party/rust/nix-0.15.0/test/sys/mod.rs b/third_party/rust/nix-0.15.0/test/sys/mod.rs
+new file mode 100644
+index 0000000000000..60a58dd106f19
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/sys/mod.rs
+@@ -0,0 +1,38 @@
++mod test_signal;
++
++// NOTE: DragonFly lacks a kernel-level implementation of Posix AIO as of
++// this writing. There is an user-level implementation, but whether aio
++// works or not heavily depends on which pthread implementation is chosen
++// by the user at link time. For this reason we do not want to run aio test
++// cases on DragonFly.
++#[cfg(any(target_os = "freebsd",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos",
++ target_os = "netbsd"))]
++mod test_aio;
++#[cfg(target_os = "linux")]
++mod test_signalfd;
++mod test_socket;
++mod test_sockopt;
++mod test_select;
++#[cfg(any(target_os = "android", target_os = "linux"))]
++mod test_sysinfo;
++mod test_termios;
++mod test_ioctl;
++mod test_wait;
++mod test_uio;
++
++#[cfg(target_os = "linux")]
++mod test_epoll;
++#[cfg(target_os = "linux")]
++mod test_inotify;
++mod test_pthread;
++#[cfg(any(target_os = "android",
++ target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "linux",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++mod test_ptrace;
+diff --git a/third_party/rust/nix-0.15.0/test/sys/test_aio.rs b/third_party/rust/nix-0.15.0/test/sys/test_aio.rs
+new file mode 100644
+index 0000000000000..d4b09b0b81905
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/sys/test_aio.rs
+@@ -0,0 +1,654 @@
++use bytes::{Bytes, BytesMut};
++use libc::{c_int, c_void};
++use nix::{Error, Result};
++use nix::errno::*;
++use nix::sys::aio::*;
++use nix::sys::signal::{SaFlags, SigAction, sigaction, SigevNotify, SigHandler, Signal, SigSet};
++use nix::sys::time::{TimeSpec, TimeValLike};
++use std::io::{Write, Read, Seek, SeekFrom};
++use std::ops::Deref;
++use std::os::unix::io::AsRawFd;
++use std::sync::atomic::{AtomicBool, Ordering};
++use std::{thread, time};
++use tempfile::tempfile;
++
++// Helper that polls an AioCb for completion or error
++fn poll_aio(aiocb: &mut AioCb) -> Result<()> {
++ loop {
++ let err = aiocb.error();
++ if err != Err(Error::from(Errno::EINPROGRESS)) { return err; };
++ thread::sleep(time::Duration::from_millis(10));
++ }
++}
++
++#[test]
++fn test_accessors() {
++ let mut rbuf = vec![0; 4];
++ let aiocb = AioCb::from_mut_slice( 1001,
++ 2, //offset
++ &mut rbuf,
++ 42, //priority
++ SigevNotify::SigevSignal {
++ signal: Signal::SIGUSR2,
++ si_value: 99
++ },
++ LioOpcode::LIO_NOP);
++ assert_eq!(1001, aiocb.fd());
++ assert_eq!(Some(LioOpcode::LIO_NOP), aiocb.lio_opcode());
++ assert_eq!(4, aiocb.nbytes());
++ assert_eq!(2, aiocb.offset());
++ assert_eq!(42, aiocb.priority());
++ let sev = aiocb.sigevent().sigevent();
++ assert_eq!(Signal::SIGUSR2 as i32, sev.sigev_signo);
++ assert_eq!(99, sev.sigev_value.sival_ptr as i64);
++}
++
++// Tests AioCb.cancel. We aren't trying to test the OS's implementation, only
++// our bindings. So it's sufficient to check that AioCb.cancel returned any
++// AioCancelStat value.
++#[test]
++#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
++fn test_cancel() {
++ let wbuf: &[u8] = b"CDEF";
++
++ let f = tempfile().unwrap();
++ let mut aiocb = AioCb::from_slice( f.as_raw_fd(),
++ 0, //offset
++ wbuf,
++ 0, //priority
++ SigevNotify::SigevNone,
++ LioOpcode::LIO_NOP);
++ aiocb.write().unwrap();
++ let err = aiocb.error();
++ assert!(err == Ok(()) || err == Err(Error::from(Errno::EINPROGRESS)));
++
++ let cancelstat = aiocb.cancel();
++ assert!(cancelstat.is_ok());
++
++ // Wait for aiocb to complete, but don't care whether it succeeded
++ let _ = poll_aio(&mut aiocb);
++ let _ = aiocb.aio_return();
++}
++
++// Tests using aio_cancel_all for all outstanding IOs.
++#[test]
++#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
++fn test_aio_cancel_all() {
++ let wbuf: &[u8] = b"CDEF";
++
++ let f = tempfile().unwrap();
++ let mut aiocb = AioCb::from_slice(f.as_raw_fd(),
++ 0, //offset
++ wbuf,
++ 0, //priority
++ SigevNotify::SigevNone,
++ LioOpcode::LIO_NOP);
++ aiocb.write().unwrap();
++ let err = aiocb.error();
++ assert!(err == Ok(()) || err == Err(Error::from(Errno::EINPROGRESS)));
++
++ let cancelstat = aio_cancel_all(f.as_raw_fd());
++ assert!(cancelstat.is_ok());
++
++ // Wait for aiocb to complete, but don't care whether it succeeded
++ let _ = poll_aio(&mut aiocb);
++ let _ = aiocb.aio_return();
++}
++
++#[test]
++#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
++fn test_fsync() {
++ const INITIAL: &[u8] = b"abcdef123456";
++ let mut f = tempfile().unwrap();
++ f.write_all(INITIAL).unwrap();
++ let mut aiocb = AioCb::from_fd( f.as_raw_fd(),
++ 0, //priority
++ SigevNotify::SigevNone);
++ let err = aiocb.fsync(AioFsyncMode::O_SYNC);
++ assert!(err.is_ok());
++ poll_aio(&mut aiocb).unwrap();
++ aiocb.aio_return().unwrap();
++}
++
++/// `AioCb::fsync` should not modify the `AioCb` object if `libc::aio_fsync` returns
++/// an error
++// Skip on Linux, because Linux's AIO implementation can't detect errors
++// synchronously
++#[test]
++#[cfg(any(target_os = "freebsd", target_os = "macos"))]
++fn test_fsync_error() {
++ use std::mem;
++
++ const INITIAL: &[u8] = b"abcdef123456";
++ // Create an invalid AioFsyncMode
++ let mode = unsafe { mem::transmute(666) };
++ let mut f = tempfile().unwrap();
++ f.write_all(INITIAL).unwrap();
++ let mut aiocb = AioCb::from_fd( f.as_raw_fd(),
++ 0, //priority
++ SigevNotify::SigevNone);
++ let err = aiocb.fsync(mode);
++ assert!(err.is_err());
++}
++
++#[test]
++#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
++fn test_aio_suspend() {
++ const INITIAL: &[u8] = b"abcdef123456";
++ const WBUF: &[u8] = b"CDEFG";
++ let timeout = TimeSpec::seconds(10);
++ let mut rbuf = vec![0; 4];
++ let rlen = rbuf.len();
++ let mut f = tempfile().unwrap();
++ f.write_all(INITIAL).unwrap();
++
++ let mut wcb = AioCb::from_slice( f.as_raw_fd(),
++ 2, //offset
++ WBUF,
++ 0, //priority
++ SigevNotify::SigevNone,
++ LioOpcode::LIO_WRITE);
++
++ let mut rcb = AioCb::from_mut_slice( f.as_raw_fd(),
++ 8, //offset
++ &mut rbuf,
++ 0, //priority
++ SigevNotify::SigevNone,
++ LioOpcode::LIO_READ);
++ wcb.write().unwrap();
++ rcb.read().unwrap();
++ loop {
++ {
++ let cbbuf = [&wcb, &rcb];
++ assert!(aio_suspend(&cbbuf[..], Some(timeout)).is_ok());
++ }
++ if rcb.error() != Err(Error::from(Errno::EINPROGRESS)) &&
++ wcb.error() != Err(Error::from(Errno::EINPROGRESS)) {
++ break
++ }
++ }
++
++ assert!(wcb.aio_return().unwrap() as usize == WBUF.len());
++ assert!(rcb.aio_return().unwrap() as usize == rlen);
++}
++
++// Test a simple aio operation with no completion notification. We must poll
++// for completion
++#[test]
++#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
++fn test_read() {
++ const INITIAL: &[u8] = b"abcdef123456";
++ let mut rbuf = vec![0; 4];
++ const EXPECT: &[u8] = b"cdef";
++ let mut f = tempfile().unwrap();
++ f.write_all(INITIAL).unwrap();
++ {
++ let mut aiocb = AioCb::from_mut_slice( f.as_raw_fd(),
++ 2, //offset
++ &mut rbuf,
++ 0, //priority
++ SigevNotify::SigevNone,
++ LioOpcode::LIO_NOP);
++ aiocb.read().unwrap();
++
++ let err = poll_aio(&mut aiocb);
++ assert!(err == Ok(()));
++ assert!(aiocb.aio_return().unwrap() as usize == EXPECT.len());
++ }
++
++ assert!(EXPECT == rbuf.deref().deref());
++}
++
++/// `AioCb::read` should not modify the `AioCb` object if `libc::aio_read`
++/// returns an error
++// Skip on Linux, because Linux's AIO implementation can't detect errors
++// synchronously
++#[test]
++#[cfg(any(target_os = "freebsd", target_os = "macos"))]
++fn test_read_error() {
++ const INITIAL: &[u8] = b"abcdef123456";
++ let mut rbuf = vec![0; 4];
++ let mut f = tempfile().unwrap();
++ f.write_all(INITIAL).unwrap();
++ let mut aiocb = AioCb::from_mut_slice( f.as_raw_fd(),
++ -1, //an invalid offset
++ &mut rbuf,
++ 0, //priority
++ SigevNotify::SigevNone,
++ LioOpcode::LIO_NOP);
++ assert!(aiocb.read().is_err());
++}
++
++// Tests from_mut_slice
++#[test]
++#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
++fn test_read_into_mut_slice() {
++ const INITIAL: &[u8] = b"abcdef123456";
++ let mut rbuf = vec![0; 4];
++ const EXPECT: &[u8] = b"cdef";
++ let mut f = tempfile().unwrap();
++ f.write_all(INITIAL).unwrap();
++ {
++ let mut aiocb = AioCb::from_mut_slice( f.as_raw_fd(),
++ 2, //offset
++ &mut rbuf,
++ 0, //priority
++ SigevNotify::SigevNone,
++ LioOpcode::LIO_NOP);
++ aiocb.read().unwrap();
++
++ let err = poll_aio(&mut aiocb);
++ assert!(err == Ok(()));
++ assert!(aiocb.aio_return().unwrap() as usize == EXPECT.len());
++ }
++
++ assert!(rbuf == EXPECT);
++}
++
++// Tests from_ptr
++#[test]
++#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
++fn test_read_into_pointer() {
++ const INITIAL: &[u8] = b"abcdef123456";
++ let mut rbuf = vec![0; 4];
++ const EXPECT: &[u8] = b"cdef";
++ let mut f = tempfile().unwrap();
++ f.write_all(INITIAL).unwrap();
++ {
++ // Safety: ok because rbuf lives until after poll_aio
++ let mut aiocb = unsafe {
++ AioCb::from_mut_ptr( f.as_raw_fd(),
++ 2, //offset
++ rbuf.as_mut_ptr() as *mut c_void,
++ rbuf.len(),
++ 0, //priority
++ SigevNotify::SigevNone,
++ LioOpcode::LIO_NOP)
++ };
++ aiocb.read().unwrap();
++
++ let err = poll_aio(&mut aiocb);
++ assert!(err == Ok(()));
++ assert!(aiocb.aio_return().unwrap() as usize == EXPECT.len());
++ }
++
++ assert!(rbuf == EXPECT);
++}
++
++// Test reading into an immutable buffer. It should fail
++// FIXME: This test fails to panic on Linux/musl
++#[test]
++#[should_panic(expected = "Can't read into an immutable buffer")]
++#[cfg_attr(target_env = "musl", ignore)]
++fn test_read_immutable_buffer() {
++ let rbuf: &[u8] = b"CDEF";
++ let f = tempfile().unwrap();
++ let mut aiocb = AioCb::from_slice( f.as_raw_fd(),
++ 2, //offset
++ rbuf,
++ 0, //priority
++ SigevNotify::SigevNone,
++ LioOpcode::LIO_NOP);
++ aiocb.read().unwrap();
++}
++
++
++// Test a simple aio operation with no completion notification. We must poll
++// for completion. Unlike test_aio_read, this test uses AioCb::from_slice
++#[test]
++#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
++fn test_write() {
++ const INITIAL: &[u8] = b"abcdef123456";
++ let wbuf = "CDEF".to_string().into_bytes();
++ let mut rbuf = Vec::new();
++ const EXPECT: &[u8] = b"abCDEF123456";
++
++ let mut f = tempfile().unwrap();
++ f.write_all(INITIAL).unwrap();
++ let mut aiocb = AioCb::from_slice( f.as_raw_fd(),
++ 2, //offset
++ &wbuf,
++ 0, //priority
++ SigevNotify::SigevNone,
++ LioOpcode::LIO_NOP);
++ aiocb.write().unwrap();
++
++ let err = poll_aio(&mut aiocb);
++ assert!(err == Ok(()));
++ assert!(aiocb.aio_return().unwrap() as usize == wbuf.len());
++
++ f.seek(SeekFrom::Start(0)).unwrap();
++ let len = f.read_to_end(&mut rbuf).unwrap();
++ assert!(len == EXPECT.len());
++ assert!(rbuf == EXPECT);
++}
++
++// Tests `AioCb::from_boxed_slice` with `Bytes`
++#[test]
++#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
++fn test_write_bytes() {
++ const INITIAL: &[u8] = b"abcdef123456";
++ let wbuf = Box::new(Bytes::from(&b"CDEF"[..]));
++ let mut rbuf = Vec::new();
++ const EXPECT: &[u8] = b"abCDEF123456";
++ let expected_len = wbuf.len();
++
++ let mut f = tempfile().unwrap();
++ f.write_all(INITIAL).unwrap();
++ let mut aiocb = AioCb::from_boxed_slice( f.as_raw_fd(),
++ 2, //offset
++ wbuf,
++ 0, //priority
++ SigevNotify::SigevNone,
++ LioOpcode::LIO_NOP);
++ aiocb.write().unwrap();
++
++ let err = poll_aio(&mut aiocb);
++ assert!(err == Ok(()));
++ assert!(aiocb.aio_return().unwrap() as usize == expected_len);
++
++ f.seek(SeekFrom::Start(0)).unwrap();
++ let len = f.read_to_end(&mut rbuf).unwrap();
++ assert!(len == EXPECT.len());
++ assert!(rbuf == EXPECT);
++}
++
++// Tests `AioCb::from_boxed_mut_slice` with `BytesMut`
++#[test]
++#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
++fn test_read_bytes_mut_small() {
++ const INITIAL: &[u8] = b"abcdef";
++ let rbuf = Box::new(BytesMut::from(vec![0; 4]));
++ const EXPECT: &[u8] = b"cdef";
++ let mut f = tempfile().unwrap();
++ f.write_all(INITIAL).unwrap();
++
++ let mut aiocb = AioCb::from_boxed_mut_slice( f.as_raw_fd(),
++ 2, //offset
++ rbuf,
++ 0, //priority
++ SigevNotify::SigevNone,
++ LioOpcode::LIO_NOP);
++ aiocb.read().unwrap();
++
++ let err = poll_aio(&mut aiocb);
++ assert_eq!(err, Ok(()));
++ assert_eq!(aiocb.aio_return().unwrap() as usize, EXPECT.len());
++ let buffer = aiocb.boxed_mut_slice().unwrap();
++ assert_eq!(buffer.borrow(), EXPECT);
++}
++
++// Tests `AioCb::from_ptr`
++#[test]
++#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
++fn test_write_from_pointer() {
++ const INITIAL: &[u8] = b"abcdef123456";
++ let wbuf = "CDEF".to_string().into_bytes();
++ let mut rbuf = Vec::new();
++ const EXPECT: &[u8] = b"abCDEF123456";
++
++ let mut f = tempfile().unwrap();
++ f.write_all(INITIAL).unwrap();
++ // Safety: ok because aiocb outlives poll_aio
++ let mut aiocb = unsafe {
++ AioCb::from_ptr( f.as_raw_fd(),
++ 2, //offset
++ wbuf.as_ptr() as *const c_void,
++ wbuf.len(),
++ 0, //priority
++ SigevNotify::SigevNone,
++ LioOpcode::LIO_NOP)
++ };
++ aiocb.write().unwrap();
++
++ let err = poll_aio(&mut aiocb);
++ assert!(err == Ok(()));
++ assert!(aiocb.aio_return().unwrap() as usize == wbuf.len());
++
++ f.seek(SeekFrom::Start(0)).unwrap();
++ let len = f.read_to_end(&mut rbuf).unwrap();
++ assert!(len == EXPECT.len());
++ assert!(rbuf == EXPECT);
++}
++
++/// `AioCb::write` should not modify the `AioCb` object if `libc::aio_write`
++/// returns an error
++// Skip on Linux, because Linux's AIO implementation can't detect errors
++// synchronously
++#[test]
++#[cfg(any(target_os = "freebsd", target_os = "macos"))]
++fn test_write_error() {
++ let wbuf = "CDEF".to_string().into_bytes();
++ let mut aiocb = AioCb::from_slice( 666, // An invalid file descriptor
++ 0, //offset
++ &wbuf,
++ 0, //priority
++ SigevNotify::SigevNone,
++ LioOpcode::LIO_NOP);
++ assert!(aiocb.write().is_err());
++}
++
++lazy_static! {
++ pub static ref SIGNALED: AtomicBool = AtomicBool::new(false);
++}
++
++extern fn sigfunc(_: c_int) {
++ SIGNALED.store(true, Ordering::Relaxed);
++}
++
++// Test an aio operation with completion delivered by a signal
++// FIXME: This test is ignored on mips because of failures in qemu in CI
++#[test]
++#[cfg_attr(any(all(target_env = "musl", target_arch = "x86_64"), target_arch = "mips", target_arch = "mips64"), ignore)]
++fn test_write_sigev_signal() {
++ let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
++ let sa = SigAction::new(SigHandler::Handler(sigfunc),
++ SaFlags::SA_RESETHAND,
++ SigSet::empty());
++ SIGNALED.store(false, Ordering::Relaxed);
++ unsafe { sigaction(Signal::SIGUSR2, &sa) }.unwrap();
++
++ const INITIAL: &[u8] = b"abcdef123456";
++ const WBUF: &[u8] = b"CDEF";
++ let mut rbuf = Vec::new();
++ const EXPECT: &[u8] = b"abCDEF123456";
++
++ let mut f = tempfile().unwrap();
++ f.write_all(INITIAL).unwrap();
++ let mut aiocb = AioCb::from_slice( f.as_raw_fd(),
++ 2, //offset
++ WBUF,
++ 0, //priority
++ SigevNotify::SigevSignal {
++ signal: Signal::SIGUSR2,
++ si_value: 0 //TODO: validate in sigfunc
++ },
++ LioOpcode::LIO_NOP);
++ aiocb.write().unwrap();
++ while !SIGNALED.load(Ordering::Relaxed) {
++ thread::sleep(time::Duration::from_millis(10));
++ }
++
++ assert!(aiocb.aio_return().unwrap() as usize == WBUF.len());
++ f.seek(SeekFrom::Start(0)).unwrap();
++ let len = f.read_to_end(&mut rbuf).unwrap();
++ assert!(len == EXPECT.len());
++ assert!(rbuf == EXPECT);
++}
++
++// Test LioCb::listio with LIO_WAIT, so all AIO ops should be complete by the
++// time listio returns.
++#[test]
++#[cfg(not(any(target_os = "ios", target_os = "macos")))]
++#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
++fn test_liocb_listio_wait() {
++ const INITIAL: &[u8] = b"abcdef123456";
++ const WBUF: &[u8] = b"CDEF";
++ let mut rbuf = vec![0; 4];
++ let rlen = rbuf.len();
++ let mut rbuf2 = Vec::new();
++ const EXPECT: &[u8] = b"abCDEF123456";
++ let mut f = tempfile().unwrap();
++
++ f.write_all(INITIAL).unwrap();
++
++ {
++ let wcb = AioCb::from_slice( f.as_raw_fd(),
++ 2, //offset
++ WBUF,
++ 0, //priority
++ SigevNotify::SigevNone,
++ LioOpcode::LIO_WRITE);
++
++ let rcb = AioCb::from_mut_slice( f.as_raw_fd(),
++ 8, //offset
++ &mut rbuf,
++ 0, //priority
++ SigevNotify::SigevNone,
++ LioOpcode::LIO_READ);
++ let mut liocb = LioCb::with_capacity(2);
++ liocb.aiocbs.push(wcb);
++ liocb.aiocbs.push(rcb);
++ let err = liocb.listio(LioMode::LIO_WAIT, SigevNotify::SigevNone);
++ err.expect("lio_listio");
++
++ assert!(liocb.aio_return(0).unwrap() as usize == WBUF.len());
++ assert!(liocb.aio_return(1).unwrap() as usize == rlen);
++ }
++ assert!(rbuf.deref().deref() == b"3456");
++
++ f.seek(SeekFrom::Start(0)).unwrap();
++ let len = f.read_to_end(&mut rbuf2).unwrap();
++ assert!(len == EXPECT.len());
++ assert!(rbuf2 == EXPECT);
++}
++
++// Test LioCb::listio with LIO_NOWAIT and no SigEvent, so we must use some other
++// mechanism to check for the individual AioCb's completion.
++#[test]
++#[cfg(not(any(target_os = "ios", target_os = "macos")))]
++#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
++fn test_liocb_listio_nowait() {
++ const INITIAL: &[u8] = b"abcdef123456";
++ const WBUF: &[u8] = b"CDEF";
++ let mut rbuf = vec![0; 4];
++ let rlen = rbuf.len();
++ let mut rbuf2 = Vec::new();
++ const EXPECT: &[u8] = b"abCDEF123456";
++ let mut f = tempfile().unwrap();
++
++ f.write_all(INITIAL).unwrap();
++
++ {
++ let wcb = AioCb::from_slice( f.as_raw_fd(),
++ 2, //offset
++ WBUF,
++ 0, //priority
++ SigevNotify::SigevNone,
++ LioOpcode::LIO_WRITE);
++
++ let rcb = AioCb::from_mut_slice( f.as_raw_fd(),
++ 8, //offset
++ &mut rbuf,
++ 0, //priority
++ SigevNotify::SigevNone,
++ LioOpcode::LIO_READ);
++ let mut liocb = LioCb::with_capacity(2);
++ liocb.aiocbs.push(wcb);
++ liocb.aiocbs.push(rcb);
++ let err = liocb.listio(LioMode::LIO_NOWAIT, SigevNotify::SigevNone);
++ err.expect("lio_listio");
++
++ poll_aio(&mut liocb.aiocbs[0]).unwrap();
++ poll_aio(&mut liocb.aiocbs[1]).unwrap();
++ assert!(liocb.aiocbs[0].aio_return().unwrap() as usize == WBUF.len());
++ assert!(liocb.aiocbs[1].aio_return().unwrap() as usize == rlen);
++ }
++ assert!(rbuf.deref().deref() == b"3456");
++
++ f.seek(SeekFrom::Start(0)).unwrap();
++ let len = f.read_to_end(&mut rbuf2).unwrap();
++ assert!(len == EXPECT.len());
++ assert!(rbuf2 == EXPECT);
++}
++
++// Test LioCb::listio with LIO_NOWAIT and a SigEvent to indicate when all
++// AioCb's are complete.
++// FIXME: This test is ignored on mips/mips64 because of failures in qemu in CI.
++#[test]
++#[cfg(not(any(target_os = "ios", target_os = "macos")))]
++#[cfg_attr(any(target_arch = "mips", target_arch = "mips64", target_env = "musl"), ignore)]
++fn test_liocb_listio_signal() {
++ let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
++ const INITIAL: &[u8] = b"abcdef123456";
++ const WBUF: &[u8] = b"CDEF";
++ let mut rbuf = vec![0; 4];
++ let rlen = rbuf.len();
++ let mut rbuf2 = Vec::new();
++ const EXPECT: &[u8] = b"abCDEF123456";
++ let mut f = tempfile().unwrap();
++ let sa = SigAction::new(SigHandler::Handler(sigfunc),
++ SaFlags::SA_RESETHAND,
++ SigSet::empty());
++ let sigev_notify = SigevNotify::SigevSignal { signal: Signal::SIGUSR2,
++ si_value: 0 };
++
++ f.write_all(INITIAL).unwrap();
++
++ {
++ let wcb = AioCb::from_slice( f.as_raw_fd(),
++ 2, //offset
++ WBUF,
++ 0, //priority
++ SigevNotify::SigevNone,
++ LioOpcode::LIO_WRITE);
++
++ let rcb = AioCb::from_mut_slice( f.as_raw_fd(),
++ 8, //offset
++ &mut rbuf,
++ 0, //priority
++ SigevNotify::SigevNone,
++ LioOpcode::LIO_READ);
++ let mut liocb = LioCb::with_capacity(2);
++ liocb.aiocbs.push(wcb);
++ liocb.aiocbs.push(rcb);
++ SIGNALED.store(false, Ordering::Relaxed);
++ unsafe { sigaction(Signal::SIGUSR2, &sa) }.unwrap();
++ let err = liocb.listio(LioMode::LIO_NOWAIT, sigev_notify);
++ err.expect("lio_listio");
++ while !SIGNALED.load(Ordering::Relaxed) {
++ thread::sleep(time::Duration::from_millis(10));
++ }
++
++ assert!(liocb.aiocbs[0].aio_return().unwrap() as usize == WBUF.len());
++ assert!(liocb.aiocbs[1].aio_return().unwrap() as usize == rlen);
++ }
++ assert!(rbuf.deref().deref() == b"3456");
++
++ f.seek(SeekFrom::Start(0)).unwrap();
++ let len = f.read_to_end(&mut rbuf2).unwrap();
++ assert!(len == EXPECT.len());
++ assert!(rbuf2 == EXPECT);
++}
++
++// Try to use LioCb::listio to read into an immutable buffer. It should fail
++// FIXME: This test fails to panic on Linux/musl
++#[test]
++#[cfg(not(any(target_os = "ios", target_os = "macos")))]
++#[should_panic(expected = "Can't read into an immutable buffer")]
++#[cfg_attr(target_env = "musl", ignore)]
++fn test_liocb_listio_read_immutable() {
++ let rbuf: &[u8] = b"abcd";
++ let f = tempfile().unwrap();
++
++
++ let mut liocb = LioCb::from(vec![
++ AioCb::from_slice( f.as_raw_fd(),
++ 2, //offset
++ rbuf,
++ 0, //priority
++ SigevNotify::SigevNone,
++ LioOpcode::LIO_READ)
++ ]);
++ let _ = liocb.listio(LioMode::LIO_NOWAIT, SigevNotify::SigevNone);
++}
+diff --git a/third_party/rust/nix-0.15.0/test/sys/test_aio_drop.rs b/third_party/rust/nix-0.15.0/test/sys/test_aio_drop.rs
+new file mode 100644
+index 0000000000000..492da401ef726
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/sys/test_aio_drop.rs
+@@ -0,0 +1,32 @@
++extern crate nix;
++extern crate tempfile;
++
++// Test dropping an AioCb that hasn't yet finished.
++// This must happen in its own process, because on OSX this test seems to hose
++// the AIO subsystem and causes subsequent tests to fail
++#[test]
++#[should_panic(expected = "Dropped an in-progress AioCb")]
++#[cfg(all(not(target_env = "musl"),
++ any(target_os = "linux",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "freebsd",
++ target_os = "netbsd")))]
++fn test_drop() {
++ use nix::sys::aio::*;
++ use nix::sys::signal::*;
++ use std::os::unix::io::AsRawFd;
++ use tempfile::tempfile;
++
++ const WBUF: &[u8] = b"CDEF";
++
++ let f = tempfile().unwrap();
++ f.set_len(6).unwrap();
++ let mut aiocb = AioCb::from_slice( f.as_raw_fd(),
++ 2, //offset
++ WBUF,
++ 0, //priority
++ SigevNotify::SigevNone,
++ LioOpcode::LIO_NOP);
++ aiocb.write().unwrap();
++}
+diff --git a/third_party/rust/nix-0.15.0/test/sys/test_epoll.rs b/third_party/rust/nix-0.15.0/test/sys/test_epoll.rs
+new file mode 100644
+index 0000000000000..e0dc5131defe0
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/sys/test_epoll.rs
+@@ -0,0 +1,24 @@
++use nix::sys::epoll::{EpollCreateFlags, EpollFlags, EpollOp, EpollEvent};
++use nix::sys::epoll::{epoll_create1, epoll_ctl};
++use nix::Error;
++use nix::errno::Errno;
++
++#[test]
++pub fn test_epoll_errno() {
++ let efd = epoll_create1(EpollCreateFlags::empty()).unwrap();
++ let result = epoll_ctl(efd, EpollOp::EpollCtlDel, 1, None);
++ assert!(result.is_err());
++ assert_eq!(result.unwrap_err(), Error::Sys(Errno::ENOENT));
++
++ let result = epoll_ctl(efd, EpollOp::EpollCtlAdd, 1, None);
++ assert!(result.is_err());
++ assert_eq!(result.unwrap_err(), Error::Sys(Errno::EINVAL));
++}
++
++#[test]
++pub fn test_epoll_ctl() {
++ let efd = epoll_create1(EpollCreateFlags::empty()).unwrap();
++ let mut event = EpollEvent::new(EpollFlags::EPOLLIN | EpollFlags::EPOLLERR, 1);
++ epoll_ctl(efd, EpollOp::EpollCtlAdd, 1, &mut event).unwrap();
++ epoll_ctl(efd, EpollOp::EpollCtlDel, 1, None).unwrap();
++}
+diff --git a/third_party/rust/nix-0.15.0/test/sys/test_inotify.rs b/third_party/rust/nix-0.15.0/test/sys/test_inotify.rs
+new file mode 100644
+index 0000000000000..a8ead46d487ba
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/sys/test_inotify.rs
+@@ -0,0 +1,65 @@
++use nix::sys::inotify::{AddWatchFlags,InitFlags,Inotify};
++use nix::Error;
++use nix::errno::Errno;
++use tempfile;
++use std::ffi::OsString;
++use std::fs::{rename, File};
++
++#[test]
++pub fn test_inotify() {
++ let instance = Inotify::init(InitFlags::IN_NONBLOCK)
++ .unwrap();
++ let tempdir = tempfile::tempdir().unwrap();
++
++ instance.add_watch(tempdir.path(), AddWatchFlags::IN_ALL_EVENTS).unwrap();
++
++ let events = instance.read_events();
++ assert_eq!(events.unwrap_err(), Error::Sys(Errno::EAGAIN));
++
++ File::create(tempdir.path().join("test")).unwrap();
++
++ let events = instance.read_events().unwrap();
++ assert_eq!(events[0].name, Some(OsString::from("test")));
++}
++
++#[test]
++pub fn test_inotify_multi_events() {
++ let instance = Inotify::init(InitFlags::IN_NONBLOCK)
++ .unwrap();
++ let tempdir = tempfile::tempdir().unwrap();
++
++ instance.add_watch(tempdir.path(), AddWatchFlags::IN_ALL_EVENTS).unwrap();
++
++ let events = instance.read_events();
++ assert_eq!(events.unwrap_err(), Error::Sys(Errno::EAGAIN));
++
++ File::create(tempdir.path().join("test")).unwrap();
++ rename(tempdir.path().join("test"), tempdir.path().join("test2")).unwrap();
++
++ // Now there should be 5 events in queue:
++ // - IN_CREATE on test
++ // - IN_OPEN on test
++ // - IN_CLOSE_WRITE on test
++ // - IN_MOVED_FROM on test with a cookie
++ // - IN_MOVED_TO on test2 with the same cookie
++
++ let events = instance.read_events().unwrap();
++ assert_eq!(events.len(), 5);
++
++ assert_eq!(events[0].mask, AddWatchFlags::IN_CREATE);
++ assert_eq!(events[0].name, Some(OsString::from("test")));
++
++ assert_eq!(events[1].mask, AddWatchFlags::IN_OPEN);
++ assert_eq!(events[1].name, Some(OsString::from("test")));
++
++ assert_eq!(events[2].mask, AddWatchFlags::IN_CLOSE_WRITE);
++ assert_eq!(events[2].name, Some(OsString::from("test")));
++
++ assert_eq!(events[3].mask, AddWatchFlags::IN_MOVED_FROM);
++ assert_eq!(events[3].name, Some(OsString::from("test")));
++
++ assert_eq!(events[4].mask, AddWatchFlags::IN_MOVED_TO);
++ assert_eq!(events[4].name, Some(OsString::from("test2")));
++
++ assert_eq!(events[3].cookie, events[4].cookie);
++}
+diff --git a/third_party/rust/nix-0.15.0/test/sys/test_ioctl.rs b/third_party/rust/nix-0.15.0/test/sys/test_ioctl.rs
+new file mode 100644
+index 0000000000000..0a439b3346f53
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/sys/test_ioctl.rs
+@@ -0,0 +1,334 @@
++#![allow(dead_code)]
++
++// Simple tests to ensure macro generated fns compile
++ioctl_none_bad!(do_bad, 0x1234);
++ioctl_read_bad!(do_bad_read, 0x1234, u16);
++ioctl_write_int_bad!(do_bad_write_int, 0x1234);
++ioctl_write_ptr_bad!(do_bad_write_ptr, 0x1234, u8);
++ioctl_readwrite_bad!(do_bad_readwrite, 0x1234, u32);
++ioctl_none!(do_none, 0, 0);
++ioctl_read!(read_test, 0, 0, u32);
++ioctl_write_int!(write_ptr_int, 0, 0);
++ioctl_write_ptr!(write_ptr_u8, 0, 0, u8);
++ioctl_write_ptr!(write_ptr_u32, 0, 0, u32);
++ioctl_write_ptr!(write_ptr_u64, 0, 0, u64);
++ioctl_readwrite!(readwrite_test, 0, 0, u64);
++ioctl_read_buf!(readbuf_test, 0, 0, u32);
++const SPI_IOC_MAGIC: u8 = b'k';
++const SPI_IOC_MESSAGE: u8 = 0;
++ioctl_write_buf!(writebuf_test_consts, SPI_IOC_MAGIC, SPI_IOC_MESSAGE, u8);
++ioctl_write_buf!(writebuf_test_u8, 0, 0, u8);
++ioctl_write_buf!(writebuf_test_u32, 0, 0, u32);
++ioctl_write_buf!(writebuf_test_u64, 0, 0, u64);
++ioctl_readwrite_buf!(readwritebuf_test, 0, 0, u32);
++
++// See C code for source of values for op calculations (does NOT work for mips/powerpc):
++// https://gist.github.com/posborne/83ea6880770a1aef332e
++//
++// TODO: Need a way to compute these constants at test time. Using precomputed
++// values is fragile and needs to be maintained.
++
++#[cfg(any(target_os = "linux", target_os = "android"))]
++mod linux {
++ #[test]
++ fn test_op_none() {
++ if cfg!(any(target_arch = "mips", target_arch = "mips64", target_arch="powerpc", target_arch="powerpc64")){
++ assert_eq!(request_code_none!(b'q', 10), 0x2000_710A);
++ assert_eq!(request_code_none!(b'a', 255), 0x2000_61FF);
++ } else {
++ assert_eq!(request_code_none!(b'q', 10), 0x0000_710A);
++ assert_eq!(request_code_none!(b'a', 255), 0x0000_61FF);
++ }
++ }
++
++ #[test]
++ fn test_op_write() {
++ if cfg!(any(target_arch = "mips", target_arch = "mips64", target_arch="powerpc", target_arch="powerpc64")){
++ assert_eq!(request_code_write!(b'z', 10, 1), 0x8001_7A0A);
++ assert_eq!(request_code_write!(b'z', 10, 512), 0x8200_7A0A);
++ } else {
++ assert_eq!(request_code_write!(b'z', 10, 1), 0x4001_7A0A);
++ assert_eq!(request_code_write!(b'z', 10, 512), 0x4200_7A0A);
++ }
++ }
++
++ #[cfg(target_pointer_width = "64")]
++ #[test]
++ fn test_op_write_64() {
++ if cfg!(any(target_arch = "mips64", target_arch="powerpc64")){
++ assert_eq!(request_code_write!(b'z', 10, (1 as u64) << 32), 0x8000_7A0A);
++ } else {
++ assert_eq!(request_code_write!(b'z', 10, (1 as u64) << 32), 0x4000_7A0A);
++ }
++
++ }
++
++ #[test]
++ fn test_op_read() {
++ if cfg!(any(target_arch = "mips", target_arch = "mips64", target_arch="powerpc", target_arch="powerpc64")){
++ assert_eq!(request_code_read!(b'z', 10, 1), 0x4001_7A0A);
++ assert_eq!(request_code_read!(b'z', 10, 512), 0x4200_7A0A);
++ } else {
++ assert_eq!(request_code_read!(b'z', 10, 1), 0x8001_7A0A);
++ assert_eq!(request_code_read!(b'z', 10, 512), 0x8200_7A0A);
++ }
++ }
++
++ #[cfg(target_pointer_width = "64")]
++ #[test]
++ fn test_op_read_64() {
++ if cfg!(any(target_arch = "mips64", target_arch="powerpc64")){
++ assert_eq!(request_code_read!(b'z', 10, (1 as u64) << 32), 0x4000_7A0A);
++ } else {
++ assert_eq!(request_code_read!(b'z', 10, (1 as u64) << 32), 0x8000_7A0A);
++ }
++ }
++
++ #[test]
++ fn test_op_read_write() {
++ assert_eq!(request_code_readwrite!(b'z', 10, 1), 0xC001_7A0A);
++ assert_eq!(request_code_readwrite!(b'z', 10, 512), 0xC200_7A0A);
++ }
++
++ #[cfg(target_pointer_width = "64")]
++ #[test]
++ fn test_op_read_write_64() {
++ assert_eq!(request_code_readwrite!(b'z', 10, (1 as u64) << 32), 0xC000_7A0A);
++ }
++}
++
++#[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
++mod bsd {
++ #[test]
++ fn test_op_none() {
++ assert_eq!(request_code_none!(b'q', 10), 0x2000_710A);
++ assert_eq!(request_code_none!(b'a', 255), 0x2000_61FF);
++ }
++
++ #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
++ #[test]
++ fn test_op_write_int() {
++ assert_eq!(request_code_write_int!(b'v', 4), 0x2004_7604);
++ assert_eq!(request_code_write_int!(b'p', 2), 0x2004_7002);
++ }
++
++ #[test]
++ fn test_op_write() {
++ assert_eq!(request_code_write!(b'z', 10, 1), 0x8001_7A0A);
++ assert_eq!(request_code_write!(b'z', 10, 512), 0x8200_7A0A);
++ }
++
++ #[cfg(target_pointer_width = "64")]
++ #[test]
++ fn test_op_write_64() {
++ assert_eq!(request_code_write!(b'z', 10, (1 as u64) << 32), 0x8000_7A0A);
++ }
++
++ #[test]
++ fn test_op_read() {
++ assert_eq!(request_code_read!(b'z', 10, 1), 0x4001_7A0A);
++ assert_eq!(request_code_read!(b'z', 10, 512), 0x4200_7A0A);
++ }
++
++ #[cfg(target_pointer_width = "64")]
++ #[test]
++ fn test_op_read_64() {
++ assert_eq!(request_code_read!(b'z', 10, (1 as u64) << 32), 0x4000_7A0A);
++ }
++
++ #[test]
++ fn test_op_read_write() {
++ assert_eq!(request_code_readwrite!(b'z', 10, 1), 0xC001_7A0A);
++ assert_eq!(request_code_readwrite!(b'z', 10, 512), 0xC200_7A0A);
++ }
++
++ #[cfg(target_pointer_width = "64")]
++ #[test]
++ fn test_op_read_write_64() {
++ assert_eq!(request_code_readwrite!(b'z', 10, (1 as u64) << 32), 0xC000_7A0A);
++ }
++}
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++mod linux_ioctls {
++ use std::mem;
++ use std::os::unix::io::AsRawFd;
++
++ use tempfile::tempfile;
++ use libc::{TCGETS, TCSBRK, TCSETS, TIOCNXCL, termios};
++
++ use nix::Error::Sys;
++ use nix::errno::Errno::{ENOTTY, ENOSYS};
++
++ ioctl_none_bad!(tiocnxcl, TIOCNXCL);
++ #[test]
++ fn test_ioctl_none_bad() {
++ let file = tempfile().unwrap();
++ let res = unsafe { tiocnxcl(file.as_raw_fd()) };
++ assert_eq!(res, Err(Sys(ENOTTY)));
++ }
++
++ ioctl_read_bad!(tcgets, TCGETS, termios);
++ #[test]
++ fn test_ioctl_read_bad() {
++ let file = tempfile().unwrap();
++ let mut termios = unsafe { mem::uninitialized() };
++ let res = unsafe { tcgets(file.as_raw_fd(), &mut termios) };
++ assert_eq!(res, Err(Sys(ENOTTY)));
++ }
++
++ ioctl_write_int_bad!(tcsbrk, TCSBRK);
++ #[test]
++ fn test_ioctl_write_int_bad() {
++ let file = tempfile().unwrap();
++ let res = unsafe { tcsbrk(file.as_raw_fd(), 0) };
++ assert_eq!(res, Err(Sys(ENOTTY)));
++ }
++
++ ioctl_write_ptr_bad!(tcsets, TCSETS, termios);
++ #[test]
++ fn test_ioctl_write_ptr_bad() {
++ let file = tempfile().unwrap();
++ let termios: termios = unsafe { mem::uninitialized() };
++ let res = unsafe { tcsets(file.as_raw_fd(), &termios) };
++ assert_eq!(res, Err(Sys(ENOTTY)));
++ }
++
++ // FIXME: Find a suitable example for `ioctl_readwrite_bad`
++
++ // From linux/videodev2.h
++ ioctl_none!(log_status, b'V', 70);
++ #[test]
++ fn test_ioctl_none() {
++ let file = tempfile().unwrap();
++ let res = unsafe { log_status(file.as_raw_fd()) };
++ assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
++ }
++
++ #[repr(C)]
++ pub struct v4l2_audio {
++ index: u32,
++ name: [u8; 32],
++ capability: u32,
++ mode: u32,
++ reserved: [u32; 2],
++ }
++
++ // From linux/videodev2.h
++ ioctl_write_ptr!(s_audio, b'V', 34, v4l2_audio);
++ #[test]
++ fn test_ioctl_write_ptr() {
++ let file = tempfile().unwrap();
++ let data: v4l2_audio = unsafe { mem::zeroed() };
++ let res = unsafe { s_audio(file.as_raw_fd(), &data) };
++ assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
++ }
++
++ // From linux/net/bluetooth/hci_sock.h
++ const HCI_IOC_MAGIC: u8 = b'H';
++ const HCI_IOC_HCIDEVUP: u8 = 201;
++ ioctl_write_int!(hcidevup, HCI_IOC_MAGIC, HCI_IOC_HCIDEVUP);
++ #[test]
++ fn test_ioctl_write_int() {
++ let file = tempfile().unwrap();
++ let res = unsafe { hcidevup(file.as_raw_fd(), 0) };
++ assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
++ }
++
++ // From linux/videodev2.h
++ ioctl_read!(g_audio, b'V', 33, v4l2_audio);
++ #[test]
++ fn test_ioctl_read() {
++ let file = tempfile().unwrap();
++ let mut data: v4l2_audio = unsafe { mem::uninitialized() };
++ let res = unsafe { g_audio(file.as_raw_fd(), &mut data) };
++ assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
++ }
++
++ // From linux/videodev2.h
++ ioctl_readwrite!(enum_audio, b'V', 65, v4l2_audio);
++ #[test]
++ fn test_ioctl_readwrite() {
++ let file = tempfile().unwrap();
++ let mut data: v4l2_audio = unsafe { mem::uninitialized() };
++ let res = unsafe { enum_audio(file.as_raw_fd(), &mut data) };
++ assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
++ }
++
++ // FIXME: Find a suitable example for `ioctl_read_buf`.
++
++ #[repr(C)]
++ pub struct spi_ioc_transfer {
++ tx_buf: u64,
++ rx_buf: u64,
++ len: u32,
++ speed_hz: u32,
++ delay_usecs: u16,
++ bits_per_word: u8,
++ cs_change: u8,
++ tx_nbits: u8,
++ rx_nbits: u8,
++ pad: u16,
++ }
++
++ // From linux/spi/spidev.h
++ ioctl_write_buf!(spi_ioc_message, super::SPI_IOC_MAGIC, super::SPI_IOC_MESSAGE, spi_ioc_transfer);
++ #[test]
++ fn test_ioctl_write_buf() {
++ let file = tempfile().unwrap();
++ let data: [spi_ioc_transfer; 4] = unsafe { mem::zeroed() };
++ let res = unsafe { spi_ioc_message(file.as_raw_fd(), &data[..]) };
++ assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
++ }
++
++ // FIXME: Find a suitable example for `ioctl_readwrite_buf`.
++}
++
++#[cfg(target_os = "freebsd")]
++mod freebsd_ioctls {
++ use std::mem;
++ use std::os::unix::io::AsRawFd;
++
++ use tempfile::tempfile;
++ use libc::termios;
++
++ use nix::Error::Sys;
++ use nix::errno::Errno::ENOTTY;
++
++ // From sys/sys/ttycom.h
++ const TTY_IOC_MAGIC: u8 = b't';
++ const TTY_IOC_TYPE_NXCL: u8 = 14;
++ const TTY_IOC_TYPE_GETA: u8 = 19;
++ const TTY_IOC_TYPE_SETA: u8 = 20;
++
++ ioctl_none!(tiocnxcl, TTY_IOC_MAGIC, TTY_IOC_TYPE_NXCL);
++ #[test]
++ fn test_ioctl_none() {
++ let file = tempfile().unwrap();
++ let res = unsafe { tiocnxcl(file.as_raw_fd()) };
++ assert_eq!(res, Err(Sys(ENOTTY)));
++ }
++
++ ioctl_read!(tiocgeta, TTY_IOC_MAGIC, TTY_IOC_TYPE_GETA, termios);
++ #[test]
++ fn test_ioctl_read() {
++ let file = tempfile().unwrap();
++ let mut termios = unsafe { mem::uninitialized() };
++ let res = unsafe { tiocgeta(file.as_raw_fd(), &mut termios) };
++ assert_eq!(res, Err(Sys(ENOTTY)));
++ }
++
++ ioctl_write_ptr!(tiocseta, TTY_IOC_MAGIC, TTY_IOC_TYPE_SETA, termios);
++ #[test]
++ fn test_ioctl_write_ptr() {
++ let file = tempfile().unwrap();
++ let termios: termios = unsafe { mem::uninitialized() };
++ let res = unsafe { tiocseta(file.as_raw_fd(), &termios) };
++ assert_eq!(res, Err(Sys(ENOTTY)));
++ }
++}
+diff --git a/third_party/rust/nix-0.15.0/test/sys/test_lio_listio_resubmit.rs b/third_party/rust/nix-0.15.0/test/sys/test_lio_listio_resubmit.rs
+new file mode 100644
+index 0000000000000..19ee3facf87d7
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/sys/test_lio_listio_resubmit.rs
+@@ -0,0 +1,111 @@
++// vim: tw=80
++
++// Annoyingly, Cargo is unable to conditionally build an entire test binary. So
++// we must disable the test here rather than in Cargo.toml
++#![cfg(target_os = "freebsd")]
++
++extern crate nix;
++extern crate sysctl;
++extern crate tempfile;
++
++use nix::Error;
++use nix::errno::*;
++use nix::libc::off_t;
++use nix::sys::aio::*;
++use nix::sys::signal::SigevNotify;
++use nix::unistd::{SysconfVar, sysconf};
++use std::os::unix::io::AsRawFd;
++use std::{thread, time};
++use sysctl::CtlValue;
++use tempfile::tempfile;
++
++const BYTES_PER_OP: usize = 512;
++
++/// Attempt to collect final status for all of `liocb`'s operations, freeing
++/// system resources
++fn finish_liocb(liocb: &mut LioCb) {
++ for j in 0..liocb.aiocbs.len() {
++ loop {
++ let e = liocb.error(j);
++ match e {
++ Ok(()) => break,
++ Err(Error::Sys(Errno::EINPROGRESS)) =>
++ thread::sleep(time::Duration::from_millis(10)),
++ Err(x) => panic!("aio_error({:?})", x)
++ }
++ }
++ assert_eq!(liocb.aio_return(j).unwrap(), BYTES_PER_OP as isize);
++ }
++}
++
++// Deliberately exceed system resource limits, causing lio_listio to return EIO.
++// This test must run in its own process since it deliberately uses all AIO
++// resources. ATM it is only enabled on FreeBSD, because I don't know how to
++// check system AIO limits on other operating systems.
++#[test]
++fn test_lio_listio_resubmit() {
++ let mut resubmit_count = 0;
++
++ // Lookup system resource limits
++ let alm = sysconf(SysconfVar::AIO_LISTIO_MAX)
++ .expect("sysconf").unwrap() as usize;
++ let maqpp = if let CtlValue::Int(x) = sysctl::value(
++ "vfs.aio.max_aio_queue_per_proc").unwrap(){
++ x as usize
++ } else {
++ panic!("unknown sysctl");
++ };
++
++ // Find lio_listio sizes that satisfy the AIO_LISTIO_MAX constraint and also
++ // result in a final lio_listio call that can only partially be queued
++ let target_ops = maqpp + alm / 2;
++ let num_listios = (target_ops + alm - 3) / (alm - 2);
++ let ops_per_listio = (target_ops + num_listios - 1) / num_listios;
++ assert!((num_listios - 1) * ops_per_listio < maqpp,
++ "the last lio_listio won't make any progress; fix the algorithm");
++ println!("Using {:?} LioCbs of {:?} operations apiece", num_listios,
++ ops_per_listio);
++
++ let f = tempfile().unwrap();
++ let buffer_set = (0..num_listios).map(|_| {
++ (0..ops_per_listio).map(|_| {
++ vec![0u8; BYTES_PER_OP]
++ }).collect::<Vec<_>>()
++ }).collect::<Vec<_>>();
++
++ let mut liocbs = (0..num_listios).map(|i| {
++ let mut liocb = LioCb::with_capacity(ops_per_listio);
++ for j in 0..ops_per_listio {
++ let offset = (BYTES_PER_OP * (i * ops_per_listio + j)) as off_t;
++ let wcb = AioCb::from_slice( f.as_raw_fd(),
++ offset,
++ &buffer_set[i][j][..],
++ 0, //priority
++ SigevNotify::SigevNone,
++ LioOpcode::LIO_WRITE);
++ liocb.aiocbs.push(wcb);
++ }
++ let mut err = liocb.listio(LioMode::LIO_NOWAIT, SigevNotify::SigevNone);
++ while err == Err(Error::Sys(Errno::EIO)) ||
++ err == Err(Error::Sys(Errno::EAGAIN)) ||
++ err == Err(Error::Sys(Errno::EINTR)) {
++ //
++ thread::sleep(time::Duration::from_millis(10));
++ resubmit_count += 1;
++ err = liocb.listio_resubmit(LioMode::LIO_NOWAIT,
++ SigevNotify::SigevNone);
++ }
++ liocb
++ }).collect::<Vec<_>>();
++
++ // Ensure that every AioCb completed
++ for liocb in liocbs.iter_mut() {
++ finish_liocb(liocb);
++ }
++
++ if resubmit_count > 0 {
++ println!("Resubmitted {:?} times, test passed", resubmit_count);
++ } else {
++ println!("Never resubmitted. Test ambiguous");
++ }
++}
+diff --git a/third_party/rust/nix-0.15.0/test/sys/test_pthread.rs b/third_party/rust/nix-0.15.0/test/sys/test_pthread.rs
+new file mode 100644
+index 0000000000000..8928010087a13
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/sys/test_pthread.rs
+@@ -0,0 +1,15 @@
++use nix::sys::pthread::*;
++
++#[cfg(target_env = "musl")]
++#[test]
++fn test_pthread_self() {
++ let tid = pthread_self();
++ assert!(tid != ::std::ptr::null_mut());
++}
++
++#[cfg(not(target_env = "musl"))]
++#[test]
++fn test_pthread_self() {
++ let tid = pthread_self();
++ assert!(tid != 0);
++}
+diff --git a/third_party/rust/nix-0.15.0/test/sys/test_ptrace.rs b/third_party/rust/nix-0.15.0/test/sys/test_ptrace.rs
+new file mode 100644
+index 0000000000000..24d9b522ee4e5
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/sys/test_ptrace.rs
+@@ -0,0 +1,107 @@
++use nix::Error;
++use nix::errno::Errno;
++use nix::unistd::getpid;
++use nix::sys::ptrace;
++#[cfg(any(target_os = "android", target_os = "linux"))]
++use nix::sys::ptrace::Options;
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++use std::mem;
++
++#[test]
++fn test_ptrace() {
++ // Just make sure ptrace can be called at all, for now.
++ // FIXME: qemu-user doesn't implement ptrace on all arches, so permit ENOSYS
++ let err = ptrace::attach(getpid()).unwrap_err();
++ assert!(err == Error::Sys(Errno::EPERM) || err == Error::Sys(Errno::EINVAL) ||
++ err == Error::Sys(Errno::ENOSYS));
++}
++
++// Just make sure ptrace_setoptions can be called at all, for now.
++#[test]
++#[cfg(any(target_os = "android", target_os = "linux"))]
++fn test_ptrace_setoptions() {
++ let err = ptrace::setoptions(getpid(), Options::PTRACE_O_TRACESYSGOOD).unwrap_err();
++ assert!(err != Error::UnsupportedOperation);
++}
++
++// Just make sure ptrace_getevent can be called at all, for now.
++#[test]
++#[cfg(any(target_os = "android", target_os = "linux"))]
++fn test_ptrace_getevent() {
++ let err = ptrace::getevent(getpid()).unwrap_err();
++ assert!(err != Error::UnsupportedOperation);
++}
++
++// Just make sure ptrace_getsiginfo can be called at all, for now.
++#[test]
++#[cfg(any(target_os = "android", target_os = "linux"))]
++fn test_ptrace_getsiginfo() {
++ if let Err(Error::UnsupportedOperation) = ptrace::getsiginfo(getpid()) {
++ panic!("ptrace_getsiginfo returns Error::UnsupportedOperation!");
++ }
++}
++
++// Just make sure ptrace_setsiginfo can be called at all, for now.
++#[test]
++#[cfg(any(target_os = "android", target_os = "linux"))]
++fn test_ptrace_setsiginfo() {
++ let siginfo = unsafe { mem::uninitialized() };
++ if let Err(Error::UnsupportedOperation) = ptrace::setsiginfo(getpid(), &siginfo) {
++ panic!("ptrace_setsiginfo returns Error::UnsupportedOperation!");
++ }
++}
++
++
++#[test]
++fn test_ptrace_cont() {
++ use nix::sys::ptrace;
++ use nix::sys::signal::{raise, Signal};
++ use nix::sys::wait::{waitpid, WaitPidFlag, WaitStatus};
++ use nix::unistd::fork;
++ use nix::unistd::ForkResult::*;
++
++ let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++
++ // FIXME: qemu-user doesn't implement ptrace on all architectures
++ // and retunrs ENOSYS in this case.
++ // We (ab)use this behavior to detect the affected platforms
++ // and skip the test then.
++ // On valid platforms the ptrace call should return Errno::EPERM, this
++ // is already tested by `test_ptrace`.
++ let err = ptrace::attach(getpid()).unwrap_err();
++ if err == Error::Sys(Errno::ENOSYS) {
++ return;
++ }
++
++ match fork().expect("Error: Fork Failed") {
++ Child => {
++ ptrace::traceme().unwrap();
++ // As recommended by ptrace(2), raise SIGTRAP to pause the child
++ // until the parent is ready to continue
++ loop {
++ raise(Signal::SIGTRAP).unwrap();
++ }
++
++ },
++ Parent { child } => {
++ assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGTRAP)));
++ ptrace::cont(child, None).unwrap();
++ assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGTRAP)));
++ ptrace::cont(child, Some(Signal::SIGKILL)).unwrap();
++ match waitpid(child, None) {
++ Ok(WaitStatus::Signaled(pid, Signal::SIGKILL, _)) if pid == child => {
++ // FIXME It's been observed on some systems (apple) the
++ // tracee may not be killed but remain as a zombie process
++ // affecting other wait based tests. Add an extra kill just
++ // to make sure there are no zombies.
++ let _ = waitpid(child, Some(WaitPidFlag::WNOHANG));
++ while ptrace::cont(child, Some(Signal::SIGKILL)).is_ok() {
++ let _ = waitpid(child, Some(WaitPidFlag::WNOHANG));
++ }
++ }
++ _ => panic!("The process should have been killed"),
++ }
++ },
++ }
++}
+diff --git a/third_party/rust/nix-0.15.0/test/sys/test_select.rs b/third_party/rust/nix-0.15.0/test/sys/test_select.rs
+new file mode 100644
+index 0000000000000..cf68700c5e16f
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/sys/test_select.rs
+@@ -0,0 +1,54 @@
++use nix::sys::select::*;
++use nix::unistd::{pipe, write};
++use nix::sys::signal::SigSet;
++use nix::sys::time::{TimeSpec, TimeValLike};
++
++#[test]
++pub fn test_pselect() {
++ let _mtx = ::SIGNAL_MTX
++ .lock()
++ .expect("Mutex got poisoned by another test");
++
++ let (r1, w1) = pipe().unwrap();
++ write(w1, b"hi!").unwrap();
++ let (r2, _w2) = pipe().unwrap();
++
++ let mut fd_set = FdSet::new();
++ fd_set.insert(r1);
++ fd_set.insert(r2);
++
++ let timeout = TimeSpec::seconds(10);
++ let sigmask = SigSet::empty();
++ assert_eq!(
++ 1,
++ pselect(None, &mut fd_set, None, None, &timeout, &sigmask).unwrap()
++ );
++ assert!(fd_set.contains(r1));
++ assert!(!fd_set.contains(r2));
++}
++
++#[test]
++pub fn test_pselect_nfds2() {
++ let (r1, w1) = pipe().unwrap();
++ write(w1, b"hi!").unwrap();
++ let (r2, _w2) = pipe().unwrap();
++
++ let mut fd_set = FdSet::new();
++ fd_set.insert(r1);
++ fd_set.insert(r2);
++
++ let timeout = TimeSpec::seconds(10);
++ assert_eq!(
++ 1,
++ pselect(
++ ::std::cmp::max(r1, r2) + 1,
++ &mut fd_set,
++ None,
++ None,
++ &timeout,
++ None
++ ).unwrap()
++ );
++ assert!(fd_set.contains(r1));
++ assert!(!fd_set.contains(r2));
++}
+diff --git a/third_party/rust/nix-0.15.0/test/sys/test_signal.rs b/third_party/rust/nix-0.15.0/test/sys/test_signal.rs
+new file mode 100644
+index 0000000000000..8780763f773ef
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/sys/test_signal.rs
+@@ -0,0 +1,104 @@
++use libc;
++use nix::Error;
++use nix::sys::signal::*;
++use nix::unistd::*;
++use std::sync::atomic::{AtomicBool, Ordering};
++
++#[test]
++fn test_kill_none() {
++ kill(getpid(), None).expect("Should be able to send signal to myself.");
++}
++
++#[test]
++fn test_killpg_none() {
++ killpg(getpgrp(), None)
++ .expect("Should be able to send signal to my process group.");
++}
++
++#[test]
++fn test_old_sigaction_flags() {
++ extern "C" fn handler(_: ::libc::c_int) {}
++ let act = SigAction::new(
++ SigHandler::Handler(handler),
++ SaFlags::empty(),
++ SigSet::empty(),
++ );
++ let oact = unsafe { sigaction(SIGINT, &act) }.unwrap();
++ let _flags = oact.flags();
++ let oact = unsafe { sigaction(SIGINT, &act) }.unwrap();
++ let _flags = oact.flags();
++}
++
++#[test]
++fn test_sigprocmask_noop() {
++ sigprocmask(SigmaskHow::SIG_BLOCK, None, None)
++ .expect("this should be an effective noop");
++}
++
++#[test]
++fn test_sigprocmask() {
++ let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
++
++ // This needs to be a signal that rust doesn't use in the test harness.
++ const SIGNAL: Signal = Signal::SIGCHLD;
++
++ let mut old_signal_set = SigSet::empty();
++ sigprocmask(SigmaskHow::SIG_BLOCK, None, Some(&mut old_signal_set))
++ .expect("expect to be able to retrieve old signals");
++
++ // Make sure the old set doesn't contain the signal, otherwise the following
++ // test don't make sense.
++ assert_eq!(old_signal_set.contains(SIGNAL), false,
++ "the {:?} signal is already blocked, please change to a \
++ different one", SIGNAL);
++
++ // Now block the signal.
++ let mut signal_set = SigSet::empty();
++ signal_set.add(SIGNAL);
++ sigprocmask(SigmaskHow::SIG_BLOCK, Some(&signal_set), None)
++ .expect("expect to be able to block signals");
++
++ // And test it again, to make sure the change was effective.
++ old_signal_set.clear();
++ sigprocmask(SigmaskHow::SIG_BLOCK, None, Some(&mut old_signal_set))
++ .expect("expect to be able to retrieve old signals");
++ assert_eq!(old_signal_set.contains(SIGNAL), true,
++ "expected the {:?} to be blocked", SIGNAL);
++
++ // Reset the signal.
++ sigprocmask(SigmaskHow::SIG_UNBLOCK, Some(&signal_set), None)
++ .expect("expect to be able to block signals");
++}
++
++lazy_static! {
++ static ref SIGNALED: AtomicBool = AtomicBool::new(false);
++}
++
++extern fn test_sigaction_handler(signal: libc::c_int) {
++ let signal = Signal::from_c_int(signal).unwrap();
++ SIGNALED.store(signal == Signal::SIGINT, Ordering::Relaxed);
++}
++
++extern fn test_sigaction_action(_: libc::c_int, _: *mut libc::siginfo_t, _: *mut libc::c_void) {
++}
++
++#[test]
++fn test_signal() {
++ let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
++
++ unsafe { signal(Signal::SIGINT, SigHandler::SigIgn) }.unwrap();
++ raise(Signal::SIGINT).unwrap();
++ assert_eq!(unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(), SigHandler::SigIgn);
++
++ let handler = SigHandler::Handler(test_sigaction_handler);
++ assert_eq!(unsafe { signal(Signal::SIGINT, handler) }.unwrap(), SigHandler::SigDfl);
++ raise(Signal::SIGINT).unwrap();
++ assert!(SIGNALED.load(Ordering::Relaxed));
++ assert_eq!(unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(), handler);
++
++ let action_handler = SigHandler::SigAction(test_sigaction_action);
++ assert_eq!(unsafe { signal(Signal::SIGINT, action_handler) }.unwrap_err(), Error::UnsupportedOperation);
++
++ // Restore default signal handler
++ unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap();
++}
+diff --git a/third_party/rust/nix-0.15.0/test/sys/test_signalfd.rs b/third_party/rust/nix-0.15.0/test/sys/test_signalfd.rs
+new file mode 100644
+index 0000000000000..a3b6098841f1c
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/sys/test_signalfd.rs
+@@ -0,0 +1,25 @@
++#[test]
++fn test_signalfd() {
++ use nix::sys::signalfd::SignalFd;
++ use nix::sys::signal::{self, raise, Signal, SigSet};
++
++ // Grab the mutex for altering signals so we don't interfere with other tests.
++ let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
++
++ // Block the SIGUSR1 signal from automatic processing for this thread
++ let mut mask = SigSet::empty();
++ mask.add(signal::SIGUSR1);
++ mask.thread_block().unwrap();
++
++ let mut fd = SignalFd::new(&mask).unwrap();
++
++ // Send a SIGUSR1 signal to the current process. Note that this uses `raise` instead of `kill`
++ // because `kill` with `getpid` isn't correct during multi-threaded execution like during a
++ // cargo test session. Instead use `raise` which does the correct thing by default.
++ raise(signal::SIGUSR1).expect("Error: raise(SIGUSR1) failed");
++
++ // And now catch that same signal.
++ let res = fd.read_signal().unwrap().unwrap();
++ let signo = Signal::from_c_int(res.ssi_signo as i32).unwrap();
++ assert_eq!(signo, signal::SIGUSR1);
++}
+diff --git a/third_party/rust/nix-0.15.0/test/sys/test_socket.rs b/third_party/rust/nix-0.15.0/test/sys/test_socket.rs
+new file mode 100644
+index 0000000000000..7e64d2b77f071
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/sys/test_socket.rs
+@@ -0,0 +1,1066 @@
++use nix::ifaddrs::InterfaceAddress;
++use nix::sys::socket::{AddressFamily, InetAddr, UnixAddr, getsockname};
++use std::collections::hash_map::DefaultHasher;
++use std::hash::{Hash, Hasher};
++use std::net::{self, Ipv6Addr, SocketAddr, SocketAddrV6};
++use std::os::unix::io::RawFd;
++use std::path::Path;
++use std::slice;
++use std::str::FromStr;
++use libc::c_char;
++use tempfile;
++
++#[test]
++pub fn test_inetv4_addr_to_sock_addr() {
++ let actual: net::SocketAddr = FromStr::from_str("127.0.0.1:3000").unwrap();
++ let addr = InetAddr::from_std(&actual);
++
++ match addr {
++ InetAddr::V4(addr) => {
++ let ip: u32 = 0x7f00_0001;
++ let port: u16 = 3000;
++ let saddr = addr.sin_addr.s_addr;
++
++ assert_eq!(saddr, ip.to_be());
++ assert_eq!(addr.sin_port, port.to_be());
++ }
++ _ => panic!("nope"),
++ }
++
++ assert_eq!(addr.to_str(), "127.0.0.1:3000");
++
++ let inet = addr.to_std();
++ assert_eq!(actual, inet);
++}
++
++#[test]
++pub fn test_inetv6_addr_to_sock_addr() {
++ let port: u16 = 3000;
++ let flowinfo: u32 = 1;
++ let scope_id: u32 = 2;
++ let ip: Ipv6Addr = "fe80::1".parse().unwrap();
++
++ let actual = SocketAddr::V6(SocketAddrV6::new(ip, port, flowinfo, scope_id));
++ let addr = InetAddr::from_std(&actual);
++
++ match addr {
++ InetAddr::V6(addr) => {
++ assert_eq!(addr.sin6_port, port.to_be());
++ assert_eq!(addr.sin6_flowinfo, flowinfo);
++ assert_eq!(addr.sin6_scope_id, scope_id);
++ }
++ _ => panic!("nope"),
++ }
++
++ assert_eq!(actual, addr.to_std());
++}
++
++#[test]
++pub fn test_path_to_sock_addr() {
++ let path = "/foo/bar";
++ let actual = Path::new(path);
++ let addr = UnixAddr::new(actual).unwrap();
++
++ let expect: &[c_char] = unsafe {
++ slice::from_raw_parts(path.as_bytes().as_ptr() as *const c_char, path.len())
++ };
++ assert_eq!(&addr.0.sun_path[..8], expect);
++
++ assert_eq!(addr.path(), Some(actual));
++}
++
++fn calculate_hash<T: Hash>(t: &T) -> u64 {
++ let mut s = DefaultHasher::new();
++ t.hash(&mut s);
++ s.finish()
++}
++
++#[test]
++pub fn test_addr_equality_path() {
++ let path = "/foo/bar";
++ let actual = Path::new(path);
++ let addr1 = UnixAddr::new(actual).unwrap();
++ let mut addr2 = addr1.clone();
++
++ addr2.0.sun_path[10] = 127;
++
++ assert_eq!(addr1, addr2);
++ assert_eq!(calculate_hash(&addr1), calculate_hash(&addr2));
++}
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++#[test]
++pub fn test_abstract_sun_path_too_long() {
++ let name = String::from("nix\0abstract\0tesnix\0abstract\0tesnix\0abstract\0tesnix\0abstract\0tesnix\0abstract\0testttttnix\0abstract\0test\0make\0sure\0this\0is\0long\0enough");
++ let addr = UnixAddr::new_abstract(name.as_bytes());
++ assert!(addr.is_err());
++}
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++#[test]
++pub fn test_addr_equality_abstract() {
++ let name = String::from("nix\0abstract\0test");
++ let addr1 = UnixAddr::new_abstract(name.as_bytes()).unwrap();
++ let mut addr2 = addr1.clone();
++
++ assert_eq!(addr1, addr2);
++ assert_eq!(calculate_hash(&addr1), calculate_hash(&addr2));
++
++ addr2.0.sun_path[18] = 127;
++ assert_ne!(addr1, addr2);
++ assert_ne!(calculate_hash(&addr1), calculate_hash(&addr2));
++}
++
++// Test getting/setting abstract addresses (without unix socket creation)
++#[cfg(target_os = "linux")]
++#[test]
++pub fn test_abstract_uds_addr() {
++ let empty = String::new();
++ let addr = UnixAddr::new_abstract(empty.as_bytes()).unwrap();
++ let sun_path = [0u8; 107];
++ assert_eq!(addr.as_abstract(), Some(&sun_path[..]));
++
++ let name = String::from("nix\0abstract\0test");
++ let addr = UnixAddr::new_abstract(name.as_bytes()).unwrap();
++ let sun_path = [
++ 110u8, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, 116, 101, 115, 116, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++ ];
++ assert_eq!(addr.as_abstract(), Some(&sun_path[..]));
++ assert_eq!(addr.path(), None);
++
++ // Internally, name is null-prefixed (abstract namespace)
++ assert_eq!(addr.0.sun_path[0], 0);
++}
++
++#[test]
++pub fn test_getsockname() {
++ use nix::sys::socket::{socket, AddressFamily, SockType, SockFlag};
++ use nix::sys::socket::{bind, SockAddr};
++
++ let tempdir = tempfile::tempdir().unwrap();
++ let sockname = tempdir.path().join("sock");
++ let sock = socket(AddressFamily::Unix, SockType::Stream, SockFlag::empty(), None)
++ .expect("socket failed");
++ let sockaddr = SockAddr::new_unix(&sockname).unwrap();
++ bind(sock, &sockaddr).expect("bind failed");
++ assert_eq!(sockaddr.to_str(),
++ getsockname(sock).expect("getsockname failed").to_str());
++}
++
++#[test]
++pub fn test_socketpair() {
++ use nix::unistd::{read, write};
++ use nix::sys::socket::{socketpair, AddressFamily, SockType, SockFlag};
++
++ let (fd1, fd2) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty())
++ .unwrap();
++ write(fd1, b"hello").unwrap();
++ let mut buf = [0;5];
++ read(fd2, &mut buf).unwrap();
++
++ assert_eq!(&buf[..], b"hello");
++}
++
++// Test error handling of our recvmsg wrapper
++#[test]
++pub fn test_recvmsg_ebadf() {
++ use nix::Error;
++ use nix::errno::Errno;
++ use nix::sys::socket::{MsgFlags, recvmsg};
++ use nix::sys::uio::IoVec;
++
++ let mut buf = [0u8; 5];
++ let iov = [IoVec::from_mut_slice(&mut buf[..])];
++ let fd = -1; // Bad file descriptor
++ let r = recvmsg(fd, &iov, None, MsgFlags::empty());
++ assert_eq!(r.err().unwrap(), Error::Sys(Errno::EBADF));
++}
++
++// Disable the test on emulated platforms due to a bug in QEMU versions <
++// 2.12.0. https://bugs.launchpad.net/qemu/+bug/1701808
++#[cfg_attr(not(any(target_arch = "x86_64", target_arch="i686")), ignore)]
++#[test]
++pub fn test_scm_rights() {
++ use nix::sys::uio::IoVec;
++ use nix::unistd::{pipe, read, write, close};
++ use nix::sys::socket::{socketpair, sendmsg, recvmsg,
++ AddressFamily, SockType, SockFlag,
++ ControlMessage, ControlMessageOwned, MsgFlags};
++
++ let (fd1, fd2) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty())
++ .unwrap();
++ let (r, w) = pipe().unwrap();
++ let mut received_r: Option<RawFd> = None;
++
++ {
++ let iov = [IoVec::from_slice(b"hello")];
++ let fds = [r];
++ let cmsg = ControlMessage::ScmRights(&fds);
++ assert_eq!(sendmsg(fd1, &iov, &[cmsg], MsgFlags::empty(), None).unwrap(), 5);
++ close(r).unwrap();
++ close(fd1).unwrap();
++ }
++
++ {
++ let mut buf = [0u8; 5];
++ let iov = [IoVec::from_mut_slice(&mut buf[..])];
++ let mut cmsgspace = cmsg_space!([RawFd; 1]);
++ let msg = recvmsg(fd2, &iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap();
++
++ for cmsg in msg.cmsgs() {
++ if let ControlMessageOwned::ScmRights(fd) = cmsg {
++ assert_eq!(received_r, None);
++ assert_eq!(fd.len(), 1);
++ received_r = Some(fd[0]);
++ } else {
++ panic!("unexpected cmsg");
++ }
++ }
++ assert_eq!(msg.bytes, 5);
++ assert!(!msg.flags.intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
++ close(fd2).unwrap();
++ }
++
++ let received_r = received_r.expect("Did not receive passed fd");
++ // Ensure that the received file descriptor works
++ write(w, b"world").unwrap();
++ let mut buf = [0u8; 5];
++ read(received_r, &mut buf).unwrap();
++ assert_eq!(&buf[..], b"world");
++ close(received_r).unwrap();
++ close(w).unwrap();
++}
++
++// Disable the test on emulated platforms due to not enabled support of AF_ALG in QEMU from rust cross
++#[cfg_attr(not(any(target_arch = "x86_64", target_arch = "i686")), ignore)]
++#[cfg(any(target_os = "linux", target_os= "android"))]
++#[test]
++pub fn test_af_alg_cipher() {
++ use libc;
++ use nix::sys::uio::IoVec;
++ use nix::unistd::read;
++ use nix::sys::socket::{socket, sendmsg, bind, accept, setsockopt,
++ AddressFamily, SockType, SockFlag, SockAddr,
++ ControlMessage, MsgFlags};
++ use nix::sys::socket::sockopt::AlgSetKey;
++
++ let alg_type = "skcipher";
++ let alg_name = "ctr(aes)";
++ // 256-bits secret key
++ let key = vec![0u8; 32];
++ // 16-bytes IV
++ let iv_len = 16;
++ let iv = vec![1u8; iv_len];
++ // 256-bytes plain payload
++ let payload_len = 256;
++ let payload = vec![2u8; payload_len];
++
++ let sock = socket(AddressFamily::Alg, SockType::SeqPacket, SockFlag::empty(), None)
++ .expect("socket failed");
++
++ let sockaddr = SockAddr::new_alg(alg_type, alg_name);
++ bind(sock, &sockaddr).expect("bind failed");
++
++ if let SockAddr::Alg(alg) = sockaddr {
++ assert_eq!(alg.alg_name().to_string_lossy(), alg_name);
++ assert_eq!(alg.alg_type().to_string_lossy(), alg_type);
++ } else {
++ panic!("unexpected SockAddr");
++ }
++
++ setsockopt(sock, AlgSetKey::default(), &key).expect("setsockopt");
++ let session_socket = accept(sock).expect("accept failed");
++
++ let msgs = [ControlMessage::AlgSetOp(&libc::ALG_OP_ENCRYPT), ControlMessage::AlgSetIv(iv.as_slice())];
++ let iov = IoVec::from_slice(&payload);
++ sendmsg(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg encrypt");
++
++ // allocate buffer for encrypted data
++ let mut encrypted = vec![0u8; payload_len];
++ let num_bytes = read(session_socket, &mut encrypted).expect("read encrypt");
++ assert_eq!(num_bytes, payload_len);
++
++ let iov = IoVec::from_slice(&encrypted);
++
++ let iv = vec![1u8; iv_len];
++
++ let msgs = [ControlMessage::AlgSetOp(&libc::ALG_OP_DECRYPT), ControlMessage::AlgSetIv(iv.as_slice())];
++ sendmsg(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg decrypt");
++
++ // allocate buffer for decrypted data
++ let mut decrypted = vec![0u8; payload_len];
++ let num_bytes = read(session_socket, &mut decrypted).expect("read decrypt");
++
++ assert_eq!(num_bytes, payload_len);
++ assert_eq!(decrypted, payload);
++}
++
++// Disable the test on emulated platforms due to not enabled support of AF_ALG in QEMU from rust cross
++#[cfg_attr(not(any(target_arch = "x86_64", target_arch = "i686")), ignore)]
++#[cfg(any(target_os = "linux", target_os= "android"))]
++#[test]
++pub fn test_af_alg_aead() {
++ use libc::{ALG_OP_DECRYPT, ALG_OP_ENCRYPT};
++ use nix::sys::uio::IoVec;
++ use nix::unistd::{read, close};
++ use nix::sys::socket::{socket, sendmsg, bind, accept, setsockopt,
++ AddressFamily, SockType, SockFlag, SockAddr,
++ ControlMessage, MsgFlags};
++ use nix::sys::socket::sockopt::{AlgSetKey, AlgSetAeadAuthSize};
++
++ let auth_size = 4usize;
++ let assoc_size = 16u32;
++
++ let alg_type = "aead";
++ let alg_name = "gcm(aes)";
++ // 256-bits secret key
++ let key = vec![0u8; 32];
++ // 12-bytes IV
++ let iv_len = 12;
++ let iv = vec![1u8; iv_len];
++ // 256-bytes plain payload
++ let payload_len = 256;
++ let mut payload = vec![2u8; payload_len + (assoc_size as usize) + auth_size];
++
++ for i in 0..assoc_size {
++ payload[i as usize] = 10;
++ }
++
++ let len = payload.len();
++
++ for i in 0..auth_size {
++ payload[len - 1 - i] = 0;
++ }
++
++ let sock = socket(AddressFamily::Alg, SockType::SeqPacket, SockFlag::empty(), None)
++ .expect("socket failed");
++
++ let sockaddr = SockAddr::new_alg(alg_type, alg_name);
++ bind(sock, &sockaddr).expect("bind failed");
++
++ setsockopt(sock, AlgSetAeadAuthSize, &auth_size).expect("setsockopt AlgSetAeadAuthSize");
++ setsockopt(sock, AlgSetKey::default(), &key).expect("setsockopt AlgSetKey");
++ let session_socket = accept(sock).expect("accept failed");
++
++ let msgs = [
++ ControlMessage::AlgSetOp(&ALG_OP_ENCRYPT),
++ ControlMessage::AlgSetIv(iv.as_slice()),
++ ControlMessage::AlgSetAeadAssoclen(&assoc_size)];
++ let iov = IoVec::from_slice(&payload);
++ sendmsg(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg encrypt");
++
++ // allocate buffer for encrypted data
++ let mut encrypted = vec![0u8; (assoc_size as usize) + payload_len + auth_size];
++ let num_bytes = read(session_socket, &mut encrypted).expect("read encrypt");
++ assert_eq!(num_bytes, payload_len + auth_size + (assoc_size as usize));
++ close(session_socket).expect("close");
++
++ for i in 0..assoc_size {
++ encrypted[i as usize] = 10;
++ }
++
++ let iov = IoVec::from_slice(&encrypted);
++
++ let iv = vec![1u8; iv_len];
++
++ let session_socket = accept(sock).expect("accept failed");
++
++ let msgs = [
++ ControlMessage::AlgSetOp(&ALG_OP_DECRYPT),
++ ControlMessage::AlgSetIv(iv.as_slice()),
++ ControlMessage::AlgSetAeadAssoclen(&assoc_size),
++ ];
++ sendmsg(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg decrypt");
++
++ // allocate buffer for decrypted data
++ let mut decrypted = vec![0u8; payload_len + (assoc_size as usize) + auth_size];
++ let num_bytes = read(session_socket, &mut decrypted).expect("read decrypt");
++
++ assert!(num_bytes >= payload_len + (assoc_size as usize));
++ assert_eq!(decrypted[(assoc_size as usize)..(payload_len + (assoc_size as usize))], payload[(assoc_size as usize)..payload_len + (assoc_size as usize)]);
++}
++
++/// Tests that passing multiple fds using a single `ControlMessage` works.
++// Disable the test on emulated platforms due to a bug in QEMU versions <
++// 2.12.0. https://bugs.launchpad.net/qemu/+bug/1701808
++#[cfg_attr(not(any(target_arch = "x86_64", target_arch="i686")), ignore)]
++#[test]
++fn test_scm_rights_single_cmsg_multiple_fds() {
++ use std::os::unix::net::UnixDatagram;
++ use std::os::unix::io::{RawFd, AsRawFd};
++ use std::thread;
++ use nix::sys::socket::{ControlMessage, ControlMessageOwned, MsgFlags,
++ sendmsg, recvmsg};
++ use nix::sys::uio::IoVec;
++ use libc;
++
++ let (send, receive) = UnixDatagram::pair().unwrap();
++ let thread = thread::spawn(move || {
++ let mut buf = [0u8; 8];
++ let iovec = [IoVec::from_mut_slice(&mut buf)];
++ let mut space = cmsg_space!([RawFd; 2]);
++ let msg = recvmsg(
++ receive.as_raw_fd(),
++ &iovec,
++ Some(&mut space),
++ MsgFlags::empty()
++ ).unwrap();
++ assert!(!msg.flags.intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
++
++ let mut cmsgs = msg.cmsgs();
++ match cmsgs.next() {
++ Some(ControlMessageOwned::ScmRights(fds)) => {
++ assert_eq!(fds.len(), 2,
++ "unexpected fd count (expected 2 fds, got {})",
++ fds.len());
++ },
++ _ => panic!(),
++ }
++ assert!(cmsgs.next().is_none(), "unexpected control msg");
++
++ assert_eq!(msg.bytes, 8);
++ assert_eq!(iovec[0].as_slice(), [1u8, 2, 3, 4, 5, 6, 7, 8]);
++ });
++
++ let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
++ let iov = [IoVec::from_slice(&slice)];
++ let fds = [libc::STDIN_FILENO, libc::STDOUT_FILENO]; // pass stdin and stdout
++ let cmsg = [ControlMessage::ScmRights(&fds)];
++ sendmsg(send.as_raw_fd(), &iov, &cmsg, MsgFlags::empty(), None).unwrap();
++ thread.join().unwrap();
++}
++
++// Verify `sendmsg` builds a valid `msghdr` when passing an empty
++// `cmsgs` argument. This should result in a msghdr with a nullptr
++// msg_control field and a msg_controllen of 0 when calling into the
++// raw `sendmsg`.
++#[test]
++pub fn test_sendmsg_empty_cmsgs() {
++ use nix::sys::uio::IoVec;
++ use nix::unistd::close;
++ use nix::sys::socket::{socketpair, sendmsg, recvmsg,
++ AddressFamily, SockType, SockFlag, MsgFlags};
++
++ let (fd1, fd2) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty())
++ .unwrap();
++
++ {
++ let iov = [IoVec::from_slice(b"hello")];
++ assert_eq!(sendmsg(fd1, &iov, &[], MsgFlags::empty(), None).unwrap(), 5);
++ close(fd1).unwrap();
++ }
++
++ {
++ let mut buf = [0u8; 5];
++ let iov = [IoVec::from_mut_slice(&mut buf[..])];
++ let mut cmsgspace = cmsg_space!([RawFd; 1]);
++ let msg = recvmsg(fd2, &iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap();
++
++ for _ in msg.cmsgs() {
++ panic!("unexpected cmsg");
++ }
++ assert!(!msg.flags.intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
++ assert_eq!(msg.bytes, 5);
++ close(fd2).unwrap();
++ }
++}
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++#[test]
++fn test_scm_credentials() {
++ use libc;
++ use nix::sys::uio::IoVec;
++ use nix::unistd::{close, getpid, getuid, getgid};
++ use nix::sys::socket::{socketpair, sendmsg, recvmsg, setsockopt,
++ AddressFamily, SockType, SockFlag,
++ ControlMessage, ControlMessageOwned, MsgFlags};
++ use nix::sys::socket::sockopt::PassCred;
++
++ let (send, recv) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty())
++ .unwrap();
++ setsockopt(recv, PassCred, &true).unwrap();
++
++ {
++ let iov = [IoVec::from_slice(b"hello")];
++ let cred = libc::ucred {
++ pid: getpid().as_raw(),
++ uid: getuid().as_raw(),
++ gid: getgid().as_raw(),
++ };
++ let cmsg = ControlMessage::ScmCredentials(&cred);
++ assert_eq!(sendmsg(send, &iov, &[cmsg], MsgFlags::empty(), None).unwrap(), 5);
++ close(send).unwrap();
++ }
++
++ {
++ let mut buf = [0u8; 5];
++ let iov = [IoVec::from_mut_slice(&mut buf[..])];
++ let mut cmsgspace = cmsg_space!(libc::ucred);
++ let msg = recvmsg(recv, &iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap();
++ let mut received_cred = None;
++
++ for cmsg in msg.cmsgs() {
++ if let ControlMessageOwned::ScmCredentials(cred) = cmsg {
++ assert!(received_cred.is_none());
++ assert_eq!(cred.pid, getpid().as_raw());
++ assert_eq!(cred.uid, getuid().as_raw());
++ assert_eq!(cred.gid, getgid().as_raw());
++ received_cred = Some(cred);
++ } else {
++ panic!("unexpected cmsg");
++ }
++ }
++ received_cred.expect("no creds received");
++ assert_eq!(msg.bytes, 5);
++ assert!(!msg.flags.intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
++ close(recv).unwrap();
++ }
++}
++
++/// Ensure that we can send `SCM_CREDENTIALS` and `SCM_RIGHTS` with a single
++/// `sendmsg` call.
++#[cfg(any(target_os = "android", target_os = "linux"))]
++// qemu's handling of multiple cmsgs is bugged, ignore tests on non-x86
++// see https://bugs.launchpad.net/qemu/+bug/1781280
++#[cfg_attr(not(any(target_arch = "x86_64", target_arch = "x86")), ignore)]
++#[test]
++fn test_scm_credentials_and_rights() {
++ use libc;
++
++ let space = cmsg_space!(libc::ucred, RawFd);
++ test_impl_scm_credentials_and_rights(space);
++}
++
++/// Ensure that passing a an oversized control message buffer to recvmsg
++/// still works.
++#[cfg(any(target_os = "android", target_os = "linux"))]
++// qemu's handling of multiple cmsgs is bugged, ignore tests on non-x86
++// see https://bugs.launchpad.net/qemu/+bug/1781280
++#[cfg_attr(not(any(target_arch = "x86_64", target_arch = "x86")), ignore)]
++#[test]
++fn test_too_large_cmsgspace() {
++ let space = vec![0u8; 1024];
++ test_impl_scm_credentials_and_rights(space);
++}
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) {
++ use libc::ucred;
++ use nix::sys::uio::IoVec;
++ use nix::unistd::{pipe, read, write, close, getpid, getuid, getgid};
++ use nix::sys::socket::{socketpair, sendmsg, recvmsg, setsockopt,
++ SockType, SockFlag,
++ ControlMessage, ControlMessageOwned, MsgFlags};
++ use nix::sys::socket::sockopt::PassCred;
++
++ let (send, recv) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty())
++ .unwrap();
++ setsockopt(recv, PassCred, &true).unwrap();
++
++ let (r, w) = pipe().unwrap();
++ let mut received_r: Option<RawFd> = None;
++
++ {
++ let iov = [IoVec::from_slice(b"hello")];
++ let cred = ucred {
++ pid: getpid().as_raw(),
++ uid: getuid().as_raw(),
++ gid: getgid().as_raw(),
++ };
++ let fds = [r];
++ let cmsgs = [
++ ControlMessage::ScmCredentials(&cred),
++ ControlMessage::ScmRights(&fds),
++ ];
++ assert_eq!(sendmsg(send, &iov, &cmsgs, MsgFlags::empty(), None).unwrap(), 5);
++ close(r).unwrap();
++ close(send).unwrap();
++ }
++
++ {
++ let mut buf = [0u8; 5];
++ let iov = [IoVec::from_mut_slice(&mut buf[..])];
++ let msg = recvmsg(recv, &iov, Some(&mut space), MsgFlags::empty()).unwrap();
++ let mut received_cred = None;
++
++ assert_eq!(msg.cmsgs().count(), 2, "expected 2 cmsgs");
++
++ for cmsg in msg.cmsgs() {
++ match cmsg {
++ ControlMessageOwned::ScmRights(fds) => {
++ assert_eq!(received_r, None, "already received fd");
++ assert_eq!(fds.len(), 1);
++ received_r = Some(fds[0]);
++ }
++ ControlMessageOwned::ScmCredentials(cred) => {
++ assert!(received_cred.is_none());
++ assert_eq!(cred.pid, getpid().as_raw());
++ assert_eq!(cred.uid, getuid().as_raw());
++ assert_eq!(cred.gid, getgid().as_raw());
++ received_cred = Some(cred);
++ }
++ _ => panic!("unexpected cmsg"),
++ }
++ }
++ received_cred.expect("no creds received");
++ assert_eq!(msg.bytes, 5);
++ assert!(!msg.flags.intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
++ close(recv).unwrap();
++ }
++
++ let received_r = received_r.expect("Did not receive passed fd");
++ // Ensure that the received file descriptor works
++ write(w, b"world").unwrap();
++ let mut buf = [0u8; 5];
++ read(received_r, &mut buf).unwrap();
++ assert_eq!(&buf[..], b"world");
++ close(received_r).unwrap();
++ close(w).unwrap();
++}
++
++// Test creating and using named unix domain sockets
++#[test]
++pub fn test_unixdomain() {
++ use nix::sys::socket::{SockType, SockFlag};
++ use nix::sys::socket::{bind, socket, connect, listen, accept, SockAddr};
++ use nix::unistd::{read, write, close};
++ use std::thread;
++
++ let tempdir = tempfile::tempdir().unwrap();
++ let sockname = tempdir.path().join("sock");
++ let s1 = socket(AddressFamily::Unix, SockType::Stream,
++ SockFlag::empty(), None).expect("socket failed");
++ let sockaddr = SockAddr::new_unix(&sockname).unwrap();
++ bind(s1, &sockaddr).expect("bind failed");
++ listen(s1, 10).expect("listen failed");
++
++ let thr = thread::spawn(move || {
++ let s2 = socket(AddressFamily::Unix, SockType::Stream, SockFlag::empty(), None)
++ .expect("socket failed");
++ connect(s2, &sockaddr).expect("connect failed");
++ write(s2, b"hello").expect("write failed");
++ close(s2).unwrap();
++ });
++
++ let s3 = accept(s1).expect("accept failed");
++
++ let mut buf = [0;5];
++ read(s3, &mut buf).unwrap();
++ close(s3).unwrap();
++ close(s1).unwrap();
++ thr.join().unwrap();
++
++ assert_eq!(&buf[..], b"hello");
++}
++
++// Test creating and using named system control sockets
++#[cfg(any(target_os = "macos", target_os = "ios"))]
++#[test]
++pub fn test_syscontrol() {
++ use nix::Error;
++ use nix::errno::Errno;
++ use nix::sys::socket::{socket, SockAddr, SockType, SockFlag, SockProtocol};
++
++ let fd = socket(AddressFamily::System, SockType::Datagram,
++ SockFlag::empty(), SockProtocol::KextControl)
++ .expect("socket failed");
++ let _sockaddr = SockAddr::new_sys_control(fd, "com.apple.net.utun_control", 0).expect("resolving sys_control name failed");
++ assert_eq!(SockAddr::new_sys_control(fd, "foo.bar.lol", 0).err(), Some(Error::Sys(Errno::ENOENT)));
++
++ // requires root privileges
++ // connect(fd, &sockaddr).expect("connect failed");
++}
++
++#[cfg(any(
++ target_os = "android",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd",
++))]
++fn loopback_address(family: AddressFamily) -> Option<InterfaceAddress> {
++ use std::io;
++ use std::io::Write;
++ use nix::ifaddrs::getifaddrs;
++ use nix::sys::socket::SockAddr;
++ use nix::net::if_::*;
++
++ let addrs = match getifaddrs() {
++ Ok(iter) => iter,
++ Err(e) => {
++ let stdioerr = io::stderr();
++ let mut handle = stdioerr.lock();
++ writeln!(handle, "getifaddrs: {:?}", e).unwrap();
++ return None;
++ },
++ };
++ // return first address matching family
++ for ifaddr in addrs {
++ if ifaddr.flags.contains(InterfaceFlags::IFF_LOOPBACK) {
++ match ifaddr.address {
++ Some(SockAddr::Inet(InetAddr::V4(..))) => {
++ match family {
++ AddressFamily::Inet => return Some(ifaddr),
++ _ => continue
++ }
++ },
++ Some(SockAddr::Inet(InetAddr::V6(..))) => {
++ match family {
++ AddressFamily::Inet6 => return Some(ifaddr),
++ _ => continue
++ }
++ },
++ _ => continue,
++ }
++ }
++ }
++ None
++}
++
++#[cfg(any(
++ target_os = "android",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos",
++ target_os = "netbsd",
++))]
++// qemu doesn't seem to be emulating this correctly in these architectures
++#[cfg_attr(any(
++ target_arch = "mips",
++ target_arch = "mips64",
++ target_arch = "powerpc64",
++), ignore)]
++#[test]
++pub fn test_recv_ipv4pktinfo() {
++ use libc;
++ use nix::sys::socket::sockopt::Ipv4PacketInfo;
++ use nix::sys::socket::{bind, SockFlag, SockType};
++ use nix::sys::socket::{getsockname, setsockopt, socket};
++ use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags};
++ use nix::sys::uio::IoVec;
++ use nix::net::if_::*;
++
++ let lo_ifaddr = loopback_address(AddressFamily::Inet);
++ let (lo_name, lo) = match lo_ifaddr {
++ Some(ifaddr) => (ifaddr.interface_name,
++ ifaddr.address.expect("Expect IPv4 address on interface")),
++ None => return,
++ };
++ let receive = socket(
++ AddressFamily::Inet,
++ SockType::Datagram,
++ SockFlag::empty(),
++ None,
++ ).expect("receive socket failed");
++ bind(receive, &lo).expect("bind failed");
++ let sa = getsockname(receive).expect("getsockname failed");
++ setsockopt(receive, Ipv4PacketInfo, &true).expect("setsockopt failed");
++
++ {
++ let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
++ let iov = [IoVec::from_slice(&slice)];
++
++ let send = socket(
++ AddressFamily::Inet,
++ SockType::Datagram,
++ SockFlag::empty(),
++ None,
++ ).expect("send socket failed");
++ sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa)).expect("sendmsg failed");
++ }
++
++ {
++ let mut buf = [0u8; 8];
++ let iovec = [IoVec::from_mut_slice(&mut buf)];
++ let mut space = cmsg_space!(libc::in_pktinfo);
++ let msg = recvmsg(
++ receive,
++ &iovec,
++ Some(&mut space),
++ MsgFlags::empty(),
++ ).expect("recvmsg failed");
++ assert!(
++ !msg.flags
++ .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)
++ );
++
++ let mut cmsgs = msg.cmsgs();
++ match cmsgs.next() {
++ Some(ControlMessageOwned::Ipv4PacketInfo(pktinfo)) => {
++ let i = if_nametoindex(lo_name.as_bytes()).expect("if_nametoindex");
++ assert_eq!(
++ pktinfo.ipi_ifindex as libc::c_uint,
++ i,
++ "unexpected ifindex (expected {}, got {})",
++ i,
++ pktinfo.ipi_ifindex
++ );
++ }
++ _ => (),
++ }
++ assert!(cmsgs.next().is_none(), "unexpected additional control msg");
++ assert_eq!(msg.bytes, 8);
++ assert_eq!(
++ iovec[0].as_slice(),
++ [1u8, 2, 3, 4, 5, 6, 7, 8]
++ );
++ }
++}
++
++#[cfg(any(
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd",
++))]
++// qemu doesn't seem to be emulating this correctly in these architectures
++#[cfg_attr(any(
++ target_arch = "mips",
++ target_arch = "mips64",
++ target_arch = "powerpc64",
++), ignore)]
++#[test]
++pub fn test_recvif() {
++ use libc;
++ use nix::net::if_::*;
++ use nix::sys::socket::sockopt::{Ipv4RecvIf, Ipv4RecvDstAddr};
++ use nix::sys::socket::{bind, SockFlag, SockType};
++ use nix::sys::socket::{getsockname, setsockopt, socket, SockAddr};
++ use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags};
++ use nix::sys::uio::IoVec;
++
++ let lo_ifaddr = loopback_address(AddressFamily::Inet);
++ let (lo_name, lo) = match lo_ifaddr {
++ Some(ifaddr) => (ifaddr.interface_name,
++ ifaddr.address.expect("Expect IPv4 address on interface")),
++ None => return,
++ };
++ let receive = socket(
++ AddressFamily::Inet,
++ SockType::Datagram,
++ SockFlag::empty(),
++ None,
++ ).expect("receive socket failed");
++ bind(receive, &lo).expect("bind failed");
++ let sa = getsockname(receive).expect("getsockname failed");
++ setsockopt(receive, Ipv4RecvIf, &true).expect("setsockopt IP_RECVIF failed");
++ setsockopt(receive, Ipv4RecvDstAddr, &true).expect("setsockopt IP_RECVDSTADDR failed");
++
++ {
++ let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
++ let iov = [IoVec::from_slice(&slice)];
++
++ let send = socket(
++ AddressFamily::Inet,
++ SockType::Datagram,
++ SockFlag::empty(),
++ None,
++ ).expect("send socket failed");
++ sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa)).expect("sendmsg failed");
++ }
++
++ {
++ let mut buf = [0u8; 8];
++ let iovec = [IoVec::from_mut_slice(&mut buf)];
++ let mut space = cmsg_space!(libc::sockaddr_dl, libc::in_addr);
++ let msg = recvmsg(
++ receive,
++ &iovec,
++ Some(&mut space),
++ MsgFlags::empty(),
++ ).expect("recvmsg failed");
++ assert!(
++ !msg.flags
++ .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)
++ );
++ assert_eq!(msg.cmsgs().count(), 2, "expected 2 cmsgs");
++
++ let mut rx_recvif = false;
++ let mut rx_recvdstaddr = false;
++ for cmsg in msg.cmsgs() {
++ match cmsg {
++ ControlMessageOwned::Ipv4RecvIf(dl) => {
++ rx_recvif = true;
++ let i = if_nametoindex(lo_name.as_bytes()).expect("if_nametoindex");
++ assert_eq!(
++ dl.sdl_index as libc::c_uint,
++ i,
++ "unexpected ifindex (expected {}, got {})",
++ i,
++ dl.sdl_index
++ );
++ },
++ ControlMessageOwned::Ipv4RecvDstAddr(addr) => {
++ rx_recvdstaddr = true;
++ if let SockAddr::Inet(InetAddr::V4(a)) = lo {
++ assert_eq!(a.sin_addr.s_addr,
++ addr.s_addr,
++ "unexpected destination address (expected {}, got {})",
++ a.sin_addr.s_addr,
++ addr.s_addr);
++ } else {
++ panic!("unexpected Sockaddr");
++ }
++ },
++ _ => panic!("unexpected additional control msg"),
++ }
++ }
++ assert_eq!(rx_recvif, true);
++ assert_eq!(rx_recvdstaddr, true);
++ assert_eq!(msg.bytes, 8);
++ assert_eq!(
++ iovec[0].as_slice(),
++ [1u8, 2, 3, 4, 5, 6, 7, 8]
++ );
++ }
++}
++
++#[cfg(any(
++ target_os = "android",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd",
++))]
++// qemu doesn't seem to be emulating this correctly in these architectures
++#[cfg_attr(any(
++ target_arch = "mips",
++ target_arch = "mips64",
++ target_arch = "powerpc64",
++), ignore)]
++#[test]
++pub fn test_recv_ipv6pktinfo() {
++ use libc;
++ use nix::net::if_::*;
++ use nix::sys::socket::sockopt::Ipv6RecvPacketInfo;
++ use nix::sys::socket::{bind, SockFlag, SockType};
++ use nix::sys::socket::{getsockname, setsockopt, socket};
++ use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags};
++ use nix::sys::uio::IoVec;
++
++ let lo_ifaddr = loopback_address(AddressFamily::Inet6);
++ let (lo_name, lo) = match lo_ifaddr {
++ Some(ifaddr) => (ifaddr.interface_name,
++ ifaddr.address.expect("Expect IPv4 address on interface")),
++ None => return,
++ };
++ let receive = socket(
++ AddressFamily::Inet6,
++ SockType::Datagram,
++ SockFlag::empty(),
++ None,
++ ).expect("receive socket failed");
++ bind(receive, &lo).expect("bind failed");
++ let sa = getsockname(receive).expect("getsockname failed");
++ setsockopt(receive, Ipv6RecvPacketInfo, &true).expect("setsockopt failed");
++
++ {
++ let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
++ let iov = [IoVec::from_slice(&slice)];
++
++ let send = socket(
++ AddressFamily::Inet6,
++ SockType::Datagram,
++ SockFlag::empty(),
++ None,
++ ).expect("send socket failed");
++ sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa)).expect("sendmsg failed");
++ }
++
++ {
++ let mut buf = [0u8; 8];
++ let iovec = [IoVec::from_mut_slice(&mut buf)];
++ let mut space = cmsg_space!(libc::in6_pktinfo);
++ let msg = recvmsg(
++ receive,
++ &iovec,
++ Some(&mut space),
++ MsgFlags::empty(),
++ ).expect("recvmsg failed");
++ assert!(
++ !msg.flags
++ .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)
++ );
++
++ let mut cmsgs = msg.cmsgs();
++ match cmsgs.next() {
++ Some(ControlMessageOwned::Ipv6PacketInfo(pktinfo)) => {
++ let i = if_nametoindex(lo_name.as_bytes()).expect("if_nametoindex");
++ assert_eq!(
++ pktinfo.ipi6_ifindex,
++ i,
++ "unexpected ifindex (expected {}, got {})",
++ i,
++ pktinfo.ipi6_ifindex
++ );
++ }
++ _ => (),
++ }
++ assert!(cmsgs.next().is_none(), "unexpected additional control msg");
++ assert_eq!(msg.bytes, 8);
++ assert_eq!(
++ iovec[0].as_slice(),
++ [1u8, 2, 3, 4, 5, 6, 7, 8]
++ );
++ }
++}
++
++#[cfg(target_os = "linux")]
++#[test]
++pub fn test_vsock() {
++ use libc;
++ use nix::Error;
++ use nix::errno::Errno;
++ use nix::sys::socket::{AddressFamily, socket, bind, connect, listen,
++ SockAddr, SockType, SockFlag};
++ use nix::unistd::{close};
++ use std::thread;
++
++ let port: u32 = 3000;
++
++ let s1 = socket(AddressFamily::Vsock, SockType::Stream,
++ SockFlag::empty(), None)
++ .expect("socket failed");
++
++ // VMADDR_CID_HYPERVISOR and VMADDR_CID_RESERVED are reserved, so we expect
++ // an EADDRNOTAVAIL error.
++ let sockaddr = SockAddr::new_vsock(libc::VMADDR_CID_HYPERVISOR, port);
++ assert_eq!(bind(s1, &sockaddr).err(),
++ Some(Error::Sys(Errno::EADDRNOTAVAIL)));
++
++ let sockaddr = SockAddr::new_vsock(libc::VMADDR_CID_RESERVED, port);
++ assert_eq!(bind(s1, &sockaddr).err(),
++ Some(Error::Sys(Errno::EADDRNOTAVAIL)));
++
++
++ let sockaddr = SockAddr::new_vsock(libc::VMADDR_CID_ANY, port);
++ assert_eq!(bind(s1, &sockaddr), Ok(()));
++ listen(s1, 10).expect("listen failed");
++
++ let thr = thread::spawn(move || {
++ let cid: u32 = libc::VMADDR_CID_HOST;
++
++ let s2 = socket(AddressFamily::Vsock, SockType::Stream,
++ SockFlag::empty(), None)
++ .expect("socket failed");
++
++ let sockaddr = SockAddr::new_vsock(cid, port);
++
++ // The current implementation does not support loopback devices, so,
++ // for now, we expect a failure on the connect.
++ assert_ne!(connect(s2, &sockaddr), Ok(()));
++
++ close(s2).unwrap();
++ });
++
++ close(s1).unwrap();
++ thr.join().unwrap();
++}
+diff --git a/third_party/rust/nix-0.15.0/test/sys/test_sockopt.rs b/third_party/rust/nix-0.15.0/test/sys/test_sockopt.rs
+new file mode 100644
+index 0000000000000..c4860c0d61d3d
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/sys/test_sockopt.rs
+@@ -0,0 +1,53 @@
++use rand::{thread_rng, Rng};
++use nix::sys::socket::{socket, sockopt, getsockopt, setsockopt, AddressFamily, SockType, SockFlag, SockProtocol};
++
++#[cfg(target_os = "linux")]
++#[test]
++fn is_so_mark_functional() {
++ use nix::sys::socket::sockopt;
++
++ require_capability!(CAP_NET_ADMIN);
++
++ let s = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap();
++ setsockopt(s, sockopt::Mark, &1337).unwrap();
++ let mark = getsockopt(s, sockopt::Mark).unwrap();
++ assert_eq!(mark, 1337);
++}
++
++#[test]
++fn test_so_buf() {
++ let fd = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), SockProtocol::Udp)
++ .unwrap();
++ let bufsize: usize = thread_rng().gen_range(4096, 131_072);
++ setsockopt(fd, sockopt::SndBuf, &bufsize).unwrap();
++ let actual = getsockopt(fd, sockopt::SndBuf).unwrap();
++ assert!(actual >= bufsize);
++ setsockopt(fd, sockopt::RcvBuf, &bufsize).unwrap();
++ let actual = getsockopt(fd, sockopt::RcvBuf).unwrap();
++ assert!(actual >= bufsize);
++}
++
++// The CI doesn't supported getsockopt and setsockopt on emulated processors.
++// It's beleived that a QEMU issue, the tests run ok on a fully emulated system.
++// Current CI just run the binary with QEMU but the Kernel remains the same as the host.
++// So the syscall doesn't work properly unless the kernel is also emulated.
++#[test]
++#[cfg(all(
++ any(target_arch = "x86", target_arch = "x86_64"),
++ any(target_os = "freebsd", target_os = "linux")
++))]
++fn test_tcp_congestion() {
++ use std::ffi::OsString;
++
++ let fd = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap();
++
++ let val = getsockopt(fd, sockopt::TcpCongestion).unwrap();
++ setsockopt(fd, sockopt::TcpCongestion, &val).unwrap();
++
++ setsockopt(fd, sockopt::TcpCongestion, &OsString::from("tcp_congestion_does_not_exist")).unwrap_err();
++
++ assert_eq!(
++ getsockopt(fd, sockopt::TcpCongestion).unwrap(),
++ val
++ );
++}
+diff --git a/third_party/rust/nix-0.15.0/test/sys/test_sysinfo.rs b/third_party/rust/nix-0.15.0/test/sys/test_sysinfo.rs
+new file mode 100644
+index 0000000000000..73e6586f6223e
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/sys/test_sysinfo.rs
+@@ -0,0 +1,18 @@
++use nix::sys::sysinfo::*;
++
++#[test]
++fn sysinfo_works() {
++ let info = sysinfo().unwrap();
++
++ let (l1, l5, l15) = info.load_average();
++ assert!(l1 >= 0.0);
++ assert!(l5 >= 0.0);
++ assert!(l15 >= 0.0);
++
++ info.uptime(); // just test Duration construction
++
++ assert!(info.swap_free() <= info.swap_total(),
++ "more swap available than installed (free: {}, total: {})",
++ info.swap_free(),
++ info.swap_total());
++}
+diff --git a/third_party/rust/nix-0.15.0/test/sys/test_termios.rs b/third_party/rust/nix-0.15.0/test/sys/test_termios.rs
+new file mode 100644
+index 0000000000000..a14b8ce1a23cb
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/sys/test_termios.rs
+@@ -0,0 +1,136 @@
++use std::os::unix::prelude::*;
++use tempfile::tempfile;
++
++use nix::{Error, fcntl};
++use nix::errno::Errno;
++use nix::pty::openpty;
++use nix::sys::termios::{self, LocalFlags, OutputFlags, Termios, tcgetattr};
++use nix::unistd::{read, write, close};
++
++/// Helper function analogous to `std::io::Write::write_all`, but for `RawFd`s
++fn write_all(f: RawFd, buf: &[u8]) {
++ let mut len = 0;
++ while len < buf.len() {
++ len += write(f, &buf[len..]).unwrap();
++ }
++}
++
++// Test tcgetattr on a terminal
++#[test]
++fn test_tcgetattr_pty() {
++ // openpty uses ptname(3) internally
++ let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++
++ let pty = openpty(None, None).expect("openpty failed");
++ assert!(termios::tcgetattr(pty.master).is_ok());
++ close(pty.master).expect("closing the master failed");
++ close(pty.slave).expect("closing the slave failed");
++}
++
++// Test tcgetattr on something that isn't a terminal
++#[test]
++fn test_tcgetattr_enotty() {
++ let file = tempfile().unwrap();
++ assert_eq!(termios::tcgetattr(file.as_raw_fd()).err(),
++ Some(Error::Sys(Errno::ENOTTY)));
++}
++
++// Test tcgetattr on an invalid file descriptor
++#[test]
++fn test_tcgetattr_ebadf() {
++ assert_eq!(termios::tcgetattr(-1).err(),
++ Some(Error::Sys(Errno::EBADF)));
++}
++
++// Test modifying output flags
++#[test]
++fn test_output_flags() {
++ // openpty uses ptname(3) internally
++ let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++
++ // Open one pty to get attributes for the second one
++ let mut termios = {
++ let pty = openpty(None, None).expect("openpty failed");
++ assert!(pty.master > 0);
++ assert!(pty.slave > 0);
++ let termios = tcgetattr(pty.master).expect("tcgetattr failed");
++ close(pty.master).unwrap();
++ close(pty.slave).unwrap();
++ termios
++ };
++
++ // Make sure postprocessing '\r' isn't specified by default or this test is useless.
++ assert!(!termios.output_flags.contains(OutputFlags::OPOST | OutputFlags::OCRNL));
++
++ // Specify that '\r' characters should be transformed to '\n'
++ // OPOST is specified to enable post-processing
++ termios.output_flags.insert(OutputFlags::OPOST | OutputFlags::OCRNL);
++
++ // Open a pty
++ let pty = openpty(None, &termios).unwrap();
++ assert!(pty.master > 0);
++ assert!(pty.slave > 0);
++
++ // Write into the master
++ let string = "foofoofoo\r";
++ write_all(pty.master, string.as_bytes());
++
++ // Read from the slave verifying that the output has been properly transformed
++ let mut buf = [0u8; 10];
++ ::read_exact(pty.slave, &mut buf);
++ let transformed_string = "foofoofoo\n";
++ close(pty.master).unwrap();
++ close(pty.slave).unwrap();
++ assert_eq!(&buf, transformed_string.as_bytes());
++}
++
++// Test modifying local flags
++#[test]
++fn test_local_flags() {
++ // openpty uses ptname(3) internally
++ let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++
++ // Open one pty to get attributes for the second one
++ let mut termios = {
++ let pty = openpty(None, None).unwrap();
++ assert!(pty.master > 0);
++ assert!(pty.slave > 0);
++ let termios = tcgetattr(pty.master).unwrap();
++ close(pty.master).unwrap();
++ close(pty.slave).unwrap();
++ termios
++ };
++
++ // Make sure echo is specified by default or this test is useless.
++ assert!(termios.local_flags.contains(LocalFlags::ECHO));
++
++ // Disable local echo
++ termios.local_flags.remove(LocalFlags::ECHO);
++
++ // Open a new pty with our modified termios settings
++ let pty = openpty(None, &termios).unwrap();
++ assert!(pty.master > 0);
++ assert!(pty.slave > 0);
++
++ // Set the master is in nonblocking mode or reading will never return.
++ let flags = fcntl::fcntl(pty.master, fcntl::F_GETFL).unwrap();
++ let new_flags = fcntl::OFlag::from_bits_truncate(flags) | fcntl::OFlag::O_NONBLOCK;
++ fcntl::fcntl(pty.master, fcntl::F_SETFL(new_flags)).unwrap();
++
++ // Write into the master
++ let string = "foofoofoo\r";
++ write_all(pty.master, string.as_bytes());
++
++ // Try to read from the master, which should not have anything as echoing was disabled.
++ let mut buf = [0u8; 10];
++ let read = read(pty.master, &mut buf).unwrap_err();
++ close(pty.master).unwrap();
++ close(pty.slave).unwrap();
++ assert_eq!(read, Error::Sys(Errno::EAGAIN));
++}
++
++#[test]
++fn test_cfmakeraw() {
++ let mut termios = unsafe { Termios::default_uninit() };
++ termios::cfmakeraw(&mut termios);
++}
+diff --git a/third_party/rust/nix-0.15.0/test/sys/test_uio.rs b/third_party/rust/nix-0.15.0/test/sys/test_uio.rs
+new file mode 100644
+index 0000000000000..3e4fc28ceb0e4
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/sys/test_uio.rs
+@@ -0,0 +1,241 @@
++use nix::sys::uio::*;
++use nix::unistd::*;
++use rand::{thread_rng, Rng};
++use rand::distributions::Alphanumeric;
++use std::{cmp, iter};
++use std::fs::{OpenOptions};
++use std::os::unix::io::AsRawFd;
++
++use tempfile::{tempfile, tempdir};
++
++#[test]
++fn test_writev() {
++ let mut to_write = Vec::with_capacity(16 * 128);
++ for _ in 0..16 {
++ let s: String = thread_rng().sample_iter(&Alphanumeric).take(128).collect();
++ let b = s.as_bytes();
++ to_write.extend(b.iter().cloned());
++ }
++ // Allocate and fill iovecs
++ let mut iovecs = Vec::new();
++ let mut consumed = 0;
++ while consumed < to_write.len() {
++ let left = to_write.len() - consumed;
++ let slice_len = if left <= 64 { left } else { thread_rng().gen_range(64, cmp::min(256, left)) };
++ let b = &to_write[consumed..consumed+slice_len];
++ iovecs.push(IoVec::from_slice(b));
++ consumed += slice_len;
++ }
++ let pipe_res = pipe();
++ assert!(pipe_res.is_ok());
++ let (reader, writer) = pipe_res.ok().unwrap();
++ // FileDesc will close its filedesc (reader).
++ let mut read_buf: Vec<u8> = iter::repeat(0u8).take(128 * 16).collect();
++ // Blocking io, should write all data.
++ let write_res = writev(writer, &iovecs);
++ // Successful write
++ assert!(write_res.is_ok());
++ let written = write_res.ok().unwrap();
++ // Check whether we written all data
++ assert_eq!(to_write.len(), written);
++ let read_res = read(reader, &mut read_buf[..]);
++ // Successful read
++ assert!(read_res.is_ok());
++ let read = read_res.ok().unwrap() as usize;
++ // Check we have read as much as we written
++ assert_eq!(read, written);
++ // Check equality of written and read data
++ assert_eq!(&to_write, &read_buf);
++ let close_res = close(writer);
++ assert!(close_res.is_ok());
++ let close_res = close(reader);
++ assert!(close_res.is_ok());
++}
++
++#[test]
++fn test_readv() {
++ let s:String = thread_rng().sample_iter(&Alphanumeric).take(128).collect();
++ let to_write = s.as_bytes().to_vec();
++ let mut storage = Vec::new();
++ let mut allocated = 0;
++ while allocated < to_write.len() {
++ let left = to_write.len() - allocated;
++ let vec_len = if left <= 64 { left } else { thread_rng().gen_range(64, cmp::min(256, left)) };
++ let v: Vec<u8> = iter::repeat(0u8).take(vec_len).collect();
++ storage.push(v);
++ allocated += vec_len;
++ }
++ let mut iovecs = Vec::with_capacity(storage.len());
++ for v in &mut storage {
++ iovecs.push(IoVec::from_mut_slice(&mut v[..]));
++ }
++ let pipe_res = pipe();
++ assert!(pipe_res.is_ok());
++ let (reader, writer) = pipe_res.ok().unwrap();
++ // Blocking io, should write all data.
++ let write_res = write(writer, &to_write);
++ // Successful write
++ assert!(write_res.is_ok());
++ let read_res = readv(reader, &mut iovecs[..]);
++ assert!(read_res.is_ok());
++ let read = read_res.ok().unwrap();
++ // Check whether we've read all data
++ assert_eq!(to_write.len(), read);
++ // Cccumulate data from iovecs
++ let mut read_buf = Vec::with_capacity(to_write.len());
++ for iovec in &iovecs {
++ read_buf.extend(iovec.as_slice().iter().cloned());
++ }
++ // Check whether iovecs contain all written data
++ assert_eq!(read_buf.len(), to_write.len());
++ // Check equality of written and read data
++ assert_eq!(&read_buf, &to_write);
++ let close_res = close(reader);
++ assert!(close_res.is_ok());
++ let close_res = close(writer);
++ assert!(close_res.is_ok());
++}
++
++#[test]
++fn test_pwrite() {
++ use std::io::Read;
++
++ let mut file = tempfile().unwrap();
++ let buf = [1u8;8];
++ assert_eq!(Ok(8), pwrite(file.as_raw_fd(), &buf, 8));
++ let mut file_content = Vec::new();
++ file.read_to_end(&mut file_content).unwrap();
++ let mut expected = vec![0u8;8];
++ expected.extend(vec![1;8]);
++ assert_eq!(file_content, expected);
++}
++
++#[test]
++fn test_pread() {
++ use std::io::Write;
++
++ let tempdir = tempdir().unwrap();
++
++ let path = tempdir.path().join("pread_test_file");
++ let mut file = OpenOptions::new().write(true).read(true).create(true)
++ .truncate(true).open(path).unwrap();
++ let file_content: Vec<u8> = (0..64).collect();
++ file.write_all(&file_content).unwrap();
++
++ let mut buf = [0u8;16];
++ assert_eq!(Ok(16), pread(file.as_raw_fd(), &mut buf, 16));
++ let expected: Vec<_> = (16..32).collect();
++ assert_eq!(&buf[..], &expected[..]);
++}
++
++#[test]
++#[cfg(target_os = "linux")]
++fn test_pwritev() {
++ use std::io::Read;
++
++ let to_write: Vec<u8> = (0..128).collect();
++ let expected: Vec<u8> = [vec![0;100], to_write.clone()].concat();
++
++ let iovecs = [
++ IoVec::from_slice(&to_write[0..17]),
++ IoVec::from_slice(&to_write[17..64]),
++ IoVec::from_slice(&to_write[64..128]),
++ ];
++
++ let tempdir = tempdir().unwrap();
++
++ // pwritev them into a temporary file
++ let path = tempdir.path().join("pwritev_test_file");
++ let mut file = OpenOptions::new().write(true).read(true).create(true)
++ .truncate(true).open(path).unwrap();
++
++ let written = pwritev(file.as_raw_fd(), &iovecs, 100).ok().unwrap();
++ assert_eq!(written, to_write.len());
++
++ // Read the data back and make sure it matches
++ let mut contents = Vec::new();
++ file.read_to_end(&mut contents).unwrap();
++ assert_eq!(contents, expected);
++}
++
++#[test]
++#[cfg(target_os = "linux")]
++fn test_preadv() {
++ use std::io::Write;
++
++ let to_write: Vec<u8> = (0..200).collect();
++ let expected: Vec<u8> = (100..200).collect();
++
++ let tempdir = tempdir().unwrap();
++
++ let path = tempdir.path().join("preadv_test_file");
++
++ let mut file = OpenOptions::new().read(true).write(true).create(true)
++ .truncate(true).open(path).unwrap();
++ file.write_all(&to_write).unwrap();
++
++ let mut buffers: Vec<Vec<u8>> = vec![
++ vec![0; 24],
++ vec![0; 1],
++ vec![0; 75],
++ ];
++
++ {
++ // Borrow the buffers into IoVecs and preadv into them
++ let iovecs: Vec<_> = buffers.iter_mut().map(
++ |buf| IoVec::from_mut_slice(&mut buf[..])).collect();
++ assert_eq!(Ok(100), preadv(file.as_raw_fd(), &iovecs, 100));
++ }
++
++ let all = buffers.concat();
++ assert_eq!(all, expected);
++}
++
++#[test]
++#[cfg(target_os = "linux")]
++// FIXME: qemu-user doesn't implement process_vm_readv/writev on most arches
++#[cfg_attr(not(any(target_arch = "x86", target_arch = "x86_64")), ignore)]
++fn test_process_vm_readv() {
++ use nix::unistd::ForkResult::*;
++ use nix::sys::signal::*;
++ use nix::sys::wait::*;
++
++ let _ = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++
++ // Pre-allocate memory in the child, since allocation isn't safe
++ // post-fork (~= async-signal-safe)
++ let mut vector = vec![1u8, 2, 3, 4, 5];
++
++ let (r, w) = pipe().unwrap();
++ match fork().expect("Error: Fork Failed") {
++ Parent { child } => {
++ close(w).unwrap();
++ // wait for child
++ read(r, &mut [0u8]).unwrap();
++ close(r).unwrap();
++
++ let ptr = vector.as_ptr() as usize;
++ let remote_iov = RemoteIoVec { base: ptr, len: 5 };
++ let mut buf = vec![0u8; 5];
++
++ let ret = process_vm_readv(child,
++ &[IoVec::from_mut_slice(&mut buf)],
++ &[remote_iov]);
++
++ kill(child, SIGTERM).unwrap();
++ waitpid(child, None).unwrap();
++
++ assert_eq!(Ok(5), ret);
++ assert_eq!(20u8, buf.iter().sum());
++ },
++ Child => {
++ let _ = close(r);
++ for i in &mut vector {
++ *i += 1;
++ }
++ let _ = write(w, b"\0");
++ let _ = close(w);
++ loop { let _ = pause(); }
++ },
++ }
++}
+diff --git a/third_party/rust/nix-0.15.0/test/sys/test_wait.rs b/third_party/rust/nix-0.15.0/test/sys/test_wait.rs
+new file mode 100644
+index 0000000000000..d07d82f0d9075
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/sys/test_wait.rs
+@@ -0,0 +1,104 @@
++use nix::Error;
++use nix::unistd::*;
++use nix::unistd::ForkResult::*;
++use nix::sys::signal::*;
++use nix::sys::wait::*;
++use libc::_exit;
++
++#[test]
++fn test_wait_signal() {
++ let _ = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++
++ // Safe: The child only calls `pause` and/or `_exit`, which are async-signal-safe.
++ match fork().expect("Error: Fork Failed") {
++ Child => {
++ pause();
++ unsafe { _exit(123) }
++ },
++ Parent { child } => {
++ kill(child, Some(SIGKILL)).expect("Error: Kill Failed");
++ assert_eq!(waitpid(child, None), Ok(WaitStatus::Signaled(child, SIGKILL, false)));
++ },
++ }
++}
++
++#[test]
++fn test_wait_exit() {
++ let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++
++ // Safe: Child only calls `_exit`, which is async-signal-safe.
++ match fork().expect("Error: Fork Failed") {
++ Child => unsafe { _exit(12); },
++ Parent { child } => {
++ assert_eq!(waitpid(child, None), Ok(WaitStatus::Exited(child, 12)));
++ },
++ }
++}
++
++#[test]
++fn test_waitstatus_from_raw() {
++ let pid = Pid::from_raw(1);
++ assert_eq!(WaitStatus::from_raw(pid, 0x0002), Ok(WaitStatus::Signaled(pid, Signal::SIGINT, false)));
++ assert_eq!(WaitStatus::from_raw(pid, 0x0200), Ok(WaitStatus::Exited(pid, 2)));
++ assert_eq!(WaitStatus::from_raw(pid, 0x7f7f), Err(Error::invalid_argument()));
++}
++
++#[test]
++fn test_waitstatus_pid() {
++ let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++
++ match fork().unwrap() {
++ Child => unsafe { _exit(0) },
++ Parent { child } => {
++ let status = waitpid(child, None).unwrap();
++ assert_eq!(status.pid(), Some(child));
++ }
++ }
++}
++
++#[cfg(any(target_os = "linux", target_os = "android"))]
++// FIXME: qemu-user doesn't implement ptrace on most arches
++#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
++mod ptrace {
++ use nix::sys::ptrace::{self, Options, Event};
++ use nix::sys::signal::*;
++ use nix::sys::wait::*;
++ use nix::unistd::*;
++ use nix::unistd::ForkResult::*;
++ use libc::_exit;
++
++ fn ptrace_child() -> ! {
++ ptrace::traceme().unwrap();
++ // As recommended by ptrace(2), raise SIGTRAP to pause the child
++ // until the parent is ready to continue
++ raise(SIGTRAP).unwrap();
++ unsafe { _exit(0) }
++ }
++
++ fn ptrace_parent(child: Pid) {
++ // Wait for the raised SIGTRAP
++ assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, SIGTRAP)));
++ // We want to test a syscall stop and a PTRACE_EVENT stop
++ assert!(ptrace::setoptions(child, Options::PTRACE_O_TRACESYSGOOD | Options::PTRACE_O_TRACEEXIT).is_ok());
++
++ // First, stop on the next system call, which will be exit()
++ assert!(ptrace::syscall(child).is_ok());
++ assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child)));
++ // Then get the ptrace event for the process exiting
++ assert!(ptrace::cont(child, None).is_ok());
++ assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceEvent(child, SIGTRAP, Event::PTRACE_EVENT_EXIT as i32)));
++ // Finally get the normal wait() result, now that the process has exited
++ assert!(ptrace::cont(child, None).is_ok());
++ assert_eq!(waitpid(child, None), Ok(WaitStatus::Exited(child, 0)));
++ }
++
++ #[test]
++ fn test_wait_ptrace() {
++ let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++
++ match fork().expect("Error: Fork Failed") {
++ Child => ptrace_child(),
++ Parent { child } => ptrace_parent(child),
++ }
++ }
++}
+diff --git a/third_party/rust/nix-0.15.0/test/test.rs b/third_party/rust/nix-0.15.0/test/test.rs
+new file mode 100644
+index 0000000000000..6a71d261b5712
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/test.rs
+@@ -0,0 +1,149 @@
++// XXX Allow deprecated items until release 0.16.0. See issue #1096.
++#![allow(deprecated)]
++extern crate bytes;
++#[cfg(any(target_os = "android", target_os = "linux"))]
++extern crate caps;
++#[macro_use]
++extern crate cfg_if;
++#[macro_use]
++extern crate nix;
++#[macro_use]
++extern crate lazy_static;
++extern crate libc;
++extern crate rand;
++#[cfg(target_os = "freebsd")]
++extern crate sysctl;
++extern crate tempfile;
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++macro_rules! require_capability {
++ ($capname:ident) => {
++ use ::caps::{Capability, CapSet, has_cap};
++ use ::std::io::{self, Write};
++
++ if !has_cap(None, CapSet::Effective, Capability::$capname).unwrap() {
++ let stderr = io::stderr();
++ let mut handle = stderr.lock();
++ writeln!(handle, "Insufficient capabilities. Skipping test.")
++ .unwrap();
++ return;
++ }
++ }
++}
++
++#[cfg(target_os = "freebsd")]
++macro_rules! skip_if_jailed {
++ ($name:expr) => {
++ use ::sysctl::CtlValue;
++
++ if let CtlValue::Int(1) = ::sysctl::value("security.jail.jailed")
++ .unwrap()
++ {
++ use ::std::io::Write;
++ let stderr = ::std::io::stderr();
++ let mut handle = stderr.lock();
++ writeln!(handle, "{} cannot run in a jail. Skipping test.", $name)
++ .unwrap();
++ return;
++ }
++ }
++}
++
++macro_rules! skip_if_not_root {
++ ($name:expr) => {
++ use nix::unistd::Uid;
++
++ if !Uid::current().is_root() {
++ use ::std::io::Write;
++ let stderr = ::std::io::stderr();
++ let mut handle = stderr.lock();
++ writeln!(handle, "{} requires root privileges. Skipping test.", $name).unwrap();
++ return;
++ }
++ };
++}
++
++mod sys;
++mod test_dir;
++mod test_fcntl;
++#[cfg(any(target_os = "android",
++ target_os = "linux"))]
++mod test_kmod;
++#[cfg(any(target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "fushsia",
++ target_os = "linux",
++ target_os = "netbsd"))]
++mod test_mq;
++mod test_net;
++mod test_nix_path;
++mod test_poll;
++mod test_pty;
++#[cfg(any(target_os = "android",
++ target_os = "freebsd",
++ target_os = "ios",
++ target_os = "linux",
++ target_os = "macos"))]
++mod test_sendfile;
++mod test_stat;
++mod test_unistd;
++
++use std::os::unix::io::RawFd;
++use std::path::PathBuf;
++use std::sync::{Mutex, RwLock, RwLockWriteGuard};
++use nix::unistd::{chdir, getcwd, read};
++
++/// Helper function analogous to `std::io::Read::read_exact`, but for `RawFD`s
++fn read_exact(f: RawFd, buf: &mut [u8]) {
++ let mut len = 0;
++ while len < buf.len() {
++ // get_mut would be better than split_at_mut, but it requires nightly
++ let (_, remaining) = buf.split_at_mut(len);
++ len += read(f, remaining).unwrap();
++ }
++}
++
++lazy_static! {
++ /// Any test that changes the process's current working directory must grab
++ /// the RwLock exclusively. Any process that cares about the current
++ /// working directory must grab it shared.
++ pub static ref CWD_LOCK: RwLock<()> = RwLock::new(());
++ /// Any test that creates child processes must grab this mutex, regardless
++ /// of what it does with those children.
++ pub static ref FORK_MTX: Mutex<()> = Mutex::new(());
++ /// Any test that changes the process's supplementary groups must grab this
++ /// mutex
++ pub static ref GROUPS_MTX: Mutex<()> = Mutex::new(());
++ /// Any tests that loads or unloads kernel modules must grab this mutex
++ pub static ref KMOD_MTX: Mutex<()> = Mutex::new(());
++ /// Any test that calls ptsname(3) must grab this mutex.
++ pub static ref PTSNAME_MTX: Mutex<()> = Mutex::new(());
++ /// Any test that alters signal handling must grab this mutex.
++ pub static ref SIGNAL_MTX: Mutex<()> = Mutex::new(());
++}
++
++/// RAII object that restores a test's original directory on drop
++struct DirRestore<'a> {
++ d: PathBuf,
++ _g: RwLockWriteGuard<'a, ()>
++}
++
++impl<'a> DirRestore<'a> {
++ fn new() -> Self {
++ let guard = ::CWD_LOCK.write()
++ .expect("Lock got poisoned by another test");
++ DirRestore{
++ _g: guard,
++ d: getcwd().unwrap(),
++ }
++ }
++}
++
++impl<'a> Drop for DirRestore<'a> {
++ fn drop(&mut self) {
++ let r = chdir(&self.d);
++ if std::thread::panicking() {
++ r.unwrap();
++ }
++ }
++}
+diff --git a/third_party/rust/nix-0.15.0/test/test_dir.rs b/third_party/rust/nix-0.15.0/test/test_dir.rs
+new file mode 100644
+index 0000000000000..c42fbcd18a29d
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/test_dir.rs
+@@ -0,0 +1,46 @@
++extern crate nix;
++extern crate tempfile;
++
++use nix::dir::{Dir, Type};
++use nix::fcntl::OFlag;
++use nix::sys::stat::Mode;
++use std::fs::File;
++use self::tempfile::tempdir;
++
++#[test]
++fn read() {
++ let tmp = tempdir().unwrap();
++ File::create(&tmp.path().join("foo")).unwrap();
++ ::std::os::unix::fs::symlink("foo", tmp.path().join("bar")).unwrap();
++ let mut dir = Dir::open(tmp.path(), OFlag::O_DIRECTORY | OFlag::O_RDONLY | OFlag::O_CLOEXEC,
++ Mode::empty()).unwrap();
++ let mut entries: Vec<_> = dir.iter().map(|e| e.unwrap()).collect();
++ entries.sort_by(|a, b| a.file_name().cmp(b.file_name()));
++ let entry_names: Vec<_> = entries
++ .iter()
++ .map(|e| e.file_name().to_str().unwrap().to_owned())
++ .collect();
++ assert_eq!(&entry_names[..], &[".", "..", "bar", "foo"]);
++
++ // Check file types. The system is allowed to return DT_UNKNOWN (aka None here) but if it does
++ // return a type, ensure it's correct.
++ assert!(&[Some(Type::Directory), None].contains(&entries[0].file_type())); // .: dir
++ assert!(&[Some(Type::Directory), None].contains(&entries[1].file_type())); // ..: dir
++ assert!(&[Some(Type::Symlink), None].contains(&entries[2].file_type())); // bar: symlink
++ assert!(&[Some(Type::File), None].contains(&entries[3].file_type())); // foo: regular file
++}
++
++#[test]
++fn rewind() {
++ let tmp = tempdir().unwrap();
++ let mut dir = Dir::open(tmp.path(), OFlag::O_DIRECTORY | OFlag::O_RDONLY | OFlag::O_CLOEXEC,
++ Mode::empty()).unwrap();
++ let entries1: Vec<_> = dir.iter().map(|e| e.unwrap().file_name().to_owned()).collect();
++ let entries2: Vec<_> = dir.iter().map(|e| e.unwrap().file_name().to_owned()).collect();
++ assert_eq!(entries1, entries2);
++}
++
++#[test]
++fn ebadf() {
++ assert_eq!(Dir::from_fd(-1).unwrap_err(), nix::Error::Sys(nix::errno::Errno::EBADF));
++}
+diff --git a/third_party/rust/nix-0.15.0/test/test_fcntl.rs b/third_party/rust/nix-0.15.0/test/test_fcntl.rs
+new file mode 100644
+index 0000000000000..6b2bbd679fc31
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/test_fcntl.rs
+@@ -0,0 +1,234 @@
++use nix::Error;
++use nix::errno::*;
++use nix::fcntl::{openat, open, OFlag, readlink, readlinkat, renameat};
++use nix::sys::stat::Mode;
++use nix::unistd::{close, read};
++use tempfile::{self, NamedTempFile};
++use std::fs::File;
++use std::io::prelude::*;
++use std::os::unix::fs;
++
++#[test]
++fn test_openat() {
++ const CONTENTS: &[u8] = b"abcd";
++ let mut tmp = NamedTempFile::new().unwrap();
++ tmp.write_all(CONTENTS).unwrap();
++
++ let dirfd = open(tmp.path().parent().unwrap(),
++ OFlag::empty(),
++ Mode::empty()).unwrap();
++ let fd = openat(dirfd,
++ tmp.path().file_name().unwrap(),
++ OFlag::O_RDONLY,
++ Mode::empty()).unwrap();
++
++ let mut buf = [0u8; 1024];
++ assert_eq!(4, read(fd, &mut buf).unwrap());
++ assert_eq!(CONTENTS, &buf[0..4]);
++
++ close(fd).unwrap();
++ close(dirfd).unwrap();
++}
++
++#[test]
++fn test_renameat() {
++ let old_dir = tempfile::tempdir().unwrap();
++ let old_dirfd = open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap();
++ let old_path = old_dir.path().join("old");
++ File::create(&old_path).unwrap();
++ let new_dir = tempfile::tempdir().unwrap();
++ let new_dirfd = open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap();
++ renameat(Some(old_dirfd), "old", Some(new_dirfd), "new").unwrap();
++ assert_eq!(renameat(Some(old_dirfd), "old", Some(new_dirfd), "new").unwrap_err(),
++ Error::Sys(Errno::ENOENT));
++ close(old_dirfd).unwrap();
++ close(new_dirfd).unwrap();
++ assert!(new_dir.path().join("new").exists());
++}
++
++#[test]
++fn test_readlink() {
++ let tempdir = tempfile::tempdir().unwrap();
++ let src = tempdir.path().join("a");
++ let dst = tempdir.path().join("b");
++ println!("a: {:?}, b: {:?}", &src, &dst);
++ fs::symlink(&src.as_path(), &dst.as_path()).unwrap();
++ let dirfd = open(tempdir.path(),
++ OFlag::empty(),
++ Mode::empty()).unwrap();
++
++ let mut buf = vec![0; src.to_str().unwrap().len() + 1];
++ assert_eq!(readlink(&dst, &mut buf).unwrap().to_str().unwrap(),
++ src.to_str().unwrap());
++ assert_eq!(readlinkat(dirfd, "b", &mut buf).unwrap().to_str().unwrap(),
++ src.to_str().unwrap());
++}
++
++#[cfg(any(target_os = "linux", target_os = "android"))]
++mod linux_android {
++ use std::io::prelude::*;
++ use std::io::SeekFrom;
++ use std::os::unix::prelude::*;
++
++ use libc::loff_t;
++
++ use nix::fcntl::*;
++ use nix::sys::uio::IoVec;
++ use nix::unistd::{close, pipe, read, write};
++
++ use tempfile::{tempfile, NamedTempFile};
++
++ /// This test creates a temporary file containing the contents
++ /// 'foobarbaz' and uses the `copy_file_range` call to transfer
++ /// 3 bytes at offset 3 (`bar`) to another empty file at offset 0. The
++ /// resulting file is read and should contain the contents `bar`.
++ /// The from_offset should be updated by the call to reflect
++ /// the 3 bytes read (6).
++ ///
++ /// FIXME: This test is disabled for linux based builds, because Travis
++ /// Linux version is too old for `copy_file_range`.
++ #[test]
++ #[ignore]
++ fn test_copy_file_range() {
++ const CONTENTS: &[u8] = b"foobarbaz";
++
++ let mut tmp1 = tempfile().unwrap();
++ let mut tmp2 = tempfile().unwrap();
++
++ tmp1.write_all(CONTENTS).unwrap();
++ tmp1.flush().unwrap();
++
++ let mut from_offset: i64 = 3;
++ copy_file_range(
++ tmp1.as_raw_fd(),
++ Some(&mut from_offset),
++ tmp2.as_raw_fd(),
++ None,
++ 3,
++ )
++ .unwrap();
++
++ let mut res: String = String::new();
++ tmp2.seek(SeekFrom::Start(0)).unwrap();
++ tmp2.read_to_string(&mut res).unwrap();
++
++ assert_eq!(res, String::from("bar"));
++ assert_eq!(from_offset, 6);
++ }
++
++ #[test]
++ fn test_splice() {
++ const CONTENTS: &[u8] = b"abcdef123456";
++ let mut tmp = tempfile().unwrap();
++ tmp.write_all(CONTENTS).unwrap();
++
++ let (rd, wr) = pipe().unwrap();
++ let mut offset: loff_t = 5;
++ let res = splice(tmp.as_raw_fd(), Some(&mut offset),
++ wr, None, 2, SpliceFFlags::empty()).unwrap();
++
++ assert_eq!(2, res);
++
++ let mut buf = [0u8; 1024];
++ assert_eq!(2, read(rd, &mut buf).unwrap());
++ assert_eq!(b"f1", &buf[0..2]);
++ assert_eq!(7, offset);
++
++ close(rd).unwrap();
++ close(wr).unwrap();
++ }
++
++ #[test]
++ fn test_tee() {
++ let (rd1, wr1) = pipe().unwrap();
++ let (rd2, wr2) = pipe().unwrap();
++
++ write(wr1, b"abc").unwrap();
++ let res = tee(rd1, wr2, 2, SpliceFFlags::empty()).unwrap();
++
++ assert_eq!(2, res);
++
++ let mut buf = [0u8; 1024];
++
++ // Check the tee'd bytes are at rd2.
++ assert_eq!(2, read(rd2, &mut buf).unwrap());
++ assert_eq!(b"ab", &buf[0..2]);
++
++ // Check all the bytes are still at rd1.
++ assert_eq!(3, read(rd1, &mut buf).unwrap());
++ assert_eq!(b"abc", &buf[0..3]);
++
++ close(rd1).unwrap();
++ close(wr1).unwrap();
++ close(rd2).unwrap();
++ close(wr2).unwrap();
++ }
++
++ #[test]
++ fn test_vmsplice() {
++ let (rd, wr) = pipe().unwrap();
++
++ let buf1 = b"abcdef";
++ let buf2 = b"defghi";
++ let mut iovecs = Vec::with_capacity(2);
++ iovecs.push(IoVec::from_slice(&buf1[0..3]));
++ iovecs.push(IoVec::from_slice(&buf2[0..3]));
++
++ let res = vmsplice(wr, &iovecs[..], SpliceFFlags::empty()).unwrap();
++
++ assert_eq!(6, res);
++
++ // Check the bytes can be read at rd.
++ let mut buf = [0u8; 32];
++ assert_eq!(6, read(rd, &mut buf).unwrap());
++ assert_eq!(b"abcdef", &buf[0..6]);
++
++ close(rd).unwrap();
++ close(wr).unwrap();
++ }
++
++ #[test]
++ fn test_fallocate() {
++ let tmp = NamedTempFile::new().unwrap();
++
++ let fd = tmp.as_raw_fd();
++ fallocate(fd, FallocateFlags::empty(), 0, 100).unwrap();
++
++ // Check if we read exactly 100 bytes
++ let mut buf = [0u8; 200];
++ assert_eq!(100, read(fd, &mut buf).unwrap());
++ }
++}
++
++#[cfg(any(target_os = "linux",
++ target_os = "android",
++ target_os = "emscripten",
++ target_os = "fuchsia",
++ any(target_os = "wasi", target_env = "wasi"),
++ target_env = "uclibc",
++ target_env = "freebsd"))]
++mod test_posix_fadvise {
++
++ use tempfile::NamedTempFile;
++ use std::os::unix::io::{RawFd, AsRawFd};
++ use nix::errno::Errno;
++ use nix::fcntl::*;
++ use nix::unistd::pipe;
++
++ #[test]
++ fn test_success() {
++ let tmp = NamedTempFile::new().unwrap();
++ let fd = tmp.as_raw_fd();
++ let res = posix_fadvise(fd, 0, 100, PosixFadviseAdvice::POSIX_FADV_WILLNEED).unwrap();
++
++ assert_eq!(res, 0);
++ }
++
++ #[test]
++ fn test_errno() {
++ let (rd, _wr) = pipe().unwrap();
++ let errno = posix_fadvise(rd as RawFd, 0, 100, PosixFadviseAdvice::POSIX_FADV_WILLNEED)
++ .unwrap();
++ assert_eq!(errno, Errno::ESPIPE as i32);
++ }
++}
+diff --git a/third_party/rust/nix-0.15.0/test/test_kmod/hello_mod/Makefile b/third_party/rust/nix-0.15.0/test/test_kmod/hello_mod/Makefile
+new file mode 100644
+index 0000000000000..74c99b77e96e1
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/test_kmod/hello_mod/Makefile
+@@ -0,0 +1,7 @@
++obj-m += hello.o
++
++all:
++ make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modules
++
++clean:
++ make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) clean
+diff --git a/third_party/rust/nix-0.15.0/test/test_kmod/hello_mod/hello.c b/third_party/rust/nix-0.15.0/test/test_kmod/hello_mod/hello.c
+new file mode 100644
+index 0000000000000..1c34987d2ac39
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/test_kmod/hello_mod/hello.c
+@@ -0,0 +1,26 @@
++/*
++ * SPDX-License-Identifier: GPL-2.0+ or MIT
++ */
++#include <linux/module.h>
++#include <linux/kernel.h>
++
++static int number= 1;
++static char *who = "World";
++
++module_param(number, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
++MODULE_PARM_DESC(myint, "Just some number");
++module_param(who, charp, 0000);
++MODULE_PARM_DESC(who, "Whot to greet");
++
++int init_module(void)
++{
++ printk(KERN_INFO "Hello %s (%d)!\n", who, number);
++ return 0;
++}
++
++void cleanup_module(void)
++{
++ printk(KERN_INFO "Goodbye %s (%d)!\n", who, number);
++}
++
++MODULE_LICENSE("Dual MIT/GPL");
+diff --git a/third_party/rust/nix-0.15.0/test/test_kmod/mod.rs b/third_party/rust/nix-0.15.0/test/test_kmod/mod.rs
+new file mode 100644
+index 0000000000000..ad406357b06d2
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/test_kmod/mod.rs
+@@ -0,0 +1,166 @@
++use std::fs::copy;
++use std::path::PathBuf;
++use std::process::Command;
++use tempfile::{tempdir, TempDir};
++
++fn compile_kernel_module() -> (PathBuf, String, TempDir) {
++ let _m = ::FORK_MTX
++ .lock()
++ .expect("Mutex got poisoned by another test");
++
++ let tmp_dir = tempdir().expect("unable to create temporary build directory");
++
++ copy(
++ "test/test_kmod/hello_mod/hello.c",
++ &tmp_dir.path().join("hello.c"),
++ ).expect("unable to copy hello.c to temporary build directory");
++ copy(
++ "test/test_kmod/hello_mod/Makefile",
++ &tmp_dir.path().join("Makefile"),
++ ).expect("unable to copy Makefile to temporary build directory");
++
++ let status = Command::new("make")
++ .current_dir(tmp_dir.path())
++ .status()
++ .expect("failed to run make");
++
++ assert!(status.success());
++
++ // Return the relative path of the build kernel module
++ (tmp_dir.path().join("hello.ko"), "hello".to_owned(), tmp_dir)
++}
++
++use nix::errno::Errno;
++use nix::kmod::{delete_module, DeleteModuleFlags};
++use nix::kmod::{finit_module, init_module, ModuleInitFlags};
++use nix::Error;
++use std::ffi::CString;
++use std::fs::File;
++use std::io::Read;
++
++#[test]
++fn test_finit_and_delete_module() {
++ require_capability!(CAP_SYS_MODULE);
++ let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
++ let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test");
++
++ let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module();
++
++ let f = File::open(kmod_path).expect("unable to open kernel module");
++ finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty())
++ .expect("unable to load kernel module");
++
++ delete_module(
++ &CString::new(kmod_name).unwrap(),
++ DeleteModuleFlags::empty(),
++ ).expect("unable to unload kernel module");
++}
++
++#[test]
++fn test_finit_and_delete_modul_with_params() {
++ require_capability!(CAP_SYS_MODULE);
++ let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
++ let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test");
++
++ let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module();
++
++ let f = File::open(kmod_path).expect("unable to open kernel module");
++ finit_module(
++ &f,
++ &CString::new("who=Rust number=2018").unwrap(),
++ ModuleInitFlags::empty(),
++ ).expect("unable to load kernel module");
++
++ delete_module(
++ &CString::new(kmod_name).unwrap(),
++ DeleteModuleFlags::empty(),
++ ).expect("unable to unload kernel module");
++}
++
++#[test]
++fn test_init_and_delete_module() {
++ require_capability!(CAP_SYS_MODULE);
++ let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
++ let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test");
++
++ let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module();
++
++ let mut f = File::open(kmod_path).expect("unable to open kernel module");
++ let mut contents: Vec<u8> = Vec::new();
++ f.read_to_end(&mut contents)
++ .expect("unable to read kernel module content to buffer");
++ init_module(&mut contents, &CString::new("").unwrap()).expect("unable to load kernel module");
++
++ delete_module(
++ &CString::new(kmod_name).unwrap(),
++ DeleteModuleFlags::empty(),
++ ).expect("unable to unload kernel module");
++}
++
++#[test]
++fn test_init_and_delete_module_with_params() {
++ require_capability!(CAP_SYS_MODULE);
++ let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
++ let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test");
++
++ let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module();
++
++ let mut f = File::open(kmod_path).expect("unable to open kernel module");
++ let mut contents: Vec<u8> = Vec::new();
++ f.read_to_end(&mut contents)
++ .expect("unable to read kernel module content to buffer");
++ init_module(&mut contents, &CString::new("who=Nix number=2015").unwrap())
++ .expect("unable to load kernel module");
++
++ delete_module(
++ &CString::new(kmod_name).unwrap(),
++ DeleteModuleFlags::empty(),
++ ).expect("unable to unload kernel module");
++}
++
++#[test]
++fn test_finit_module_invalid() {
++ require_capability!(CAP_SYS_MODULE);
++ let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
++ let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test");
++
++ let kmod_path = "/dev/zero";
++
++ let f = File::open(kmod_path).expect("unable to open kernel module");
++ let result = finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty());
++
++ assert_eq!(result.unwrap_err(), Error::Sys(Errno::EINVAL));
++}
++
++#[test]
++fn test_finit_module_twice_and_delete_module() {
++ require_capability!(CAP_SYS_MODULE);
++ let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
++ let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test");
++
++ let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module();
++
++ let f = File::open(kmod_path).expect("unable to open kernel module");
++ finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty())
++ .expect("unable to load kernel module");
++
++ let result = finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty());
++
++ assert_eq!(result.unwrap_err(), Error::Sys(Errno::EEXIST));
++
++ delete_module(
++ &CString::new(kmod_name).unwrap(),
++ DeleteModuleFlags::empty(),
++ ).expect("unable to unload kernel module");
++}
++
++#[test]
++fn test_delete_module_not_loaded() {
++ require_capability!(CAP_SYS_MODULE);
++ let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
++ let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test");
++
++ let result = delete_module(&CString::new("hello").unwrap(), DeleteModuleFlags::empty());
++
++ assert_eq!(result.unwrap_err(), Error::Sys(Errno::ENOENT));
++}
+diff --git a/third_party/rust/nix-0.15.0/test/test_mount.rs b/third_party/rust/nix-0.15.0/test/test_mount.rs
+new file mode 100644
+index 0000000000000..d2e08bc42855d
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/test_mount.rs
+@@ -0,0 +1,238 @@
++// Impelmentation note: to allow unprivileged users to run it, this test makes
++// use of user and mount namespaces. On systems that allow unprivileged user
++// namespaces (Linux >= 3.8 compiled with CONFIG_USER_NS), the test should run
++// without root.
++
++extern crate libc;
++extern crate nix;
++extern crate tempfile;
++
++#[cfg(target_os = "linux")]
++mod test_mount {
++ use std::fs::{self, File};
++ use std::io::{self, Read, Write};
++ use std::os::unix::fs::OpenOptionsExt;
++ use std::os::unix::fs::PermissionsExt;
++ use std::process::{self, Command};
++
++ use libc::{EACCES, EROFS};
++
++ use nix::errno::Errno;
++ use nix::mount::{mount, umount, MsFlags};
++ use nix::sched::{unshare, CloneFlags};
++ use nix::sys::stat::{self, Mode};
++ use nix::unistd::getuid;
++
++ use tempfile;
++
++ static SCRIPT_CONTENTS: &'static [u8] = b"#!/bin/sh
++exit 23";
++
++ const EXPECTED_STATUS: i32 = 23;
++
++ const NONE: Option<&'static [u8]> = None;
++ pub fn test_mount_tmpfs_without_flags_allows_rwx() {
++ let tempdir = tempfile::tempdir().unwrap();
++
++ mount(NONE,
++ tempdir.path(),
++ Some(b"tmpfs".as_ref()),
++ MsFlags::empty(),
++ NONE)
++ .unwrap_or_else(|e| panic!("mount failed: {}", e));
++
++ let test_path = tempdir.path().join("test");
++
++ // Verify write.
++ fs::OpenOptions::new()
++ .create(true)
++ .write(true)
++ .mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits())
++ .open(&test_path)
++ .or_else(|e|
++ if Errno::from_i32(e.raw_os_error().unwrap()) == Errno::EOVERFLOW {
++ // Skip tests on certain Linux kernels which have a bug
++ // regarding tmpfs in namespaces.
++ // Ubuntu 14.04 and 16.04 are known to be affected; 16.10 is
++ // not. There is no legitimate reason for open(2) to return
++ // EOVERFLOW here.
++ // https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1659087
++ let stderr = io::stderr();
++ let mut handle = stderr.lock();
++ writeln!(handle, "Buggy Linux kernel detected. Skipping test.")
++ .unwrap();
++ process::exit(0);
++ } else {
++ panic!("open failed: {}", e);
++ }
++ )
++ .and_then(|mut f| f.write(SCRIPT_CONTENTS))
++ .unwrap_or_else(|e| panic!("write failed: {}", e));
++
++ // Verify read.
++ let mut buf = Vec::new();
++ File::open(&test_path)
++ .and_then(|mut f| f.read_to_end(&mut buf))
++ .unwrap_or_else(|e| panic!("read failed: {}", e));
++ assert_eq!(buf, SCRIPT_CONTENTS);
++
++ // Verify execute.
++ assert_eq!(EXPECTED_STATUS,
++ Command::new(&test_path)
++ .status()
++ .unwrap_or_else(|e| panic!("exec failed: {}", e))
++ .code()
++ .unwrap_or_else(|| panic!("child killed by signal")));
++
++ umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {}", e));
++ }
++
++ pub fn test_mount_rdonly_disallows_write() {
++ let tempdir = tempfile::tempdir().unwrap();
++
++ mount(NONE,
++ tempdir.path(),
++ Some(b"tmpfs".as_ref()),
++ MsFlags::MS_RDONLY,
++ NONE)
++ .unwrap_or_else(|e| panic!("mount failed: {}", e));
++
++ // EROFS: Read-only file system
++ assert_eq!(EROFS as i32,
++ File::create(tempdir.path().join("test")).unwrap_err().raw_os_error().unwrap());
++
++ umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {}", e));
++ }
++
++ pub fn test_mount_noexec_disallows_exec() {
++ let tempdir = tempfile::tempdir().unwrap();
++
++ mount(NONE,
++ tempdir.path(),
++ Some(b"tmpfs".as_ref()),
++ MsFlags::MS_NOEXEC,
++ NONE)
++ .unwrap_or_else(|e| panic!("mount failed: {}", e));
++
++ let test_path = tempdir.path().join("test");
++
++ fs::OpenOptions::new()
++ .create(true)
++ .write(true)
++ .mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits())
++ .open(&test_path)
++ .and_then(|mut f| f.write(SCRIPT_CONTENTS))
++ .unwrap_or_else(|e| panic!("write failed: {}", e));
++
++ // Verify that we cannot execute despite a+x permissions being set.
++ let mode = stat::Mode::from_bits_truncate(fs::metadata(&test_path)
++ .map(|md| md.permissions().mode())
++ .unwrap_or_else(|e| {
++ panic!("metadata failed: {}", e)
++ }));
++
++ assert!(mode.contains(Mode::S_IXUSR | Mode::S_IXGRP | Mode::S_IXOTH),
++ "{:?} did not have execute permissions",
++ &test_path);
++
++ // EACCES: Permission denied
++ assert_eq!(EACCES as i32,
++ Command::new(&test_path).status().unwrap_err().raw_os_error().unwrap());
++
++ umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {}", e));
++ }
++
++ pub fn test_mount_bind() {
++ let tempdir = tempfile::tempdir().unwrap();
++ let file_name = "test";
++
++ {
++ let mount_point = tempfile::tempdir().unwrap();
++
++ mount(Some(tempdir.path()),
++ mount_point.path(),
++ NONE,
++ MsFlags::MS_BIND,
++ NONE)
++ .unwrap_or_else(|e| panic!("mount failed: {}", e));
++
++ fs::OpenOptions::new()
++ .create(true)
++ .write(true)
++ .mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits())
++ .open(mount_point.path().join(file_name))
++ .and_then(|mut f| f.write(SCRIPT_CONTENTS))
++ .unwrap_or_else(|e| panic!("write failed: {}", e));
++
++ umount(mount_point.path()).unwrap_or_else(|e| panic!("umount failed: {}", e));
++ }
++
++ // Verify the file written in the mount shows up in source directory, even
++ // after unmounting.
++
++ let mut buf = Vec::new();
++ File::open(tempdir.path().join(file_name))
++ .and_then(|mut f| f.read_to_end(&mut buf))
++ .unwrap_or_else(|e| panic!("read failed: {}", e));
++ assert_eq!(buf, SCRIPT_CONTENTS);
++ }
++
++ pub fn setup_namespaces() {
++ // Hold on to the uid in the parent namespace.
++ let uid = getuid();
++
++ unshare(CloneFlags::CLONE_NEWNS | CloneFlags::CLONE_NEWUSER).unwrap_or_else(|e| {
++ let stderr = io::stderr();
++ let mut handle = stderr.lock();
++ writeln!(handle,
++ "unshare failed: {}. Are unprivileged user namespaces available?",
++ e).unwrap();
++ writeln!(handle, "mount is not being tested").unwrap();
++ // Exit with success because not all systems support unprivileged user namespaces, and
++ // that's not what we're testing for.
++ process::exit(0);
++ });
++
++ // Map user as uid 1000.
++ fs::OpenOptions::new()
++ .write(true)
++ .open("/proc/self/uid_map")
++ .and_then(|mut f| f.write(format!("1000 {} 1\n", uid).as_bytes()))
++ .unwrap_or_else(|e| panic!("could not write uid map: {}", e));
++ }
++}
++
++
++// Test runner
++
++/// Mimic normal test output (hackishly).
++#[cfg(target_os = "linux")]
++macro_rules! run_tests {
++ ( $($test_fn:ident),* ) => {{
++ println!();
++
++ $(
++ print!("test test_mount::{} ... ", stringify!($test_fn));
++ $test_fn();
++ println!("ok");
++ )*
++
++ println!();
++ }}
++}
++
++#[cfg(target_os = "linux")]
++fn main() {
++ use test_mount::{setup_namespaces, test_mount_tmpfs_without_flags_allows_rwx,
++ test_mount_rdonly_disallows_write, test_mount_noexec_disallows_exec,
++ test_mount_bind};
++ setup_namespaces();
++
++ run_tests!(test_mount_tmpfs_without_flags_allows_rwx,
++ test_mount_rdonly_disallows_write,
++ test_mount_noexec_disallows_exec,
++ test_mount_bind);
++}
++
++#[cfg(not(target_os = "linux"))]
++fn main() {}
+diff --git a/third_party/rust/nix-0.15.0/test/test_mq.rs b/third_party/rust/nix-0.15.0/test/test_mq.rs
+new file mode 100644
+index 0000000000000..caac4fc261cd6
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/test_mq.rs
+@@ -0,0 +1,152 @@
++use libc::c_long;
++
++use std::ffi::CString;
++use std::str;
++
++use nix::errno::Errno::*;
++use nix::Error::Sys;
++use nix::mqueue::{mq_open, mq_close, mq_send, mq_receive};
++use nix::mqueue::{MqAttr, MQ_OFlag};
++use nix::sys::stat::Mode;
++
++#[test]
++fn test_mq_send_and_receive() {
++ const MSG_SIZE: c_long = 32;
++ let attr = MqAttr::new(0, 10, MSG_SIZE, 0);
++ let mq_name= &CString::new(b"/a_nix_test_queue".as_ref()).unwrap();
++
++ let oflag0 = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
++ let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH;
++ let r0 = mq_open(mq_name, oflag0, mode, Some(&attr));
++ if let Err(Sys(ENOSYS)) = r0 {
++ println!("message queues not supported or module not loaded?");
++ return;
++ };
++ let mqd0 = r0.unwrap();
++ let msg_to_send = "msg_1";
++ mq_send(mqd0, msg_to_send.as_bytes(), 1).unwrap();
++
++ let oflag1 = MQ_OFlag::O_CREAT | MQ_OFlag::O_RDONLY;
++ let mqd1 = mq_open(mq_name, oflag1, mode, Some(&attr)).unwrap();
++ let mut buf = [0u8; 32];
++ let mut prio = 0u32;
++ let len = mq_receive(mqd1, &mut buf, &mut prio).unwrap();
++ assert!(prio == 1);
++
++ mq_close(mqd1).unwrap();
++ mq_close(mqd0).unwrap();
++ assert_eq!(msg_to_send, str::from_utf8(&buf[0..len]).unwrap());
++}
++
++
++#[test]
++#[cfg(not(any(target_os = "netbsd")))]
++fn test_mq_getattr() {
++ use nix::mqueue::mq_getattr;
++ const MSG_SIZE: c_long = 32;
++ let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0);
++ let mq_name = &CString::new(b"/attr_test_get_attr".as_ref()).unwrap();
++ let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
++ let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH;
++ let r = mq_open(mq_name, oflag, mode, Some(&initial_attr));
++ if let Err(Sys(ENOSYS)) = r {
++ println!("message queues not supported or module not loaded?");
++ return;
++ };
++ let mqd = r.unwrap();
++
++ let read_attr = mq_getattr(mqd).unwrap();
++ assert_eq!(read_attr, initial_attr);
++ mq_close(mqd).unwrap();
++}
++
++// FIXME: Fix failures for mips in QEMU
++#[test]
++#[cfg(not(any(target_os = "netbsd")))]
++#[cfg_attr(any(target_arch = "mips", target_arch = "mips64"), ignore)]
++fn test_mq_setattr() {
++ use nix::mqueue::{mq_getattr, mq_setattr};
++ const MSG_SIZE: c_long = 32;
++ let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0);
++ let mq_name = &CString::new(b"/attr_test_get_attr".as_ref()).unwrap();
++ let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
++ let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH;
++ let r = mq_open(mq_name, oflag, mode, Some(&initial_attr));
++ if let Err(Sys(ENOSYS)) = r {
++ println!("message queues not supported or module not loaded?");
++ return;
++ };
++ let mqd = r.unwrap();
++
++ let new_attr = MqAttr::new(0, 20, MSG_SIZE * 2, 100);
++ let old_attr = mq_setattr(mqd, &new_attr).unwrap();
++ assert_eq!(old_attr, initial_attr);
++
++ let new_attr_get = mq_getattr(mqd).unwrap();
++ // The following tests make sense. No changes here because according to the Linux man page only
++ // O_NONBLOCK can be set (see tests below)
++ assert_ne!(new_attr_get, new_attr);
++
++ let new_attr_non_blocking = MqAttr::new(MQ_OFlag::O_NONBLOCK.bits() as c_long, 10, MSG_SIZE, 0);
++ mq_setattr(mqd, &new_attr_non_blocking).unwrap();
++ let new_attr_get = mq_getattr(mqd).unwrap();
++
++ // now the O_NONBLOCK flag has been set
++ assert_ne!(new_attr_get, initial_attr);
++ assert_eq!(new_attr_get, new_attr_non_blocking);
++ mq_close(mqd).unwrap();
++}
++
++// FIXME: Fix failures for mips in QEMU
++#[test]
++#[cfg(not(any(target_os = "netbsd")))]
++#[cfg_attr(any(target_arch = "mips", target_arch = "mips64"), ignore)]
++fn test_mq_set_nonblocking() {
++ use nix::mqueue::{mq_getattr, mq_set_nonblock, mq_remove_nonblock};
++ const MSG_SIZE: c_long = 32;
++ let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0);
++ let mq_name = &CString::new(b"/attr_test_get_attr".as_ref()).unwrap();
++ let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
++ let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH;
++ let r = mq_open(mq_name, oflag, mode, Some(&initial_attr));
++ if let Err(Sys(ENOSYS)) = r {
++ println!("message queues not supported or module not loaded?");
++ return;
++ };
++ let mqd = r.unwrap();
++ mq_set_nonblock(mqd).unwrap();
++ let new_attr = mq_getattr(mqd);
++ assert!(new_attr.unwrap().flags() == MQ_OFlag::O_NONBLOCK.bits() as c_long);
++ mq_remove_nonblock(mqd).unwrap();
++ let new_attr = mq_getattr(mqd);
++ assert!(new_attr.unwrap().flags() == 0);
++ mq_close(mqd).unwrap();
++}
++
++#[test]
++#[cfg(not(any(target_os = "netbsd")))]
++fn test_mq_unlink() {
++ use nix::mqueue::mq_unlink;
++ const MSG_SIZE: c_long = 32;
++ let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0);
++ let mq_name_opened = &CString::new(b"/mq_unlink_test".as_ref()).unwrap();
++ let mq_name_not_opened = &CString::new(b"/mq_unlink_test".as_ref()).unwrap();
++ let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
++ let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH;
++ let r = mq_open(mq_name_opened, oflag, mode, Some(&initial_attr));
++ if let Err(Sys(ENOSYS)) = r {
++ println!("message queues not supported or module not loaded?");
++ return;
++ };
++ let mqd = r.unwrap();
++
++ let res_unlink = mq_unlink(mq_name_opened);
++ assert!(res_unlink == Ok(()) );
++
++ let res_unlink_not_opened = mq_unlink(mq_name_not_opened);
++ assert!(res_unlink_not_opened == Err(Sys(ENOENT)) );
++
++ mq_close(mqd).unwrap();
++ let res_unlink_after_close = mq_unlink(mq_name_opened);
++ assert!(res_unlink_after_close == Err(Sys(ENOENT)) );
++}
+diff --git a/third_party/rust/nix-0.15.0/test/test_net.rs b/third_party/rust/nix-0.15.0/test/test_net.rs
+new file mode 100644
+index 0000000000000..b8940e718bdf3
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/test_net.rs
+@@ -0,0 +1,12 @@
++use nix::net::if_::*;
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++const LOOPBACK: &[u8] = b"lo";
++
++#[cfg(not(any(target_os = "android", target_os = "linux")))]
++const LOOPBACK: &[u8] = b"lo0";
++
++#[test]
++fn test_if_nametoindex() {
++ assert!(if_nametoindex(&LOOPBACK[..]).is_ok());
++}
+diff --git a/third_party/rust/nix-0.15.0/test/test_nix_path.rs b/third_party/rust/nix-0.15.0/test/test_nix_path.rs
+new file mode 100644
+index 0000000000000..e69de29bb2d1d
+diff --git a/third_party/rust/nix-0.15.0/test/test_poll.rs b/third_party/rust/nix-0.15.0/test/test_poll.rs
+new file mode 100644
+index 0000000000000..aef40e4792b5a
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/test_poll.rs
+@@ -0,0 +1,50 @@
++use nix::poll::{PollFlags, poll, PollFd};
++use nix::unistd::{write, pipe};
++
++#[test]
++fn test_poll() {
++ let (r, w) = pipe().unwrap();
++ let mut fds = [PollFd::new(r, PollFlags::POLLIN)];
++
++ // Poll an idle pipe. Should timeout
++ let nfds = poll(&mut fds, 100).unwrap();
++ assert_eq!(nfds, 0);
++ assert!(!fds[0].revents().unwrap().contains(PollFlags::POLLIN));
++
++ write(w, b".").unwrap();
++
++ // Poll a readable pipe. Should return an event.
++ let nfds = poll(&mut fds, 100).unwrap();
++ assert_eq!(nfds, 1);
++ assert!(fds[0].revents().unwrap().contains(PollFlags::POLLIN));
++}
++
++// ppoll(2) is the same as poll except for how it handles timeouts and signals.
++// Repeating the test for poll(2) should be sufficient to check that our
++// bindings are correct.
++#[cfg(any(target_os = "android",
++ target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "linux"))]
++#[test]
++fn test_ppoll() {
++ use nix::poll::ppoll;
++ use nix::sys::signal::SigSet;
++ use nix::sys::time::{TimeSpec, TimeValLike};
++
++ let timeout = TimeSpec::milliseconds(1);
++ let (r, w) = pipe().unwrap();
++ let mut fds = [PollFd::new(r, PollFlags::POLLIN)];
++
++ // Poll an idle pipe. Should timeout
++ let nfds = ppoll(&mut fds, timeout, SigSet::empty()).unwrap();
++ assert_eq!(nfds, 0);
++ assert!(!fds[0].revents().unwrap().contains(PollFlags::POLLIN));
++
++ write(w, b".").unwrap();
++
++ // Poll a readable pipe. Should return an event.
++ let nfds = ppoll(&mut fds, timeout, SigSet::empty()).unwrap();
++ assert_eq!(nfds, 1);
++ assert!(fds[0].revents().unwrap().contains(PollFlags::POLLIN));
++}
+diff --git a/third_party/rust/nix-0.15.0/test/test_pty.rs b/third_party/rust/nix-0.15.0/test/test_pty.rs
+new file mode 100644
+index 0000000000000..476b15c10128c
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/test_pty.rs
+@@ -0,0 +1,235 @@
++use std::io::Write;
++use std::path::Path;
++use std::os::unix::prelude::*;
++use tempfile::tempfile;
++
++use libc::{_exit, STDOUT_FILENO};
++use nix::fcntl::{OFlag, open};
++use nix::pty::*;
++use nix::sys::stat;
++use nix::sys::termios::*;
++use nix::unistd::{write, close, pause};
++
++/// Regression test for Issue #659
++/// This is the correct way to explicitly close a `PtyMaster`
++#[test]
++fn test_explicit_close() {
++ let mut f = {
++ let m = posix_openpt(OFlag::O_RDWR).unwrap();
++ close(m.into_raw_fd()).unwrap();
++ tempfile().unwrap()
++ };
++ // This should work. But if there's been a double close, then it will
++ // return EBADF
++ f.write_all(b"whatever").unwrap();
++}
++
++/// Test equivalence of `ptsname` and `ptsname_r`
++#[test]
++#[cfg(any(target_os = "android", target_os = "linux"))]
++fn test_ptsname_equivalence() {
++ let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++
++ // Open a new PTTY master
++ let master_fd = posix_openpt(OFlag::O_RDWR).unwrap();
++ assert!(master_fd.as_raw_fd() > 0);
++
++ // Get the name of the slave
++ let slave_name = unsafe { ptsname(&master_fd) }.unwrap() ;
++ let slave_name_r = ptsname_r(&master_fd).unwrap();
++ assert_eq!(slave_name, slave_name_r);
++}
++
++/// Test data copying of `ptsname`
++// TODO need to run in a subprocess, since ptsname is non-reentrant
++#[test]
++#[cfg(any(target_os = "android", target_os = "linux"))]
++fn test_ptsname_copy() {
++ let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++
++ // Open a new PTTY master
++ let master_fd = posix_openpt(OFlag::O_RDWR).unwrap();
++ assert!(master_fd.as_raw_fd() > 0);
++
++ // Get the name of the slave
++ let slave_name1 = unsafe { ptsname(&master_fd) }.unwrap();
++ let slave_name2 = unsafe { ptsname(&master_fd) }.unwrap();
++ assert!(slave_name1 == slave_name2);
++ // Also make sure that the string was actually copied and they point to different parts of
++ // memory.
++ assert!(slave_name1.as_ptr() != slave_name2.as_ptr());
++}
++
++/// Test data copying of `ptsname_r`
++#[test]
++#[cfg(any(target_os = "android", target_os = "linux"))]
++fn test_ptsname_r_copy() {
++ // Open a new PTTY master
++ let master_fd = posix_openpt(OFlag::O_RDWR).unwrap();
++ assert!(master_fd.as_raw_fd() > 0);
++
++ // Get the name of the slave
++ let slave_name1 = ptsname_r(&master_fd).unwrap();
++ let slave_name2 = ptsname_r(&master_fd).unwrap();
++ assert!(slave_name1 == slave_name2);
++ assert!(slave_name1.as_ptr() != slave_name2.as_ptr());
++}
++
++/// Test that `ptsname` returns different names for different devices
++#[test]
++#[cfg(any(target_os = "android", target_os = "linux"))]
++fn test_ptsname_unique() {
++ let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++
++ // Open a new PTTY master
++ let master1_fd = posix_openpt(OFlag::O_RDWR).unwrap();
++ assert!(master1_fd.as_raw_fd() > 0);
++
++ // Open a second PTTY master
++ let master2_fd = posix_openpt(OFlag::O_RDWR).unwrap();
++ assert!(master2_fd.as_raw_fd() > 0);
++
++ // Get the name of the slave
++ let slave_name1 = unsafe { ptsname(&master1_fd) }.unwrap();
++ let slave_name2 = unsafe { ptsname(&master2_fd) }.unwrap();
++ assert!(slave_name1 != slave_name2);
++}
++
++/// Test opening a master/slave PTTY pair
++///
++/// This is a single larger test because much of these functions aren't useful by themselves. So for
++/// this test we perform the basic act of getting a file handle for a connect master/slave PTTY
++/// pair.
++#[test]
++fn test_open_ptty_pair() {
++ let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++
++ // Open a new PTTY master
++ let master_fd = posix_openpt(OFlag::O_RDWR).expect("posix_openpt failed");
++ assert!(master_fd.as_raw_fd() > 0);
++
++ // Allow a slave to be generated for it
++ grantpt(&master_fd).expect("grantpt failed");
++ unlockpt(&master_fd).expect("unlockpt failed");
++
++ // Get the name of the slave
++ let slave_name = unsafe { ptsname(&master_fd) }.expect("ptsname failed");
++
++ // Open the slave device
++ let slave_fd = open(Path::new(&slave_name), OFlag::O_RDWR, stat::Mode::empty()).unwrap();
++ assert!(slave_fd > 0);
++}
++
++#[test]
++fn test_openpty() {
++ // openpty uses ptname(3) internally
++ let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++
++ let pty = openpty(None, None).unwrap();
++ assert!(pty.master > 0);
++ assert!(pty.slave > 0);
++
++ // Writing to one should be readable on the other one
++ let string = "foofoofoo\n";
++ let mut buf = [0u8; 10];
++ write(pty.master, string.as_bytes()).unwrap();
++ ::read_exact(pty.slave, &mut buf);
++
++ assert_eq!(&buf, string.as_bytes());
++
++ // Read the echo as well
++ let echoed_string = "foofoofoo\r\n";
++ let mut buf = [0u8; 11];
++ ::read_exact(pty.master, &mut buf);
++ assert_eq!(&buf, echoed_string.as_bytes());
++
++ let string2 = "barbarbarbar\n";
++ let echoed_string2 = "barbarbarbar\r\n";
++ let mut buf = [0u8; 14];
++ write(pty.slave, string2.as_bytes()).unwrap();
++ ::read_exact(pty.master, &mut buf);
++
++ assert_eq!(&buf, echoed_string2.as_bytes());
++
++ close(pty.master).unwrap();
++ close(pty.slave).unwrap();
++}
++
++#[test]
++fn test_openpty_with_termios() {
++ // openpty uses ptname(3) internally
++ let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++
++ // Open one pty to get attributes for the second one
++ let mut termios = {
++ let pty = openpty(None, None).unwrap();
++ assert!(pty.master > 0);
++ assert!(pty.slave > 0);
++ let termios = tcgetattr(pty.master).unwrap();
++ close(pty.master).unwrap();
++ close(pty.slave).unwrap();
++ termios
++ };
++ // Make sure newlines are not transformed so the data is preserved when sent.
++ termios.output_flags.remove(OutputFlags::ONLCR);
++
++ let pty = openpty(None, &termios).unwrap();
++ // Must be valid file descriptors
++ assert!(pty.master > 0);
++ assert!(pty.slave > 0);
++
++ // Writing to one should be readable on the other one
++ let string = "foofoofoo\n";
++ let mut buf = [0u8; 10];
++ write(pty.master, string.as_bytes()).unwrap();
++ ::read_exact(pty.slave, &mut buf);
++
++ assert_eq!(&buf, string.as_bytes());
++
++ // read the echo as well
++ let echoed_string = "foofoofoo\n";
++ ::read_exact(pty.master, &mut buf);
++ assert_eq!(&buf, echoed_string.as_bytes());
++
++ let string2 = "barbarbarbar\n";
++ let echoed_string2 = "barbarbarbar\n";
++ let mut buf = [0u8; 13];
++ write(pty.slave, string2.as_bytes()).unwrap();
++ ::read_exact(pty.master, &mut buf);
++
++ assert_eq!(&buf, echoed_string2.as_bytes());
++
++ close(pty.master).unwrap();
++ close(pty.slave).unwrap();
++}
++
++#[test]
++fn test_forkpty() {
++ use nix::unistd::ForkResult::*;
++ use nix::sys::signal::*;
++ use nix::sys::wait::wait;
++ // forkpty calls openpty which uses ptname(3) internally.
++ let _m0 = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++ // forkpty spawns a child process
++ let _m1 = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++
++ let string = "naninani\n";
++ let echoed_string = "naninani\r\n";
++ let pty = forkpty(None, None).unwrap();
++ match pty.fork_result {
++ Child => {
++ write(STDOUT_FILENO, string.as_bytes()).unwrap();
++ pause(); // we need the child to stay alive until the parent calls read
++ unsafe { _exit(0); }
++ },
++ Parent { child } => {
++ let mut buf = [0u8; 10];
++ assert!(child.as_raw() > 0);
++ ::read_exact(pty.master, &mut buf);
++ kill(child, SIGTERM).unwrap();
++ wait().unwrap(); // keep other tests using generic wait from getting our child
++ assert_eq!(&buf, echoed_string.as_bytes());
++ close(pty.master).unwrap();
++ },
++ }
++}
+diff --git a/third_party/rust/nix-0.15.0/test/test_ptymaster_drop.rs b/third_party/rust/nix-0.15.0/test/test_ptymaster_drop.rs
+new file mode 100644
+index 0000000000000..9b59d66435ed0
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/test_ptymaster_drop.rs
+@@ -0,0 +1,21 @@
++extern crate nix;
++
++use nix::fcntl::OFlag;
++use nix::pty::*;
++use nix::unistd::close;
++use std::os::unix::io::AsRawFd;
++
++/// Regression test for Issue #659
++/// `PtyMaster` should panic rather than double close the file descriptor
++/// This must run in its own test process because it deliberately creates a race
++/// condition.
++#[test]
++#[should_panic(expected = "Closing an invalid file descriptor!")]
++// In Travis on i686-unknown-linux-musl, this test gets SIGABRT. I don't know
++// why. It doesn't happen on any other target, and it doesn't happen on my PC.
++#[cfg_attr(all(target_env = "musl", target_arch = "x86"), ignore)]
++fn test_double_close() {
++ let m = posix_openpt(OFlag::O_RDWR).unwrap();
++ close(m.as_raw_fd()).unwrap();
++ drop(m); // should panic here
++}
+diff --git a/third_party/rust/nix-0.15.0/test/test_sendfile.rs b/third_party/rust/nix-0.15.0/test/test_sendfile.rs
+new file mode 100644
+index 0000000000000..3bc7932f4c84f
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/test_sendfile.rs
+@@ -0,0 +1,129 @@
++use std::io::prelude::*;
++use std::os::unix::prelude::*;
++
++use libc::off_t;
++use nix::sys::sendfile::*;
++use tempfile::tempfile;
++
++cfg_if! {
++ if #[cfg(any(target_os = "android", target_os = "linux"))] {
++ use nix::unistd::{close, pipe, read};
++ } else if #[cfg(any(target_os = "freebsd", target_os = "ios", target_os = "macos"))] {
++ use std::net::Shutdown;
++ use std::os::unix::net::UnixStream;
++ }
++}
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++#[test]
++fn test_sendfile_linux() {
++ const CONTENTS: &[u8] = b"abcdef123456";
++ let mut tmp = tempfile().unwrap();
++ tmp.write_all(CONTENTS).unwrap();
++
++ let (rd, wr) = pipe().unwrap();
++ let mut offset: off_t = 5;
++ let res = sendfile(wr, tmp.as_raw_fd(), Some(&mut offset), 2).unwrap();
++
++ assert_eq!(2, res);
++
++ let mut buf = [0u8; 1024];
++ assert_eq!(2, read(rd, &mut buf).unwrap());
++ assert_eq!(b"f1", &buf[0..2]);
++ assert_eq!(7, offset);
++
++ close(rd).unwrap();
++ close(wr).unwrap();
++}
++
++#[cfg(target_os = "freebsd")]
++#[test]
++fn test_sendfile_freebsd() {
++ // Declare the content
++ let header_strings = vec!["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"];
++ let body = "Xabcdef123456";
++ let body_offset = 1;
++ let trailer_strings = vec!["\n", "Served by Make Believe\n"];
++
++ // Write the body to a file
++ let mut tmp = tempfile().unwrap();
++ tmp.write_all(body.as_bytes()).unwrap();
++
++ // Prepare headers and trailers for sendfile
++ let headers: Vec<&[u8]> = header_strings.iter().map(|s| s.as_bytes()).collect();
++ let trailers: Vec<&[u8]> = trailer_strings.iter().map(|s| s.as_bytes()).collect();
++
++ // Prepare socket pair
++ let (mut rd, wr) = UnixStream::pair().unwrap();
++
++ // Call the test method
++ let (res, bytes_written) = sendfile(
++ tmp.as_raw_fd(),
++ wr.as_raw_fd(),
++ body_offset as off_t,
++ None,
++ Some(headers.as_slice()),
++ Some(trailers.as_slice()),
++ SfFlags::empty(),
++ 0,
++ );
++ assert!(res.is_ok());
++ wr.shutdown(Shutdown::Both).unwrap();
++
++ // Prepare the expected result
++ let expected_string =
++ header_strings.concat() + &body[body_offset..] + &trailer_strings.concat();
++
++ // Verify the message that was sent
++ assert_eq!(bytes_written as usize, expected_string.as_bytes().len());
++
++ let mut read_string = String::new();
++ let bytes_read = rd.read_to_string(&mut read_string).unwrap();
++ assert_eq!(bytes_written as usize, bytes_read);
++ assert_eq!(expected_string, read_string);
++}
++
++#[cfg(any(target_os = "ios", target_os = "macos"))]
++#[test]
++fn test_sendfile_darwin() {
++ // Declare the content
++ let header_strings = vec!["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"];
++ let body = "Xabcdef123456";
++ let body_offset = 1;
++ let trailer_strings = vec!["\n", "Served by Make Believe\n"];
++
++ // Write the body to a file
++ let mut tmp = tempfile().unwrap();
++ tmp.write_all(body.as_bytes()).unwrap();
++
++ // Prepare headers and trailers for sendfile
++ let headers: Vec<&[u8]> = header_strings.iter().map(|s| s.as_bytes()).collect();
++ let trailers: Vec<&[u8]> = trailer_strings.iter().map(|s| s.as_bytes()).collect();
++
++ // Prepare socket pair
++ let (mut rd, wr) = UnixStream::pair().unwrap();
++
++ // Call the test method
++ let (res, bytes_written) = sendfile(
++ tmp.as_raw_fd(),
++ wr.as_raw_fd(),
++ body_offset as off_t,
++ None,
++ Some(headers.as_slice()),
++ Some(trailers.as_slice()),
++ );
++ assert!(res.is_ok());
++ wr.shutdown(Shutdown::Both).unwrap();
++
++ // Prepare the expected result
++ let expected_string =
++ header_strings.concat() + &body[body_offset..] + &trailer_strings.concat();
++
++ // Verify the message that was sent
++ assert_eq!(bytes_written as usize, expected_string.as_bytes().len());
++
++ let mut read_string = String::new();
++ let bytes_read = rd.read_to_string(&mut read_string).unwrap();
++ assert_eq!(bytes_written as usize, bytes_read);
++ assert_eq!(expected_string, read_string);
++}
+diff --git a/third_party/rust/nix-0.15.0/test/test_stat.rs b/third_party/rust/nix-0.15.0/test/test_stat.rs
+new file mode 100644
+index 0000000000000..1173455fae8db
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/test_stat.rs
+@@ -0,0 +1,296 @@
++use std::fs::{self, File};
++use std::os::unix::fs::{symlink, PermissionsExt};
++use std::os::unix::prelude::AsRawFd;
++use std::time::{Duration, UNIX_EPOCH};
++use std::path::Path;
++
++#[cfg(not(any(target_os = "netbsd")))]
++use libc::{S_IFMT, S_IFLNK, mode_t};
++
++use nix::{fcntl, Error};
++use nix::errno::{Errno};
++use nix::sys::stat::{self, fchmod, fchmodat, futimens, stat, utimes, utimensat, mkdirat};
++#[cfg(any(target_os = "linux",
++ target_os = "haiku",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "freebsd",
++ target_os = "netbsd"))]
++use nix::sys::stat::lutimes;
++use nix::sys::stat::{Mode, FchmodatFlags, UtimensatFlags};
++
++#[cfg(not(any(target_os = "netbsd")))]
++use nix::sys::stat::FileStat;
++
++use nix::sys::time::{TimeSpec, TimeVal, TimeValLike};
++use nix::unistd::chdir;
++
++#[cfg(not(any(target_os = "netbsd")))]
++use nix::Result;
++use tempfile;
++
++#[allow(unused_comparisons)]
++// uid and gid are signed on Windows, but not on other platforms. This function
++// allows warning free compiles on all platforms, and can be removed when
++// expression-level #[allow] is available.
++#[cfg(not(any(target_os = "netbsd")))]
++fn valid_uid_gid(stat: FileStat) -> bool {
++ // uid could be 0 for the `root` user. This quite possible when
++ // the tests are being run on a rooted Android device.
++ stat.st_uid >= 0 && stat.st_gid >= 0
++}
++
++#[cfg(not(any(target_os = "netbsd")))]
++fn assert_stat_results(stat_result: Result<FileStat>) {
++ let stats = stat_result.expect("stat call failed");
++ assert!(stats.st_dev > 0); // must be positive integer, exact number machine dependent
++ assert!(stats.st_ino > 0); // inode is positive integer, exact number machine dependent
++ assert!(stats.st_mode > 0); // must be positive integer
++ assert!(stats.st_nlink == 1); // there links created, must be 1
++ assert!(valid_uid_gid(stats)); // must be positive integers
++ assert!(stats.st_size == 0); // size is 0 because we did not write anything to the file
++ assert!(stats.st_blksize > 0); // must be positive integer, exact number machine dependent
++ assert!(stats.st_blocks <= 16); // Up to 16 blocks can be allocated for a blank file
++}
++
++#[cfg(not(any(target_os = "netbsd")))]
++fn assert_lstat_results(stat_result: Result<FileStat>) {
++ let stats = stat_result.expect("stat call failed");
++ assert!(stats.st_dev > 0); // must be positive integer, exact number machine dependent
++ assert!(stats.st_ino > 0); // inode is positive integer, exact number machine dependent
++ assert!(stats.st_mode > 0); // must be positive integer
++
++ // st_mode is c_uint (u32 on Android) while S_IFMT is mode_t
++ // (u16 on Android), and that will be a compile error.
++ // On other platforms they are the same (either both are u16 or u32).
++ assert!((stats.st_mode as usize) & (S_IFMT as usize) == S_IFLNK as usize); // should be a link
++ assert!(stats.st_nlink == 1); // there links created, must be 1
++ assert!(valid_uid_gid(stats)); // must be positive integers
++ assert!(stats.st_size > 0); // size is > 0 because it points to another file
++ assert!(stats.st_blksize > 0); // must be positive integer, exact number machine dependent
++
++ // st_blocks depends on whether the machine's file system uses fast
++ // or slow symlinks, so just make sure it's not negative
++ // (Android's st_blocks is ulonglong which is always non-negative.)
++ assert!(stats.st_blocks >= 0);
++}
++
++#[test]
++#[cfg(not(any(target_os = "netbsd")))]
++fn test_stat_and_fstat() {
++ use nix::sys::stat::fstat;
++
++ let tempdir = tempfile::tempdir().unwrap();
++ let filename = tempdir.path().join("foo.txt");
++ let file = File::create(&filename).unwrap();
++
++ let stat_result = stat(&filename);
++ assert_stat_results(stat_result);
++
++ let fstat_result = fstat(file.as_raw_fd());
++ assert_stat_results(fstat_result);
++}
++
++#[test]
++#[cfg(not(any(target_os = "netbsd")))]
++fn test_fstatat() {
++ let tempdir = tempfile::tempdir().unwrap();
++ let filename = tempdir.path().join("foo.txt");
++ File::create(&filename).unwrap();
++ let dirfd = fcntl::open(tempdir.path(),
++ fcntl::OFlag::empty(),
++ stat::Mode::empty());
++
++ let result = stat::fstatat(dirfd.unwrap(),
++ &filename,
++ fcntl::AtFlags::empty());
++ assert_stat_results(result);
++}
++
++#[test]
++#[cfg(not(any(target_os = "netbsd")))]
++fn test_stat_fstat_lstat() {
++ use nix::sys::stat::{fstat, lstat};
++
++ let tempdir = tempfile::tempdir().unwrap();
++ let filename = tempdir.path().join("bar.txt");
++ let linkname = tempdir.path().join("barlink");
++
++ File::create(&filename).unwrap();
++ symlink("bar.txt", &linkname).unwrap();
++ let link = File::open(&linkname).unwrap();
++
++ // should be the same result as calling stat,
++ // since it's a regular file
++ let stat_result = stat(&filename);
++ assert_stat_results(stat_result);
++
++ let lstat_result = lstat(&linkname);
++ assert_lstat_results(lstat_result);
++
++ let fstat_result = fstat(link.as_raw_fd());
++ assert_stat_results(fstat_result);
++}
++
++#[test]
++fn test_fchmod() {
++ let tempdir = tempfile::tempdir().unwrap();
++ let filename = tempdir.path().join("foo.txt");
++ let file = File::create(&filename).unwrap();
++
++ let mut mode1 = Mode::empty();
++ mode1.insert(Mode::S_IRUSR);
++ mode1.insert(Mode::S_IWUSR);
++ fchmod(file.as_raw_fd(), mode1).unwrap();
++
++ let file_stat1 = stat(&filename).unwrap();
++ assert_eq!(file_stat1.st_mode & 0o7777, mode1.bits());
++
++ let mut mode2 = Mode::empty();
++ mode2.insert(Mode::S_IROTH);
++ fchmod(file.as_raw_fd(), mode2).unwrap();
++
++ let file_stat2 = stat(&filename).unwrap();
++ assert_eq!(file_stat2.st_mode & 0o7777, mode2.bits());
++}
++
++#[test]
++fn test_fchmodat() {
++ let _dr = ::DirRestore::new();
++ let tempdir = tempfile::tempdir().unwrap();
++ let filename = "foo.txt";
++ let fullpath = tempdir.path().join(filename);
++ File::create(&fullpath).unwrap();
++
++ let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap();
++
++ let mut mode1 = Mode::empty();
++ mode1.insert(Mode::S_IRUSR);
++ mode1.insert(Mode::S_IWUSR);
++ fchmodat(Some(dirfd), filename, mode1, FchmodatFlags::FollowSymlink).unwrap();
++
++ let file_stat1 = stat(&fullpath).unwrap();
++ assert_eq!(file_stat1.st_mode & 0o7777, mode1.bits());
++
++ chdir(tempdir.path()).unwrap();
++
++ let mut mode2 = Mode::empty();
++ mode2.insert(Mode::S_IROTH);
++ fchmodat(None, filename, mode2, FchmodatFlags::FollowSymlink).unwrap();
++
++ let file_stat2 = stat(&fullpath).unwrap();
++ assert_eq!(file_stat2.st_mode & 0o7777, mode2.bits());
++}
++
++/// Asserts that the atime and mtime in a file's metadata match expected values.
++///
++/// The atime and mtime are expressed with a resolution of seconds because some file systems
++/// (like macOS's HFS+) do not have higher granularity.
++fn assert_times_eq(exp_atime_sec: u64, exp_mtime_sec: u64, attr: &fs::Metadata) {
++ assert_eq!(
++ Duration::new(exp_atime_sec, 0),
++ attr.accessed().unwrap().duration_since(UNIX_EPOCH).unwrap());
++ assert_eq!(
++ Duration::new(exp_mtime_sec, 0),
++ attr.modified().unwrap().duration_since(UNIX_EPOCH).unwrap());
++}
++
++#[test]
++fn test_utimes() {
++ let tempdir = tempfile::tempdir().unwrap();
++ let fullpath = tempdir.path().join("file");
++ drop(File::create(&fullpath).unwrap());
++
++ utimes(&fullpath, &TimeVal::seconds(9990), &TimeVal::seconds(5550)).unwrap();
++ assert_times_eq(9990, 5550, &fs::metadata(&fullpath).unwrap());
++}
++
++#[test]
++#[cfg(any(target_os = "linux",
++ target_os = "haiku",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "freebsd",
++ target_os = "netbsd"))]
++fn test_lutimes() {
++ let tempdir = tempfile::tempdir().unwrap();
++ let target = tempdir.path().join("target");
++ let fullpath = tempdir.path().join("symlink");
++ drop(File::create(&target).unwrap());
++ symlink(&target, &fullpath).unwrap();
++
++ let exp_target_metadata = fs::symlink_metadata(&target).unwrap();
++ lutimes(&fullpath, &TimeVal::seconds(4560), &TimeVal::seconds(1230)).unwrap();
++ assert_times_eq(4560, 1230, &fs::symlink_metadata(&fullpath).unwrap());
++
++ let target_metadata = fs::symlink_metadata(&target).unwrap();
++ assert_eq!(exp_target_metadata.accessed().unwrap(), target_metadata.accessed().unwrap(),
++ "atime of symlink target was unexpectedly modified");
++ assert_eq!(exp_target_metadata.modified().unwrap(), target_metadata.modified().unwrap(),
++ "mtime of symlink target was unexpectedly modified");
++}
++
++#[test]
++fn test_futimens() {
++ let tempdir = tempfile::tempdir().unwrap();
++ let fullpath = tempdir.path().join("file");
++ drop(File::create(&fullpath).unwrap());
++
++ let fd = fcntl::open(&fullpath, fcntl::OFlag::empty(), stat::Mode::empty()).unwrap();
++
++ futimens(fd, &TimeSpec::seconds(10), &TimeSpec::seconds(20)).unwrap();
++ assert_times_eq(10, 20, &fs::metadata(&fullpath).unwrap());
++}
++
++#[test]
++fn test_utimensat() {
++ let _dr = ::DirRestore::new();
++ let tempdir = tempfile::tempdir().unwrap();
++ let filename = "foo.txt";
++ let fullpath = tempdir.path().join(filename);
++ drop(File::create(&fullpath).unwrap());
++
++ let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap();
++
++ utimensat(Some(dirfd), filename, &TimeSpec::seconds(12345), &TimeSpec::seconds(678),
++ UtimensatFlags::FollowSymlink).unwrap();
++ assert_times_eq(12345, 678, &fs::metadata(&fullpath).unwrap());
++
++ chdir(tempdir.path()).unwrap();
++
++ utimensat(None, filename, &TimeSpec::seconds(500), &TimeSpec::seconds(800),
++ UtimensatFlags::FollowSymlink).unwrap();
++ assert_times_eq(500, 800, &fs::metadata(&fullpath).unwrap());
++}
++
++#[test]
++fn test_mkdirat_success_path() {
++ let tempdir = tempfile::tempdir().unwrap();
++ let filename = "example_subdir";
++ let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap();
++ assert!((mkdirat(dirfd, filename, Mode::S_IRWXU)).is_ok());
++ assert!(Path::exists(&tempdir.path().join(filename)));
++}
++
++#[test]
++fn test_mkdirat_success_mode() {
++ let expected_bits = stat::SFlag::S_IFDIR.bits() | stat::Mode::S_IRWXU.bits();
++ let tempdir = tempfile::tempdir().unwrap();
++ let filename = "example_subdir";
++ let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap();
++ assert!((mkdirat(dirfd, filename, Mode::S_IRWXU)).is_ok());
++ let permissions = fs::metadata(tempdir.path().join(filename)).unwrap().permissions();
++ let mode = permissions.mode();
++ assert_eq!(mode as mode_t, expected_bits)
++}
++
++#[test]
++fn test_mkdirat_fail() {
++ let tempdir = tempfile::tempdir().unwrap();
++ let not_dir_filename= "example_not_dir";
++ let filename = "example_subdir_dir";
++ let dirfd = fcntl::open(&tempdir.path().join(not_dir_filename), fcntl::OFlag::O_CREAT,
++ stat::Mode::empty()).unwrap();
++ let result = mkdirat(dirfd, filename, Mode::S_IRWXU).unwrap_err();
++ assert_eq!(result, Error::Sys(Errno::ENOTDIR));
++}
+diff --git a/third_party/rust/nix-0.15.0/test/test_unistd.rs b/third_party/rust/nix-0.15.0/test/test_unistd.rs
+new file mode 100644
+index 0000000000000..46196dec7ccce
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/test_unistd.rs
+@@ -0,0 +1,669 @@
++use nix::fcntl::{self, fcntl, FcntlArg, FdFlag, open, OFlag, readlink};
++use nix::unistd::*;
++use nix::unistd::ForkResult::*;
++use nix::sys::signal::{SaFlags, SigAction, SigHandler, SigSet, Signal, sigaction};
++use nix::sys::wait::*;
++use nix::sys::stat::{self, Mode, SFlag};
++use nix::errno::Errno;
++use nix::Error;
++use std::{env, iter};
++use std::ffi::CString;
++use std::fs::{self, DirBuilder, File};
++use std::io::Write;
++use std::os::unix::prelude::*;
++use tempfile::{self, tempfile};
++use libc::{self, _exit, off_t};
++
++#[test]
++#[cfg(not(any(target_os = "netbsd")))]
++fn test_fork_and_waitpid() {
++ let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++
++ // Safe: Child only calls `_exit`, which is signal-safe
++ match fork().expect("Error: Fork Failed") {
++ Child => unsafe { _exit(0) },
++ Parent { child } => {
++ // assert that child was created and pid > 0
++ let child_raw: ::libc::pid_t = child.into();
++ assert!(child_raw > 0);
++ let wait_status = waitpid(child, None);
++ match wait_status {
++ // assert that waitpid returned correct status and the pid is the one of the child
++ Ok(WaitStatus::Exited(pid_t, _)) => assert!(pid_t == child),
++
++ // panic, must never happen
++ s @ Ok(_) => panic!("Child exited {:?}, should never happen", s),
++
++ // panic, waitpid should never fail
++ Err(s) => panic!("Error: waitpid returned Err({:?}", s)
++ }
++
++ },
++ }
++}
++
++#[test]
++fn test_wait() {
++ // Grab FORK_MTX so wait doesn't reap a different test's child process
++ let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++
++ // Safe: Child only calls `_exit`, which is signal-safe
++ match fork().expect("Error: Fork Failed") {
++ Child => unsafe { _exit(0) },
++ Parent { child } => {
++ let wait_status = wait();
++
++ // just assert that (any) one child returns with WaitStatus::Exited
++ assert_eq!(wait_status, Ok(WaitStatus::Exited(child, 0)));
++ },
++ }
++}
++
++#[test]
++fn test_mkstemp() {
++ let mut path = env::temp_dir();
++ path.push("nix_tempfile.XXXXXX");
++
++ let result = mkstemp(&path);
++ match result {
++ Ok((fd, path)) => {
++ close(fd).unwrap();
++ unlink(path.as_path()).unwrap();
++ },
++ Err(e) => panic!("mkstemp failed: {}", e)
++ }
++}
++
++#[test]
++fn test_mkstemp_directory() {
++ // mkstemp should fail if a directory is given
++ assert!(mkstemp(&env::temp_dir()).is_err());
++}
++
++#[test]
++fn test_mkfifo() {
++ let tempdir = tempfile::tempdir().unwrap();
++ let mkfifo_fifo = tempdir.path().join("mkfifo_fifo");
++
++ mkfifo(&mkfifo_fifo, Mode::S_IRUSR).unwrap();
++
++ let stats = stat::stat(&mkfifo_fifo).unwrap();
++ let typ = stat::SFlag::from_bits_truncate(stats.st_mode);
++ assert!(typ == SFlag::S_IFIFO);
++}
++
++#[test]
++fn test_mkfifo_directory() {
++ // mkfifo should fail if a directory is given
++ assert!(mkfifo(&env::temp_dir(), Mode::S_IRUSR).is_err());
++}
++
++#[test]
++fn test_getpid() {
++ let pid: ::libc::pid_t = getpid().into();
++ let ppid: ::libc::pid_t = getppid().into();
++ assert!(pid > 0);
++ assert!(ppid > 0);
++}
++
++#[test]
++fn test_getsid() {
++ let none_sid: ::libc::pid_t = getsid(None).unwrap().into();
++ let pid_sid: ::libc::pid_t = getsid(Some(getpid())).unwrap().into();
++ assert!(none_sid > 0);
++ assert!(none_sid == pid_sid);
++}
++
++#[cfg(any(target_os = "linux", target_os = "android"))]
++mod linux_android {
++ use nix::unistd::gettid;
++
++ #[test]
++ fn test_gettid() {
++ let tid: ::libc::pid_t = gettid().into();
++ assert!(tid > 0);
++ }
++}
++
++#[test]
++// `getgroups()` and `setgroups()` do not behave as expected on Apple platforms
++#[cfg(not(any(target_os = "ios", target_os = "macos")))]
++fn test_setgroups() {
++ // Skip this test when not run as root as `setgroups()` requires root.
++ skip_if_not_root!("test_setgroups");
++
++ let _m = ::GROUPS_MTX.lock().expect("Mutex got poisoned by another test");
++
++ // Save the existing groups
++ let old_groups = getgroups().unwrap();
++
++ // Set some new made up groups
++ let groups = [Gid::from_raw(123), Gid::from_raw(456)];
++ setgroups(&groups).unwrap();
++
++ let new_groups = getgroups().unwrap();
++ assert_eq!(new_groups, groups);
++
++ // Revert back to the old groups
++ setgroups(&old_groups).unwrap();
++}
++
++#[test]
++// `getgroups()` and `setgroups()` do not behave as expected on Apple platforms
++#[cfg(not(any(target_os = "ios", target_os = "macos")))]
++fn test_initgroups() {
++ // Skip this test when not run as root as `initgroups()` and `setgroups()`
++ // require root.
++ skip_if_not_root!("test_initgroups");
++
++ let _m = ::GROUPS_MTX.lock().expect("Mutex got poisoned by another test");
++
++ // Save the existing groups
++ let old_groups = getgroups().unwrap();
++
++ // It doesn't matter if the root user is not called "root" or if a user
++ // called "root" doesn't exist. We are just checking that the extra,
++ // made-up group, `123`, is set.
++ // FIXME: Test the other half of initgroups' functionality: whether the
++ // groups that the user belongs to are also set.
++ let user = CString::new("root").unwrap();
++ let group = Gid::from_raw(123);
++ let group_list = getgrouplist(&user, group).unwrap();
++ assert!(group_list.contains(&group));
++
++ initgroups(&user, group).unwrap();
++
++ let new_groups = getgroups().unwrap();
++ assert_eq!(new_groups, group_list);
++
++ // Revert back to the old groups
++ setgroups(&old_groups).unwrap();
++}
++
++macro_rules! execve_test_factory(
++ ($test_name:ident, $syscall:ident, $exe: expr $(, $pathname:expr, $flags:expr)*) => (
++ #[test]
++ fn $test_name() {
++ let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++ // The `exec`d process will write to `writer`, and we'll read that
++ // data from `reader`.
++ let (reader, writer) = pipe().unwrap();
++
++ // Safe: Child calls `exit`, `dup`, `close` and the provided `exec*` family function.
++ // NOTE: Technically, this makes the macro unsafe to use because you could pass anything.
++ // The tests make sure not to do that, though.
++ match fork().unwrap() {
++ Child => {
++ // Close stdout.
++ close(1).unwrap();
++ // Make `writer` be the stdout of the new process.
++ dup(writer).unwrap();
++ // exec!
++ $syscall(
++ $exe,
++ $(&CString::new($pathname).unwrap(), )*
++ &[CString::new(b"".as_ref()).unwrap(),
++ CString::new(b"-c".as_ref()).unwrap(),
++ CString::new(b"echo nix!!! && echo foo=$foo && echo baz=$baz"
++ .as_ref()).unwrap()],
++ &[CString::new(b"foo=bar".as_ref()).unwrap(),
++ CString::new(b"baz=quux".as_ref()).unwrap()]
++ $(, $flags)*).unwrap();
++ },
++ Parent { child } => {
++ // Wait for the child to exit.
++ waitpid(child, None).unwrap();
++ // Read 1024 bytes.
++ let mut buf = [0u8; 1024];
++ read(reader, &mut buf).unwrap();
++ // It should contain the things we printed using `/bin/sh`.
++ let string = String::from_utf8_lossy(&buf);
++ assert!(string.contains("nix!!!"));
++ assert!(string.contains("foo=bar"));
++ assert!(string.contains("baz=quux"));
++ }
++ }
++ }
++ )
++);
++
++cfg_if!{
++ if #[cfg(target_os = "android")] {
++ execve_test_factory!(test_execve, execve, &CString::new("/system/bin/sh").unwrap());
++ execve_test_factory!(test_fexecve, fexecve, File::open("/system/bin/sh").unwrap().into_raw_fd());
++ } else if #[cfg(any(target_os = "freebsd",
++ target_os = "linux"))] {
++ execve_test_factory!(test_execve, execve, &CString::new("/bin/sh").unwrap());
++ execve_test_factory!(test_fexecve, fexecve, File::open("/bin/sh").unwrap().into_raw_fd());
++ } else if #[cfg(any(target_os = "dragonfly",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "openbsd"))] {
++ execve_test_factory!(test_execve, execve, &CString::new("/bin/sh").unwrap());
++ // No fexecve() on DragonFly, ios, macos, NetBSD, OpenBSD.
++ //
++ // Note for NetBSD and OpenBSD: although rust-lang/libc includes it
++ // (under unix/bsd/netbsdlike/) fexecve is not currently implemented on
++ // NetBSD nor on OpenBSD.
++ }
++}
++
++#[cfg(any(target_os = "haiku", target_os = "linux", target_os = "openbsd"))]
++execve_test_factory!(test_execvpe, execvpe, &CString::new("sh").unwrap());
++
++cfg_if!{
++ if #[cfg(target_os = "android")] {
++ use nix::fcntl::AtFlags;
++ execve_test_factory!(test_execveat_empty, execveat, File::open("/system/bin/sh").unwrap().into_raw_fd(),
++ "", AtFlags::AT_EMPTY_PATH);
++ execve_test_factory!(test_execveat_relative, execveat, File::open("/system/bin/").unwrap().into_raw_fd(),
++ "./sh", AtFlags::empty());
++ execve_test_factory!(test_execveat_absolute, execveat, File::open("/").unwrap().into_raw_fd(),
++ "/system/bin/sh", AtFlags::empty());
++ } else if #[cfg(all(target_os = "linux"), any(target_arch ="x86_64", target_arch ="x86"))] {
++ use nix::fcntl::AtFlags;
++ execve_test_factory!(test_execveat_empty, execveat, File::open("/bin/sh").unwrap().into_raw_fd(),
++ "", AtFlags::AT_EMPTY_PATH);
++ execve_test_factory!(test_execveat_relative, execveat, File::open("/bin/").unwrap().into_raw_fd(),
++ "./sh", AtFlags::empty());
++ execve_test_factory!(test_execveat_absolute, execveat, File::open("/").unwrap().into_raw_fd(),
++ "/bin/sh", AtFlags::empty());
++ }
++}
++
++#[test]
++fn test_fchdir() {
++ // fchdir changes the process's cwd
++ let _dr = ::DirRestore::new();
++
++ let tmpdir = tempfile::tempdir().unwrap();
++ let tmpdir_path = tmpdir.path().canonicalize().unwrap();
++ let tmpdir_fd = File::open(&tmpdir_path).unwrap().into_raw_fd();
++
++ assert!(fchdir(tmpdir_fd).is_ok());
++ assert_eq!(getcwd().unwrap(), tmpdir_path);
++
++ assert!(close(tmpdir_fd).is_ok());
++}
++
++#[test]
++fn test_getcwd() {
++ // chdir changes the process's cwd
++ let _dr = ::DirRestore::new();
++
++ let tmpdir = tempfile::tempdir().unwrap();
++ let tmpdir_path = tmpdir.path().canonicalize().unwrap();
++ assert!(chdir(&tmpdir_path).is_ok());
++ assert_eq!(getcwd().unwrap(), tmpdir_path);
++
++ // make path 500 chars longer so that buffer doubling in getcwd
++ // kicks in. Note: One path cannot be longer than 255 bytes
++ // (NAME_MAX) whole path cannot be longer than PATH_MAX (usually
++ // 4096 on linux, 1024 on macos)
++ let mut inner_tmp_dir = tmpdir_path.to_path_buf();
++ for _ in 0..5 {
++ let newdir = iter::repeat("a").take(100).collect::<String>();
++ inner_tmp_dir.push(newdir);
++ assert!(mkdir(inner_tmp_dir.as_path(), Mode::S_IRWXU).is_ok());
++ }
++ assert!(chdir(inner_tmp_dir.as_path()).is_ok());
++ assert_eq!(getcwd().unwrap(), inner_tmp_dir.as_path());
++}
++
++#[test]
++fn test_chown() {
++ // Testing for anything other than our own UID/GID is hard.
++ let uid = Some(getuid());
++ let gid = Some(getgid());
++
++ let tempdir = tempfile::tempdir().unwrap();
++ let path = tempdir.path().join("file");
++ {
++ File::create(&path).unwrap();
++ }
++
++ chown(&path, uid, gid).unwrap();
++ chown(&path, uid, None).unwrap();
++ chown(&path, None, gid).unwrap();
++
++ fs::remove_file(&path).unwrap();
++ chown(&path, uid, gid).unwrap_err();
++}
++
++#[test]
++fn test_fchownat() {
++ let _dr = ::DirRestore::new();
++ // Testing for anything other than our own UID/GID is hard.
++ let uid = Some(getuid());
++ let gid = Some(getgid());
++
++ let tempdir = tempfile::tempdir().unwrap();
++ let path = tempdir.path().join("file");
++ {
++ File::create(&path).unwrap();
++ }
++
++ let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap();
++
++ fchownat(Some(dirfd), "file", uid, gid, FchownatFlags::FollowSymlink).unwrap();
++
++ chdir(tempdir.path()).unwrap();
++ fchownat(None, "file", uid, gid, FchownatFlags::FollowSymlink).unwrap();
++
++ fs::remove_file(&path).unwrap();
++ fchownat(None, "file", uid, gid, FchownatFlags::FollowSymlink).unwrap_err();
++}
++
++#[test]
++fn test_lseek() {
++ const CONTENTS: &[u8] = b"abcdef123456";
++ let mut tmp = tempfile().unwrap();
++ tmp.write_all(CONTENTS).unwrap();
++ let tmpfd = tmp.into_raw_fd();
++
++ let offset: off_t = 5;
++ lseek(tmpfd, offset, Whence::SeekSet).unwrap();
++
++ let mut buf = [0u8; 7];
++ ::read_exact(tmpfd, &mut buf);
++ assert_eq!(b"f123456", &buf);
++
++ close(tmpfd).unwrap();
++}
++
++#[cfg(any(target_os = "linux", target_os = "android"))]
++#[test]
++fn test_lseek64() {
++ const CONTENTS: &[u8] = b"abcdef123456";
++ let mut tmp = tempfile().unwrap();
++ tmp.write_all(CONTENTS).unwrap();
++ let tmpfd = tmp.into_raw_fd();
++
++ lseek64(tmpfd, 5, Whence::SeekSet).unwrap();
++
++ let mut buf = [0u8; 7];
++ ::read_exact(tmpfd, &mut buf);
++ assert_eq!(b"f123456", &buf);
++
++ close(tmpfd).unwrap();
++}
++
++cfg_if!{
++ if #[cfg(any(target_os = "android", target_os = "linux"))] {
++ macro_rules! require_acct{
++ () => {
++ require_capability!(CAP_SYS_PACCT);
++ }
++ }
++ } else if #[cfg(target_os = "freebsd")] {
++ macro_rules! require_acct{
++ () => {
++ skip_if_not_root!("test_acct");
++ skip_if_jailed!("test_acct");
++ }
++ }
++ } else {
++ macro_rules! require_acct{
++ () => {
++ skip_if_not_root!("test_acct");
++ }
++ }
++ }
++}
++
++#[test]
++fn test_acct() {
++ use tempfile::NamedTempFile;
++ use std::process::Command;
++ use std::{thread, time};
++
++ let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++ require_acct!();
++
++ let file = NamedTempFile::new().unwrap();
++ let path = file.path().to_str().unwrap();
++
++ acct::enable(path).unwrap();
++
++ loop {
++ Command::new("echo").arg("Hello world");
++ let len = fs::metadata(path).unwrap().len();
++ if len > 0 { break; }
++ thread::sleep(time::Duration::from_millis(10));
++ }
++ acct::disable().unwrap();
++}
++
++#[test]
++fn test_fpathconf_limited() {
++ let f = tempfile().unwrap();
++ // AFAIK, PATH_MAX is limited on all platforms, so it makes a good test
++ let path_max = fpathconf(f.as_raw_fd(), PathconfVar::PATH_MAX);
++ assert!(path_max.expect("fpathconf failed").expect("PATH_MAX is unlimited") > 0);
++}
++
++#[test]
++fn test_pathconf_limited() {
++ // AFAIK, PATH_MAX is limited on all platforms, so it makes a good test
++ let path_max = pathconf("/", PathconfVar::PATH_MAX);
++ assert!(path_max.expect("pathconf failed").expect("PATH_MAX is unlimited") > 0);
++}
++
++#[test]
++fn test_sysconf_limited() {
++ // AFAIK, OPEN_MAX is limited on all platforms, so it makes a good test
++ let open_max = sysconf(SysconfVar::OPEN_MAX);
++ assert!(open_max.expect("sysconf failed").expect("OPEN_MAX is unlimited") > 0);
++}
++
++#[cfg(target_os = "freebsd")]
++#[test]
++fn test_sysconf_unsupported() {
++ // I know of no sysconf variables that are unsupported everywhere, but
++ // _XOPEN_CRYPT is unsupported on FreeBSD 11.0, which is one of the platforms
++ // we test.
++ let open_max = sysconf(SysconfVar::_XOPEN_CRYPT);
++ assert!(open_max.expect("sysconf failed").is_none())
++}
++
++// Test that we can create a pair of pipes. No need to verify that they pass
++// data; that's the domain of the OS, not nix.
++#[test]
++fn test_pipe() {
++ let (fd0, fd1) = pipe().unwrap();
++ let m0 = stat::SFlag::from_bits_truncate(stat::fstat(fd0).unwrap().st_mode);
++ // S_IFIFO means it's a pipe
++ assert_eq!(m0, SFlag::S_IFIFO);
++ let m1 = stat::SFlag::from_bits_truncate(stat::fstat(fd1).unwrap().st_mode);
++ assert_eq!(m1, SFlag::S_IFIFO);
++}
++
++// pipe2(2) is the same as pipe(2), except it allows setting some flags. Check
++// that we can set a flag.
++#[test]
++fn test_pipe2() {
++ let (fd0, fd1) = pipe2(OFlag::O_CLOEXEC).unwrap();
++ let f0 = FdFlag::from_bits_truncate(fcntl(fd0, FcntlArg::F_GETFD).unwrap());
++ assert!(f0.contains(FdFlag::FD_CLOEXEC));
++ let f1 = FdFlag::from_bits_truncate(fcntl(fd1, FcntlArg::F_GETFD).unwrap());
++ assert!(f1.contains(FdFlag::FD_CLOEXEC));
++}
++
++#[test]
++fn test_truncate() {
++ let tempdir = tempfile::tempdir().unwrap();
++ let path = tempdir.path().join("file");
++
++ {
++ let mut tmp = File::create(&path).unwrap();
++ const CONTENTS: &[u8] = b"12345678";
++ tmp.write_all(CONTENTS).unwrap();
++ }
++
++ truncate(&path, 4).unwrap();
++
++ let metadata = fs::metadata(&path).unwrap();
++ assert_eq!(4, metadata.len());
++}
++
++#[test]
++fn test_ftruncate() {
++ let tempdir = tempfile::tempdir().unwrap();
++ let path = tempdir.path().join("file");
++
++ let tmpfd = {
++ let mut tmp = File::create(&path).unwrap();
++ const CONTENTS: &[u8] = b"12345678";
++ tmp.write_all(CONTENTS).unwrap();
++ tmp.into_raw_fd()
++ };
++
++ ftruncate(tmpfd, 2).unwrap();
++ close(tmpfd).unwrap();
++
++ let metadata = fs::metadata(&path).unwrap();
++ assert_eq!(2, metadata.len());
++}
++
++// Used in `test_alarm`.
++static mut ALARM_CALLED: bool = false;
++
++// Used in `test_alarm`.
++pub extern fn alarm_signal_handler(raw_signal: libc::c_int) {
++ assert_eq!(raw_signal, libc::SIGALRM, "unexpected signal: {}", raw_signal);
++ unsafe { ALARM_CALLED = true };
++}
++
++#[test]
++fn test_alarm() {
++ let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
++
++ let handler = SigHandler::Handler(alarm_signal_handler);
++ let signal_action = SigAction::new(handler, SaFlags::SA_RESTART, SigSet::empty());
++ let old_handler = unsafe {
++ sigaction(Signal::SIGALRM, &signal_action)
++ .expect("unable to set signal handler for alarm")
++ };
++
++ // Set an alarm.
++ assert_eq!(alarm::set(60), None);
++
++ // Overwriting an alarm should return the old alarm.
++ assert_eq!(alarm::set(1), Some(60));
++
++ // We should be woken up after 1 second by the alarm, so we'll sleep for 2
++ // seconds to be sure.
++ sleep(2);
++ assert_eq!(unsafe { ALARM_CALLED }, true, "expected our alarm signal handler to be called");
++
++ // Reset the signal.
++ unsafe {
++ sigaction(Signal::SIGALRM, &old_handler)
++ .expect("unable to set signal handler for alarm");
++ }
++}
++
++#[test]
++fn test_canceling_alarm() {
++ let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
++
++ assert_eq!(alarm::cancel(), None);
++
++ assert_eq!(alarm::set(60), None);
++ assert_eq!(alarm::cancel(), Some(60));
++}
++
++#[test]
++fn test_symlinkat() {
++ let mut buf = [0; 1024];
++ let tempdir = tempfile::tempdir().unwrap();
++
++ let target = tempdir.path().join("a");
++ let linkpath = tempdir.path().join("b");
++ symlinkat(&target, None, &linkpath).unwrap();
++ assert_eq!(
++ readlink(&linkpath, &mut buf).unwrap().to_str().unwrap(),
++ target.to_str().unwrap()
++ );
++
++ let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap();
++ let target = "c";
++ let linkpath = "d";
++ symlinkat(target, Some(dirfd), linkpath).unwrap();
++ assert_eq!(
++ readlink(&tempdir.path().join(linkpath), &mut buf)
++ .unwrap()
++ .to_str()
++ .unwrap(),
++ target
++ );
++}
++
++
++#[test]
++fn test_unlinkat_dir_noremovedir() {
++ let tempdir = tempfile::tempdir().unwrap();
++ let dirname = "foo_dir";
++ let dirpath = tempdir.path().join(dirname);
++
++ // Create dir
++ DirBuilder::new().recursive(true).create(&dirpath).unwrap();
++
++ // Get file descriptor for base directory
++ let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap();
++
++ // Attempt unlink dir at relative path without proper flag
++ let err_result = unlinkat(Some(dirfd), dirname, UnlinkatFlags::NoRemoveDir).unwrap_err();
++ assert!(err_result == Error::Sys(Errno::EISDIR) || err_result == Error::Sys(Errno::EPERM));
++ }
++
++#[test]
++fn test_unlinkat_dir_removedir() {
++ let tempdir = tempfile::tempdir().unwrap();
++ let dirname = "foo_dir";
++ let dirpath = tempdir.path().join(dirname);
++
++ // Create dir
++ DirBuilder::new().recursive(true).create(&dirpath).unwrap();
++
++ // Get file descriptor for base directory
++ let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap();
++
++ // Attempt unlink dir at relative path with proper flag
++ unlinkat(Some(dirfd), dirname, UnlinkatFlags::RemoveDir).unwrap();
++ assert!(!dirpath.exists());
++ }
++
++#[test]
++fn test_unlinkat_file() {
++ let tempdir = tempfile::tempdir().unwrap();
++ let filename = "foo.txt";
++ let filepath = tempdir.path().join(filename);
++
++ // Create file
++ File::create(&filepath).unwrap();
++
++ // Get file descriptor for base directory
++ let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap();
++
++ // Attempt unlink file at relative path
++ unlinkat(Some(dirfd), filename, UnlinkatFlags::NoRemoveDir).unwrap();
++ assert!(!filepath.exists());
++ }
++
++#[test]
++fn test_access_not_existing() {
++ let tempdir = tempfile::tempdir().unwrap();
++ let dir = tempdir.path().join("does_not_exist.txt");
++ assert_eq!(access(&dir, AccessFlags::F_OK).err().unwrap().as_errno().unwrap(),
++ Errno::ENOENT);
++}
++
++#[test]
++fn test_access_file_exists() {
++ let tempdir = tempfile::tempdir().unwrap();
++ let path = tempdir.path().join("does_exist.txt");
++ let _file = File::create(path.clone()).unwrap();
++ assert!(access(&path, AccessFlags::R_OK | AccessFlags::W_OK).is_ok());
++}
+diff --git a/third_party/rust/nix/.cargo-checksum.json b/third_party/rust/nix/.cargo-checksum.json
+index e5f2bc789185a..85adbc1eae931 100644
+--- a/third_party/rust/nix/.cargo-checksum.json
++++ b/third_party/rust/nix/.cargo-checksum.json
+@@ -1 +1 @@
+-{"files":{"CHANGELOG.md":"91af9fd5f2d9cdb9c8bb750e24b625742e95a6c74bcff419f3de70eb26578281","CONTRIBUTING.md":"a9101e3d1487170d691d5f062ff49a433c167582ac8984dd41a744be92652f74","CONVENTIONS.md":"e150ce43c1d188c392c1a3bf7f2e08e3cf84906705c7bef43f319037d29ea385","Cargo.toml":"af0cc0ae7ff4bf6c2e5b35fe062f54fe2d619f70ba67795f4f43a981420b5de0","LICENSE":"66e3ee1fa7f909ad3c612d556f2a0cdabcd809ad6e66f3b0605015ac64841b70","README.md":"80d71b9eaac7bf7f0d307372592ed1467f994291e6fad816a44f3c70e2887d0f","build.rs":"14c9c678c33f5894509da47f77d6a326b14aecb4190ce87a24cce98687ca63b2","src/dir.rs":"21e330cbe6594274335b94d9e9b6059f1fa8e53d2e5b5c697058c52ec6b3c5ff","src/errno.rs":"a009ccf18b45c0a4c9319c65b0dc5bc322d9ad43cfe462ec4661559f44162451","src/errno_dragonfly.c":"a857e47b114acb85fddcb252a610ab5734d225c26b7bedd7c35d7789d46c8526","src/fcntl.rs":"6ae2f7f01dd2568b82a4e57f86e02b1d63eec6c26111c5adb2ca5d78a2a99fe7","src/features.rs":"22ff626ff8287a07dd55bcfc63c9f518c19c56144e15f9b6f9e3bbdcda51c2a8","src/ifaddrs.rs":"9a93de176edcca4613e668b8ccc2c3e3b6b711aa2d8d94ccb0ba08694d1ef35f","src/kmod.rs":"4d8a695d3d761f351a39d654303a1bd168e74295b7d142b918737e355b24f34d","src/lib.rs":"fdd8049a79ffb92384c72f0a6b0bab717001ddfa9b01f2b33413c83f424f2ac8","src/macros.rs":"aec27fa0fd98900913fada926c9a4581cd28f2640e3a7b5480707f923c9200f8","src/mount.rs":"cdf5db8409017483132db9d7493b5d6cc96df5560d0fa5ad8f385aff72db10ca","src/mqueue.rs":"82af42b31381af73e7966f845d1ed93957f0b9976bf2da524b178fad15b2b08d","src/net/if_.rs":"f7e02076fcf3cadf3fdf141884c9bd2c468a7047ba60bc490f0057df802b53ce","src/net/mod.rs":"577f70170e53d4a6de1abb70bf8f1031ec3e65c0e63ef5fcf05c907125e7ac17","src/poll.rs":"7305e250066cd1a7318cd239ed3db787937ee98426fe9289cf00fa874d76b6c7","src/pty.rs":"6b965b586579933af47d4efef4c82c391b927037eaa08d8c83fc974ef17fc7c8","src/sched.rs":"f9b214fa60006b5450ffb3589a55ec59c3694bd49597c65c38ac813fcd96c7dd","src/sys/aio.rs":"a1ba629258b3ce1268e5fe8e5b41dce3581f77d415dc5e2455c1f82f26dd3085","src/sys/epoll.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":"8a7eacfc172b55763ae32109bf9b252669ba68b72cd5122f7504eb35c0c08345","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":"c663505d6a7a7ae9d76e03fbc17e53d308ea6b1eae92212812e1d76b2bf2916f","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":"84ae63c2baa49eebeabe5bbd347b9c5417e14ba97f342719d753dc1c1c768d60","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":"0219f7bce0603f97d997fb377ca071966c90333ecc665e78a54dfeb97a9c811b","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":"1dc420d3119bf4d863a7ae0ba63efa7f1416f6e46e4100ea161003fe1c3f66ba","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/kmod.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/event.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":"feced79575c5dbeaf0a0877ba888761675310b277f477acee820c785e132dbe9","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":"42b335e7a2e2b8cf160506524490bb685bd2488ebff65921aa10f60363ffda7b","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/ucontext.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":"ae915c03e4f64ce370ae46f5dbe37834dae2849bb9fa7961872cec50f45de1f4","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":"ec6d580b87292519d514b0236bdd5abdd576fcf4835cfe49ed1ddb47c5f1aea3","test/test_nix_path.rs":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","test/test_poll.rs":"fbcf1780447f75a0177b4f47ba3d99b68f4324059ff66d993034ae5035c6d3ef","test/test_pty.rs":"56198cb9537ec3409717acecb133a49eb48bfc180c135ff0296974ec466d1171","test/test_ptymaster_drop.rs":"d162510cc96b8b7389d8bc34e097db1c80b84b5070c1d16f15b053ffd20cfa17","test/test_sched.rs":"f8ad92eb554164b0f92428f716db99040186d741cc6e1976f7930f099652f70c","test/test_sendfile.rs":"e0cbabbd34052ccaa03d6555d5631686aa076728f6378ee90f7ecec68f891144","test/test_stat.rs":"9668fc1f894b7f8a60dfddbdaef4bc833463e4e0cf04c1cff7f8c0569a226ad2","test/test_time.rs":"199b1c89d373e9398cca97f83ecd6459c6bd5ba7adca28013d9109d5cbad03f3","test/test_unistd.rs":"9bf047d877fd7c0826a2241737574923c3fd102a6b143b6d9710f52af5655588"},"package":"f5e06129fb611568ef4e868c14b326274959aa70ff7776e9d55323531c374945"}
+\ No newline at end of file
+diff --git a/third_party/rust/nix/CHANGELOG.md b/third_party/rust/nix/CHANGELOG.md
+index d93a5ce6bbfc9..234f2307c6d36 100644
+--- a/third_party/rust/nix/CHANGELOG.md
++++ b/third_party/rust/nix/CHANGELOG.md
+@@ -2,12 +2,316 @@
+
+ All notable changes to this project will be documented in this file.
+ This project adheres to [Semantic Versioning](http://semver.org/).
++This project adheres to [Semantic Versioning](https://semver.org/).
+
+-## [Unreleased] - ReleaseDate
++## [0.20.2] - 28 September 2021
+ ### Added
+ ### Changed
+ ### Fixed
++
++- Fixed buffer overflow in `unistd::getgrouplist`.
++ (#[1545](https://github.com/nix-rust/nix/pull/1545))
++
++## [0.20.1] - 13 August 2021
++### Added
++### Changed
++### Fixed
++
++- Locked bitflags to < 1.3.0 to fix the build with rust < 1.46.0.
++
++### Removed
++
++- Removed a couple of termios constants on redox that were never actually
++ supported.
++ (#[1483](https://github.com/nix-rust/nix/pull/1483))
++
++## [0.20.0] - 20 February 2021
++### Added
++
++- Added a `passwd` field to `Group` (#[1338](https://github.com/nix-rust/nix/pull/1338))
++- Added `mremap` (#[1306](https://github.com/nix-rust/nix/pull/1306))
++- Added `personality` (#[1331](https://github.com/nix-rust/nix/pull/1331))
++- Added limited Fuchsia support (#[1285](https://github.com/nix-rust/nix/pull/1285))
++- Added `getpeereid` (#[1342](https://github.com/nix-rust/nix/pull/1342))
++- Implemented `IntoIterator` for `Dir`
++ (#[1333](https://github.com/nix-rust/nix/pull/1333)).
++
++### Changed
++
++- Minimum supported Rust version is now 1.40.0.
++ ([#1356](https://github.com/nix-rust/nix/pull/1356))
++- i686-apple-darwin has been demoted to Tier 2 support, because it's deprecated
++ by Xcode.
++ (#[1350](https://github.com/nix-rust/nix/pull/1350))
++- Fixed calling `recvfrom` on an `AddrFamily::Packet` socket
++ (#[1344](https://github.com/nix-rust/nix/pull/1344))
++
++### Fixed
++- `TimerFd` now closes the underlying fd on drop.
++ ([#1381](https://github.com/nix-rust/nix/pull/1381))
++- Define `*_MAGIC` filesystem constants on Linux s390x
++ (#[1372](https://github.com/nix-rust/nix/pull/1372))
++- mqueue, sysinfo, timespec, statfs, test_ptrace_syscall() on x32
++ (#[1366](https://github.com/nix-rust/nix/pull/1366))
++
++### Removed
++
++- `Dir`, `SignalFd`, and `PtyMaster` are no longer `Clone`.
++ (#[1382](https://github.com/nix-rust/nix/pull/1382))
++- Removed `SockLevel`, which hasn't been used for a few years
++ (#[1362](https://github.com/nix-rust/nix/pull/1362))
++- Removed both `Copy` and `Clone` from `TimerFd`.
++ ([#1381](https://github.com/nix-rust/nix/pull/1381))
++
++## [0.19.1] - 28 November 2020
++### Fixed
++- Fixed bugs in `recvmmsg`.
++ (#[1341](https://github.com/nix-rust/nix/pull/1341))
++
++## [0.19.0] - 6 October 2020
++### Added
++- Added Netlink protocol families to the `SockProtocol` enum
++ (#[1289](https://github.com/nix-rust/nix/pull/1289))
++- Added `clock_gettime`, `clock_settime`, `clock_getres`,
++ `clock_getcpuclockid` functions and `ClockId` struct.
++ (#[1281](https://github.com/nix-rust/nix/pull/1281))
++- Added wrapper functions for `PTRACE_SYSEMU` and `PTRACE_SYSEMU_SINGLESTEP`.
++ (#[1300](https://github.com/nix-rust/nix/pull/1300))
++- Add support for Vsock on Android rather than just Linux.
++ (#[1301](https://github.com/nix-rust/nix/pull/1301))
++- Added `TCP_KEEPCNT` and `TCP_KEEPINTVL` TCP keepalive options.
++ (#[1283](https://github.com/nix-rust/nix/pull/1283))
++### Changed
++- Expose `SeekData` and `SeekHole` on all Linux targets
++ (#[1284](https://github.com/nix-rust/nix/pull/1284))
++- Changed unistd::{execv,execve,execvp,execvpe,fexecve,execveat} to take both `&[&CStr]` and `&[CString]` as its list argument(s).
++ (#[1278](https://github.com/nix-rust/nix/pull/1278))
++- Made `unistd::fork` an unsafe funtion, bringing it in line with [libstd's decision](https://github.com/rust-lang/rust/pull/58059).
++ (#[1293](https://github.com/nix-rust/nix/pull/1293))
++### Fixed
++### Removed
++
++## [0.18.0] - 26 July 2020
++### Added
++- Added `fchown(2)` wrapper.
++ (#[1257](https://github.com/nix-rust/nix/pull/1257))
++- Added support on linux systems for `MAP_HUGE_`_`SIZE`_ family of flags.
++ (#[1211](https://github.com/nix-rust/nix/pull/1211))
++- Added support for `F_OFD_*` `fcntl` commands on Linux and Android.
++ (#[1195](https://github.com/nix-rust/nix/pull/1195))
++- Added `env::clearenv()`: calls `libc::clearenv` on platforms
++ where it's available, and clears the environment of all variables
++ via `std::env::vars` and `std::env::remove_var` on others.
++ (#[1185](https://github.com/nix-rust/nix/pull/1185))
++- `FsType` inner value made public.
++ (#[1187](https://github.com/nix-rust/nix/pull/1187))
++- Added `unistd::setfsuid` and `unistd::setfsgid` to set the user or group
++ identity for filesystem checks per-thread.
++ (#[1163](https://github.com/nix-rust/nix/pull/1163))
++- Derived `Ord`, `PartialOrd` for `unistd::Pid` (#[1189](https://github.com/nix-rust/nix/pull/1189))
++- Added `select::FdSet::fds` method to iterate over file descriptors in a set.
++ ([#1207](https://github.com/nix-rust/nix/pull/1207))
++- Added support for UDP generic segmentation offload (GSO) and generic
++ receive offload (GRO) ([#1209](https://github.com/nix-rust/nix/pull/1209))
++- Added support for `sendmmsg` and `recvmmsg` calls
++ (#[1208](https://github.com/nix-rust/nix/pull/1208))
++- Added support for `SCM_CREDS` messages (`UnixCredentials`) on FreeBSD/DragonFly
++ (#[1216](https://github.com/nix-rust/nix/pull/1216))
++- Added `BindToDevice` socket option (sockopt) on Linux
++ (#[1233](https://github.com/nix-rust/nix/pull/1233))
++- Added `EventFilter` bitflags for `EV_DISPATCH` and `EV_RECEIPT` on OpenBSD.
++ (#[1252](https://github.com/nix-rust/nix/pull/1252))
++- Added support for `Ipv4PacketInfo` and `Ipv6PacketInfo` to `ControlMessage`.
++ (#[1222](https://github.com/nix-rust/nix/pull/1222))
++- `CpuSet` and `UnixCredentials` now implement `Default`.
++ (#[1244](https://github.com/nix-rust/nix/pull/1244))
++- Added `unistd::ttyname`
++ (#[1259](https://github.com/nix-rust/nix/pull/1259))
++- Added support for `Ipv4PacketInfo` and `Ipv6PacketInfo` to `ControlMessage` for iOS and Android.
++ (#[1265](https://github.com/nix-rust/nix/pull/1265))
++- Added support for `TimerFd`.
++ (#[1261](https://github.com/nix-rust/nix/pull/1261))
++
++### Changed
++- Changed `fallocate` return type from `c_int` to `()` (#[1201](https://github.com/nix-rust/nix/pull/1201))
++- Enabled `sys::ptrace::setregs` and `sys::ptrace::getregs` on x86_64-unknown-linux-musl target
++ (#[1198](https://github.com/nix-rust/nix/pull/1198))
++- On Linux, `ptrace::write` is now an `unsafe` function. Caveat programmer.
++ (#[1245](https://github.com/nix-rust/nix/pull/1245))
++- `execv`, `execve`, `execvp` and `execveat` in `::nix::unistd` and `reboot` in
++ `::nix::sys::reboot` now return `Result<Infallible>` instead of `Result<Void>` (#[1239](https://github.com/nix-rust/nix/pull/1239))
++- `sys::socket::sockaddr_storage_to_addr` is no longer `unsafe`. So is
++ `offset_of!`.
++- `sys::socket::sockaddr_storage_to_addr`, `offset_of!`, and `Errno::clear` are
++ no longer `unsafe`.
++- `SockAddr::as_ffi_pair`,`sys::socket::sockaddr_storage_to_addr`, `offset_of!`,
++ and `Errno::clear` are no longer `unsafe`.
++ (#[1244](https://github.com/nix-rust/nix/pull/1244))
++- Several `Inotify` methods now take `self` by value instead of by reference
++ (#[1244](https://github.com/nix-rust/nix/pull/1244))
++- `nix::poll::ppoll`: `timeout` parameter is now optional, None is equivalent for infinite timeout.
++
++### Fixed
++
++- Fixed `getsockopt`. The old code produced UB which triggers a panic with
++ Rust 1.44.0.
++ (#[1214](https://github.com/nix-rust/nix/pull/1214))
++
++- Fixed a bug in nix::unistd that would result in an infinite loop
++ when a group or user lookup required a buffer larger than
++ 16KB. (#[1198](https://github.com/nix-rust/nix/pull/1198))
++- Fixed unaligned casting of `cmsg_data` to `af_alg_iv` (#[1206](https://github.com/nix-rust/nix/pull/1206))
++- Fixed `readlink`/`readlinkat` when reading symlinks longer than `PATH_MAX` (#[1231](https://github.com/nix-rust/nix/pull/1231))
++- `PollFd`, `EpollEvent`, `IpMembershipRequest`, `Ipv6MembershipRequest`,
++ `TimeVal`, and `IoVec` are now `repr(transparent)`. This is required for
++ correctness's sake across all architectures and compilers, though now bugs
++ have been reported so far.
++ (#[1243](https://github.com/nix-rust/nix/pull/1243))
++- Fixed unaligned pointer read in `Inotify::read_events`.
++ (#[1244](https://github.com/nix-rust/nix/pull/1244))
++
++### Removed
++
++- Removed `sys::socket::addr::from_libc_sockaddr` from the public API.
++ (#[1215](https://github.com/nix-rust/nix/pull/1215))
++- Removed `sys::termios::{get_libc_termios, get_libc_termios_mut, update_wrapper`
++ from the public API. These were previously hidden in the docs but still usable
++ by downstream.
++ (#[1235](https://github.com/nix-rust/nix/pull/1235))
++
++- Nix no longer implements `NixPath` for `Option<P> where P: NixPath`. Most
++ Nix functions that accept `NixPath` arguments can't do anything useful with
++ `None`. The exceptions (`mount` and `quotactl_sync`) already take explicitly
++ optional arguments.
++ (#[1242](https://github.com/nix-rust/nix/pull/1242))
++
++- Removed `unistd::daemon` and `unistd::pipe2` on OSX and ios
++ (#[1255](https://github.com/nix-rust/nix/pull/1255))
++
++- Removed `sys::event::FilterFlag::NOTE_EXIT_REPARENTED` and
++ `sys::event::FilterFlag::NOTE_REAP` on OSX and ios.
++ (#[1255](https://github.com/nix-rust/nix/pull/1255))
++
++- Removed `sys::ptrace::ptrace` on Android and Linux.
++ (#[1255](https://github.com/nix-rust/nix/pull/1255))
++
++- Dropped support for powerpc64-unknown-linux-gnu
++ (#[1266](https://github.com/nix-rust/nix/pull/1268))
++
++## [0.17.0] - 3 February 2020
++### Added
++- Add `CLK_TCK` to `SysconfVar`
++ (#[1177](https://github.com/nix-rust/nix/pull/1177))
++### Changed
++### Fixed
++### Removed
++- Removed deprecated Error::description from error types
++ (#[1175](https://github.com/nix-rust/nix/pull/1175))
++
++## [0.16.1] - 23 December 2019
++### Added
++### Changed
++### Fixed
++
++- Fixed the build for OpenBSD
++ (#[1168](https://github.com/nix-rust/nix/pull/1168))
++
++### Removed
++
++## [0.16.0] - 1 December 2019
++### Added
++- Added `ptrace::seize()`: similar to `attach()` on Linux
++ but with better-defined semantics.
++ (#[1154](https://github.com/nix-rust/nix/pull/1154))
++
++- Added `Signal::as_str()`: returns signal name as `&'static str`
++ (#[1138](https://github.com/nix-rust/nix/pull/1138))
++
++- Added `posix_fallocate`.
++ ([#1105](https://github.com/nix-rust/nix/pull/1105))
++
++- Implemented `Default` for `FdSet`
++ ([#1107](https://github.com/nix-rust/nix/pull/1107))
++
++- Added `NixPath::is_empty`.
++ ([#1107](https://github.com/nix-rust/nix/pull/1107))
++
++- Added `mkfifoat`
++ ([#1133](https://github.com/nix-rust/nix/pull/1133))
++
++- Added `User::from_uid`, `User::from_name`, `User::from_gid` and
++ `Group::from_name`,
++ ([#1139](https://github.com/nix-rust/nix/pull/1139))
++
++- Added `linkat`
++ ([#1101](https://github.com/nix-rust/nix/pull/1101))
++
++- Added `sched_getaffinity`.
++ ([#1148](https://github.com/nix-rust/nix/pull/1148))
++
++- Added optional `Signal` argument to `ptrace::{detach, syscall}` for signal
++ injection. ([#1083](https://github.com/nix-rust/nix/pull/1083))
++
++### Changed
++- `sys::termios::BaudRate` now implements `TryFrom<speed_t>` instead of
++ `From<speed_t>`. The old `From` implementation would panic on failure.
++ ([#1159](https://github.com/nix-rust/nix/pull/1159))
++
++- `sys::socket::ControlMessage::ScmCredentials` and
++ `sys::socket::ControlMessageOwned::ScmCredentials` now wrap `UnixCredentials`
++ rather than `libc::ucred`.
++ ([#1160](https://github.com/nix-rust/nix/pull/1160))
++
++- `sys::socket::recvmsg` now takes a plain `Vec` instead of a `CmsgBuffer`
++ implementor. If you were already using `cmsg_space!`, then you needn't worry.
++ ([#1156](https://github.com/nix-rust/nix/pull/1156))
++
++- `sys::socket::recvfrom` now returns
++ `Result<(usize, Option<SockAddr>)>` instead of `Result<(usize, SockAddr)>`.
++ ([#1145](https://github.com/nix-rust/nix/pull/1145))
++
++- `Signal::from_c_int` has been replaced by `Signal::try_from`
++ ([#1113](https://github.com/nix-rust/nix/pull/1113))
++
++- Changed `readlink` and `readlinkat` to return `OsString`
++ ([#1109](https://github.com/nix-rust/nix/pull/1109))
++
++ ```rust
++ # use nix::fcntl::{readlink, readlinkat};
++ // the buffer argument of `readlink` and `readlinkat` has been removed,
++ // and the return value is now an owned type (`OsString`).
++ // Existing code can be updated by removing the buffer argument
++ // and removing any clone or similar operation on the output
++
++ // old code `readlink(&path, &mut buf)` can be replaced with the following
++ let _: OsString = readlink(&path);
++
++ // old code `readlinkat(dirfd, &path, &mut buf)` can be replaced with the following
++ let _: OsString = readlinkat(dirfd, &path);
++ ```
++
++- Minimum supported Rust version is now 1.36.0.
++ ([#1108](https://github.com/nix-rust/nix/pull/1108))
++
++- `Ipv4Addr::octets`, `Ipv4Addr::to_std`, `Error::as_errno`,
++ `ForkResult::is_child`, `ForkResult::is_parent`, `Gid::as_raw`,
++ `Uid::is_root`, `Uid::as_raw`, `Pid::as_raw`, and `PollFd::revents` now take
++ `self` by value.
++ ([#1107](https://github.com/nix-rust/nix/pull/1107))
++
++- Type `&CString` for parameters of `exec(v|ve|vp|vpe|veat)` are changed to `&CStr`.
++ ([#1121](https://github.com/nix-rust/nix/pull/1121))
++
++### Fixed
++- Fix length of abstract socket addresses
++ ([#1120](https://github.com/nix-rust/nix/pull/1120))
++
++- Fix initialization of msghdr in recvmsg/sendmsg when built with musl
++ ([#1136](https://github.com/nix-rust/nix/pull/1136))
++
+ ### Removed
++- Remove the deprecated `CmsgSpace`.
++ ([#1156](https://github.com/nix-rust/nix/pull/1156))
+
+ ## [0.15.0] - 10 August 2019
+ ### Added
+diff --git a/third_party/rust/nix/CONTRIBUTING.md b/third_party/rust/nix/CONTRIBUTING.md
+index 03a1f630dbb06..55990c4f1a24f 100644
+--- a/third_party/rust/nix/CONTRIBUTING.md
++++ b/third_party/rust/nix/CONTRIBUTING.md
+@@ -76,21 +76,21 @@ add a test that would have failed without the fix.
+
+ After you've made your change, make sure the tests pass in your development
+ environment. We also have [continuous integration set up on
+-Travis-CI][travis-ci], which might find some issues on other platforms. The CI
++Cirrus-CI][cirrus-ci], which might find some issues on other platforms. The CI
+ will run once you open a pull request.
+
+ There is also infrastructure for running tests for other targets
+ locally. More information is available in the [CI Readme][ci-readme].
+
+-[travis-ci]: https://travis-ci.org/nix-rust/nix
++[cirrus-ci]: https://cirrus-ci.com/github/nix-rust/nix
+ [ci-readme]: ci/README.md
+
+ ### Disabling a test in the CI environment
+
+ Sometimes there are features that cannot be tested in the CI environment.
+-To stop a test from running under CI, add `#[cfg_attr(travis, ignore)]`
+-to it. Please include a comment describing the reason it shouldn't run
+-under CI, and a link to an upstream issue if possible!
++To stop a test from running under CI, add `skip_if_cirrus!()` to it. Please
++describe the reason it shouldn't run under CI, and a link to an issue if
++possible!
+
+ ## bors, the bot who merges all the PRs
+
+diff --git a/third_party/rust/nix/CONVENTIONS.md b/third_party/rust/nix/CONVENTIONS.md
+index 48daa937345d2..2461085eb664a 100644
+--- a/third_party/rust/nix/CONVENTIONS.md
++++ b/third_party/rust/nix/CONVENTIONS.md
+@@ -76,12 +76,11 @@ to parameters of functions by [enumerations][enum].
+
+ Whenever we need to use a [libc][libc] function to properly initialize a
+ variable and said function allows us to use uninitialized memory, we use
+-[`std::mem::uninitialized`][std_uninitialized] (or [`core::mem::uninitialized`][core_uninitialized])
+-when defining the variable. This allows us to avoid the overhead incurred by
+-zeroing or otherwise initializing the variable.
++[`std::mem::MaybeUninit`][std_MaybeUninit] when defining the variable. This
++allows us to avoid the overhead incurred by zeroing or otherwise initializing
++the variable.
+
+ [bitflags]: https://crates.io/crates/bitflags/
+-[core_uninitialized]: https://doc.rust-lang.org/core/mem/fn.uninitialized.html
+ [enum]: https://doc.rust-lang.org/reference.html#enumerations
+ [libc]: https://crates.io/crates/libc/
+-[std_uninitialized]: https://doc.rust-lang.org/std/mem/fn.uninitialized.html
++[std_MaybeUninit]: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html
+diff --git a/third_party/rust/nix/Cargo.toml b/third_party/rust/nix/Cargo.toml
+index 555b99020d68f..456bdca9c2599 100644
+--- a/third_party/rust/nix/Cargo.toml
++++ b/third_party/rust/nix/Cargo.toml
+@@ -3,22 +3,24 @@
+ # When uploading crates to the registry Cargo will automatically
+ # "normalize" Cargo.toml files for maximal compatibility
+ # with all versions of Cargo and also rewrite `path` dependencies
+-# to registry (e.g., crates.io) dependencies
++# to registry (e.g., crates.io) dependencies.
+ #
+-# If you believe there's an error in this file please file an
+-# issue against the rust-lang/cargo repository. If you're
+-# editing this file be aware that the upstream Cargo.toml
+-# will likely look very different (and much more reasonable)
++# If you are reading this file be aware that the original Cargo.toml
++# will likely look very different (and much more reasonable).
++# See Cargo.toml.orig for the original contents.
+
+ [package]
++edition = "2018"
+ name = "nix"
+-version = "0.15.0"
++version = "0.20.2"
+ authors = ["The nix-rust Project Developers"]
+-exclude = ["/.gitignore", "/.travis.yml", "/ci/*", "/Cross.toml", "/RELEASE_PROCEDURE.md", "/bors.toml"]
++exclude = ["/.gitignore", "/.cirrus.yml", "/ci/*", "/Cross.toml", "/RELEASE_PROCEDURE.md", "/bors.toml"]
+ description = "Rust friendly bindings to *nix APIs"
+ categories = ["os::unix-apis"]
+ license = "MIT"
+ repository = "https://github.com/nix-rust/nix"
++[package.metadata.docs.rs]
++targets = ["x86_64-unknown-linux-gnu", "aarch64-linux-android", "x86_64-apple-darwin", "aarch64-apple-ios", "x86_64-unknown-freebsd", "x86_64-unknown-openbsd", "x86_64-unknown-netbsd", "x86_64-unknown-dragonfly", "x86_64-fuchsia", "x86_64-unknown-redox"]
+
+ [[test]]
+ name = "test"
+@@ -28,6 +30,10 @@ path = "test/test.rs"
+ name = "test-aio-drop"
+ path = "test/sys/test_aio_drop.rs"
+
++[[test]]
++name = "test-clearenv"
++path = "test/test_clearenv.rs"
++
+ [[test]]
+ name = "test-lio-listio-resubmit"
+ path = "test/sys/test_lio_listio_resubmit.rs"
+@@ -41,17 +47,14 @@ harness = false
+ name = "test-ptymaster-drop"
+ path = "test/test_ptymaster_drop.rs"
+ [dependencies.bitflags]
+-version = "1.0"
++version = ">= 1.1.0, < 1.3.0"
+
+ [dependencies.cfg-if]
+-version = "0.1.2"
++version = "1.0"
+
+ [dependencies.libc]
+-version = "0.2.60"
++version = "0.2.99"
+ features = ["extra_traits"]
+-
+-[dependencies.void]
+-version = "1.0.2"
+ [dev-dependencies.bytes]
+ version = "0.4.8"
+
+@@ -59,12 +62,17 @@ version = "0.4.8"
+ version = "1.2"
+
+ [dev-dependencies.rand]
+-version = ">= 0.6, < 0.7"
++version = "0.6"
++
++[dev-dependencies.semver]
++version = "0.9.0"
+
+ [dev-dependencies.tempfile]
+-version = ">= 3.0.5, < 3.0.9"
++version = "3.0.5"
+ [target."cfg(any(target_os = \"android\", target_os = \"linux\"))".dev-dependencies.caps]
+-version = "0.3.1"
++version = "0.5.1"
++[target."cfg(not(target_os = \"redox\"))".dependencies.memoffset]
++version = "0.6.3"
+ [target."cfg(target_os = \"dragonfly\")".build-dependencies.cc]
+ version = "1"
+ [target."cfg(target_os = \"freebsd\")".dev-dependencies.sysctl]
+diff --git a/third_party/rust/nix/README.md b/third_party/rust/nix/README.md
+index 0e540ba5b968e..b4909ea4345cc 100644
+--- a/third_party/rust/nix/README.md
++++ b/third_party/rust/nix/README.md
+@@ -1,6 +1,6 @@
+ # Rust bindings to *nix APIs
+
+-[![Build Status](https://travis-ci.org/nix-rust/nix.svg?branch=master)](https://travis-ci.org/nix-rust/nix)
++[![Cirrus Build Status](https://api.cirrus-ci.com/github/nix-rust/nix.svg)](https://cirrus-ci.com/github/nix-rust/nix)
+ [![crates.io](http://meritbadge.herokuapp.com/nix)](https://crates.io/crates/nix)
+
+ [Documentation (Releases)](https://docs.rs/nix/)
+@@ -50,7 +50,6 @@ Tier 1:
+ * aarch64-unknown-linux-gnu
+ * arm-unknown-linux-gnueabi
+ * armv7-unknown-linux-gnueabihf
+- * i686-apple-darwin
+ * i686-unknown-freebsd
+ * i686-unknown-linux-gnu
+ * i686-unknown-linux-musl
+@@ -58,7 +57,6 @@ Tier 1:
+ * mips64-unknown-linux-gnuabi64
+ * mips64el-unknown-linux-gnuabi64
+ * mipsel-unknown-linux-gnu
+- * powerpc64-unknown-linux-gnu
+ * powerpc64le-unknown-linux-gnu
+ * x86_64-apple-darwin
+ * x86_64-unknown-freebsd
+@@ -74,6 +72,7 @@ Tier 2:
+ * armv7-linux-androideabi
+ * armv7s-apple-ios
+ * i386-apple-ios
++ * i686-apple-darwin
+ * i686-linux-android
+ * powerpc-unknown-linux-gnu
+ * s390x-unknown-linux-gnu
+@@ -81,21 +80,20 @@ Tier 2:
+ * x86_64-linux-android
+ * x86_64-unknown-netbsd
+
++Tier 3:
++ * x86_64-fuchsia
++ * x86_64-unknown-redox
++ * x86_64-unknown-linux-gnux32
++
+ ## Usage
+
+-`nix` requires Rust 1.31.0 or newer.
++`nix` requires Rust 1.40.0 or newer.
+
+-To use `nix`, first add this to your `Cargo.toml`:
++To use `nix`, add this to your `Cargo.toml`:
+
+ ```toml
+ [dependencies]
+-nix = "0.15.0"
+-```
+-
+-Then, add this to your crate root:
+-
+-```rust,ignore
+-extern crate nix;
++nix = "0.20.2"
+ ```
+
+ ## Contributing
+diff --git a/third_party/rust/nix/src/dir.rs b/third_party/rust/nix/src/dir.rs
+index 1820b5330ff60..7d4ab82f79e0d 100644
+--- a/third_party/rust/nix/src/dir.rs
++++ b/third_party/rust/nix/src/dir.rs
+@@ -1,10 +1,10 @@
+-use {Error, NixPath, Result};
+-use errno::Errno;
+-use fcntl::{self, OFlag};
+-use libc;
++use crate::{Error, NixPath, Result};
++use crate::errno::Errno;
++use crate::fcntl::{self, OFlag};
+ use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
+-use std::{ffi, ptr};
+-use sys;
++use std::ptr;
++use std::ffi;
++use crate::sys;
+
+ #[cfg(target_os = "linux")]
+ use libc::{dirent64 as dirent, readdir64_r as readdir_r};
+@@ -25,7 +25,7 @@ use libc::{dirent, readdir_r};
+ /// * returns entries for `.` (current directory) and `..` (parent directory).
+ /// * returns entries' names as a `CStr` (no allocation or conversion beyond whatever libc
+ /// does).
+-#[derive(Clone, Debug, Eq, Hash, PartialEq)]
++#[derive(Debug, Eq, Hash, PartialEq)]
+ pub struct Dir(
+ ptr::NonNull<libc::DIR>
+ );
+@@ -85,7 +85,32 @@ impl AsRawFd for Dir {
+
+ impl Drop for Dir {
+ fn drop(&mut self) {
+- unsafe { libc::closedir(self.0.as_ptr()) };
++ let e = Errno::result(unsafe { libc::closedir(self.0.as_ptr()) });
++ if !std::thread::panicking() && e == Err(Error::Sys(Errno::EBADF)) {
++ panic!("Closing an invalid file descriptor!");
++ };
++ }
++}
++
++fn next(dir: &mut Dir) -> Option<Result<Entry>> {
++ unsafe {
++ // Note: POSIX specifies that portable applications should dynamically allocate a
++ // buffer with room for a `d_name` field of size `pathconf(..., _PC_NAME_MAX)` plus 1
++ // for the NUL byte. It doesn't look like the std library does this; it just uses
++ // fixed-sized buffers (and libc's dirent seems to be sized so this is appropriate).
++ // Probably fine here too then.
++ let mut ent = std::mem::MaybeUninit::<dirent>::uninit();
++ let mut result = ptr::null_mut();
++ if let Err(e) = Errno::result(
++ readdir_r(dir.0.as_ptr(), ent.as_mut_ptr(), &mut result))
++ {
++ return Some(Err(e));
++ }
++ if result.is_null() {
++ return None;
++ }
++ assert_eq!(result, ent.as_mut_ptr());
++ Some(Ok(Entry(ent.assume_init())))
+ }
+ }
+
+@@ -96,23 +121,7 @@ impl<'d> Iterator for Iter<'d> {
+ type Item = Result<Entry>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+- unsafe {
+- // Note: POSIX specifies that portable applications should dynamically allocate a
+- // buffer with room for a `d_name` field of size `pathconf(..., _PC_NAME_MAX)` plus 1
+- // for the NUL byte. It doesn't look like the std library does this; it just uses
+- // fixed-sized buffers (and libc's dirent seems to be sized so this is appropriate).
+- // Probably fine here too then.
+- let mut ent: Entry = Entry(::std::mem::uninitialized());
+- let mut result = ptr::null_mut();
+- if let Err(e) = Errno::result(readdir_r((self.0).0.as_ptr(), &mut ent.0, &mut result)) {
+- return Some(Err(e));
+- }
+- if result == ptr::null_mut() {
+- return None;
+- }
+- assert_eq!(result, &mut ent.0 as *mut dirent);
+- return Some(Ok(ent));
+- }
++ next(self.0)
+ }
+ }
+
+@@ -122,10 +131,48 @@ impl<'d> Drop for Iter<'d> {
+ }
+ }
+
++/// The return type of [Dir::into_iter]
++#[derive(Debug, Eq, Hash, PartialEq)]
++pub struct OwningIter(Dir);
++
++impl Iterator for OwningIter {
++ type Item = Result<Entry>;
++
++ fn next(&mut self) -> Option<Self::Item> {
++ next(&mut self.0)
++ }
++}
++
++impl IntoIterator for Dir {
++ type Item = Result<Entry>;
++ type IntoIter = OwningIter;
++
++ /// Creates a owning iterator, that is, one that takes ownership of the
++ /// `Dir`. The `Dir` cannot be used after calling this. This can be useful
++ /// when you have a function that both creates a `Dir` instance and returns
++ /// an `Iterator`.
++ ///
++ /// Example:
++ ///
++ /// ```
++ /// use nix::{dir::Dir, fcntl::OFlag, sys::stat::Mode};
++ /// use std::{iter::Iterator, string::String};
++ ///
++ /// fn ls_upper(dirname: &str) -> impl Iterator<Item=String> {
++ /// let d = Dir::open(dirname, OFlag::O_DIRECTORY, Mode::S_IXUSR).unwrap();
++ /// d.into_iter().map(|x| x.unwrap().file_name().as_ref().to_string_lossy().to_ascii_uppercase())
++ /// }
++ /// ```
++ fn into_iter(self) -> Self::IntoIter {
++ OwningIter(self)
++ }
++}
++
+ /// A directory entry, similar to `std::fs::DirEntry`.
+ ///
+ /// Note that unlike the std version, this may represent the `.` or `..` entries.
+ #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
++#[repr(transparent)]
+ pub struct Entry(dirent);
+
+ #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
+@@ -165,7 +212,7 @@ impl Entry {
+ target_os = "macos",
+ target_os = "solaris")))]
+ pub fn ino(&self) -> u64 {
+- self.0.d_fileno as u64
++ u64::from(self.0.d_fileno)
+ }
+
+ /// Returns the bare file name of this directory entry without any other leading path component.
+diff --git a/third_party/rust/nix/src/env.rs b/third_party/rust/nix/src/env.rs
+new file mode 100644
+index 0000000000000..f144dfedd0c1a
+--- /dev/null
++++ b/third_party/rust/nix/src/env.rs
+@@ -0,0 +1,53 @@
++use cfg_if::cfg_if;
++use crate::{Error, Result};
++
++/// Clear the environment of all name-value pairs.
++///
++/// On platforms where libc provides `clearenv()`, it will be used. libc's
++/// `clearenv()` is documented to return an error code but not set errno; if the
++/// return value indicates a failure, this function will return
++/// `Error::UnsupportedOperation`.
++///
++/// On platforms where libc does not provide `clearenv()`, a fallback
++/// implementation will be used that iterates over all environment variables and
++/// removes them one-by-one.
++///
++/// # Safety
++///
++/// This function is not threadsafe and can cause undefined behavior in
++/// combination with `std::env` or other program components that access the
++/// environment. See, for example, the discussion on `std::env::remove_var`; this
++/// function is a case of an "inherently unsafe non-threadsafe API" dealing with
++/// the environment.
++///
++/// The caller must ensure no other threads access the process environment while
++/// this function executes and that no raw pointers to an element of libc's
++/// `environ` is currently held. The latter is not an issue if the only other
++/// environment access in the program is via `std::env`, but the requirement on
++/// thread safety must still be upheld.
++pub unsafe fn clearenv() -> Result<()> {
++ let ret;
++ cfg_if! {
++ if #[cfg(any(target_os = "fuchsia",
++ target_os = "wasi",
++ target_env = "wasi",
++ target_env = "uclibc",
++ target_os = "linux",
++ target_os = "android",
++ target_os = "emscripten"))] {
++ ret = libc::clearenv();
++ } else {
++ use std::env;
++ for (name, _) in env::vars_os() {
++ env::remove_var(name);
++ }
++ ret = 0;
++ }
++ }
++
++ if ret == 0 {
++ Ok(())
++ } else {
++ Err(Error::UnsupportedOperation)
++ }
++}
+diff --git a/third_party/rust/nix/src/errno.rs b/third_party/rust/nix/src/errno.rs
+index 6a2447bc52675..e5c709252025c 100644
+--- a/third_party/rust/nix/src/errno.rs
++++ b/third_party/rust/nix/src/errno.rs
+@@ -1,8 +1,7 @@
+-#[cfg(not(target_os = "dragonfly"))]
+-use libc;
++use cfg_if::cfg_if;
+ use libc::{c_int, c_void};
+ use std::{fmt, io, error};
+-use {Error, Result};
++use crate::{Error, Result};
+
+ pub use self::consts::*;
+
+@@ -13,32 +12,16 @@ cfg_if! {
+ unsafe fn errno_location() -> *mut c_int {
+ libc::__error()
+ }
+- } else if #[cfg(target_os = "dragonfly")] {
+- // DragonFly uses a thread-local errno variable, but #[thread_local] is
+- // feature-gated and not available in stable Rust as of this writing
+- // (Rust 1.21.0). We have to use a C extension to access it
+- // (src/errno_dragonfly.c).
+- //
+- // Tracking issue for `thread_local` stabilization:
+- //
+- // https://github.com/rust-lang/rust/issues/29594
+- //
+- // Once this becomes stable, we can remove build.rs,
+- // src/errno_dragonfly.c, and use:
+- //
+- // extern { #[thread_local] static errno: c_int; }
+- //
+- #[link(name="errno_dragonfly", kind="static")]
+- extern {
+- pub fn errno_location() -> *mut c_int;
+- }
+ } else if #[cfg(any(target_os = "android",
+ target_os = "netbsd",
+ target_os = "openbsd"))] {
+ unsafe fn errno_location() -> *mut c_int {
+ libc::__errno()
+ }
+- } else if #[cfg(target_os = "linux")] {
++ } else if #[cfg(any(target_os = "linux",
++ target_os = "redox",
++ target_os = "dragonfly",
++ target_os = "fuchsia"))] {
+ unsafe fn errno_location() -> *mut c_int {
+ libc::__errno_location()
+ }
+@@ -46,8 +29,11 @@ cfg_if! {
+ }
+
+ /// Sets the platform-specific errno to no-error
+-unsafe fn clear() -> () {
+- *errno_location() = 0;
++fn clear() {
++ // Safe because errno is a thread-local variable
++ unsafe {
++ *errno_location() = 0;
++ }
+ }
+
+ /// Returns the platform-specific value of errno
+@@ -70,7 +56,7 @@ impl Errno {
+ from_i32(err)
+ }
+
+- pub unsafe fn clear() -> () {
++ pub fn clear() {
+ clear()
+ }
+
+@@ -111,11 +97,7 @@ impl ErrnoSentinel for libc::sighandler_t {
+ fn sentinel() -> Self { libc::SIG_ERR }
+ }
+
+-impl error::Error for Errno {
+- fn description(&self) -> &str {
+- self.desc()
+- }
+-}
++impl error::Error for Errno {}
+
+ impl fmt::Display for Errno {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+@@ -207,200 +189,263 @@ fn desc(errno: Errno) -> &'static str {
+ EHOSTDOWN => "Host is down",
+ EHOSTUNREACH => "No route to host",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ ECHRNG => "Channel number out of range",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ EL2NSYNC => "Level 2 not synchronized",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ EL3HLT => "Level 3 halted",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ EL3RST => "Level 3 reset",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ ELNRNG => "Link number out of range",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ EUNATCH => "Protocol driver not attached",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ ENOCSI => "No CSI structure available",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ EL2HLT => "Level 2 halted",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ EBADE => "Invalid exchange",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ EBADR => "Invalid request descriptor",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ EXFULL => "Exchange full",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ ENOANO => "No anode",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ EBADRQC => "Invalid request code",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ EBADSLT => "Invalid slot",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ EBFONT => "Bad font file format",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ ENOSTR => "Device not a stream",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ ENODATA => "No data available",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ ETIME => "Timer expired",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ ENOSR => "Out of streams resources",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ ENONET => "Machine is not on the network",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ ENOPKG => "Package not installed",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ EREMOTE => "Object is remote",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ ENOLINK => "Link has been severed",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ EADV => "Advertise error",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ ESRMNT => "Srmount error",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ ECOMM => "Communication error on send",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ EPROTO => "Protocol error",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ EMULTIHOP => "Multihop attempted",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ EDOTDOT => "RFS specific error",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ EBADMSG => "Not a data message",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ EOVERFLOW => "Value too large for defined data type",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ ENOTUNIQ => "Name not unique on network",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ EBADFD => "File descriptor in bad state",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ EREMCHG => "Remote address changed",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ ELIBACC => "Can not access a needed shared library",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ ELIBBAD => "Accessing a corrupted shared library",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ ELIBSCN => ".lib section in a.out corrupted",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ ELIBMAX => "Attempting to link in too many shared libraries",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ ELIBEXEC => "Cannot exec a shared library directly",
+
+- #[cfg(any(target_os = "linux", target_os = "android", target_os = "openbsd"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia", target_os = "openbsd"))]
+ EILSEQ => "Illegal byte sequence",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ ERESTART => "Interrupted system call should be restarted",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ ESTRPIPE => "Streams pipe error",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ EUSERS => "Too many users",
+
+- #[cfg(any(target_os = "linux", target_os = "android", target_os = "netbsd"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia", target_os = "netbsd",
++ target_os = "redox"))]
+ EOPNOTSUPP => "Operation not supported on transport endpoint",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ ESTALE => "Stale file handle",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ EUCLEAN => "Structure needs cleaning",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ ENOTNAM => "Not a XENIX named type file",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ ENAVAIL => "No XENIX semaphores available",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ EISNAM => "Is a named type file",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ EREMOTEIO => "Remote I/O error",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ EDQUOT => "Quota exceeded",
+
+ #[cfg(any(target_os = "linux", target_os = "android",
+- target_os = "openbsd", target_os = "dragonfly"))]
++ target_os = "fuchsia", target_os = "openbsd",
++ target_os = "dragonfly"))]
+ ENOMEDIUM => "No medium found",
+
+- #[cfg(any(target_os = "linux", target_os = "android", target_os = "openbsd"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia", target_os = "openbsd"))]
+ EMEDIUMTYPE => "Wrong medium type",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ ECANCELED => "Operation canceled",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ ENOKEY => "Required key not available",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ EKEYEXPIRED => "Key has expired",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ EKEYREVOKED => "Key has been revoked",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ EKEYREJECTED => "Key was rejected by service",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ EOWNERDEAD => "Owner died",
+
+- #[cfg(any(target_os = "linux", target_os = "android"))]
++ #[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ ENOTRECOVERABLE => "State not recoverable",
+
+- #[cfg(all(target_os = "linux", not(target_arch="mips")))]
++ #[cfg(any(all(target_os = "linux", not(target_arch="mips")),
++ target_os = "fuchsia"))]
+ ERFKILL => "Operation not possible due to RF-kill",
+
+- #[cfg(all(target_os = "linux", not(target_arch="mips")))]
++ #[cfg(any(all(target_os = "linux", not(target_arch="mips")),
++ target_os = "fuchsia"))]
+ EHWPOISON => "Memory page has hardware error",
+
+ #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
+ EDOOFUS => "Programming error",
+
+- #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++ #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "redox"))]
+ EMULTIHOP => "Multihop attempted",
+
+- #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++ #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "redox"))]
+ ENOLINK => "Link has been severed",
+
+ #[cfg(target_os = "freebsd")]
+@@ -416,12 +461,13 @@ fn desc(errno: Errno) -> &'static str {
+
+ #[cfg(any(target_os = "macos", target_os = "freebsd",
+ target_os = "dragonfly", target_os = "ios",
+- target_os = "openbsd", target_os = "netbsd"))]
++ target_os = "openbsd", target_os = "netbsd",
++ target_os = "redox"))]
+ EOVERFLOW => "Value too large to be stored in data type",
+
+ #[cfg(any(target_os = "macos", target_os = "freebsd",
+ target_os = "dragonfly", target_os = "ios",
+- target_os = "netbsd"))]
++ target_os = "netbsd", target_os = "redox"))]
+ EILSEQ => "Illegal byte sequence",
+
+ #[cfg(any(target_os = "macos", target_os = "freebsd",
+@@ -431,12 +477,14 @@ fn desc(errno: Errno) -> &'static str {
+
+ #[cfg(any(target_os = "macos", target_os = "freebsd",
+ target_os = "dragonfly", target_os = "ios",
+- target_os = "openbsd", target_os = "netbsd"))]
++ target_os = "openbsd", target_os = "netbsd",
++ target_os = "redox"))]
+ EBADMSG => "Bad message",
+
+ #[cfg(any(target_os = "macos", target_os = "freebsd",
+ target_os = "dragonfly", target_os = "ios",
+- target_os = "openbsd", target_os = "netbsd"))]
++ target_os = "openbsd", target_os = "netbsd",
++ target_os = "redox"))]
+ EPROTO => "Protocol error",
+
+ #[cfg(any(target_os = "macos", target_os = "freebsd",
+@@ -459,22 +507,26 @@ fn desc(errno: Errno) -> &'static str {
+
+ #[cfg(any(target_os = "macos", target_os = "freebsd",
+ target_os = "dragonfly", target_os = "ios",
+- target_os = "openbsd", target_os = "netbsd"))]
++ target_os = "openbsd", target_os = "netbsd",
++ target_os = "redox"))]
+ EUSERS => "Too many users",
+
+ #[cfg(any(target_os = "macos", target_os = "freebsd",
+ target_os = "dragonfly", target_os = "ios",
+- target_os = "openbsd", target_os = "netbsd"))]
++ target_os = "openbsd", target_os = "netbsd",
++ target_os = "redox"))]
+ EDQUOT => "Disc quota exceeded",
+
+ #[cfg(any(target_os = "macos", target_os = "freebsd",
+ target_os = "dragonfly", target_os = "ios",
+- target_os = "openbsd", target_os = "netbsd"))]
++ target_os = "openbsd", target_os = "netbsd",
++ target_os = "redox"))]
+ ESTALE => "Stale NFS file handle",
+
+ #[cfg(any(target_os = "macos", target_os = "freebsd",
+ target_os = "dragonfly", target_os = "ios",
+- target_os = "openbsd", target_os = "netbsd"))]
++ target_os = "openbsd", target_os = "netbsd",
++ target_os = "redox"))]
+ EREMOTE => "Too many levels of remote in path",
+
+ #[cfg(any(target_os = "macos", target_os = "freebsd",
+@@ -514,7 +566,8 @@ fn desc(errno: Errno) -> &'static str {
+
+ #[cfg(any(target_os = "macos", target_os = "freebsd",
+ target_os = "dragonfly", target_os = "ios",
+- target_os = "openbsd", target_os = "netbsd"))]
++ target_os = "openbsd", target_os = "netbsd",
++ target_os = "redox"))]
+ ECANCELED => "Operation canceled",
+
+ #[cfg(any(target_os = "macos", target_os = "ios"))]
+@@ -538,19 +591,23 @@ fn desc(errno: Errno) -> &'static str {
+ #[cfg(any(target_os = "macos", target_os = "ios", target_os = "netbsd"))]
+ EMULTIHOP => "Reserved",
+
+- #[cfg(any(target_os = "macos", target_os = "ios", target_os = "netbsd"))]
++ #[cfg(any(target_os = "macos", target_os = "ios",
++ target_os = "netbsd", target_os = "redox"))]
+ ENODATA => "No message available on STREAM",
+
+ #[cfg(any(target_os = "macos", target_os = "ios", target_os = "netbsd"))]
+ ENOLINK => "Reserved",
+
+- #[cfg(any(target_os = "macos", target_os = "ios", target_os = "netbsd"))]
++ #[cfg(any(target_os = "macos", target_os = "ios",
++ target_os = "netbsd", target_os = "redox"))]
+ ENOSR => "No STREAM resources",
+
+- #[cfg(any(target_os = "macos", target_os = "ios", target_os = "netbsd"))]
++ #[cfg(any(target_os = "macos", target_os = "ios",
++ target_os = "netbsd", target_os = "redox"))]
+ ENOSTR => "Not a STREAM",
+
+- #[cfg(any(target_os = "macos", target_os = "ios", target_os = "netbsd"))]
++ #[cfg(any(target_os = "macos", target_os = "ios",
++ target_os = "netbsd", target_os = "redox"))]
+ ETIME => "STREAM ioctl timeout",
+
+ #[cfg(any(target_os = "macos", target_os = "ios"))]
+@@ -573,10 +630,9 @@ fn desc(errno: Errno) -> &'static str {
+ }
+ }
+
+-#[cfg(any(target_os = "linux", target_os = "android"))]
++#[cfg(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia"))]
+ mod consts {
+- use libc;
+-
+ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
+ #[repr(i32)]
+ pub enum Errno {
+@@ -864,8 +920,6 @@ mod consts {
+
+ #[cfg(any(target_os = "macos", target_os = "ios"))]
+ mod consts {
+- use libc;
+-
+ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
+ #[repr(i32)]
+ pub enum Errno {
+@@ -1101,8 +1155,6 @@ mod consts {
+
+ #[cfg(target_os = "freebsd")]
+ mod consts {
+- use libc;
+-
+ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
+ #[repr(i32)]
+ pub enum Errno {
+@@ -1319,8 +1371,6 @@ mod consts {
+
+ #[cfg(target_os = "dragonfly")]
+ mod consts {
+- use libc;
+-
+ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
+ #[repr(i32)]
+ pub enum Errno {
+@@ -1534,8 +1584,6 @@ mod consts {
+
+ #[cfg(target_os = "openbsd")]
+ mod consts {
+- use libc;
+-
+ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
+ #[repr(i32)]
+ pub enum Errno {
+@@ -1748,8 +1796,6 @@ mod consts {
+
+ #[cfg(target_os = "netbsd")]
+ mod consts {
+- use libc;
+-
+ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
+ #[repr(i32)]
+ pub enum Errno {
+@@ -1961,3 +2007,195 @@ mod consts {
+ }
+ }
+ }
++
++#[cfg(target_os = "redox")]
++mod consts {
++ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
++ #[repr(i32)]
++ pub enum Errno {
++ UnknownErrno = 0,
++ EPERM = libc::EPERM,
++ ENOENT = libc::ENOENT,
++ ESRCH = libc::ESRCH,
++ EINTR = libc::EINTR,
++ EIO = libc::EIO,
++ ENXIO = libc::ENXIO,
++ E2BIG = libc::E2BIG,
++ ENOEXEC = libc::ENOEXEC,
++ EBADF = libc::EBADF,
++ ECHILD = libc::ECHILD,
++ EDEADLK = libc::EDEADLK,
++ ENOMEM = libc::ENOMEM,
++ EACCES = libc::EACCES,
++ EFAULT = libc::EFAULT,
++ ENOTBLK = libc::ENOTBLK,
++ EBUSY = libc::EBUSY,
++ EEXIST = libc::EEXIST,
++ EXDEV = libc::EXDEV,
++ ENODEV = libc::ENODEV,
++ ENOTDIR = libc::ENOTDIR,
++ EISDIR = libc::EISDIR,
++ EINVAL = libc::EINVAL,
++ ENFILE = libc::ENFILE,
++ EMFILE = libc::EMFILE,
++ ENOTTY = libc::ENOTTY,
++ ETXTBSY = libc::ETXTBSY,
++ EFBIG = libc::EFBIG,
++ ENOSPC = libc::ENOSPC,
++ ESPIPE = libc::ESPIPE,
++ EROFS = libc::EROFS,
++ EMLINK = libc::EMLINK,
++ EPIPE = libc::EPIPE,
++ EDOM = libc::EDOM,
++ ERANGE = libc::ERANGE,
++ EAGAIN = libc::EAGAIN,
++ EINPROGRESS = libc::EINPROGRESS,
++ EALREADY = libc::EALREADY,
++ ENOTSOCK = libc::ENOTSOCK,
++ EDESTADDRREQ = libc::EDESTADDRREQ,
++ EMSGSIZE = libc::EMSGSIZE,
++ EPROTOTYPE = libc::EPROTOTYPE,
++ ENOPROTOOPT = libc::ENOPROTOOPT,
++ EPROTONOSUPPORT = libc::EPROTONOSUPPORT,
++ ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT,
++ EOPNOTSUPP = libc::EOPNOTSUPP,
++ EPFNOSUPPORT = libc::EPFNOSUPPORT,
++ EAFNOSUPPORT = libc::EAFNOSUPPORT,
++ EADDRINUSE = libc::EADDRINUSE,
++ EADDRNOTAVAIL = libc::EADDRNOTAVAIL,
++ ENETDOWN = libc::ENETDOWN,
++ ENETUNREACH = libc::ENETUNREACH,
++ ENETRESET = libc::ENETRESET,
++ ECONNABORTED = libc::ECONNABORTED,
++ ECONNRESET = libc::ECONNRESET,
++ ENOBUFS = libc::ENOBUFS,
++ EISCONN = libc::EISCONN,
++ ENOTCONN = libc::ENOTCONN,
++ ESHUTDOWN = libc::ESHUTDOWN,
++ ETOOMANYREFS = libc::ETOOMANYREFS,
++ ETIMEDOUT = libc::ETIMEDOUT,
++ ECONNREFUSED = libc::ECONNREFUSED,
++ ELOOP = libc::ELOOP,
++ ENAMETOOLONG = libc::ENAMETOOLONG,
++ EHOSTDOWN = libc::EHOSTDOWN,
++ EHOSTUNREACH = libc::EHOSTUNREACH,
++ ENOTEMPTY = libc::ENOTEMPTY,
++ EUSERS = libc::EUSERS,
++ EDQUOT = libc::EDQUOT,
++ ESTALE = libc::ESTALE,
++ EREMOTE = libc::EREMOTE,
++ ENOLCK = libc::ENOLCK,
++ ENOSYS = libc::ENOSYS,
++ EIDRM = libc::EIDRM,
++ ENOMSG = libc::ENOMSG,
++ EOVERFLOW = libc::EOVERFLOW,
++ EILSEQ = libc::EILSEQ,
++ ECANCELED = libc::ECANCELED,
++ EBADMSG = libc::EBADMSG,
++ ENODATA = libc::ENODATA,
++ ENOSR = libc::ENOSR,
++ ENOSTR = libc::ENOSTR,
++ ETIME = libc::ETIME,
++ EMULTIHOP = libc::EMULTIHOP,
++ ENOLINK = libc::ENOLINK,
++ EPROTO = libc::EPROTO,
++ }
++
++ pub const ELAST: Errno = Errno::UnknownErrno;
++ pub const EWOULDBLOCK: Errno = Errno::EAGAIN;
++
++ pub const EL2NSYNC: Errno = Errno::UnknownErrno;
++
++ pub fn from_i32(e: i32) -> Errno {
++ use self::Errno::*;
++
++ match e {
++ libc::EPERM => EPERM,
++ libc::ENOENT => ENOENT,
++ libc::ESRCH => ESRCH,
++ libc::EINTR => EINTR,
++ libc::EIO => EIO,
++ libc::ENXIO => ENXIO,
++ libc::E2BIG => E2BIG,
++ libc::ENOEXEC => ENOEXEC,
++ libc::EBADF => EBADF,
++ libc::ECHILD => ECHILD,
++ libc::EDEADLK => EDEADLK,
++ libc::ENOMEM => ENOMEM,
++ libc::EACCES => EACCES,
++ libc::EFAULT => EFAULT,
++ libc::ENOTBLK => ENOTBLK,
++ libc::EBUSY => EBUSY,
++ libc::EEXIST => EEXIST,
++ libc::EXDEV => EXDEV,
++ libc::ENODEV => ENODEV,
++ libc::ENOTDIR => ENOTDIR,
++ libc::EISDIR => EISDIR,
++ libc::EINVAL => EINVAL,
++ libc::ENFILE => ENFILE,
++ libc::EMFILE => EMFILE,
++ libc::ENOTTY => ENOTTY,
++ libc::ETXTBSY => ETXTBSY,
++ libc::EFBIG => EFBIG,
++ libc::ENOSPC => ENOSPC,
++ libc::ESPIPE => ESPIPE,
++ libc::EROFS => EROFS,
++ libc::EMLINK => EMLINK,
++ libc::EPIPE => EPIPE,
++ libc::EDOM => EDOM,
++ libc::ERANGE => ERANGE,
++ libc::EAGAIN => EAGAIN,
++ libc::EINPROGRESS => EINPROGRESS,
++ libc::EALREADY => EALREADY,
++ libc::ENOTSOCK => ENOTSOCK,
++ libc::EDESTADDRREQ => EDESTADDRREQ,
++ libc::EMSGSIZE => EMSGSIZE,
++ libc::EPROTOTYPE => EPROTOTYPE,
++ libc::ENOPROTOOPT => ENOPROTOOPT,
++ libc::EPROTONOSUPPORT => EPROTONOSUPPORT,
++ libc::ESOCKTNOSUPPORT => ESOCKTNOSUPPORT,
++ libc::EOPNOTSUPP => EOPNOTSUPP,
++ libc::EPFNOSUPPORT => EPFNOSUPPORT,
++ libc::EAFNOSUPPORT => EAFNOSUPPORT,
++ libc::EADDRINUSE => EADDRINUSE,
++ libc::EADDRNOTAVAIL => EADDRNOTAVAIL,
++ libc::ENETDOWN => ENETDOWN,
++ libc::ENETUNREACH => ENETUNREACH,
++ libc::ENETRESET => ENETRESET,
++ libc::ECONNABORTED => ECONNABORTED,
++ libc::ECONNRESET => ECONNRESET,
++ libc::ENOBUFS => ENOBUFS,
++ libc::EISCONN => EISCONN,
++ libc::ENOTCONN => ENOTCONN,
++ libc::ESHUTDOWN => ESHUTDOWN,
++ libc::ETOOMANYREFS => ETOOMANYREFS,
++ libc::ETIMEDOUT => ETIMEDOUT,
++ libc::ECONNREFUSED => ECONNREFUSED,
++ libc::ELOOP => ELOOP,
++ libc::ENAMETOOLONG => ENAMETOOLONG,
++ libc::EHOSTDOWN => EHOSTDOWN,
++ libc::EHOSTUNREACH => EHOSTUNREACH,
++ libc::ENOTEMPTY => ENOTEMPTY,
++ libc::EUSERS => EUSERS,
++ libc::EDQUOT => EDQUOT,
++ libc::ESTALE => ESTALE,
++ libc::EREMOTE => EREMOTE,
++ libc::ENOLCK => ENOLCK,
++ libc::ENOSYS => ENOSYS,
++ libc::EIDRM => EIDRM,
++ libc::ENOMSG => ENOMSG,
++ libc::EOVERFLOW => EOVERFLOW,
++ libc::EILSEQ => EILSEQ,
++ libc::ECANCELED => ECANCELED,
++ libc::EBADMSG => EBADMSG,
++ libc::ENODATA => ENODATA,
++ libc::ENOSR => ENOSR,
++ libc::ENOSTR => ENOSTR,
++ libc::ETIME => ETIME,
++ libc::EMULTIHOP => EMULTIHOP,
++ libc::ENOLINK => ENOLINK,
++ libc::EPROTO => EPROTO,
++ _ => UnknownErrno,
++ }
++ }
++}
+diff --git a/third_party/rust/nix/src/fcntl.rs b/third_party/rust/nix/src/fcntl.rs
+index be6ee0f73a8be..d2242dacd61b0 100644
+--- a/third_party/rust/nix/src/fcntl.rs
++++ b/third_party/rust/nix/src/fcntl.rs
+@@ -1,29 +1,34 @@
+-use {Error, Result, NixPath};
+-use errno::Errno;
+-use libc::{self, c_int, c_uint, c_char, size_t, ssize_t};
+-use sys::stat::Mode;
++use crate::errno::Errno;
++use libc::{self, c_char, c_int, c_uint, size_t, ssize_t};
++use std::ffi::OsString;
++#[cfg(not(target_os = "redox"))]
+ use std::os::raw;
++use std::os::unix::ffi::OsStringExt;
+ use std::os::unix::io::RawFd;
+-use std::ffi::OsStr;
+-use std::os::unix::ffi::OsStrExt;
++use crate::sys::stat::Mode;
++use crate::{NixPath, Result};
+
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ use std::ptr; // For splice and copy_file_range
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+-use sys::uio::IoVec; // For vmsplice
+-
+-#[cfg(any(target_os = "linux",
+- target_os = "android",
+- target_os = "emscripten",
+- target_os = "fuchsia",
+- any(target_os = "wasi", target_env = "wasi"),
+- target_env = "uclibc",
+- target_env = "freebsd"))]
++use crate::sys::uio::IoVec; // For vmsplice
++
++#[cfg(any(
++ target_os = "linux",
++ target_os = "android",
++ target_os = "emscripten",
++ target_os = "fuchsia",
++ any(target_os = "wasi", target_env = "wasi"),
++ target_env = "uclibc",
++ target_os = "freebsd"
++))]
+ pub use self::posix_fadvise::*;
+
+-libc_bitflags!{
++#[cfg(not(target_os = "redox"))]
++libc_bitflags! {
+ pub struct AtFlags: c_int {
+ AT_REMOVEDIR;
++ AT_SYMLINK_FOLLOW;
+ AT_SYMLINK_NOFOLLOW;
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ AT_NO_AUTOMOUNT;
+@@ -78,7 +83,8 @@ libc_bitflags!(
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+- target_os = "openbsd"))]
++ target_os = "openbsd",
++ target_os = "redox"))]
+ O_EXLOCK;
+ /// Same as `O_SYNC`.
+ #[cfg(any(target_os = "dragonfly",
+@@ -87,7 +93,8 @@ libc_bitflags!(
+ all(target_os = "linux", not(target_env = "musl")),
+ target_os = "macos",
+ target_os = "netbsd",
+- target_os = "openbsd"))]
++ target_os = "openbsd",
++ target_os = "redox"))]
+ O_FSYNC;
+ /// Allow files whose sizes can't be represented in an `off_t` to be opened.
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+@@ -96,8 +103,10 @@ libc_bitflags!(
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ O_NOATIME;
+ /// Don't attach the device as the process' controlling terminal.
++ #[cfg(not(target_os = "redox"))]
+ O_NOCTTY;
+ /// Same as `O_NONBLOCK`.
++ #[cfg(not(target_os = "redox"))]
+ O_NDELAY;
+ /// `open()` will fail if the given path is a symbolic link.
+ O_NOFOLLOW;
+@@ -109,7 +118,7 @@ libc_bitflags!(
+ /// Obtain a file descriptor for low-level access.
+ ///
+ /// The file itself is not opened and other file operations will fail.
+- #[cfg(any(target_os = "android", target_os = "linux"))]
++ #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))]
+ O_PATH;
+ /// Only allow reading.
+ ///
+@@ -131,9 +140,11 @@ libc_bitflags!(
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+- target_os = "openbsd"))]
++ target_os = "openbsd",
++ target_os = "redox"))]
+ O_SHLOCK;
+ /// Implicitly follow each `write()` with an `fsync()`.
++ #[cfg(not(target_os = "redox"))]
+ O_SYNC;
+ /// Create an unnamed temporary file.
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+@@ -150,6 +161,8 @@ libc_bitflags!(
+ }
+ );
+
++// The conversion is not identical on all operating systems.
++#[allow(clippy::identity_conversion)]
+ pub fn open<P: ?Sized + NixPath>(path: &P, oflag: OFlag, mode: Mode) -> Result<RawFd> {
+ let fd = path.with_nix_path(|cstr| {
+ unsafe { libc::open(cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint) }
+@@ -158,56 +171,125 @@ pub fn open<P: ?Sized + NixPath>(path: &P, oflag: OFlag, mode: Mode) -> Result<R
+ Errno::result(fd)
+ }
+
+-pub fn openat<P: ?Sized + NixPath>(dirfd: RawFd, path: &P, oflag: OFlag, mode: Mode) -> Result<RawFd> {
++// The conversion is not identical on all operating systems.
++#[allow(clippy::identity_conversion)]
++#[cfg(not(target_os = "redox"))]
++pub fn openat<P: ?Sized + NixPath>(
++ dirfd: RawFd,
++ path: &P,
++ oflag: OFlag,
++ mode: Mode,
++) -> Result<RawFd> {
+ let fd = path.with_nix_path(|cstr| {
+ unsafe { libc::openat(dirfd, cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint) }
+ })?;
+ Errno::result(fd)
+ }
+
+-pub fn renameat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(old_dirfd: Option<RawFd>, old_path: &P1,
+- new_dirfd: Option<RawFd>, new_path: &P2)
+- -> Result<()> {
++#[cfg(not(target_os = "redox"))]
++pub fn renameat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(
++ old_dirfd: Option<RawFd>,
++ old_path: &P1,
++ new_dirfd: Option<RawFd>,
++ new_path: &P2,
++) -> Result<()> {
+ let res = old_path.with_nix_path(|old_cstr| {
+ new_path.with_nix_path(|new_cstr| unsafe {
+- libc::renameat(at_rawfd(old_dirfd), old_cstr.as_ptr(),
+- at_rawfd(new_dirfd), new_cstr.as_ptr())
++ libc::renameat(
++ at_rawfd(old_dirfd),
++ old_cstr.as_ptr(),
++ at_rawfd(new_dirfd),
++ new_cstr.as_ptr(),
++ )
+ })
+ })??;
+ Errno::result(res).map(drop)
+ }
+
+-fn wrap_readlink_result(buffer: &mut[u8], res: ssize_t) -> Result<&OsStr> {
+- match Errno::result(res) {
+- Err(err) => Err(err),
+- Ok(len) => {
+- if (len as usize) >= buffer.len() {
+- Err(Error::Sys(Errno::ENAMETOOLONG))
+- } else {
+- Ok(OsStr::from_bytes(&buffer[..(len as usize)]))
++fn wrap_readlink_result(mut v: Vec<u8>, len: ssize_t) -> Result<OsString> {
++ unsafe { v.set_len(len as usize) }
++ v.shrink_to_fit();
++ Ok(OsString::from_vec(v.to_vec()))
++}
++
++fn readlink_maybe_at<P: ?Sized + NixPath>(
++ dirfd: Option<RawFd>,
++ path: &P,
++ v: &mut Vec<u8>,
++) -> Result<libc::ssize_t> {
++ path.with_nix_path(|cstr| unsafe {
++ match dirfd {
++ #[cfg(target_os = "redox")]
++ Some(_) => unreachable!(),
++ #[cfg(not(target_os = "redox"))]
++ Some(dirfd) => libc::readlinkat(
++ dirfd,
++ cstr.as_ptr(),
++ v.as_mut_ptr() as *mut c_char,
++ v.capacity() as size_t,
++ ),
++ None => libc::readlink(
++ cstr.as_ptr(),
++ v.as_mut_ptr() as *mut c_char,
++ v.capacity() as size_t,
++ ),
++ }
++ })
++}
++
++fn inner_readlink<P: ?Sized + NixPath>(dirfd: Option<RawFd>, path: &P) -> Result<OsString> {
++ let mut v = Vec::with_capacity(libc::PATH_MAX as usize);
++ // simple case: result is strictly less than `PATH_MAX`
++ let res = readlink_maybe_at(dirfd, path, &mut v)?;
++ let len = Errno::result(res)?;
++ debug_assert!(len >= 0);
++ if (len as usize) < v.capacity() {
++ return wrap_readlink_result(v, res);
++ }
++ // Uh oh, the result is too long...
++ // Let's try to ask lstat how many bytes to allocate.
++ let reported_size = super::sys::stat::lstat(path)
++ .and_then(|x| Ok(x.st_size))
++ .unwrap_or(0);
++ let mut try_size = if reported_size > 0 {
++ // Note: even if `lstat`'s apparently valid answer turns out to be
++ // wrong, we will still read the full symlink no matter what.
++ reported_size as usize + 1
++ } else {
++ // If lstat doesn't cooperate, or reports an error, be a little less
++ // precise.
++ (libc::PATH_MAX as usize).max(128) << 1
++ };
++ loop {
++ v.reserve_exact(try_size);
++ let res = readlink_maybe_at(dirfd, path, &mut v)?;
++ let len = Errno::result(res)?;
++ debug_assert!(len >= 0);
++ if (len as usize) < v.capacity() {
++ break wrap_readlink_result(v, res);
++ } else {
++ // Ugh! Still not big enough!
++ match try_size.checked_shl(1) {
++ Some(next_size) => try_size = next_size,
++ // It's absurd that this would happen, but handle it sanely
++ // anyway.
++ None => break Err(super::Error::Sys(Errno::ENAMETOOLONG)),
+ }
+ }
+ }
+ }
+
+-pub fn readlink<'a, P: ?Sized + NixPath>(path: &P, buffer: &'a mut [u8]) -> Result<&'a OsStr> {
+- let res = path.with_nix_path(|cstr| {
+- unsafe { libc::readlink(cstr.as_ptr(), buffer.as_mut_ptr() as *mut c_char, buffer.len() as size_t) }
+- })?;
+-
+- wrap_readlink_result(buffer, res)
++pub fn readlink<P: ?Sized + NixPath>(path: &P) -> Result<OsString> {
++ inner_readlink(None, path)
+ }
+
+-
+-pub fn readlinkat<'a, P: ?Sized + NixPath>(dirfd: RawFd, path: &P, buffer: &'a mut [u8]) -> Result<&'a OsStr> {
+- let res = path.with_nix_path(|cstr| {
+- unsafe { libc::readlinkat(dirfd, cstr.as_ptr(), buffer.as_mut_ptr() as *mut c_char, buffer.len() as size_t) }
+- })?;
+-
+- wrap_readlink_result(buffer, res)
++#[cfg(not(target_os = "redox"))]
++pub fn readlinkat<P: ?Sized + NixPath>(dirfd: RawFd, path: &P) -> Result<OsString> {
++ inner_readlink(Some(dirfd), path)
+ }
+
+ /// Computes the raw fd consumed by a function of the form `*at`.
++#[cfg(not(target_os = "redox"))]
+ pub(crate) fn at_rawfd(fd: Option<RawFd>) -> raw::c_int {
+ match fd {
+ None => libc::AT_FDCWD,
+@@ -238,6 +320,7 @@ libc_bitflags!(
+ }
+ );
+
++#[cfg(not(target_os = "redox"))]
+ #[derive(Debug, Eq, Hash, PartialEq)]
+ pub enum FcntlArg<'a> {
+ F_DUPFD(RawFd),
+@@ -265,9 +348,19 @@ pub enum FcntlArg<'a> {
+ F_GETPIPE_SZ,
+ #[cfg(any(target_os = "linux", target_os = "android"))]
+ F_SETPIPE_SZ(c_int),
+-
+ // TODO: Rest of flags
+ }
++
++#[cfg(target_os = "redox")]
++#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
++pub enum FcntlArg {
++ F_DUPFD(RawFd),
++ F_DUPFD_CLOEXEC(RawFd),
++ F_GETFD,
++ F_SETFD(FdFlag), // FD_FLAGS
++ F_GETFL,
++ F_SETFL(OFlag), // O_NONBLOCK
++}
+ pub use self::FcntlArg::*;
+
+ // TODO: Figure out how to handle value fcntl returns
+@@ -280,10 +373,19 @@ pub fn fcntl(fd: RawFd, arg: FcntlArg) -> Result<c_int> {
+ F_SETFD(flag) => libc::fcntl(fd, libc::F_SETFD, flag.bits()),
+ F_GETFL => libc::fcntl(fd, libc::F_GETFL),
+ F_SETFL(flag) => libc::fcntl(fd, libc::F_SETFL, flag.bits()),
++ #[cfg(not(target_os = "redox"))]
+ F_SETLK(flock) => libc::fcntl(fd, libc::F_SETLK, flock),
++ #[cfg(not(target_os = "redox"))]
+ F_SETLKW(flock) => libc::fcntl(fd, libc::F_SETLKW, flock),
++ #[cfg(not(target_os = "redox"))]
+ F_GETLK(flock) => libc::fcntl(fd, libc::F_GETLK, flock),
+ #[cfg(any(target_os = "android", target_os = "linux"))]
++ F_OFD_SETLK(flock) => libc::fcntl(fd, libc::F_OFD_SETLK, flock),
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ F_OFD_SETLKW(flock) => libc::fcntl(fd, libc::F_OFD_SETLKW, flock),
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ F_OFD_GETLK(flock) => libc::fcntl(fd, libc::F_OFD_GETLK, flock),
++ #[cfg(any(target_os = "android", target_os = "linux"))]
+ F_ADD_SEALS(flag) => libc::fcntl(fd, libc::F_ADD_SEALS, flag.bits()),
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ F_GET_SEALS => libc::fcntl(fd, libc::F_GET_SEALS),
+@@ -293,8 +395,6 @@ pub fn fcntl(fd: RawFd, arg: FcntlArg) -> Result<c_int> {
+ F_GETPIPE_SZ => libc::fcntl(fd, libc::F_GETPIPE_SZ),
+ #[cfg(any(target_os = "linux", target_os = "android"))]
+ F_SETPIPE_SZ(size) => libc::fcntl(fd, libc::F_SETPIPE_SZ, size),
+- #[cfg(any(target_os = "linux", target_os = "android"))]
+- _ => unimplemented!()
+ }
+ };
+
+@@ -311,6 +411,7 @@ pub enum FlockArg {
+ UnlockNonblock,
+ }
+
++#[cfg(not(target_os = "redox"))]
+ pub fn flock(fd: RawFd, arg: FlockArg) -> Result<()> {
+ use self::FlockArg::*;
+
+@@ -410,9 +511,7 @@ pub fn splice(
+ .map(|offset| offset as *mut libc::loff_t)
+ .unwrap_or(ptr::null_mut());
+
+- let ret = unsafe {
+- libc::splice(fd_in, off_in, fd_out, off_out, len, flags.bits())
+- };
++ let ret = unsafe { libc::splice(fd_in, off_in, fd_out, off_out, len, flags.bits()) };
+ Errno::result(ret).map(|r| r as usize)
+ }
+
+@@ -425,7 +524,12 @@ pub fn tee(fd_in: RawFd, fd_out: RawFd, len: usize, flags: SpliceFFlags) -> Resu
+ #[cfg(any(target_os = "linux", target_os = "android"))]
+ pub fn vmsplice(fd: RawFd, iov: &[IoVec<&[u8]>], flags: SpliceFFlags) -> Result<usize> {
+ let ret = unsafe {
+- libc::vmsplice(fd, iov.as_ptr() as *const libc::iovec, iov.len(), flags.bits())
++ libc::vmsplice(
++ fd,
++ iov.as_ptr() as *const libc::iovec,
++ iov.len(),
++ flags.bits(),
++ )
+ };
+ Errno::result(ret).map(|r| r as usize)
+ }
+@@ -466,23 +570,30 @@ libc_bitflags!(
+ /// Allows the caller to directly manipulate the allocated disk space for the
+ /// file referred to by fd.
+ #[cfg(any(target_os = "linux"))]
+-pub fn fallocate(fd: RawFd, mode: FallocateFlags, offset: libc::off_t, len: libc::off_t) -> Result<c_int> {
++pub fn fallocate(
++ fd: RawFd,
++ mode: FallocateFlags,
++ offset: libc::off_t,
++ len: libc::off_t,
++) -> Result<()> {
+ let res = unsafe { libc::fallocate(fd, mode.bits(), offset, len) };
+- Errno::result(res)
++ Errno::result(res).map(drop)
+ }
+
+-#[cfg(any(target_os = "linux",
+- target_os = "android",
+- target_os = "emscripten",
+- target_os = "fuchsia",
+- any(target_os = "wasi", target_env = "wasi"),
+- target_env = "uclibc",
+- target_env = "freebsd"))]
++#[cfg(any(
++ target_os = "linux",
++ target_os = "android",
++ target_os = "emscripten",
++ target_os = "fuchsia",
++ any(target_os = "wasi", target_env = "wasi"),
++ target_env = "uclibc",
++ target_os = "freebsd"
++))]
+ mod posix_fadvise {
+- use Result;
++ use crate::errno::Errno;
+ use libc;
+- use errno::Errno;
+ use std::os::unix::io::RawFd;
++ use crate::Result;
+
+ libc_enum! {
+ #[repr(i32)]
+@@ -496,11 +607,30 @@ mod posix_fadvise {
+ }
+ }
+
+- pub fn posix_fadvise(fd: RawFd,
+- offset: libc::off_t,
+- len: libc::off_t,
+- advice: PosixFadviseAdvice) -> Result<libc::c_int> {
++ pub fn posix_fadvise(
++ fd: RawFd,
++ offset: libc::off_t,
++ len: libc::off_t,
++ advice: PosixFadviseAdvice,
++ ) -> Result<libc::c_int> {
+ let res = unsafe { libc::posix_fadvise(fd, offset, len, advice as libc::c_int) };
+ Errno::result(res)
+ }
+ }
++
++#[cfg(any(
++ target_os = "linux",
++ target_os = "android",
++ target_os = "emscripten",
++ target_os = "fuchsia",
++ any(target_os = "wasi", target_env = "wasi"),
++ target_os = "freebsd"
++))]
++pub fn posix_fallocate(fd: RawFd, offset: libc::off_t, len: libc::off_t) -> Result<()> {
++ let res = unsafe { libc::posix_fallocate(fd, offset, len) };
++ match Errno::result(res) {
++ Err(err) => Err(err),
++ Ok(0) => Ok(()),
++ Ok(errno) => Err(crate::Error::Sys(Errno::from_i32(errno))),
++ }
++}
+diff --git a/third_party/rust/nix/src/features.rs b/third_party/rust/nix/src/features.rs
+index 76cdfd3a1a6f1..6b1cff5deed1d 100644
+--- a/third_party/rust/nix/src/features.rs
++++ b/third_party/rust/nix/src/features.rs
+@@ -3,7 +3,7 @@ pub use self::os::*;
+
+ #[cfg(any(target_os = "linux", target_os = "android"))]
+ mod os {
+- use sys::utsname::uname;
++ use crate::sys::utsname::uname;
+
+ // Features:
+ // * atomic cloexec on socket: 2.6.27
+@@ -94,7 +94,10 @@ mod os {
+ }
+ }
+
+-#[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "dragonfly", target_os = "ios", target_os = "openbsd", target_os = "netbsd"))]
++#[cfg(any(target_os = "macos", target_os = "freebsd",
++ target_os = "dragonfly", target_os = "ios",
++ target_os = "openbsd", target_os = "netbsd",
++ target_os = "redox", target_os = "fuchsia"))]
+ mod os {
+ /// Check if the OS supports atomic close-on-exec for sockets
+ pub fn socket_atomic_cloexec() -> bool {
+diff --git a/third_party/rust/nix/src/ifaddrs.rs b/third_party/rust/nix/src/ifaddrs.rs
+index 12b59bcc92bef..ed6328f3efab2 100644
+--- a/third_party/rust/nix/src/ifaddrs.rs
++++ b/third_party/rust/nix/src/ifaddrs.rs
+@@ -3,16 +3,15 @@
+ //! Uses the Linux and/or BSD specific function `getifaddrs` to query the list
+ //! of interfaces and their associated addresses.
+
++use cfg_if::cfg_if;
+ use std::ffi;
+ use std::iter::Iterator;
+ use std::mem;
+ use std::option::Option;
+
+-use libc;
+-
+-use {Result, Errno};
+-use sys::socket::SockAddr;
+-use net::if_::*;
++use crate::{Result, Errno};
++use crate::sys::socket::SockAddr;
++use crate::net::if_::*;
+
+ /// Describes a single address for an interface as returned by `getifaddrs`.
+ #[derive(Clone, Debug, Eq, Hash, PartialEq)]
+@@ -52,8 +51,8 @@ impl InterfaceAddress {
+ let mut addr = InterfaceAddress {
+ interface_name: ifname.to_string_lossy().to_string(),
+ flags: InterfaceFlags::from_bits_truncate(info.ifa_flags as i32),
+- address: address,
+- netmask: netmask,
++ address,
++ netmask,
+ broadcast: None,
+ destination: None,
+ };
+@@ -125,13 +124,15 @@ impl Iterator for InterfaceAddressIterator {
+ /// }
+ /// ```
+ pub fn getifaddrs() -> Result<InterfaceAddressIterator> {
+- let mut addrs: *mut libc::ifaddrs = unsafe { mem::uninitialized() };
+- Errno::result(unsafe { libc::getifaddrs(&mut addrs) }).map(|_| {
+- InterfaceAddressIterator {
+- base: addrs,
+- next: addrs,
+- }
+- })
++ let mut addrs = mem::MaybeUninit::<*mut libc::ifaddrs>::uninit();
++ unsafe {
++ Errno::result(libc::getifaddrs(addrs.as_mut_ptr())).map(|_| {
++ InterfaceAddressIterator {
++ base: addrs.assume_init(),
++ next: addrs.assume_init(),
++ }
++ })
++ }
+ }
+
+ #[cfg(test)]
+diff --git a/third_party/rust/nix/src/kmod.rs b/third_party/rust/nix/src/kmod.rs
+index e853261b14f9d..8789cb69f4617 100644
+--- a/third_party/rust/nix/src/kmod.rs
++++ b/third_party/rust/nix/src/kmod.rs
+@@ -6,8 +6,8 @@ use libc;
+ use std::ffi::CStr;
+ use std::os::unix::io::AsRawFd;
+
+-use errno::Errno;
+-use Result;
++use crate::errno::Errno;
++use crate::Result;
+
+ /// Loads a kernel module from a buffer.
+ ///
+diff --git a/third_party/rust/nix/src/lib.rs b/third_party/rust/nix/src/lib.rs
+index 71485d2af1824..e62c158c8bc9b 100644
+--- a/third_party/rust/nix/src/lib.rs
++++ b/third_party/rust/nix/src/lib.rs
+@@ -14,24 +14,17 @@
+ #![deny(unstable_features)]
+ #![deny(missing_copy_implementations)]
+ #![deny(missing_debug_implementations)]
+-// XXX Allow deprecated items until release 0.16.0. See issue #1096.
+-#![allow(deprecated)]
+-
+-// External crates
+-#[macro_use]
+-extern crate bitflags;
+-#[macro_use]
+-extern crate cfg_if;
+-extern crate void;
+
+ // Re-exported external crates
+-pub extern crate libc;
++pub use libc;
+
+ // Private internal modules
+ #[macro_use] mod macros;
+
+ // Public crates
++#[cfg(not(target_os = "redox"))]
+ pub mod dir;
++pub mod env;
+ pub mod errno;
+ #[deny(missing_docs)]
+ pub mod features;
+@@ -59,13 +52,16 @@ pub mod mount;
+ target_os = "netbsd"))]
+ pub mod mqueue;
+ #[deny(missing_docs)]
++#[cfg(not(target_os = "redox"))]
+ pub mod net;
+ #[deny(missing_docs)]
+ pub mod poll;
+ #[deny(missing_docs)]
++#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
+ pub mod pty;
+ pub mod sched;
+ pub mod sys;
++pub mod time;
+ // This can be implemented for other platforms as soon as libc
+ // provides bindings for them.
+ #[cfg(all(target_os = "linux",
+@@ -121,9 +117,9 @@ impl Error {
+ /// let e = Error::from(Errno::EPERM);
+ /// assert_eq!(Some(Errno::EPERM), e.as_errno());
+ /// ```
+- pub fn as_errno(&self) -> Option<Errno> {
+- if let &Error::Sys(ref e) = self {
+- Some(*e)
++ pub fn as_errno(self) -> Option<Errno> {
++ if let Error::Sys(e) = self {
++ Some(e)
+ } else {
+ None
+ }
+@@ -154,16 +150,7 @@ impl From<std::string::FromUtf8Error> for Error {
+ fn from(_: std::string::FromUtf8Error) -> Error { Error::InvalidUtf8 }
+ }
+
+-impl error::Error for Error {
+- fn description(&self) -> &str {
+- match *self {
+- Error::InvalidPath => "Invalid path",
+- Error::InvalidUtf8 => "Invalid UTF-8 string",
+- Error::UnsupportedOperation => "Unsupported Operation",
+- Error::Sys(ref errno) => errno.desc(),
+- }
+- }
+-}
++impl error::Error for Error {}
+
+ impl fmt::Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+@@ -177,6 +164,8 @@ impl fmt::Display for Error {
+ }
+
+ pub trait NixPath {
++ fn is_empty(&self) -> bool;
++
+ fn len(&self) -> usize;
+
+ fn with_nix_path<T, F>(&self, f: F) -> Result<T>
+@@ -184,6 +173,10 @@ pub trait NixPath {
+ }
+
+ impl NixPath for str {
++ fn is_empty(&self) -> bool {
++ NixPath::is_empty(OsStr::new(self))
++ }
++
+ fn len(&self) -> usize {
+ NixPath::len(OsStr::new(self))
+ }
+@@ -195,6 +188,10 @@ impl NixPath for str {
+ }
+
+ impl NixPath for OsStr {
++ fn is_empty(&self) -> bool {
++ self.as_bytes().is_empty()
++ }
++
+ fn len(&self) -> usize {
+ self.as_bytes().len()
+ }
+@@ -206,6 +203,10 @@ impl NixPath for OsStr {
+ }
+
+ impl NixPath for CStr {
++ fn is_empty(&self) -> bool {
++ self.to_bytes().is_empty()
++ }
++
+ fn len(&self) -> usize {
+ self.to_bytes().len()
+ }
+@@ -222,6 +223,10 @@ impl NixPath for CStr {
+ }
+
+ impl NixPath for [u8] {
++ fn is_empty(&self) -> bool {
++ self.is_empty()
++ }
++
+ fn len(&self) -> usize {
+ self.len()
+ }
+@@ -249,6 +254,10 @@ impl NixPath for [u8] {
+ }
+
+ impl NixPath for Path {
++ fn is_empty(&self) -> bool {
++ NixPath::is_empty(self.as_os_str())
++ }
++
+ fn len(&self) -> usize {
+ NixPath::len(self.as_os_str())
+ }
+@@ -259,26 +268,15 @@ impl NixPath for Path {
+ }
+
+ impl NixPath for PathBuf {
+- fn len(&self) -> usize {
+- NixPath::len(self.as_os_str())
++ fn is_empty(&self) -> bool {
++ NixPath::is_empty(self.as_os_str())
+ }
+
+- fn with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T {
+- self.as_os_str().with_nix_path(f)
+- }
+-}
+-
+-/// Treats `None` as an empty string.
+-impl<'a, NP: ?Sized + NixPath> NixPath for Option<&'a NP> {
+ fn len(&self) -> usize {
+- self.map_or(0, NixPath::len)
++ NixPath::len(self.as_os_str())
+ }
+
+ fn with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T {
+- if let Some(nix_path) = *self {
+- nix_path.with_nix_path(f)
+- } else {
+- unsafe { CStr::from_ptr("\0".as_ptr() as *const _).with_nix_path(f) }
+- }
++ self.as_os_str().with_nix_path(f)
+ }
+ }
+diff --git a/third_party/rust/nix/src/macros.rs b/third_party/rust/nix/src/macros.rs
+index 3d1b0e4b7699c..7d6ac8dfbf5f7 100644
+--- a/third_party/rust/nix/src/macros.rs
++++ b/third_party/rust/nix/src/macros.rs
+@@ -48,7 +48,7 @@ macro_rules! libc_bitflags {
+ )+
+ }
+ ) => {
+- bitflags! {
++ ::bitflags::bitflags! {
+ $(#[$outer])*
+ pub struct $BitFlags: $T {
+ $(
+@@ -81,9 +81,10 @@ macro_rules! libc_bitflags {
+ /// }
+ /// ```
+ macro_rules! libc_enum {
+- // (non-pub) Exit rule.
++ // Exit rule.
+ (@make_enum
+ {
++ $v:vis
+ name: $BitFlags:ident,
+ attrs: [$($attrs:tt)*],
+ entries: [$($entries:tt)*],
+@@ -91,49 +92,15 @@ macro_rules! libc_enum {
+ ) => {
+ $($attrs)*
+ #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+- enum $BitFlags {
++ $v enum $BitFlags {
+ $($entries)*
+ }
+ };
+
+- // (pub) Exit rule.
+- (@make_enum
+- {
+- pub,
+- name: $BitFlags:ident,
+- attrs: [$($attrs:tt)*],
+- entries: [$($entries:tt)*],
+- }
+- ) => {
+- $($attrs)*
+- #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+- pub enum $BitFlags {
+- $($entries)*
+- }
+- };
+-
+- // (non-pub) Done accumulating.
+- (@accumulate_entries
+- {
+- name: $BitFlags:ident,
+- attrs: $attrs:tt,
+- },
+- $entries:tt;
+- ) => {
+- libc_enum! {
+- @make_enum
+- {
+- name: $BitFlags,
+- attrs: $attrs,
+- entries: $entries,
+- }
+- }
+- };
+-
+- // (pub) Done accumulating.
++ // Done accumulating.
+ (@accumulate_entries
+ {
+- pub,
++ $v:vis
+ name: $BitFlags:ident,
+ attrs: $attrs:tt,
+ },
+@@ -142,7 +109,7 @@ macro_rules! libc_enum {
+ libc_enum! {
+ @make_enum
+ {
+- pub,
++ $v
+ name: $BitFlags,
+ attrs: $attrs,
+ entries: $entries,
+@@ -217,35 +184,17 @@ macro_rules! libc_enum {
+ }
+ };
+
+- // (non-pub) Entry rule.
+- (
+- $(#[$attr:meta])*
+- enum $BitFlags:ident {
+- $($vals:tt)*
+- }
+- ) => {
+- libc_enum! {
+- @accumulate_entries
+- {
+- name: $BitFlags,
+- attrs: [$(#[$attr])*],
+- },
+- [];
+- $($vals)*
+- }
+- };
+-
+- // (pub) Entry rule.
++ // Entry rule.
+ (
+ $(#[$attr:meta])*
+- pub enum $BitFlags:ident {
++ $v:vis enum $BitFlags:ident {
+ $($vals:tt)*
+ }
+ ) => {
+ libc_enum! {
+ @accumulate_entries
+ {
+- pub,
++ $v
+ name: $BitFlags,
+ attrs: [$(#[$attr])*],
+ },
+@@ -254,11 +203,3 @@ macro_rules! libc_enum {
+ }
+ };
+ }
+-
+-/// A Rust version of the familiar C `offset_of` macro. It returns the byte
+-/// offset of `field` within struct `ty`
+-macro_rules! offset_of {
+- ($ty:ty, $field:ident) => {
+- &(*(0 as *const $ty)).$field as *const _ as usize
+- }
+-}
+diff --git a/third_party/rust/nix/src/mount.rs b/third_party/rust/nix/src/mount.rs
+index a9902b170ace8..2c54761e2bb0c 100644
+--- a/third_party/rust/nix/src/mount.rs
++++ b/third_party/rust/nix/src/mount.rs
+@@ -1,6 +1,6 @@
+ use libc::{self, c_ulong, c_int};
+-use {Result, NixPath};
+-use errno::Errno;
++use crate::{Result, NixPath};
++use crate::errno::Errno;
+
+ libc_bitflags!(
+ pub struct MsFlags: c_ulong {
+@@ -61,22 +61,33 @@ pub fn mount<P1: ?Sized + NixPath, P2: ?Sized + NixPath, P3: ?Sized + NixPath, P
+ flags: MsFlags,
+ data: Option<&P4>) -> Result<()> {
+
+- let res =
+- source.with_nix_path(|source| {
+- target.with_nix_path(|target| {
+- fstype.with_nix_path(|fstype| {
+- data.with_nix_path(|data| {
+- unsafe {
+- libc::mount(source.as_ptr(),
+- target.as_ptr(),
+- fstype.as_ptr(),
+- flags.bits,
+- data.as_ptr() as *const libc::c_void)
+- }
+- })
++ fn with_opt_nix_path<P, T, F>(p: Option<&P>, f: F) -> Result<T>
++ where P: ?Sized + NixPath,
++ F: FnOnce(*const libc::c_char) -> T
++ {
++ match p {
++ Some(path) => path.with_nix_path(|p_str| f(p_str.as_ptr())),
++ None => Ok(f(std::ptr::null()))
++ }
++ }
++
++ let res = with_opt_nix_path(source, |s| {
++ target.with_nix_path(|t| {
++ with_opt_nix_path(fstype, |ty| {
++ with_opt_nix_path(data, |d| {
++ unsafe {
++ libc::mount(
++ s,
++ t.as_ptr(),
++ ty,
++ flags.bits,
++ d as *const libc::c_void
++ )
++ }
+ })
+ })
+- })????;
++ })
++ })????;
+
+ Errno::result(res).map(drop)
+ }
+diff --git a/third_party/rust/nix/src/mqueue.rs b/third_party/rust/nix/src/mqueue.rs
+index b958b71cddb46..0215de5af214b 100644
+--- a/third_party/rust/nix/src/mqueue.rs
++++ b/third_party/rust/nix/src/mqueue.rs
+@@ -2,12 +2,12 @@
+ //!
+ //! [Further reading and details on the C API](http://man7.org/linux/man-pages/man7/mq_overview.7.html)
+
+-use Result;
+-use errno::Errno;
++use crate::Result;
++use crate::errno::Errno;
+
+-use libc::{self, c_char, c_long, mqd_t, size_t};
++use libc::{self, c_char, mqd_t, size_t};
+ use std::ffi::CString;
+-use sys::stat::Mode;
++use crate::sys::stat::Mode;
+ use std::mem;
+
+ libc_bitflags!{
+@@ -34,21 +34,32 @@ pub struct MqAttr {
+ mq_attr: libc::mq_attr,
+ }
+
++// x32 compatibility
++// See https://sourceware.org/bugzilla/show_bug.cgi?id=21279
++#[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))]
++pub type mq_attr_member_t = i64;
++#[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))]
++pub type mq_attr_member_t = libc::c_long;
++
+ impl MqAttr {
+- pub fn new(mq_flags: c_long,
+- mq_maxmsg: c_long,
+- mq_msgsize: c_long,
+- mq_curmsgs: c_long)
+- -> MqAttr {
+- let mut attr = unsafe { mem::uninitialized::<libc::mq_attr>() };
+- attr.mq_flags = mq_flags;
+- attr.mq_maxmsg = mq_maxmsg;
+- attr.mq_msgsize = mq_msgsize;
+- attr.mq_curmsgs = mq_curmsgs;
+- MqAttr { mq_attr: attr }
++ pub fn new(mq_flags: mq_attr_member_t,
++ mq_maxmsg: mq_attr_member_t,
++ mq_msgsize: mq_attr_member_t,
++ mq_curmsgs: mq_attr_member_t)
++ -> MqAttr
++ {
++ let mut attr = mem::MaybeUninit::<libc::mq_attr>::uninit();
++ unsafe {
++ let p = attr.as_mut_ptr();
++ (*p).mq_flags = mq_flags;
++ (*p).mq_maxmsg = mq_maxmsg;
++ (*p).mq_msgsize = mq_msgsize;
++ (*p).mq_curmsgs = mq_curmsgs;
++ MqAttr { mq_attr: attr.assume_init() }
++ }
+ }
+
+- pub fn flags(&self) -> c_long {
++ pub fn flags(&self) -> mq_attr_member_t {
+ self.mq_attr.mq_flags
+ }
+ }
+@@ -57,6 +68,8 @@ impl MqAttr {
+ /// Open a message queue
+ ///
+ /// See also [`mq_open(2)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_open.html)
++// The mode.bits cast is only lossless on some OSes
++#[allow(clippy::cast_lossless)]
+ pub fn mq_open(name: &CString,
+ oflag: MQ_OFlag,
+ mode: Mode,
+@@ -121,9 +134,9 @@ pub fn mq_send(mqdes: mqd_t, message: &[u8], msq_prio: u32) -> Result<()> {
+ ///
+ /// See also [`mq_getattr(2)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_getattr.html)
+ pub fn mq_getattr(mqd: mqd_t) -> Result<MqAttr> {
+- let mut attr = unsafe { mem::uninitialized::<libc::mq_attr>() };
+- let res = unsafe { libc::mq_getattr(mqd, &mut attr) };
+- Errno::result(res).map(|_| MqAttr { mq_attr: attr })
++ let mut attr = mem::MaybeUninit::<libc::mq_attr>::uninit();
++ let res = unsafe { libc::mq_getattr(mqd, attr.as_mut_ptr()) };
++ Errno::result(res).map(|_| unsafe{MqAttr { mq_attr: attr.assume_init() }})
+ }
+
+ /// Set the attributes of the message queue. Only `O_NONBLOCK` can be set, everything else will be ignored
+@@ -132,17 +145,19 @@ pub fn mq_getattr(mqd: mqd_t) -> Result<MqAttr> {
+ ///
+ /// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_setattr.html)
+ pub fn mq_setattr(mqd: mqd_t, newattr: &MqAttr) -> Result<MqAttr> {
+- let mut attr = unsafe { mem::uninitialized::<libc::mq_attr>() };
+- let res = unsafe { libc::mq_setattr(mqd, &newattr.mq_attr as *const libc::mq_attr, &mut attr) };
+- Errno::result(res).map(|_| MqAttr { mq_attr: attr })
++ let mut attr = mem::MaybeUninit::<libc::mq_attr>::uninit();
++ let res = unsafe {
++ libc::mq_setattr(mqd, &newattr.mq_attr as *const libc::mq_attr, attr.as_mut_ptr())
++ };
++ Errno::result(res).map(|_| unsafe{ MqAttr { mq_attr: attr.assume_init() }})
+ }
+
+ /// Convenience function.
+ /// Sets the `O_NONBLOCK` attribute for a given message queue descriptor
+ /// Returns the old attributes
+-pub fn mq_set_nonblock(mqd: mqd_t) -> Result<(MqAttr)> {
++pub fn mq_set_nonblock(mqd: mqd_t) -> Result<MqAttr> {
+ let oldattr = mq_getattr(mqd)?;
+- let newattr = MqAttr::new(MQ_OFlag::O_NONBLOCK.bits() as c_long,
++ let newattr = MqAttr::new(mq_attr_member_t::from(MQ_OFlag::O_NONBLOCK.bits()),
+ oldattr.mq_attr.mq_maxmsg,
+ oldattr.mq_attr.mq_msgsize,
+ oldattr.mq_attr.mq_curmsgs);
+@@ -152,7 +167,7 @@ pub fn mq_set_nonblock(mqd: mqd_t) -> Result<(MqAttr)> {
+ /// Convenience function.
+ /// Removes `O_NONBLOCK` attribute for a given message queue descriptor
+ /// Returns the old attributes
+-pub fn mq_remove_nonblock(mqd: mqd_t) -> Result<(MqAttr)> {
++pub fn mq_remove_nonblock(mqd: mqd_t) -> Result<MqAttr> {
+ let oldattr = mq_getattr(mqd)?;
+ let newattr = MqAttr::new(0,
+ oldattr.mq_attr.mq_maxmsg,
+diff --git a/third_party/rust/nix/src/net/if_.rs b/third_party/rust/nix/src/net/if_.rs
+index 58d677ae343d1..96364884e39cb 100644
+--- a/third_party/rust/nix/src/net/if_.rs
++++ b/third_party/rust/nix/src/net/if_.rs
+@@ -3,9 +3,8 @@
+ //! Uses Linux and/or POSIX functions to resolve interface names like "eth0"
+ //! or "socan1" into device numbers.
+
+-use libc;
+ use libc::c_uint;
+-use {Result, Error, NixPath};
++use crate::{Result, Error, NixPath};
+
+ /// Resolve an interface into a interface number.
+ pub fn if_nametoindex<P: ?Sized + NixPath>(name: &P) -> Result<c_uint> {
+diff --git a/third_party/rust/nix/src/poll.rs b/third_party/rust/nix/src/poll.rs
+index c603611e3176f..be5bf224990f2 100644
+--- a/third_party/rust/nix/src/poll.rs
++++ b/third_party/rust/nix/src/poll.rs
+@@ -1,13 +1,12 @@
+ //! Wait for events to trigger on specific file descriptors
+ #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))]
+-use sys::time::TimeSpec;
++use crate::sys::time::TimeSpec;
+ #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))]
+-use sys::signal::SigSet;
++use crate::sys::signal::SigSet;
+ use std::os::unix::io::RawFd;
+
+-use libc;
+-use Result;
+-use errno::Errno;
++use crate::Result;
++use crate::errno::Errno;
+
+ /// This is a wrapper around `libc::pollfd`.
+ ///
+@@ -17,7 +16,7 @@ use errno::Errno;
+ ///
+ /// After a call to `poll` or `ppoll`, the events that occured can be
+ /// retrieved by calling [`revents()`](#method.revents) on the `PollFd`.
+-#[repr(C)]
++#[repr(transparent)]
+ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+ pub struct PollFd {
+ pollfd: libc::pollfd,
+@@ -29,7 +28,7 @@ impl PollFd {
+ pub fn new(fd: RawFd, events: PollFlags) -> PollFd {
+ PollFd {
+ pollfd: libc::pollfd {
+- fd: fd,
++ fd,
+ events: events.bits(),
+ revents: PollFlags::empty().bits(),
+ },
+@@ -37,7 +36,7 @@ impl PollFd {
+ }
+
+ /// Returns the events that occured in the last call to `poll` or `ppoll`.
+- pub fn revents(&self) -> Option<PollFlags> {
++ pub fn revents(self) -> Option<PollFlags> {
+ PollFlags::from_bits(self.pollfd.revents)
+ }
+ }
+@@ -64,12 +63,16 @@ libc_bitflags! {
+ /// `O_NONBLOCK` is set).
+ POLLOUT;
+ /// Equivalent to [`POLLIN`](constant.POLLIN.html)
++ #[cfg(not(target_os = "redox"))]
+ POLLRDNORM;
++ #[cfg(not(target_os = "redox"))]
+ /// Equivalent to [`POLLOUT`](constant.POLLOUT.html)
+ POLLWRNORM;
+ /// Priority band data can be read (generally unused on Linux).
++ #[cfg(not(target_os = "redox"))]
+ POLLRDBAND;
+ /// Priority data may be written.
++ #[cfg(not(target_os = "redox"))]
+ POLLWRBAND;
+ /// Error condition (only returned in
+ /// [`PollFd::revents`](struct.PollFd.html#method.revents);
+@@ -127,16 +130,16 @@ pub fn poll(fds: &mut [PollFd], timeout: libc::c_int) -> Result<libc::c_int> {
+ /// ([`poll(2)`](http://man7.org/linux/man-pages/man2/poll.2.html))
+ ///
+ /// `ppoll` behaves like `poll`, but let you specify what signals may interrupt it
+-/// with the `sigmask` argument.
++/// with the `sigmask` argument. If you want `ppoll` to block indefinitely,
++/// specify `None` as `timeout` (it is like `timeout = -1` for `poll`).
+ ///
+ #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))]
+-pub fn ppoll(fds: &mut [PollFd], timeout: TimeSpec, sigmask: SigSet) -> Result<libc::c_int> {
+-
+-
++pub fn ppoll(fds: &mut [PollFd], timeout: Option<TimeSpec>, sigmask: SigSet) -> Result<libc::c_int> {
++ let timeout = timeout.as_ref().map_or(core::ptr::null(), |r| r.as_ref());
+ let res = unsafe {
+ libc::ppoll(fds.as_mut_ptr() as *mut libc::pollfd,
+ fds.len() as libc::nfds_t,
+- timeout.as_ref(),
++ timeout,
+ sigmask.as_ref())
+ };
+ Errno::result(res)
+diff --git a/third_party/rust/nix/src/pty.rs b/third_party/rust/nix/src/pty.rs
+index db012d8158c53..d67518f4744f3 100644
+--- a/third_party/rust/nix/src/pty.rs
++++ b/third_party/rust/nix/src/pty.rs
+@@ -1,18 +1,17 @@
+ //! Create master and slave virtual pseudo-terminals (PTYs)
+
+-use libc;
+-
+ pub use libc::pid_t as SessionId;
+ pub use libc::winsize as Winsize;
+
+ use std::ffi::CStr;
++use std::io;
+ use std::mem;
+ use std::os::unix::prelude::*;
+
+-use sys::termios::Termios;
+-use unistd::ForkResult;
+-use {Result, Error, fcntl};
+-use errno::Errno;
++use crate::sys::termios::Termios;
++use crate::unistd::{self, ForkResult, Pid};
++use crate::{Result, Error, fcntl};
++use crate::errno::Errno;
+
+ /// Representation of a master/slave pty pair
+ ///
+@@ -44,7 +43,7 @@ pub struct ForkptyResult {
+ /// While this datatype is a thin wrapper around `RawFd`, it enforces that the available PTY
+ /// functions are given the correct file descriptor. Additionally this type implements `Drop`,
+ /// so that when it's consumed or goes out of scope, it's automatically cleaned-up.
+-#[derive(Clone, Debug, Eq, Hash, PartialEq)]
++#[derive(Debug, Eq, Hash, PartialEq)]
+ pub struct PtyMaster(RawFd);
+
+ impl AsRawFd for PtyMaster {
+@@ -70,13 +69,28 @@ impl Drop for PtyMaster {
+ // invalid file descriptor. That frequently indicates a double-close
+ // condition, which can cause confusing errors for future I/O
+ // operations.
+- let e = ::unistd::close(self.0);
++ let e = unistd::close(self.0);
+ if e == Err(Error::Sys(Errno::EBADF)) {
+ panic!("Closing an invalid file descriptor!");
+ };
+ }
+ }
+
++impl io::Read for PtyMaster {
++ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
++ unistd::read(self.0, buf).map_err(|e| e.as_errno().unwrap().into())
++ }
++}
++
++impl io::Write for PtyMaster {
++ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
++ unistd::write(self.0, buf).map_err(|e| e.as_errno().unwrap().into())
++ }
++ fn flush(&mut self) -> io::Result<()> {
++ Ok(())
++ }
++}
++
+ /// Grant access to a slave pseudoterminal (see
+ /// [`grantpt(3)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/grantpt.html))
+ ///
+@@ -218,16 +232,16 @@ pub fn unlockpt(fd: &PtyMaster) -> Result<()> {
+ pub fn openpty<'a, 'b, T: Into<Option<&'a Winsize>>, U: Into<Option<&'b Termios>>>(winsize: T, termios: U) -> Result<OpenptyResult> {
+ use std::ptr;
+
+- let mut slave: libc::c_int = unsafe { mem::uninitialized() };
+- let mut master: libc::c_int = unsafe { mem::uninitialized() };
++ let mut slave = mem::MaybeUninit::<libc::c_int>::uninit();
++ let mut master = mem::MaybeUninit::<libc::c_int>::uninit();
+ let ret = {
+ match (termios.into(), winsize.into()) {
+ (Some(termios), Some(winsize)) => {
+ let inner_termios = termios.get_libc_termios();
+ unsafe {
+ libc::openpty(
+- &mut master,
+- &mut slave,
++ master.as_mut_ptr(),
++ slave.as_mut_ptr(),
+ ptr::null_mut(),
+ &*inner_termios as *const libc::termios as *mut _,
+ winsize as *const Winsize as *mut _,
+@@ -237,8 +251,8 @@ pub fn openpty<'a, 'b, T: Into<Option<&'a Winsize>>, U: Into<Option<&'b Termios>
+ (None, Some(winsize)) => {
+ unsafe {
+ libc::openpty(
+- &mut master,
+- &mut slave,
++ master.as_mut_ptr(),
++ slave.as_mut_ptr(),
+ ptr::null_mut(),
+ ptr::null_mut(),
+ winsize as *const Winsize as *mut _,
+@@ -249,8 +263,8 @@ pub fn openpty<'a, 'b, T: Into<Option<&'a Winsize>>, U: Into<Option<&'b Termios>
+ let inner_termios = termios.get_libc_termios();
+ unsafe {
+ libc::openpty(
+- &mut master,
+- &mut slave,
++ master.as_mut_ptr(),
++ slave.as_mut_ptr(),
+ ptr::null_mut(),
+ &*inner_termios as *const libc::termios as *mut _,
+ ptr::null_mut(),
+@@ -260,8 +274,8 @@ pub fn openpty<'a, 'b, T: Into<Option<&'a Winsize>>, U: Into<Option<&'b Termios>
+ (None, None) => {
+ unsafe {
+ libc::openpty(
+- &mut master,
+- &mut slave,
++ master.as_mut_ptr(),
++ slave.as_mut_ptr(),
+ ptr::null_mut(),
+ ptr::null_mut(),
+ ptr::null_mut(),
+@@ -273,10 +287,12 @@ pub fn openpty<'a, 'b, T: Into<Option<&'a Winsize>>, U: Into<Option<&'b Termios>
+
+ Errno::result(ret)?;
+
+- Ok(OpenptyResult {
+- master: master,
+- slave: slave,
+- })
++ unsafe {
++ Ok(OpenptyResult {
++ master: master.assume_init(),
++ slave: slave.assume_init(),
++ })
++ }
+ }
+
+ /// Create a new pseudoterminal, returning the master file descriptor and forked pid.
+@@ -291,10 +307,8 @@ pub fn forkpty<'a, 'b, T: Into<Option<&'a Winsize>>, U: Into<Option<&'b Termios>
+ termios: U,
+ ) -> Result<ForkptyResult> {
+ use std::ptr;
+- use unistd::Pid;
+- use unistd::ForkResult::*;
+
+- let mut master: libc::c_int = unsafe { mem::uninitialized() };
++ let mut master = mem::MaybeUninit::<libc::c_int>::uninit();
+
+ let term = match termios.into() {
+ Some(termios) => {
+@@ -310,17 +324,19 @@ pub fn forkpty<'a, 'b, T: Into<Option<&'a Winsize>>, U: Into<Option<&'b Termios>
+ .unwrap_or(ptr::null_mut());
+
+ let res = unsafe {
+- libc::forkpty(&mut master, ptr::null_mut(), term, win)
++ libc::forkpty(master.as_mut_ptr(), ptr::null_mut(), term, win)
+ };
+
+ let fork_result = Errno::result(res).map(|res| match res {
+- 0 => Child,
+- res => Parent { child: Pid::from_raw(res) },
++ 0 => ForkResult::Child,
++ res => ForkResult::Parent { child: Pid::from_raw(res) },
+ })?;
+
+- Ok(ForkptyResult {
+- master: master,
+- fork_result: fork_result,
+- })
++ unsafe {
++ Ok(ForkptyResult {
++ master: master.assume_init(),
++ fork_result,
++ })
++ }
+ }
+
+diff --git a/third_party/rust/nix/src/sched.rs b/third_party/rust/nix/src/sched.rs
+index 67188c57eef7d..3b48b4adf6d05 100644
+--- a/third_party/rust/nix/src/sched.rs
++++ b/third_party/rust/nix/src/sched.rs
+@@ -1,18 +1,17 @@
+-use libc;
+-use {Errno, Result};
++use crate::{Errno, Result};
+
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ pub use self::sched_linux_like::*;
+
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ mod sched_linux_like {
+- use errno::Errno;
++ use crate::errno::Errno;
+ use libc::{self, c_int, c_void};
+ use std::mem;
+ use std::option::Option;
+ use std::os::unix::io::RawFd;
+- use unistd::Pid;
+- use {Error, Result};
++ use crate::unistd::Pid;
++ use crate::{Error, Result};
+
+ // For some functions taking with a parameter of type CloneFlags,
+ // only a subset of these flags have an effect.
+@@ -46,6 +45,11 @@ mod sched_linux_like {
+
+ pub type CloneCb<'a> = Box<dyn FnMut() -> isize + 'a>;
+
++ /// CpuSet represent a bit-mask of CPUs.
++ /// CpuSets are used by sched_setaffinity and
++ /// sched_getaffinity for example.
++ ///
++ /// This is a wrapper around `libc::cpu_set_t`.
+ #[repr(C)]
+ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+ pub struct CpuSet {
+@@ -53,37 +57,78 @@ mod sched_linux_like {
+ }
+
+ impl CpuSet {
++ /// Create a new and empty CpuSet.
+ pub fn new() -> CpuSet {
+ CpuSet {
+ cpu_set: unsafe { mem::zeroed() },
+ }
+ }
+
++ /// Test to see if a CPU is in the CpuSet.
++ /// `field` is the CPU id to test
+ pub fn is_set(&self, field: usize) -> Result<bool> {
+- if field >= 8 * mem::size_of::<libc::cpu_set_t>() {
++ if field >= CpuSet::count() {
+ Err(Error::Sys(Errno::EINVAL))
+ } else {
+ Ok(unsafe { libc::CPU_ISSET(field, &self.cpu_set) })
+ }
+ }
+
++ /// Add a CPU to CpuSet.
++ /// `field` is the CPU id to add
+ pub fn set(&mut self, field: usize) -> Result<()> {
+- if field >= 8 * mem::size_of::<libc::cpu_set_t>() {
++ if field >= CpuSet::count() {
+ Err(Error::Sys(Errno::EINVAL))
+ } else {
+- Ok(unsafe { libc::CPU_SET(field, &mut self.cpu_set) })
++ unsafe { libc::CPU_SET(field, &mut self.cpu_set); }
++ Ok(())
+ }
+ }
+
++ /// Remove a CPU from CpuSet.
++ /// `field` is the CPU id to remove
+ pub fn unset(&mut self, field: usize) -> Result<()> {
+- if field >= 8 * mem::size_of::<libc::cpu_set_t>() {
++ if field >= CpuSet::count() {
+ Err(Error::Sys(Errno::EINVAL))
+ } else {
+- Ok(unsafe { libc::CPU_CLR(field, &mut self.cpu_set) })
++ unsafe { libc::CPU_CLR(field, &mut self.cpu_set);}
++ Ok(())
+ }
+ }
++
++ /// Return the maximum number of CPU in CpuSet
++ pub fn count() -> usize {
++ 8 * mem::size_of::<libc::cpu_set_t>()
++ }
+ }
+
++ impl Default for CpuSet {
++ fn default() -> Self {
++ Self::new()
++ }
++ }
++
++ /// `sched_setaffinity` set a thread's CPU affinity mask
++ /// ([`sched_setaffinity(2)`](http://man7.org/linux/man-pages/man2/sched_setaffinity.2.html))
++ ///
++ /// `pid` is the thread ID to update.
++ /// If pid is zero, then the calling thread is updated.
++ ///
++ /// The `cpuset` argument specifies the set of CPUs on which the thread
++ /// will be eligible to run.
++ ///
++ /// # Example
++ ///
++ /// Binding the current thread to CPU 0 can be done as follows:
++ ///
++ /// ```rust,no_run
++ /// use nix::sched::{CpuSet, sched_setaffinity};
++ /// use nix::unistd::Pid;
++ ///
++ /// let mut cpu_set = CpuSet::new();
++ /// cpu_set.set(0);
++ /// sched_setaffinity(Pid::from_raw(0), &cpu_set);
++ /// ```
+ pub fn sched_setaffinity(pid: Pid, cpuset: &CpuSet) -> Result<()> {
+ let res = unsafe {
+ libc::sched_setaffinity(
+@@ -96,6 +141,41 @@ mod sched_linux_like {
+ Errno::result(res).map(drop)
+ }
+
++ /// `sched_getaffinity` get a thread's CPU affinity mask
++ /// ([`sched_getaffinity(2)`](http://man7.org/linux/man-pages/man2/sched_getaffinity.2.html))
++ ///
++ /// `pid` is the thread ID to check.
++ /// If pid is zero, then the calling thread is checked.
++ ///
++ /// Returned `cpuset` is the set of CPUs on which the thread
++ /// is eligible to run.
++ ///
++ /// # Example
++ ///
++ /// Checking if the current thread can run on CPU 0 can be done as follows:
++ ///
++ /// ```rust,no_run
++ /// use nix::sched::sched_getaffinity;
++ /// use nix::unistd::Pid;
++ ///
++ /// let cpu_set = sched_getaffinity(Pid::from_raw(0)).unwrap();
++ /// if cpu_set.is_set(0).unwrap() {
++ /// println!("Current thread can run on CPU 0");
++ /// }
++ /// ```
++ pub fn sched_getaffinity(pid: Pid) -> Result<CpuSet> {
++ let mut cpuset = CpuSet::new();
++ let res = unsafe {
++ libc::sched_getaffinity(
++ pid.into(),
++ mem::size_of::<CpuSet>() as libc::size_t,
++ &mut cpuset.cpu_set,
++ )
++ };
++
++ Errno::result(res).and(Ok(cpuset))
++ }
++
+ pub fn clone(
+ mut cb: CloneCb,
+ stack: &mut [u8],
+@@ -109,8 +189,8 @@ mod sched_linux_like {
+
+ let res = unsafe {
+ let combined = flags.bits() | signal.unwrap_or(0);
+- let ptr = stack.as_mut_ptr().offset(stack.len() as isize);
+- let ptr_aligned = ptr.offset((ptr as usize % 16) as isize * -1);
++ let ptr = stack.as_mut_ptr().add(stack.len());
++ let ptr_aligned = ptr.sub(ptr as usize % 16);
+ libc::clone(
+ mem::transmute(
+ callback as extern "C" fn(*mut Box<dyn FnMut() -> isize>) -> i32,
+diff --git a/third_party/rust/nix/src/sys/aio.rs b/third_party/rust/nix/src/sys/aio.rs
+index 9258a0657cc8a..1afdb35866c28 100644
+--- a/third_party/rust/nix/src/sys/aio.rs
++++ b/third_party/rust/nix/src/sys/aio.rs
+@@ -21,20 +21,19 @@
+ //! [`aio_cancel_all`](fn.aio_cancel_all.html), though the operating system may
+ //! not support this for all filesystems and devices.
+
+-use {Error, Result};
+-use errno::Errno;
++use crate::{Error, Result};
++use crate::errno::Errno;
+ use std::os::unix::io::RawFd;
+ use libc::{c_void, off_t, size_t};
+-use libc;
+ use std::borrow::{Borrow, BorrowMut};
+ use std::fmt;
+ use std::fmt::Debug;
+ use std::marker::PhantomData;
+ use std::mem;
+ use std::ptr::{null, null_mut};
+-use sys::signal::*;
++use crate::sys::signal::*;
+ use std::thread;
+-use sys::time::TimeSpec;
++use crate::sys::time::TimeSpec;
+
+ libc_enum! {
+ /// Mode for `AioCb::fsync`. Controls whether only data or both data and
+@@ -226,8 +225,6 @@ impl<'a> AioCb<'a> {
+ /// [`fsync`](#method.fsync) operation.
+ ///
+ /// ```
+- /// # extern crate tempfile;
+- /// # extern crate nix;
+ /// # use nix::errno::Errno;
+ /// # use nix::Error;
+ /// # use nix::sys::aio::*;
+@@ -287,8 +284,6 @@ impl<'a> AioCb<'a> {
+ /// Create an `AioCb` from a mutable slice and read into it.
+ ///
+ /// ```
+- /// # extern crate tempfile;
+- /// # extern crate nix;
+ /// # use nix::errno::Errno;
+ /// # use nix::Error;
+ /// # use nix::sys::aio::*;
+@@ -363,8 +358,6 @@ impl<'a> AioCb<'a> {
+ /// Create an `AioCb` from a Vector and use it for writing
+ ///
+ /// ```
+- /// # extern crate tempfile;
+- /// # extern crate nix;
+ /// # use nix::errno::Errno;
+ /// # use nix::Error;
+ /// # use nix::sys::aio::*;
+@@ -394,9 +387,6 @@ impl<'a> AioCb<'a> {
+ /// Create an `AioCb` from a `Bytes` object
+ ///
+ /// ```
+- /// # extern crate bytes;
+- /// # extern crate tempfile;
+- /// # extern crate nix;
+ /// # use bytes::Bytes;
+ /// # use nix::sys::aio::*;
+ /// # use nix::sys::signal::SigevNotify;
+@@ -419,9 +409,6 @@ impl<'a> AioCb<'a> {
+ /// using an un`Box`ed `Bytes` object.
+ ///
+ /// ```
+- /// # extern crate bytes;
+- /// # extern crate tempfile;
+- /// # extern crate nix;
+ /// # use bytes::Bytes;
+ /// # use nix::sys::aio::*;
+ /// # use nix::sys::signal::SigevNotify;
+@@ -480,8 +467,6 @@ impl<'a> AioCb<'a> {
+ /// Create an `AioCb` from a Vector and use it for reading
+ ///
+ /// ```
+- /// # extern crate tempfile;
+- /// # extern crate nix;
+ /// # use nix::errno::Errno;
+ /// # use nix::Error;
+ /// # use nix::sys::aio::*;
+@@ -642,8 +627,6 @@ impl<'a> AioCb<'a> {
+ /// Construct an `AioCb` from a slice and use it for writing.
+ ///
+ /// ```
+- /// # extern crate tempfile;
+- /// # extern crate nix;
+ /// # use nix::errno::Errno;
+ /// # use nix::Error;
+ /// # use nix::sys::aio::*;
+@@ -726,8 +709,6 @@ impl<'a> AioCb<'a> {
+ /// result.
+ ///
+ /// ```
+- /// # extern crate tempfile;
+- /// # extern crate nix;
+ /// # use nix::errno::Errno;
+ /// # use nix::Error;
+ /// # use nix::sys::aio::*;
+@@ -781,8 +762,6 @@ impl<'a> AioCb<'a> {
+ /// is an alternative to `aio_suspend`, used by most of the other examples.
+ ///
+ /// ```
+- /// # extern crate tempfile;
+- /// # extern crate nix;
+ /// # use nix::errno::Errno;
+ /// # use nix::Error;
+ /// # use nix::sys::aio::*;
+@@ -925,8 +904,6 @@ impl<'a> AioCb<'a> {
+ /// descriptor.
+ ///
+ /// ```
+-/// # extern crate tempfile;
+-/// # extern crate nix;
+ /// # use nix::errno::Errno;
+ /// # use nix::Error;
+ /// # use nix::sys::aio::*;
+@@ -978,13 +955,7 @@ pub fn aio_cancel_all(fd: RawFd) -> Result<AioCancelStat> {
+ ///
+ /// Use `aio_suspend` to block until an aio operation completes.
+ ///
+-// Disable doctest due to a known bug in FreeBSD's 32-bit emulation. The fix
+-// will be included in release 11.2.
+-// FIXME reenable the doc test when the CI machine gets upgraded to that release.
+-// https://svnweb.freebsd.org/base?view=revision&revision=325018
+-/// ```no_run
+-/// # extern crate tempfile;
+-/// # extern crate nix;
++/// ```
+ /// # use nix::sys::aio::*;
+ /// # use nix::sys::signal::SigevNotify;
+ /// # use std::os::unix::io::AsRawFd;
+@@ -1091,8 +1062,6 @@ impl<'a> LioCb<'a> {
+ /// [`AioCb::error`] to poll.
+ ///
+ /// ```
+- /// # extern crate tempfile;
+- /// # extern crate nix;
+ /// # use nix::sys::aio::*;
+ /// # use nix::sys::signal::SigevNotify;
+ /// # use std::os::unix::io::AsRawFd;
+@@ -1148,8 +1117,6 @@ impl<'a> LioCb<'a> {
+ ///
+ /// # Examples
+ /// ```no_run
+- /// # extern crate tempfile;
+- /// # extern crate nix;
+ /// # use nix::Error;
+ /// # use nix::errno::Errno;
+ /// # use nix::sys::aio::*;
+@@ -1213,7 +1180,6 @@ impl<'a> LioCb<'a> {
+ },
+ Err(Error::Sys(Errno::EINPROGRESS)) => {
+ // aiocb is was successfully queued; no need to do anything
+- ()
+ },
+ Err(Error::Sys(Errno::EINVAL)) => panic!(
+ "AioCb was never submitted, or already finalized"),
+diff --git a/third_party/rust/nix/src/sys/epoll.rs b/third_party/rust/nix/src/sys/epoll.rs
+index fef6f4e3ec92c..2437bbe2ddb3b 100644
+--- a/third_party/rust/nix/src/sys/epoll.rs
++++ b/third_party/rust/nix/src/sys/epoll.rs
+@@ -1,10 +1,10 @@
+-use Result;
+-use errno::Errno;
++use crate::Result;
++use crate::errno::Errno;
+ use libc::{self, c_int};
+ use std::os::unix::io::RawFd;
+ use std::ptr;
+ use std::mem;
+-use ::Error;
++use crate::Error;
+
+ libc_bitflags!(
+ pub struct EpollFlags: c_int {
+@@ -43,7 +43,7 @@ libc_bitflags!{
+ }
+
+ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+-#[repr(C)]
++#[repr(transparent)]
+ pub struct EpollEvent {
+ event: libc::epoll_event,
+ }
+diff --git a/third_party/rust/nix/src/sys/event.rs b/third_party/rust/nix/src/sys/event.rs
+index 8cd7372f88188..8050af313245d 100644
+--- a/third_party/rust/nix/src/sys/event.rs
++++ b/third_party/rust/nix/src/sys/event.rs
+@@ -1,12 +1,11 @@
+ /* TOOD: Implement for other kqueue based systems
+ */
+
+-use {Errno, Result};
++use crate::{Errno, Result};
+ #[cfg(not(target_os = "netbsd"))]
+ use libc::{timespec, time_t, c_int, c_long, intptr_t, uintptr_t};
+ #[cfg(target_os = "netbsd")]
+ use libc::{timespec, time_t, c_long, intptr_t, uintptr_t, size_t};
+-use libc;
+ use std::os::unix::io::RawFd;
+ use std::ptr;
+ use std::mem;
+@@ -28,7 +27,7 @@ type type_of_data = intptr_t;
+ #[cfg(any(target_os = "netbsd"))]
+ type type_of_udata = intptr_t;
+ #[cfg(any(target_os = "netbsd", target_os = "openbsd"))]
+-type type_of_data = libc::int64_t;
++type type_of_data = i64;
+
+ #[cfg(target_os = "netbsd")]
+ type type_of_event_filter = u32;
+@@ -90,14 +89,9 @@ libc_bitflags!{
+ EV_CLEAR;
+ EV_DELETE;
+ EV_DISABLE;
+- // No released version of OpenBSD supports EV_DISPATCH or EV_RECEIPT.
+- // These have been commited to the -current branch though and are
+- // expected to be part of the OpenBSD 6.2 release in Nov 2017.
+- // See: https://marc.info/?l=openbsd-tech&m=149621427511219&w=2
+- // https://github.com/rust-lang/libc/pull/613
+ #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
+ target_os = "ios", target_os = "macos",
+- target_os = "netbsd"))]
++ target_os = "netbsd", target_os = "openbsd"))]
+ EV_DISPATCH;
+ #[cfg(target_os = "freebsd")]
+ EV_DROP;
+@@ -116,7 +110,7 @@ libc_bitflags!{
+ EV_POLL;
+ #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
+ target_os = "ios", target_os = "macos",
+- target_os = "netbsd"))]
++ target_os = "netbsd", target_os = "openbsd"))]
+ EV_RECEIPT;
+ EV_SYSFLAGS;
+ }
+@@ -134,10 +128,6 @@ libc_bitflags!(
+ NOTE_EXEC;
+ NOTE_EXIT;
+ #[cfg(any(target_os = "macos", target_os = "ios"))]
+- #[deprecated( since="0.14.0", note="Deprecated since OSX 10.9")]
+- #[allow(deprecated)]
+- NOTE_EXIT_REPARENTED;
+- #[cfg(any(target_os = "macos", target_os = "ios"))]
+ NOTE_EXITSTATUS;
+ NOTE_EXTEND;
+ #[cfg(any(target_os = "macos",
+@@ -183,11 +173,6 @@ libc_bitflags!(
+ NOTE_OOB;
+ NOTE_PCTRLMASK;
+ NOTE_PDATAMASK;
+- #[cfg(any(target_os = "macos", target_os = "ios"))]
+- #[cfg(any(target_os = "macos", target_os = "ios"))]
+- #[deprecated( since="0.14.0", note="Deprecated since OSX 10.9")]
+- #[allow(deprecated)]
+- NOTE_REAP;
+ NOTE_RENAME;
+ NOTE_REVOKE;
+ #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
+@@ -234,7 +219,7 @@ impl KEvent {
+ pub fn new(ident: uintptr_t, filter: EventFilter, flags: EventFlag,
+ fflags:FilterFlag, data: intptr_t, udata: intptr_t) -> KEvent {
+ KEvent { kevent: libc::kevent {
+- ident: ident,
++ ident,
+ filter: filter as type_of_event_filter,
+ flags: flags.bits(),
+ fflags: fflags.bits(),
+@@ -329,23 +314,17 @@ pub fn ev_set(ev: &mut KEvent,
+ fn test_struct_kevent() {
+ let udata : intptr_t = 12345;
+
+- let expected = libc::kevent{ident: 0xdead_beef,
+- filter: libc::EVFILT_READ,
+- flags: libc::EV_ONESHOT | libc::EV_ADD,
+- fflags: libc::NOTE_CHILD | libc::NOTE_EXIT,
+- data: 0x1337,
+- udata: udata as type_of_udata};
+ let actual = KEvent::new(0xdead_beef,
+ EventFilter::EVFILT_READ,
+ EventFlag::EV_ONESHOT | EventFlag::EV_ADD,
+ FilterFlag::NOTE_CHILD | FilterFlag::NOTE_EXIT,
+ 0x1337,
+ udata);
+- assert!(expected.ident == actual.ident());
+- assert!(expected.filter == actual.filter() as type_of_event_filter);
+- assert!(expected.flags == actual.flags().bits());
+- assert!(expected.fflags == actual.fflags().bits());
+- assert!(expected.data == actual.data() as type_of_data);
+- assert!(expected.udata == actual.udata() as type_of_udata);
+- assert!(mem::size_of::<libc::kevent>() == mem::size_of::<KEvent>());
++ assert_eq!(0xdead_beef, actual.ident());
++ assert_eq!(libc::EVFILT_READ, actual.filter() as type_of_event_filter);
++ assert_eq!(libc::EV_ONESHOT | libc::EV_ADD, actual.flags().bits());
++ assert_eq!(libc::NOTE_CHILD | libc::NOTE_EXIT, actual.fflags().bits());
++ assert_eq!(0x1337, actual.data() as type_of_data);
++ assert_eq!(udata as type_of_udata, actual.udata() as type_of_udata);
++ assert_eq!(mem::size_of::<libc::kevent>(), mem::size_of::<KEvent>());
+ }
+diff --git a/third_party/rust/nix/src/sys/eventfd.rs b/third_party/rust/nix/src/sys/eventfd.rs
+index c5a54e46a1735..baaaa89ddd52e 100644
+--- a/third_party/rust/nix/src/sys/eventfd.rs
++++ b/third_party/rust/nix/src/sys/eventfd.rs
+@@ -1,7 +1,7 @@
+ use libc;
+ use std::os::unix::io::RawFd;
+-use Result;
+-use errno::Errno;
++use crate::Result;
++use crate::errno::Errno;
+
+ libc_bitflags! {
+ pub struct EfdFlags: libc::c_int {
+diff --git a/third_party/rust/nix/src/sys/inotify.rs b/third_party/rust/nix/src/sys/inotify.rs
+index e6c2cf64d29dc..4880a4a514e77 100644
+--- a/third_party/rust/nix/src/sys/inotify.rs
++++ b/third_party/rust/nix/src/sys/inotify.rs
+@@ -23,19 +23,19 @@
+ //! }
+ //! ```
+
+-use libc;
+ use libc::{
+ c_char,
+ c_int,
+ };
+ use std::ffi::{OsString,OsStr,CStr};
+ use std::os::unix::ffi::OsStrExt;
+-use std::mem::size_of;
++use std::mem::{MaybeUninit, size_of};
+ use std::os::unix::io::{RawFd,AsRawFd,FromRawFd};
+-use unistd::read;
+-use Result;
+-use NixPath;
+-use errno::Errno;
++use std::ptr;
++use crate::unistd::read;
++use crate::Result;
++use crate::NixPath;
++use crate::errno::Errno;
+
+ libc_bitflags! {
+ /// Configuration options for [`inotify_add_watch`](fn.inotify_add_watch.html).
+@@ -131,7 +131,7 @@ impl Inotify {
+ /// Returns a watch descriptor. This is not a File Descriptor!
+ ///
+ /// For more information see, [inotify_add_watch(2)](http://man7.org/linux/man-pages/man2/inotify_add_watch.2.html).
+- pub fn add_watch<P: ?Sized + NixPath>(&self,
++ pub fn add_watch<P: ?Sized + NixPath>(self,
+ path: &P,
+ mask: AddWatchFlags)
+ -> Result<WatchDescriptor>
+@@ -152,14 +152,14 @@ impl Inotify {
+ ///
+ /// For more information see, [inotify_rm_watch(2)](http://man7.org/linux/man-pages/man2/inotify_rm_watch.2.html).
+ #[cfg(target_os = "linux")]
+- pub fn rm_watch(&self, wd: WatchDescriptor) -> Result<()> {
++ pub fn rm_watch(self, wd: WatchDescriptor) -> Result<()> {
+ let res = unsafe { libc::inotify_rm_watch(self.fd, wd.wd) };
+
+ Errno::result(res).map(drop)
+ }
+
+ #[cfg(target_os = "android")]
+- pub fn rm_watch(&self, wd: WatchDescriptor) -> Result<()> {
++ pub fn rm_watch(self, wd: WatchDescriptor) -> Result<()> {
+ let res = unsafe { libc::inotify_rm_watch(self.fd, wd.wd as u32) };
+
+ Errno::result(res).map(drop)
+@@ -171,9 +171,10 @@ impl Inotify {
+ ///
+ /// Returns as many events as available. If the call was non blocking and no
+ /// events could be read then the EAGAIN error is returned.
+- pub fn read_events(&self) -> Result<Vec<InotifyEvent>> {
++ pub fn read_events(self) -> Result<Vec<InotifyEvent>> {
+ let header_size = size_of::<libc::inotify_event>();
+- let mut buffer = [0u8; 4096];
++ const BUFSIZ: usize = 4096;
++ let mut buffer = [0u8; BUFSIZ];
+ let mut events = Vec::new();
+ let mut offset = 0;
+
+@@ -181,11 +182,13 @@ impl Inotify {
+
+ while (nread - offset) >= header_size {
+ let event = unsafe {
+- &*(
+- buffer
+- .as_ptr()
+- .offset(offset as isize) as *const libc::inotify_event
+- )
++ let mut event = MaybeUninit::<libc::inotify_event>::uninit();
++ ptr::copy_nonoverlapping(
++ buffer.as_ptr().add(offset),
++ event.as_mut_ptr() as *mut u8,
++ (BUFSIZ - offset).min(header_size)
++ );
++ event.assume_init()
+ };
+
+ let name = match event.len {
+@@ -194,7 +197,7 @@ impl Inotify {
+ let ptr = unsafe {
+ buffer
+ .as_ptr()
+- .offset(offset as isize + header_size as isize)
++ .add(offset + header_size)
+ as *const c_char
+ };
+ let cstr = unsafe { CStr::from_ptr(ptr) };
+diff --git a/third_party/rust/nix/src/sys/ioctl/bsd.rs b/third_party/rust/nix/src/sys/ioctl/bsd.rs
+index 9b8b0ff1a155f..f39c0eb688f8a 100644
+--- a/third_party/rust/nix/src/sys/ioctl/bsd.rs
++++ b/third_party/rust/nix/src/sys/ioctl/bsd.rs
+@@ -6,7 +6,7 @@ pub type ioctl_num_type = ::libc::c_ulong;
+ pub type ioctl_param_type = ::libc::c_int;
+
+ mod consts {
+- use ::sys::ioctl::ioctl_num_type;
++ use crate::sys::ioctl::ioctl_num_type;
+ #[doc(hidden)]
+ pub const VOID: ioctl_num_type = 0x2000_0000;
+ #[doc(hidden)]
+@@ -14,7 +14,7 @@ mod consts {
+ #[doc(hidden)]
+ pub const IN: ioctl_num_type = 0x8000_0000;
+ #[doc(hidden)]
+- pub const INOUT: ioctl_num_type = (IN|OUT);
++ pub const INOUT: ioctl_num_type = IN|OUT;
+ #[doc(hidden)]
+ pub const IOCPARM_MASK: ioctl_num_type = 0x1fff;
+ }
+diff --git a/third_party/rust/nix/src/sys/ioctl/linux.rs b/third_party/rust/nix/src/sys/ioctl/linux.rs
+index 9cdac72a4b80b..68ebaba9bf496 100644
+--- a/third_party/rust/nix/src/sys/ioctl/linux.rs
++++ b/third_party/rust/nix/src/sys/ioctl/linux.rs
+@@ -33,7 +33,8 @@ mod consts {
+ target_arch = "arm",
+ target_arch = "s390x",
+ target_arch = "x86_64",
+- target_arch = "aarch64"))]
++ target_arch = "aarch64",
++ target_arch = "riscv64"))]
+ mod consts {
+ #[doc(hidden)]
+ pub const NONE: u8 = 0;
+diff --git a/third_party/rust/nix/src/sys/ioctl/mod.rs b/third_party/rust/nix/src/sys/ioctl/mod.rs
+index 4513bf877434a..8858a9d57779f 100644
+--- a/third_party/rust/nix/src/sys/ioctl/mod.rs
++++ b/third_party/rust/nix/src/sys/ioctl/mod.rs
+@@ -29,7 +29,7 @@
+ //! Historically `ioctl` numbers were arbitrary hard-coded values. In Linux (before 2.6) and some
+ //! unices this has changed to a more-ordered system where the ioctl numbers are partitioned into
+ //! subcomponents (For linux this is documented in
+-//! [`Documentation/ioctl/ioctl-number.txt`](http://elixir.free-electrons.com/linux/latest/source/Documentation/ioctl/ioctl-number.txt)):
++//! [`Documentation/ioctl/ioctl-number.rst`](https://elixir.bootlin.com/linux/latest/source/Documentation/userspace-api/ioctl/ioctl-number.rst)):
+ //!
+ //! * Number: The actual ioctl ID
+ //! * Type: A grouping of ioctls for a common purpose or driver
+@@ -221,11 +221,13 @@
+ //!
+ //! # fn main() {}
+ //! ```
+-#[cfg(any(target_os = "android", target_os = "linux"))]
++use cfg_if::cfg_if;
++
++#[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))]
+ #[macro_use]
+ mod linux;
+
+-#[cfg(any(target_os = "android", target_os = "linux"))]
++#[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))]
+ pub use self::linux::*;
+
+ #[cfg(any(target_os = "dragonfly",
+@@ -317,7 +319,6 @@ macro_rules! ioctl_none {
+ ///
+ /// ```no_run
+ /// # #[macro_use] extern crate nix;
+-/// # extern crate libc;
+ /// # use libc::TIOCNXCL;
+ /// # use std::fs::File;
+ /// # use std::os::unix::io::AsRawFd;
+@@ -396,7 +397,6 @@ macro_rules! ioctl_read {
+ /// # Example
+ ///
+ /// ```
+-/// # extern crate libc;
+ /// # #[macro_use] extern crate nix;
+ /// # #[cfg(any(target_os = "android", target_os = "linux"))]
+ /// ioctl_read_bad!(tcgets, libc::TCGETS, libc::termios);
+@@ -470,7 +470,6 @@ macro_rules! ioctl_write_ptr {
+ /// # Example
+ ///
+ /// ```
+-/// # extern crate libc;
+ /// # #[macro_use] extern crate nix;
+ /// # #[cfg(any(target_os = "android", target_os = "linux"))]
+ /// ioctl_write_ptr_bad!(tcsets, libc::TCSETS, libc::termios);
+@@ -590,7 +589,6 @@ cfg_if!{
+ /// # Examples
+ ///
+ /// ```
+-/// # extern crate libc;
+ /// # #[macro_use] extern crate nix;
+ /// # #[cfg(any(target_os = "android", target_os = "linux"))]
+ /// ioctl_write_int_bad!(tcsbrk, libc::TCSBRK);
+diff --git a/third_party/rust/nix/src/sys/memfd.rs b/third_party/rust/nix/src/sys/memfd.rs
+index 9672429b31e7f..51b7e6b18849b 100644
+--- a/third_party/rust/nix/src/sys/memfd.rs
++++ b/third_party/rust/nix/src/sys/memfd.rs
+@@ -1,7 +1,7 @@
+ use libc;
+ use std::os::unix::io::RawFd;
+-use Result;
+-use errno::Errno;
++use crate::Result;
++use crate::errno::Errno;
+ use std::ffi::CStr;
+
+ libc_bitflags!(
+diff --git a/third_party/rust/nix/src/sys/mman.rs b/third_party/rust/nix/src/sys/mman.rs
+index 4e250501dd0f0..63a0779c19382 100644
+--- a/third_party/rust/nix/src/sys/mman.rs
++++ b/third_party/rust/nix/src/sys/mman.rs
+@@ -1,12 +1,12 @@
+-use {Error, Result};
++use crate::{Error, Result};
+ #[cfg(not(target_os = "android"))]
+-use NixPath;
+-use errno::Errno;
++use crate::NixPath;
++use crate::errno::Errno;
+ #[cfg(not(target_os = "android"))]
+-use fcntl::OFlag;
++use crate::fcntl::OFlag;
+ use libc::{self, c_int, c_void, size_t, off_t};
+ #[cfg(not(target_os = "android"))]
+-use sys::stat::Mode;
++use crate::sys::stat::Mode;
+ use std::os::unix::io::RawFd;
+
+ libc_bitflags!{
+@@ -77,6 +77,43 @@ libc_bitflags!{
+ /// Allocate the mapping using "huge pages."
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ MAP_HUGETLB;
++ /// Make use of 64KB huge page (must be supported by the system)
++ #[cfg(target_os = "linux")]
++ MAP_HUGE_64KB;
++ /// Make use of 512KB huge page (must be supported by the system)
++ #[cfg(target_os = "linux")]
++ MAP_HUGE_512KB;
++ /// Make use of 1MB huge page (must be supported by the system)
++ #[cfg(target_os = "linux")]
++ MAP_HUGE_1MB;
++ /// Make use of 2MB huge page (must be supported by the system)
++ #[cfg(target_os = "linux")]
++ MAP_HUGE_2MB;
++ /// Make use of 8MB huge page (must be supported by the system)
++ #[cfg(target_os = "linux")]
++ MAP_HUGE_8MB;
++ /// Make use of 16MB huge page (must be supported by the system)
++ #[cfg(target_os = "linux")]
++ MAP_HUGE_16MB;
++ /// Make use of 32MB huge page (must be supported by the system)
++ #[cfg(target_os = "linux")]
++ MAP_HUGE_32MB;
++ /// Make use of 256MB huge page (must be supported by the system)
++ #[cfg(target_os = "linux")]
++ MAP_HUGE_256MB;
++ /// Make use of 512MB huge page (must be supported by the system)
++ #[cfg(target_os = "linux")]
++ MAP_HUGE_512MB;
++ /// Make use of 1GB huge page (must be supported by the system)
++ #[cfg(target_os = "linux")]
++ MAP_HUGE_1GB;
++ /// Make use of 2GB huge page (must be supported by the system)
++ #[cfg(target_os = "linux")]
++ MAP_HUGE_2GB;
++ /// Make use of 16GB huge page (must be supported by the system)
++ #[cfg(target_os = "linux")]
++ MAP_HUGE_16GB;
++
+ /// Lock the mapped region into memory as with `mlock(2)`.
+ #[cfg(target_os = "netbsd")]
+ MAP_WIRED;
+@@ -102,6 +139,17 @@ libc_bitflags!{
+ }
+ }
+
++#[cfg(target_os = "linux")]
++libc_bitflags!{
++ /// Options for `mremap()`.
++ pub struct MRemapFlags: c_int {
++ /// Permit the kernel to relocate the mapping to a new virtual address, if necessary.
++ MREMAP_MAYMOVE;
++ /// Place the mapping at exactly the address specified in `new_address`.
++ MREMAP_FIXED;
++ }
++}
++
+ libc_enum!{
+ /// Usage information for a range of memory to allow for performance optimizations by the kernel.
+ ///
+@@ -223,20 +271,37 @@ libc_bitflags!{
+ }
+ }
+
+-/// Locks all memory pages that contain part of the address range with `length` bytes starting at
+-/// `addr`. Locked pages never move to the swap area.
++/// Locks all memory pages that contain part of the address range with `length`
++/// bytes starting at `addr`.
++///
++/// Locked pages never move to the swap area.
++///
++/// # Safety
++///
++/// `addr` must meet all the requirements described in the `mlock(2)` man page.
+ pub unsafe fn mlock(addr: *const c_void, length: size_t) -> Result<()> {
+ Errno::result(libc::mlock(addr, length)).map(drop)
+ }
+
+-/// Unlocks all memory pages that contain part of the address range with `length` bytes starting at
+-/// `addr`.
++/// Unlocks all memory pages that contain part of the address range with
++/// `length` bytes starting at `addr`.
++///
++/// # Safety
++///
++/// `addr` must meet all the requirements described in the `munlock(2)` man
++/// page.
+ pub unsafe fn munlock(addr: *const c_void, length: size_t) -> Result<()> {
+ Errno::result(libc::munlock(addr, length)).map(drop)
+ }
+
+-/// Locks all memory pages mapped into this process' address space. Locked pages never move to the
+-/// swap area.
++/// Locks all memory pages mapped into this process' address space.
++///
++/// Locked pages never move to the swap area.
++///
++/// # Safety
++///
++/// `addr` must meet all the requirements described in the `mlockall(2)` man
++/// page.
+ pub fn mlockall(flags: MlockAllFlags) -> Result<()> {
+ unsafe { Errno::result(libc::mlockall(flags.bits())) }.map(drop)
+ }
+@@ -246,8 +311,11 @@ pub fn munlockall() -> Result<()> {
+ unsafe { Errno::result(libc::munlockall()) }.map(drop)
+ }
+
+-/// Calls to mmap are inherently unsafe, so they must be made in an unsafe block. Typically
+-/// a higher-level abstraction will hide the unsafe interactions with the mmap'd region.
++/// allocate memory, or map files or devices into memory
++///
++/// # Safety
++///
++/// See the `mmap(2)` man page for detailed requirements.
+ pub unsafe fn mmap(addr: *mut c_void, length: size_t, prot: ProtFlags, flags: MapFlags, fd: RawFd, offset: off_t) -> Result<*mut c_void> {
+ let ret = libc::mmap(addr, length, prot.bits(), flags.bits(), fd, offset);
+
+@@ -258,10 +326,46 @@ pub unsafe fn mmap(addr: *mut c_void, length: size_t, prot: ProtFlags, flags: Ma
+ }
+ }
+
++/// Expands (or shrinks) an existing memory mapping, potentially moving it at
++/// the same time.
++///
++/// # Safety
++///
++/// See the `mremap(2)` [man page](https://man7.org/linux/man-pages/man2/mremap.2.html) for
++/// detailed requirements.
++#[cfg(target_os = "linux")]
++pub unsafe fn mremap(
++ addr: *mut c_void,
++ old_size: size_t,
++ new_size: size_t,
++ flags: MRemapFlags,
++ new_address: Option<* mut c_void>,
++) -> Result<*mut c_void> {
++ let ret = libc::mremap(addr, old_size, new_size, flags.bits(), new_address.unwrap_or(std::ptr::null_mut()));
++
++ if ret == libc::MAP_FAILED {
++ Err(Error::Sys(Errno::last()))
++ } else {
++ Ok(ret)
++ }
++}
++
++/// remove a mapping
++///
++/// # Safety
++///
++/// `addr` must meet all the requirements described in the `munmap(2)` man
++/// page.
+ pub unsafe fn munmap(addr: *mut c_void, len: size_t) -> Result<()> {
+ Errno::result(libc::munmap(addr, len)).map(drop)
+ }
+
++/// give advice about use of memory
++///
++/// # Safety
++///
++/// See the `madvise(2)` man page. Take special care when using
++/// `MmapAdvise::MADV_FREE`.
+ pub unsafe fn madvise(addr: *mut c_void, length: size_t, advise: MmapAdvise) -> Result<()> {
+ Errno::result(libc::madvise(addr, length, advise as i32)).map(drop)
+ }
+@@ -295,6 +399,12 @@ pub unsafe fn mprotect(addr: *mut c_void, length: size_t, prot: ProtFlags) -> Re
+ Errno::result(libc::mprotect(addr, length, prot.bits())).map(drop)
+ }
+
++/// synchronize a mapped region
++///
++/// # Safety
++///
++/// `addr` must meet all the requirements described in the `msync(2)` man
++/// page.
+ pub unsafe fn msync(addr: *mut c_void, length: size_t, flags: MsFlags) -> Result<()> {
+ Errno::result(libc::msync(addr, length, flags.bits())).map(drop)
+ }
+diff --git a/third_party/rust/nix/src/sys/mod.rs b/third_party/rust/nix/src/sys/mod.rs
+index d3c2f92bbaaea..438fb4fdcb438 100644
+--- a/third_party/rust/nix/src/sys/mod.rs
++++ b/third_party/rust/nix/src/sys/mod.rs
+@@ -25,6 +25,7 @@ pub mod eventfd;
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
++ target_os = "redox",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+@@ -34,8 +35,12 @@ pub mod ioctl;
+ #[cfg(target_os = "linux")]
+ pub mod memfd;
+
++#[cfg(not(target_os = "redox"))]
+ pub mod mman;
+
++#[cfg(target_os = "linux")]
++pub mod personality;
++
+ pub mod pthread;
+
+ #[cfg(any(target_os = "android",
+@@ -53,6 +58,7 @@ pub mod quota;
+ #[cfg(any(target_os = "linux"))]
+ pub mod reboot;
+
++#[cfg(not(target_os = "redox"))]
+ pub mod select;
+
+ #[cfg(any(target_os = "android",
+@@ -67,6 +73,7 @@ pub mod signal;
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ pub mod signalfd;
+
++#[cfg(not(target_os = "redox"))]
+ pub mod socket;
+
+ pub mod stat;
+@@ -98,3 +105,6 @@ pub mod wait;
+
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ pub mod inotify;
++
++#[cfg(target_os = "linux")]
++pub mod timerfd;
+diff --git a/third_party/rust/nix/src/sys/personality.rs b/third_party/rust/nix/src/sys/personality.rs
+new file mode 100644
+index 0000000000000..6548b654aa1f4
+--- /dev/null
++++ b/third_party/rust/nix/src/sys/personality.rs
+@@ -0,0 +1,70 @@
++use crate::Result;
++use crate::errno::Errno;
++
++use libc::{self, c_int, c_ulong};
++
++libc_bitflags! {
++ /// Flags used and returned by [`get()`](fn.get.html) and
++ /// [`set()`](fn.set.html).
++ pub struct Persona: c_int {
++ ADDR_COMPAT_LAYOUT;
++ ADDR_NO_RANDOMIZE;
++ ADDR_LIMIT_32BIT;
++ ADDR_LIMIT_3GB;
++ #[cfg(not(target_env = "musl"))]
++ FDPIC_FUNCPTRS;
++ MMAP_PAGE_ZERO;
++ READ_IMPLIES_EXEC;
++ SHORT_INODE;
++ STICKY_TIMEOUTS;
++ #[cfg(not(target_env = "musl"))]
++ UNAME26;
++ WHOLE_SECONDS;
++ }
++}
++
++/// Retrieve the current process personality.
++///
++/// Returns a Result containing a Persona instance.
++///
++/// Example:
++///
++/// ```
++/// # use nix::sys::personality::{self, Persona};
++/// let pers = personality::get().unwrap();
++/// assert!(!pers.contains(Persona::WHOLE_SECONDS));
++/// ```
++pub fn get() -> Result<Persona> {
++ let res = unsafe {
++ libc::personality(0xFFFFFFFF)
++ };
++
++ Errno::result(res).map(|r| Persona::from_bits_truncate(r))
++}
++
++/// Set the current process personality.
++///
++/// Returns a Result containing the *previous* personality for the
++/// process, as a Persona.
++///
++/// For more information, see [personality(2)](https://man7.org/linux/man-pages/man2/personality.2.html)
++///
++/// **NOTE**: This call **replaces** the current personality entirely.
++/// To **update** the personality, first call `get()` and then `set()`
++/// with the modified persona.
++///
++/// Example:
++///
++/// ```
++/// # use nix::sys::personality::{self, Persona};
++/// let mut pers = personality::get().unwrap();
++/// assert!(!pers.contains(Persona::ADDR_NO_RANDOMIZE));
++/// personality::set(pers | Persona::ADDR_NO_RANDOMIZE);
++/// ```
++pub fn set(persona: Persona) -> Result<Persona> {
++ let res = unsafe {
++ libc::personality(persona.bits() as c_ulong)
++ };
++
++ Errno::result(res).map(|r| Persona::from_bits_truncate(r))
++}
+diff --git a/third_party/rust/nix/src/sys/ptrace/bsd.rs b/third_party/rust/nix/src/sys/ptrace/bsd.rs
+index 7797d10647ef4..e85afc761198b 100644
+--- a/third_party/rust/nix/src/sys/ptrace/bsd.rs
++++ b/third_party/rust/nix/src/sys/ptrace/bsd.rs
+@@ -1,9 +1,10 @@
+-use errno::Errno;
++use cfg_if::cfg_if;
++use crate::errno::Errno;
+ use libc::{self, c_int};
+ use std::ptr;
+-use sys::signal::Signal;
+-use unistd::Pid;
+-use Result;
++use crate::sys::signal::Signal;
++use crate::unistd::Pid;
++use crate::Result;
+
+ pub type RequestType = c_int;
+
+@@ -77,16 +78,23 @@ pub fn traceme() -> Result<()> {
+
+ /// Attach to a running process, as with `ptrace(PT_ATTACH, ...)`
+ ///
+-/// Attaches to the process specified in pid, making it a tracee of the calling process.
++/// Attaches to the process specified by `pid`, making it a tracee of the calling process.
+ pub fn attach(pid: Pid) -> Result<()> {
+ unsafe { ptrace_other(Request::PT_ATTACH, pid, ptr::null_mut(), 0).map(drop) }
+ }
+
+ /// Detaches the current running process, as with `ptrace(PT_DETACH, ...)`
+ ///
+-/// Detaches from the process specified in pid allowing it to run freely
+-pub fn detach(pid: Pid) -> Result<()> {
+- unsafe { ptrace_other(Request::PT_DETACH, pid, ptr::null_mut(), 0).map(drop) }
++/// Detaches from the process specified by `pid` allowing it to run freely, optionally delivering a
++/// signal specified by `sig`.
++pub fn detach<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
++ let data = match sig.into() {
++ Some(s) => s as c_int,
++ None => 0,
++ };
++ unsafe {
++ ptrace_other(Request::PT_DETACH, pid, ptr::null_mut(), data).map(drop)
++ }
+ }
+
+ /// Restart the stopped tracee process, as with `ptrace(PTRACE_CONT, ...)`
+@@ -121,7 +129,6 @@ pub fn kill(pid: Pid) -> Result<()> {
+ ///
+ /// # Example
+ /// ```rust
+-/// extern crate nix;
+ /// use nix::sys::ptrace::step;
+ /// use nix::unistd::Pid;
+ /// use nix::sys::signal::Signal;
+diff --git a/third_party/rust/nix/src/sys/ptrace/linux.rs b/third_party/rust/nix/src/sys/ptrace/linux.rs
+index df15e66527562..8d1dd16e5dd76 100644
+--- a/third_party/rust/nix/src/sys/ptrace/linux.rs
++++ b/third_party/rust/nix/src/sys/ptrace/linux.rs
+@@ -1,18 +1,21 @@
+ //! For detailed description of the ptrace requests, consult `man ptrace`.
+
++use cfg_if::cfg_if;
+ use std::{mem, ptr};
+-use {Error, Result};
+-use errno::Errno;
++use crate::{Error, Result};
++use crate::errno::Errno;
+ use libc::{self, c_void, c_long, siginfo_t};
+-use ::unistd::Pid;
+-use sys::signal::Signal;
++use crate::unistd::Pid;
++use crate::sys::signal::Signal;
+
+ pub type AddressType = *mut ::libc::c_void;
+
+-#[cfg(all(target_os = "linux",
+- any(target_arch = "x86_64",
+- target_arch = "x86"),
+- target_env = "gnu"))]
++#[cfg(all(
++ target_os = "linux",
++ any(all(target_arch = "x86_64",
++ any(target_env = "gnu", target_env = "musl")),
++ all(target_arch = "x86", target_env = "gnu"))
++))]
+ use libc::user_regs_struct;
+
+ cfg_if! {
+@@ -106,6 +109,12 @@ libc_enum!{
+ #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
+ target_arch = "mips64"))))]
+ PTRACE_PEEKSIGINFO,
++ #[cfg(all(target_os = "linux", target_env = "gnu",
++ any(target_arch = "x86", target_arch = "x86_64")))]
++ PTRACE_SYSEMU,
++ #[cfg(all(target_os = "linux", target_env = "gnu",
++ any(target_arch = "x86", target_arch = "x86_64")))]
++ PTRACE_SYSEMU_SINGLESTEP,
+ }
+ }
+
+@@ -165,22 +174,6 @@ libc_bitflags! {
+ }
+ }
+
+-/// Performs a ptrace request. If the request in question is provided by a specialised function
+-/// this function will return an unsupported operation error.
+-#[deprecated(
+- since="0.10.0",
+- note="usages of `ptrace()` should be replaced with the specialized helper functions instead"
+-)]
+-pub unsafe fn ptrace(request: Request, pid: Pid, addr: AddressType, data: *mut c_void) -> Result<c_long> {
+- use self::Request::*;
+- match request {
+- PTRACE_PEEKTEXT | PTRACE_PEEKDATA | PTRACE_GETSIGINFO |
+- PTRACE_GETEVENTMSG | PTRACE_SETSIGINFO | PTRACE_SETOPTIONS |
+- PTRACE_POKETEXT | PTRACE_POKEDATA | PTRACE_KILL => Err(Error::UnsupportedOperation),
+- _ => ptrace_other(request, pid, addr, data)
+- }
+-}
+-
+ fn ptrace_peek(request: Request, pid: Pid, addr: AddressType, data: *mut c_void) -> Result<c_long> {
+ let ret = unsafe {
+ Errno::clear();
+@@ -193,19 +186,23 @@ fn ptrace_peek(request: Request, pid: Pid, addr: AddressType, data: *mut c_void)
+ }
+
+ /// Get user registers, as with `ptrace(PTRACE_GETREGS, ...)`
+-#[cfg(all(target_os = "linux",
+- any(target_arch = "x86_64",
+- target_arch = "x86"),
+- target_env = "gnu"))]
++#[cfg(all(
++ target_os = "linux",
++ any(all(target_arch = "x86_64",
++ any(target_env = "gnu", target_env = "musl")),
++ all(target_arch = "x86", target_env = "gnu"))
++))]
+ pub fn getregs(pid: Pid) -> Result<user_regs_struct> {
+ ptrace_get_data::<user_regs_struct>(Request::PTRACE_GETREGS, pid)
+ }
+
+ /// Set user registers, as with `ptrace(PTRACE_SETREGS, ...)`
+-#[cfg(all(target_os = "linux",
+- any(target_arch = "x86_64",
+- target_arch = "x86"),
+- target_env = "gnu"))]
++#[cfg(all(
++ target_os = "linux",
++ any(all(target_arch = "x86_64",
++ any(target_env = "gnu", target_env = "musl")),
++ all(target_arch = "x86", target_env = "gnu"))
++))]
+ pub fn setregs(pid: Pid, regs: user_regs_struct) -> Result<()> {
+ let res = unsafe {
+ libc::ptrace(Request::PTRACE_SETREGS as RequestType,
+@@ -221,16 +218,15 @@ pub fn setregs(pid: Pid, regs: user_regs_struct) -> Result<()> {
+ /// and therefore use the data field to return values. This function handles these
+ /// requests.
+ fn ptrace_get_data<T>(request: Request, pid: Pid) -> Result<T> {
+- // Creates an uninitialized pointer to store result in
+- let data: T = unsafe { mem::uninitialized() };
++ let mut data = mem::MaybeUninit::uninit();
+ let res = unsafe {
+ libc::ptrace(request as RequestType,
+ libc::pid_t::from(pid),
+ ptr::null_mut::<T>(),
+- &data as *const _ as *const c_void)
++ data.as_mut_ptr() as *const _ as *const c_void)
+ };
+ Errno::result(res)?;
+- Ok(data)
++ Ok(unsafe{ data.assume_init() })
+ }
+
+ unsafe fn ptrace_other(request: Request, pid: Pid, addr: AddressType, data: *mut c_void) -> Result<c_long> {
+@@ -288,23 +284,45 @@ pub fn traceme() -> Result<()> {
+ }
+ }
+
+-/// Ask for next syscall, as with `ptrace(PTRACE_SYSCALL, ...)`
++/// Continue execution until the next syscall, as with `ptrace(PTRACE_SYSCALL, ...)`
+ ///
+-/// Arranges for the tracee to be stopped at the next entry to or exit from a system call.
+-pub fn syscall(pid: Pid) -> Result<()> {
++/// Arranges for the tracee to be stopped at the next entry to or exit from a system call,
++/// optionally delivering a signal specified by `sig`.
++pub fn syscall<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
++ let data = match sig.into() {
++ Some(s) => s as i32 as *mut c_void,
++ None => ptr::null_mut(),
++ };
+ unsafe {
+ ptrace_other(
+ Request::PTRACE_SYSCALL,
+ pid,
+ ptr::null_mut(),
+- ptr::null_mut(),
++ data,
+ ).map(drop) // ignore the useless return value
+ }
+ }
+
++/// Continue execution until the next syscall, as with `ptrace(PTRACE_SYSEMU, ...)`
++///
++/// In contrast to the `syscall` function, the syscall stopped at will not be executed.
++/// Thus the the tracee will only be stopped once per syscall,
++/// optionally delivering a signal specified by `sig`.
++#[cfg(all(target_os = "linux", target_env = "gnu", any(target_arch = "x86", target_arch = "x86_64")))]
++pub fn sysemu<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
++ let data = match sig.into() {
++ Some(s) => s as i32 as *mut c_void,
++ None => ptr::null_mut(),
++ };
++ unsafe {
++ ptrace_other(Request::PTRACE_SYSEMU, pid, ptr::null_mut(), data).map(drop)
++ // ignore the useless return value
++ }
++}
++
+ /// Attach to a running process, as with `ptrace(PTRACE_ATTACH, ...)`
+ ///
+-/// Attaches to the process specified in pid, making it a tracee of the calling process.
++/// Attaches to the process specified by `pid`, making it a tracee of the calling process.
+ pub fn attach(pid: Pid) -> Result<()> {
+ unsafe {
+ ptrace_other(
+@@ -316,16 +334,36 @@ pub fn attach(pid: Pid) -> Result<()> {
+ }
+ }
+
++/// Attach to a running process, as with `ptrace(PTRACE_SEIZE, ...)`
++///
++/// Attaches to the process specified in pid, making it a tracee of the calling process.
++#[cfg(all(target_os = "linux", not(any(target_arch = "mips", target_arch = "mips64"))))]
++pub fn seize(pid: Pid, options: Options) -> Result<()> {
++ unsafe {
++ ptrace_other(
++ Request::PTRACE_SEIZE,
++ pid,
++ ptr::null_mut(),
++ options.bits() as *mut c_void,
++ ).map(drop) // ignore the useless return value
++ }
++}
++
+ /// Detaches the current running process, as with `ptrace(PTRACE_DETACH, ...)`
+ ///
+-/// Detaches from the process specified in pid allowing it to run freely
+-pub fn detach(pid: Pid) -> Result<()> {
++/// Detaches from the process specified by `pid` allowing it to run freely, optionally delivering a
++/// signal specified by `sig`.
++pub fn detach<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
++ let data = match sig.into() {
++ Some(s) => s as i32 as *mut c_void,
++ None => ptr::null_mut(),
++ };
+ unsafe {
+ ptrace_other(
+ Request::PTRACE_DETACH,
+ pid,
+ ptr::null_mut(),
+- ptr::null_mut()
++ data
+ ).map(drop)
+ }
+ }
+@@ -361,7 +399,6 @@ pub fn kill(pid: Pid) -> Result<()> {
+ ///
+ /// # Example
+ /// ```rust
+-/// extern crate nix;
+ /// use nix::sys::ptrace::step;
+ /// use nix::unistd::Pid;
+ /// use nix::sys::signal::Signal;
+@@ -388,6 +425,28 @@ pub fn step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
+ }
+ }
+
++/// Move the stopped tracee process forward by a single step or stop at the next syscall
++/// as with `ptrace(PTRACE_SYSEMU_SINGLESTEP, ...)`
++///
++/// Advances the execution by a single step or until the next syscall.
++/// In case the tracee is stopped at a syscall, the syscall will not be executed.
++/// Optionally, the signal specified by `sig` is delivered to the tracee upon continuation.
++#[cfg(all(target_os = "linux", target_env = "gnu", any(target_arch = "x86", target_arch = "x86_64")))]
++pub fn sysemu_step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
++ let data = match sig.into() {
++ Some(s) => s as i32 as *mut c_void,
++ None => ptr::null_mut(),
++ };
++ unsafe {
++ ptrace_other(
++ Request::PTRACE_SYSEMU_SINGLESTEP,
++ pid,
++ ptr::null_mut(),
++ data,
++ )
++ .map(drop) // ignore the useless return value
++ }
++}
+
+ /// Reads a word from a processes memory at the given address
+ pub fn read(pid: Pid, addr: AddressType) -> Result<c_long> {
+@@ -395,8 +454,15 @@ pub fn read(pid: Pid, addr: AddressType) -> Result<c_long> {
+ }
+
+ /// Writes a word into the processes memory at the given address
+-pub fn write(pid: Pid, addr: AddressType, data: *mut c_void) -> Result<()> {
+- unsafe {
+- ptrace_other(Request::PTRACE_POKEDATA, pid, addr, data).map(drop)
+- }
++///
++/// # Safety
++///
++/// The `data` argument is passed directly to `ptrace(2)`. Read that man page
++/// for guidance.
++pub unsafe fn write(
++ pid: Pid,
++ addr: AddressType,
++ data: *mut c_void) -> Result<()>
++{
++ ptrace_other(Request::PTRACE_POKEDATA, pid, addr, data).map(drop)
+ }
+diff --git a/third_party/rust/nix/src/sys/quota.rs b/third_party/rust/nix/src/sys/quota.rs
+index 8946fca2213c8..1933013219102 100644
+--- a/third_party/rust/nix/src/sys/quota.rs
++++ b/third_party/rust/nix/src/sys/quota.rs
+@@ -15,12 +15,13 @@
+ use std::default::Default;
+ use std::{mem, ptr};
+ use libc::{self, c_int, c_char};
+-use {Result, NixPath};
+-use errno::Errno;
++use crate::{Result, NixPath};
++use crate::errno::Errno;
+
+ struct QuotaCmd(QuotaSubCmd, QuotaType);
+
+ impl QuotaCmd {
++ #[allow(unused_unsafe)]
+ fn as_int(&self) -> c_int {
+ unsafe { libc::QCMD(self.0 as i32, self.1 as i32) }
+ }
+@@ -94,8 +95,7 @@ libc_bitflags!(
+ );
+
+ /// Wrapper type for `if_dqblk`
+-// FIXME: Change to repr(transparent)
+-#[repr(C)]
++#[repr(transparent)]
+ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+ pub struct Dqblk(libc::dqblk);
+
+@@ -254,15 +254,17 @@ pub fn quotactl_off<P: ?Sized + NixPath>(which: QuotaType, special: &P) -> Resul
+ }
+
+ /// Update the on-disk copy of quota usages for a filesystem.
++///
++/// If `special` is `None`, then all file systems with active quotas are sync'd.
+ pub fn quotactl_sync<P: ?Sized + NixPath>(which: QuotaType, special: Option<&P>) -> Result<()> {
+ quotactl(QuotaCmd(QuotaSubCmd::Q_SYNC, which), special, 0, ptr::null_mut())
+ }
+
+ /// Get disk quota limits and current usage for the given user/group id.
+ pub fn quotactl_get<P: ?Sized + NixPath>(which: QuotaType, special: &P, id: c_int) -> Result<Dqblk> {
+- let mut dqblk = unsafe { mem::uninitialized() };
+- quotactl(QuotaCmd(QuotaSubCmd::Q_GETQUOTA, which), Some(special), id, &mut dqblk as *mut _ as *mut c_char)?;
+- dqblk
++ let mut dqblk = mem::MaybeUninit::uninit();
++ quotactl(QuotaCmd(QuotaSubCmd::Q_GETQUOTA, which), Some(special), id, dqblk.as_mut_ptr() as *mut c_char)?;
++ Ok(unsafe{ Dqblk(dqblk.assume_init())})
+ }
+
+ /// Configure quota values for the specified fields for a given user/group id.
+diff --git a/third_party/rust/nix/src/sys/reboot.rs b/third_party/rust/nix/src/sys/reboot.rs
+index bafa8fc11996d..e319130698e82 100644
+--- a/third_party/rust/nix/src/sys/reboot.rs
++++ b/third_party/rust/nix/src/sys/reboot.rs
+@@ -1,9 +1,9 @@
+ //! Reboot/shutdown or enable/disable Ctrl-Alt-Delete.
+
+-use {Error, Result};
+-use errno::Errno;
++use crate::{Error, Result};
++use crate::errno::Errno;
+ use libc;
+-use void::Void;
++use std::convert::Infallible;
+ use std::mem::drop;
+
+ libc_enum! {
+@@ -22,7 +22,7 @@ libc_enum! {
+ }
+ }
+
+-pub fn reboot(how: RebootMode) -> Result<Void> {
++pub fn reboot(how: RebootMode) -> Result<Infallible> {
+ unsafe {
+ libc::reboot(how as libc::c_int)
+ };
+diff --git a/third_party/rust/nix/src/sys/select.rs b/third_party/rust/nix/src/sys/select.rs
+index 1b518e29f67a6..a576c7e4929c4 100644
+--- a/third_party/rust/nix/src/sys/select.rs
++++ b/third_party/rust/nix/src/sys/select.rs
+@@ -1,24 +1,27 @@
++use std::iter::FusedIterator;
+ use std::mem;
++use std::ops::Range;
+ use std::os::unix::io::RawFd;
+ use std::ptr::{null, null_mut};
+ use libc::{self, c_int};
+-use Result;
+-use errno::Errno;
+-use sys::signal::SigSet;
+-use sys::time::{TimeSpec, TimeVal};
++use crate::Result;
++use crate::errno::Errno;
++use crate::sys::signal::SigSet;
++use crate::sys::time::{TimeSpec, TimeVal};
+
+ pub use libc::FD_SETSIZE;
+
+-// FIXME: Change to repr(transparent) once it's stable
+-#[repr(C)]
++#[repr(transparent)]
+ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+ pub struct FdSet(libc::fd_set);
+
+ impl FdSet {
+ pub fn new() -> FdSet {
+- let mut fdset = unsafe { mem::uninitialized() };
+- unsafe { libc::FD_ZERO(&mut fdset) };
+- FdSet(fdset)
++ let mut fdset = mem::MaybeUninit::uninit();
++ unsafe {
++ libc::FD_ZERO(fdset.as_mut_ptr());
++ FdSet(fdset.assume_init())
++ }
+ }
+
+ pub fn insert(&mut self, fd: RawFd) {
+@@ -46,7 +49,6 @@ impl FdSet {
+ /// # Example
+ ///
+ /// ```
+- /// # extern crate nix;
+ /// # use nix::sys::select::FdSet;
+ /// # fn main() {
+ /// let mut set = FdSet::new();
+@@ -58,17 +60,81 @@ impl FdSet {
+ ///
+ /// [`select`]: fn.select.html
+ pub fn highest(&mut self) -> Option<RawFd> {
+- for i in (0..FD_SETSIZE).rev() {
+- let i = i as RawFd;
+- if unsafe { libc::FD_ISSET(i, self as *mut _ as *mut libc::fd_set) } {
+- return Some(i)
++ self.fds(None).next_back()
++ }
++
++ /// Returns an iterator over the file descriptors in the set.
++ ///
++ /// For performance, it takes an optional higher bound: the iterator will
++ /// not return any elements of the set greater than the given file
++ /// descriptor.
++ ///
++ /// # Examples
++ ///
++ /// ```
++ /// # use nix::sys::select::FdSet;
++ /// # use std::os::unix::io::RawFd;
++ /// let mut set = FdSet::new();
++ /// set.insert(4);
++ /// set.insert(9);
++ /// let fds: Vec<RawFd> = set.fds(None).collect();
++ /// assert_eq!(fds, vec![4, 9]);
++ /// ```
++ #[inline]
++ pub fn fds(&mut self, highest: Option<RawFd>) -> Fds {
++ Fds {
++ set: self,
++ range: 0..highest.map(|h| h as usize + 1).unwrap_or(FD_SETSIZE),
++ }
++ }
++}
++
++impl Default for FdSet {
++ fn default() -> Self {
++ Self::new()
++ }
++}
++
++/// Iterator over `FdSet`.
++#[derive(Debug)]
++pub struct Fds<'a> {
++ set: &'a mut FdSet,
++ range: Range<usize>,
++}
++
++impl<'a> Iterator for Fds<'a> {
++ type Item = RawFd;
++
++ fn next(&mut self) -> Option<RawFd> {
++ while let Some(i) = self.range.next() {
++ if self.set.contains(i as RawFd) {
++ return Some(i as RawFd);
+ }
+ }
++ None
++ }
++
++ #[inline]
++ fn size_hint(&self) -> (usize, Option<usize>) {
++ let (_, upper) = self.range.size_hint();
++ (0, upper)
++ }
++}
+
++impl<'a> DoubleEndedIterator for Fds<'a> {
++ #[inline]
++ fn next_back(&mut self) -> Option<RawFd> {
++ while let Some(i) = self.range.next_back() {
++ if self.set.contains(i as RawFd) {
++ return Some(i as RawFd);
++ }
++ }
+ None
+ }
+ }
+
++impl<'a> FusedIterator for Fds<'a> {}
++
+ /// Monitors file descriptors for readiness
+ ///
+ /// Returns the total number of ready file descriptors in all sets. The sets are changed so that all
+@@ -93,9 +159,9 @@ impl FdSet {
+ ///
+ /// [`FdSet::highest`]: struct.FdSet.html#method.highest
+ pub fn select<'a, N, R, W, E, T>(nfds: N,
+- readfds: R,
+- writefds: W,
+- errorfds: E,
++ readfds: R,
++ writefds: W,
++ errorfds: E,
+ timeout: T) -> Result<c_int>
+ where
+ N: Into<Option<c_int>>,
+@@ -122,7 +188,7 @@ where
+ let writefds = writefds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
+ let errorfds = errorfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
+ let timeout = timeout.map(|tv| tv as *mut _ as *mut libc::timeval)
+- .unwrap_or(null_mut());
++ .unwrap_or(null_mut());
+
+ let res = unsafe {
+ libc::select(nfds, readfds, writefds, errorfds, timeout)
+@@ -161,10 +227,10 @@ where
+ ///
+ /// [`FdSet::highest`]: struct.FdSet.html#method.highest
+ pub fn pselect<'a, N, R, W, E, T, S>(nfds: N,
+- readfds: R,
+- writefds: W,
+- errorfds: E,
+- timeout: T,
++ readfds: R,
++ writefds: W,
++ errorfds: E,
++ timeout: T,
+ sigmask: S) -> Result<c_int>
+ where
+ N: Into<Option<c_int>>,
+@@ -207,8 +273,8 @@ where
+ mod tests {
+ use super::*;
+ use std::os::unix::io::RawFd;
+- use sys::time::{TimeVal, TimeValLike};
+- use unistd::{write, pipe};
++ use crate::sys::time::{TimeVal, TimeValLike};
++ use crate::unistd::{write, pipe};
+
+ #[test]
+ fn fdset_insert() {
+@@ -272,6 +338,20 @@ mod tests {
+ assert_eq!(set.highest(), Some(7));
+ }
+
++ #[test]
++ fn fdset_fds() {
++ let mut set = FdSet::new();
++ assert_eq!(set.fds(None).collect::<Vec<_>>(), vec![]);
++ set.insert(0);
++ assert_eq!(set.fds(None).collect::<Vec<_>>(), vec![0]);
++ set.insert(90);
++ assert_eq!(set.fds(None).collect::<Vec<_>>(), vec![0, 90]);
++
++ // highest limit
++ assert_eq!(set.fds(Some(89)).collect::<Vec<_>>(), vec![0]);
++ assert_eq!(set.fds(Some(90)).collect::<Vec<_>>(), vec![0, 90]);
++ }
++
+ #[test]
+ fn test_select() {
+ let (r1, w1) = pipe().unwrap();
+@@ -304,9 +384,9 @@ mod tests {
+
+ let mut timeout = TimeVal::seconds(10);
+ assert_eq!(1, select(Some(fd_set.highest().unwrap() + 1),
+- &mut fd_set,
+- None,
+- None,
++ &mut fd_set,
++ None,
++ None,
+ &mut timeout).unwrap());
+ assert!(fd_set.contains(r1));
+ assert!(!fd_set.contains(r2));
+@@ -324,9 +404,9 @@ mod tests {
+
+ let mut timeout = TimeVal::seconds(10);
+ assert_eq!(1, select(::std::cmp::max(r1, r2) + 1,
+- &mut fd_set,
+- None,
+- None,
++ &mut fd_set,
++ None,
++ None,
+ &mut timeout).unwrap());
+ assert!(fd_set.contains(r1));
+ assert!(!fd_set.contains(r2));
+diff --git a/third_party/rust/nix/src/sys/sendfile.rs b/third_party/rust/nix/src/sys/sendfile.rs
+index a47d8962f73fb..84fe2a919e8b4 100644
+--- a/third_party/rust/nix/src/sys/sendfile.rs
++++ b/third_party/rust/nix/src/sys/sendfile.rs
+@@ -1,10 +1,11 @@
++use cfg_if::cfg_if;
+ use std::os::unix::io::RawFd;
+ use std::ptr;
+
+ use libc::{self, off_t};
+
+-use Result;
+-use errno::Errno;
++use crate::Result;
++use crate::errno::Errno;
+
+ /// Copy up to `count` bytes to `out_fd` from `in_fd` starting at `offset`.
+ ///
+@@ -36,7 +37,7 @@ cfg_if! {
+ if #[cfg(any(target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos"))] {
+- use sys::uio::IoVec;
++ use crate::sys::uio::IoVec;
+
+ #[derive(Clone, Debug, Eq, Hash, PartialEq)]
+ struct SendfileHeaderTrailer<'a>(
+@@ -123,6 +124,7 @@ cfg_if! {
+ ///
+ /// For more information, see
+ /// [the sendfile(2) man page.](https://www.freebsd.org/cgi/man.cgi?query=sendfile&sektion=2)
++ #[allow(clippy::too_many_arguments)]
+ pub fn sendfile(
+ in_fd: RawFd,
+ out_sock: RawFd,
+@@ -136,7 +138,8 @@ cfg_if! {
+ // Readahead goes in upper 16 bits
+ // Flags goes in lower 16 bits
+ // see `man 2 sendfile`
+- let flags: u32 = ((readahead as u32) << 16) | (flags.bits() as u32);
++ let ra32 = u32::from(readahead);
++ let flags: u32 = (ra32 << 16) | (flags.bits() as u32);
+ let mut bytes_sent: off_t = 0;
+ let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers));
+ let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr);
+diff --git a/third_party/rust/nix/src/sys/signal.rs b/third_party/rust/nix/src/sys/signal.rs
+index 1013a77fd4b40..2f8b5fa88823d 100644
+--- a/third_party/rust/nix/src/sys/signal.rs
++++ b/third_party/rust/nix/src/sys/signal.rs
+@@ -3,9 +3,10 @@
+
+ ///! Operating system signals.
+
+-use libc;
+-use {Error, Result};
+-use errno::Errno;
++use crate::{Error, Result};
++use crate::errno::Errno;
++use crate::unistd::Pid;
++use std::convert::TryFrom;
+ use std::mem;
+ use std::fmt;
+ use std::str::FromStr;
+@@ -13,7 +14,7 @@ use std::str::FromStr;
+ use std::os::unix::io::RawFd;
+ use std::ptr;
+
+-#[cfg(not(target_os = "openbsd"))]
++#[cfg(not(any(target_os = "openbsd", target_os = "redox")))]
+ pub use self::sigevent::*;
+
+ libc_enum!{
+@@ -38,8 +39,10 @@ libc_enum!{
+ SIGPIPE,
+ SIGALRM,
+ SIGTERM,
+- #[cfg(all(any(target_os = "android", target_os = "emscripten", target_os = "linux"),
+- not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
++ #[cfg(all(any(target_os = "android", target_os = "emscripten",
++ target_os = "fuchsia", target_os = "linux"),
++ not(any(target_arch = "mips", target_arch = "mips64",
++ target_arch = "sparc64"))))]
+ SIGSTKFLT,
+ SIGCHLD,
+ SIGCONT,
+@@ -54,12 +57,17 @@ libc_enum!{
+ SIGPROF,
+ SIGWINCH,
+ SIGIO,
+- #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))]
++ #[cfg(any(target_os = "android", target_os = "emscripten",
++ target_os = "fuchsia", target_os = "linux"))]
+ SIGPWR,
+ SIGSYS,
+- #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
++ #[cfg(not(any(target_os = "android", target_os = "emscripten",
++ target_os = "fuchsia", target_os = "linux",
++ target_os = "redox")))]
+ SIGEMT,
+- #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
++ #[cfg(not(any(target_os = "android", target_os = "emscripten",
++ target_os = "fuchsia", target_os = "linux",
++ target_os = "redox")))]
+ SIGINFO,
+ }
+ }
+@@ -83,8 +91,10 @@ impl FromStr for Signal {
+ "SIGPIPE" => Signal::SIGPIPE,
+ "SIGALRM" => Signal::SIGALRM,
+ "SIGTERM" => Signal::SIGTERM,
+- #[cfg(all(any(target_os = "android", target_os = "emscripten", target_os = "linux"),
+- not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
++ #[cfg(all(any(target_os = "android", target_os = "emscripten",
++ target_os = "fuchsia", target_os = "linux"),
++ not(any(target_arch = "mips", target_arch = "mips64",
++ target_arch = "sparc64"))))]
+ "SIGSTKFLT" => Signal::SIGSTKFLT,
+ "SIGCHLD" => Signal::SIGCHLD,
+ "SIGCONT" => Signal::SIGCONT,
+@@ -99,21 +109,31 @@ impl FromStr for Signal {
+ "SIGPROF" => Signal::SIGPROF,
+ "SIGWINCH" => Signal::SIGWINCH,
+ "SIGIO" => Signal::SIGIO,
+- #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))]
++ #[cfg(any(target_os = "android", target_os = "emscripten",
++ target_os = "fuchsia", target_os = "linux"))]
+ "SIGPWR" => Signal::SIGPWR,
+ "SIGSYS" => Signal::SIGSYS,
+- #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
++ #[cfg(not(any(target_os = "android", target_os = "emscripten",
++ target_os = "fuchsia", target_os = "linux",
++ target_os = "redox")))]
+ "SIGEMT" => Signal::SIGEMT,
+- #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
++ #[cfg(not(any(target_os = "android", target_os = "emscripten",
++ target_os = "fuchsia", target_os = "linux",
++ target_os = "redox")))]
+ "SIGINFO" => Signal::SIGINFO,
+ _ => return Err(Error::invalid_argument()),
+ })
+ }
+ }
+
+-impl AsRef<str> for Signal {
+- fn as_ref(&self) -> &str {
+- match *self {
++impl Signal {
++ /// Returns name of signal.
++ ///
++ /// This function is equivalent to `<Signal as AsRef<str>>::as_ref()`,
++ /// with difference that returned string is `'static`
++ /// and not bound to `self`'s lifetime.
++ pub fn as_str(self) -> &'static str {
++ match self {
+ Signal::SIGHUP => "SIGHUP",
+ Signal::SIGINT => "SIGINT",
+ Signal::SIGQUIT => "SIGQUIT",
+@@ -129,7 +149,8 @@ impl AsRef<str> for Signal {
+ Signal::SIGPIPE => "SIGPIPE",
+ Signal::SIGALRM => "SIGALRM",
+ Signal::SIGTERM => "SIGTERM",
+- #[cfg(all(any(target_os = "android", target_os = "emscripten", target_os = "linux"),
++ #[cfg(all(any(target_os = "android", target_os = "emscripten",
++ target_os = "fuchsia", target_os = "linux"),
+ not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
+ Signal::SIGSTKFLT => "SIGSTKFLT",
+ Signal::SIGCHLD => "SIGCHLD",
+@@ -145,17 +166,28 @@ impl AsRef<str> for Signal {
+ Signal::SIGPROF => "SIGPROF",
+ Signal::SIGWINCH => "SIGWINCH",
+ Signal::SIGIO => "SIGIO",
+- #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))]
++ #[cfg(any(target_os = "android", target_os = "emscripten",
++ target_os = "fuchsia", target_os = "linux"))]
+ Signal::SIGPWR => "SIGPWR",
+ Signal::SIGSYS => "SIGSYS",
+- #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
++ #[cfg(not(any(target_os = "android", target_os = "emscripten",
++ target_os = "fuchsia", target_os = "linux",
++ target_os = "redox")))]
+ Signal::SIGEMT => "SIGEMT",
+- #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
++ #[cfg(not(any(target_os = "android", target_os = "emscripten",
++ target_os = "fuchsia", target_os = "linux",
++ target_os = "redox")))]
+ Signal::SIGINFO => "SIGINFO",
+ }
+ }
+ }
+
++impl AsRef<str> for Signal {
++ fn as_ref(&self) -> &str {
++ self.as_str()
++ }
++}
++
+ impl fmt::Display for Signal {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.write_str(self.as_ref())
+@@ -164,7 +196,41 @@ impl fmt::Display for Signal {
+
+ pub use self::Signal::*;
+
+-#[cfg(all(any(target_os = "linux", target_os = "android", target_os = "emscripten"), not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
++#[cfg(target_os = "redox")]
++const SIGNALS: [Signal; 29] = [
++ SIGHUP,
++ SIGINT,
++ SIGQUIT,
++ SIGILL,
++ SIGTRAP,
++ SIGABRT,
++ SIGBUS,
++ SIGFPE,
++ SIGKILL,
++ SIGUSR1,
++ SIGSEGV,
++ SIGUSR2,
++ SIGPIPE,
++ SIGALRM,
++ SIGTERM,
++ SIGCHLD,
++ SIGCONT,
++ SIGSTOP,
++ SIGTSTP,
++ SIGTTIN,
++ SIGTTOU,
++ SIGURG,
++ SIGXCPU,
++ SIGXFSZ,
++ SIGVTALRM,
++ SIGPROF,
++ SIGWINCH,
++ SIGIO,
++ SIGSYS];
++#[cfg(all(any(target_os = "linux", target_os = "android",
++ target_os = "emscripten", target_os = "fuchsia"),
++ not(any(target_arch = "mips", target_arch = "mips64",
++ target_arch = "sparc64"))))]
+ const SIGNALS: [Signal; 31] = [
+ SIGHUP,
+ SIGINT,
+@@ -197,7 +263,10 @@ const SIGNALS: [Signal; 31] = [
+ SIGIO,
+ SIGPWR,
+ SIGSYS];
+-#[cfg(all(any(target_os = "linux", target_os = "android", target_os = "emscripten"), any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64")))]
++#[cfg(all(any(target_os = "linux", target_os = "android",
++ target_os = "emscripten", target_os = "fuchsia"),
++ any(target_arch = "mips", target_arch = "mips64",
++ target_arch = "sparc64")))]
+ const SIGNALS: [Signal; 30] = [
+ SIGHUP,
+ SIGINT,
+@@ -229,7 +298,9 @@ const SIGNALS: [Signal; 30] = [
+ SIGIO,
+ SIGPWR,
+ SIGSYS];
+-#[cfg(not(any(target_os = "linux", target_os = "android", target_os = "emscripten")))]
++#[cfg(not(any(target_os = "linux", target_os = "android",
++ target_os = "fuchsia", target_os = "emscripten",
++ target_os = "redox")))]
+ const SIGNALS: [Signal; 31] = [
+ SIGHUP,
+ SIGINT,
+@@ -288,12 +359,12 @@ impl Signal {
+ pub fn iterator() -> SignalIterator {
+ SignalIterator{next: 0}
+ }
++}
++
++impl TryFrom<libc::c_int> for Signal {
++ type Error = Error;
+
+- // We do not implement the From trait, because it is supposed to be infallible.
+- // With Rust RFC 1542 comes the appropriate trait TryFrom. Once it is
+- // implemented, we'll replace this function.
+- #[inline]
+- pub fn from_c_int(signum: libc::c_int) -> Result<Signal> {
++ fn try_from(signum: libc::c_int) -> Result<Signal> {
+ if 0 < signum && signum < NSIG {
+ Ok(unsafe { mem::transmute(signum) })
+ } else {
+@@ -306,8 +377,13 @@ pub const SIGIOT : Signal = SIGABRT;
+ pub const SIGPOLL : Signal = SIGIO;
+ pub const SIGUNUSED : Signal = SIGSYS;
+
++#[cfg(not(target_os = "redox"))]
++type SaFlags_t = libc::c_int;
++#[cfg(target_os = "redox")]
++type SaFlags_t = libc::c_ulong;
++
+ libc_bitflags!{
+- pub struct SaFlags: libc::c_int {
++ pub struct SaFlags: SaFlags_t {
+ SA_NOCLDSTOP;
+ SA_NOCLDWAIT;
+ SA_NODEFER;
+@@ -335,17 +411,17 @@ pub struct SigSet {
+
+ impl SigSet {
+ pub fn all() -> SigSet {
+- let mut sigset: libc::sigset_t = unsafe { mem::uninitialized() };
+- let _ = unsafe { libc::sigfillset(&mut sigset as *mut libc::sigset_t) };
++ let mut sigset = mem::MaybeUninit::uninit();
++ let _ = unsafe { libc::sigfillset(sigset.as_mut_ptr()) };
+
+- SigSet { sigset: sigset }
++ unsafe{ SigSet { sigset: sigset.assume_init() } }
+ }
+
+ pub fn empty() -> SigSet {
+- let mut sigset: libc::sigset_t = unsafe { mem::uninitialized() };
+- let _ = unsafe { libc::sigemptyset(&mut sigset as *mut libc::sigset_t) };
++ let mut sigset = mem::MaybeUninit::uninit();
++ let _ = unsafe { libc::sigemptyset(sigset.as_mut_ptr()) };
+
+- SigSet { sigset: sigset }
++ unsafe{ SigSet { sigset: sigset.assume_init() } }
+ }
+
+ pub fn add(&mut self, signal: Signal) {
+@@ -380,9 +456,9 @@ impl SigSet {
+
+ /// Gets the currently blocked (masked) set of signals for the calling thread.
+ pub fn thread_get_mask() -> Result<SigSet> {
+- let mut oldmask: SigSet = unsafe { mem::uninitialized() };
+- pthread_sigmask(SigmaskHow::SIG_SETMASK, None, Some(&mut oldmask))?;
+- Ok(oldmask)
++ let mut oldmask = mem::MaybeUninit::uninit();
++ do_pthread_sigmask(SigmaskHow::SIG_SETMASK, None, Some(oldmask.as_mut_ptr()))?;
++ Ok(unsafe{ SigSet{sigset: oldmask.assume_init()}})
+ }
+
+ /// Sets the set of signals as the signal mask for the calling thread.
+@@ -402,18 +478,21 @@ impl SigSet {
+
+ /// Sets the set of signals as the signal mask, and returns the old mask.
+ pub fn thread_swap_mask(&self, how: SigmaskHow) -> Result<SigSet> {
+- let mut oldmask: SigSet = unsafe { mem::uninitialized() };
+- pthread_sigmask(how, Some(self), Some(&mut oldmask))?;
+- Ok(oldmask)
++ let mut oldmask = mem::MaybeUninit::uninit();
++ do_pthread_sigmask(how, Some(self), Some(oldmask.as_mut_ptr()))?;
++ Ok(unsafe{ SigSet{sigset: oldmask.assume_init()}})
+ }
+
+ /// Suspends execution of the calling thread until one of the signals in the
+ /// signal mask becomes pending, and returns the accepted signal.
++ #[cfg(not(target_os = "redox"))] // RedoxFS does not yet support sigwait
+ pub fn wait(&self) -> Result<Signal> {
+- let mut signum: libc::c_int = unsafe { mem::uninitialized() };
+- let res = unsafe { libc::sigwait(&self.sigset as *const libc::sigset_t, &mut signum) };
++ let mut signum = mem::MaybeUninit::uninit();
++ let res = unsafe { libc::sigwait(&self.sigset as *const libc::sigset_t, signum.as_mut_ptr()) };
+
+- Errno::result(res).map(|_| Signal::from_c_int(signum).unwrap())
++ Errno::result(res).map(|_| unsafe {
++ Signal::try_from(signum.assume_init()).unwrap()
++ })
+ }
+ }
+
+@@ -435,6 +514,7 @@ pub enum SigHandler {
+ Handler(extern fn(libc::c_int)),
+ /// Use the given signal-catching function, which takes in the signal, information about how
+ /// the signal was generated, and a pointer to the threads `ucontext_t`.
++ #[cfg(not(target_os = "redox"))]
+ SigAction(extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void))
+ }
+
+@@ -451,20 +531,38 @@ impl SigAction {
+ /// is the `SigAction` variant). `mask` specifies other signals to block during execution of
+ /// the signal-catching function.
+ pub fn new(handler: SigHandler, flags: SaFlags, mask: SigSet) -> SigAction {
+- let mut s = unsafe { mem::uninitialized::<libc::sigaction>() };
+- s.sa_sigaction = match handler {
+- SigHandler::SigDfl => libc::SIG_DFL,
+- SigHandler::SigIgn => libc::SIG_IGN,
+- SigHandler::Handler(f) => f as *const extern fn(libc::c_int) as usize,
+- SigHandler::SigAction(f) => f as *const extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void) as usize,
+- };
+- s.sa_flags = match handler {
+- SigHandler::SigAction(_) => (flags | SaFlags::SA_SIGINFO).bits(),
+- _ => (flags - SaFlags::SA_SIGINFO).bits(),
+- };
+- s.sa_mask = mask.sigset;
+-
+- SigAction { sigaction: s }
++ #[cfg(target_os = "redox")]
++ unsafe fn install_sig(p: *mut libc::sigaction, handler: SigHandler) {
++ (*p).sa_handler = match handler {
++ SigHandler::SigDfl => libc::SIG_DFL,
++ SigHandler::SigIgn => libc::SIG_IGN,
++ SigHandler::Handler(f) => f as *const extern fn(libc::c_int) as usize,
++ };
++ }
++
++ #[cfg(not(target_os = "redox"))]
++ unsafe fn install_sig(p: *mut libc::sigaction, handler: SigHandler) {
++ (*p).sa_sigaction = match handler {
++ SigHandler::SigDfl => libc::SIG_DFL,
++ SigHandler::SigIgn => libc::SIG_IGN,
++ SigHandler::Handler(f) => f as *const extern fn(libc::c_int) as usize,
++ SigHandler::SigAction(f) => f as *const extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void) as usize,
++ };
++ }
++
++ let mut s = mem::MaybeUninit::<libc::sigaction>::uninit();
++ unsafe {
++ let p = s.as_mut_ptr();
++ install_sig(p, handler);
++ (*p).sa_flags = match handler {
++ #[cfg(not(target_os = "redox"))]
++ SigHandler::SigAction(_) => (flags | SaFlags::SA_SIGINFO).bits(),
++ _ => (flags - SaFlags::SA_SIGINFO).bits(),
++ };
++ (*p).sa_mask = mask.sigset;
++
++ SigAction { sigaction: s.assume_init() }
++ }
+ }
+
+ /// Returns the flags set on the action.
+@@ -479,6 +577,7 @@ impl SigAction {
+ }
+
+ /// Returns the action's handler.
++ #[cfg(not(target_os = "redox"))]
+ pub fn handler(&self) -> SigHandler {
+ match self.sigaction.sa_sigaction {
+ libc::SIG_DFL => SigHandler::SigDfl,
+@@ -488,6 +587,16 @@ impl SigAction {
+ f => SigHandler::Handler( unsafe { mem::transmute(f) } ),
+ }
+ }
++
++ /// Returns the action's handler.
++ #[cfg(target_os = "redox")]
++ pub fn handler(&self) -> SigHandler {
++ match self.sigaction.sa_handler {
++ libc::SIG_DFL => SigHandler::SigDfl,
++ libc::SIG_IGN => SigHandler::SigIgn,
++ f => SigHandler::Handler( unsafe { mem::transmute(f) } ),
++ }
++ }
+ }
+
+ /// Changes the action taken by a process on receipt of a specific signal.
+@@ -501,12 +610,13 @@ impl SigAction {
+ /// the body of the signal-catching function. Be certain to only make syscalls that are explicitly
+ /// marked safe for signal handlers and only share global data using atomics.
+ pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigAction> {
+- let mut oldact = mem::uninitialized::<libc::sigaction>();
++ let mut oldact = mem::MaybeUninit::<libc::sigaction>::uninit();
+
+- let res =
+- libc::sigaction(signal as libc::c_int, &sigaction.sigaction as *const libc::sigaction, &mut oldact as *mut libc::sigaction);
++ let res = libc::sigaction(signal as libc::c_int,
++ &sigaction.sigaction as *const libc::sigaction,
++ oldact.as_mut_ptr());
+
+- Errno::result(res).map(|_| SigAction { sigaction: oldact })
++ Errno::result(res).map(|_| SigAction { sigaction: oldact.assume_init() })
+ }
+
+ /// Signal management (see [signal(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/signal.html))
+@@ -534,8 +644,7 @@ pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigActi
+ ///
+ /// ```no_run
+ /// # #[macro_use] extern crate lazy_static;
+-/// # extern crate libc;
+-/// # extern crate nix;
++/// # use std::convert::TryFrom;
+ /// # use std::sync::atomic::{AtomicBool, Ordering};
+ /// # use nix::sys::signal::{self, Signal, SigHandler};
+ /// lazy_static! {
+@@ -543,7 +652,7 @@ pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigActi
+ /// }
+ ///
+ /// extern fn handle_sigint(signal: libc::c_int) {
+-/// let signal = Signal::from_c_int(signal).unwrap();
++/// let signal = Signal::try_from(signal).unwrap();
+ /// SIGNALED.store(signal == Signal::SIGINT, Ordering::Relaxed);
+ /// }
+ ///
+@@ -571,6 +680,7 @@ pub unsafe fn signal(signal: Signal, handler: SigHandler) -> Result<SigHandler>
+ SigHandler::SigDfl => libc::signal(signal, libc::SIG_DFL),
+ SigHandler::SigIgn => libc::signal(signal, libc::SIG_IGN),
+ SigHandler::Handler(handler) => libc::signal(signal, handler as libc::sighandler_t),
++ #[cfg(not(target_os = "redox"))]
+ SigHandler::SigAction(_) => return Err(Error::UnsupportedOperation),
+ };
+ Errno::result(res).map(|oldhandler| {
+@@ -582,6 +692,25 @@ pub unsafe fn signal(signal: Signal, handler: SigHandler) -> Result<SigHandler>
+ })
+ }
+
++fn do_pthread_sigmask(how: SigmaskHow,
++ set: Option<&SigSet>,
++ oldset: Option<*mut libc::sigset_t>) -> Result<()> {
++ if set.is_none() && oldset.is_none() {
++ return Ok(())
++ }
++
++ let res = unsafe {
++ // if set or oldset is None, pass in null pointers instead
++ libc::pthread_sigmask(how as libc::c_int,
++ set.map_or_else(ptr::null::<libc::sigset_t>,
++ |s| &s.sigset as *const libc::sigset_t),
++ oldset.unwrap_or(ptr::null_mut())
++ )
++ };
++
++ Errno::result(res).map(drop)
++}
++
+ /// Manages the signal mask (set of blocked signals) for the calling thread.
+ ///
+ /// If the `set` parameter is `Some(..)`, then the signal mask will be updated with the signal set.
+@@ -599,21 +728,9 @@ pub unsafe fn signal(signal: Signal, handler: SigHandler) -> Result<SigHandler>
+ /// or [`sigprocmask`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html) man pages.
+ pub fn pthread_sigmask(how: SigmaskHow,
+ set: Option<&SigSet>,
+- oldset: Option<&mut SigSet>) -> Result<()> {
+- if set.is_none() && oldset.is_none() {
+- return Ok(())
+- }
+-
+- let res = unsafe {
+- // if set or oldset is None, pass in null pointers instead
+- libc::pthread_sigmask(how as libc::c_int,
+- set.map_or_else(ptr::null::<libc::sigset_t>,
+- |s| &s.sigset as *const libc::sigset_t),
+- oldset.map_or_else(ptr::null_mut::<libc::sigset_t>,
+- |os| &mut os.sigset as *mut libc::sigset_t))
+- };
+-
+- Errno::result(res).map(drop)
++ oldset: Option<&mut SigSet>) -> Result<()>
++{
++ do_pthread_sigmask(how, set, oldset.map(|os| &mut os.sigset as *mut _ ))
+ }
+
+ /// Examine and change blocked signals.
+@@ -637,7 +754,7 @@ pub fn sigprocmask(how: SigmaskHow, set: Option<&SigSet>, oldset: Option<&mut Si
+ Errno::result(res).map(drop)
+ }
+
+-pub fn kill<T: Into<Option<Signal>>>(pid: ::unistd::Pid, signal: T) -> Result<()> {
++pub fn kill<T: Into<Option<Signal>>>(pid: Pid, signal: T) -> Result<()> {
+ let res = unsafe { libc::kill(pid.into(),
+ match signal.into() {
+ Some(s) => s as libc::c_int,
+@@ -653,7 +770,8 @@ pub fn kill<T: Into<Option<Signal>>>(pid: ::unistd::Pid, signal: T) -> Result<()
+ /// If `pgrp` less then or equal 1, the behavior is platform-specific.
+ /// If `signal` is `None`, `killpg` will only preform error checking and won't
+ /// send any signal.
+-pub fn killpg<T: Into<Option<Signal>>>(pgrp: ::unistd::Pid, signal: T) -> Result<()> {
++#[cfg(not(target_os = "fuchsia"))]
++pub fn killpg<T: Into<Option<Signal>>>(pgrp: Pid, signal: T) -> Result<()> {
+ let res = unsafe { libc::killpg(pgrp.into(),
+ match signal.into() {
+ Some(s) => s as libc::c_int,
+@@ -702,9 +820,8 @@ pub enum SigevNotify {
+ si_value: libc::intptr_t },
+ }
+
+-#[cfg(not(target_os = "openbsd"))]
++#[cfg(not(any(target_os = "openbsd", target_os = "redox")))]
+ mod sigevent {
+- use libc;
+ use std::mem;
+ use std::ptr;
+ use super::SigevNotify;
+@@ -734,7 +851,10 @@ mod sigevent {
+ /// `SIGEV_SIGNAL`. That field is part of a union that shares space with the
+ /// more genuinely useful `sigev_notify_thread_id`
+ pub fn new(sigev_notify: SigevNotify) -> SigEvent {
+- let mut sev = unsafe { mem::zeroed::<libc::sigevent>()};
++ // NB: This uses MaybeUninit rather than mem::zeroed because libc::sigevent contains a
++ // function pointer on Fuchsia as of https://github.com/rust-lang/libc/commit/2f59370,
++ // and function pointers must not be null.
++ let mut sev = unsafe { mem::MaybeUninit::<libc::sigevent>::zeroed().assume_init() };
+ sev.sigev_notify = match sigev_notify {
+ SigevNotify::SigevNone => libc::SIGEV_NONE,
+ SigevNotify::SigevSignal{..} => libc::SIGEV_SIGNAL,
+@@ -793,6 +913,7 @@ mod sigevent {
+
+ #[cfg(test)]
+ mod tests {
++ #[cfg(not(target_os = "redox"))]
+ use std::thread;
+ use super::*;
+
+@@ -848,6 +969,7 @@ mod tests {
+ }
+
+ #[test]
++ #[cfg(not(target_os = "redox"))]
+ fn test_thread_signal_set_mask() {
+ thread::spawn(|| {
+ let prev_mask = SigSet::thread_get_mask()
+@@ -868,6 +990,7 @@ mod tests {
+ }
+
+ #[test]
++ #[cfg(not(target_os = "redox"))]
+ fn test_thread_signal_block() {
+ thread::spawn(|| {
+ let mut mask = SigSet::empty();
+@@ -880,6 +1003,7 @@ mod tests {
+ }
+
+ #[test]
++ #[cfg(not(target_os = "redox"))]
+ fn test_thread_signal_unblock() {
+ thread::spawn(|| {
+ let mut mask = SigSet::empty();
+@@ -892,6 +1016,7 @@ mod tests {
+ }
+
+ #[test]
++ #[cfg(not(target_os = "redox"))]
+ fn test_thread_signal_swap() {
+ thread::spawn(|| {
+ let mut mask = SigSet::empty();
+@@ -914,8 +1039,8 @@ mod tests {
+ }
+
+ #[test]
++ #[cfg(not(target_os = "redox"))]
+ fn test_sigaction() {
+- use libc;
+ thread::spawn(|| {
+ extern fn test_sigaction_handler(_: libc::c_int) {}
+ extern fn test_sigaction_action(_: libc::c_int,
+@@ -952,6 +1077,7 @@ mod tests {
+ }
+
+ #[test]
++ #[cfg(not(target_os = "redox"))]
+ fn test_sigwait() {
+ thread::spawn(|| {
+ let mut mask = SigSet::empty();
+diff --git a/third_party/rust/nix/src/sys/signalfd.rs b/third_party/rust/nix/src/sys/signalfd.rs
+index 5425a27be9e52..c43b45046f719 100644
+--- a/third_party/rust/nix/src/sys/signalfd.rs
++++ b/third_party/rust/nix/src/sys/signalfd.rs
+@@ -16,10 +16,10 @@
+ //! Please note that signal discarding is not specific to `signalfd`, but also happens with regular
+ //! signal handlers.
+ use libc;
+-use unistd;
+-use {Error, Result};
+-use errno::Errno;
+-pub use sys::signal::{self, SigSet};
++use crate::unistd;
++use crate::{Error, Result};
++use crate::errno::Errno;
++pub use crate::sys::signal::{self, SigSet};
+ pub use libc::signalfd_siginfo as siginfo;
+
+ use std::os::unix::io::{RawFd, AsRawFd};
+@@ -79,7 +79,7 @@ pub fn signalfd(fd: RawFd, mask: &SigSet, flags: SfdFlags) -> Result<RawFd> {
+ /// Err(err) => (), // some error happend
+ /// }
+ /// ```
+-#[derive(Clone, Debug, Eq, Hash, PartialEq)]
++#[derive(Debug, Eq, Hash, PartialEq)]
+ pub struct SignalFd(RawFd);
+
+ impl SignalFd {
+@@ -98,10 +98,15 @@ impl SignalFd {
+ }
+
+ pub fn read_signal(&mut self) -> Result<Option<siginfo>> {
+- let mut buffer: [u8; SIGNALFD_SIGINFO_SIZE] = unsafe { mem::uninitialized() };
+-
+- match unistd::read(self.0, &mut buffer) {
+- Ok(SIGNALFD_SIGINFO_SIZE) => Ok(Some(unsafe { mem::transmute(buffer) })),
++ let mut buffer = mem::MaybeUninit::<[u8; SIGNALFD_SIGINFO_SIZE]>::uninit();
++
++ let res = Errno::result(unsafe {
++ libc::read(self.0,
++ buffer.as_mut_ptr() as *mut libc::c_void,
++ SIGNALFD_SIGINFO_SIZE as libc::size_t)
++ }).map(|r| r as usize);
++ match res {
++ Ok(SIGNALFD_SIGINFO_SIZE) => Ok(Some(unsafe { mem::transmute(buffer.assume_init()) })),
+ Ok(_) => unreachable!("partial read on signalfd"),
+ Err(Error::Sys(Errno::EAGAIN)) => Ok(None),
+ Err(error) => Err(error)
+@@ -111,7 +116,10 @@ impl SignalFd {
+
+ impl Drop for SignalFd {
+ fn drop(&mut self) {
+- let _ = unistd::close(self.0);
++ let e = unistd::close(self.0);
++ if !std::thread::panicking() && e == Err(Error::Sys(Errno::EBADF)) {
++ panic!("Closing an invalid file descriptor!");
++ };
+ }
+ }
+
+diff --git a/third_party/rust/nix/src/sys/socket/addr.rs b/third_party/rust/nix/src/sys/socket/addr.rs
+index ed41441155361..5a2739bd10194 100644
+--- a/third_party/rust/nix/src/sys/socket/addr.rs
++++ b/third_party/rust/nix/src/sys/socket/addr.rs
+@@ -1,20 +1,20 @@
+ use super::sa_family_t;
+-use {Error, Result, NixPath};
+-use errno::Errno;
+-use libc;
++use crate::{Error, Result, NixPath};
++use crate::errno::Errno;
++use memoffset::offset_of;
+ use std::{fmt, mem, net, ptr, slice};
+ use std::ffi::OsStr;
+ use std::hash::{Hash, Hasher};
+ use std::path::Path;
+ use std::os::unix::ffi::OsStrExt;
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+-use ::sys::socket::addr::netlink::NetlinkAddr;
++use crate::sys::socket::addr::netlink::NetlinkAddr;
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+-use ::sys::socket::addr::alg::AlgAddr;
++use crate::sys::socket::addr::alg::AlgAddr;
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ use std::os::unix::io::RawFd;
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+-use ::sys::socket::addr::sys_control::SysControlAddr;
++use crate::sys::socket::addr::sys_control::SysControlAddr;
+ #[cfg(any(target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+@@ -22,9 +22,10 @@ use ::sys::socket::addr::sys_control::SysControlAddr;
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+- target_os = "openbsd"))]
++ target_os = "openbsd",
++ target_os = "fuchsia"))]
+ pub use self::datalink::LinkAddr;
+-#[cfg(target_os = "linux")]
++#[cfg(any(target_os = "android", target_os = "linux"))]
+ pub use self::vsock::VsockAddr;
+
+ /// These constants specify the protocol family to be used
+@@ -42,7 +43,7 @@ pub enum AddressFamily {
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Netlink = libc::AF_NETLINK,
+ /// Low level packet interface (see [`packet(7)`](http://man7.org/linux/man-pages/man7/packet.7.html))
+- #[cfg(any(target_os = "android", target_os = "linux"))]
++ #[cfg(any(target_os = "android", target_os = "linux", target_os = "fuchsia"))]
+ Packet = libc::AF_PACKET,
+ /// KEXT Controls and Notifications
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+@@ -116,7 +117,7 @@ pub enum AddressFamily {
+ Alg = libc::AF_ALG,
+ #[cfg(target_os = "linux")]
+ Nfc = libc::AF_NFC,
+- #[cfg(target_os = "linux")]
++ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Vsock = libc::AF_VSOCK,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+@@ -243,7 +244,7 @@ impl AddressFamily {
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ libc::AF_LINK => Some(AddressFamily::Link),
+- #[cfg(target_os = "linux")]
++ #[cfg(any(target_os = "android", target_os = "linux"))]
+ libc::AF_VSOCK => Some(AddressFamily::Vsock),
+ _ => None
+ }
+@@ -367,6 +368,8 @@ impl IpAddr {
+ /// Create a new IpAddr that contains an IPv6 address.
+ ///
+ /// The result will represent the IP address a:b:c:d:e:f
++ #[allow(clippy::many_single_char_names)]
++ #[allow(clippy::too_many_arguments)]
+ pub fn new_v6(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> IpAddr {
+ IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g, h))
+ }
+@@ -405,15 +408,18 @@ impl fmt::Display for IpAddr {
+ pub struct Ipv4Addr(pub libc::in_addr);
+
+ impl Ipv4Addr {
++ #[allow(clippy::identity_op)] // More readable this way
+ pub fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr {
+- let ip = (((a as u32) << 24) |
+- ((b as u32) << 16) |
+- ((c as u32) << 8) |
+- ((d as u32) << 0)).to_be();
++ let ip = ((u32::from(a) << 24) |
++ (u32::from(b) << 16) |
++ (u32::from(c) << 8) |
++ (u32::from(d) << 0)).to_be();
+
+ Ipv4Addr(libc::in_addr { s_addr: ip })
+ }
+
++ // Use pass by reference for symmetry with Ipv6Addr::from_std
++ #[allow(clippy::trivially_copy_pass_by_ref)]
+ pub fn from_std(std: &net::Ipv4Addr) -> Ipv4Addr {
+ let bits = std.octets();
+ Ipv4Addr::new(bits[0], bits[1], bits[2], bits[3])
+@@ -423,12 +429,12 @@ impl Ipv4Addr {
+ Ipv4Addr(libc::in_addr { s_addr: libc::INADDR_ANY })
+ }
+
+- pub fn octets(&self) -> [u8; 4] {
++ pub fn octets(self) -> [u8; 4] {
+ let bits = u32::from_be(self.0.s_addr);
+ [(bits >> 24) as u8, (bits >> 16) as u8, (bits >> 8) as u8, bits as u8]
+ }
+
+- pub fn to_std(&self) -> net::Ipv4Addr {
++ pub fn to_std(self) -> net::Ipv4Addr {
+ let bits = self.octets();
+ net::Ipv4Addr::new(bits[0], bits[1], bits[2], bits[3])
+ }
+@@ -467,10 +473,10 @@ macro_rules! to_u16_array {
+ }
+
+ impl Ipv6Addr {
++ #[allow(clippy::many_single_char_names)]
++ #[allow(clippy::too_many_arguments)]
+ pub fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr {
+- let mut in6_addr_var: libc::in6_addr = unsafe{mem::uninitialized()};
+- in6_addr_var.s6_addr = to_u8_array!(a,b,c,d,e,f,g,h);
+- Ipv6Addr(in6_addr_var)
++ Ipv6Addr(libc::in6_addr{s6_addr: to_u8_array!(a,b,c,d,e,f,g,h)})
+ }
+
+ pub fn from_std(std: &net::Ipv6Addr) -> Ipv6Addr {
+@@ -555,7 +561,7 @@ impl UnixAddr {
+ ret.sun_path.as_mut_ptr().offset(1) as *mut u8,
+ path.len());
+
+- Ok(UnixAddr(ret, ret.sun_path.len()))
++ Ok(UnixAddr(ret, path.len() + 1))
+ }
+ }
+
+@@ -643,7 +649,7 @@ pub enum SockAddr {
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ Link(LinkAddr),
+- #[cfg(target_os = "linux")]
++ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Vsock(VsockAddr),
+ }
+
+@@ -671,7 +677,7 @@ impl SockAddr {
+ SysControlAddr::from_name(sockfd, name, unit).map(|a| SockAddr::SysControl(a))
+ }
+
+- #[cfg(target_os = "linux")]
++ #[cfg(any(target_os = "android", target_os = "linux"))]
+ pub fn new_vsock(cid: u32, port: u32) -> SockAddr {
+ SockAddr::Vsock(VsockAddr::new(cid, port))
+ }
+@@ -696,7 +702,7 @@ impl SockAddr {
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ SockAddr::Link(..) => AddressFamily::Link,
+- #[cfg(target_os = "linux")]
++ #[cfg(any(target_os = "android", target_os = "linux"))]
+ SockAddr::Vsock(..) => AddressFamily::Vsock,
+ }
+ }
+@@ -709,11 +715,17 @@ impl SockAddr {
+ ///
+ /// Supports only the following address families: Unix, Inet (v4 & v6), Netlink and System.
+ /// Returns None for unsupported families.
+- pub unsafe fn from_libc_sockaddr(addr: *const libc::sockaddr) -> Option<SockAddr> {
++ ///
++ /// # Safety
++ ///
++ /// unsafe because it takes a raw pointer as argument. The caller must
++ /// ensure that the pointer is valid.
++ #[cfg(not(target_os = "fuchsia"))]
++ pub(crate) unsafe fn from_libc_sockaddr(addr: *const libc::sockaddr) -> Option<SockAddr> {
+ if addr.is_null() {
+ None
+ } else {
+- match AddressFamily::from_i32((*addr).sa_family as i32) {
++ match AddressFamily::from_i32(i32::from((*addr).sa_family)) {
+ Some(AddressFamily::Unix) => None,
+ Some(AddressFamily::Inet) => Some(SockAddr::Inet(
+ InetAddr::V4(*(addr as *const libc::sockaddr_in)))),
+@@ -742,7 +754,7 @@ impl SockAddr {
+ Some(SockAddr::Link(ether_addr))
+ }
+ },
+- #[cfg(target_os = "linux")]
++ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Some(AddressFamily::Vsock) => Some(SockAddr::Vsock(
+ VsockAddr(*(addr as *const libc::sockaddr_vm)))),
+ // Other address families are currently not supported and simply yield a None
+@@ -759,28 +771,83 @@ impl SockAddr {
+ /// with the size of the actual data type. sockaddr is commonly used as a proxy for
+ /// a superclass as C doesn't support inheritance, so many functions that take
+ /// a sockaddr * need to take the size of the underlying type as well and then internally cast it back.
+- pub unsafe fn as_ffi_pair(&self) -> (&libc::sockaddr, libc::socklen_t) {
++ pub fn as_ffi_pair(&self) -> (&libc::sockaddr, libc::socklen_t) {
+ match *self {
+- SockAddr::Inet(InetAddr::V4(ref addr)) => (mem::transmute(addr), mem::size_of::<libc::sockaddr_in>() as libc::socklen_t),
+- SockAddr::Inet(InetAddr::V6(ref addr)) => (mem::transmute(addr), mem::size_of::<libc::sockaddr_in6>() as libc::socklen_t),
+- SockAddr::Unix(UnixAddr(ref addr, len)) => (mem::transmute(addr), (len + offset_of!(libc::sockaddr_un, sun_path)) as libc::socklen_t),
++ SockAddr::Inet(InetAddr::V4(ref addr)) => (
++ // This cast is always allowed in C
++ unsafe {
++ &*(addr as *const libc::sockaddr_in as *const libc::sockaddr)
++ },
++ mem::size_of_val(addr) as libc::socklen_t
++ ),
++ SockAddr::Inet(InetAddr::V6(ref addr)) => (
++ // This cast is always allowed in C
++ unsafe {
++ &*(addr as *const libc::sockaddr_in6 as *const libc::sockaddr)
++ },
++ mem::size_of_val(addr) as libc::socklen_t
++ ),
++ SockAddr::Unix(UnixAddr(ref addr, len)) => (
++ // This cast is always allowed in C
++ unsafe {
++ &*(addr as *const libc::sockaddr_un as *const libc::sockaddr)
++ },
++ (len + offset_of!(libc::sockaddr_un, sun_path)) as libc::socklen_t
++ ),
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+- SockAddr::Netlink(NetlinkAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<libc::sockaddr_nl>() as libc::socklen_t),
++ SockAddr::Netlink(NetlinkAddr(ref sa)) => (
++ // This cast is always allowed in C
++ unsafe {
++ &*(sa as *const libc::sockaddr_nl as *const libc::sockaddr)
++ },
++ mem::size_of_val(sa) as libc::socklen_t
++ ),
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+- SockAddr::Alg(AlgAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<libc::sockaddr_alg>() as libc::socklen_t),
++ SockAddr::Alg(AlgAddr(ref sa)) => (
++ // This cast is always allowed in C
++ unsafe {
++ &*(sa as *const libc::sockaddr_alg as *const libc::sockaddr)
++ },
++ mem::size_of_val(sa) as libc::socklen_t
++ ),
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+- SockAddr::SysControl(SysControlAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<libc::sockaddr_ctl>() as libc::socklen_t),
++ SockAddr::SysControl(SysControlAddr(ref sa)) => (
++ // This cast is always allowed in C
++ unsafe {
++ &*(sa as *const libc::sockaddr_ctl as *const libc::sockaddr)
++ },
++ mem::size_of_val(sa) as libc::socklen_t
++
++ ),
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+- SockAddr::Link(LinkAddr(ref ether_addr)) => (mem::transmute(ether_addr), mem::size_of::<libc::sockaddr_ll>() as libc::socklen_t),
++ SockAddr::Link(LinkAddr(ref addr)) => (
++ // This cast is always allowed in C
++ unsafe {
++ &*(addr as *const libc::sockaddr_ll as *const libc::sockaddr)
++ },
++ mem::size_of_val(addr) as libc::socklen_t
++ ),
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+- SockAddr::Link(LinkAddr(ref ether_addr)) => (mem::transmute(ether_addr), mem::size_of::<libc::sockaddr_dl>() as libc::socklen_t),
+- #[cfg(target_os = "linux")]
+- SockAddr::Vsock(VsockAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<libc::sockaddr_vm>() as libc::socklen_t),
++ SockAddr::Link(LinkAddr(ref addr)) => (
++ // This cast is always allowed in C
++ unsafe {
++ &*(addr as *const libc::sockaddr_dl as *const libc::sockaddr)
++ },
++ mem::size_of_val(addr) as libc::socklen_t
++ ),
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ SockAddr::Vsock(VsockAddr(ref sa)) => (
++ // This cast is always allowed in C
++ unsafe {
++ &*(sa as *const libc::sockaddr_vm as *const libc::sockaddr)
++ },
++ mem::size_of_val(sa) as libc::socklen_t
++ ),
+ }
+ }
+ }
+@@ -805,7 +872,7 @@ impl fmt::Display for SockAddr {
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ SockAddr::Link(ref ether_addr) => ether_addr.fmt(f),
+- #[cfg(target_os = "linux")]
++ #[cfg(any(target_os = "android", target_os = "linux"))]
+ SockAddr::Vsock(ref svm) => svm.fmt(f),
+ }
+ }
+@@ -813,7 +880,7 @@ impl fmt::Display for SockAddr {
+
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ pub mod netlink {
+- use ::sys::socket::addr::AddressFamily;
++ use crate::sys::socket::addr::AddressFamily;
+ use libc::{sa_family_t, sockaddr_nl};
+ use std::{fmt, mem};
+
+@@ -911,11 +978,11 @@ pub mod alg {
+
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ pub mod sys_control {
+- use ::sys::socket::addr::AddressFamily;
++ use crate::sys::socket::addr::AddressFamily;
+ use libc::{self, c_uchar};
+ use std::{fmt, mem};
+ use std::os::unix::io::RawFd;
+- use {Errno, Error, Result};
++ use crate::{Errno, Error, Result};
+
+ // FIXME: Move type into `libc`
+ #[repr(C)]
+@@ -957,7 +1024,7 @@ pub mod sys_control {
+
+ let mut ctl_name = [0; MAX_KCTL_NAME];
+ ctl_name[..name.len()].clone_from_slice(name.as_bytes());
+- let mut info = ctl_ioc_info { ctl_id: 0, ctl_name: ctl_name };
++ let mut info = ctl_ioc_info { ctl_id: 0, ctl_name };
+
+ unsafe { ctl_info(sockfd, &mut info)?; }
+
+@@ -981,9 +1048,9 @@ pub mod sys_control {
+ }
+
+
+-#[cfg(any(target_os = "android", target_os = "linux"))]
++#[cfg(any(target_os = "android", target_os = "linux", target_os = "fuchsia"))]
+ mod datalink {
+- use super::{libc, fmt, AddressFamily};
++ use super::{fmt, AddressFamily};
+
+ /// Hardware Address
+ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+@@ -1023,14 +1090,14 @@ mod datalink {
+
+ /// Physical-layer address (MAC)
+ pub fn addr(&self) -> [u8; 6] {
+- let a = self.0.sll_addr[0] as u8;
+- let b = self.0.sll_addr[1] as u8;
+- let c = self.0.sll_addr[2] as u8;
+- let d = self.0.sll_addr[3] as u8;
+- let e = self.0.sll_addr[4] as u8;
+- let f = self.0.sll_addr[5] as u8;
+-
+- [a, b, c, d, e, f]
++ [
++ self.0.sll_addr[0] as u8,
++ self.0.sll_addr[1] as u8,
++ self.0.sll_addr[2] as u8,
++ self.0.sll_addr[3] as u8,
++ self.0.sll_addr[4] as u8,
++ self.0.sll_addr[5] as u8,
++ ]
+ }
+ }
+
+@@ -1055,7 +1122,7 @@ mod datalink {
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ mod datalink {
+- use super::{libc, fmt, AddressFamily};
++ use super::{fmt, AddressFamily};
+
+ /// Hardware Address
+ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+@@ -1069,7 +1136,7 @@ mod datalink {
+
+ /// always == AF_LINK
+ pub fn family(&self) -> AddressFamily {
+- assert_eq!(self.0.sdl_family as i32, libc::AF_LINK);
++ assert_eq!(i32::from(self.0.sdl_family), libc::AF_LINK);
+ AddressFamily::Link
+ }
+
+@@ -1105,11 +1172,7 @@ mod datalink {
+ let alen = self.alen();
+ let data_len = self.0.sdl_data.len();
+
+- if alen > 0 && nlen + alen < data_len {
+- false
+- } else {
+- true
+- }
++ alen == 0 || nlen + alen >= data_len
+ }
+
+ /// Physical-layer address (MAC)
+@@ -1119,14 +1182,14 @@ mod datalink {
+
+ assert!(!self.is_empty());
+
+- let a = data[nlen] as u8;
+- let b = data[nlen + 1] as u8;
+- let c = data[nlen + 2] as u8;
+- let d = data[nlen + 3] as u8;
+- let e = data[nlen + 4] as u8;
+- let f = data[nlen + 5] as u8;
+-
+- [a, b, c, d, e, f]
++ [
++ data[nlen] as u8,
++ data[nlen + 1] as u8,
++ data[nlen + 2] as u8,
++ data[nlen + 3] as u8,
++ data[nlen + 4] as u8,
++ data[nlen + 5] as u8,
++ ]
+ }
+ }
+
+@@ -1144,9 +1207,9 @@ mod datalink {
+ }
+ }
+
+-#[cfg(target_os = "linux")]
++#[cfg(any(target_os = "android", target_os = "linux"))]
+ pub mod vsock {
+- use ::sys::socket::addr::AddressFamily;
++ use crate::sys::socket::addr::AddressFamily;
+ use libc::{sa_family_t, sockaddr_vm};
+ use std::{fmt, mem};
+ use std::hash::{Hash, Hasher};
+@@ -1269,7 +1332,7 @@ mod tests {
+ let addr = UnixAddr::new_abstract(name.as_bytes()).unwrap();
+
+ let sun_path1 = addr.sun_path();
+- let sun_path2 = [0u8, 110, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, 116, 101, 115, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
++ let sun_path2 = [0u8, 110, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, 116, 101, 115, 116];
+ assert_eq!(sun_path1.len(), sun_path2.len());
+ for i in 0..sun_path1.len() {
+ assert_eq!(sun_path1[i], sun_path2[i]);
+diff --git a/third_party/rust/nix/src/sys/socket/mod.rs b/third_party/rust/nix/src/sys/socket/mod.rs
+index 1c12c5f851734..631d281ed16af 100644
+--- a/third_party/rust/nix/src/sys/socket/mod.rs
++++ b/third_party/rust/nix/src/sys/socket/mod.rs
+@@ -1,14 +1,15 @@
+ //! Socket interface functions
+ //!
+ //! [Further reading](http://man7.org/linux/man-pages/man7/socket.7.html)
+-use {Error, Result};
+-use errno::Errno;
++use cfg_if::cfg_if;
++use crate::{Error, Result, errno::Errno};
+ use libc::{self, c_void, c_int, iovec, socklen_t, size_t,
+ CMSG_FIRSTHDR, CMSG_NXTHDR, CMSG_DATA, CMSG_LEN};
++use memoffset::offset_of;
+ use std::{mem, ptr, slice};
+ use std::os::unix::io::RawFd;
+-use sys::time::TimeVal;
+-use sys::uio::IoVec;
++use crate::sys::time::TimeVal;
++use crate::sys::uio::IoVec;
+
+ mod addr;
+ pub mod sockopt;
+@@ -30,11 +31,11 @@ pub use self::addr::{
+ LinkAddr,
+ };
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+-pub use ::sys::socket::addr::netlink::NetlinkAddr;
++pub use crate::sys::socket::addr::netlink::NetlinkAddr;
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+-pub use sys::socket::addr::alg::AlgAddr;
+-#[cfg(target_os = "linux")]
+-pub use sys::socket::addr::vsock::VsockAddr;
++pub use crate::sys::socket::addr::alg::AlgAddr;
++#[cfg(any(target_os = "android", target_os = "linux"))]
++pub use crate::sys::socket::addr::vsock::VsockAddr;
+
+ pub use libc::{
+ cmsghdr,
+@@ -92,6 +93,64 @@ pub enum SockProtocol {
+ /// ([ref](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/control/control.html))
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ KextControl = libc::SYSPROTO_CONTROL,
++ /// Receives routing and link updates and may be used to modify the routing tables (both IPv4 and IPv6), IP addresses, link
++ // parameters, neighbor setups, queueing disciplines, traffic classes and packet classifiers
++ /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ NetlinkRoute = libc::NETLINK_ROUTE,
++ /// Reserved for user-mode socket protocols
++ /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ NetlinkUserSock = libc::NETLINK_USERSOCK,
++ /// Query information about sockets of various protocol families from the kernel
++ /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ NetlinkSockDiag = libc::NETLINK_SOCK_DIAG,
++ /// SELinux event notifications.
++ /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ NetlinkSELinux = libc::NETLINK_SELINUX,
++ /// Open-iSCSI
++ /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ NetlinkISCSI = libc::NETLINK_ISCSI,
++ /// Auditing
++ /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ NetlinkAudit = libc::NETLINK_AUDIT,
++ /// Access to FIB lookup from user space
++ /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ NetlinkFIBLookup = libc::NETLINK_FIB_LOOKUP,
++ /// Netfilter subsystem
++ /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ NetlinkNetFilter = libc::NETLINK_NETFILTER,
++ /// SCSI Transports
++ /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ NetlinkSCSITransport = libc::NETLINK_SCSITRANSPORT,
++ /// Infiniband RDMA
++ /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ NetlinkRDMA = libc::NETLINK_RDMA,
++ /// Transport IPv6 packets from netfilter to user space. Used by ip6_queue kernel module.
++ /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ NetlinkIPv6Firewall = libc::NETLINK_IP6_FW,
++ /// DECnet routing messages
++ /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ NetlinkDECNetRoutingMessage = libc::NETLINK_DNRTMSG,
++ /// Kernel messages to user space
++ /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ NetlinkKObjectUEvent = libc::NETLINK_KOBJECT_UEVENT,
++ /// Netlink interface to request information about ciphers registered with the kernel crypto API as well as allow
++ /// configuration of the kernel crypto API.
++ /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ NetlinkCrypto = libc::NETLINK_CRYPTO,
+ }
+
+ libc_bitflags!{
+@@ -189,12 +248,22 @@ cfg_if! {
+ if #[cfg(any(target_os = "android", target_os = "linux"))] {
+ /// Unix credentials of the sending process.
+ ///
+- /// This struct is used with the `SO_PEERCRED` ancillary message for UNIX sockets.
+- #[repr(C)]
++ /// This struct is used with the `SO_PEERCRED` ancillary message
++ /// and the `SCM_CREDENTIALS` control message for UNIX sockets.
++ #[repr(transparent)]
+ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
+ pub struct UnixCredentials(libc::ucred);
+
+ impl UnixCredentials {
++ /// Creates a new instance with the credentials of the current process
++ pub fn new() -> Self {
++ UnixCredentials(libc::ucred {
++ pid: crate::unistd::getpid().as_raw(),
++ uid: crate::unistd::getuid().as_raw(),
++ gid: crate::unistd::getgid().as_raw(),
++ })
++ }
++
+ /// Returns the process identifier
+ pub fn pid(&self) -> libc::pid_t {
+ self.0.pid
+@@ -211,6 +280,12 @@ cfg_if! {
+ }
+ }
+
++ impl Default for UnixCredentials {
++ fn default() -> Self {
++ Self::new()
++ }
++ }
++
+ impl From<libc::ucred> for UnixCredentials {
+ fn from(cred: libc::ucred) -> Self {
+ UnixCredentials(cred)
+@@ -222,13 +297,53 @@ cfg_if! {
+ self.0
+ }
+ }
++ } else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] {
++ /// Unix credentials of the sending process.
++ ///
++ /// This struct is used with the `SCM_CREDS` ancillary message for UNIX sockets.
++ #[repr(transparent)]
++ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
++ pub struct UnixCredentials(libc::cmsgcred);
++
++ impl UnixCredentials {
++ /// Returns the process identifier
++ pub fn pid(&self) -> libc::pid_t {
++ self.0.cmcred_pid
++ }
++
++ /// Returns the real user identifier
++ pub fn uid(&self) -> libc::uid_t {
++ self.0.cmcred_uid
++ }
++
++ /// Returns the effective user identifier
++ pub fn euid(&self) -> libc::uid_t {
++ self.0.cmcred_euid
++ }
++
++ /// Returns the real group identifier
++ pub fn gid(&self) -> libc::gid_t {
++ self.0.cmcred_gid
++ }
++
++ /// Returns a list group identifiers (the first one being the effective GID)
++ pub fn groups(&self) -> &[libc::gid_t] {
++ unsafe { slice::from_raw_parts(self.0.cmcred_groups.as_ptr() as *const libc::gid_t, self.0.cmcred_ngroups as _) }
++ }
++ }
++
++ impl From<libc::cmsgcred> for UnixCredentials {
++ fn from(cred: libc::cmsgcred) -> Self {
++ UnixCredentials(cred)
++ }
++ }
+ }
+ }
+
+ /// Request for multicast socket operations
+ ///
+ /// This is a wrapper type around `ip_mreq`.
+-#[repr(C)]
++#[repr(transparent)]
+ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
+ pub struct IpMembershipRequest(libc::ip_mreq);
+
+@@ -247,7 +362,7 @@ impl IpMembershipRequest {
+ /// Request for ipv6 multicast socket operations
+ ///
+ /// This is a wrapper type around `ipv6_mreq`.
+-#[repr(C)]
++#[repr(transparent)]
+ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
+ pub struct Ipv6MembershipRequest(libc::ipv6_mreq);
+
+@@ -261,21 +376,6 @@ impl Ipv6MembershipRequest {
+ }
+ }
+
+-cfg_if! {
+- // Darwin and DragonFly BSD always align struct cmsghdr to 32-bit only.
+- if #[cfg(any(target_os = "dragonfly", target_os = "ios", target_os = "macos"))] {
+- type align_of_cmsg_data = u32;
+- } else {
+- type align_of_cmsg_data = size_t;
+- }
+-}
+-
+-/// A type that can be used to store ancillary data received by
+-/// [`recvmsg`](fn.recvmsg.html)
+-pub trait CmsgBuffer {
+- fn as_bytes_mut(&mut self) -> &mut [u8];
+-}
+-
+ /// Create a buffer large enough for storing some control messages as returned
+ /// by [`recvmsg`](fn.recvmsg.html).
+ ///
+@@ -311,61 +411,11 @@ macro_rules! cmsg_space {
+ CMSG_SPACE(mem::size_of::<$x>() as c_uint)
+ } as usize;
+ )*
+- let mut v = Vec::<u8>::with_capacity(space);
+- // safe because any bit pattern is a valid u8
+- unsafe {v.set_len(space)};
+- v
++ Vec::<u8>::with_capacity(space)
+ }
+ }
+ }
+
+-/// A structure used to make room in a cmsghdr passed to recvmsg. The
+-/// size and alignment match that of a cmsghdr followed by a T, but the
+-/// fields are not accessible, as the actual types will change on a call
+-/// to recvmsg.
+-///
+-/// To make room for multiple messages, nest the type parameter with
+-/// tuples:
+-///
+-/// ```
+-/// use std::os::unix::io::RawFd;
+-/// use nix::sys::socket::CmsgSpace;
+-/// let cmsg: CmsgSpace<([RawFd; 3], CmsgSpace<[RawFd; 2]>)> = CmsgSpace::new();
+-/// ```
+-#[repr(C)]
+-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+-pub struct CmsgSpace<T> {
+- _hdr: cmsghdr,
+- _pad: [align_of_cmsg_data; 0],
+- _data: T,
+-}
+-
+-impl<T> CmsgSpace<T> {
+- /// Create a CmsgSpace<T>. The structure is used only for space, so
+- /// the fields are uninitialized.
+- #[deprecated( since="0.14.0", note="Use the cmsg_space! macro instead")]
+- pub fn new() -> Self {
+- // Safe because the fields themselves aren't accessible.
+- unsafe { mem::uninitialized() }
+- }
+-}
+-
+-impl<T> CmsgBuffer for CmsgSpace<T> {
+- fn as_bytes_mut(&mut self) -> &mut [u8] {
+- // Safe because nothing ever attempts to access CmsgSpace's fields
+- unsafe {
+- slice::from_raw_parts_mut(self as *mut CmsgSpace<T> as *mut u8,
+- mem::size_of::<Self>())
+- }
+- }
+-}
+-
+-impl CmsgBuffer for Vec<u8> {
+- fn as_bytes_mut(&mut self) -> &mut [u8] {
+- &mut self[..]
+- }
+-}
+-
+ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
+ pub struct RecvMsg<'a> {
+ pub bytes: usize,
+@@ -433,7 +483,11 @@ pub enum ControlMessageOwned {
+ /// Received version of
+ /// [`ControlMessage::ScmCredentials`][#enum.ControlMessage.html#variant.ScmCredentials]
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+- ScmCredentials(libc::ucred),
++ ScmCredentials(UnixCredentials),
++ /// Received version of
++ /// [`ControlMessage::ScmCreds`][#enum.ControlMessage.html#variant.ScmCreds]
++ #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++ ScmCreds(UnixCredentials),
+ /// A message of type `SCM_TIMESTAMP`, containing the time the
+ /// packet was received by the kernel.
+ ///
+@@ -442,10 +496,6 @@ pub enum ControlMessageOwned {
+ ///
+ /// # Examples
+ ///
+- // Disable this test on FreeBSD i386
+- // https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=222039
+- #[cfg_attr(not(all(target_os = "freebsd", target_arch = "x86")), doc = " ```")]
+- #[cfg_attr(all(target_os = "freebsd", target_arch = "x86"), doc = " ```no_run")]
+ /// # #[macro_use] extern crate nix;
+ /// # use nix::sys::socket::*;
+ /// # use nix::sys::uio::IoVec;
+@@ -528,6 +578,18 @@ pub enum ControlMessageOwned {
+ target_os = "openbsd",
+ ))]
+ Ipv4RecvDstAddr(libc::in_addr),
++
++ /// UDP Generic Receive Offload (GRO) allows receiving multiple UDP
++ /// packets from a single sender.
++ /// Fixed-size payloads are following one by one in a receive buffer.
++ /// This Control Message indicates the size of all smaller packets,
++ /// except, maybe, the last one.
++ ///
++ /// `UdpGroSegment` socket option should be enabled on a socket
++ /// to allow receiving GRO packets.
++ #[cfg(target_os = "linux")]
++ UdpGroSegments(u16),
++
+ /// Catch-all variant for unimplemented cmsg types.
+ #[doc(hidden)]
+ Unknown(UnknownCmsg),
+@@ -540,9 +602,9 @@ impl ControlMessageOwned {
+ /// specified in the header. Normally, the kernel ensures that this is the
+ /// case. "Correct" in this case includes correct length, alignment and
+ /// actual content.
+- ///
+- /// Returns `None` if the data may be unaligned. In that case use
+- /// `ControlMessageOwned::decode_from`.
++ // Clippy complains about the pointer alignment of `p`, not understanding
++ // that it's being fed to a function that can handle that.
++ #[allow(clippy::cast_ptr_alignment)]
+ unsafe fn decode_from(header: &cmsghdr) -> ControlMessageOwned
+ {
+ let p = CMSG_DATA(header);
+@@ -553,16 +615,20 @@ impl ControlMessageOwned {
+ let n = len / mem::size_of::<RawFd>();
+ let mut fds = Vec::with_capacity(n);
+ for i in 0..n {
+- let fdp = (p as *const RawFd).offset(i as isize);
++ let fdp = (p as *const RawFd).add(i);
+ fds.push(ptr::read_unaligned(fdp));
+ }
+- let cmo = ControlMessageOwned::ScmRights(fds);
+- cmo
++ ControlMessageOwned::ScmRights(fds)
+ },
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ (libc::SOL_SOCKET, libc::SCM_CREDENTIALS) => {
+ let cred: libc::ucred = ptr::read_unaligned(p as *const _);
+- ControlMessageOwned::ScmCredentials(cred)
++ ControlMessageOwned::ScmCredentials(cred.into())
++ }
++ #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++ (libc::SOL_SOCKET, libc::SCM_CREDS) => {
++ let cred: libc::cmsgcred = ptr::read_unaligned(p as *const _);
++ ControlMessageOwned::ScmCreds(cred.into())
+ }
+ (libc::SOL_SOCKET, libc::SCM_TIMESTAMP) => {
+ let tv: libc::timeval = ptr::read_unaligned(p as *const _);
+@@ -612,6 +678,11 @@ impl ControlMessageOwned {
+ let dl = ptr::read_unaligned(p as *const libc::in_addr);
+ ControlMessageOwned::Ipv4RecvDstAddr(dl)
+ },
++ #[cfg(target_os = "linux")]
++ (libc::SOL_UDP, libc::UDP_GRO) => {
++ let gso_size: u16 = ptr::read_unaligned(p as *const _);
++ ControlMessageOwned::UdpGroSegments(gso_size)
++ },
+ (_, _) => {
+ let sl = slice::from_raw_parts(p, len);
+ let ucmsg = UnknownCmsg(*header, Vec::<u8>::from(&sl[..]));
+@@ -650,10 +721,22 @@ pub enum ControlMessage<'a> {
+ ///
+ /// For further information, please refer to the
+ /// [`unix(7)`](http://man7.org/linux/man-pages/man7/unix.7.html) man page.
+- // FIXME: When `#[repr(transparent)]` is stable, use it on `UnixCredentials`
+- // and put that in here instead of a raw ucred.
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+- ScmCredentials(&'a libc::ucred),
++ ScmCredentials(&'a UnixCredentials),
++ /// A message of type `SCM_CREDS`, containing the pid, uid, euid, gid and groups of
++ /// a process connected to the socket.
++ ///
++ /// This is similar to the socket options `LOCAL_CREDS` and `LOCAL_PEERCRED`, but
++ /// requires a process to explicitly send its credentials.
++ ///
++ /// Credentials are always overwritten by the kernel, so this variant does have
++ /// any data, unlike the receive-side
++ /// [`ControlMessageOwned::ScmCreds`][#enum.ControlMessageOwned.html#variant.ScmCreds].
++ ///
++ /// For further information, please refer to the
++ /// [`unix(4)`](https://www.freebsd.org/cgi/man.cgi?query=unix) man page.
++ #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++ ScmCreds,
+
+ /// Set IV for `AF_ALG` crypto API.
+ ///
+@@ -685,6 +768,39 @@ pub enum ControlMessage<'a> {
+ ))]
+ AlgSetAeadAssoclen(&'a u32),
+
++ /// UDP GSO makes it possible for applications to generate network packets
++ /// for a virtual MTU much greater than the real one.
++ /// The length of the send data no longer matches the expected length on
++ /// the wire.
++ /// The size of the datagram payload as it should appear on the wire may be
++ /// passed through this control message.
++ /// Send buffer should consist of multiple fixed-size wire payloads
++ /// following one by one, and the last, possibly smaller one.
++ #[cfg(target_os = "linux")]
++ UdpGsoSegments(&'a u16),
++
++ /// Configure the sending addressing and interface for v4
++ ///
++ /// For further information, please refer to the
++ /// [`ip(7)`](http://man7.org/linux/man-pages/man7/ip.7.html) man page.
++ #[cfg(any(target_os = "linux",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "android",
++ target_os = "ios",))]
++ Ipv4PacketInfo(&'a libc::in_pktinfo),
++
++ /// Configure the sending addressing and interface for v6
++ ///
++ /// For further information, please refer to the
++ /// [`ipv6(7)`](http://man7.org/linux/man-pages/man7/ipv6.7.html) man page.
++ #[cfg(any(target_os = "linux",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "freebsd",
++ target_os = "android",
++ target_os = "ios",))]
++ Ipv6PacketInfo(&'a libc::in6_pktinfo),
+ }
+
+ // An opaque structure used to prevent cmsghdr from being a public type
+@@ -715,35 +831,66 @@ impl<'a> ControlMessage<'a> {
+
+ /// Return a reference to the payload data as a byte pointer
+ fn copy_to_cmsg_data(&self, cmsg_data: *mut u8) {
+- let data_ptr = match self {
+- &ControlMessage::ScmRights(fds) => {
++ let data_ptr = match *self {
++ ControlMessage::ScmRights(fds) => {
+ fds as *const _ as *const u8
+ },
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+- &ControlMessage::ScmCredentials(creds) => {
+- creds as *const libc::ucred as *const u8
++ ControlMessage::ScmCredentials(creds) => {
++ &creds.0 as *const libc::ucred as *const u8
++ }
++ #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++ ControlMessage::ScmCreds => {
++ // The kernel overwrites the data, we just zero it
++ // to make sure it's not uninitialized memory
++ unsafe { ptr::write_bytes(cmsg_data, 0, self.len()) };
++ return
+ }
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+- &ControlMessage::AlgSetIv(iv) => {
++ ControlMessage::AlgSetIv(iv) => {
++ #[allow(deprecated)] // https://github.com/rust-lang/libc/issues/1501
++ let af_alg_iv = libc::af_alg_iv {
++ ivlen: iv.len() as u32,
++ iv: [0u8; 0],
++ };
++
++ let size = mem::size_of_val(&af_alg_iv);
++
+ unsafe {
+- let alg_iv = cmsg_data as *mut libc::af_alg_iv;
+- (*alg_iv).ivlen = iv.len() as u32;
++ ptr::copy_nonoverlapping(
++ &af_alg_iv as *const _ as *const u8,
++ cmsg_data,
++ size,
++ );
+ ptr::copy_nonoverlapping(
+ iv.as_ptr(),
+- (*alg_iv).iv.as_mut_ptr(),
++ cmsg_data.add(size),
+ iv.len()
+ );
+ };
++
+ return
+ },
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+- &ControlMessage::AlgSetOp(op) => {
++ ControlMessage::AlgSetOp(op) => {
+ op as *const _ as *const u8
+ },
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+- &ControlMessage::AlgSetAeadAssoclen(len) => {
++ ControlMessage::AlgSetAeadAssoclen(len) => {
+ len as *const _ as *const u8
+ },
++ #[cfg(target_os = "linux")]
++ ControlMessage::UdpGsoSegments(gso_size) => {
++ gso_size as *const _ as *const u8
++ },
++ #[cfg(any(target_os = "linux", target_os = "macos",
++ target_os = "netbsd", target_os = "android",
++ target_os = "ios",))]
++ ControlMessage::Ipv4PacketInfo(info) => info as *const _ as *const u8,
++ #[cfg(any(target_os = "linux", target_os = "macos",
++ target_os = "netbsd", target_os = "freebsd",
++ target_os = "android", target_os = "ios",))]
++ ControlMessage::Ipv6PacketInfo(info) => info as *const _ as *const u8,
+ };
+ unsafe {
+ ptr::copy_nonoverlapping(
+@@ -756,60 +903,101 @@ impl<'a> ControlMessage<'a> {
+
+ /// The size of the payload, excluding its cmsghdr
+ fn len(&self) -> usize {
+- match self {
+- &ControlMessage::ScmRights(fds) => {
++ match *self {
++ ControlMessage::ScmRights(fds) => {
+ mem::size_of_val(fds)
+ },
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+- &ControlMessage::ScmCredentials(creds) => {
++ ControlMessage::ScmCredentials(creds) => {
+ mem::size_of_val(creds)
+ }
++ #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++ ControlMessage::ScmCreds => {
++ mem::size_of::<libc::cmsgcred>()
++ }
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+- &ControlMessage::AlgSetIv(iv) => {
+- mem::size_of::<libc::af_alg_iv>() + iv.len()
++ ControlMessage::AlgSetIv(iv) => {
++ mem::size_of_val(&iv) + iv.len()
+ },
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+- &ControlMessage::AlgSetOp(op) => {
++ ControlMessage::AlgSetOp(op) => {
+ mem::size_of_val(op)
+ },
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+- &ControlMessage::AlgSetAeadAssoclen(len) => {
++ ControlMessage::AlgSetAeadAssoclen(len) => {
+ mem::size_of_val(len)
+ },
++ #[cfg(target_os = "linux")]
++ ControlMessage::UdpGsoSegments(gso_size) => {
++ mem::size_of_val(gso_size)
++ },
++ #[cfg(any(target_os = "linux", target_os = "macos",
++ target_os = "netbsd", target_os = "android",
++ target_os = "ios",))]
++ ControlMessage::Ipv4PacketInfo(info) => mem::size_of_val(info),
++ #[cfg(any(target_os = "linux", target_os = "macos",
++ target_os = "netbsd", target_os = "freebsd",
++ target_os = "android", target_os = "ios",))]
++ ControlMessage::Ipv6PacketInfo(info) => mem::size_of_val(info),
+ }
+ }
+
+ /// Returns the value to put into the `cmsg_level` field of the header.
+ fn cmsg_level(&self) -> libc::c_int {
+- match self {
+- &ControlMessage::ScmRights(_) => libc::SOL_SOCKET,
++ match *self {
++ ControlMessage::ScmRights(_) => libc::SOL_SOCKET,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+- &ControlMessage::ScmCredentials(_) => libc::SOL_SOCKET,
++ ControlMessage::ScmCredentials(_) => libc::SOL_SOCKET,
++ #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++ ControlMessage::ScmCreds => libc::SOL_SOCKET,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+- &ControlMessage::AlgSetIv(_) | &ControlMessage::AlgSetOp(_) | &ControlMessage::AlgSetAeadAssoclen(_) => {
+- libc::SOL_ALG
+- },
++ ControlMessage::AlgSetIv(_) | ControlMessage::AlgSetOp(_) |
++ ControlMessage::AlgSetAeadAssoclen(_) => libc::SOL_ALG,
++ #[cfg(target_os = "linux")]
++ ControlMessage::UdpGsoSegments(_) => libc::SOL_UDP,
++ #[cfg(any(target_os = "linux", target_os = "macos",
++ target_os = "netbsd", target_os = "android",
++ target_os = "ios",))]
++ ControlMessage::Ipv4PacketInfo(_) => libc::IPPROTO_IP,
++ #[cfg(any(target_os = "linux", target_os = "macos",
++ target_os = "netbsd", target_os = "freebsd",
++ target_os = "android", target_os = "ios",))]
++ ControlMessage::Ipv6PacketInfo(_) => libc::IPPROTO_IPV6,
+ }
+ }
+
+ /// Returns the value to put into the `cmsg_type` field of the header.
+ fn cmsg_type(&self) -> libc::c_int {
+- match self {
+- &ControlMessage::ScmRights(_) => libc::SCM_RIGHTS,
++ match *self {
++ ControlMessage::ScmRights(_) => libc::SCM_RIGHTS,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+- &ControlMessage::ScmCredentials(_) => libc::SCM_CREDENTIALS,
++ ControlMessage::ScmCredentials(_) => libc::SCM_CREDENTIALS,
++ #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++ ControlMessage::ScmCreds => libc::SCM_CREDS,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+- &ControlMessage::AlgSetIv(_) => {
++ ControlMessage::AlgSetIv(_) => {
+ libc::ALG_SET_IV
+ },
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+- &ControlMessage::AlgSetOp(_) => {
++ ControlMessage::AlgSetOp(_) => {
+ libc::ALG_SET_OP
+ },
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+- &ControlMessage::AlgSetAeadAssoclen(_) => {
++ ControlMessage::AlgSetAeadAssoclen(_) => {
+ libc::ALG_SET_AEAD_ASSOCLEN
+ },
++ #[cfg(target_os = "linux")]
++ ControlMessage::UdpGsoSegments(_) => {
++ libc::UDP_SEGMENT
++ },
++ #[cfg(any(target_os = "linux", target_os = "macos",
++ target_os = "netbsd", target_os = "android",
++ target_os = "ios",))]
++ ControlMessage::Ipv4PacketInfo(_) => libc::IP_PKTINFO,
++ #[cfg(any(target_os = "linux", target_os = "macos",
++ target_os = "netbsd", target_os = "freebsd",
++ target_os = "android", target_os = "ios",))]
++ ControlMessage::Ipv6PacketInfo(_) => libc::IPV6_PKTINFO,
+ }
+ }
+
+@@ -836,12 +1024,303 @@ pub fn sendmsg(fd: RawFd, iov: &[IoVec<&[u8]>], cmsgs: &[ControlMessage],
+
+ // First size the buffer needed to hold the cmsgs. It must be zeroed,
+ // because subsequent code will not clear the padding bytes.
+- let cmsg_buffer = vec![0u8; capacity];
++ let mut cmsg_buffer = vec![0u8; capacity];
++
++ let mhdr = pack_mhdr_to_send(&mut cmsg_buffer[..], &iov, &cmsgs, addr);
++
++ let ret = unsafe { libc::sendmsg(fd, &mhdr, flags.bits()) };
++
++ Errno::result(ret).map(|r| r as usize)
++}
++
++#[cfg(any(
++ target_os = "linux",
++ target_os = "android",
++ target_os = "freebsd",
++ target_os = "netbsd",
++))]
++#[derive(Debug)]
++pub struct SendMmsgData<'a, I, C>
++ where
++ I: AsRef<[IoVec<&'a [u8]>]>,
++ C: AsRef<[ControlMessage<'a>]>
++{
++ pub iov: I,
++ pub cmsgs: C,
++ pub addr: Option<SockAddr>,
++ pub _lt: std::marker::PhantomData<&'a I>,
++}
++
++/// An extension of `sendmsg` that allows the caller to transmit multiple
++/// messages on a socket using a single system call. This has performance
++/// benefits for some applications.
++///
++/// Allocations are performed for cmsgs and to build `msghdr` buffer
++///
++/// # Arguments
++///
++/// * `fd`: Socket file descriptor
++/// * `data`: Struct that implements `IntoIterator` with `SendMmsgData` items
++/// * `flags`: Optional flags passed directly to the operating system.
++///
++/// # Returns
++/// `Vec` with numbers of sent bytes on each sent message.
++///
++/// # References
++/// [`sendmsg`](fn.sendmsg.html)
++#[cfg(any(
++ target_os = "linux",
++ target_os = "android",
++ target_os = "freebsd",
++ target_os = "netbsd",
++))]
++pub fn sendmmsg<'a, I, C>(
++ fd: RawFd,
++ data: impl std::iter::IntoIterator<Item=&'a SendMmsgData<'a, I, C>>,
++ flags: MsgFlags
++) -> Result<Vec<usize>>
++ where
++ I: AsRef<[IoVec<&'a [u8]>]> + 'a,
++ C: AsRef<[ControlMessage<'a>]> + 'a,
++{
++ let iter = data.into_iter();
++
++ let size_hint = iter.size_hint();
++ let reserve_items = size_hint.1.unwrap_or(size_hint.0);
++
++ let mut output = Vec::<libc::mmsghdr>::with_capacity(reserve_items);
++
++ let mut cmsgs_buffer = vec![0u8; 0];
++
++ for d in iter {
++ let cmsgs_start = cmsgs_buffer.len();
++ let cmsgs_required_capacity: usize = d.cmsgs.as_ref().iter().map(|c| c.space()).sum();
++ let cmsgs_buffer_need_capacity = cmsgs_start + cmsgs_required_capacity;
++ cmsgs_buffer.resize(cmsgs_buffer_need_capacity, 0);
++
++ output.push(libc::mmsghdr {
++ msg_hdr: pack_mhdr_to_send(
++ &mut cmsgs_buffer[cmsgs_start..],
++ &d.iov,
++ &d.cmsgs,
++ d.addr.as_ref()
++ ),
++ msg_len: 0,
++ });
++ };
++
++ let ret = unsafe { libc::sendmmsg(fd, output.as_mut_ptr(), output.len() as _, flags.bits() as _) };
++
++ let sent_messages = Errno::result(ret)? as usize;
++ let mut sent_bytes = Vec::with_capacity(sent_messages);
++
++ for item in &output {
++ sent_bytes.push(item.msg_len as usize);
++ }
++
++ Ok(sent_bytes)
++}
++
++
++#[cfg(any(
++ target_os = "linux",
++ target_os = "android",
++ target_os = "freebsd",
++ target_os = "netbsd",
++))]
++#[derive(Debug)]
++pub struct RecvMmsgData<'a, I>
++ where
++ I: AsRef<[IoVec<&'a mut [u8]>]> + 'a,
++{
++ pub iov: I,
++ pub cmsg_buffer: Option<&'a mut Vec<u8>>,
++}
++
++/// An extension of `recvmsg` that allows the caller to receive multiple
++/// messages from a socket using a single system call. This has
++/// performance benefits for some applications.
++///
++/// `iov` and `cmsg_buffer` should be constructed similarly to `recvmsg`
++///
++/// Multiple allocations are performed
++///
++/// # Arguments
++///
++/// * `fd`: Socket file descriptor
++/// * `data`: Struct that implements `IntoIterator` with `RecvMmsgData` items
++/// * `flags`: Optional flags passed directly to the operating system.
++///
++/// # RecvMmsgData
++///
++/// * `iov`: Scatter-gather list of buffers to receive the message
++/// * `cmsg_buffer`: Space to receive ancillary data. Should be created by
++/// [`cmsg_space!`](macro.cmsg_space.html)
++///
++/// # Returns
++/// A `Vec` with multiple `RecvMsg`, one per received message
++///
++/// # References
++/// - [`recvmsg`](fn.recvmsg.html)
++/// - [`RecvMsg`](struct.RecvMsg.html)
++#[cfg(any(
++ target_os = "linux",
++ target_os = "android",
++ target_os = "freebsd",
++ target_os = "netbsd",
++))]
++pub fn recvmmsg<'a, I>(
++ fd: RawFd,
++ data: impl std::iter::IntoIterator<Item=&'a mut RecvMmsgData<'a, I>,
++ IntoIter=impl ExactSizeIterator + Iterator<Item=&'a mut RecvMmsgData<'a, I>>>,
++ flags: MsgFlags,
++ timeout: Option<crate::sys::time::TimeSpec>
++) -> Result<Vec<RecvMsg<'a>>>
++ where
++ I: AsRef<[IoVec<&'a mut [u8]>]> + 'a,
++{
++ let iter = data.into_iter();
++
++ let num_messages = iter.len();
++
++ let mut output: Vec<libc::mmsghdr> = Vec::with_capacity(num_messages);
++
++ // Addresses should be pre-allocated. pack_mhdr_to_receive will store them
++ // as raw pointers, so we may not move them. Turn the vec into a boxed
++ // slice so we won't inadvertently reallocate the vec.
++ let mut addresses = vec![mem::MaybeUninit::uninit(); num_messages]
++ .into_boxed_slice();
++
++ let results: Vec<_> = iter.enumerate().map(|(i, d)| {
++ let (msg_controllen, mhdr) = unsafe {
++ pack_mhdr_to_receive(
++ d.iov.as_ref(),
++ &mut d.cmsg_buffer,
++ addresses[i].as_mut_ptr(),
++ )
++ };
++
++ output.push(
++ libc::mmsghdr {
++ msg_hdr: mhdr,
++ msg_len: 0,
++ }
++ );
++
++ (msg_controllen as usize, &mut d.cmsg_buffer)
++ }).collect();
++
++ let timeout = if let Some(mut t) = timeout {
++ t.as_mut() as *mut libc::timespec
++ } else {
++ ptr::null_mut()
++ };
++
++ let ret = unsafe { libc::recvmmsg(fd, output.as_mut_ptr(), output.len() as _, flags.bits() as _, timeout) };
++
++ let _ = Errno::result(ret)?;
++
++ Ok(output
++ .into_iter()
++ .take(ret as usize)
++ .zip(addresses.iter().map(|addr| unsafe{addr.assume_init()}))
++ .zip(results.into_iter())
++ .map(|((mmsghdr, address), (msg_controllen, cmsg_buffer))| {
++ unsafe {
++ read_mhdr(
++ mmsghdr.msg_hdr,
++ mmsghdr.msg_len as isize,
++ msg_controllen,
++ address,
++ cmsg_buffer
++ )
++ }
++ })
++ .collect())
++}
++
++unsafe fn read_mhdr<'a, 'b>(
++ mhdr: msghdr,
++ r: isize,
++ msg_controllen: usize,
++ address: sockaddr_storage,
++ cmsg_buffer: &'a mut Option<&'b mut Vec<u8>>
++) -> RecvMsg<'b> {
++ let cmsghdr = {
++ if mhdr.msg_controllen > 0 {
++ // got control message(s)
++ cmsg_buffer
++ .as_mut()
++ .unwrap()
++ .set_len(mhdr.msg_controllen as usize);
++ debug_assert!(!mhdr.msg_control.is_null());
++ debug_assert!(msg_controllen >= mhdr.msg_controllen as usize);
++ CMSG_FIRSTHDR(&mhdr as *const msghdr)
++ } else {
++ ptr::null()
++ }.as_ref()
++ };
++
++ let address = sockaddr_storage_to_addr(
++ &address ,
++ mhdr.msg_namelen as usize
++ ).ok();
++
++ RecvMsg {
++ bytes: r as usize,
++ cmsghdr,
++ address,
++ flags: MsgFlags::from_bits_truncate(mhdr.msg_flags),
++ mhdr,
++ }
++}
++
++unsafe fn pack_mhdr_to_receive<'a, I>(
++ iov: I,
++ cmsg_buffer: &mut Option<&mut Vec<u8>>,
++ address: *mut sockaddr_storage,
++) -> (usize, msghdr)
++ where
++ I: AsRef<[IoVec<&'a mut [u8]>]> + 'a,
++{
++ let (msg_control, msg_controllen) = cmsg_buffer.as_mut()
++ .map(|v| (v.as_mut_ptr(), v.capacity()))
++ .unwrap_or((ptr::null_mut(), 0));
++
++ let mhdr = {
++ // Musl's msghdr has private fields, so this is the only way to
++ // initialize it.
++ let mut mhdr = mem::MaybeUninit::<msghdr>::zeroed();
++ let p = mhdr.as_mut_ptr();
++ (*p).msg_name = address as *mut c_void;
++ (*p).msg_namelen = mem::size_of::<sockaddr_storage>() as socklen_t;
++ (*p).msg_iov = iov.as_ref().as_ptr() as *mut iovec;
++ (*p).msg_iovlen = iov.as_ref().len() as _;
++ (*p).msg_control = msg_control as *mut c_void;
++ (*p).msg_controllen = msg_controllen as _;
++ (*p).msg_flags = 0;
++ mhdr.assume_init()
++ };
++
++ (msg_controllen, mhdr)
++}
++
++fn pack_mhdr_to_send<'a, I, C>(
++ cmsg_buffer: &mut [u8],
++ iov: I,
++ cmsgs: C,
++ addr: Option<&SockAddr>
++) -> msghdr
++ where
++ I: AsRef<[IoVec<&'a [u8]>]>,
++ C: AsRef<[ControlMessage<'a>]>
++{
++ let capacity = cmsg_buffer.len();
+
+ // Next encode the sending address, if provided
+ let (name, namelen) = match addr {
+ Some(addr) => {
+- let (x, y) = unsafe { addr.as_ffi_pair() };
++ let (x, y) = addr.as_ffi_pair();
+ (x as *const _, y)
+ },
+ None => (ptr::null(), 0),
+@@ -854,97 +1333,68 @@ pub fn sendmsg(fd: RawFd, iov: &[IoVec<&[u8]>], cmsgs: &[ControlMessage],
+ ptr::null_mut()
+ };
+
+- let mhdr = {
++ let mhdr = unsafe {
+ // Musl's msghdr has private fields, so this is the only way to
+ // initialize it.
+- let mut mhdr: msghdr = unsafe{mem::uninitialized()};
+- mhdr.msg_name = name as *mut _;
+- mhdr.msg_namelen = namelen;
++ let mut mhdr = mem::MaybeUninit::<msghdr>::zeroed();
++ let p = mhdr.as_mut_ptr();
++ (*p).msg_name = name as *mut _;
++ (*p).msg_namelen = namelen;
+ // transmute iov into a mutable pointer. sendmsg doesn't really mutate
+ // the buffer, but the standard says that it takes a mutable pointer
+- mhdr.msg_iov = iov.as_ptr() as *mut _;
+- mhdr.msg_iovlen = iov.len() as _;
+- mhdr.msg_control = cmsg_ptr;
+- mhdr.msg_controllen = capacity as _;
+- mhdr.msg_flags = 0;
+- mhdr
++ (*p).msg_iov = iov.as_ref().as_ptr() as *mut _;
++ (*p).msg_iovlen = iov.as_ref().len() as _;
++ (*p).msg_control = cmsg_ptr;
++ (*p).msg_controllen = capacity as _;
++ (*p).msg_flags = 0;
++ mhdr.assume_init()
+ };
+
+ // Encode each cmsg. This must happen after initializing the header because
+ // CMSG_NEXT_HDR and friends read the msg_control and msg_controllen fields.
+ // CMSG_FIRSTHDR is always safe
+- let mut pmhdr: *mut cmsghdr = unsafe{CMSG_FIRSTHDR(&mhdr as *const msghdr)};
+- for cmsg in cmsgs {
++ let mut pmhdr: *mut cmsghdr = unsafe { CMSG_FIRSTHDR(&mhdr as *const msghdr) };
++ for cmsg in cmsgs.as_ref() {
+ assert_ne!(pmhdr, ptr::null_mut());
+ // Safe because we know that pmhdr is valid, and we initialized it with
+ // sufficient space
+ unsafe { cmsg.encode_into(pmhdr) };
+ // Safe because mhdr is valid
+- pmhdr = unsafe{CMSG_NXTHDR(&mhdr as *const msghdr, pmhdr)};
++ pmhdr = unsafe { CMSG_NXTHDR(&mhdr as *const msghdr, pmhdr) };
+ }
+
+- let ret = unsafe { libc::sendmsg(fd, &mhdr, flags.bits()) };
+-
+- Errno::result(ret).map(|r| r as usize)
++ mhdr
+ }
+
+ /// Receive message in scatter-gather vectors from a socket, and
+ /// optionally receive ancillary data into the provided buffer.
+ /// If no ancillary data is desired, use () as the type parameter.
+ ///
++/// # Arguments
++///
++/// * `fd`: Socket file descriptor
++/// * `iov`: Scatter-gather list of buffers to receive the message
++/// * `cmsg_buffer`: Space to receive ancillary data. Should be created by
++/// [`cmsg_space!`](macro.cmsg_space.html)
++/// * `flags`: Optional flags passed directly to the operating system.
++///
+ /// # References
+ /// [recvmsg(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html)
+ pub fn recvmsg<'a>(fd: RawFd, iov: &[IoVec<&mut [u8]>],
+- cmsg_buffer: Option<&'a mut dyn CmsgBuffer>,
++ mut cmsg_buffer: Option<&'a mut Vec<u8>>,
+ flags: MsgFlags) -> Result<RecvMsg<'a>>
+ {
+- let mut address: sockaddr_storage = unsafe { mem::uninitialized() };
+- let (msg_control, msg_controllen) = match cmsg_buffer {
+- Some(cmsgspace) => {
+- let msg_buf = cmsgspace.as_bytes_mut();
+- (msg_buf.as_mut_ptr(), msg_buf.len())
+- },
+- None => (ptr::null_mut(), 0),
+- };
+- let mut mhdr = {
+- // Musl's msghdr has private fields, so this is the only way to
+- // initialize it.
+- let mut mhdr: msghdr = unsafe{mem::uninitialized()};
+- mhdr.msg_name = &mut address as *mut sockaddr_storage as *mut c_void;
+- mhdr.msg_namelen = mem::size_of::<sockaddr_storage>() as socklen_t;
+- mhdr.msg_iov = iov.as_ptr() as *mut iovec;
+- mhdr.msg_iovlen = iov.len() as _;
+- mhdr.msg_control = msg_control as *mut c_void;
+- mhdr.msg_controllen = msg_controllen as _;
+- mhdr.msg_flags = 0;
+- mhdr
++ let mut address = mem::MaybeUninit::uninit();
++
++ let (msg_controllen, mut mhdr) = unsafe {
++ pack_mhdr_to_receive(&iov, &mut cmsg_buffer, address.as_mut_ptr())
+ };
+
+ let ret = unsafe { libc::recvmsg(fd, &mut mhdr, flags.bits()) };
+
+- Errno::result(ret).map(|r| {
+- let cmsghdr = unsafe {
+- if mhdr.msg_controllen > 0 {
+- // got control message(s)
+- debug_assert!(!mhdr.msg_control.is_null());
+- debug_assert!(msg_controllen >= mhdr.msg_controllen as usize);
+- CMSG_FIRSTHDR(&mhdr as *const msghdr)
+- } else {
+- ptr::null()
+- }.as_ref()
+- };
++ let r = Errno::result(ret)?;
+
+- let address = unsafe {
+- sockaddr_storage_to_addr(&address, mhdr.msg_namelen as usize).ok()
+- };
+- RecvMsg {
+- bytes: r as usize,
+- cmsghdr,
+- address,
+- flags: MsgFlags::from_bits_truncate(mhdr.msg_flags),
+- mhdr,
+- }
+- })
++ Ok(unsafe { read_mhdr(mhdr, r, msg_controllen, address.assume_init(), &mut cmsg_buffer) })
+ }
+
+
+@@ -1071,12 +1521,15 @@ pub fn recv(sockfd: RawFd, buf: &mut [u8], flags: MsgFlags) -> Result<usize> {
+ }
+
+ /// Receive data from a connectionless or connection-oriented socket. Returns
+-/// the number of bytes read and the socket address of the sender.
++/// the number of bytes read and, for connectionless sockets, the socket
++/// address of the sender.
+ ///
+ /// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/recvfrom.html)
+-pub fn recvfrom(sockfd: RawFd, buf: &mut [u8]) -> Result<(usize, SockAddr)> {
++pub fn recvfrom(sockfd: RawFd, buf: &mut [u8])
++ -> Result<(usize, Option<SockAddr>)>
++{
+ unsafe {
+- let addr: sockaddr_storage = mem::zeroed();
++ let mut addr: sockaddr_storage = mem::zeroed();
+ let mut len = mem::size_of::<sockaddr_storage>() as socklen_t;
+
+ let ret = Errno::result(libc::recvfrom(
+@@ -1084,11 +1537,14 @@ pub fn recvfrom(sockfd: RawFd, buf: &mut [u8]) -> Result<(usize, SockAddr)> {
+ buf.as_ptr() as *mut c_void,
+ buf.len() as size_t,
+ 0,
+- mem::transmute(&addr),
+- &mut len as *mut socklen_t))?;
++ &mut addr as *mut libc::sockaddr_storage as *mut libc::sockaddr,
++ &mut len as *mut socklen_t))? as usize;
+
+- sockaddr_storage_to_addr(&addr, len as usize)
+- .map(|addr| (ret as usize, addr))
++ match sockaddr_storage_to_addr(&addr, len as usize) {
++ Err(Error::Sys(Errno::ENOTCONN)) => Ok((ret, None)),
++ Ok(addr) => Ok((ret, Some(addr))),
++ Err(e) => Err(e)
++ }
+ }
+ }
+
+@@ -1121,24 +1577,6 @@ pub fn send(fd: RawFd, buf: &[u8], flags: MsgFlags) -> Result<usize> {
+ *
+ */
+
+-/// The protocol level at which to get / set socket options. Used as an
+-/// argument to `getsockopt` and `setsockopt`.
+-///
+-/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html)
+-#[repr(i32)]
+-#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+-pub enum SockLevel {
+- Socket = libc::SOL_SOCKET,
+- Tcp = libc::IPPROTO_TCP,
+- Ip = libc::IPPROTO_IP,
+- Ipv6 = libc::IPPROTO_IPV6,
+- Udp = libc::IPPROTO_UDP,
+- #[cfg(any(target_os = "android", target_os = "linux"))]
+- Netlink = libc::SOL_NETLINK,
+- #[cfg(any(target_os = "android", target_os = "linux"))]
+- Alg = libc::SOL_ALG,
+-}
+-
+ /// Represents a socket option that can be accessed or set. Used as an argument
+ /// to `getsockopt`
+ pub trait GetSockOpt : Copy {
+@@ -1190,14 +1628,18 @@ pub fn setsockopt<O: SetSockOpt>(fd: RawFd, opt: O, val: &O::Val) -> Result<()>
+ /// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpeername.html)
+ pub fn getpeername(fd: RawFd) -> Result<SockAddr> {
+ unsafe {
+- let addr: sockaddr_storage = mem::uninitialized();
++ let mut addr = mem::MaybeUninit::uninit();
+ let mut len = mem::size_of::<sockaddr_storage>() as socklen_t;
+
+- let ret = libc::getpeername(fd, mem::transmute(&addr), &mut len);
++ let ret = libc::getpeername(
++ fd,
++ addr.as_mut_ptr() as *mut libc::sockaddr,
++ &mut len
++ );
+
+ Errno::result(ret)?;
+
+- sockaddr_storage_to_addr(&addr, len as usize)
++ sockaddr_storage_to_addr(&addr.assume_init(), len as usize)
+ }
+ }
+
+@@ -1206,60 +1648,92 @@ pub fn getpeername(fd: RawFd) -> Result<SockAddr> {
+ /// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockname.html)
+ pub fn getsockname(fd: RawFd) -> Result<SockAddr> {
+ unsafe {
+- let addr: sockaddr_storage = mem::uninitialized();
++ let mut addr = mem::MaybeUninit::uninit();
+ let mut len = mem::size_of::<sockaddr_storage>() as socklen_t;
+
+- let ret = libc::getsockname(fd, mem::transmute(&addr), &mut len);
++ let ret = libc::getsockname(
++ fd,
++ addr.as_mut_ptr() as *mut libc::sockaddr,
++ &mut len
++ );
+
+ Errno::result(ret)?;
+
+- sockaddr_storage_to_addr(&addr, len as usize)
++ sockaddr_storage_to_addr(&addr.assume_init(), len as usize)
+ }
+ }
+
+-/// Return the appropriate `SockAddr` type from a `sockaddr_storage` of a certain
+-/// size. In C this would usually be done by casting. The `len` argument
++/// Return the appropriate `SockAddr` type from a `sockaddr_storage` of a
++/// certain size.
++///
++/// In C this would usually be done by casting. The `len` argument
+ /// should be the number of bytes in the `sockaddr_storage` that are actually
+ /// allocated and valid. It must be at least as large as all the useful parts
+ /// of the structure. Note that in the case of a `sockaddr_un`, `len` need not
+ /// include the terminating null.
+-pub unsafe fn sockaddr_storage_to_addr(
++pub fn sockaddr_storage_to_addr(
+ addr: &sockaddr_storage,
+ len: usize) -> Result<SockAddr> {
+
++ assert!(len <= mem::size_of::<sockaddr_un>());
+ if len < mem::size_of_val(&addr.ss_family) {
+ return Err(Error::Sys(Errno::ENOTCONN));
+ }
+
+- match addr.ss_family as c_int {
++ match c_int::from(addr.ss_family) {
+ libc::AF_INET => {
+- assert!(len as usize == mem::size_of::<sockaddr_in>());
+- let ret = *(addr as *const _ as *const sockaddr_in);
+- Ok(SockAddr::Inet(InetAddr::V4(ret)))
++ assert_eq!(len as usize, mem::size_of::<sockaddr_in>());
++ let sin = unsafe {
++ *(addr as *const sockaddr_storage as *const sockaddr_in)
++ };
++ Ok(SockAddr::Inet(InetAddr::V4(sin)))
+ }
+ libc::AF_INET6 => {
+- assert!(len as usize == mem::size_of::<sockaddr_in6>());
+- Ok(SockAddr::Inet(InetAddr::V6(*(addr as *const _ as *const sockaddr_in6))))
++ assert_eq!(len as usize, mem::size_of::<sockaddr_in6>());
++ let sin6 = unsafe {
++ *(addr as *const _ as *const sockaddr_in6)
++ };
++ Ok(SockAddr::Inet(InetAddr::V6(sin6)))
+ }
+ libc::AF_UNIX => {
+- let sun = *(addr as *const _ as *const sockaddr_un);
+ let pathlen = len - offset_of!(sockaddr_un, sun_path);
++ let sun = unsafe {
++ *(addr as *const _ as *const sockaddr_un)
++ };
+ Ok(SockAddr::Unix(UnixAddr(sun, pathlen)))
+ }
+ #[cfg(any(target_os = "android", target_os = "linux"))]
++ libc::AF_PACKET => {
++ use libc::sockaddr_ll;
++ assert_eq!(len as usize, mem::size_of::<sockaddr_ll>());
++ let sll = unsafe {
++ *(addr as *const _ as *const sockaddr_ll)
++ };
++ Ok(SockAddr::Link(LinkAddr(sll)))
++ }
++ #[cfg(any(target_os = "android", target_os = "linux"))]
+ libc::AF_NETLINK => {
+ use libc::sockaddr_nl;
+- Ok(SockAddr::Netlink(NetlinkAddr(*(addr as *const _ as *const sockaddr_nl))))
++ let snl = unsafe {
++ *(addr as *const _ as *const sockaddr_nl)
++ };
++ Ok(SockAddr::Netlink(NetlinkAddr(snl)))
+ }
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ libc::AF_ALG => {
+ use libc::sockaddr_alg;
+- Ok(SockAddr::Alg(AlgAddr(*(addr as *const _ as *const sockaddr_alg))))
++ let salg = unsafe {
++ *(addr as *const _ as *const sockaddr_alg)
++ };
++ Ok(SockAddr::Alg(AlgAddr(salg)))
+ }
+- #[cfg(target_os = "linux")]
++ #[cfg(any(target_os = "android", target_os = "linux"))]
+ libc::AF_VSOCK => {
+ use libc::sockaddr_vm;
+- Ok(SockAddr::Vsock(VsockAddr(*(addr as *const _ as *const sockaddr_vm))))
++ let svm = unsafe {
++ *(addr as *const _ as *const sockaddr_vm)
++ };
++ Ok(SockAddr::Vsock(VsockAddr(svm)))
+ }
+ af => panic!("unexpected address family {}", af),
+ }
+diff --git a/third_party/rust/nix/src/sys/socket/sockopt.rs b/third_party/rust/nix/src/sys/socket/sockopt.rs
+index a996010018d5b..5b7b4feafb49a 100644
+--- a/third_party/rust/nix/src/sys/socket/sockopt.rs
++++ b/third_party/rust/nix/src/sys/socket/sockopt.rs
+@@ -1,9 +1,13 @@
++use cfg_if::cfg_if;
+ use super::{GetSockOpt, SetSockOpt};
+-use Result;
+-use errno::Errno;
+-use sys::time::TimeVal;
++use crate::Result;
++use crate::errno::Errno;
++use crate::sys::time::TimeVal;
+ use libc::{self, c_int, c_void, socklen_t};
+-use std::mem;
++use std::mem::{
++ self,
++ MaybeUninit
++};
+ use std::os::unix::io::RawFd;
+ use std::ffi::{OsStr, OsString};
+ #[cfg(target_family = "unix")]
+@@ -84,14 +88,14 @@ macro_rules! getsockopt_impl {
+
+ fn get(&self, fd: RawFd) -> Result<$ty> {
+ unsafe {
+- let mut getter: $getter = Get::blank();
++ let mut getter: $getter = Get::uninit();
+
+ let res = libc::getsockopt(fd, $level, $flag,
+ getter.ffi_ptr(),
+ getter.ffi_len());
+ Errno::result(res)?;
+
+- Ok(getter.unwrap())
++ Ok(getter.assume_init())
+ }
+ }
+ }
+@@ -248,6 +252,10 @@ sockopt_impl!(Both, TcpKeepAlive, libc::IPPROTO_TCP, libc::TCP_KEEPALIVE, u32);
+ target_os = "linux",
+ target_os = "nacl"))]
+ sockopt_impl!(Both, TcpKeepIdle, libc::IPPROTO_TCP, libc::TCP_KEEPIDLE, u32);
++#[cfg(not(target_os = "openbsd"))]
++sockopt_impl!(Both, TcpKeepCount, libc::IPPROTO_TCP, libc::TCP_KEEPCNT, u32);
++#[cfg(not(target_os = "openbsd"))]
++sockopt_impl!(Both, TcpKeepInterval, libc::IPPROTO_TCP, libc::TCP_KEEPINTVL, u32);
+ sockopt_impl!(Both, RcvBuf, libc::SOL_SOCKET, libc::SO_RCVBUF, usize);
+ sockopt_impl!(Both, SndBuf, libc::SOL_SOCKET, libc::SO_SNDBUF, usize);
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+@@ -257,6 +265,8 @@ sockopt_impl!(SetOnly, SndBufForce, libc::SOL_SOCKET, libc::SO_SNDBUFFORCE, usiz
+ sockopt_impl!(GetOnly, SockType, libc::SOL_SOCKET, libc::SO_TYPE, super::SockType);
+ sockopt_impl!(GetOnly, AcceptConn, libc::SOL_SOCKET, libc::SO_ACCEPTCONN, bool);
+ #[cfg(any(target_os = "android", target_os = "linux"))]
++sockopt_impl!(Both, BindToDevice, libc::SOL_SOCKET, libc::SO_BINDTODEVICE, OsString<[u8; libc::IFNAMSIZ]>);
++#[cfg(any(target_os = "android", target_os = "linux"))]
+ sockopt_impl!(GetOnly, OriginalDst, libc::SOL_IP, libc::SO_ORIGINAL_DST, libc::sockaddr_in);
+ sockopt_impl!(Both, ReceiveTimestamp, libc::SOL_SOCKET, libc::SO_TIMESTAMP, bool);
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+@@ -305,7 +315,10 @@ sockopt_impl!(Both, Ipv4RecvIf, libc::IPPROTO_IP, libc::IP_RECVIF, bool);
+ target_os = "openbsd",
+ ))]
+ sockopt_impl!(Both, Ipv4RecvDstAddr, libc::IPPROTO_IP, libc::IP_RECVDSTADDR, bool);
+-
++#[cfg(target_os = "linux")]
++sockopt_impl!(Both, UdpGsoSegment, libc::SOL_UDP, libc::UDP_SEGMENT, libc::c_int);
++#[cfg(target_os = "linux")]
++sockopt_impl!(Both, UdpGroSegment, libc::IPPROTO_UDP, libc::UDP_GRO, bool);
+
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[derive(Copy, Clone, Debug)]
+@@ -364,16 +377,16 @@ impl<T> SetSockOpt for AlgSetKey<T> where T: AsRef<[u8]> + Clone {
+
+ /// Helper trait that describes what is expected from a `GetSockOpt` getter.
+ unsafe trait Get<T> {
+- /// Returns an empty value.
+- unsafe fn blank() -> Self;
++ /// Returns an uninitialized value.
++ unsafe fn uninit() -> Self;
+ /// Returns a pointer to the stored value. This pointer will be passed to the system's
+ /// `getsockopt` call (`man 3p getsockopt`, argument `option_value`).
+ fn ffi_ptr(&mut self) -> *mut c_void;
+ /// Returns length of the stored value. This pointer will be passed to the system's
+ /// `getsockopt` call (`man 3p getsockopt`, argument `option_len`).
+ fn ffi_len(&mut self) -> *mut socklen_t;
+- /// Returns the stored value.
+- unsafe fn unwrap(self) -> T;
++ /// Returns the hopefully initialized inner value.
++ unsafe fn assume_init(self) -> T;
+ }
+
+ /// Helper trait that describes what is expected from a `SetSockOpt` setter.
+@@ -391,28 +404,28 @@ unsafe trait Set<'a, T> {
+ /// Getter for an arbitrary `struct`.
+ struct GetStruct<T> {
+ len: socklen_t,
+- val: T,
++ val: MaybeUninit<T>,
+ }
+
+ unsafe impl<T> Get<T> for GetStruct<T> {
+- unsafe fn blank() -> Self {
++ unsafe fn uninit() -> Self {
+ GetStruct {
+ len: mem::size_of::<T>() as socklen_t,
+- val: mem::zeroed(),
++ val: MaybeUninit::uninit(),
+ }
+ }
+
+ fn ffi_ptr(&mut self) -> *mut c_void {
+- &mut self.val as *mut T as *mut c_void
++ self.val.as_mut_ptr() as *mut c_void
+ }
+
+ fn ffi_len(&mut self) -> *mut socklen_t {
+ &mut self.len
+ }
+
+- unsafe fn unwrap(self) -> T {
+- assert!(self.len as usize == mem::size_of::<T>(), "invalid getsockopt implementation");
+- self.val
++ unsafe fn assume_init(self) -> T {
++ assert_eq!(self.len as usize, mem::size_of::<T>(), "invalid getsockopt implementation");
++ self.val.assume_init()
+ }
+ }
+
+@@ -423,7 +436,7 @@ struct SetStruct<'a, T: 'static> {
+
+ unsafe impl<'a, T> Set<'a, T> for SetStruct<'a, T> {
+ fn new(ptr: &'a T) -> SetStruct<'a, T> {
+- SetStruct { ptr: ptr }
++ SetStruct { ptr }
+ }
+
+ fn ffi_ptr(&self) -> *const c_void {
+@@ -438,28 +451,28 @@ unsafe impl<'a, T> Set<'a, T> for SetStruct<'a, T> {
+ /// Getter for a boolean value.
+ struct GetBool {
+ len: socklen_t,
+- val: c_int,
++ val: MaybeUninit<c_int>,
+ }
+
+ unsafe impl Get<bool> for GetBool {
+- unsafe fn blank() -> Self {
++ unsafe fn uninit() -> Self {
+ GetBool {
+ len: mem::size_of::<c_int>() as socklen_t,
+- val: mem::zeroed(),
++ val: MaybeUninit::uninit(),
+ }
+ }
+
+ fn ffi_ptr(&mut self) -> *mut c_void {
+- &mut self.val as *mut c_int as *mut c_void
++ self.val.as_mut_ptr() as *mut c_void
+ }
+
+ fn ffi_len(&mut self) -> *mut socklen_t {
+ &mut self.len
+ }
+
+- unsafe fn unwrap(self) -> bool {
+- assert!(self.len as usize == mem::size_of::<c_int>(), "invalid getsockopt implementation");
+- self.val != 0
++ unsafe fn assume_init(self) -> bool {
++ assert_eq!(self.len as usize, mem::size_of::<c_int>(), "invalid getsockopt implementation");
++ self.val.assume_init() != 0
+ }
+ }
+
+@@ -485,28 +498,28 @@ unsafe impl<'a> Set<'a, bool> for SetBool {
+ /// Getter for an `u8` value.
+ struct GetU8 {
+ len: socklen_t,
+- val: u8,
++ val: MaybeUninit<u8>,
+ }
+
+ unsafe impl Get<u8> for GetU8 {
+- unsafe fn blank() -> Self {
++ unsafe fn uninit() -> Self {
+ GetU8 {
+ len: mem::size_of::<u8>() as socklen_t,
+- val: mem::zeroed(),
++ val: MaybeUninit::uninit(),
+ }
+ }
+
+ fn ffi_ptr(&mut self) -> *mut c_void {
+- &mut self.val as *mut u8 as *mut c_void
++ self.val.as_mut_ptr() as *mut c_void
+ }
+
+ fn ffi_len(&mut self) -> *mut socklen_t {
+ &mut self.len
+ }
+
+- unsafe fn unwrap(self) -> u8 {
+- assert!(self.len as usize == mem::size_of::<u8>(), "invalid getsockopt implementation");
+- self.val as u8
++ unsafe fn assume_init(self) -> u8 {
++ assert_eq!(self.len as usize, mem::size_of::<u8>(), "invalid getsockopt implementation");
++ self.val.assume_init()
+ }
+ }
+
+@@ -532,28 +545,28 @@ unsafe impl<'a> Set<'a, u8> for SetU8 {
+ /// Getter for an `usize` value.
+ struct GetUsize {
+ len: socklen_t,
+- val: c_int,
++ val: MaybeUninit<c_int>,
+ }
+
+ unsafe impl Get<usize> for GetUsize {
+- unsafe fn blank() -> Self {
++ unsafe fn uninit() -> Self {
+ GetUsize {
+ len: mem::size_of::<c_int>() as socklen_t,
+- val: mem::zeroed(),
++ val: MaybeUninit::uninit(),
+ }
+ }
+
+ fn ffi_ptr(&mut self) -> *mut c_void {
+- &mut self.val as *mut c_int as *mut c_void
++ self.val.as_mut_ptr() as *mut c_void
+ }
+
+ fn ffi_len(&mut self) -> *mut socklen_t {
+ &mut self.len
+ }
+
+- unsafe fn unwrap(self) -> usize {
+- assert!(self.len as usize == mem::size_of::<c_int>(), "invalid getsockopt implementation");
+- self.val as usize
++ unsafe fn assume_init(self) -> usize {
++ assert_eq!(self.len as usize, mem::size_of::<c_int>(), "invalid getsockopt implementation");
++ self.val.assume_init() as usize
+ }
+ }
+
+@@ -579,27 +592,29 @@ unsafe impl<'a> Set<'a, usize> for SetUsize {
+ /// Getter for a `OsString` value.
+ struct GetOsString<T: AsMut<[u8]>> {
+ len: socklen_t,
+- val: T,
++ val: MaybeUninit<T>,
+ }
+
+ unsafe impl<T: AsMut<[u8]>> Get<OsString> for GetOsString<T> {
+- unsafe fn blank() -> Self {
++ unsafe fn uninit() -> Self {
+ GetOsString {
+ len: mem::size_of::<T>() as socklen_t,
+- val: mem::zeroed(),
++ val: MaybeUninit::uninit(),
+ }
+ }
+
+ fn ffi_ptr(&mut self) -> *mut c_void {
+- &mut self.val as *mut T as *mut c_void
++ self.val.as_mut_ptr() as *mut c_void
+ }
+
+ fn ffi_len(&mut self) -> *mut socklen_t {
+ &mut self.len
+ }
+
+- unsafe fn unwrap(mut self) -> OsString {
+- OsStr::from_bytes(self.val.as_mut()).to_owned()
++ unsafe fn assume_init(self) -> OsString {
++ let len = self.len as usize;
++ let mut v = self.val.assume_init();
++ OsStr::from_bytes(&v.as_mut()[0..len]).to_owned()
+ }
+ }
+
+@@ -640,11 +655,11 @@ mod test {
+ #[test]
+ fn is_socket_type_unix() {
+ use super::super::*;
+- use ::unistd::close;
++ use crate::unistd::close;
+
+ let (a, b) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()).unwrap();
+ let a_type = getsockopt(a, super::SockType).unwrap();
+- assert!(a_type == SockType::Stream);
++ assert_eq!(a_type, SockType::Stream);
+ close(a).unwrap();
+ close(b).unwrap();
+ }
+@@ -652,11 +667,11 @@ mod test {
+ #[test]
+ fn is_socket_type_dgram() {
+ use super::super::*;
+- use ::unistd::close;
++ use crate::unistd::close;
+
+ let s = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), None).unwrap();
+ let s_type = getsockopt(s, super::SockType).unwrap();
+- assert!(s_type == SockType::Datagram);
++ assert_eq!(s_type, SockType::Datagram);
+ close(s).unwrap();
+ }
+
+@@ -666,7 +681,7 @@ mod test {
+ #[test]
+ fn can_get_listen_on_tcp_socket() {
+ use super::super::*;
+- use ::unistd::close;
++ use crate::unistd::close;
+
+ let s = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap();
+ let s_listening = getsockopt(s, super::AcceptConn).unwrap();
+diff --git a/third_party/rust/nix/src/sys/stat.rs b/third_party/rust/nix/src/sys/stat.rs
+index 66c8c9dd1b720..df81a2cb329d6 100644
+--- a/third_party/rust/nix/src/sys/stat.rs
++++ b/third_party/rust/nix/src/sys/stat.rs
+@@ -1,13 +1,12 @@
+ pub use libc::{dev_t, mode_t};
+ pub use libc::stat as FileStat;
+
+-use {Result, NixPath};
+-use errno::Errno;
+-use fcntl::{AtFlags, at_rawfd};
+-use libc;
++use crate::{Result, NixPath, errno::Errno};
++#[cfg(not(target_os = "redox"))]
++use crate::fcntl::{AtFlags, at_rawfd};
+ use std::mem;
+ use std::os::unix::io::RawFd;
+-use sys::time::{TimeSpec, TimeVal};
++use crate::sys::time::{TimeSpec, TimeVal};
+
+ libc_bitflags!(
+ pub struct SFlag: mode_t {
+@@ -78,49 +77,50 @@ pub fn umask(mode: Mode) -> Mode {
+ }
+
+ pub fn stat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> {
+- let mut dst = unsafe { mem::uninitialized() };
++ let mut dst = mem::MaybeUninit::uninit();
+ let res = path.with_nix_path(|cstr| {
+ unsafe {
+- libc::stat(cstr.as_ptr(), &mut dst as *mut FileStat)
++ libc::stat(cstr.as_ptr(), dst.as_mut_ptr())
+ }
+ })?;
+
+ Errno::result(res)?;
+
+- Ok(dst)
++ Ok(unsafe{dst.assume_init()})
+ }
+
+ pub fn lstat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> {
+- let mut dst = unsafe { mem::uninitialized() };
++ let mut dst = mem::MaybeUninit::uninit();
+ let res = path.with_nix_path(|cstr| {
+ unsafe {
+- libc::lstat(cstr.as_ptr(), &mut dst as *mut FileStat)
++ libc::lstat(cstr.as_ptr(), dst.as_mut_ptr())
+ }
+ })?;
+
+ Errno::result(res)?;
+
+- Ok(dst)
++ Ok(unsafe{dst.assume_init()})
+ }
+
+ pub fn fstat(fd: RawFd) -> Result<FileStat> {
+- let mut dst = unsafe { mem::uninitialized() };
+- let res = unsafe { libc::fstat(fd, &mut dst as *mut FileStat) };
++ let mut dst = mem::MaybeUninit::uninit();
++ let res = unsafe { libc::fstat(fd, dst.as_mut_ptr()) };
+
+ Errno::result(res)?;
+
+- Ok(dst)
++ Ok(unsafe{dst.assume_init()})
+ }
+
++#[cfg(not(target_os = "redox"))]
+ pub fn fstatat<P: ?Sized + NixPath>(dirfd: RawFd, pathname: &P, f: AtFlags) -> Result<FileStat> {
+- let mut dst = unsafe { mem::uninitialized() };
++ let mut dst = mem::MaybeUninit::uninit();
+ let res = pathname.with_nix_path(|cstr| {
+- unsafe { libc::fstatat(dirfd, cstr.as_ptr(), &mut dst as *mut FileStat, f.bits() as libc::c_int) }
++ unsafe { libc::fstatat(dirfd, cstr.as_ptr(), dst.as_mut_ptr(), f.bits() as libc::c_int) }
+ })?;
+
+ Errno::result(res)?;
+
+- Ok(dst)
++ Ok(unsafe{dst.assume_init()})
+ }
+
+ /// Change the file permission bits of the file specified by a file descriptor.
+@@ -150,13 +150,14 @@ pub enum FchmodatFlags {
+ /// If `flag` is `FchmodatFlags::NoFollowSymlink` and `path` names a symbolic link,
+ /// then the mode of the symbolic link is changed.
+ ///
+-/// `fchmod(None, path, mode, FchmodatFlags::FollowSymlink)` is identical to
++/// `fchmodat(None, path, mode, FchmodatFlags::FollowSymlink)` is identical to
+ /// a call `libc::chmod(path, mode)`. That's why `chmod` is unimplemented
+ /// in the `nix` crate.
+ ///
+ /// # References
+ ///
+ /// [fchmodat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmodat.html).
++#[cfg(not(target_os = "redox"))]
+ pub fn fchmodat<P: ?Sized + NixPath>(
+ dirfd: Option<RawFd>,
+ path: &P,
+@@ -260,6 +261,7 @@ pub enum UtimensatFlags {
+ /// # References
+ ///
+ /// [utimensat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/utimens.html).
++#[cfg(not(target_os = "redox"))]
+ pub fn utimensat<P: ?Sized + NixPath>(
+ dirfd: Option<RawFd>,
+ path: &P,
+@@ -285,6 +287,7 @@ pub fn utimensat<P: ?Sized + NixPath>(
+ Errno::result(res).map(drop)
+ }
+
++#[cfg(not(target_os = "redox"))]
+ pub fn mkdirat<P: ?Sized + NixPath>(fd: RawFd, path: &P, mode: Mode) -> Result<()> {
+ let res = path.with_nix_path(|cstr| {
+ unsafe { libc::mkdirat(fd, cstr.as_ptr(), mode.bits() as mode_t) }
+diff --git a/third_party/rust/nix/src/sys/statfs.rs b/third_party/rust/nix/src/sys/statfs.rs
+index d4596bf336958..27b72592b9a30 100644
+--- a/third_party/rust/nix/src/sys/statfs.rs
++++ b/third_party/rust/nix/src/sys/statfs.rs
+@@ -4,10 +4,7 @@ use std::os::unix::io::AsRawFd;
+ #[cfg(not(any(target_os = "linux", target_os = "android")))]
+ use std::ffi::CStr;
+
+-use libc;
+-
+-use {NixPath, Result};
+-use errno::Errno;
++use crate::{NixPath, Result, errno::Errno};
+
+ #[cfg(target_os = "android")]
+ pub type fsid_t = libc::__fsid_t;
+@@ -15,81 +12,95 @@ pub type fsid_t = libc::__fsid_t;
+ pub type fsid_t = libc::fsid_t;
+
+ #[derive(Clone, Copy)]
++#[repr(transparent)]
+ pub struct Statfs(libc::statfs);
+
+ #[cfg(target_os = "freebsd")]
+-#[derive(Eq, Copy, Clone, PartialEq, Debug)]
+-pub struct FsType(u32);
++type fs_type_t = u32;
+ #[cfg(target_os = "android")]
+-#[derive(Eq, Copy, Clone, PartialEq, Debug)]
+-pub struct FsType(libc::c_ulong);
++type fs_type_t = libc::c_ulong;
+ #[cfg(all(target_os = "linux", target_arch = "s390x"))]
+-#[derive(Eq, Copy, Clone, PartialEq, Debug)]
+-pub struct FsType(u32);
++type fs_type_t = libc::c_uint;
+ #[cfg(all(target_os = "linux", target_env = "musl"))]
+-#[derive(Eq, Copy, Clone, PartialEq, Debug)]
+-pub struct FsType(libc::c_ulong);
++type fs_type_t = libc::c_ulong;
+ #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))]
++type fs_type_t = libc::__fsword_t;
++
++#[cfg(any(
++ target_os = "freebsd",
++ target_os = "android",
++ all(target_os = "linux", target_arch = "s390x"),
++ all(target_os = "linux", target_env = "musl"),
++ all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))),
++))]
+ #[derive(Eq, Copy, Clone, PartialEq, Debug)]
+-pub struct FsType(libc::c_long);
+-
+-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+-pub const ADFS_SUPER_MAGIC: FsType = FsType(libc::ADFS_SUPER_MAGIC);
+-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+-pub const AFFS_SUPER_MAGIC: FsType = FsType(libc::AFFS_SUPER_MAGIC);
+-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+-pub const CODA_SUPER_MAGIC: FsType = FsType(libc::CODA_SUPER_MAGIC);
+-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+-pub const CRAMFS_MAGIC: FsType = FsType(libc::CRAMFS_MAGIC);
+-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+-pub const EFS_SUPER_MAGIC: FsType = FsType(libc::EFS_SUPER_MAGIC);
+-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+-pub const EXT2_SUPER_MAGIC: FsType = FsType(libc::EXT2_SUPER_MAGIC);
+-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+-pub const EXT3_SUPER_MAGIC: FsType = FsType(libc::EXT3_SUPER_MAGIC);
+-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+-pub const EXT4_SUPER_MAGIC: FsType = FsType(libc::EXT4_SUPER_MAGIC);
+-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+-pub const HPFS_SUPER_MAGIC: FsType = FsType(libc::HPFS_SUPER_MAGIC);
+-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+-pub const HUGETLBFS_MAGIC: FsType = FsType(libc::HUGETLBFS_MAGIC);
+-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+-pub const ISOFS_SUPER_MAGIC: FsType = FsType(libc::ISOFS_SUPER_MAGIC);
+-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+-pub const JFFS2_SUPER_MAGIC: FsType = FsType(libc::JFFS2_SUPER_MAGIC);
+-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+-pub const MINIX_SUPER_MAGIC: FsType = FsType(libc::MINIX_SUPER_MAGIC);
+-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+-pub const MINIX_SUPER_MAGIC2: FsType = FsType(libc::MINIX_SUPER_MAGIC2);
+-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+-pub const MINIX2_SUPER_MAGIC: FsType = FsType(libc::MINIX2_SUPER_MAGIC);
+-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+-pub const MINIX2_SUPER_MAGIC2: FsType = FsType(libc::MINIX2_SUPER_MAGIC2);
+-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+-pub const MSDOS_SUPER_MAGIC: FsType = FsType(libc::MSDOS_SUPER_MAGIC);
+-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+-pub const NCP_SUPER_MAGIC: FsType = FsType(libc::NCP_SUPER_MAGIC);
+-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+-pub const NFS_SUPER_MAGIC: FsType = FsType(libc::NFS_SUPER_MAGIC);
+-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+-pub const OPENPROM_SUPER_MAGIC: FsType = FsType(libc::OPENPROM_SUPER_MAGIC);
+-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+-pub const PROC_SUPER_MAGIC: FsType = FsType(libc::PROC_SUPER_MAGIC);
+-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+-pub const QNX4_SUPER_MAGIC: FsType = FsType(libc::QNX4_SUPER_MAGIC);
+-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+-pub const REISERFS_SUPER_MAGIC: FsType = FsType(libc::REISERFS_SUPER_MAGIC);
+-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+-pub const SMB_SUPER_MAGIC: FsType = FsType(libc::SMB_SUPER_MAGIC);
+-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+-pub const TMPFS_MAGIC: FsType = FsType(libc::TMPFS_MAGIC);
+-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+-pub const USBDEVICE_SUPER_MAGIC: FsType = FsType(libc::USBDEVICE_SUPER_MAGIC);
++pub struct FsType(pub fs_type_t);
++
++#[cfg(all(target_os = "linux", not(target_env = "musl")))]
++pub const ADFS_SUPER_MAGIC: FsType = FsType(libc::ADFS_SUPER_MAGIC as fs_type_t);
++#[cfg(all(target_os = "linux", not(target_env = "musl")))]
++pub const AFFS_SUPER_MAGIC: FsType = FsType(libc::AFFS_SUPER_MAGIC as fs_type_t);
++#[cfg(all(target_os = "linux", not(target_env = "musl")))]
++pub const CODA_SUPER_MAGIC: FsType = FsType(libc::CODA_SUPER_MAGIC as fs_type_t);
++#[cfg(all(target_os = "linux", not(target_env = "musl")))]
++pub const CRAMFS_MAGIC: FsType = FsType(libc::CRAMFS_MAGIC as fs_type_t);
++#[cfg(all(target_os = "linux", not(target_env = "musl")))]
++pub const EFS_SUPER_MAGIC: FsType = FsType(libc::EFS_SUPER_MAGIC as fs_type_t);
++#[cfg(all(target_os = "linux", not(target_env = "musl")))]
++pub const EXT2_SUPER_MAGIC: FsType = FsType(libc::EXT2_SUPER_MAGIC as fs_type_t);
++#[cfg(all(target_os = "linux", not(target_env = "musl")))]
++pub const EXT3_SUPER_MAGIC: FsType = FsType(libc::EXT3_SUPER_MAGIC as fs_type_t);
++#[cfg(all(target_os = "linux", not(target_env = "musl")))]
++pub const EXT4_SUPER_MAGIC: FsType = FsType(libc::EXT4_SUPER_MAGIC as fs_type_t);
++#[cfg(all(target_os = "linux", not(target_env = "musl")))]
++pub const HPFS_SUPER_MAGIC: FsType = FsType(libc::HPFS_SUPER_MAGIC as fs_type_t);
++#[cfg(all(target_os = "linux", not(target_env = "musl")))]
++pub const HUGETLBFS_MAGIC: FsType = FsType(libc::HUGETLBFS_MAGIC as fs_type_t);
++#[cfg(all(target_os = "linux", not(target_env = "musl")))]
++pub const ISOFS_SUPER_MAGIC: FsType = FsType(libc::ISOFS_SUPER_MAGIC as fs_type_t);
++#[cfg(all(target_os = "linux", not(target_env = "musl")))]
++pub const JFFS2_SUPER_MAGIC: FsType = FsType(libc::JFFS2_SUPER_MAGIC as fs_type_t);
++#[cfg(all(target_os = "linux", not(target_env = "musl")))]
++pub const MINIX_SUPER_MAGIC: FsType = FsType(libc::MINIX_SUPER_MAGIC as fs_type_t);
++#[cfg(all(target_os = "linux", not(target_env = "musl")))]
++pub const MINIX_SUPER_MAGIC2: FsType = FsType(libc::MINIX_SUPER_MAGIC2 as fs_type_t);
++#[cfg(all(target_os = "linux", not(target_env = "musl")))]
++pub const MINIX2_SUPER_MAGIC: FsType = FsType(libc::MINIX2_SUPER_MAGIC as fs_type_t);
++#[cfg(all(target_os = "linux", not(target_env = "musl")))]
++pub const MINIX2_SUPER_MAGIC2: FsType = FsType(libc::MINIX2_SUPER_MAGIC2 as fs_type_t);
++#[cfg(all(target_os = "linux", not(target_env = "musl")))]
++pub const MSDOS_SUPER_MAGIC: FsType = FsType(libc::MSDOS_SUPER_MAGIC as fs_type_t);
++#[cfg(all(target_os = "linux", not(target_env = "musl")))]
++pub const NCP_SUPER_MAGIC: FsType = FsType(libc::NCP_SUPER_MAGIC as fs_type_t);
++#[cfg(all(target_os = "linux", not(target_env = "musl")))]
++pub const NFS_SUPER_MAGIC: FsType = FsType(libc::NFS_SUPER_MAGIC as fs_type_t);
++#[cfg(all(target_os = "linux", not(target_env = "musl")))]
++pub const OPENPROM_SUPER_MAGIC: FsType = FsType(libc::OPENPROM_SUPER_MAGIC as fs_type_t);
++#[cfg(all(target_os = "linux", not(target_env = "musl")))]
++pub const OVERLAYFS_SUPER_MAGIC: FsType = FsType(libc::OVERLAYFS_SUPER_MAGIC as fs_type_t);
++#[cfg(all(target_os = "linux", not(target_env = "musl")))]
++pub const PROC_SUPER_MAGIC: FsType = FsType(libc::PROC_SUPER_MAGIC as fs_type_t);
++#[cfg(all(target_os = "linux", not(target_env = "musl")))]
++pub const QNX4_SUPER_MAGIC: FsType = FsType(libc::QNX4_SUPER_MAGIC as fs_type_t);
++#[cfg(all(target_os = "linux", not(target_env = "musl")))]
++pub const REISERFS_SUPER_MAGIC: FsType = FsType(libc::REISERFS_SUPER_MAGIC as fs_type_t);
++#[cfg(all(target_os = "linux", not(target_env = "musl")))]
++pub const SMB_SUPER_MAGIC: FsType = FsType(libc::SMB_SUPER_MAGIC as fs_type_t);
++#[cfg(all(target_os = "linux", not(target_env = "musl")))]
++pub const TMPFS_MAGIC: FsType = FsType(libc::TMPFS_MAGIC as fs_type_t);
++#[cfg(all(target_os = "linux", not(target_env = "musl")))]
++pub const USBDEVICE_SUPER_MAGIC: FsType = FsType(libc::USBDEVICE_SUPER_MAGIC as fs_type_t);
++#[cfg(all(target_os = "linux", not(target_env = "musl")))]
++pub const CGROUP_SUPER_MAGIC: FsType = FsType(libc::CGROUP_SUPER_MAGIC as fs_type_t);
++#[cfg(all(target_os = "linux", not(target_env = "musl")))]
++pub const CGROUP2_SUPER_MAGIC: FsType = FsType(libc::CGROUP2_SUPER_MAGIC as fs_type_t);
++
+
+ impl Statfs {
+ /// Magic code defining system type
+ #[cfg(not(any(
+ target_os = "openbsd",
++ target_os = "dragonfly",
+ target_os = "ios",
+ target_os = "macos"
+ )))]
+@@ -105,32 +116,35 @@ impl Statfs {
+ }
+
+ /// Optimal transfer block size
+- #[cfg(any(target_os = "ios", target_os = "macos", target_os = "openbsd"))]
++ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ pub fn optimal_transfer_size(&self) -> i32 {
+ self.0.f_iosize
+ }
+
+ /// Optimal transfer block size
+- #[cfg(all(target_os = "linux", target_arch = "s390x"))]
++ #[cfg(target_os = "openbsd")]
+ pub fn optimal_transfer_size(&self) -> u32 {
+- self.0.f_bsize
++ self.0.f_iosize
+ }
+
+ /// Optimal transfer block size
+- #[cfg(all(target_os = "linux", target_env = "musl"))]
+- pub fn optimal_transfer_size(&self) -> libc::c_ulong {
++ #[cfg(all(target_os = "linux", target_arch = "s390x"))]
++ pub fn optimal_transfer_size(&self) -> u32 {
+ self.0.f_bsize
+ }
+
+ /// Optimal transfer block size
+- #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))]
+- pub fn optimal_transfer_size(&self) -> libc::c_long {
++ #[cfg(any(
++ target_os = "android",
++ all(target_os = "linux", target_env = "musl")
++ ))]
++ pub fn optimal_transfer_size(&self) -> libc::c_ulong {
+ self.0.f_bsize
+ }
+
+ /// Optimal transfer block size
+- #[cfg(target_os = "android")]
+- pub fn optimal_transfer_size(&self) -> libc::c_ulong {
++ #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))]
++ pub fn optimal_transfer_size(&self) -> libc::__fsword_t {
+ self.0.f_bsize
+ }
+
+@@ -169,7 +183,7 @@ impl Statfs {
+ /// Size of a block
+ // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471
+ #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))]
+- pub fn block_size(&self) -> libc::c_long {
++ pub fn block_size(&self) -> libc::__fsword_t {
+ self.0.f_bsize
+ }
+
+@@ -211,7 +225,7 @@ impl Statfs {
+
+ /// Maximum length of filenames
+ #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))]
+- pub fn maximum_name_length(&self) -> libc::c_long {
++ pub fn maximum_name_length(&self) -> libc::__fsword_t {
+ self.0.f_namelen
+ }
+
+@@ -240,7 +254,7 @@ impl Statfs {
+ }
+
+ /// Total data blocks in filesystem
+- #[cfg(all(target_os = "linux", target_env = "musl"))]
++ #[cfg(all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))))]
+ pub fn blocks(&self) -> u64 {
+ self.0.f_blocks
+ }
+@@ -253,7 +267,7 @@ impl Statfs {
+ target_os = "freebsd",
+ target_os = "openbsd",
+ target_os = "dragonfly",
+- all(target_os = "linux", target_env = "musl")
++ all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32")))
+ )))]
+ pub fn blocks(&self) -> libc::c_ulong {
+ self.0.f_blocks
+@@ -278,7 +292,7 @@ impl Statfs {
+ }
+
+ /// Free blocks in filesystem
+- #[cfg(all(target_os = "linux", target_env = "musl"))]
++ #[cfg(all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))))]
+ pub fn blocks_free(&self) -> u64 {
+ self.0.f_bfree
+ }
+@@ -291,7 +305,7 @@ impl Statfs {
+ target_os = "freebsd",
+ target_os = "openbsd",
+ target_os = "dragonfly",
+- all(target_os = "linux", target_env = "musl")
++ all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32")))
+ )))]
+ pub fn blocks_free(&self) -> libc::c_ulong {
+ self.0.f_bfree
+@@ -316,7 +330,7 @@ impl Statfs {
+ }
+
+ /// Free blocks available to unprivileged user
+- #[cfg(all(target_os = "linux", target_env = "musl"))]
++ #[cfg(all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))))]
+ pub fn blocks_available(&self) -> u64 {
+ self.0.f_bavail
+ }
+@@ -329,7 +343,7 @@ impl Statfs {
+ target_os = "freebsd",
+ target_os = "openbsd",
+ target_os = "dragonfly",
+- all(target_os = "linux", target_env = "musl")
++ all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32")))
+ )))]
+ pub fn blocks_available(&self) -> libc::c_ulong {
+ self.0.f_bavail
+@@ -354,8 +368,8 @@ impl Statfs {
+ }
+
+ /// Total file nodes in filesystem
+- #[cfg(all(target_os = "linux", target_env = "musl"))]
+- pub fn files(&self) -> u64 {
++ #[cfg(all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))))]
++ pub fn files(&self) -> libc::fsfilcnt_t {
+ self.0.f_files
+ }
+
+@@ -367,14 +381,19 @@ impl Statfs {
+ target_os = "freebsd",
+ target_os = "openbsd",
+ target_os = "dragonfly",
+- all(target_os = "linux", target_env = "musl")
++ all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32")))
+ )))]
+ pub fn files(&self) -> libc::c_ulong {
+ self.0.f_files
+ }
+
+ /// Free file nodes in filesystem
+- #[cfg(any(target_os = "ios", target_os = "macos", target_os = "android"))]
++ #[cfg(any(
++ target_os = "android",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "openbsd"
++ ))]
+ pub fn files_free(&self) -> u64 {
+ self.0.f_ffree
+ }
+@@ -386,14 +405,14 @@ impl Statfs {
+ }
+
+ /// Free file nodes in filesystem
+- #[cfg(any(target_os = "freebsd", target_os = "openbsd"))]
++ #[cfg(target_os = "freebsd")]
+ pub fn files_free(&self) -> i64 {
+ self.0.f_ffree
+ }
+
+ /// Free file nodes in filesystem
+- #[cfg(all(target_os = "linux", target_env = "musl"))]
+- pub fn files_free(&self) -> u64 {
++ #[cfg(all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))))]
++ pub fn files_free(&self) -> libc::fsfilcnt_t {
+ self.0.f_ffree
+ }
+
+@@ -405,7 +424,7 @@ impl Statfs {
+ target_os = "freebsd",
+ target_os = "openbsd",
+ target_os = "dragonfly",
+- all(target_os = "linux", target_env = "musl")
++ all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32")))
+ )))]
+ pub fn files_free(&self) -> libc::c_ulong {
+ self.0.f_ffree
+@@ -434,16 +453,17 @@ impl Debug for Statfs {
+
+ pub fn statfs<P: ?Sized + NixPath>(path: &P) -> Result<Statfs> {
+ unsafe {
+- let mut stat: Statfs = mem::uninitialized();
+- let res = path.with_nix_path(|path| libc::statfs(path.as_ptr(), &mut stat.0))?;
+- Errno::result(res).map(|_| stat)
++ let mut stat = mem::MaybeUninit::<libc::statfs>::uninit();
++ let res = path.with_nix_path(|path| libc::statfs(path.as_ptr(), stat.as_mut_ptr()))?;
++ Errno::result(res).map(|_| Statfs(stat.assume_init()))
+ }
+ }
+
+ pub fn fstatfs<T: AsRawFd>(fd: &T) -> Result<Statfs> {
+ unsafe {
+- let mut stat: Statfs = mem::uninitialized();
+- Errno::result(libc::fstatfs(fd.as_raw_fd(), &mut stat.0)).map(|_| stat)
++ let mut stat = mem::MaybeUninit::<libc::statfs>::uninit();
++ Errno::result(libc::fstatfs(fd.as_raw_fd(), stat.as_mut_ptr()))
++ .map(|_| Statfs(stat.assume_init()))
+ }
+ }
+
+@@ -451,8 +471,8 @@ pub fn fstatfs<T: AsRawFd>(fd: &T) -> Result<Statfs> {
+ mod test {
+ use std::fs::File;
+
+- use sys::statfs::*;
+- use sys::statvfs::*;
++ use crate::sys::statfs::*;
++ use crate::sys::statvfs::*;
+ use std::path::Path;
+
+ #[test]
+diff --git a/third_party/rust/nix/src/sys/statvfs.rs b/third_party/rust/nix/src/sys/statvfs.rs
+index e5980369d5119..9bea9734925f0 100644
+--- a/third_party/rust/nix/src/sys/statvfs.rs
++++ b/third_party/rust/nix/src/sys/statvfs.rs
+@@ -7,9 +7,9 @@ use std::os::unix::io::AsRawFd;
+
+ use libc::{self, c_ulong};
+
+-use {Result, NixPath};
+-use errno::Errno;
++use crate::{Result, NixPath, errno::Errno};
+
++#[cfg(not(target_os = "redox"))]
+ libc_bitflags!(
+ /// File system mount Flags
+ #[repr(C)]
+@@ -55,8 +55,7 @@ libc_bitflags!(
+ /// Wrapper around the POSIX `statvfs` struct
+ ///
+ /// For more information see the [`statvfs(3)` man pages](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_statvfs.h.html).
+-// FIXME: Replace with repr(transparent)
+-#[repr(C)]
++#[repr(transparent)]
+ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+ pub struct Statvfs(libc::statvfs);
+
+@@ -109,6 +108,7 @@ impl Statvfs {
+ }
+
+ /// Get the mount flags
++ #[cfg(not(target_os = "redox"))]
+ pub fn flags(&self) -> FsFlags {
+ FsFlags::from_bits_truncate(self.0.f_flag)
+ }
+@@ -124,12 +124,12 @@ impl Statvfs {
+ pub fn statvfs<P: ?Sized + NixPath>(path: &P) -> Result<Statvfs> {
+ unsafe {
+ Errno::clear();
+- let mut stat: Statvfs = mem::uninitialized();
++ let mut stat = mem::MaybeUninit::<libc::statvfs>::uninit();
+ let res = path.with_nix_path(|path|
+- libc::statvfs(path.as_ptr(), &mut stat.0)
++ libc::statvfs(path.as_ptr(), stat.as_mut_ptr())
+ )?;
+
+- Errno::result(res).map(|_| stat)
++ Errno::result(res).map(|_| Statvfs(stat.assume_init()))
+ }
+ }
+
+@@ -137,15 +137,16 @@ pub fn statvfs<P: ?Sized + NixPath>(path: &P) -> Result<Statvfs> {
+ pub fn fstatvfs<T: AsRawFd>(fd: &T) -> Result<Statvfs> {
+ unsafe {
+ Errno::clear();
+- let mut stat: Statvfs = mem::uninitialized();
+- Errno::result(libc::fstatvfs(fd.as_raw_fd(), &mut stat.0)).map(|_| stat)
++ let mut stat = mem::MaybeUninit::<libc::statvfs>::uninit();
++ Errno::result(libc::fstatvfs(fd.as_raw_fd(), stat.as_mut_ptr()))
++ .map(|_| Statvfs(stat.assume_init()))
+ }
+ }
+
+ #[cfg(test)]
+ mod test {
+ use std::fs::File;
+- use sys::statvfs::*;
++ use crate::sys::statvfs::*;
+
+ #[test]
+ fn statvfs_call() {
+diff --git a/third_party/rust/nix/src/sys/sysinfo.rs b/third_party/rust/nix/src/sys/sysinfo.rs
+index 4c8e38988886d..222a2fc0480c3 100644
+--- a/third_party/rust/nix/src/sys/sysinfo.rs
++++ b/third_party/rust/nix/src/sys/sysinfo.rs
+@@ -2,13 +2,20 @@ use libc::{self, SI_LOAD_SHIFT};
+ use std::{cmp, mem};
+ use std::time::Duration;
+
+-use Result;
+-use errno::Errno;
++use crate::Result;
++use crate::errno::Errno;
+
+ /// System info structure returned by `sysinfo`.
+ #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
++#[repr(transparent)]
+ pub struct SysInfo(libc::sysinfo);
+
++// The fields are c_ulong on 32-bit linux, u64 on 64-bit linux; x32's ulong is u32
++#[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))]
++type mem_blocks_t = u64;
++#[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))]
++type mem_blocks_t = libc::c_ulong;
++
+ impl SysInfo {
+ /// Returns the load average tuple.
+ ///
+@@ -57,7 +64,7 @@ impl SysInfo {
+ self.scale_mem(self.0.freeram)
+ }
+
+- fn scale_mem(&self, units: libc::c_ulong) -> u64 {
++ fn scale_mem(&self, units: mem_blocks_t) -> u64 {
+ units as u64 * self.0.mem_unit as u64
+ }
+ }
+@@ -66,7 +73,7 @@ impl SysInfo {
+ ///
+ /// [See `sysinfo(2)`](http://man7.org/linux/man-pages/man2/sysinfo.2.html).
+ pub fn sysinfo() -> Result<SysInfo> {
+- let mut info: libc::sysinfo = unsafe { mem::uninitialized() };
+- let res = unsafe { libc::sysinfo(&mut info) };
+- Errno::result(res).map(|_| SysInfo(info))
++ let mut info = mem::MaybeUninit::uninit();
++ let res = unsafe { libc::sysinfo(info.as_mut_ptr()) };
++ Errno::result(res).map(|_| unsafe{ SysInfo(info.assume_init()) })
+ }
+diff --git a/third_party/rust/nix/src/sys/termios.rs b/third_party/rust/nix/src/sys/termios.rs
+index c7cdf10b461c1..95148360495f1 100644
+--- a/third_party/rust/nix/src/sys/termios.rs
++++ b/third_party/rust/nix/src/sys/termios.rs
+@@ -25,7 +25,7 @@
+ //! ```
+ //! # use self::nix::sys::termios::SpecialCharacterIndices::VEOF;
+ //! # use self::nix::sys::termios::{_POSIX_VDISABLE, Termios};
+-//! # let mut termios = unsafe { Termios::default_uninit() };
++//! # let mut termios: Termios = unsafe { std::mem::zeroed() };
+ //! termios.control_chars[VEOF as usize] = _POSIX_VDISABLE;
+ //! ```
+ //!
+@@ -38,7 +38,7 @@
+ //!
+ //! ```
+ //! # use self::nix::sys::termios::{ControlFlags, Termios};
+-//! # let mut termios = unsafe { Termios::default_uninit() };
++//! # let mut termios: Termios = unsafe { std::mem::zeroed() };
+ //! termios.control_flags & ControlFlags::CSIZE == ControlFlags::CS5;
+ //! termios.control_flags |= ControlFlags::CS5;
+ //! ```
+@@ -61,10 +61,9 @@
+ //! platforms:
+ //!
+ //! ```rust
+-//! # #[macro_use] extern crate nix;
+ //! # use nix::sys::termios::{BaudRate, cfsetispeed, cfsetospeed, cfsetspeed, Termios};
+ //! # fn main() {
+-//! # let mut t = unsafe { Termios::default_uninit() };
++//! # let mut t: Termios = unsafe { std::mem::zeroed() };
+ //! cfsetispeed(&mut t, BaudRate::B9600);
+ //! cfsetospeed(&mut t, BaudRate::B9600);
+ //! cfsetspeed(&mut t, BaudRate::B9600);
+@@ -74,102 +73,94 @@
+ //! Additionally round-tripping baud rates is consistent across platforms:
+ //!
+ //! ```rust
+-//! # extern crate nix;
+ //! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetispeed, cfsetspeed, Termios};
+ //! # fn main() {
+-//! # let mut t = unsafe { Termios::default_uninit() };
++//! # let mut t: Termios = unsafe { std::mem::zeroed() };
+ //! # cfsetspeed(&mut t, BaudRate::B9600);
+ //! let speed = cfgetispeed(&t);
+-//! assert!(speed == cfgetospeed(&t));
++//! assert_eq!(speed, cfgetospeed(&t));
+ //! cfsetispeed(&mut t, speed);
+ //! # }
+ //! ```
+ //!
+ //! On non-BSDs, `cfgetispeed()` and `cfgetospeed()` both return a `BaudRate`:
+ //!
+-// FIXME: Replace `ignore` with `compile_fail` once 1.22 is the minimum support Rust version
+ #![cfg_attr(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
+ target_os = "macos", target_os = "netbsd", target_os = "openbsd"),
+ doc = " ```rust,ignore")]
+ #![cfg_attr(not(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
+ target_os = "macos", target_os = "netbsd", target_os = "openbsd")),
+ doc = " ```rust")]
+-//! # extern crate nix;
+ //! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetspeed, Termios};
+ //! # fn main() {
+-//! # let mut t = unsafe { Termios::default_uninit() };
++//! # let mut t: Termios = unsafe { std::mem::zeroed() };
+ //! # cfsetspeed(&mut t, BaudRate::B9600);
+-//! assert!(cfgetispeed(&t) == BaudRate::B9600);
+-//! assert!(cfgetospeed(&t) == BaudRate::B9600);
++//! assert_eq!(cfgetispeed(&t), BaudRate::B9600);
++//! assert_eq!(cfgetospeed(&t), BaudRate::B9600);
+ //! # }
+ //! ```
+ //!
+ //! But on the BSDs, `cfgetispeed()` and `cfgetospeed()` both return `u32`s:
+ //!
+-// FIXME: Replace `ignore` with `compile_fail` once 1.22 is the minimum support Rust version
+ #![cfg_attr(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
+ target_os = "macos", target_os = "netbsd", target_os = "openbsd"),
+ doc = " ```rust")]
+ #![cfg_attr(not(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
+ target_os = "macos", target_os = "netbsd", target_os = "openbsd")),
+ doc = " ```rust,ignore")]
+-//! # extern crate nix;
+ //! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetspeed, Termios};
+ //! # fn main() {
+-//! # let mut t = unsafe { Termios::default_uninit() };
++//! # let mut t: Termios = unsafe { std::mem::zeroed() };
+ //! # cfsetspeed(&mut t, 9600u32);
+-//! assert!(cfgetispeed(&t) == 9600u32);
+-//! assert!(cfgetospeed(&t) == 9600u32);
++//! assert_eq!(cfgetispeed(&t), 9600u32);
++//! assert_eq!(cfgetospeed(&t), 9600u32);
+ //! # }
+ //! ```
+ //!
+ //! It's trivial to convert from a `BaudRate` to a `u32` on BSDs:
+ //!
+-// FIXME: Replace `ignore` with `compile_fail` once 1.22 is the minimum support Rust version
+ #![cfg_attr(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
+ target_os = "macos", target_os = "netbsd", target_os = "openbsd"),
+ doc = " ```rust")]
+ #![cfg_attr(not(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
+ target_os = "macos", target_os = "netbsd", target_os = "openbsd")),
+ doc = " ```rust,ignore")]
+-//! # extern crate nix;
+ //! # use nix::sys::termios::{BaudRate, cfgetispeed, cfsetspeed, Termios};
+ //! # fn main() {
+-//! # let mut t = unsafe { Termios::default_uninit() };
++//! # let mut t: Termios = unsafe { std::mem::zeroed() };
+ //! # cfsetspeed(&mut t, 9600u32);
+-//! assert!(cfgetispeed(&t) == BaudRate::B9600.into());
+-//! assert!(u32::from(BaudRate::B9600) == 9600u32);
++//! assert_eq!(cfgetispeed(&t), BaudRate::B9600.into());
++//! assert_eq!(u32::from(BaudRate::B9600), 9600u32);
+ //! # }
+ //! ```
+ //!
+ //! And on BSDs you can specify arbitrary baud rates (**note** this depends on hardware support)
+ //! by specifying baud rates directly using `u32`s:
+ //!
+-// FIXME: Replace `ignore` with `compile_fail` once 1.22 is the minimum support Rust version
+ #![cfg_attr(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
+ target_os = "macos", target_os = "netbsd", target_os = "openbsd"),
+ doc = " ```rust")]
+ #![cfg_attr(not(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
+ target_os = "macos", target_os = "netbsd", target_os = "openbsd")),
+ doc = " ```rust,ignore")]
+-//! # extern crate nix;
+ //! # use nix::sys::termios::{cfsetispeed, cfsetospeed, cfsetspeed, Termios};
+ //! # fn main() {
+-//! # let mut t = unsafe { Termios::default_uninit() };
++//! # let mut t: Termios = unsafe { std::mem::zeroed() };
+ //! cfsetispeed(&mut t, 9600u32);
+ //! cfsetospeed(&mut t, 9600u32);
+ //! cfsetspeed(&mut t, 9600u32);
+ //! # }
+ //! ```
+-use Result;
+-use errno::Errno;
++use cfg_if::cfg_if;
++use crate::{Error, Result};
++use crate::errno::Errno;
+ use libc::{self, c_int, tcflag_t};
+ use std::cell::{Ref, RefCell};
+-use std::convert::From;
++use std::convert::{From, TryFrom};
+ use std::mem;
+ use std::os::unix::io::RawFd;
+
+-use ::unistd::Pid;
++use crate::unistd::Pid;
+
+ /// Stores settings for the termios API
+ ///
+@@ -194,24 +185,9 @@ pub struct Termios {
+ impl Termios {
+ /// Exposes an immutable reference to the underlying `libc::termios` data structure.
+ ///
+- /// This can be used for interfacing with other FFI functions like:
+- ///
+- /// ```rust
+- /// # extern crate libc;
+- /// # extern crate nix;
+- /// # fn main() {
+- /// # use nix::sys::termios::Termios;
+- /// # let mut termios = unsafe { Termios::default_uninit() };
+- /// let inner_termios = termios.get_libc_termios();
+- /// unsafe { libc::cfgetispeed(&*inner_termios) };
+- /// # }
+- /// ```
+- ///
+- /// There is no public API exposed for functions that modify the underlying `libc::termios`
+- /// data because it requires additional work to maintain type safety.
+- // FIXME: Switch this over to use pub(crate)
+- #[doc(hidden)]
+- pub fn get_libc_termios(&self) -> Ref<libc::termios> {
++ /// This is not part of `nix`'s public API because it requires additional work to maintain type
++ /// safety.
++ pub(crate) fn get_libc_termios(&self) -> Ref<libc::termios> {
+ {
+ let mut termios = self.inner.borrow_mut();
+ termios.c_iflag = self.input_flags.bits();
+@@ -225,12 +201,11 @@ impl Termios {
+
+ /// Exposes the inner `libc::termios` datastore within `Termios`.
+ ///
+- /// This is unsafe because if this is used to modify the inner libc::termios struct, it will not
+- /// automatically update the safe wrapper type around it. Therefore we disable docs to
+- /// effectively limit its use to nix internals. In this case it should also be paired with a
+- /// call to `update_wrapper()` so that the wrapper-type and internal representation stay
+- /// consistent.
+- unsafe fn get_libc_termios_mut(&mut self) -> *mut libc::termios {
++ /// This is unsafe because if this is used to modify the inner `libc::termios` struct, it will
++ /// not automatically update the safe wrapper type around it. In this case it should also be
++ /// paired with a call to `update_wrapper()` so that the wrapper-type and internal
++ /// representation stay consistent.
++ pub(crate) unsafe fn get_libc_termios_mut(&mut self) -> *mut libc::termios {
+ {
+ let mut termios = self.inner.borrow_mut();
+ termios.c_iflag = self.input_flags.bits();
+@@ -242,26 +217,8 @@ impl Termios {
+ self.inner.as_ptr()
+ }
+
+- /// Allows for easily creating new `Termios` structs that will be overwritten with real data.
+- ///
+- /// This should only be used when the inner libc::termios struct will be overwritten before it's
+- /// read.
+- // FIXME: Switch this over to use pub(crate)
+- #[doc(hidden)]
+- pub unsafe fn default_uninit() -> Self {
+- Termios {
+- inner: RefCell::new(mem::uninitialized()),
+- input_flags: InputFlags::empty(),
+- output_flags: OutputFlags::empty(),
+- control_flags: ControlFlags::empty(),
+- local_flags: LocalFlags::empty(),
+- control_chars: [0 as libc::cc_t; NCCS],
+- }
+- }
+-
+ /// Updates the wrapper values from the internal `libc::termios` data structure.
+- #[doc(hidden)]
+- pub fn update_wrapper(&mut self) {
++ pub(crate) fn update_wrapper(&mut self) {
+ let termios = *self.inner.borrow_mut();
+ self.input_flags = InputFlags::from_bits_truncate(termios.c_iflag);
+ self.output_flags = OutputFlags::from_bits_truncate(termios.c_oflag);
+@@ -376,9 +333,10 @@ libc_enum!{
+ }
+ }
+
+-impl From<libc::speed_t> for BaudRate {
+- fn from(s: libc::speed_t) -> BaudRate {
++impl TryFrom<libc::speed_t> for BaudRate {
++ type Error = Error;
+
++ fn try_from(s: libc::speed_t) -> Result<BaudRate> {
+ use libc::{B0, B50, B75, B110, B134, B150, B200, B300, B600, B1200, B1800, B2400, B4800,
+ B9600, B19200, B38400, B57600, B115200, B230400};
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+@@ -398,85 +356,84 @@ impl From<libc::speed_t> for BaudRate {
+ use libc::{B460800, B921600};
+
+ match s {
+- B0 => BaudRate::B0,
+- B50 => BaudRate::B50,
+- B75 => BaudRate::B75,
+- B110 => BaudRate::B110,
+- B134 => BaudRate::B134,
+- B150 => BaudRate::B150,
+- B200 => BaudRate::B200,
+- B300 => BaudRate::B300,
+- B600 => BaudRate::B600,
+- B1200 => BaudRate::B1200,
+- B1800 => BaudRate::B1800,
+- B2400 => BaudRate::B2400,
+- B4800 => BaudRate::B4800,
++ B0 => Ok(BaudRate::B0),
++ B50 => Ok(BaudRate::B50),
++ B75 => Ok(BaudRate::B75),
++ B110 => Ok(BaudRate::B110),
++ B134 => Ok(BaudRate::B134),
++ B150 => Ok(BaudRate::B150),
++ B200 => Ok(BaudRate::B200),
++ B300 => Ok(BaudRate::B300),
++ B600 => Ok(BaudRate::B600),
++ B1200 => Ok(BaudRate::B1200),
++ B1800 => Ok(BaudRate::B1800),
++ B2400 => Ok(BaudRate::B2400),
++ B4800 => Ok(BaudRate::B4800),
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+- B7200 => BaudRate::B7200,
+- B9600 => BaudRate::B9600,
++ B7200 => Ok(BaudRate::B7200),
++ B9600 => Ok(BaudRate::B9600),
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+- B14400 => BaudRate::B14400,
+- B19200 => BaudRate::B19200,
++ B14400 => Ok(BaudRate::B14400),
++ B19200 => Ok(BaudRate::B19200),
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+- B28800 => BaudRate::B28800,
+- B38400 => BaudRate::B38400,
+- B57600 => BaudRate::B57600,
++ B28800 => Ok(BaudRate::B28800),
++ B38400 => Ok(BaudRate::B38400),
++ B57600 => Ok(BaudRate::B57600),
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+- B76800 => BaudRate::B76800,
+- B115200 => BaudRate::B115200,
+- B230400 => BaudRate::B230400,
++ B76800 => Ok(BaudRate::B76800),
++ B115200 => Ok(BaudRate::B115200),
++ B230400 => Ok(BaudRate::B230400),
+ #[cfg(any(target_os = "android",
+ target_os = "freebsd",
+ target_os = "linux",
+ target_os = "netbsd"))]
+- B460800 => BaudRate::B460800,
++ B460800 => Ok(BaudRate::B460800),
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+- B500000 => BaudRate::B500000,
++ B500000 => Ok(BaudRate::B500000),
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+- B576000 => BaudRate::B576000,
++ B576000 => Ok(BaudRate::B576000),
+ #[cfg(any(target_os = "android",
+ target_os = "freebsd",
+ target_os = "linux",
+ target_os = "netbsd"))]
+- B921600 => BaudRate::B921600,
++ B921600 => Ok(BaudRate::B921600),
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+- B1000000 => BaudRate::B1000000,
++ B1000000 => Ok(BaudRate::B1000000),
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+- B1152000 => BaudRate::B1152000,
++ B1152000 => Ok(BaudRate::B1152000),
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+- B1500000 => BaudRate::B1500000,
++ B1500000 => Ok(BaudRate::B1500000),
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+- B2000000 => BaudRate::B2000000,
++ B2000000 => Ok(BaudRate::B2000000),
+ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
+- B2500000 => BaudRate::B2500000,
++ B2500000 => Ok(BaudRate::B2500000),
+ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
+- B3000000 => BaudRate::B3000000,
++ B3000000 => Ok(BaudRate::B3000000),
+ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
+- B3500000 => BaudRate::B3500000,
++ B3500000 => Ok(BaudRate::B3500000),
+ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
+- B4000000 => BaudRate::B4000000,
+- b => unreachable!("Invalid baud constant: {}", b),
++ B4000000 => Ok(BaudRate::B4000000),
++ _ => Err(Error::invalid_argument())
+ }
+ }
+ }
+
+-// TODO: Include `TryFrom<u32> for BaudRate` once that API stabilizes
+ #[cfg(any(target_os = "freebsd",
+ target_os = "dragonfly",
+ target_os = "ios",
+@@ -583,6 +540,12 @@ libc_enum! {
+ }
+ }
+
++#[cfg(all(target_os = "linux", target_arch = "sparc64"))]
++impl SpecialCharacterIndices {
++ pub const VMIN: SpecialCharacterIndices = SpecialCharacterIndices::VEOF;
++ pub const VTIME: SpecialCharacterIndices = SpecialCharacterIndices::VEOL;
++}
++
+ pub use libc::NCCS;
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+@@ -606,7 +569,9 @@ libc_bitflags! {
+ ICRNL;
+ IXON;
+ IXOFF;
++ #[cfg(not(target_os = "redox"))]
+ IXANY;
++ #[cfg(not(target_os = "redox"))]
+ IMAXBEL;
+ #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))]
+ IUTF8;
+@@ -816,6 +781,7 @@ libc_bitflags! {
+ PARODD;
+ HUPCL;
+ CLOCAL;
++ #[cfg(not(target_os = "redox"))]
+ CRTSCTS;
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ CBAUD;
+@@ -866,12 +832,15 @@ libc_bitflags! {
+ libc_bitflags! {
+ /// Flags for setting any local modes
+ pub struct LocalFlags: tcflag_t {
++ #[cfg(not(target_os = "redox"))]
+ ECHOKE;
+ ECHOE;
+ ECHOK;
+ ECHO;
+ ECHONL;
++ #[cfg(not(target_os = "redox"))]
+ ECHOPRT;
++ #[cfg(not(target_os = "redox"))]
+ ECHOCTL;
+ ISIG;
+ ICANON;
+@@ -883,8 +852,10 @@ libc_bitflags! {
+ target_os = "openbsd"))]
+ ALTWERASE;
+ IEXTEN;
++ #[cfg(not(target_os = "redox"))]
+ EXTPROC;
+ TOSTOP;
++ #[cfg(not(target_os = "redox"))]
+ FLUSHO;
+ #[cfg(any(target_os = "freebsd",
+ target_os = "dragonfly",
+@@ -893,6 +864,7 @@ libc_bitflags! {
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ NOKERNINFO;
++ #[cfg(not(target_os = "redox"))]
+ PENDIN;
+ NOFLSH;
+ }
+@@ -957,13 +929,15 @@ cfg_if!{
+ Errno::result(res).map(drop)
+ }
+ } else {
++ use std::convert::TryInto;
++
+ /// Get input baud rate (see
+ /// [cfgetispeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetispeed.html)).
+ ///
+ /// `cfgetispeed()` extracts the input baud rate from the given `Termios` structure.
+ pub fn cfgetispeed(termios: &Termios) -> BaudRate {
+ let inner_termios = termios.get_libc_termios();
+- unsafe { libc::cfgetispeed(&*inner_termios) }.into()
++ unsafe { libc::cfgetispeed(&*inner_termios) }.try_into().unwrap()
+ }
+
+ /// Get output baud rate (see
+@@ -972,7 +946,7 @@ cfg_if!{
+ /// `cfgetospeed()` extracts the output baud rate from the given `Termios` structure.
+ pub fn cfgetospeed(termios: &Termios) -> BaudRate {
+ let inner_termios = termios.get_libc_termios();
+- unsafe { libc::cfgetospeed(&*inner_termios) }.into()
++ unsafe { libc::cfgetospeed(&*inner_termios) }.try_into().unwrap()
+ }
+
+ /// Set input baud rate (see
+@@ -1045,13 +1019,13 @@ pub fn cfmakesane(termios: &mut Termios) {
+ /// this structure *will not* reconfigure the port, instead the modifications should be done to
+ /// the `Termios` structure and then the port should be reconfigured using `tcsetattr()`.
+ pub fn tcgetattr(fd: RawFd) -> Result<Termios> {
+- let mut termios: libc::termios = unsafe { mem::uninitialized() };
++ let mut termios = mem::MaybeUninit::uninit();
+
+- let res = unsafe { libc::tcgetattr(fd, &mut termios) };
++ let res = unsafe { libc::tcgetattr(fd, termios.as_mut_ptr()) };
+
+ Errno::result(res)?;
+
+- Ok(termios.into())
++ unsafe { Ok(termios.assume_init().into()) }
+ }
+
+ /// Set the configuration for a terminal (see
+@@ -1105,3 +1079,14 @@ pub fn tcgetsid(fd: RawFd) -> Result<Pid> {
+
+ Errno::result(res).map(Pid::from_raw)
+ }
++
++#[cfg(test)]
++mod test {
++ use super::*;
++
++ #[test]
++ fn try_from() {
++ assert_eq!(Ok(BaudRate::B0), BaudRate::try_from(libc::B0));
++ assert!(BaudRate::try_from(999999999).is_err());
++ }
++}
+diff --git a/third_party/rust/nix/src/sys/time.rs b/third_party/rust/nix/src/sys/time.rs
+index 3ad57543b18a7..7546d1b367c5e 100644
+--- a/third_party/rust/nix/src/sys/time.rs
++++ b/third_party/rust/nix/src/sys/time.rs
+@@ -1,6 +1,8 @@
+ use std::{cmp, fmt, ops};
++use std::time::Duration;
+ use std::convert::From;
+-use libc::{c_long, timespec, timeval};
++use libc::{timespec, timeval};
++#[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
+ pub use libc::{time_t, suseconds_t};
+
+ pub trait TimeValLike: Sized {
+@@ -60,6 +62,34 @@ const TS_MAX_SECONDS: i64 = ::std::isize::MAX as i64;
+
+ const TS_MIN_SECONDS: i64 = -TS_MAX_SECONDS;
+
++// x32 compatibility
++// See https://sourceware.org/bugzilla/show_bug.cgi?id=16437
++#[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))]
++type timespec_tv_nsec_t = i64;
++#[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))]
++type timespec_tv_nsec_t = libc::c_long;
++
++impl From<timespec> for TimeSpec {
++ fn from(ts: timespec) -> Self {
++ Self(ts)
++ }
++}
++
++impl From<Duration> for TimeSpec {
++ fn from(duration: Duration) -> Self {
++ #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
++ TimeSpec(timespec {
++ tv_sec: duration.as_secs() as time_t,
++ tv_nsec: duration.subsec_nanos() as timespec_tv_nsec_t
++ })
++ }
++}
++
++impl From<TimeSpec> for Duration {
++ fn from(timespec: TimeSpec) -> Self {
++ Duration::new(timespec.0.tv_sec as u64, timespec.0.tv_nsec as u32)
++ }
++}
+
+ impl AsRef<timespec> for TimeSpec {
+ fn as_ref(&self) -> &timespec {
+@@ -67,6 +97,12 @@ impl AsRef<timespec> for TimeSpec {
+ }
+ }
+
++impl AsMut<timespec> for TimeSpec {
++ fn as_mut(&mut self) -> &mut timespec {
++ &mut self.0
++ }
++}
++
+ impl Ord for TimeSpec {
+ // The implementation of cmp is simplified by assuming that the struct is
+ // normalized. That is, tv_nsec must always be within [0, 1_000_000_000)
+@@ -90,6 +126,7 @@ impl TimeValLike for TimeSpec {
+ fn seconds(seconds: i64) -> TimeSpec {
+ assert!(seconds >= TS_MIN_SECONDS && seconds <= TS_MAX_SECONDS,
+ "TimeSpec out of bounds; seconds={}", seconds);
++ #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
+ TimeSpec(timespec {tv_sec: seconds as time_t, tv_nsec: 0 })
+ }
+
+@@ -116,8 +153,9 @@ impl TimeValLike for TimeSpec {
+ let (secs, nanos) = div_mod_floor_64(nanoseconds, NANOS_PER_SEC);
+ assert!(secs >= TS_MIN_SECONDS && secs <= TS_MAX_SECONDS,
+ "TimeSpec out of bounds");
++ #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
+ TimeSpec(timespec {tv_sec: secs as time_t,
+- tv_nsec: nanos as c_long })
++ tv_nsec: nanos as timespec_tv_nsec_t })
+ }
+
+ fn num_seconds(&self) -> i64 {
+@@ -144,19 +182,20 @@ impl TimeValLike for TimeSpec {
+ }
+
+ impl TimeSpec {
+- fn nanos_mod_sec(&self) -> c_long {
++ fn nanos_mod_sec(&self) -> timespec_tv_nsec_t {
+ if self.tv_sec() < 0 && self.tv_nsec() > 0 {
+- self.tv_nsec() - NANOS_PER_SEC as c_long
++ self.tv_nsec() - NANOS_PER_SEC as timespec_tv_nsec_t
+ } else {
+ self.tv_nsec()
+ }
+ }
+
++ #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
+ pub fn tv_sec(&self) -> time_t {
+ self.0.tv_sec
+ }
+
+- pub fn tv_nsec(&self) -> c_long {
++ pub fn tv_nsec(&self) -> timespec_tv_nsec_t {
+ self.0.tv_nsec
+ }
+ }
+@@ -191,7 +230,7 @@ impl ops::Mul<i32> for TimeSpec {
+ type Output = TimeSpec;
+
+ fn mul(self, rhs: i32) -> TimeSpec {
+- let usec = self.num_nanoseconds().checked_mul(rhs as i64)
++ let usec = self.num_nanoseconds().checked_mul(i64::from(rhs))
+ .expect("TimeSpec multiply out of bounds");
+
+ TimeSpec::nanoseconds(usec)
+@@ -202,7 +241,7 @@ impl ops::Div<i32> for TimeSpec {
+ type Output = TimeSpec;
+
+ fn div(self, rhs: i32) -> TimeSpec {
+- let usec = self.num_nanoseconds() / rhs as i64;
++ let usec = self.num_nanoseconds() / i64::from(rhs);
+ TimeSpec::nanoseconds(usec)
+ }
+ }
+@@ -239,7 +278,7 @@ impl fmt::Display for TimeSpec {
+
+
+
+-#[repr(C)]
++#[repr(transparent)]
+ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+ pub struct TimeVal(timeval);
+
+@@ -259,6 +298,12 @@ impl AsRef<timeval> for TimeVal {
+ }
+ }
+
++impl AsMut<timeval> for TimeVal {
++ fn as_mut(&mut self) -> &mut timeval {
++ &mut self.0
++ }
++}
++
+ impl Ord for TimeVal {
+ // The implementation of cmp is simplified by assuming that the struct is
+ // normalized. That is, tv_usec must always be within [0, 1_000_000)
+@@ -282,6 +327,7 @@ impl TimeValLike for TimeVal {
+ fn seconds(seconds: i64) -> TimeVal {
+ assert!(seconds >= TV_MIN_SECONDS && seconds <= TV_MAX_SECONDS,
+ "TimeVal out of bounds; seconds={}", seconds);
++ #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
+ TimeVal(timeval {tv_sec: seconds as time_t, tv_usec: 0 })
+ }
+
+@@ -299,6 +345,7 @@ impl TimeValLike for TimeVal {
+ let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
+ assert!(secs >= TV_MIN_SECONDS && secs <= TV_MAX_SECONDS,
+ "TimeVal out of bounds");
++ #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
+ TimeVal(timeval {tv_sec: secs as time_t,
+ tv_usec: micros as suseconds_t })
+ }
+@@ -311,6 +358,7 @@ impl TimeValLike for TimeVal {
+ let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
+ assert!(secs >= TV_MIN_SECONDS && secs <= TV_MAX_SECONDS,
+ "TimeVal out of bounds");
++ #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
+ TimeVal(timeval {tv_sec: secs as time_t,
+ tv_usec: micros as suseconds_t })
+ }
+@@ -347,6 +395,7 @@ impl TimeVal {
+ }
+ }
+
++ #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
+ pub fn tv_sec(&self) -> time_t {
+ self.0.tv_sec
+ }
+@@ -386,7 +435,7 @@ impl ops::Mul<i32> for TimeVal {
+ type Output = TimeVal;
+
+ fn mul(self, rhs: i32) -> TimeVal {
+- let usec = self.num_microseconds().checked_mul(rhs as i64)
++ let usec = self.num_microseconds().checked_mul(i64::from(rhs))
+ .expect("TimeVal multiply out of bounds");
+
+ TimeVal::microseconds(usec)
+@@ -397,7 +446,7 @@ impl ops::Div<i32> for TimeVal {
+ type Output = TimeVal;
+
+ fn div(self, rhs: i32) -> TimeVal {
+- let usec = self.num_microseconds() / rhs as i64;
++ let usec = self.num_microseconds() / i64::from(rhs);
+ TimeVal::microseconds(usec)
+ }
+ }
+@@ -467,6 +516,7 @@ fn div_rem_64(this: i64, other: i64) -> (i64, i64) {
+ #[cfg(test)]
+ mod test {
+ use super::{TimeSpec, TimeVal, TimeValLike};
++ use std::time::Duration;
+
+ #[test]
+ pub fn test_timespec() {
+@@ -477,6 +527,15 @@ mod test {
+ TimeSpec::seconds(182));
+ }
+
++ #[test]
++ pub fn test_timespec_from() {
++ let duration = Duration::new(123, 123_456_789);
++ let timespec = TimeSpec::nanoseconds(123_123_456_789);
++
++ assert_eq!(TimeSpec::from(duration), timespec);
++ assert_eq!(Duration::from(timespec), duration);
++ }
++
+ #[test]
+ pub fn test_timespec_neg() {
+ let a = TimeSpec::seconds(1) + TimeSpec::nanoseconds(123);
+diff --git a/third_party/rust/nix/src/sys/timerfd.rs b/third_party/rust/nix/src/sys/timerfd.rs
+new file mode 100644
+index 0000000000000..4a24719498602
+--- /dev/null
++++ b/third_party/rust/nix/src/sys/timerfd.rs
+@@ -0,0 +1,285 @@
++//! Timer API via file descriptors.
++//!
++//! Timer FD is a Linux-only API to create timers and get expiration
++//! notifications through file descriptors.
++//!
++//! For more documentation, please read [timerfd_create(2)](http://man7.org/linux/man-pages/man2/timerfd_create.2.html).
++//!
++//! # Examples
++//!
++//! Create a new one-shot timer that expires after 1 second.
++//! ```
++//! # use std::os::unix::io::AsRawFd;
++//! # use nix::sys::timerfd::{TimerFd, ClockId, TimerFlags, TimerSetTimeFlags,
++//! # Expiration};
++//! # use nix::sys::time::{TimeSpec, TimeValLike};
++//! # use nix::unistd::read;
++//! #
++//! // We create a new monotonic timer.
++//! let timer = TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty())
++//! .unwrap();
++//!
++//! // We set a new one-shot timer in 1 seconds.
++//! timer.set(
++//! Expiration::OneShot(TimeSpec::seconds(1)),
++//! TimerSetTimeFlags::empty()
++//! ).unwrap();
++//!
++//! // We wait for the timer to expire.
++//! timer.wait().unwrap();
++//! ```
++use crate::sys::time::TimeSpec;
++use crate::unistd::read;
++use crate::{errno::Errno, Error, Result};
++use bitflags::bitflags;
++use libc::c_int;
++use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
++
++/// A timerfd instance. This is also a file descriptor, you can feed it to
++/// other interfaces consuming file descriptors, epoll for example.
++#[derive(Debug)]
++pub struct TimerFd {
++ fd: RawFd,
++}
++
++impl AsRawFd for TimerFd {
++ fn as_raw_fd(&self) -> RawFd {
++ self.fd
++ }
++}
++
++impl FromRawFd for TimerFd {
++ unsafe fn from_raw_fd(fd: RawFd) -> Self {
++ TimerFd { fd }
++ }
++}
++
++libc_enum! {
++ /// The type of the clock used to mark the progress of the timer. For more
++ /// details on each kind of clock, please refer to [timerfd_create(2)](http://man7.org/linux/man-pages/man2/timerfd_create.2.html).
++ #[repr(i32)]
++ pub enum ClockId {
++ CLOCK_REALTIME,
++ CLOCK_MONOTONIC,
++ CLOCK_BOOTTIME,
++ CLOCK_REALTIME_ALARM,
++ CLOCK_BOOTTIME_ALARM,
++ }
++}
++
++libc_bitflags! {
++ /// Additional flags to change the behaviour of the file descriptor at the
++ /// time of creation.
++ pub struct TimerFlags: c_int {
++ TFD_NONBLOCK;
++ TFD_CLOEXEC;
++ }
++}
++
++bitflags! {
++ /// Flags that are used for arming the timer.
++ pub struct TimerSetTimeFlags: libc::c_int {
++ const TFD_TIMER_ABSTIME = libc::TFD_TIMER_ABSTIME;
++ }
++}
++
++#[derive(Debug, Clone, Copy)]
++struct TimerSpec(libc::itimerspec);
++
++impl TimerSpec {
++ pub fn none() -> Self {
++ Self(libc::itimerspec {
++ it_interval: libc::timespec {
++ tv_sec: 0,
++ tv_nsec: 0,
++ },
++ it_value: libc::timespec {
++ tv_sec: 0,
++ tv_nsec: 0,
++ },
++ })
++ }
++}
++
++impl AsRef<libc::itimerspec> for TimerSpec {
++ fn as_ref(&self) -> &libc::itimerspec {
++ &self.0
++ }
++}
++
++impl From<Expiration> for TimerSpec {
++ fn from(expiration: Expiration) -> TimerSpec {
++ match expiration {
++ Expiration::OneShot(t) => TimerSpec(libc::itimerspec {
++ it_interval: libc::timespec {
++ tv_sec: 0,
++ tv_nsec: 0,
++ },
++ it_value: *t.as_ref(),
++ }),
++ Expiration::IntervalDelayed(start, interval) => TimerSpec(libc::itimerspec {
++ it_interval: *interval.as_ref(),
++ it_value: *start.as_ref(),
++ }),
++ Expiration::Interval(t) => TimerSpec(libc::itimerspec {
++ it_interval: *t.as_ref(),
++ it_value: *t.as_ref(),
++ }),
++ }
++ }
++}
++
++impl From<TimerSpec> for Expiration {
++ fn from(timerspec: TimerSpec) -> Expiration {
++ match timerspec {
++ TimerSpec(libc::itimerspec {
++ it_interval:
++ libc::timespec {
++ tv_sec: 0,
++ tv_nsec: 0,
++ },
++ it_value: ts,
++ }) => Expiration::OneShot(ts.into()),
++ TimerSpec(libc::itimerspec {
++ it_interval: int_ts,
++ it_value: val_ts,
++ }) => {
++ if (int_ts.tv_sec == val_ts.tv_sec) && (int_ts.tv_nsec == val_ts.tv_nsec) {
++ Expiration::Interval(int_ts.into())
++ } else {
++ Expiration::IntervalDelayed(val_ts.into(), int_ts.into())
++ }
++ }
++ }
++ }
++}
++
++/// An enumeration allowing the definition of the expiration time of an alarm,
++/// recurring or not.
++#[derive(Debug, Clone, Copy, PartialEq)]
++pub enum Expiration {
++ OneShot(TimeSpec),
++ IntervalDelayed(TimeSpec, TimeSpec),
++ Interval(TimeSpec),
++}
++
++impl TimerFd {
++ /// Creates a new timer based on the clock defined by `clockid`. The
++ /// underlying fd can be assigned specific flags with `flags` (CLOEXEC,
++ /// NONBLOCK). The underlying fd will be closed on drop.
++ pub fn new(clockid: ClockId, flags: TimerFlags) -> Result<Self> {
++ Errno::result(unsafe { libc::timerfd_create(clockid as i32, flags.bits()) })
++ .map(|fd| Self { fd })
++ }
++
++ /// Sets a new alarm on the timer.
++ ///
++ /// # Types of alarm
++ ///
++ /// There are 3 types of alarms you can set:
++ ///
++ /// - one shot: the alarm will trigger once after the specified amount of
++ /// time.
++ /// Example: I want an alarm to go off in 60s and then disables itself.
++ ///
++ /// - interval: the alarm will trigger every specified interval of time.
++ /// Example: I want an alarm to go off every 60s. The alarm will first
++ /// go off 60s after I set it and every 60s after that. The alarm will
++ /// not disable itself.
++ ///
++ /// - interval delayed: the alarm will trigger after a certain amount of
++ /// time and then trigger at a specified interval.
++ /// Example: I want an alarm to go off every 60s but only start in 1h.
++ /// The alarm will first trigger 1h after I set it and then every 60s
++ /// after that. The alarm will not disable itself.
++ ///
++ /// # Relative vs absolute alarm
++ ///
++ /// If you do not set any `TimerSetTimeFlags`, then the `TimeSpec` you pass
++ /// to the `Expiration` you want is relative. If however you want an alarm
++ /// to go off at a certain point in time, you can set `TFD_TIMER_ABSTIME`.
++ /// Then the one shot TimeSpec and the delay TimeSpec of the delayed
++ /// interval are going to be interpreted as absolute.
++ ///
++ /// # Disabling alarms
++ ///
++ /// Note: Only one alarm can be set for any given timer. Setting a new alarm
++ /// actually removes the previous one.
++ ///
++ /// Note: Setting a one shot alarm with a 0s TimeSpec disables the alarm
++ /// altogether.
++ pub fn set(&self, expiration: Expiration, flags: TimerSetTimeFlags) -> Result<()> {
++ let timerspec: TimerSpec = expiration.into();
++ Errno::result(unsafe {
++ libc::timerfd_settime(
++ self.fd,
++ flags.bits(),
++ timerspec.as_ref(),
++ std::ptr::null_mut(),
++ )
++ })
++ .map(drop)
++ }
++
++ /// Get the parameters for the alarm currently set, if any.
++ pub fn get(&self) -> Result<Option<Expiration>> {
++ let mut timerspec = TimerSpec::none();
++ let timerspec_ptr: *mut libc::itimerspec = &mut timerspec.0;
++
++ Errno::result(unsafe { libc::timerfd_gettime(self.fd, timerspec_ptr) }).map(|_| {
++ if timerspec.0.it_interval.tv_sec == 0
++ && timerspec.0.it_interval.tv_nsec == 0
++ && timerspec.0.it_value.tv_sec == 0
++ && timerspec.0.it_value.tv_nsec == 0
++ {
++ None
++ } else {
++ Some(timerspec.into())
++ }
++ })
++ }
++
++ /// Remove the alarm if any is set.
++ pub fn unset(&self) -> Result<()> {
++ Errno::result(unsafe {
++ libc::timerfd_settime(
++ self.fd,
++ TimerSetTimeFlags::empty().bits(),
++ TimerSpec::none().as_ref(),
++ std::ptr::null_mut(),
++ )
++ })
++ .map(drop)
++ }
++
++ /// Wait for the configured alarm to expire.
++ ///
++ /// Note: If the alarm is unset, then you will wait forever.
++ pub fn wait(&self) -> Result<()> {
++ loop {
++ if let Err(e) = read(self.fd, &mut [0u8; 8]) {
++ match e {
++ Error::Sys(Errno::EINTR) => continue,
++ _ => return Err(e),
++ }
++ } else {
++ break;
++ }
++ }
++
++ Ok(())
++ }
++}
++
++impl Drop for TimerFd {
++ fn drop(&mut self) {
++ if !std::thread::panicking() {
++ let result = Errno::result(unsafe {
++ libc::close(self.fd)
++ });
++ if let Err(Error::Sys(Errno::EBADF)) = result {
++ panic!("close of TimerFd encountered EBADF");
++ }
++ }
++ }
++}
+diff --git a/third_party/rust/nix/src/sys/uio.rs b/third_party/rust/nix/src/sys/uio.rs
+index d089084eed711..65334227b4d1d 100644
+--- a/third_party/rust/nix/src/sys/uio.rs
++++ b/third_party/rust/nix/src/sys/uio.rs
+@@ -1,8 +1,8 @@
+ // Silence invalid warnings due to rust-lang/rust#16719
+ #![allow(improper_ctypes)]
+
+-use Result;
+-use errno::Errno;
++use crate::Result;
++use crate::errno::Errno;
+ use libc::{self, c_int, c_void, size_t, off_t};
+ use std::marker::PhantomData;
+ use std::os::unix::io::RawFd;
+@@ -117,7 +117,11 @@ pub struct RemoteIoVec {
+ /// [`IoVec`]: struct.IoVec.html
+ /// [`RemoteIoVec`]: struct.RemoteIoVec.html
+ #[cfg(target_os = "linux")]
+-pub fn process_vm_writev(pid: ::unistd::Pid, local_iov: &[IoVec<&[u8]>], remote_iov: &[RemoteIoVec]) -> Result<usize> {
++pub fn process_vm_writev(
++ pid: crate::unistd::Pid,
++ local_iov: &[IoVec<&[u8]>],
++ remote_iov: &[RemoteIoVec]) -> Result<usize>
++{
+ let res = unsafe {
+ libc::process_vm_writev(pid.into(),
+ local_iov.as_ptr() as *const libc::iovec, local_iov.len() as libc::c_ulong,
+@@ -148,7 +152,11 @@ pub fn process_vm_writev(pid: ::unistd::Pid, local_iov: &[IoVec<&[u8]>], remote_
+ /// [`IoVec`]: struct.IoVec.html
+ /// [`RemoteIoVec`]: struct.RemoteIoVec.html
+ #[cfg(any(target_os = "linux"))]
+-pub fn process_vm_readv(pid: ::unistd::Pid, local_iov: &[IoVec<&mut [u8]>], remote_iov: &[RemoteIoVec]) -> Result<usize> {
++pub fn process_vm_readv(
++ pid: crate::unistd::Pid,
++ local_iov: &[IoVec<&mut [u8]>],
++ remote_iov: &[RemoteIoVec]) -> Result<usize>
++{
+ let res = unsafe {
+ libc::process_vm_readv(pid.into(),
+ local_iov.as_ptr() as *const libc::iovec, local_iov.len() as libc::c_ulong,
+@@ -158,7 +166,7 @@ pub fn process_vm_readv(pid: ::unistd::Pid, local_iov: &[IoVec<&mut [u8]>], remo
+ Errno::result(res).map(|r| r as usize)
+ }
+
+-#[repr(C)]
++#[repr(transparent)]
+ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+ pub struct IoVec<T>(libc::iovec, PhantomData<T>);
+
+diff --git a/third_party/rust/nix/src/sys/utsname.rs b/third_party/rust/nix/src/sys/utsname.rs
+index ab09c7d23232a..bf1a814d6d863 100644
+--- a/third_party/rust/nix/src/sys/utsname.rs
++++ b/third_party/rust/nix/src/sys/utsname.rs
+@@ -3,8 +3,8 @@ use libc::{self, c_char};
+ use std::ffi::CStr;
+ use std::str::from_utf8_unchecked;
+
+-#[repr(C)]
+ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++#[repr(transparent)]
+ pub struct UtsName(libc::utsname);
+
+ impl UtsName {
+@@ -31,9 +31,9 @@ impl UtsName {
+
+ pub fn uname() -> UtsName {
+ unsafe {
+- let mut ret: UtsName = mem::uninitialized();
+- libc::uname(&mut ret.0);
+- ret
++ let mut ret = mem::MaybeUninit::uninit();
++ libc::uname(ret.as_mut_ptr());
++ UtsName(ret.assume_init())
+ }
+ }
+
+diff --git a/third_party/rust/nix/src/sys/wait.rs b/third_party/rust/nix/src/sys/wait.rs
+index c54f7ec579667..faf8543cb1589 100644
+--- a/third_party/rust/nix/src/sys/wait.rs
++++ b/third_party/rust/nix/src/sys/wait.rs
+@@ -1,9 +1,10 @@
++use crate::errno::Errno;
++use crate::sys::signal::Signal;
++use crate::unistd::Pid;
++use crate::Result;
++use cfg_if::cfg_if;
+ use libc::{self, c_int};
+-use Result;
+-use errno::Errno;
+-use unistd::Pid;
+-
+-use sys::signal::Signal;
++use std::convert::TryFrom;
+
+ libc_bitflags!(
+ pub struct WaitPidFlag: c_int {
+@@ -14,6 +15,7 @@ libc_bitflags!(
+ target_os = "haiku",
+ target_os = "ios",
+ target_os = "linux",
++ target_os = "redox",
+ target_os = "macos",
+ target_os = "netbsd"))]
+ WEXITED;
+@@ -23,6 +25,7 @@ libc_bitflags!(
+ target_os = "haiku",
+ target_os = "ios",
+ target_os = "linux",
++ target_os = "redox",
+ target_os = "macos",
+ target_os = "netbsd"))]
+ WSTOPPED;
+@@ -32,16 +35,17 @@ libc_bitflags!(
+ target_os = "haiku",
+ target_os = "ios",
+ target_os = "linux",
++ target_os = "redox",
+ target_os = "macos",
+ target_os = "netbsd"))]
+ WNOWAIT;
+ /// Don't wait on children of other threads in this group
+- #[cfg(any(target_os = "android", target_os = "linux"))]
++ #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))]
+ __WNOTHREAD;
+ /// Wait on all children, regardless of type
+- #[cfg(any(target_os = "android", target_os = "linux"))]
++ #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))]
+ __WALL;
+- #[cfg(any(target_os = "android", target_os = "linux"))]
++ #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))]
+ __WCLONE;
+ }
+ );
+@@ -104,8 +108,7 @@ impl WaitStatus {
+ pub fn pid(&self) -> Option<Pid> {
+ use self::WaitStatus::*;
+ match *self {
+- Exited(p, _) | Signaled(p, _, _) |
+- Stopped(p, _) | Continued(p) => Some(p),
++ Exited(p, _) | Signaled(p, _, _) | Stopped(p, _) | Continued(p) => Some(p),
+ StillAlive => None,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ PtraceEvent(p, _, _) | PtraceSyscall(p) => Some(p),
+@@ -114,31 +117,31 @@ impl WaitStatus {
+ }
+
+ fn exited(status: i32) -> bool {
+- unsafe { libc::WIFEXITED(status) }
++ libc::WIFEXITED(status)
+ }
+
+ fn exit_status(status: i32) -> i32 {
+- unsafe { libc::WEXITSTATUS(status) }
++ libc::WEXITSTATUS(status)
+ }
+
+ fn signaled(status: i32) -> bool {
+- unsafe { libc::WIFSIGNALED(status) }
++ libc::WIFSIGNALED(status)
+ }
+
+ fn term_signal(status: i32) -> Result<Signal> {
+- Signal::from_c_int(unsafe { libc::WTERMSIG(status) })
++ Signal::try_from(libc::WTERMSIG(status))
+ }
+
+ fn dumped_core(status: i32) -> bool {
+- unsafe { libc::WCOREDUMP(status) }
++ libc::WCOREDUMP(status)
+ }
+
+ fn stopped(status: i32) -> bool {
+- unsafe { libc::WIFSTOPPED(status) }
++ libc::WIFSTOPPED(status)
+ }
+
+ fn stop_signal(status: i32) -> Result<Signal> {
+- Signal::from_c_int(unsafe { libc::WSTOPSIG(status) })
++ Signal::try_from(libc::WSTOPSIG(status))
+ }
+
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+@@ -147,7 +150,7 @@ fn syscall_stop(status: i32) -> bool {
+ // of delivering SIGTRAP | 0x80 as the signal number for syscall
+ // stops. This allows easily distinguishing syscall stops from
+ // genuine SIGTRAP signals.
+- unsafe { libc::WSTOPSIG(status) == libc::SIGTRAP | 0x80 }
++ libc::WSTOPSIG(status) == libc::SIGTRAP | 0x80
+ }
+
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+@@ -156,7 +159,7 @@ fn stop_additional(status: i32) -> c_int {
+ }
+
+ fn continued(status: i32) -> bool {
+- unsafe { libc::WIFCONTINUED(status) }
++ libc::WIFCONTINUED(status)
+ }
+
+ impl WaitStatus {
+@@ -222,7 +225,7 @@ pub fn waitpid<P: Into<Option<Pid>>>(pid: P, options: Option<WaitPidFlag>) -> Re
+
+ let res = unsafe {
+ libc::waitpid(
+- pid.into().unwrap_or(Pid::from_raw(-1)).into(),
++ pid.into().unwrap_or_else(|| Pid::from_raw(-1)).into(),
+ &mut status as *mut c_int,
+ option_bits,
+ )
+diff --git a/third_party/rust/nix/src/time.rs b/third_party/rust/nix/src/time.rs
+new file mode 100644
+index 0000000000000..e6c3f8ded5a52
+--- /dev/null
++++ b/third_party/rust/nix/src/time.rs
+@@ -0,0 +1,260 @@
++use crate::sys::time::TimeSpec;
++#[cfg(any(
++ target_os = "freebsd",
++ target_os = "dragonfly",
++ target_os = "linux",
++ target_os = "android",
++ target_os = "emscripten",
++))]
++use crate::{unistd::Pid, Error};
++use crate::{Errno, Result};
++use libc::{self, clockid_t};
++use std::mem::MaybeUninit;
++
++/// Clock identifier
++///
++/// Newtype pattern around `clockid_t` (which is just alias). It pervents bugs caused by
++/// accidentally passing wrong value.
++#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
++pub struct ClockId(clockid_t);
++
++impl ClockId {
++ /// Creates `ClockId` from raw `clockid_t`
++ pub fn from_raw(clk_id: clockid_t) -> Self {
++ ClockId(clk_id)
++ }
++
++ /// Returns `ClockId` of a `pid` CPU-time clock
++ #[cfg(any(
++ target_os = "freebsd",
++ target_os = "dragonfly",
++ target_os = "linux",
++ target_os = "android",
++ target_os = "emscripten",
++ ))]
++ pub fn pid_cpu_clock_id(pid: Pid) -> Result<Self> {
++ clock_getcpuclockid(pid)
++ }
++
++ /// Returns resolution of the clock id
++ #[cfg(not(target_os = "redox"))]
++ pub fn res(self) -> Result<TimeSpec> {
++ clock_getres(self)
++ }
++
++ /// Returns the current time on the clock id
++ pub fn now(self) -> Result<TimeSpec> {
++ clock_gettime(self)
++ }
++
++ /// Sets time to `timespec` on the clock id
++ #[cfg(not(any(
++ target_os = "macos",
++ target_os = "ios",
++ all(
++ not(any(target_env = "uclibc", target_env = "newlibc")),
++ any(target_os = "redox", target_os = "hermit",),
++ ),
++ )))]
++ pub fn set_time(self, timespec: TimeSpec) -> Result<()> {
++ clock_settime(self, timespec)
++ }
++
++ /// Gets the raw `clockid_t` wrapped by `self`
++ pub fn as_raw(self) -> clockid_t {
++ self.0
++ }
++
++ #[cfg(any(
++ target_os = "fuchsia",
++ all(
++ not(any(target_env = "uclibc", target_env = "newlib")),
++ any(target_os = "linux", target_os = "android", target_os = "emscripten"),
++ )
++ ))]
++ pub const CLOCK_BOOTTIME: ClockId = ClockId(libc::CLOCK_BOOTTIME);
++ #[cfg(any(
++ target_os = "fuchsia",
++ all(
++ not(any(target_env = "uclibc", target_env = "newlib")),
++ any(target_os = "linux", target_os = "android", target_os = "emscripten")
++ )
++ ))]
++ pub const CLOCK_BOOTTIME_ALARM: ClockId = ClockId(libc::CLOCK_BOOTTIME_ALARM);
++ pub const CLOCK_MONOTONIC: ClockId = ClockId(libc::CLOCK_MONOTONIC);
++ #[cfg(any(
++ target_os = "fuchsia",
++ all(
++ not(any(target_env = "uclibc", target_env = "newlib")),
++ any(target_os = "linux", target_os = "android", target_os = "emscripten")
++ )
++ ))]
++ pub const CLOCK_MONOTONIC_COARSE: ClockId = ClockId(libc::CLOCK_MONOTONIC_COARSE);
++ #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++ pub const CLOCK_MONOTONIC_FAST: ClockId = ClockId(libc::CLOCK_MONOTONIC_FAST);
++ #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++ pub const CLOCK_MONOTONIC_PRECISE: ClockId = ClockId(libc::CLOCK_MONOTONIC_PRECISE);
++ #[cfg(any(
++ target_os = "fuchsia",
++ all(
++ not(any(target_env = "uclibc", target_env = "newlib")),
++ any(target_os = "linux", target_os = "android", target_os = "emscripten")
++ )
++ ))]
++ pub const CLOCK_MONOTONIC_RAW: ClockId = ClockId(libc::CLOCK_MONOTONIC_RAW);
++ #[cfg(any(
++ target_os = "fuchsia",
++ target_env = "uclibc",
++ target_os = "macos",
++ target_os = "ios",
++ target_os = "freebsd",
++ target_os = "dragonfly",
++ all(
++ not(target_env = "newlib"),
++ any(target_os = "linux", target_os = "android", target_os = "emscripten")
++ )
++ ))]
++ pub const CLOCK_PROCESS_CPUTIME_ID: ClockId = ClockId(libc::CLOCK_PROCESS_CPUTIME_ID);
++ #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++ pub const CLOCK_PROF: ClockId = ClockId(libc::CLOCK_PROF);
++ pub const CLOCK_REALTIME: ClockId = ClockId(libc::CLOCK_REALTIME);
++ #[cfg(any(
++ target_os = "fuchsia",
++ all(
++ not(any(target_env = "uclibc", target_env = "newlib")),
++ any(target_os = "linux", target_os = "android", target_os = "emscripten")
++ )
++ ))]
++ pub const CLOCK_REALTIME_ALARM: ClockId = ClockId(libc::CLOCK_REALTIME_ALARM);
++ #[cfg(any(
++ target_os = "fuchsia",
++ all(
++ not(any(target_env = "uclibc", target_env = "newlib")),
++ any(target_os = "linux", target_os = "android", target_os = "emscripten")
++ )
++ ))]
++ pub const CLOCK_REALTIME_COARSE: ClockId = ClockId(libc::CLOCK_REALTIME_COARSE);
++ #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++ pub const CLOCK_REALTIME_FAST: ClockId = ClockId(libc::CLOCK_REALTIME_FAST);
++ #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++ pub const CLOCK_REALTIME_PRECISE: ClockId = ClockId(libc::CLOCK_REALTIME_PRECISE);
++ #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++ pub const CLOCK_SECOND: ClockId = ClockId(libc::CLOCK_SECOND);
++ #[cfg(any(
++ target_os = "fuchsia",
++ all(
++ not(any(target_env = "uclibc", target_env = "newlib")),
++ any(
++ target_os = "emscripten",
++ all(target_os = "linux", target_env = "musl")
++ )
++ )
++ ))]
++ pub const CLOCK_SGI_CYCLE: ClockId = ClockId(libc::CLOCK_SGI_CYCLE);
++ #[cfg(any(
++ target_os = "fuchsia",
++ all(
++ not(any(target_env = "uclibc", target_env = "newlib")),
++ any(
++ target_os = "emscripten",
++ all(target_os = "linux", target_env = "musl")
++ )
++ )
++ ))]
++ pub const CLOCK_TAI: ClockId = ClockId(libc::CLOCK_TAI);
++ #[cfg(any(
++ target_env = "uclibc",
++ target_os = "fuchsia",
++ target_os = "ios",
++ target_os = "macos",
++ target_os = "freebsd",
++ target_os = "dragonfly",
++ all(
++ not(target_env = "newlib"),
++ any(target_os = "linux", target_os = "android", target_os = "emscripten",),
++ ),
++ ))]
++ pub const CLOCK_THREAD_CPUTIME_ID: ClockId = ClockId(libc::CLOCK_THREAD_CPUTIME_ID);
++ #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++ pub const CLOCK_UPTIME: ClockId = ClockId(libc::CLOCK_UPTIME);
++ #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++ pub const CLOCK_UPTIME_FAST: ClockId = ClockId(libc::CLOCK_UPTIME_FAST);
++ #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++ pub const CLOCK_UPTIME_PRECISE: ClockId = ClockId(libc::CLOCK_UPTIME_PRECISE);
++ #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++ pub const CLOCK_VIRTUAL: ClockId = ClockId(libc::CLOCK_VIRTUAL);
++}
++
++impl Into<clockid_t> for ClockId {
++ fn into(self) -> clockid_t {
++ self.as_raw()
++ }
++}
++
++impl From<clockid_t> for ClockId {
++ fn from(clk_id: clockid_t) -> Self {
++ ClockId::from_raw(clk_id)
++ }
++}
++
++impl std::fmt::Display for ClockId {
++ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
++ std::fmt::Display::fmt(&self.0, f)
++ }
++}
++
++/// Get the resolution of the specified clock, (see
++/// [clock_getres(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_getres.html)).
++#[cfg(not(target_os = "redox"))]
++pub fn clock_getres(clock_id: ClockId) -> Result<TimeSpec> {
++ let mut c_time: MaybeUninit<libc::timespec> = MaybeUninit::uninit();
++ let ret = unsafe { libc::clock_getres(clock_id.as_raw(), c_time.as_mut_ptr()) };
++ Errno::result(ret)?;
++ let res = unsafe { c_time.assume_init() };
++ Ok(TimeSpec::from(res))
++}
++
++/// Get the time of the specified clock, (see
++/// [clock_gettime(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_gettime.html)).
++pub fn clock_gettime(clock_id: ClockId) -> Result<TimeSpec> {
++ let mut c_time: MaybeUninit<libc::timespec> = MaybeUninit::uninit();
++ let ret = unsafe { libc::clock_gettime(clock_id.as_raw(), c_time.as_mut_ptr()) };
++ Errno::result(ret)?;
++ let res = unsafe { c_time.assume_init() };
++ Ok(TimeSpec::from(res))
++}
++
++/// Set the time of the specified clock, (see
++/// [clock_settime(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_settime.html)).
++#[cfg(not(any(
++ target_os = "macos",
++ target_os = "ios",
++ all(
++ not(any(target_env = "uclibc", target_env = "newlibc")),
++ any(target_os = "redox", target_os = "hermit",),
++ ),
++)))]
++pub fn clock_settime(clock_id: ClockId, timespec: TimeSpec) -> Result<()> {
++ let ret = unsafe { libc::clock_settime(clock_id.as_raw(), timespec.as_ref()) };
++ Errno::result(ret).map(drop)
++}
++
++/// Get the clock id of the specified process id, (see
++/// [clock_getcpuclockid(3)](https://pubs.opengroup.org/onlinepubs/009695399/functions/clock_getcpuclockid.html)).
++#[cfg(any(
++ target_os = "freebsd",
++ target_os = "dragonfly",
++ target_os = "linux",
++ target_os = "android",
++ target_os = "emscripten",
++))]
++pub fn clock_getcpuclockid(pid: Pid) -> Result<ClockId> {
++ let mut clk_id: MaybeUninit<libc::clockid_t> = MaybeUninit::uninit();
++ let ret = unsafe { libc::clock_getcpuclockid(pid.into(), clk_id.as_mut_ptr()) };
++ if ret == 0 {
++ let res = unsafe { clk_id.assume_init() };
++ Ok(ClockId::from(res))
++ } else {
++ Err(Error::Sys(Errno::from_i32(ret)))
++ }
++}
+diff --git a/third_party/rust/nix/src/ucontext.rs b/third_party/rust/nix/src/ucontext.rs
+index 5e10e7d1f8934..a5b8cc75cb330 100644
+--- a/third_party/rust/nix/src/ucontext.rs
++++ b/third_party/rust/nix/src/ucontext.rs
+@@ -1,10 +1,11 @@
+ use libc;
+ #[cfg(not(target_env = "musl"))]
+-use Result;
++use crate::Result;
++#[cfg(not(target_env = "musl"))]
++use crate::errno::Errno;
+ #[cfg(not(target_env = "musl"))]
+-use errno::Errno;
+ use std::mem;
+-use sys::signal::SigSet;
++use crate::sys::signal::SigSet;
+
+ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+ pub struct UContext {
+@@ -14,11 +15,11 @@ pub struct UContext {
+ impl UContext {
+ #[cfg(not(target_env = "musl"))]
+ pub fn get() -> Result<UContext> {
+- let mut context: libc::ucontext_t = unsafe { mem::uninitialized() };
+- let res = unsafe {
+- libc::getcontext(&mut context as *mut libc::ucontext_t)
+- };
+- Errno::result(res).map(|_| UContext { context: context })
++ let mut context = mem::MaybeUninit::<libc::ucontext_t>::uninit();
++ let res = unsafe { libc::getcontext(context.as_mut_ptr()) };
++ Errno::result(res).map(|_| unsafe {
++ UContext { context: context.assume_init()}
++ })
+ }
+
+ #[cfg(not(target_env = "musl"))]
+@@ -30,10 +31,14 @@ impl UContext {
+ }
+
+ pub fn sigmask_mut(&mut self) -> &mut SigSet {
+- unsafe { mem::transmute(&mut self.context.uc_sigmask) }
++ unsafe {
++ &mut *(&mut self.context.uc_sigmask as *mut libc::sigset_t as *mut SigSet)
++ }
+ }
+
+ pub fn sigmask(&self) -> &SigSet {
+- unsafe { mem::transmute(&self.context.uc_sigmask) }
++ unsafe {
++ &*(&self.context.uc_sigmask as *const libc::sigset_t as *const SigSet)
++ }
+ }
+ }
+diff --git a/third_party/rust/nix/src/unistd.rs b/third_party/rust/nix/src/unistd.rs
+index f422f09198655..59cb1ed8b5901 100644
+--- a/third_party/rust/nix/src/unistd.rs
++++ b/third_party/rust/nix/src/unistd.rs
+@@ -1,18 +1,26 @@
+ //! Safe wrappers around functions found in libc "unistd.h" header
+
+-use errno::{self, Errno};
+-use {Error, Result, NixPath};
+-use fcntl::{AtFlags, at_rawfd, fcntl, FdFlag, OFlag};
+-use fcntl::FcntlArg::F_SETFD;
++#[cfg(not(target_os = "redox"))]
++use cfg_if::cfg_if;
++use crate::errno::{self, Errno};
++use crate::{Error, Result, NixPath};
++#[cfg(not(target_os = "redox"))]
++use crate::fcntl::{AtFlags, at_rawfd};
++use crate::fcntl::{FdFlag, OFlag, fcntl};
++use crate::fcntl::FcntlArg::F_SETFD;
+ use libc::{self, c_char, c_void, c_int, c_long, c_uint, size_t, pid_t, off_t,
+- uid_t, gid_t, mode_t};
++ uid_t, gid_t, mode_t, PATH_MAX};
+ use std::{fmt, mem, ptr};
+-use std::ffi::{CString, CStr, OsString, OsStr};
+-use std::os::unix::ffi::{OsStringExt, OsStrExt};
++use std::convert::Infallible;
++use std::ffi::{CStr, OsString};
++#[cfg(not(target_os = "redox"))]
++use std::ffi::{CString, OsStr};
++use std::os::unix::ffi::OsStringExt;
++#[cfg(not(target_os = "redox"))]
++use std::os::unix::ffi::OsStrExt;
+ use std::os::unix::io::RawFd;
+ use std::path::PathBuf;
+-use void::Void;
+-use sys::stat::Mode;
++use crate::sys::stat::Mode;
+
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ pub use self::pivot_root::*;
+@@ -45,12 +53,12 @@ impl Uid {
+ }
+
+ /// Returns true if the `Uid` represents privileged user - root. (If it equals zero.)
+- pub fn is_root(&self) -> bool {
+- *self == ROOT
++ pub fn is_root(self) -> bool {
++ self == ROOT
+ }
+
+ /// Get the raw `uid_t` wrapped by `self`.
+- pub fn as_raw(&self) -> uid_t {
++ pub fn as_raw(self) -> uid_t {
+ self.0
+ }
+ }
+@@ -88,13 +96,13 @@ impl Gid {
+ getgid()
+ }
+
+- /// Returns effective Gid of calling process. This is practically a more Rusty alias for `getgid`.
++ /// Returns effective Gid of calling process. This is practically a more Rusty alias for `getegid`.
+ pub fn effective() -> Self {
+ getegid()
+ }
+
+ /// Get the raw `gid_t` wrapped by `self`.
+- pub fn as_raw(&self) -> gid_t {
++ pub fn as_raw(self) -> gid_t {
+ self.0
+ }
+ }
+@@ -115,7 +123,7 @@ impl fmt::Display for Gid {
+ ///
+ /// Newtype pattern around `pid_t` (which is just alias). It prevents bugs caused by accidentally
+ /// passing wrong value.
+-#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
++#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
+ pub struct Pid(pid_t);
+
+ impl Pid {
+@@ -135,7 +143,7 @@ impl Pid {
+ }
+
+ /// Get the raw `pid_t` wrapped by `self`.
+- pub fn as_raw(&self) -> pid_t {
++ pub fn as_raw(self) -> pid_t {
+ self.0
+ }
+ }
+@@ -168,8 +176,8 @@ impl ForkResult {
+
+ /// Return `true` if this is the child process of the `fork()`
+ #[inline]
+- pub fn is_child(&self) -> bool {
+- match *self {
++ pub fn is_child(self) -> bool {
++ match self {
+ ForkResult::Child => true,
+ _ => false
+ }
+@@ -177,7 +185,7 @@ impl ForkResult {
+
+ /// Returns `true` if this is the parent process of the `fork()`
+ #[inline]
+- pub fn is_parent(&self) -> bool {
++ pub fn is_parent(self) -> bool {
+ !self.is_child()
+ }
+ }
+@@ -192,7 +200,7 @@ impl ForkResult {
+ /// ```no_run
+ /// use nix::unistd::{fork, ForkResult};
+ ///
+-/// match fork() {
++/// match unsafe{fork()} {
+ /// Ok(ForkResult::Parent { child, .. }) => {
+ /// println!("Continuing execution in parent process, new child has pid: {}", child);
+ /// }
+@@ -222,9 +230,9 @@ impl ForkResult {
+ ///
+ /// [async-signal-safe]: http://man7.org/linux/man-pages/man7/signal-safety.7.html
+ #[inline]
+-pub fn fork() -> Result<ForkResult> {
++pub unsafe fn fork() -> Result<ForkResult> {
+ use self::ForkResult::*;
+- let res = unsafe { libc::fork() };
++ let res = libc::fork();
+
+ Errno::result(res).map(|res| match res {
+ 0 => Child,
+@@ -285,6 +293,7 @@ pub fn setsid() -> Result<Pid> {
+ /// Obtain the process group ID of the process that is the session leader of the process specified
+ /// by pid. If pid is zero, it specifies the calling process.
+ #[inline]
++#[cfg(not(target_os = "redox"))]
+ pub fn getsid(pid: Option<Pid>) -> Result<Pid> {
+ let res = unsafe { libc::getsid(pid.unwrap_or(Pid(0)).into()) };
+ Errno::result(res).map(Pid)
+@@ -417,6 +426,7 @@ pub fn chdir<P: ?Sized + NixPath>(path: &P) -> Result<()> {
+ /// This function may fail in a number of different scenarios. See the man
+ /// pages for additional details on possible failure cases.
+ #[inline]
++#[cfg(not(target_os = "fuchsia"))]
+ pub fn fchdir(dirfd: RawFd) -> Result<()> {
+ let res = unsafe { libc::fchdir(dirfd) };
+
+@@ -436,9 +446,6 @@ pub fn fchdir(dirfd: RawFd) -> Result<()> {
+ /// # Example
+ ///
+ /// ```rust
+-/// extern crate tempfile;
+-/// extern crate nix;
+-///
+ /// use nix::unistd;
+ /// use nix::sys::stat;
+ /// use tempfile::tempdir;
+@@ -479,9 +486,6 @@ pub fn mkdir<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> {
+ /// # Example
+ ///
+ /// ```rust
+-/// extern crate tempfile;
+-/// extern crate nix;
+-///
+ /// use nix::unistd;
+ /// use nix::sys::stat;
+ /// use tempfile::tempdir;
+@@ -498,6 +502,7 @@ pub fn mkdir<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> {
+ /// }
+ /// ```
+ #[inline]
++#[cfg(not(target_os = "redox"))] // RedoxFS does not support fifo yet
+ pub fn mkfifo<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> {
+ let res = path.with_nix_path(|cstr| {
+ unsafe { libc::mkfifo(cstr.as_ptr(), mode.bits() as mode_t) }
+@@ -506,6 +511,28 @@ pub fn mkfifo<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> {
+ Errno::result(res).map(drop)
+ }
+
++/// Creates new fifo special file (named pipe) with path `path` and access rights `mode`.
++///
++/// If `dirfd` has a value, then `path` is relative to directory associated with the file descriptor.
++///
++/// If `dirfd` is `None`, then `path` is relative to the current working directory.
++///
++/// # References
++///
++/// [mkfifoat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mkfifoat.html).
++// mkfifoat is not implemented in OSX or android
++#[inline]
++#[cfg(not(any(
++ target_os = "macos", target_os = "ios",
++ target_os = "android", target_os = "redox")))]
++pub fn mkfifoat<P: ?Sized + NixPath>(dirfd: Option<RawFd>, path: &P, mode: Mode) -> Result<()> {
++ let res = path.with_nix_path(|cstr| unsafe {
++ libc::mkfifoat(at_rawfd(dirfd), cstr.as_ptr(), mode.bits() as mode_t)
++ })?;
++
++ Errno::result(res).map(drop)
++}
++
+ /// Creates a symbolic link at `path2` which points to `path1`.
+ ///
+ /// If `dirfd` has a value, then `path2` is relative to directory associated
+@@ -515,6 +542,7 @@ pub fn mkfifo<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> {
+ /// directory. This is identical to `libc::symlink(path1, path2)`.
+ ///
+ /// See also [symlinkat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/symlinkat.html).
++#[cfg(not(target_os = "redox"))]
+ pub fn symlinkat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(
+ path1: &P1,
+ dirfd: Option<RawFd>,
+@@ -534,6 +562,21 @@ pub fn symlinkat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(
+ Errno::result(res).map(drop)
+ }
+
++// Double the buffer capacity up to limit. In case it already has
++// reached the limit, return Errno::ERANGE.
++fn reserve_double_buffer_size<T>(buf: &mut Vec<T>, limit: usize) -> Result<()> {
++ use std::cmp::min;
++
++ if buf.capacity() >= limit {
++ return Err(Error::Sys(Errno::ERANGE))
++ }
++
++ let capacity = min(buf.capacity() * 2, limit);
++ buf.reserve(capacity);
++
++ Ok(())
++}
++
+ /// Returns the current directory as a `PathBuf`
+ ///
+ /// Err is returned if the current user doesn't have the permission to read or search a component
+@@ -542,8 +585,6 @@ pub fn symlinkat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(
+ /// # Example
+ ///
+ /// ```rust
+-/// extern crate nix;
+-///
+ /// use nix::unistd;
+ ///
+ /// fn main() {
+@@ -576,11 +617,8 @@ pub fn getcwd() -> Result<PathBuf> {
+ }
+ }
+
+- // Trigger the internal buffer resizing logic of `Vec` by requiring
+- // more space than the current capacity.
+- let cap = buf.capacity();
+- buf.set_len(cap);
+- buf.reserve(1);
++ // Trigger the internal buffer resizing logic.
++ reserve_double_buffer_size(&mut buf, PATH_MAX as usize)?;
+ }
+ }
+ }
+@@ -590,8 +628,10 @@ fn chown_raw_ids(owner: Option<Uid>, group: Option<Gid>) -> (libc::uid_t, libc::
+ // According to the POSIX specification, -1 is used to indicate that owner and group
+ // are not to be changed. Since uid_t and gid_t are unsigned types, we have to wrap
+ // around to get -1.
+- let uid = owner.map(Into::into).unwrap_or((0 as uid_t).wrapping_sub(1));
+- let gid = group.map(Into::into).unwrap_or((0 as gid_t).wrapping_sub(1));
++ let uid = owner.map(Into::into)
++ .unwrap_or_else(|| (0 as uid_t).wrapping_sub(1));
++ let gid = group.map(Into::into)
++ .unwrap_or_else(|| (0 as gid_t).wrapping_sub(1));
+ (uid, gid)
+ }
+
+@@ -612,6 +652,20 @@ pub fn chown<P: ?Sized + NixPath>(path: &P, owner: Option<Uid>, group: Option<Gi
+ Errno::result(res).map(drop)
+ }
+
++/// Change the ownership of the file referred to by the open file descriptor `fd` to be owned by
++/// the specified `owner` (user) and `group` (see
++/// [fchown(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchown.html)).
++///
++/// The owner/group for the provided file will not be modified if `None` is
++/// provided for that argument. Ownership change will be attempted for the path
++/// only if `Some` owner/group is provided.
++#[inline]
++pub fn fchown(fd: RawFd, owner: Option<Uid>, group: Option<Gid>) -> Result<()> {
++ let (uid, gid) = chown_raw_ids(owner, group);
++ let res = unsafe { libc::fchown(fd, uid, gid) };
++ Errno::result(res).map(drop)
++}
++
+ /// Flags for `fchownat` function.
+ #[derive(Clone, Copy, Debug)]
+ pub enum FchownatFlags {
+@@ -640,6 +694,7 @@ pub enum FchownatFlags {
+ /// # References
+ ///
+ /// [fchownat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fchownat.html).
++#[cfg(not(target_os = "redox"))]
+ pub fn fchownat<P: ?Sized + NixPath>(
+ dirfd: Option<RawFd>,
+ path: &P,
+@@ -661,10 +716,9 @@ pub fn fchownat<P: ?Sized + NixPath>(
+ Errno::result(res).map(drop)
+ }
+
+-fn to_exec_array(args: &[CString]) -> Vec<*const c_char> {
+- let mut args_p: Vec<*const c_char> = args.iter().map(|s| s.as_ptr()).collect();
+- args_p.push(ptr::null());
+- args_p
++fn to_exec_array<S: AsRef<CStr>>(args: &[S]) -> Vec<*const c_char> {
++ use std::iter::once;
++ args.iter().map(|s| s.as_ref().as_ptr()).chain(once(ptr::null())).collect()
+ }
+
+ /// Replace the current process image with a new one (see
+@@ -674,7 +728,7 @@ fn to_exec_array(args: &[CString]) -> Vec<*const c_char> {
+ /// performs the same action but does not allow for customization of the
+ /// environment for the new process.
+ #[inline]
+-pub fn execv(path: &CString, argv: &[CString]) -> Result<Void> {
++pub fn execv<S: AsRef<CStr>>(path: &CStr, argv: &[S]) -> Result<Infallible> {
+ let args_p = to_exec_array(argv);
+
+ unsafe {
+@@ -698,7 +752,7 @@ pub fn execv(path: &CString, argv: &[CString]) -> Result<Void> {
+ /// in the `args` list is an argument to the new process. Each element in the
+ /// `env` list should be a string in the form "key=value".
+ #[inline]
+-pub fn execve(path: &CString, args: &[CString], env: &[CString]) -> Result<Void> {
++pub fn execve<SA: AsRef<CStr>, SE: AsRef<CStr>>(path: &CStr, args: &[SA], env: &[SE]) -> Result<Infallible> {
+ let args_p = to_exec_array(args);
+ let env_p = to_exec_array(env);
+
+@@ -719,7 +773,7 @@ pub fn execve(path: &CString, args: &[CString], env: &[CString]) -> Result<Void>
+ /// would not work if "bash" was specified for the path argument, but `execvp`
+ /// would assuming that a bash executable was on the system `PATH`.
+ #[inline]
+-pub fn execvp(filename: &CString, args: &[CString]) -> Result<Void> {
++pub fn execvp<S: AsRef<CStr>>(filename: &CStr, args: &[S]) -> Result<Infallible> {
+ let args_p = to_exec_array(args);
+
+ unsafe {
+@@ -739,7 +793,7 @@ pub fn execvp(filename: &CString, args: &[CString]) -> Result<Void> {
+ #[cfg(any(target_os = "haiku",
+ target_os = "linux",
+ target_os = "openbsd"))]
+-pub fn execvpe(filename: &CString, args: &[CString], env: &[CString]) -> Result<Void> {
++pub fn execvpe<SA: AsRef<CStr>, SE: AsRef<CStr>>(filename: &CStr, args: &[SA], env: &[SE]) -> Result<Infallible> {
+ let args_p = to_exec_array(args);
+ let env_p = to_exec_array(env);
+
+@@ -767,7 +821,7 @@ pub fn execvpe(filename: &CString, args: &[CString], env: &[CString]) -> Result<
+ target_os = "linux",
+ target_os = "freebsd"))]
+ #[inline]
+-pub fn fexecve(fd: RawFd, args: &[CString], env: &[CString]) -> Result<Void> {
++pub fn fexecve<SA: AsRef<CStr> ,SE: AsRef<CStr>>(fd: RawFd, args: &[SA], env: &[SE]) -> Result<Infallible> {
+ let args_p = to_exec_array(args);
+ let env_p = to_exec_array(env);
+
+@@ -790,8 +844,8 @@ pub fn fexecve(fd: RawFd, args: &[CString], env: &[CString]) -> Result<Void> {
+ /// is referenced as a file descriptor to the base directory plus a path.
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[inline]
+-pub fn execveat(dirfd: RawFd, pathname: &CString, args: &[CString],
+- env: &[CString], flags: super::fcntl::AtFlags) -> Result<Void> {
++pub fn execveat<SA: AsRef<CStr>,SE: AsRef<CStr>>(dirfd: RawFd, pathname: &CStr, args: &[SA],
++ env: &[SE], flags: super::fcntl::AtFlags) -> Result<Infallible> {
+ let args_p = to_exec_array(args);
+ let env_p = to_exec_array(env);
+
+@@ -828,11 +882,12 @@ pub fn execveat(dirfd: RawFd, pathname: &CString, args: &[CString],
+ /// descriptors will remain identical after daemonizing.
+ /// * `noclose = false`: The process' stdin, stdout, and stderr will point to
+ /// `/dev/null` after daemonizing.
+-#[cfg_attr(any(target_os = "macos", target_os = "ios"), deprecated(
+- since="0.14.0",
+- note="Deprecated in MacOSX 10.5"
+-))]
+-#[cfg_attr(any(target_os = "macos", target_os = "ios"), allow(deprecated))]
++#[cfg(any(target_os = "android",
++ target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "linux",
++ target_os = "netbsd",
++ target_os = "openbsd"))]
+ pub fn daemon(nochdir: bool, noclose: bool) -> Result<()> {
+ let res = unsafe { libc::daemon(nochdir as c_int, noclose as c_int) };
+ Errno::result(res).map(drop)
+@@ -845,6 +900,7 @@ pub fn daemon(nochdir: bool, noclose: bool) -> Result<()> {
+ /// On some systems, the host name is limited to as few as 64 bytes. An error
+ /// will be return if the name is not valid or the current process does not have
+ /// permissions to update the host name.
++#[cfg(not(target_os = "redox"))]
+ pub fn sethostname<S: AsRef<OsStr>>(name: S) -> Result<()> {
+ // Handle some differences in type of the len arg across platforms.
+ cfg_if! {
+@@ -906,9 +962,6 @@ pub fn gethostname(buffer: &mut [u8]) -> Result<&CStr> {
+ /// # Examples
+ ///
+ /// ```no_run
+-/// extern crate tempfile;
+-/// extern crate nix;
+-///
+ /// use std::os::unix::io::AsRawFd;
+ /// use nix::unistd::close;
+ ///
+@@ -919,9 +972,6 @@ pub fn gethostname(buffer: &mut [u8]) -> Result<&CStr> {
+ /// ```
+ ///
+ /// ```rust
+-/// extern crate tempfile;
+-/// extern crate nix;
+-///
+ /// use std::os::unix::io::IntoRawFd;
+ /// use nix::unistd::close;
+ ///
+@@ -969,20 +1019,14 @@ pub enum Whence {
+ /// Specify an offset relative to the next location in the file greater than or
+ /// equal to offset that contains some data. If offset points to
+ /// some data, then the file offset is set to offset.
+- #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
+- all(target_os = "linux", not(any(target_env = "musl",
+- target_arch = "mips",
+- target_arch = "mips64")))))]
++ #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))]
+ SeekData = libc::SEEK_DATA,
+ /// Specify an offset relative to the next hole in the file greater than
+ /// or equal to offset. If offset points into the middle of a hole, then
+ /// the file offset should be set to offset. If there is no hole past offset,
+ /// then the file offset should be adjusted to the end of the file (i.e., there
+ /// is an implicit hole at the end of any file).
+- #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
+- all(target_os = "linux", not(any(target_env = "musl",
+- target_arch = "mips",
+- target_arch = "mips64")))))]
++ #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))]
+ SeekHole = libc::SEEK_HOLE
+ }
+
+@@ -1007,13 +1051,13 @@ pub fn lseek64(fd: RawFd, offset: libc::off64_t, whence: Whence) -> Result<libc:
+ /// See also [pipe(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pipe.html)
+ pub fn pipe() -> Result<(RawFd, RawFd)> {
+ unsafe {
+- let mut fds: [c_int; 2] = mem::uninitialized();
++ let mut fds = mem::MaybeUninit::<[c_int; 2]>::uninit();
+
+- let res = libc::pipe(fds.as_mut_ptr());
++ let res = libc::pipe(fds.as_mut_ptr() as *mut c_int);
+
+ Errno::result(res)?;
+
+- Ok((fds[0], fds[1]))
++ Ok((fds.assume_init()[0], fds.assume_init()[1]))
+ }
+ }
+
+@@ -1022,7 +1066,9 @@ pub fn pipe() -> Result<(RawFd, RawFd)> {
+ /// The following flags are supported, and will be set atomically as the pipe is
+ /// created:
+ ///
+-/// `O_CLOEXEC`: Set the close-on-exec flag for the new file descriptors.
++/// `O_CLOEXEC`: Set the close-on-exec flag for the new file descriptors.
++#[cfg_attr(target_os = "linux", doc = "`O_DIRECT`: Create a pipe that performs I/O in \"packet\" mode. ")]
++#[cfg_attr(target_os = "netbsd", doc = "`O_NOSIGPIPE`: Return `EPIPE` instead of raising `SIGPIPE`. ")]
+ /// `O_NONBLOCK`: Set the non-blocking flag for the ends of the pipe.
+ ///
+ /// See also [pipe(2)](http://man7.org/linux/man-pages/man2/pipe.2.html)
+@@ -1031,74 +1077,26 @@ pub fn pipe() -> Result<(RawFd, RawFd)> {
+ target_os = "emscripten",
+ target_os = "freebsd",
+ target_os = "linux",
++ target_os = "redox",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> {
+- let mut fds: [c_int; 2] = unsafe { mem::uninitialized() };
+-
+- let res = unsafe { libc::pipe2(fds.as_mut_ptr(), flags.bits()) };
+-
+- Errno::result(res)?;
+-
+- Ok((fds[0], fds[1]))
+-}
++ let mut fds = mem::MaybeUninit::<[c_int; 2]>::uninit();
+
+-/// Like `pipe`, but allows setting certain file descriptor flags.
+-///
+-/// The following flags are supported, and will be set after the pipe is
+-/// created:
+-///
+-/// `O_CLOEXEC`: Set the close-on-exec flag for the new file descriptors.
+-/// `O_NONBLOCK`: Set the non-blocking flag for the ends of the pipe.
+-#[cfg(any(target_os = "ios", target_os = "macos"))]
+-#[deprecated(
+- since="0.10.0",
+- note="pipe2(2) is not actually atomic on these platforms. Use pipe(2) and fcntl(2) instead"
+-)]
+-pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> {
+- let mut fds: [c_int; 2] = unsafe { mem::uninitialized() };
+-
+- let res = unsafe { libc::pipe(fds.as_mut_ptr()) };
++ let res = unsafe {
++ libc::pipe2(fds.as_mut_ptr() as *mut c_int, flags.bits())
++ };
+
+ Errno::result(res)?;
+
+- pipe2_setflags(fds[0], fds[1], flags)?;
+-
+- Ok((fds[0], fds[1]))
+-}
+-
+-#[cfg(any(target_os = "ios", target_os = "macos"))]
+-fn pipe2_setflags(fd1: RawFd, fd2: RawFd, flags: OFlag) -> Result<()> {
+- use fcntl::FcntlArg::F_SETFL;
+-
+- let mut res = Ok(0);
+-
+- if flags.contains(OFlag::O_CLOEXEC) {
+- res = res
+- .and_then(|_| fcntl(fd1, F_SETFD(FdFlag::FD_CLOEXEC)))
+- .and_then(|_| fcntl(fd2, F_SETFD(FdFlag::FD_CLOEXEC)));
+- }
+-
+- if flags.contains(OFlag::O_NONBLOCK) {
+- res = res
+- .and_then(|_| fcntl(fd1, F_SETFL(OFlag::O_NONBLOCK)))
+- .and_then(|_| fcntl(fd2, F_SETFL(OFlag::O_NONBLOCK)));
+- }
+-
+- match res {
+- Ok(_) => Ok(()),
+- Err(e) => {
+- let _ = close(fd1);
+- let _ = close(fd2);
+- Err(e)
+- }
+- }
++ unsafe { Ok((fds.assume_init()[0], fds.assume_init()[1])) }
+ }
+
+ /// Truncate a file to a specified length
+ ///
+ /// See also
+ /// [truncate(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/truncate.html)
++#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
+ pub fn truncate<P: ?Sized + NixPath>(path: &P, len: off_t) -> Result<()> {
+ let res = path.with_nix_path(|cstr| {
+ unsafe {
+@@ -1132,6 +1130,59 @@ pub fn isatty(fd: RawFd) -> Result<bool> {
+ }
+ }
+
++/// Flags for `linkat` function.
++#[derive(Clone, Copy, Debug)]
++pub enum LinkatFlags {
++ SymlinkFollow,
++ NoSymlinkFollow,
++}
++
++/// Link one file to another file
++///
++/// Creates a new link (directory entry) at `newpath` for the existing file at `oldpath`. In the
++/// case of a relative `oldpath`, the path is interpreted relative to the directory associated
++/// with file descriptor `olddirfd` instead of the current working directory and similiarly for
++/// `newpath` and file descriptor `newdirfd`. In case `flag` is LinkatFlags::SymlinkFollow and
++/// `oldpath` names a symoblic link, a new link for the target of the symbolic link is created.
++/// If either `olddirfd` or `newdirfd` is `None`, `AT_FDCWD` is used respectively where `oldpath`
++/// and/or `newpath` is then interpreted relative to the current working directory of the calling
++/// process. If either `oldpath` or `newpath` is absolute, then `dirfd` is ignored.
++///
++/// # References
++/// See also [linkat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/linkat.html)
++#[cfg(not(target_os = "redox"))] // RedoxFS does not support symlinks yet
++pub fn linkat<P: ?Sized + NixPath>(
++ olddirfd: Option<RawFd>,
++ oldpath: &P,
++ newdirfd: Option<RawFd>,
++ newpath: &P,
++ flag: LinkatFlags,
++) -> Result<()> {
++
++ let atflag =
++ match flag {
++ LinkatFlags::SymlinkFollow => AtFlags::AT_SYMLINK_FOLLOW,
++ LinkatFlags::NoSymlinkFollow => AtFlags::empty(),
++ };
++
++ let res =
++ oldpath.with_nix_path(|oldcstr| {
++ newpath.with_nix_path(|newcstr| {
++ unsafe {
++ libc::linkat(
++ at_rawfd(olddirfd),
++ oldcstr.as_ptr(),
++ at_rawfd(newdirfd),
++ newcstr.as_ptr(),
++ atflag.bits() as libc::c_int
++ )
++ }
++ })
++ })??;
++ Errno::result(res).map(drop)
++}
++
++
+ /// Remove a directory entry
+ ///
+ /// See also [unlink(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/unlink.html)
+@@ -1161,6 +1212,7 @@ pub enum UnlinkatFlags {
+ ///
+ /// # References
+ /// See also [unlinkat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/unlinkat.html)
++#[cfg(not(target_os = "redox"))]
+ pub fn unlinkat<P: ?Sized + NixPath>(
+ dirfd: Option<RawFd>,
+ path: &P,
+@@ -1181,6 +1233,7 @@ pub fn unlinkat<P: ?Sized + NixPath>(
+
+
+ #[inline]
++#[cfg(not(target_os = "fuchsia"))]
+ pub fn chroot<P: ?Sized + NixPath>(path: &P) -> Result<()> {
+ let res = path.with_nix_path(|cstr| {
+ unsafe { libc::chroot(cstr.as_ptr()) }
+@@ -1199,7 +1252,7 @@ pub fn chroot<P: ?Sized + NixPath>(path: &P) -> Result<()> {
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
+-pub fn sync() -> () {
++pub fn sync() {
+ unsafe { libc::sync() };
+ }
+
+@@ -1309,6 +1362,28 @@ pub fn setgid(gid: Gid) -> Result<()> {
+ Errno::result(res).map(drop)
+ }
+
++/// Set the user identity used for filesystem checks per-thread.
++/// On both success and failure, this call returns the previous filesystem user
++/// ID of the caller.
++///
++/// See also [setfsuid(2)](http://man7.org/linux/man-pages/man2/setfsuid.2.html)
++#[cfg(any(target_os = "linux", target_os = "android"))]
++pub fn setfsuid(uid: Uid) -> Uid {
++ let prev_fsuid = unsafe { libc::setfsuid(uid.into()) };
++ Uid::from_raw(prev_fsuid as uid_t)
++}
++
++/// Set the group identity used for filesystem checks per-thread.
++/// On both success and failure, this call returns the previous filesystem group
++/// ID of the caller.
++///
++/// See also [setfsgid(2)](http://man7.org/linux/man-pages/man2/setfsgid.2.html)
++#[cfg(any(target_os = "linux", target_os = "android"))]
++pub fn setfsgid(gid: Gid) -> Gid {
++ let prev_fsgid = unsafe { libc::setfsgid(gid.into()) };
++ Gid::from_raw(prev_fsgid as gid_t)
++}
++
+ /// Get the list of supplementary group IDs of the calling process.
+ ///
+ /// [Further reading](http://pubs.opengroup.org/onlinepubs/009695399/functions/getgroups.html)
+@@ -1318,33 +1393,39 @@ pub fn setgid(gid: Gid) -> Result<()> {
+ /// with the `opendirectoryd` service.
+ #[cfg(not(any(target_os = "ios", target_os = "macos")))]
+ pub fn getgroups() -> Result<Vec<Gid>> {
+- // First get the number of groups so we can size our Vec
+- let ret = unsafe { libc::getgroups(0, ptr::null_mut()) };
++ // First get the maximum number of groups. The value returned
++ // shall always be greater than or equal to one and less than or
++ // equal to the value of {NGROUPS_MAX} + 1.
++ let ngroups_max = match sysconf(SysconfVar::NGROUPS_MAX) {
++ Ok(Some(n)) => (n + 1) as usize,
++ Ok(None) | Err(_) => <usize>::max_value(),
++ };
++
++ // Next, get the number of groups so we can size our Vec
++ let ngroups = unsafe { libc::getgroups(0, ptr::null_mut()) };
+
+ // Now actually get the groups. We try multiple times in case the number of
+ // groups has changed since the first call to getgroups() and the buffer is
+ // now too small.
+- let mut groups = Vec::<Gid>::with_capacity(Errno::result(ret)? as usize);
++ let mut groups = Vec::<Gid>::with_capacity(Errno::result(ngroups)? as usize);
+ loop {
+ // FIXME: On the platforms we currently support, the `Gid` struct has
+ // the same representation in memory as a bare `gid_t`. This is not
+ // necessarily the case on all Rust platforms, though. See RFC 1785.
+- let ret = unsafe {
++ let ngroups = unsafe {
+ libc::getgroups(groups.capacity() as c_int, groups.as_mut_ptr() as *mut gid_t)
+ };
+
+- match Errno::result(ret) {
++ match Errno::result(ngroups) {
+ Ok(s) => {
+ unsafe { groups.set_len(s as usize) };
+ return Ok(groups);
+ },
+ Err(Error::Sys(Errno::EINVAL)) => {
+- // EINVAL indicates that the buffer size was too small. Trigger
+- // the internal buffer resizing logic of `Vec` by requiring
+- // more space than the current capacity.
+- let cap = groups.capacity();
+- unsafe { groups.set_len(cap) };
+- groups.reserve(1);
++ // EINVAL indicates that the buffer size was too
++ // small, resize it up to ngroups_max as limit.
++ reserve_double_buffer_size(&mut groups, ngroups_max)
++ .or(Err(Error::Sys(Errno::EINVAL)))?;
+ },
+ Err(e) => return Err(e)
+ }
+@@ -1380,11 +1461,9 @@ pub fn getgroups() -> Result<Vec<Gid>> {
+ /// # Ok(())
+ /// # }
+ /// #
+-/// # fn main() {
+-/// # try_main().unwrap();
+-/// # }
++/// # try_main().unwrap();
+ /// ```
+-#[cfg(not(any(target_os = "ios", target_os = "macos")))]
++#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox")))]
+ pub fn setgroups(groups: &[Gid]) -> Result<()> {
+ cfg_if! {
+ if #[cfg(any(target_os = "dragonfly",
+@@ -1428,15 +1507,14 @@ pub fn setgroups(groups: &[Gid]) -> Result<()> {
+ /// and `setgroups()`. Additionally, while some implementations will return a
+ /// partial list of groups when `NGROUPS_MAX` is exceeded, this implementation
+ /// will only ever return the complete list or else an error.
+-#[cfg(not(any(target_os = "ios", target_os = "macos")))]
++#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox")))]
+ pub fn getgrouplist(user: &CStr, group: Gid) -> Result<Vec<Gid>> {
+ let ngroups_max = match sysconf(SysconfVar::NGROUPS_MAX) {
+ Ok(Some(n)) => n as c_int,
+ Ok(None) | Err(_) => <c_int>::max_value(),
+ };
+ use std::cmp::min;
+- let mut ngroups = min(ngroups_max, 8);
+- let mut groups = Vec::<Gid>::with_capacity(ngroups as usize);
++ let mut groups = Vec::<Gid>::with_capacity(min(ngroups_max, 8) as usize);
+ cfg_if! {
+ if #[cfg(any(target_os = "ios", target_os = "macos"))] {
+ type getgrouplist_group_t = c_int;
+@@ -1446,6 +1524,7 @@ pub fn getgrouplist(user: &CStr, group: Gid) -> Result<Vec<Gid>> {
+ }
+ let gid: gid_t = group.into();
+ loop {
++ let mut ngroups = groups.capacity() as i32;
+ let ret = unsafe {
+ libc::getgrouplist(user.as_ptr(),
+ gid as getgrouplist_group_t,
+@@ -1462,19 +1541,8 @@ pub fn getgrouplist(user: &CStr, group: Gid) -> Result<Vec<Gid>> {
+ // BSD systems will still fill the groups buffer with as many
+ // groups as possible, but Linux manpages do not mention this
+ // behavior.
+-
+- let cap = groups.capacity();
+- if cap >= ngroups_max as usize {
+- // We already have the largest capacity we can, give up
+- return Err(Error::invalid_argument());
+- }
+-
+- // Reserve space for at least ngroups
+- groups.reserve(ngroups as usize);
+-
+- // Even if the buffer gets resized to bigger than ngroups_max,
+- // don't ever ask for more than ngroups_max groups
+- ngroups = min(ngroups_max, groups.capacity() as c_int);
++ reserve_double_buffer_size(&mut groups, ngroups_max as usize)
++ .or_else(|_| Err(Error::invalid_argument()))?;
+ }
+ }
+ }
+@@ -1515,11 +1583,9 @@ pub fn getgrouplist(user: &CStr, group: Gid) -> Result<Vec<Gid>> {
+ /// # Ok(())
+ /// # }
+ /// #
+-/// # fn main() {
+-/// # try_main().unwrap();
+-/// # }
++/// # try_main().unwrap();
+ /// ```
+-#[cfg(not(any(target_os = "ios", target_os = "macos")))]
++#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox")))]
+ pub fn initgroups(user: &CStr, group: Gid) -> Result<()> {
+ cfg_if! {
+ if #[cfg(any(target_os = "ios", target_os = "macos"))] {
+@@ -1538,6 +1604,7 @@ pub fn initgroups(user: &CStr, group: Gid) -> Result<()> {
+ ///
+ /// See also [pause(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pause.html).
+ #[inline]
++#[cfg(not(target_os = "redox"))]
+ pub fn pause() {
+ unsafe { libc::pause() };
+ }
+@@ -1568,7 +1635,8 @@ pub mod alarm {
+ //!
+ //! Scheduling an alarm and waiting for the signal:
+ //!
+- //! ```
++#![cfg_attr(target_os = "redox", doc = " ```rust,ignore")]
++#![cfg_attr(not(target_os = "redox"), doc = " ```rust")]
+ //! use std::time::{Duration, Instant};
+ //!
+ //! use nix::unistd::{alarm, pause};
+@@ -1577,14 +1645,23 @@ pub mod alarm {
+ //! // We need to setup an empty signal handler to catch the alarm signal,
+ //! // otherwise the program will be terminated once the signal is delivered.
+ //! extern fn signal_handler(_: nix::libc::c_int) { }
+- //! unsafe { sigaction(Signal::SIGALRM, &SigAction::new(SigHandler::Handler(signal_handler), SaFlags::empty(), SigSet::empty())); }
++ //! let sa = SigAction::new(
++ //! SigHandler::Handler(signal_handler),
++ //! SaFlags::empty(),
++ //! SigSet::empty()
++ //! );
++ //! unsafe {
++ //! sigaction(Signal::SIGALRM, &sa);
++ //! }
+ //!
+ //! // Set an alarm for 1 second from now.
+ //! alarm::set(1);
+ //!
+ //! let start = Instant::now();
+ //! // Pause the process until the alarm signal is received.
+- //! pause();
++ //! let mut sigset = SigSet::empty();
++ //! sigset.add(Signal::SIGALRM);
++ //! sigset.wait();
+ //!
+ //! assert!(start.elapsed() >= Duration::from_secs(1));
+ //! ```
+@@ -1593,8 +1670,6 @@ pub mod alarm {
+ //!
+ //! See also [alarm(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/alarm.html).
+
+- use libc;
+-
+ /// Schedule an alarm signal.
+ ///
+ /// This will cause the system to generate a `SIGALRM` signal for the
+@@ -1630,10 +1705,10 @@ pub fn sleep(seconds: c_uint) -> c_uint {
+ unsafe { libc::sleep(seconds) }
+ }
+
++#[cfg(not(target_os = "redox"))]
+ pub mod acct {
+- use libc;
+- use {Result, NixPath};
+- use errno::Errno;
++ use crate::{Result, NixPath};
++ use crate::errno::Errno;
+ use std::ptr;
+
+ /// Enable process accounting
+@@ -1711,7 +1786,7 @@ pub fn mkstemp<P: ?Sized + NixPath>(template: &P) -> Result<(RawFd, PathBuf)> {
+ #[repr(i32)]
+ pub enum PathconfVar {
+ #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "linux",
+- target_os = "netbsd", target_os = "openbsd"))]
++ target_os = "netbsd", target_os = "openbsd", target_os = "redox"))]
+ /// Minimum number of bits needed to represent, as a signed integer value,
+ /// the maximum size of a regular file allowed in the specified directory.
+ FILESIZEBITS = libc::_PC_FILESIZEBITS,
+@@ -1735,11 +1810,11 @@ pub enum PathconfVar {
+ /// a pipe.
+ PIPE_BUF = libc::_PC_PIPE_BUF,
+ #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "linux",
+- target_os = "netbsd", target_os = "openbsd"))]
++ target_os = "netbsd", target_os = "openbsd", target_os = "redox"))]
+ /// Symbolic links can be created.
+ POSIX2_SYMLINKS = libc::_PC_2_SYMLINKS,
+ #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
+- target_os = "linux", target_os = "openbsd"))]
++ target_os = "linux", target_os = "openbsd", target_os = "redox"))]
+ /// Minimum number of bytes of storage actually allocated for any portion of
+ /// a file.
+ POSIX_ALLOC_SIZE_MIN = libc::_PC_ALLOC_SIZE_MIN,
+@@ -1749,19 +1824,20 @@ pub enum PathconfVar {
+ /// `POSIX_REC_MIN_XFER_SIZE` and `POSIX_REC_MAX_XFER_SIZE` values.
+ POSIX_REC_INCR_XFER_SIZE = libc::_PC_REC_INCR_XFER_SIZE,
+ #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
+- target_os = "linux", target_os = "openbsd"))]
++ target_os = "linux", target_os = "openbsd", target_os = "redox"))]
+ /// Maximum recommended file transfer size.
+ POSIX_REC_MAX_XFER_SIZE = libc::_PC_REC_MAX_XFER_SIZE,
+ #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
+- target_os = "linux", target_os = "openbsd"))]
++ target_os = "linux", target_os = "openbsd", target_os = "redox"))]
+ /// Minimum recommended file transfer size.
+ POSIX_REC_MIN_XFER_SIZE = libc::_PC_REC_MIN_XFER_SIZE,
+ #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
+- target_os = "linux", target_os = "openbsd"))]
++ target_os = "linux", target_os = "openbsd", target_os = "redox"))]
+ /// Recommended file transfer buffer alignment.
+ POSIX_REC_XFER_ALIGN = libc::_PC_REC_XFER_ALIGN,
+ #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
+- target_os = "linux", target_os = "netbsd", target_os = "openbsd"))]
++ target_os = "linux", target_os = "netbsd", target_os = "openbsd",
++ target_os = "redox"))]
+ /// Maximum number of bytes in a symbolic link.
+ SYMLINK_MAX = libc::_PC_SYMLINK_MAX,
+ /// The use of `chown` and `fchown` is restricted to a process with
+@@ -1775,17 +1851,18 @@ pub enum PathconfVar {
+ /// disable terminal special character handling.
+ _POSIX_VDISABLE = libc::_PC_VDISABLE,
+ #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
+- target_os = "linux", target_os = "openbsd"))]
++ target_os = "linux", target_os = "openbsd", target_os = "redox"))]
+ /// Asynchronous input or output operations may be performed for the
+ /// associated file.
+ _POSIX_ASYNC_IO = libc::_PC_ASYNC_IO,
+ #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
+- target_os = "linux", target_os = "openbsd"))]
++ target_os = "linux", target_os = "openbsd", target_os = "redox"))]
+ /// Prioritized input or output operations may be performed for the
+ /// associated file.
+ _POSIX_PRIO_IO = libc::_PC_PRIO_IO,
+ #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
+- target_os = "linux", target_os = "netbsd", target_os = "openbsd"))]
++ target_os = "linux", target_os = "netbsd", target_os = "openbsd",
++ target_os = "redox"))]
+ /// Synchronized input or output operations may be performed for the
+ /// associated file.
+ _POSIX_SYNC_IO = libc::_PC_SYNC_IO,
+@@ -1886,9 +1963,11 @@ pub fn pathconf<P: ?Sized + NixPath>(path: &P, var: PathconfVar) -> Result<Optio
+ pub enum SysconfVar {
+ /// Maximum number of I/O operations in a single list I/O call supported by
+ /// the implementation.
++ #[cfg(not(target_os = "redox"))]
+ AIO_LISTIO_MAX = libc::_SC_AIO_LISTIO_MAX,
+ /// Maximum number of outstanding asynchronous I/O operations supported by
+ /// the implementation.
++ #[cfg(not(target_os = "redox"))]
+ AIO_MAX = libc::_SC_AIO_MAX,
+ #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
+ target_os = "ios", target_os="linux", target_os = "macos",
+@@ -1899,25 +1978,34 @@ pub enum SysconfVar {
+ /// Maximum length of argument to the exec functions including environment data.
+ ARG_MAX = libc::_SC_ARG_MAX,
+ /// Maximum number of functions that may be registered with `atexit`.
++ #[cfg(not(target_os = "redox"))]
+ ATEXIT_MAX = libc::_SC_ATEXIT_MAX,
+ /// Maximum obase values allowed by the bc utility.
++ #[cfg(not(target_os = "redox"))]
+ BC_BASE_MAX = libc::_SC_BC_BASE_MAX,
+ /// Maximum number of elements permitted in an array by the bc utility.
++ #[cfg(not(target_os = "redox"))]
+ BC_DIM_MAX = libc::_SC_BC_DIM_MAX,
+ /// Maximum scale value allowed by the bc utility.
++ #[cfg(not(target_os = "redox"))]
+ BC_SCALE_MAX = libc::_SC_BC_SCALE_MAX,
+ /// Maximum length of a string constant accepted by the bc utility.
++ #[cfg(not(target_os = "redox"))]
+ BC_STRING_MAX = libc::_SC_BC_STRING_MAX,
+ /// Maximum number of simultaneous processes per real user ID.
+ CHILD_MAX = libc::_SC_CHILD_MAX,
+- // _SC_CLK_TCK is obsolete
++ // The number of clock ticks per second.
++ CLK_TCK = libc::_SC_CLK_TCK,
+ /// Maximum number of weights that can be assigned to an entry of the
+ /// LC_COLLATE order keyword in the locale definition file
++ #[cfg(not(target_os = "redox"))]
+ COLL_WEIGHTS_MAX = libc::_SC_COLL_WEIGHTS_MAX,
+ /// Maximum number of timer expiration overruns.
++ #[cfg(not(target_os = "redox"))]
+ DELAYTIMER_MAX = libc::_SC_DELAYTIMER_MAX,
+ /// Maximum number of expressions that can be nested within parentheses by
+ /// the expr utility.
++ #[cfg(not(target_os = "redox"))]
+ EXPR_NEST_MAX = libc::_SC_EXPR_NEST_MAX,
+ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
+ target_os="linux", target_os = "macos", target_os="netbsd",
+@@ -1927,23 +2015,29 @@ pub enum SysconfVar {
+ HOST_NAME_MAX = libc::_SC_HOST_NAME_MAX,
+ /// Maximum number of iovec structures that one process has available for
+ /// use with `readv` or `writev`.
++ #[cfg(not(target_os = "redox"))]
+ IOV_MAX = libc::_SC_IOV_MAX,
+ /// Unless otherwise noted, the maximum length, in bytes, of a utility's
+ /// input line (either standard input or another file), when the utility is
+ /// described as processing text files. The length includes room for the
+ /// trailing <newline>.
++ #[cfg(not(target_os = "redox"))]
+ LINE_MAX = libc::_SC_LINE_MAX,
+ /// Maximum length of a login name.
+ LOGIN_NAME_MAX = libc::_SC_LOGIN_NAME_MAX,
+ /// Maximum number of simultaneous supplementary group IDs per process.
+ NGROUPS_MAX = libc::_SC_NGROUPS_MAX,
+ /// Initial size of `getgrgid_r` and `getgrnam_r` data buffers
++ #[cfg(not(target_os = "redox"))]
+ GETGR_R_SIZE_MAX = libc::_SC_GETGR_R_SIZE_MAX,
+ /// Initial size of `getpwuid_r` and `getpwnam_r` data buffers
++ #[cfg(not(target_os = "redox"))]
+ GETPW_R_SIZE_MAX = libc::_SC_GETPW_R_SIZE_MAX,
+ /// The maximum number of open message queue descriptors a process may hold.
++ #[cfg(not(target_os = "redox"))]
+ MQ_OPEN_MAX = libc::_SC_MQ_OPEN_MAX,
+ /// The maximum number of message priorities supported by the implementation.
++ #[cfg(not(target_os = "redox"))]
+ MQ_PRIO_MAX = libc::_SC_MQ_PRIO_MAX,
+ /// A value one greater than the maximum value that the system may assign to
+ /// a newly-created file descriptor.
+@@ -1958,6 +2052,7 @@ pub enum SysconfVar {
+ /// The implementation supports barriers.
+ _POSIX_BARRIERS = libc::_SC_BARRIERS,
+ /// The implementation supports asynchronous input and output.
++ #[cfg(not(target_os = "redox"))]
+ _POSIX_ASYNCHRONOUS_IO = libc::_SC_ASYNCHRONOUS_IO,
+ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
+ target_os="linux", target_os = "macos", target_os="netbsd",
+@@ -1970,24 +2065,32 @@ pub enum SysconfVar {
+ /// The implementation supports the Process CPU-Time Clocks option.
+ _POSIX_CPUTIME = libc::_SC_CPUTIME,
+ /// The implementation supports the File Synchronization option.
++ #[cfg(not(target_os = "redox"))]
+ _POSIX_FSYNC = libc::_SC_FSYNC,
+ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
+ target_os="linux", target_os = "macos", target_os="openbsd"))]
+ /// The implementation supports the IPv6 option.
+ _POSIX_IPV6 = libc::_SC_IPV6,
+ /// The implementation supports job control.
++ #[cfg(not(target_os = "redox"))]
+ _POSIX_JOB_CONTROL = libc::_SC_JOB_CONTROL,
+ /// The implementation supports memory mapped Files.
++ #[cfg(not(target_os = "redox"))]
+ _POSIX_MAPPED_FILES = libc::_SC_MAPPED_FILES,
+ /// The implementation supports the Process Memory Locking option.
++ #[cfg(not(target_os = "redox"))]
+ _POSIX_MEMLOCK = libc::_SC_MEMLOCK,
+ /// The implementation supports the Range Memory Locking option.
++ #[cfg(not(target_os = "redox"))]
+ _POSIX_MEMLOCK_RANGE = libc::_SC_MEMLOCK_RANGE,
+ /// The implementation supports memory protection.
++ #[cfg(not(target_os = "redox"))]
+ _POSIX_MEMORY_PROTECTION = libc::_SC_MEMORY_PROTECTION,
+ /// The implementation supports the Message Passing option.
++ #[cfg(not(target_os = "redox"))]
+ _POSIX_MESSAGE_PASSING = libc::_SC_MESSAGE_PASSING,
+ /// The implementation supports the Monotonic Clock option.
++ #[cfg(not(target_os = "redox"))]
+ _POSIX_MONOTONIC_CLOCK = libc::_SC_MONOTONIC_CLOCK,
+ #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
+ target_os = "ios", target_os="linux", target_os = "macos",
+@@ -1995,6 +2098,7 @@ pub enum SysconfVar {
+ /// The implementation supports the Prioritized Input and Output option.
+ _POSIX_PRIORITIZED_IO = libc::_SC_PRIORITIZED_IO,
+ /// The implementation supports the Process Scheduling option.
++ #[cfg(not(target_os = "redox"))]
+ _POSIX_PRIORITY_SCHEDULING = libc::_SC_PRIORITY_SCHEDULING,
+ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
+ target_os="linux", target_os = "macos", target_os="openbsd"))]
+@@ -2016,10 +2120,13 @@ pub enum SysconfVar {
+ /// The implementation supports the Regular Expression Handling option.
+ _POSIX_REGEXP = libc::_SC_REGEXP,
+ /// Each process has a saved set-user-ID and a saved set-group-ID.
++ #[cfg(not(target_os = "redox"))]
+ _POSIX_SAVED_IDS = libc::_SC_SAVED_IDS,
+ /// The implementation supports semaphores.
++ #[cfg(not(target_os = "redox"))]
+ _POSIX_SEMAPHORES = libc::_SC_SEMAPHORES,
+ /// The implementation supports the Shared Memory Objects option.
++ #[cfg(not(target_os = "redox"))]
+ _POSIX_SHARED_MEMORY_OBJECTS = libc::_SC_SHARED_MEMORY_OBJECTS,
+ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
+ target_os="linux", target_os = "macos", target_os="netbsd",
+@@ -2044,10 +2151,13 @@ pub enum SysconfVar {
+ target_os="openbsd"))]
+ _POSIX_SS_REPL_MAX = libc::_SC_SS_REPL_MAX,
+ /// The implementation supports the Synchronized Input and Output option.
++ #[cfg(not(target_os = "redox"))]
+ _POSIX_SYNCHRONIZED_IO = libc::_SC_SYNCHRONIZED_IO,
+ /// The implementation supports the Thread Stack Address Attribute option.
++ #[cfg(not(target_os = "redox"))]
+ _POSIX_THREAD_ATTR_STACKADDR = libc::_SC_THREAD_ATTR_STACKADDR,
+ /// The implementation supports the Thread Stack Size Attribute option.
++ #[cfg(not(target_os = "redox"))]
+ _POSIX_THREAD_ATTR_STACKSIZE = libc::_SC_THREAD_ATTR_STACKSIZE,
+ #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos",
+ target_os="netbsd", target_os="openbsd"))]
+@@ -2055,10 +2165,13 @@ pub enum SysconfVar {
+ _POSIX_THREAD_CPUTIME = libc::_SC_THREAD_CPUTIME,
+ /// The implementation supports the Non-Robust Mutex Priority Inheritance
+ /// option.
++ #[cfg(not(target_os = "redox"))]
+ _POSIX_THREAD_PRIO_INHERIT = libc::_SC_THREAD_PRIO_INHERIT,
+ /// The implementation supports the Non-Robust Mutex Priority Protection option.
++ #[cfg(not(target_os = "redox"))]
+ _POSIX_THREAD_PRIO_PROTECT = libc::_SC_THREAD_PRIO_PROTECT,
+ /// The implementation supports the Thread Execution Scheduling option.
++ #[cfg(not(target_os = "redox"))]
+ _POSIX_THREAD_PRIORITY_SCHEDULING = libc::_SC_THREAD_PRIORITY_SCHEDULING,
+ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
+ target_os="linux", target_os = "macos", target_os="netbsd",
+@@ -2073,18 +2186,21 @@ pub enum SysconfVar {
+ /// The implementation supports the Robust Mutex Priority Protection option.
+ _POSIX_THREAD_ROBUST_PRIO_PROTECT = libc::_SC_THREAD_ROBUST_PRIO_PROTECT,
+ /// The implementation supports thread-safe functions.
++ #[cfg(not(target_os = "redox"))]
+ _POSIX_THREAD_SAFE_FUNCTIONS = libc::_SC_THREAD_SAFE_FUNCTIONS,
+ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
+ target_os="linux", target_os = "macos", target_os="openbsd"))]
+ /// The implementation supports the Thread Sporadic Server option.
+ _POSIX_THREAD_SPORADIC_SERVER = libc::_SC_THREAD_SPORADIC_SERVER,
+ /// The implementation supports threads.
++ #[cfg(not(target_os = "redox"))]
+ _POSIX_THREADS = libc::_SC_THREADS,
+ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
+ target_os="linux", target_os = "macos", target_os="openbsd"))]
+ /// The implementation supports timeouts.
+ _POSIX_TIMEOUTS = libc::_SC_TIMEOUTS,
+ /// The implementation supports timers.
++ #[cfg(not(target_os = "redox"))]
+ _POSIX_TIMERS = libc::_SC_TIMERS,
+ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
+ target_os="linux", target_os = "macos", target_os="openbsd"))]
+@@ -2149,17 +2265,23 @@ pub enum SysconfVar {
+ /// using at least 64 bits.
+ _POSIX_V6_LPBIG_OFFBIG = libc::_SC_V6_LPBIG_OFFBIG,
+ /// The implementation supports the C-Language Binding option.
++ #[cfg(not(target_os = "redox"))]
+ _POSIX2_C_BIND = libc::_SC_2_C_BIND,
+ /// The implementation supports the C-Language Development Utilities option.
++ #[cfg(not(target_os = "redox"))]
+ _POSIX2_C_DEV = libc::_SC_2_C_DEV,
+ /// The implementation supports the Terminal Characteristics option.
++ #[cfg(not(target_os = "redox"))]
+ _POSIX2_CHAR_TERM = libc::_SC_2_CHAR_TERM,
+ /// The implementation supports the FORTRAN Development Utilities option.
++ #[cfg(not(target_os = "redox"))]
+ _POSIX2_FORT_DEV = libc::_SC_2_FORT_DEV,
+ /// The implementation supports the FORTRAN Runtime Utilities option.
++ #[cfg(not(target_os = "redox"))]
+ _POSIX2_FORT_RUN = libc::_SC_2_FORT_RUN,
+ /// The implementation supports the creation of locales by the localedef
+ /// utility.
++ #[cfg(not(target_os = "redox"))]
+ _POSIX2_LOCALEDEF = libc::_SC_2_LOCALEDEF,
+ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
+ target_os="linux", target_os = "macos", target_os="netbsd",
+@@ -2193,26 +2315,34 @@ pub enum SysconfVar {
+ /// The implementation supports the Track Batch Job Request option.
+ _POSIX2_PBS_TRACK = libc::_SC_2_PBS_TRACK,
+ /// The implementation supports the Software Development Utilities option.
++ #[cfg(not(target_os = "redox"))]
+ _POSIX2_SW_DEV = libc::_SC_2_SW_DEV,
+ /// The implementation supports the User Portability Utilities option.
++ #[cfg(not(target_os = "redox"))]
+ _POSIX2_UPE = libc::_SC_2_UPE,
+ /// Integer value indicating version of the Shell and Utilities volume of
+ /// POSIX.1 to which the implementation conforms.
++ #[cfg(not(target_os = "redox"))]
+ _POSIX2_VERSION = libc::_SC_2_VERSION,
+ /// The size of a system page in bytes.
+ ///
+ /// POSIX also defines an alias named `PAGESIZE`, but Rust does not allow two
+ /// enum constants to have the same value, so nix omits `PAGESIZE`.
+ PAGE_SIZE = libc::_SC_PAGE_SIZE,
++ #[cfg(not(target_os = "redox"))]
+ PTHREAD_DESTRUCTOR_ITERATIONS = libc::_SC_THREAD_DESTRUCTOR_ITERATIONS,
++ #[cfg(not(target_os = "redox"))]
+ PTHREAD_KEYS_MAX = libc::_SC_THREAD_KEYS_MAX,
++ #[cfg(not(target_os = "redox"))]
+ PTHREAD_STACK_MIN = libc::_SC_THREAD_STACK_MIN,
++ #[cfg(not(target_os = "redox"))]
+ PTHREAD_THREADS_MAX = libc::_SC_THREAD_THREADS_MAX,
+ RE_DUP_MAX = libc::_SC_RE_DUP_MAX,
+ #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
+ target_os = "ios", target_os="linux", target_os = "macos",
+ target_os="openbsd"))]
+ RTSIG_MAX = libc::_SC_RTSIG_MAX,
++ #[cfg(not(target_os = "redox"))]
+ SEM_NSEMS_MAX = libc::_SC_SEM_NSEMS_MAX,
+ #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
+ target_os = "ios", target_os="linux", target_os = "macos",
+@@ -2227,6 +2357,7 @@ pub enum SysconfVar {
+ target_os="linux", target_os = "macos", target_os="netbsd",
+ target_os="openbsd"))]
+ SYMLOOP_MAX = libc::_SC_SYMLOOP_MAX,
++ #[cfg(not(target_os = "redox"))]
+ TIMER_MAX = libc::_SC_TIMER_MAX,
+ TTY_NAME_MAX = libc::_SC_TTY_NAME_MAX,
+ TZNAME_MAX = libc::_SC_TZNAME_MAX,
+@@ -2257,6 +2388,7 @@ pub enum SysconfVar {
+ _XOPEN_REALTIME_THREADS = libc::_SC_XOPEN_REALTIME_THREADS,
+ /// The implementation supports the Issue 4, Version 2 Shared Memory Option
+ /// Group.
++ #[cfg(not(target_os = "redox"))]
+ _XOPEN_SHM = libc::_SC_XOPEN_SHM,
+ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
+ target_os="linux", target_os = "macos", target_os="openbsd"))]
+@@ -2309,9 +2441,8 @@ pub fn sysconf(var: SysconfVar) -> Result<Option<c_long>> {
+
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ mod pivot_root {
+- use libc;
+- use {Result, NixPath};
+- use errno::Errno;
++ use crate::{Result, NixPath};
++ use crate::errno::Errno;
+
+ pub fn pivot_root<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(
+ new_root: &P1, put_old: &P2) -> Result<()> {
+@@ -2330,9 +2461,8 @@ mod pivot_root {
+ #[cfg(any(target_os = "android", target_os = "freebsd",
+ target_os = "linux", target_os = "openbsd"))]
+ mod setres {
+- use libc;
+- use Result;
+- use errno::Errno;
++ use crate::Result;
++ use crate::errno::Errno;
+ use super::{Uid, Gid};
+
+ /// Sets the real, effective, and saved uid.
+@@ -2392,3 +2522,308 @@ pub fn access<P: ?Sized + NixPath>(path: &P, amode: AccessFlags) -> Result<()> {
+ })?;
+ Errno::result(res).map(drop)
+ }
++
++/// Representation of a User, based on `libc::passwd`
++///
++/// The reason some fields in this struct are `String` and others are `CString` is because some
++/// fields are based on the user's locale, which could be non-UTF8, while other fields are
++/// guaranteed to conform to [`NAME_REGEX`](https://serverfault.com/a/73101/407341), which only
++/// contains ASCII.
++#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd
++#[derive(Debug, Clone, PartialEq)]
++pub struct User {
++ /// Username
++ pub name: String,
++ /// User password (probably encrypted)
++ pub passwd: CString,
++ /// User ID
++ pub uid: Uid,
++ /// Group ID
++ pub gid: Gid,
++ /// User information
++ #[cfg(not(target_os = "android"))]
++ pub gecos: CString,
++ /// Home directory
++ pub dir: PathBuf,
++ /// Path to shell
++ pub shell: PathBuf,
++ /// Login class
++ #[cfg(not(any(target_os = "android", target_os = "fuchsia",
++ target_os = "linux")))]
++ pub class: CString,
++ /// Last password change
++ #[cfg(not(any(target_os = "android", target_os = "fuchsia",
++ target_os = "linux")))]
++ pub change: libc::time_t,
++ /// Expiration time of account
++ #[cfg(not(any(target_os = "android", target_os = "fuchsia",
++ target_os = "linux")))]
++ pub expire: libc::time_t
++}
++
++#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd
++impl From<&libc::passwd> for User {
++ fn from(pw: &libc::passwd) -> User {
++ unsafe {
++ User {
++ name: CStr::from_ptr((*pw).pw_name).to_string_lossy().into_owned(),
++ passwd: CString::new(CStr::from_ptr((*pw).pw_passwd).to_bytes()).unwrap(),
++ #[cfg(not(target_os = "android"))]
++ gecos: CString::new(CStr::from_ptr((*pw).pw_gecos).to_bytes()).unwrap(),
++ dir: PathBuf::from(OsStr::from_bytes(CStr::from_ptr((*pw).pw_dir).to_bytes())),
++ shell: PathBuf::from(OsStr::from_bytes(CStr::from_ptr((*pw).pw_shell).to_bytes())),
++ uid: Uid::from_raw((*pw).pw_uid),
++ gid: Gid::from_raw((*pw).pw_gid),
++ #[cfg(not(any(target_os = "android", target_os = "fuchsia",
++ target_os = "linux")))]
++ class: CString::new(CStr::from_ptr((*pw).pw_class).to_bytes()).unwrap(),
++ #[cfg(not(any(target_os = "android", target_os = "fuchsia",
++ target_os = "linux")))]
++ change: (*pw).pw_change,
++ #[cfg(not(any(target_os = "android", target_os = "fuchsia",
++ target_os = "linux")))]
++ expire: (*pw).pw_expire
++ }
++ }
++ }
++}
++
++#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd
++impl User {
++ fn from_anything<F>(f: F) -> Result<Option<Self>>
++ where
++ F: Fn(*mut libc::passwd,
++ *mut libc::c_char,
++ libc::size_t,
++ *mut *mut libc::passwd) -> libc::c_int
++ {
++ let buflimit = 16384;
++ let bufsize = match sysconf(SysconfVar::GETPW_R_SIZE_MAX) {
++ Ok(Some(n)) => n as usize,
++ Ok(None) | Err(_) => buflimit as usize,
++ };
++
++ let mut cbuf = Vec::with_capacity(bufsize);
++ let mut pwd = mem::MaybeUninit::<libc::passwd>::uninit();
++ let mut res = ptr::null_mut();
++
++ loop {
++ let error = f(pwd.as_mut_ptr(), cbuf.as_mut_ptr(), cbuf.capacity(), &mut res);
++ if error == 0 {
++ if res.is_null() {
++ return Ok(None);
++ } else {
++ let pwd = unsafe { pwd.assume_init() };
++ return Ok(Some(User::from(&pwd)));
++ }
++ } else if Errno::last() == Errno::ERANGE {
++ // Trigger the internal buffer resizing logic.
++ reserve_double_buffer_size(&mut cbuf, buflimit)?;
++ } else {
++ return Err(Error::Sys(Errno::last()));
++ }
++ }
++ }
++
++ /// Get a user by UID.
++ ///
++ /// Internally, this function calls
++ /// [getpwuid_r(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html)
++ ///
++ /// # Examples
++ ///
++ /// ```
++ /// use nix::unistd::{Uid, User};
++ /// // Returns an Result<Option<User>>, thus the double unwrap.
++ /// let res = User::from_uid(Uid::from_raw(0)).unwrap().unwrap();
++ /// assert!(res.name == "root");
++ /// ```
++ pub fn from_uid(uid: Uid) -> Result<Option<Self>> {
++ User::from_anything(|pwd, cbuf, cap, res| {
++ unsafe { libc::getpwuid_r(uid.0, pwd, cbuf, cap, res) }
++ })
++ }
++
++ /// Get a user by name.
++ ///
++ /// Internally, this function calls
++ /// [getpwnam_r(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html)
++ ///
++ /// # Examples
++ ///
++ /// ```
++ /// use nix::unistd::User;
++ /// // Returns an Result<Option<User>>, thus the double unwrap.
++ /// let res = User::from_name("root").unwrap().unwrap();
++ /// assert!(res.name == "root");
++ /// ```
++ pub fn from_name(name: &str) -> Result<Option<Self>> {
++ let name = CString::new(name).unwrap();
++ User::from_anything(|pwd, cbuf, cap, res| {
++ unsafe { libc::getpwnam_r(name.as_ptr(), pwd, cbuf, cap, res) }
++ })
++ }
++}
++
++/// Representation of a Group, based on `libc::group`
++#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd
++#[derive(Debug, Clone, PartialEq)]
++pub struct Group {
++ /// Group name
++ pub name: String,
++ /// Group password
++ pub passwd: CString,
++ /// Group ID
++ pub gid: Gid,
++ /// List of Group members
++ pub mem: Vec<String>
++}
++
++#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd
++impl From<&libc::group> for Group {
++ fn from(gr: &libc::group) -> Group {
++ unsafe {
++ Group {
++ name: CStr::from_ptr((*gr).gr_name).to_string_lossy().into_owned(),
++ passwd: CString::new(CStr::from_ptr((*gr).gr_passwd).to_bytes()).unwrap(),
++ gid: Gid::from_raw((*gr).gr_gid),
++ mem: Group::members((*gr).gr_mem)
++ }
++ }
++ }
++}
++
++#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd
++impl Group {
++ unsafe fn members(mem: *mut *mut c_char) -> Vec<String> {
++ let mut ret = Vec::new();
++
++ for i in 0.. {
++ let u = mem.offset(i);
++ if (*u).is_null() {
++ break;
++ } else {
++ let s = CStr::from_ptr(*u).to_string_lossy().into_owned();
++ ret.push(s);
++ }
++ }
++
++ ret
++ }
++
++ fn from_anything<F>(f: F) -> Result<Option<Self>>
++ where
++ F: Fn(*mut libc::group,
++ *mut libc::c_char,
++ libc::size_t,
++ *mut *mut libc::group) -> libc::c_int
++ {
++ let buflimit = 16384;
++ let bufsize = match sysconf(SysconfVar::GETGR_R_SIZE_MAX) {
++ Ok(Some(n)) => n as usize,
++ Ok(None) | Err(_) => buflimit as usize,
++ };
++
++ let mut cbuf = Vec::with_capacity(bufsize);
++ let mut grp = mem::MaybeUninit::<libc::group>::uninit();
++ let mut res = ptr::null_mut();
++
++ loop {
++ let error = f(grp.as_mut_ptr(), cbuf.as_mut_ptr(), cbuf.capacity(), &mut res);
++ if error == 0 {
++ if res.is_null() {
++ return Ok(None);
++ } else {
++ let grp = unsafe { grp.assume_init() };
++ return Ok(Some(Group::from(&grp)));
++ }
++ } else if Errno::last() == Errno::ERANGE {
++ // Trigger the internal buffer resizing logic.
++ reserve_double_buffer_size(&mut cbuf, buflimit)?;
++ } else {
++ return Err(Error::Sys(Errno::last()));
++ }
++ }
++ }
++
++ /// Get a group by GID.
++ ///
++ /// Internally, this function calls
++ /// [getgrgid_r(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html)
++ ///
++ /// # Examples
++ ///
++ // Disable this test on all OS except Linux as root group may not exist.
++ #[cfg_attr(not(target_os = "linux"), doc = " ```no_run")]
++ #[cfg_attr(target_os = "linux", doc = " ```")]
++ /// use nix::unistd::{Gid, Group};
++ /// // Returns an Result<Option<Group>>, thus the double unwrap.
++ /// let res = Group::from_gid(Gid::from_raw(0)).unwrap().unwrap();
++ /// assert!(res.name == "root");
++ /// ```
++ pub fn from_gid(gid: Gid) -> Result<Option<Self>> {
++ Group::from_anything(|grp, cbuf, cap, res| {
++ unsafe { libc::getgrgid_r(gid.0, grp, cbuf, cap, res) }
++ })
++ }
++
++ /// Get a group by name.
++ ///
++ /// Internally, this function calls
++ /// [getgrnam_r(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html)
++ ///
++ /// # Examples
++ ///
++ // Disable this test on all OS except Linux as root group may not exist.
++ #[cfg_attr(not(target_os = "linux"), doc = " ```no_run")]
++ #[cfg_attr(target_os = "linux", doc = " ```")]
++ /// use nix::unistd::Group;
++ /// // Returns an Result<Option<Group>>, thus the double unwrap.
++ /// let res = Group::from_name("root").unwrap().unwrap();
++ /// assert!(res.name == "root");
++ /// ```
++ pub fn from_name(name: &str) -> Result<Option<Self>> {
++ let name = CString::new(name).unwrap();
++ Group::from_anything(|grp, cbuf, cap, res| {
++ unsafe { libc::getgrnam_r(name.as_ptr(), grp, cbuf, cap, res) }
++ })
++ }
++}
++
++/// Get the name of the terminal device that is open on file descriptor fd
++/// (see [`ttyname(3)`](http://man7.org/linux/man-pages/man3/ttyname.3.html)).
++#[cfg(not(target_os = "fuchsia"))]
++pub fn ttyname(fd: RawFd) -> Result<PathBuf> {
++ const PATH_MAX: usize = libc::PATH_MAX as usize;
++ let mut buf = vec![0_u8; PATH_MAX];
++ let c_buf = buf.as_mut_ptr() as *mut libc::c_char;
++
++ let ret = unsafe { libc::ttyname_r(fd, c_buf, buf.len()) };
++ if ret != 0 {
++ return Err(Error::Sys(Errno::from_i32(ret)));
++ }
++
++ let nul = buf.iter().position(|c| *c == b'\0').unwrap();
++ buf.truncate(nul);
++ Ok(OsString::from_vec(buf).into())
++}
++
++/// Get the effective user ID and group ID associated with a Unix domain socket.
++///
++/// See also [getpeereid(3)](https://www.freebsd.org/cgi/man.cgi?query=getpeereid)
++#[cfg(any(
++ target_os = "macos",
++ target_os = "ios",
++ target_os = "freebsd",
++ target_os = "openbsd",
++ target_os = "netbsd",
++ target_os = "dragonfly",
++))]
++pub fn getpeereid(fd: RawFd) -> Result<(Uid, Gid)> {
++ let mut uid = 1;
++ let mut gid = 1;
++
++ let ret = unsafe { libc::getpeereid(fd, &mut uid, &mut gid) };
++
++ Errno::result(ret).map(|_| (Uid(uid), Gid(gid)))
++}
+diff --git a/third_party/rust/nix/test/common/mod.rs b/third_party/rust/nix/test/common/mod.rs
+new file mode 100644
+index 0000000000000..a871b47041d3e
+--- /dev/null
++++ b/third_party/rust/nix/test/common/mod.rs
+@@ -0,0 +1,127 @@
++use cfg_if::cfg_if;
++
++#[macro_export] macro_rules! skip {
++ ($($reason: expr),+) => {
++ use ::std::io::{self, Write};
++
++ let stderr = io::stderr();
++ let mut handle = stderr.lock();
++ writeln!(handle, $($reason),+).unwrap();
++ return;
++ }
++}
++
++cfg_if! {
++ if #[cfg(any(target_os = "android", target_os = "linux"))] {
++ #[macro_export] macro_rules! require_capability {
++ ($capname:ident) => {
++ use ::caps::{Capability, CapSet, has_cap};
++
++ if !has_cap(None, CapSet::Effective, Capability::$capname)
++ .unwrap()
++ {
++ skip!("Insufficient capabilities. Skipping test.");
++ }
++ }
++ }
++ } else if #[cfg(not(target_os = "redox"))] {
++ #[macro_export] macro_rules! require_capability {
++ ($capname:ident) => {}
++ }
++ }
++}
++
++#[cfg(any(target_os = "linux", target_os= "android"))]
++#[macro_export] macro_rules! skip_if_cirrus {
++ ($reason:expr) => {
++ if std::env::var_os("CIRRUS_CI").is_some() {
++ skip!("{}", $reason);
++ }
++ }
++}
++
++#[cfg(target_os = "freebsd")]
++#[macro_export] macro_rules! skip_if_jailed {
++ ($name:expr) => {
++ use ::sysctl::CtlValue;
++
++ if let CtlValue::Int(1) = ::sysctl::value("security.jail.jailed")
++ .unwrap()
++ {
++ skip!("{} cannot run in a jail. Skipping test.", $name);
++ }
++ }
++}
++
++#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
++#[macro_export] macro_rules! skip_if_not_root {
++ ($name:expr) => {
++ use nix::unistd::Uid;
++
++ if !Uid::current().is_root() {
++ skip!("{} requires root privileges. Skipping test.", $name);
++ }
++ };
++}
++
++cfg_if! {
++ if #[cfg(any(target_os = "android", target_os = "linux"))] {
++ #[macro_export] macro_rules! skip_if_seccomp {
++ ($name:expr) => {
++ if let Ok(s) = std::fs::read_to_string("/proc/self/status") {
++ for l in s.lines() {
++ let mut fields = l.split_whitespace();
++ if fields.next() == Some("Seccomp:") &&
++ fields.next() != Some("0")
++ {
++ skip!("{} cannot be run in Seccomp mode. Skipping test.",
++ stringify!($name));
++ }
++ }
++ }
++ }
++ }
++ } else if #[cfg(not(target_os = "redox"))] {
++ #[macro_export] macro_rules! skip_if_seccomp {
++ ($name:expr) => {}
++ }
++ }
++}
++
++cfg_if! {
++ if #[cfg(target_os = "linux")] {
++ #[macro_export] macro_rules! require_kernel_version {
++ ($name:expr, $version_requirement:expr) => {
++ use semver::{Version, VersionReq};
++
++ let version_requirement = VersionReq::parse($version_requirement)
++ .expect("Bad match_version provided");
++
++ let uname = nix::sys::utsname::uname();
++ println!("{}", uname.sysname());
++ println!("{}", uname.nodename());
++ println!("{}", uname.release());
++ println!("{}", uname.version());
++ println!("{}", uname.machine());
++
++ // Fix stuff that the semver parser can't handle
++ let fixed_release = &uname.release().to_string()
++ // Fedora 33 reports version as 4.18.el8_2.x86_64 or
++ // 5.18.200-fc33.x86_64. Remove the underscore.
++ .replace("_", "-")
++ // Cirrus-CI reports version as 4.19.112+ . Remove the +
++ .replace("+", "");
++ let mut version = Version::parse(fixed_release).unwrap();
++
++ //Keep only numeric parts
++ version.pre.clear();
++ version.build.clear();
++
++ if !version_requirement.matches(&version) {
++ skip!("Skip {} because kernel version `{}` doesn't match the requirement `{}`",
++ stringify!($name), version, version_requirement);
++ }
++ }
++ }
++ }
++}
+diff --git a/third_party/rust/nix/test/sys/mod.rs b/third_party/rust/nix/test/sys/mod.rs
+index 60a58dd106f19..14b03784a0a57 100644
+--- a/third_party/rust/nix/test/sys/mod.rs
++++ b/third_party/rust/nix/test/sys/mod.rs
+@@ -13,12 +13,17 @@ mod test_signal;
+ mod test_aio;
+ #[cfg(target_os = "linux")]
+ mod test_signalfd;
++#[cfg(not(target_os = "redox"))]
+ mod test_socket;
++#[cfg(not(target_os = "redox"))]
+ mod test_sockopt;
++#[cfg(not(target_os = "redox"))]
+ mod test_select;
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ mod test_sysinfo;
++#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
+ mod test_termios;
++#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
+ mod test_ioctl;
+ mod test_wait;
+ mod test_uio;
+@@ -36,3 +41,5 @@ mod test_pthread;
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ mod test_ptrace;
++#[cfg(any(target_os = "android", target_os = "linux"))]
++mod test_timerfd;
+diff --git a/third_party/rust/nix/test/sys/test_aio.rs b/third_party/rust/nix/test/sys/test_aio.rs
+index d4b09b0b81905..3878da94a6ef6 100644
+--- a/third_party/rust/nix/test/sys/test_aio.rs
++++ b/third_party/rust/nix/test/sys/test_aio.rs
+@@ -47,7 +47,7 @@ fn test_accessors() {
+ // our bindings. So it's sufficient to check that AioCb.cancel returned any
+ // AioCancelStat value.
+ #[test]
+-#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
++#[cfg_attr(target_env = "musl", ignore)]
+ fn test_cancel() {
+ let wbuf: &[u8] = b"CDEF";
+
+@@ -72,7 +72,7 @@ fn test_cancel() {
+
+ // Tests using aio_cancel_all for all outstanding IOs.
+ #[test]
+-#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
++#[cfg_attr(target_env = "musl", ignore)]
+ fn test_aio_cancel_all() {
+ let wbuf: &[u8] = b"CDEF";
+
+@@ -133,6 +133,13 @@ fn test_fsync_error() {
+
+ #[test]
+ #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
++// On Travis, aio_suspend hits an assertion within glibc. This is either a bug
++// in Travis's version of glibc or Linux. Either way, we must skip the test.
++// https://github.com/nix-rust/nix/issues/1099
++#[cfg_attr(target_os = "linux", ignore)]
++// On Cirrus, aio_suspend is failing with EINVAL
++// https://github.com/nix-rust/nix/issues/1361
++#[cfg_attr(target_os = "macos", ignore)]
+ fn test_aio_suspend() {
+ const INITIAL: &[u8] = b"abcdef123456";
+ const WBUF: &[u8] = b"CDEFG";
+@@ -160,7 +167,12 @@ fn test_aio_suspend() {
+ loop {
+ {
+ let cbbuf = [&wcb, &rcb];
+- assert!(aio_suspend(&cbbuf[..], Some(timeout)).is_ok());
++ let r = aio_suspend(&cbbuf[..], Some(timeout));
++ match r {
++ Err(Error::Sys(Errno::EINTR)) => continue,
++ Err(e) => panic!("aio_suspend returned {:?}", e),
++ Ok(_) => ()
++ };
+ }
+ if rcb.error() != Err(Error::from(Errno::EINPROGRESS)) &&
+ wcb.error() != Err(Error::from(Errno::EINPROGRESS)) {
+@@ -168,8 +180,8 @@ fn test_aio_suspend() {
+ }
+ }
+
+- assert!(wcb.aio_return().unwrap() as usize == WBUF.len());
+- assert!(rcb.aio_return().unwrap() as usize == rlen);
++ assert_eq!(wcb.aio_return().unwrap() as usize, WBUF.len());
++ assert_eq!(rcb.aio_return().unwrap() as usize, rlen);
+ }
+
+ // Test a simple aio operation with no completion notification. We must poll
+@@ -192,11 +204,11 @@ fn test_read() {
+ aiocb.read().unwrap();
+
+ let err = poll_aio(&mut aiocb);
+- assert!(err == Ok(()));
+- assert!(aiocb.aio_return().unwrap() as usize == EXPECT.len());
++ assert_eq!(err, Ok(()));
++ assert_eq!(aiocb.aio_return().unwrap() as usize, EXPECT.len());
+ }
+
+- assert!(EXPECT == rbuf.deref().deref());
++ assert_eq!(EXPECT, rbuf.deref().deref());
+ }
+
+ /// `AioCb::read` should not modify the `AioCb` object if `libc::aio_read`
+@@ -238,11 +250,11 @@ fn test_read_into_mut_slice() {
+ aiocb.read().unwrap();
+
+ let err = poll_aio(&mut aiocb);
+- assert!(err == Ok(()));
+- assert!(aiocb.aio_return().unwrap() as usize == EXPECT.len());
++ assert_eq!(err, Ok(()));
++ assert_eq!(aiocb.aio_return().unwrap() as usize, EXPECT.len());
+ }
+
+- assert!(rbuf == EXPECT);
++ assert_eq!(rbuf, EXPECT);
+ }
+
+ // Tests from_ptr
+@@ -268,11 +280,11 @@ fn test_read_into_pointer() {
+ aiocb.read().unwrap();
+
+ let err = poll_aio(&mut aiocb);
+- assert!(err == Ok(()));
+- assert!(aiocb.aio_return().unwrap() as usize == EXPECT.len());
++ assert_eq!(err, Ok(()));
++ assert_eq!(aiocb.aio_return().unwrap() as usize, EXPECT.len());
+ }
+
+- assert!(rbuf == EXPECT);
++ assert_eq!(rbuf, EXPECT);
+ }
+
+ // Test reading into an immutable buffer. It should fail
+@@ -314,13 +326,13 @@ fn test_write() {
+ aiocb.write().unwrap();
+
+ let err = poll_aio(&mut aiocb);
+- assert!(err == Ok(()));
+- assert!(aiocb.aio_return().unwrap() as usize == wbuf.len());
++ assert_eq!(err, Ok(()));
++ assert_eq!(aiocb.aio_return().unwrap() as usize, wbuf.len());
+
+ f.seek(SeekFrom::Start(0)).unwrap();
+ let len = f.read_to_end(&mut rbuf).unwrap();
+- assert!(len == EXPECT.len());
+- assert!(rbuf == EXPECT);
++ assert_eq!(len, EXPECT.len());
++ assert_eq!(rbuf, EXPECT);
+ }
+
+ // Tests `AioCb::from_boxed_slice` with `Bytes`
+@@ -344,13 +356,13 @@ fn test_write_bytes() {
+ aiocb.write().unwrap();
+
+ let err = poll_aio(&mut aiocb);
+- assert!(err == Ok(()));
+- assert!(aiocb.aio_return().unwrap() as usize == expected_len);
++ assert_eq!(err, Ok(()));
++ assert_eq!(aiocb.aio_return().unwrap() as usize, expected_len);
+
+ f.seek(SeekFrom::Start(0)).unwrap();
+ let len = f.read_to_end(&mut rbuf).unwrap();
+- assert!(len == EXPECT.len());
+- assert!(rbuf == EXPECT);
++ assert_eq!(len, EXPECT.len());
++ assert_eq!(rbuf, EXPECT);
+ }
+
+ // Tests `AioCb::from_boxed_mut_slice` with `BytesMut`
+@@ -402,13 +414,13 @@ fn test_write_from_pointer() {
+ aiocb.write().unwrap();
+
+ let err = poll_aio(&mut aiocb);
+- assert!(err == Ok(()));
+- assert!(aiocb.aio_return().unwrap() as usize == wbuf.len());
++ assert_eq!(err, Ok(()));
++ assert_eq!(aiocb.aio_return().unwrap() as usize, wbuf.len());
+
+ f.seek(SeekFrom::Start(0)).unwrap();
+ let len = f.read_to_end(&mut rbuf).unwrap();
+- assert!(len == EXPECT.len());
+- assert!(rbuf == EXPECT);
++ assert_eq!(len, EXPECT.len());
++ assert_eq!(rbuf, EXPECT);
+ }
+
+ /// `AioCb::write` should not modify the `AioCb` object if `libc::aio_write`
+@@ -441,7 +453,7 @@ extern fn sigfunc(_: c_int) {
+ #[test]
+ #[cfg_attr(any(all(target_env = "musl", target_arch = "x86_64"), target_arch = "mips", target_arch = "mips64"), ignore)]
+ fn test_write_sigev_signal() {
+- let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
++ let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
+ let sa = SigAction::new(SigHandler::Handler(sigfunc),
+ SaFlags::SA_RESETHAND,
+ SigSet::empty());
+@@ -469,11 +481,11 @@ fn test_write_sigev_signal() {
+ thread::sleep(time::Duration::from_millis(10));
+ }
+
+- assert!(aiocb.aio_return().unwrap() as usize == WBUF.len());
++ assert_eq!(aiocb.aio_return().unwrap() as usize, WBUF.len());
+ f.seek(SeekFrom::Start(0)).unwrap();
+ let len = f.read_to_end(&mut rbuf).unwrap();
+- assert!(len == EXPECT.len());
+- assert!(rbuf == EXPECT);
++ assert_eq!(len, EXPECT.len());
++ assert_eq!(rbuf, EXPECT);
+ }
+
+ // Test LioCb::listio with LIO_WAIT, so all AIO ops should be complete by the
+@@ -512,15 +524,15 @@ fn test_liocb_listio_wait() {
+ let err = liocb.listio(LioMode::LIO_WAIT, SigevNotify::SigevNone);
+ err.expect("lio_listio");
+
+- assert!(liocb.aio_return(0).unwrap() as usize == WBUF.len());
+- assert!(liocb.aio_return(1).unwrap() as usize == rlen);
++ assert_eq!(liocb.aio_return(0).unwrap() as usize, WBUF.len());
++ assert_eq!(liocb.aio_return(1).unwrap() as usize, rlen);
+ }
+- assert!(rbuf.deref().deref() == b"3456");
++ assert_eq!(rbuf.deref().deref(), b"3456");
+
+ f.seek(SeekFrom::Start(0)).unwrap();
+ let len = f.read_to_end(&mut rbuf2).unwrap();
+- assert!(len == EXPECT.len());
+- assert!(rbuf2 == EXPECT);
++ assert_eq!(len, EXPECT.len());
++ assert_eq!(rbuf2, EXPECT);
+ }
+
+ // Test LioCb::listio with LIO_NOWAIT and no SigEvent, so we must use some other
+@@ -561,15 +573,15 @@ fn test_liocb_listio_nowait() {
+
+ poll_aio(&mut liocb.aiocbs[0]).unwrap();
+ poll_aio(&mut liocb.aiocbs[1]).unwrap();
+- assert!(liocb.aiocbs[0].aio_return().unwrap() as usize == WBUF.len());
+- assert!(liocb.aiocbs[1].aio_return().unwrap() as usize == rlen);
++ assert_eq!(liocb.aiocbs[0].aio_return().unwrap() as usize, WBUF.len());
++ assert_eq!(liocb.aiocbs[1].aio_return().unwrap() as usize, rlen);
+ }
+- assert!(rbuf.deref().deref() == b"3456");
++ assert_eq!(rbuf.deref().deref(), b"3456");
+
+ f.seek(SeekFrom::Start(0)).unwrap();
+ let len = f.read_to_end(&mut rbuf2).unwrap();
+- assert!(len == EXPECT.len());
+- assert!(rbuf2 == EXPECT);
++ assert_eq!(len, EXPECT.len());
++ assert_eq!(rbuf2, EXPECT);
+ }
+
+ // Test LioCb::listio with LIO_NOWAIT and a SigEvent to indicate when all
+@@ -579,7 +591,7 @@ fn test_liocb_listio_nowait() {
+ #[cfg(not(any(target_os = "ios", target_os = "macos")))]
+ #[cfg_attr(any(target_arch = "mips", target_arch = "mips64", target_env = "musl"), ignore)]
+ fn test_liocb_listio_signal() {
+- let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
++ let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
+ const INITIAL: &[u8] = b"abcdef123456";
+ const WBUF: &[u8] = b"CDEF";
+ let mut rbuf = vec![0; 4];
+@@ -620,15 +632,15 @@ fn test_liocb_listio_signal() {
+ thread::sleep(time::Duration::from_millis(10));
+ }
+
+- assert!(liocb.aiocbs[0].aio_return().unwrap() as usize == WBUF.len());
+- assert!(liocb.aiocbs[1].aio_return().unwrap() as usize == rlen);
++ assert_eq!(liocb.aiocbs[0].aio_return().unwrap() as usize, WBUF.len());
++ assert_eq!(liocb.aiocbs[1].aio_return().unwrap() as usize, rlen);
+ }
+- assert!(rbuf.deref().deref() == b"3456");
++ assert_eq!(rbuf.deref().deref(), b"3456");
+
+ f.seek(SeekFrom::Start(0)).unwrap();
+ let len = f.read_to_end(&mut rbuf2).unwrap();
+- assert!(len == EXPECT.len());
+- assert!(rbuf2 == EXPECT);
++ assert_eq!(len, EXPECT.len());
++ assert_eq!(rbuf2, EXPECT);
+ }
+
+ // Try to use LioCb::listio to read into an immutable buffer. It should fail
+diff --git a/third_party/rust/nix/test/sys/test_aio_drop.rs b/third_party/rust/nix/test/sys/test_aio_drop.rs
+index 492da401ef726..784ee3ef6c75e 100644
+--- a/third_party/rust/nix/test/sys/test_aio_drop.rs
++++ b/third_party/rust/nix/test/sys/test_aio_drop.rs
+@@ -1,6 +1,3 @@
+-extern crate nix;
+-extern crate tempfile;
+-
+ // Test dropping an AioCb that hasn't yet finished.
+ // This must happen in its own process, because on OSX this test seems to hose
+ // the AIO subsystem and causes subsequent tests to fail
+@@ -12,6 +9,7 @@ extern crate tempfile;
+ target_os = "macos",
+ target_os = "freebsd",
+ target_os = "netbsd")))]
++#[cfg_attr(target_env = "gnu", ignore = "Occasionally fails in Travis; glibc bug suspected")]
+ fn test_drop() {
+ use nix::sys::aio::*;
+ use nix::sys::signal::*;
+diff --git a/third_party/rust/nix/test/sys/test_ioctl.rs b/third_party/rust/nix/test/sys/test_ioctl.rs
+index 0a439b3346f53..fa4510a69c089 100644
+--- a/third_party/rust/nix/test/sys/test_ioctl.rs
++++ b/third_party/rust/nix/test/sys/test_ioctl.rs
+@@ -33,22 +33,22 @@ mod linux {
+ #[test]
+ fn test_op_none() {
+ if cfg!(any(target_arch = "mips", target_arch = "mips64", target_arch="powerpc", target_arch="powerpc64")){
+- assert_eq!(request_code_none!(b'q', 10), 0x2000_710A);
+- assert_eq!(request_code_none!(b'a', 255), 0x2000_61FF);
++ assert_eq!(request_code_none!(b'q', 10) as u32, 0x2000_710A);
++ assert_eq!(request_code_none!(b'a', 255) as u32, 0x2000_61FF);
+ } else {
+- assert_eq!(request_code_none!(b'q', 10), 0x0000_710A);
+- assert_eq!(request_code_none!(b'a', 255), 0x0000_61FF);
++ assert_eq!(request_code_none!(b'q', 10) as u32, 0x0000_710A);
++ assert_eq!(request_code_none!(b'a', 255) as u32, 0x0000_61FF);
+ }
+ }
+
+ #[test]
+ fn test_op_write() {
+ if cfg!(any(target_arch = "mips", target_arch = "mips64", target_arch="powerpc", target_arch="powerpc64")){
+- assert_eq!(request_code_write!(b'z', 10, 1), 0x8001_7A0A);
+- assert_eq!(request_code_write!(b'z', 10, 512), 0x8200_7A0A);
++ assert_eq!(request_code_write!(b'z', 10, 1) as u32, 0x8001_7A0A);
++ assert_eq!(request_code_write!(b'z', 10, 512) as u32, 0x8200_7A0A);
+ } else {
+- assert_eq!(request_code_write!(b'z', 10, 1), 0x4001_7A0A);
+- assert_eq!(request_code_write!(b'z', 10, 512), 0x4200_7A0A);
++ assert_eq!(request_code_write!(b'z', 10, 1) as u32, 0x4001_7A0A);
++ assert_eq!(request_code_write!(b'z', 10, 512) as u32, 0x4200_7A0A);
+ }
+ }
+
+@@ -56,9 +56,11 @@ mod linux {
+ #[test]
+ fn test_op_write_64() {
+ if cfg!(any(target_arch = "mips64", target_arch="powerpc64")){
+- assert_eq!(request_code_write!(b'z', 10, (1 as u64) << 32), 0x8000_7A0A);
++ assert_eq!(request_code_write!(b'z', 10, (1 as u64) << 32) as u32,
++ 0x8000_7A0A);
+ } else {
+- assert_eq!(request_code_write!(b'z', 10, (1 as u64) << 32), 0x4000_7A0A);
++ assert_eq!(request_code_write!(b'z', 10, (1 as u64) << 32) as u32,
++ 0x4000_7A0A);
+ }
+
+ }
+@@ -66,11 +68,11 @@ mod linux {
+ #[test]
+ fn test_op_read() {
+ if cfg!(any(target_arch = "mips", target_arch = "mips64", target_arch="powerpc", target_arch="powerpc64")){
+- assert_eq!(request_code_read!(b'z', 10, 1), 0x4001_7A0A);
+- assert_eq!(request_code_read!(b'z', 10, 512), 0x4200_7A0A);
++ assert_eq!(request_code_read!(b'z', 10, 1) as u32, 0x4001_7A0A);
++ assert_eq!(request_code_read!(b'z', 10, 512) as u32, 0x4200_7A0A);
+ } else {
+- assert_eq!(request_code_read!(b'z', 10, 1), 0x8001_7A0A);
+- assert_eq!(request_code_read!(b'z', 10, 512), 0x8200_7A0A);
++ assert_eq!(request_code_read!(b'z', 10, 1) as u32, 0x8001_7A0A);
++ assert_eq!(request_code_read!(b'z', 10, 512) as u32, 0x8200_7A0A);
+ }
+ }
+
+@@ -78,22 +80,25 @@ mod linux {
+ #[test]
+ fn test_op_read_64() {
+ if cfg!(any(target_arch = "mips64", target_arch="powerpc64")){
+- assert_eq!(request_code_read!(b'z', 10, (1 as u64) << 32), 0x4000_7A0A);
++ assert_eq!(request_code_read!(b'z', 10, (1 as u64) << 32) as u32,
++ 0x4000_7A0A);
+ } else {
+- assert_eq!(request_code_read!(b'z', 10, (1 as u64) << 32), 0x8000_7A0A);
++ assert_eq!(request_code_read!(b'z', 10, (1 as u64) << 32) as u32,
++ 0x8000_7A0A);
+ }
+ }
+
+ #[test]
+ fn test_op_read_write() {
+- assert_eq!(request_code_readwrite!(b'z', 10, 1), 0xC001_7A0A);
+- assert_eq!(request_code_readwrite!(b'z', 10, 512), 0xC200_7A0A);
++ assert_eq!(request_code_readwrite!(b'z', 10, 1) as u32, 0xC001_7A0A);
++ assert_eq!(request_code_readwrite!(b'z', 10, 512) as u32, 0xC200_7A0A);
+ }
+
+ #[cfg(target_pointer_width = "64")]
+ #[test]
+ fn test_op_read_write_64() {
+- assert_eq!(request_code_readwrite!(b'z', 10, (1 as u64) << 32), 0xC000_7A0A);
++ assert_eq!(request_code_readwrite!(b'z', 10, (1 as u64) << 32) as u32,
++ 0xC000_7A0A);
+ }
+ }
+
+@@ -177,7 +182,7 @@ mod linux_ioctls {
+ #[test]
+ fn test_ioctl_read_bad() {
+ let file = tempfile().unwrap();
+- let mut termios = unsafe { mem::uninitialized() };
++ let mut termios = unsafe { mem::zeroed() };
+ let res = unsafe { tcgets(file.as_raw_fd(), &mut termios) };
+ assert_eq!(res, Err(Sys(ENOTTY)));
+ }
+@@ -194,7 +199,7 @@ mod linux_ioctls {
+ #[test]
+ fn test_ioctl_write_ptr_bad() {
+ let file = tempfile().unwrap();
+- let termios: termios = unsafe { mem::uninitialized() };
++ let termios: termios = unsafe { mem::zeroed() };
+ let res = unsafe { tcsets(file.as_raw_fd(), &termios) };
+ assert_eq!(res, Err(Sys(ENOTTY)));
+ }
+@@ -245,7 +250,7 @@ mod linux_ioctls {
+ #[test]
+ fn test_ioctl_read() {
+ let file = tempfile().unwrap();
+- let mut data: v4l2_audio = unsafe { mem::uninitialized() };
++ let mut data: v4l2_audio = unsafe { mem::zeroed() };
+ let res = unsafe { g_audio(file.as_raw_fd(), &mut data) };
+ assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
+ }
+@@ -255,7 +260,7 @@ mod linux_ioctls {
+ #[test]
+ fn test_ioctl_readwrite() {
+ let file = tempfile().unwrap();
+- let mut data: v4l2_audio = unsafe { mem::uninitialized() };
++ let mut data: v4l2_audio = unsafe { mem::zeroed() };
+ let res = unsafe { enum_audio(file.as_raw_fd(), &mut data) };
+ assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
+ }
+@@ -318,7 +323,7 @@ mod freebsd_ioctls {
+ #[test]
+ fn test_ioctl_read() {
+ let file = tempfile().unwrap();
+- let mut termios = unsafe { mem::uninitialized() };
++ let mut termios = unsafe { mem::zeroed() };
+ let res = unsafe { tiocgeta(file.as_raw_fd(), &mut termios) };
+ assert_eq!(res, Err(Sys(ENOTTY)));
+ }
+@@ -327,7 +332,7 @@ mod freebsd_ioctls {
+ #[test]
+ fn test_ioctl_write_ptr() {
+ let file = tempfile().unwrap();
+- let termios: termios = unsafe { mem::uninitialized() };
++ let termios: termios = unsafe { mem::zeroed() };
+ let res = unsafe { tiocseta(file.as_raw_fd(), &termios) };
+ assert_eq!(res, Err(Sys(ENOTTY)));
+ }
+diff --git a/third_party/rust/nix/test/sys/test_lio_listio_resubmit.rs b/third_party/rust/nix/test/sys/test_lio_listio_resubmit.rs
+index 19ee3facf87d7..0795370b8c448 100644
+--- a/third_party/rust/nix/test/sys/test_lio_listio_resubmit.rs
++++ b/third_party/rust/nix/test/sys/test_lio_listio_resubmit.rs
+@@ -4,10 +4,6 @@
+ // we must disable the test here rather than in Cargo.toml
+ #![cfg(target_os = "freebsd")]
+
+-extern crate nix;
+-extern crate sysctl;
+-extern crate tempfile;
+-
+ use nix::Error;
+ use nix::errno::*;
+ use nix::libc::off_t;
+diff --git a/third_party/rust/nix/test/sys/test_mman.rs b/third_party/rust/nix/test/sys/test_mman.rs
+new file mode 100644
+index 0000000000000..152fff69c24de
+--- /dev/null
++++ b/third_party/rust/nix/test/sys/test_mman.rs
+@@ -0,0 +1,80 @@
++use nix::Error;
++use nix::libc::{c_void, size_t};
++use nix::sys::mman::{mmap, MapFlags, ProtFlags};
++
++#[cfg(target_os = "linux")]
++use nix::sys::mman::{mremap, MRemapFlags};
++
++#[test]
++fn test_mmap_anonymous() {
++ let ref mut byte = unsafe {
++ let ptr = mmap(std::ptr::null_mut(), 1,
++ ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
++ MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS, -1, 0)
++ .unwrap();
++ *(ptr as * mut u8)
++ };
++ assert_eq !(*byte, 0x00u8);
++ *byte = 0xffu8;
++ assert_eq !(*byte, 0xffu8);
++}
++
++#[test]
++#[cfg(target_os = "linux")]
++fn test_mremap_grow() {
++ const ONE_K : size_t = 1024;
++ let slice : &mut[u8] = unsafe {
++ let mem = mmap(std::ptr::null_mut(), ONE_K,
++ ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
++ MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE, -1, 0)
++ .unwrap();
++ std::slice::from_raw_parts_mut(mem as * mut u8, ONE_K)
++ };
++ assert_eq !(slice[ONE_K - 1], 0x00);
++ slice[ONE_K - 1] = 0xFF;
++ assert_eq !(slice[ONE_K - 1], 0xFF);
++
++ let slice : &mut[u8] = unsafe {
++ let mem = mremap(slice.as_mut_ptr() as * mut c_void, ONE_K, 10 * ONE_K,
++ MRemapFlags::MREMAP_MAYMOVE, None)
++ .unwrap();
++ std::slice::from_raw_parts_mut(mem as * mut u8, 10 * ONE_K)
++ };
++
++ // The first KB should still have the old data in it.
++ assert_eq !(slice[ONE_K - 1], 0xFF);
++
++ // The additional range should be zero-init'd and accessible.
++ assert_eq !(slice[10 * ONE_K - 1], 0x00);
++ slice[10 * ONE_K - 1] = 0xFF;
++ assert_eq !(slice[10 * ONE_K - 1], 0xFF);
++}
++
++#[test]
++#[cfg(target_os = "linux")]
++fn test_mremap_shrink() {
++ const ONE_K : size_t = 1024;
++ let slice : &mut[u8] = unsafe {
++ let mem = mmap(std::ptr::null_mut(), 10 * ONE_K,
++ ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
++ MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE, -1, 0)
++ .unwrap();
++ std::slice::from_raw_parts_mut(mem as * mut u8, ONE_K)
++ };
++ assert_eq !(slice[ONE_K - 1], 0x00);
++ slice[ONE_K - 1] = 0xFF;
++ assert_eq !(slice[ONE_K - 1], 0xFF);
++
++ let slice : &mut[u8] = unsafe {
++ let mem = mremap(slice.as_mut_ptr() as * mut c_void, 10 * ONE_K, ONE_K,
++ MRemapFlags::empty(), None)
++ .unwrap();
++ // Since we didn't supply MREMAP_MAYMOVE, the address should be the
++ // same.
++ assert_eq !(mem, slice.as_mut_ptr() as * mut c_void);
++ std::slice::from_raw_parts_mut(mem as * mut u8, ONE_K)
++ };
++
++ // The first KB should still be accessible and have the old data in it.
++ assert_eq !(slice[ONE_K - 1], 0xFF);
++}
+diff --git a/third_party/rust/nix/test/sys/test_pthread.rs b/third_party/rust/nix/test/sys/test_pthread.rs
+index 8928010087a13..1fc3dd900f382 100644
+--- a/third_party/rust/nix/test/sys/test_pthread.rs
++++ b/third_party/rust/nix/test/sys/test_pthread.rs
+@@ -1,13 +1,13 @@
+ use nix::sys::pthread::*;
+
+-#[cfg(target_env = "musl")]
++#[cfg(any(target_env = "musl", target_os = "redox"))]
+ #[test]
+ fn test_pthread_self() {
+ let tid = pthread_self();
+ assert!(tid != ::std::ptr::null_mut());
+ }
+
+-#[cfg(not(target_env = "musl"))]
++#[cfg(not(any(target_env = "musl", target_os = "redox")))]
+ #[test]
+ fn test_pthread_self() {
+ let tid = pthread_self();
+diff --git a/third_party/rust/nix/test/sys/test_ptrace.rs b/third_party/rust/nix/test/sys/test_ptrace.rs
+index 24d9b522ee4e5..b9793b39c54ae 100644
+--- a/third_party/rust/nix/test/sys/test_ptrace.rs
++++ b/third_party/rust/nix/test/sys/test_ptrace.rs
+@@ -8,10 +8,13 @@ use nix::sys::ptrace::Options;
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ use std::mem;
+
++use crate::*;
++
+ #[test]
+ fn test_ptrace() {
+ // Just make sure ptrace can be called at all, for now.
+ // FIXME: qemu-user doesn't implement ptrace on all arches, so permit ENOSYS
++ require_capability!(CAP_SYS_PTRACE);
+ let err = ptrace::attach(getpid()).unwrap_err();
+ assert!(err == Error::Sys(Errno::EPERM) || err == Error::Sys(Errno::EINVAL) ||
+ err == Error::Sys(Errno::ENOSYS));
+@@ -21,6 +24,7 @@ fn test_ptrace() {
+ #[test]
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ fn test_ptrace_setoptions() {
++ require_capability!(CAP_SYS_PTRACE);
+ let err = ptrace::setoptions(getpid(), Options::PTRACE_O_TRACESYSGOOD).unwrap_err();
+ assert!(err != Error::UnsupportedOperation);
+ }
+@@ -29,6 +33,7 @@ fn test_ptrace_setoptions() {
+ #[test]
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ fn test_ptrace_getevent() {
++ require_capability!(CAP_SYS_PTRACE);
+ let err = ptrace::getevent(getpid()).unwrap_err();
+ assert!(err != Error::UnsupportedOperation);
+ }
+@@ -37,6 +42,7 @@ fn test_ptrace_getevent() {
+ #[test]
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ fn test_ptrace_getsiginfo() {
++ require_capability!(CAP_SYS_PTRACE);
+ if let Err(Error::UnsupportedOperation) = ptrace::getsiginfo(getpid()) {
+ panic!("ptrace_getsiginfo returns Error::UnsupportedOperation!");
+ }
+@@ -46,7 +52,8 @@ fn test_ptrace_getsiginfo() {
+ #[test]
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ fn test_ptrace_setsiginfo() {
+- let siginfo = unsafe { mem::uninitialized() };
++ require_capability!(CAP_SYS_PTRACE);
++ let siginfo = unsafe { mem::zeroed() };
+ if let Err(Error::UnsupportedOperation) = ptrace::setsiginfo(getpid(), &siginfo) {
+ panic!("ptrace_setsiginfo returns Error::UnsupportedOperation!");
+ }
+@@ -61,7 +68,9 @@ fn test_ptrace_cont() {
+ use nix::unistd::fork;
+ use nix::unistd::ForkResult::*;
+
+- let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++ require_capability!(CAP_SYS_PTRACE);
++
++ let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test");
+
+ // FIXME: qemu-user doesn't implement ptrace on all architectures
+ // and retunrs ENOSYS in this case.
+@@ -74,7 +83,7 @@ fn test_ptrace_cont() {
+ return;
+ }
+
+- match fork().expect("Error: Fork Failed") {
++ match unsafe{fork()}.expect("Error: Fork Failed") {
+ Child => {
+ ptrace::traceme().unwrap();
+ // As recommended by ptrace(2), raise SIGTRAP to pause the child
+@@ -91,7 +100,7 @@ fn test_ptrace_cont() {
+ ptrace::cont(child, Some(Signal::SIGKILL)).unwrap();
+ match waitpid(child, None) {
+ Ok(WaitStatus::Signaled(pid, Signal::SIGKILL, _)) if pid == child => {
+- // FIXME It's been observed on some systems (apple) the
++ // FIXME It's been observed on some systems (apple) the
+ // tracee may not be killed but remain as a zombie process
+ // affecting other wait based tests. Add an extra kill just
+ // to make sure there are no zombies.
+@@ -105,3 +114,65 @@ fn test_ptrace_cont() {
+ },
+ }
+ }
++
++// ptrace::{setoptions, getregs} are only available in these platforms
++#[cfg(all(target_os = "linux",
++ any(target_arch = "x86_64",
++ target_arch = "x86"),
++ target_env = "gnu"))]
++#[test]
++fn test_ptrace_syscall() {
++ use nix::sys::signal::kill;
++ use nix::sys::ptrace;
++ use nix::sys::signal::Signal;
++ use nix::sys::wait::{waitpid, WaitStatus};
++ use nix::unistd::fork;
++ use nix::unistd::getpid;
++ use nix::unistd::ForkResult::*;
++
++ require_capability!(CAP_SYS_PTRACE);
++
++ let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++
++ match unsafe{fork()}.expect("Error: Fork Failed") {
++ Child => {
++ ptrace::traceme().unwrap();
++ // first sigstop until parent is ready to continue
++ let pid = getpid();
++ kill(pid, Signal::SIGSTOP).unwrap();
++ kill(pid, Signal::SIGTERM).unwrap();
++ unsafe { ::libc::_exit(0); }
++ },
++
++ Parent { child } => {
++ assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGSTOP)));
++
++ // set this option to recognize syscall-stops
++ ptrace::setoptions(child, ptrace::Options::PTRACE_O_TRACESYSGOOD).unwrap();
++
++ #[cfg(target_arch = "x86_64")]
++ let get_syscall_id = || ptrace::getregs(child).unwrap().orig_rax as libc::c_long;
++
++ #[cfg(target_arch = "x86")]
++ let get_syscall_id = || ptrace::getregs(child).unwrap().orig_eax as libc::c_long;
++
++ // kill entry
++ ptrace::syscall(child, None).unwrap();
++ assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child)));
++ assert_eq!(get_syscall_id(), ::libc::SYS_kill);
++
++ // kill exit
++ ptrace::syscall(child, None).unwrap();
++ assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child)));
++ assert_eq!(get_syscall_id(), ::libc::SYS_kill);
++
++ // receive signal
++ ptrace::syscall(child, None).unwrap();
++ assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGTERM)));
++
++ // inject signal
++ ptrace::syscall(child, Signal::SIGTERM).unwrap();
++ assert_eq!(waitpid(child, None), Ok(WaitStatus::Signaled(child, Signal::SIGTERM, false)));
++ },
++ }
++}
+diff --git a/third_party/rust/nix/test/sys/test_select.rs b/third_party/rust/nix/test/sys/test_select.rs
+index cf68700c5e16f..37951086c2d8d 100644
+--- a/third_party/rust/nix/test/sys/test_select.rs
++++ b/third_party/rust/nix/test/sys/test_select.rs
+@@ -5,7 +5,7 @@ use nix::sys::time::{TimeSpec, TimeValLike};
+
+ #[test]
+ pub fn test_pselect() {
+- let _mtx = ::SIGNAL_MTX
++ let _mtx = crate::SIGNAL_MTX
+ .lock()
+ .expect("Mutex got poisoned by another test");
+
+diff --git a/third_party/rust/nix/test/sys/test_signal.rs b/third_party/rust/nix/test/sys/test_signal.rs
+index 8780763f773ef..ae22527fde278 100644
+--- a/third_party/rust/nix/test/sys/test_signal.rs
++++ b/third_party/rust/nix/test/sys/test_signal.rs
+@@ -1,7 +1,9 @@
+ use libc;
++#[cfg(not(target_os = "redox"))]
+ use nix::Error;
+ use nix::sys::signal::*;
+ use nix::unistd::*;
++use std::convert::TryFrom;
+ use std::sync::atomic::{AtomicBool, Ordering};
+
+ #[test]
+@@ -10,6 +12,7 @@ fn test_kill_none() {
+ }
+
+ #[test]
++#[cfg(not(target_os = "fuchsia"))]
+ fn test_killpg_none() {
+ killpg(getpgrp(), None)
+ .expect("Should be able to send signal to my process group.");
+@@ -17,6 +20,8 @@ fn test_killpg_none() {
+
+ #[test]
+ fn test_old_sigaction_flags() {
++ let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
++
+ extern "C" fn handler(_: ::libc::c_int) {}
+ let act = SigAction::new(
+ SigHandler::Handler(handler),
+@@ -37,7 +42,7 @@ fn test_sigprocmask_noop() {
+
+ #[test]
+ fn test_sigprocmask() {
+- let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
++ let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
+
+ // This needs to be a signal that rust doesn't use in the test harness.
+ const SIGNAL: Signal = Signal::SIGCHLD;
+@@ -75,16 +80,25 @@ lazy_static! {
+ }
+
+ extern fn test_sigaction_handler(signal: libc::c_int) {
+- let signal = Signal::from_c_int(signal).unwrap();
++ let signal = Signal::try_from(signal).unwrap();
+ SIGNALED.store(signal == Signal::SIGINT, Ordering::Relaxed);
+ }
+
+-extern fn test_sigaction_action(_: libc::c_int, _: *mut libc::siginfo_t, _: *mut libc::c_void) {
++#[cfg(not(target_os = "redox"))]
++extern fn test_sigaction_action(_: libc::c_int, _: *mut libc::siginfo_t, _: *mut libc::c_void) {}
++
++#[test]
++#[cfg(not(target_os = "redox"))]
++fn test_signal_sigaction() {
++ let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
++
++ let action_handler = SigHandler::SigAction(test_sigaction_action);
++ assert_eq!(unsafe { signal(Signal::SIGINT, action_handler) }.unwrap_err(), Error::UnsupportedOperation);
+ }
+
+ #[test]
+ fn test_signal() {
+- let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
++ let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
+
+ unsafe { signal(Signal::SIGINT, SigHandler::SigIgn) }.unwrap();
+ raise(Signal::SIGINT).unwrap();
+@@ -96,9 +110,6 @@ fn test_signal() {
+ assert!(SIGNALED.load(Ordering::Relaxed));
+ assert_eq!(unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(), handler);
+
+- let action_handler = SigHandler::SigAction(test_sigaction_action);
+- assert_eq!(unsafe { signal(Signal::SIGINT, action_handler) }.unwrap_err(), Error::UnsupportedOperation);
+-
+ // Restore default signal handler
+ unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap();
+ }
+diff --git a/third_party/rust/nix/test/sys/test_signalfd.rs b/third_party/rust/nix/test/sys/test_signalfd.rs
+index a3b6098841f1c..af04c222852d8 100644
+--- a/third_party/rust/nix/test/sys/test_signalfd.rs
++++ b/third_party/rust/nix/test/sys/test_signalfd.rs
+@@ -1,10 +1,12 @@
++use std::convert::TryFrom;
++
+ #[test]
+ fn test_signalfd() {
+ use nix::sys::signalfd::SignalFd;
+ use nix::sys::signal::{self, raise, Signal, SigSet};
+
+ // Grab the mutex for altering signals so we don't interfere with other tests.
+- let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
++ let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
+
+ // Block the SIGUSR1 signal from automatic processing for this thread
+ let mut mask = SigSet::empty();
+@@ -20,6 +22,6 @@ fn test_signalfd() {
+
+ // And now catch that same signal.
+ let res = fd.read_signal().unwrap().unwrap();
+- let signo = Signal::from_c_int(res.ssi_signo as i32).unwrap();
++ let signo = Signal::try_from(res.ssi_signo as i32).unwrap();
+ assert_eq!(signo, signal::SIGUSR1);
+ }
+diff --git a/third_party/rust/nix/test/sys/test_socket.rs b/third_party/rust/nix/test/sys/test_socket.rs
+index 7e64d2b77f071..2b89a45336f3e 100644
+--- a/third_party/rust/nix/test/sys/test_socket.rs
++++ b/third_party/rust/nix/test/sys/test_socket.rs
+@@ -1,4 +1,3 @@
+-use nix::ifaddrs::InterfaceAddress;
+ use nix::sys::socket::{AddressFamily, InetAddr, UnixAddr, getsockname};
+ use std::collections::hash_map::DefaultHasher;
+ use std::hash::{Hash, Hasher};
+@@ -9,6 +8,8 @@ use std::slice;
+ use std::str::FromStr;
+ use libc::c_char;
+ use tempfile;
++#[cfg(any(target_os = "linux", target_os= "android"))]
++use crate::*;
+
+ #[test]
+ pub fn test_inetv4_addr_to_sock_addr() {
+@@ -106,7 +107,7 @@ pub fn test_addr_equality_abstract() {
+ assert_eq!(addr1, addr2);
+ assert_eq!(calculate_hash(&addr1), calculate_hash(&addr2));
+
+- addr2.0.sun_path[18] = 127;
++ addr2.0.sun_path[17] = 127;
+ assert_ne!(addr1, addr2);
+ assert_ne!(calculate_hash(&addr1), calculate_hash(&addr2));
+ }
+@@ -117,16 +118,13 @@ pub fn test_addr_equality_abstract() {
+ pub fn test_abstract_uds_addr() {
+ let empty = String::new();
+ let addr = UnixAddr::new_abstract(empty.as_bytes()).unwrap();
+- let sun_path = [0u8; 107];
++ let sun_path: [u8; 0] = [];
+ assert_eq!(addr.as_abstract(), Some(&sun_path[..]));
+
+ let name = String::from("nix\0abstract\0test");
+ let addr = UnixAddr::new_abstract(name.as_bytes()).unwrap();
+ let sun_path = [
+- 110u8, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, 116, 101, 115, 116, 0, 0, 0, 0,
+- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++ 110u8, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, 116, 101, 115, 116
+ ];
+ assert_eq!(addr.as_abstract(), Some(&sun_path[..]));
+ assert_eq!(addr.path(), None);
+@@ -164,6 +162,360 @@ pub fn test_socketpair() {
+ assert_eq!(&buf[..], b"hello");
+ }
+
++mod recvfrom {
++ use nix::Result;
++ use nix::sys::socket::*;
++ use std::thread;
++ use super::*;
++
++ const MSG: &'static [u8] = b"Hello, World!";
++
++ fn sendrecv<Fs, Fr>(rsock: RawFd, ssock: RawFd, f_send: Fs, mut f_recv: Fr) -> Option<SockAddr>
++ where
++ Fs: Fn(RawFd, &[u8], MsgFlags) -> Result<usize> + Send + 'static,
++ Fr: FnMut(usize, Option<SockAddr>),
++ {
++ let mut buf: [u8; 13] = [0u8; 13];
++ let mut l = 0;
++ let mut from = None;
++
++ let send_thread = thread::spawn(move || {
++ let mut l = 0;
++ while l < std::mem::size_of_val(MSG) {
++ l += f_send(ssock, &MSG[l..], MsgFlags::empty()).unwrap();
++ }
++ });
++
++ while l < std::mem::size_of_val(MSG) {
++ let (len, from_) = recvfrom(rsock, &mut buf[l..]).unwrap();
++ f_recv(len, from_);
++ from = from_;
++ l += len;
++ }
++ assert_eq!(&buf, MSG);
++ send_thread.join().unwrap();
++ from
++ }
++
++ #[test]
++ pub fn stream() {
++ let (fd2, fd1) = socketpair(AddressFamily::Unix, SockType::Stream,
++ None, SockFlag::empty()).unwrap();
++ // Ignore from for stream sockets
++ let _ = sendrecv(fd1, fd2, |s, m, flags| {
++ send(s, m, flags)
++ }, |_, _| {});
++ }
++
++ #[test]
++ pub fn udp() {
++ let std_sa = SocketAddr::from_str("127.0.0.1:6789").unwrap();
++ let inet_addr = InetAddr::from_std(&std_sa);
++ let sock_addr = SockAddr::new_inet(inet_addr);
++ let rsock = socket(AddressFamily::Inet,
++ SockType::Datagram,
++ SockFlag::empty(),
++ None
++ ).unwrap();
++ bind(rsock, &sock_addr).unwrap();
++ let ssock = socket(
++ AddressFamily::Inet,
++ SockType::Datagram,
++ SockFlag::empty(),
++ None,
++ ).expect("send socket failed");
++ let from = sendrecv(rsock, ssock, move |s, m, flags| {
++ sendto(s, m, &sock_addr, flags)
++ },|_, _| {});
++ // UDP sockets should set the from address
++ assert_eq!(AddressFamily::Inet, from.unwrap().family());
++ }
++
++ #[cfg(target_os = "linux")]
++ mod udp_offload {
++ use super::*;
++ use nix::sys::uio::IoVec;
++ use nix::sys::socket::sockopt::{UdpGroSegment, UdpGsoSegment};
++
++ #[test]
++ // Disable the test on emulated platforms because it fails in Cirrus-CI. Lack of QEMU
++ // support is suspected.
++ #[cfg_attr(not(any(target_arch = "x86_64", target_arch="i686")), ignore)]
++ pub fn gso() {
++ require_kernel_version!(udp_offload::gso, ">= 4.18");
++
++ // In this test, we send the data and provide a GSO segment size.
++ // Since we are sending the buffer of size 13, six UDP packets
++ // with size 2 and two UDP packet with size 1 will be sent.
++ let segment_size: u16 = 2;
++
++ let std_sa = SocketAddr::from_str("127.0.0.1:6791").unwrap();
++ let inet_addr = InetAddr::from_std(&std_sa);
++ let sock_addr = SockAddr::new_inet(inet_addr);
++ let rsock = socket(AddressFamily::Inet,
++ SockType::Datagram,
++ SockFlag::empty(),
++ None
++ ).unwrap();
++
++ setsockopt(rsock, UdpGsoSegment, &(segment_size as _))
++ .expect("setsockopt UDP_SEGMENT failed");
++
++ bind(rsock, &sock_addr).unwrap();
++ let ssock = socket(
++ AddressFamily::Inet,
++ SockType::Datagram,
++ SockFlag::empty(),
++ None,
++ ).expect("send socket failed");
++
++ let mut num_packets_received: i32 = 0;
++
++ sendrecv(rsock, ssock, move |s, m, flags| {
++ let iov = [IoVec::from_slice(m)];
++ let cmsg = ControlMessage::UdpGsoSegments(&segment_size);
++ sendmsg(s, &iov, &[cmsg], flags, Some(&sock_addr))
++ }, {
++ let num_packets_received_ref = &mut num_packets_received;
++
++ move |len, _| {
++ // check that we receive UDP packets with payload size
++ // less or equal to segment size
++ assert!(len <= segment_size as usize);
++ *num_packets_received_ref += 1;
++ }
++ });
++
++ // Buffer size is 13, we will receive six packets of size 2,
++ // and one packet of size 1.
++ assert_eq!(7, num_packets_received);
++ }
++
++ #[test]
++ // Disable the test on emulated platforms because it fails in Cirrus-CI. Lack of QEMU
++ // support is suspected.
++ #[cfg_attr(not(any(target_arch = "x86_64", target_arch="i686")), ignore)]
++ pub fn gro() {
++ require_kernel_version!(udp_offload::gro, ">= 5.3");
++
++ // It's hard to guarantee receiving GRO packets. Just checking
++ // that `setsockopt` doesn't fail with error
++
++ let rsock = socket(AddressFamily::Inet,
++ SockType::Datagram,
++ SockFlag::empty(),
++ None
++ ).unwrap();
++
++ setsockopt(rsock, UdpGroSegment, &true)
++ .expect("setsockopt UDP_GRO failed");
++ }
++ }
++
++ #[cfg(any(
++ target_os = "linux",
++ target_os = "android",
++ target_os = "freebsd",
++ target_os = "netbsd",
++ ))]
++ #[test]
++ pub fn udp_sendmmsg() {
++ use nix::sys::uio::IoVec;
++
++ let std_sa = SocketAddr::from_str("127.0.0.1:6793").unwrap();
++ let std_sa2 = SocketAddr::from_str("127.0.0.1:6794").unwrap();
++ let inet_addr = InetAddr::from_std(&std_sa);
++ let inet_addr2 = InetAddr::from_std(&std_sa2);
++ let sock_addr = SockAddr::new_inet(inet_addr);
++ let sock_addr2 = SockAddr::new_inet(inet_addr2);
++
++ let rsock = socket(AddressFamily::Inet,
++ SockType::Datagram,
++ SockFlag::empty(),
++ None
++ ).unwrap();
++ bind(rsock, &sock_addr).unwrap();
++ let ssock = socket(
++ AddressFamily::Inet,
++ SockType::Datagram,
++ SockFlag::empty(),
++ None,
++ ).expect("send socket failed");
++
++ let from = sendrecv(rsock, ssock, move |s, m, flags| {
++ let iov = [IoVec::from_slice(m)];
++ let mut msgs = Vec::new();
++ msgs.push(
++ SendMmsgData {
++ iov: &iov,
++ cmsgs: &[],
++ addr: Some(sock_addr),
++ _lt: Default::default(),
++ });
++
++ let batch_size = 15;
++
++ for _ in 0..batch_size {
++ msgs.push(
++ SendMmsgData {
++ iov: &iov,
++ cmsgs: &[],
++ addr: Some(sock_addr2),
++ _lt: Default::default(),
++ }
++ );
++ }
++ sendmmsg(s, msgs.iter(), flags)
++ .map(move |sent_bytes| {
++ assert!(sent_bytes.len() >= 1);
++ for sent in &sent_bytes {
++ assert_eq!(*sent, m.len());
++ }
++ sent_bytes.len()
++ })
++ }, |_, _ | {});
++ // UDP sockets should set the from address
++ assert_eq!(AddressFamily::Inet, from.unwrap().family());
++ }
++
++ #[cfg(any(
++ target_os = "linux",
++ target_os = "android",
++ target_os = "freebsd",
++ target_os = "netbsd",
++ ))]
++ #[test]
++ pub fn udp_recvmmsg() {
++ use nix::sys::uio::IoVec;
++ use nix::sys::socket::{MsgFlags, recvmmsg};
++
++ const NUM_MESSAGES_SENT: usize = 2;
++ const DATA: [u8; 2] = [1,2];
++
++ let std_sa = SocketAddr::from_str("127.0.0.1:6798").unwrap();
++ let inet_addr = InetAddr::from_std(&std_sa);
++ let sock_addr = SockAddr::new_inet(inet_addr);
++
++ let rsock = socket(AddressFamily::Inet,
++ SockType::Datagram,
++ SockFlag::empty(),
++ None
++ ).unwrap();
++ bind(rsock, &sock_addr).unwrap();
++ let ssock = socket(
++ AddressFamily::Inet,
++ SockType::Datagram,
++ SockFlag::empty(),
++ None,
++ ).expect("send socket failed");
++
++ let send_thread = thread::spawn(move || {
++ for _ in 0..NUM_MESSAGES_SENT {
++ sendto(ssock, &DATA[..], &sock_addr, MsgFlags::empty()).unwrap();
++ }
++ });
++
++ let mut msgs = std::collections::LinkedList::new();
++
++ // Buffers to receive exactly `NUM_MESSAGES_SENT` messages
++ let mut receive_buffers = [[0u8; 32]; NUM_MESSAGES_SENT];
++ let iovs: Vec<_> = receive_buffers.iter_mut().map(|buf| {
++ [IoVec::from_mut_slice(&mut buf[..])]
++ }).collect();
++
++ for iov in &iovs {
++ msgs.push_back(RecvMmsgData {
++ iov: iov,
++ cmsg_buffer: None,
++ })
++ };
++
++ let res = recvmmsg(rsock, &mut msgs, MsgFlags::empty(), None).expect("recvmmsg");
++ assert_eq!(res.len(), DATA.len());
++
++ for RecvMsg { address, bytes, .. } in res.into_iter() {
++ assert_eq!(AddressFamily::Inet, address.unwrap().family());
++ assert_eq!(DATA.len(), bytes);
++ }
++
++ for buf in &receive_buffers {
++ assert_eq!(&buf[..DATA.len()], DATA);
++ }
++
++ send_thread.join().unwrap();
++ }
++
++ #[cfg(any(
++ target_os = "linux",
++ target_os = "android",
++ target_os = "freebsd",
++ target_os = "netbsd",
++ ))]
++ #[test]
++ pub fn udp_recvmmsg_dontwait_short_read() {
++ use nix::sys::uio::IoVec;
++ use nix::sys::socket::{MsgFlags, recvmmsg};
++
++ const NUM_MESSAGES_SENT: usize = 2;
++ const DATA: [u8; 4] = [1,2,3,4];
++
++ let std_sa = SocketAddr::from_str("127.0.0.1:6799").unwrap();
++ let inet_addr = InetAddr::from_std(&std_sa);
++ let sock_addr = SockAddr::new_inet(inet_addr);
++
++ let rsock = socket(AddressFamily::Inet,
++ SockType::Datagram,
++ SockFlag::empty(),
++ None
++ ).unwrap();
++ bind(rsock, &sock_addr).unwrap();
++ let ssock = socket(
++ AddressFamily::Inet,
++ SockType::Datagram,
++ SockFlag::empty(),
++ None,
++ ).expect("send socket failed");
++
++ let send_thread = thread::spawn(move || {
++ for _ in 0..NUM_MESSAGES_SENT {
++ sendto(ssock, &DATA[..], &sock_addr, MsgFlags::empty()).unwrap();
++ }
++ });
++ // Ensure we've sent all the messages before continuing so `recvmmsg`
++ // will return right away
++ send_thread.join().unwrap();
++
++ let mut msgs = std::collections::LinkedList::new();
++
++ // Buffers to receive >`NUM_MESSAGES_SENT` messages to ensure `recvmmsg`
++ // will return when there are fewer than requested messages in the
++ // kernel buffers when using `MSG_DONTWAIT`.
++ let mut receive_buffers = [[0u8; 32]; NUM_MESSAGES_SENT + 2];
++ let iovs: Vec<_> = receive_buffers.iter_mut().map(|buf| {
++ [IoVec::from_mut_slice(&mut buf[..])]
++ }).collect();
++
++ for iov in &iovs {
++ msgs.push_back(RecvMmsgData {
++ iov: iov,
++ cmsg_buffer: None,
++ })
++ };
++
++ let res = recvmmsg(rsock, &mut msgs, MsgFlags::MSG_DONTWAIT, None).expect("recvmmsg");
++ assert_eq!(res.len(), NUM_MESSAGES_SENT);
++
++ for RecvMsg { address, bytes, .. } in res.into_iter() {
++ assert_eq!(AddressFamily::Inet, address.unwrap().family());
++ assert_eq!(DATA.len(), bytes);
++ }
++
++ for buf in &receive_buffers[..NUM_MESSAGES_SENT] {
++ assert_eq!(&buf[..DATA.len()], DATA);
++ }
++ }
++}
++
+ // Test error handling of our recvmsg wrapper
+ #[test]
+ pub fn test_recvmsg_ebadf() {
+@@ -247,8 +599,13 @@ pub fn test_af_alg_cipher() {
+ ControlMessage, MsgFlags};
+ use nix::sys::socket::sockopt::AlgSetKey;
+
++ skip_if_cirrus!("Fails for an unknown reason Cirrus CI. Bug #1352");
++ // Travis's seccomp profile blocks AF_ALG
++ // https://docs.docker.com/engine/security/seccomp/
++ skip_if_seccomp!(test_af_alg_cipher);
++
+ let alg_type = "skcipher";
+- let alg_name = "ctr(aes)";
++ let alg_name = "ctr-aes-aesni";
+ // 256-bits secret key
+ let key = vec![0u8; 32];
+ // 16-bytes IV
+@@ -311,6 +668,11 @@ pub fn test_af_alg_aead() {
+ ControlMessage, MsgFlags};
+ use nix::sys::socket::sockopt::{AlgSetKey, AlgSetAeadAuthSize};
+
++ skip_if_cirrus!("Fails for an unknown reason Cirrus CI. Bug #1352");
++ // Travis's seccomp profile blocks AF_ALG
++ // https://docs.docker.com/engine/security/seccomp/
++ skip_if_seccomp!(test_af_alg_aead);
++
+ let auth_size = 4usize;
+ let assoc_size = 16u32;
+
+@@ -383,6 +745,111 @@ pub fn test_af_alg_aead() {
+ assert_eq!(decrypted[(assoc_size as usize)..(payload_len + (assoc_size as usize))], payload[(assoc_size as usize)..payload_len + (assoc_size as usize)]);
+ }
+
++// Verify `ControlMessage::Ipv4PacketInfo` for `sendmsg`.
++// This creates a (udp) socket bound to localhost, then sends a message to
++// itself but uses Ipv4PacketInfo to force the source address to be localhost.
++//
++// This would be a more interesting test if we could assume that the test host
++// has more than one IP address (since we could select a different address to
++// test from).
++#[cfg(any(target_os = "linux",
++ target_os = "macos",
++ target_os = "netbsd"))]
++#[test]
++pub fn test_sendmsg_ipv4packetinfo() {
++ use nix::sys::uio::IoVec;
++ use nix::sys::socket::{socket, sendmsg, bind,
++ AddressFamily, SockType, SockFlag, SockAddr,
++ ControlMessage, MsgFlags};
++
++ let sock = socket(AddressFamily::Inet,
++ SockType::Datagram,
++ SockFlag::empty(),
++ None)
++ .expect("socket failed");
++
++ let std_sa = SocketAddr::from_str("127.0.0.1:4000").unwrap();
++ let inet_addr = InetAddr::from_std(&std_sa);
++ let sock_addr = SockAddr::new_inet(inet_addr);
++
++ bind(sock, &sock_addr).expect("bind failed");
++
++ let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
++ let iov = [IoVec::from_slice(&slice)];
++
++ if let InetAddr::V4(sin) = inet_addr {
++ let pi = libc::in_pktinfo {
++ ipi_ifindex: 0, /* Unspecified interface */
++ ipi_addr: libc::in_addr { s_addr: 0 },
++ ipi_spec_dst: sin.sin_addr,
++ };
++
++ let cmsg = [ControlMessage::Ipv4PacketInfo(&pi)];
++
++ sendmsg(sock, &iov, &cmsg, MsgFlags::empty(), Some(&sock_addr))
++ .expect("sendmsg");
++ } else {
++ panic!("No IPv4 addresses available for testing?");
++ }
++}
++
++// Verify `ControlMessage::Ipv6PacketInfo` for `sendmsg`.
++// This creates a (udp) socket bound to ip6-localhost, then sends a message to
++// itself but uses Ipv6PacketInfo to force the source address to be
++// ip6-localhost.
++//
++// This would be a more interesting test if we could assume that the test host
++// has more than one IP address (since we could select a different address to
++// test from).
++#[cfg(any(target_os = "linux",
++ target_os = "macos",
++ target_os = "netbsd",
++ target_os = "freebsd"))]
++#[test]
++pub fn test_sendmsg_ipv6packetinfo() {
++ use nix::Error;
++ use nix::errno::Errno;
++ use nix::sys::uio::IoVec;
++ use nix::sys::socket::{socket, sendmsg, bind,
++ AddressFamily, SockType, SockFlag, SockAddr,
++ ControlMessage, MsgFlags};
++
++ let sock = socket(AddressFamily::Inet6,
++ SockType::Datagram,
++ SockFlag::empty(),
++ None)
++ .expect("socket failed");
++
++ let std_sa = SocketAddr::from_str("[::1]:6000").unwrap();
++ let inet_addr = InetAddr::from_std(&std_sa);
++ let sock_addr = SockAddr::new_inet(inet_addr);
++
++ match bind(sock, &sock_addr) {
++ Err(Error::Sys(Errno::EADDRNOTAVAIL)) => {
++ println!("IPv6 not available, skipping test.");
++ return;
++ },
++ _ => (),
++ }
++
++ let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
++ let iov = [IoVec::from_slice(&slice)];
++
++ if let InetAddr::V6(sin) = inet_addr {
++ let pi = libc::in6_pktinfo {
++ ipi6_ifindex: 0, /* Unspecified interface */
++ ipi6_addr: sin.sin6_addr,
++ };
++
++ let cmsg = [ControlMessage::Ipv6PacketInfo(&pi)];
++
++ sendmsg(sock, &iov, &cmsg, MsgFlags::empty(), Some(&sock_addr))
++ .expect("sendmsg");
++ } else {
++ println!("No IPv6 addresses available for testing: skipping testing Ipv6PacketInfo");
++ }
++}
++
+ /// Tests that passing multiple fds using a single `ControlMessage` works.
+ // Disable the test on emulated platforms due to a bug in QEMU versions <
+ // 2.12.0. https://bugs.launchpad.net/qemu/+bug/1701808
+@@ -468,29 +935,36 @@ pub fn test_sendmsg_empty_cmsgs() {
+ }
+ }
+
+-#[cfg(any(target_os = "android", target_os = "linux"))]
++#[cfg(any(
++ target_os = "android",
++ target_os = "linux",
++ target_os = "freebsd",
++ target_os = "dragonfly",
++))]
+ #[test]
+ fn test_scm_credentials() {
+- use libc;
+ use nix::sys::uio::IoVec;
+ use nix::unistd::{close, getpid, getuid, getgid};
+- use nix::sys::socket::{socketpair, sendmsg, recvmsg, setsockopt,
++ use nix::sys::socket::{socketpair, sendmsg, recvmsg,
+ AddressFamily, SockType, SockFlag,
+- ControlMessage, ControlMessageOwned, MsgFlags};
+- use nix::sys::socket::sockopt::PassCred;
++ ControlMessage, ControlMessageOwned, MsgFlags,
++ UnixCredentials};
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ use nix::sys::socket::{setsockopt, sockopt::PassCred};
+
+ let (send, recv) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty())
+ .unwrap();
++ #[cfg(any(target_os = "android", target_os = "linux"))]
+ setsockopt(recv, PassCred, &true).unwrap();
+
+ {
+ let iov = [IoVec::from_slice(b"hello")];
+- let cred = libc::ucred {
+- pid: getpid().as_raw(),
+- uid: getuid().as_raw(),
+- gid: getgid().as_raw(),
+- };
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ let cred = UnixCredentials::new();
++ #[cfg(any(target_os = "android", target_os = "linux"))]
+ let cmsg = ControlMessage::ScmCredentials(&cred);
++ #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++ let cmsg = ControlMessage::ScmCreds;
+ assert_eq!(sendmsg(send, &iov, &[cmsg], MsgFlags::empty(), None).unwrap(), 5);
+ close(send).unwrap();
+ }
+@@ -498,20 +972,23 @@ fn test_scm_credentials() {
+ {
+ let mut buf = [0u8; 5];
+ let iov = [IoVec::from_mut_slice(&mut buf[..])];
+- let mut cmsgspace = cmsg_space!(libc::ucred);
++ let mut cmsgspace = cmsg_space!(UnixCredentials);
+ let msg = recvmsg(recv, &iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap();
+ let mut received_cred = None;
+
+ for cmsg in msg.cmsgs() {
+- if let ControlMessageOwned::ScmCredentials(cred) = cmsg {
+- assert!(received_cred.is_none());
+- assert_eq!(cred.pid, getpid().as_raw());
+- assert_eq!(cred.uid, getuid().as_raw());
+- assert_eq!(cred.gid, getgid().as_raw());
+- received_cred = Some(cred);
+- } else {
+- panic!("unexpected cmsg");
+- }
++ let cred = match cmsg {
++ #[cfg(any(target_os = "android", target_os = "linux"))]
++ ControlMessageOwned::ScmCredentials(cred) => cred,
++ #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++ ControlMessageOwned::ScmCreds(cred) => cred,
++ other => panic!("unexpected cmsg {:?}", other),
++ };
++ assert!(received_cred.is_none());
++ assert_eq!(cred.pid(), getpid().as_raw());
++ assert_eq!(cred.uid(), getuid().as_raw());
++ assert_eq!(cred.gid(), getgid().as_raw());
++ received_cred = Some(cred);
+ }
+ received_cred.expect("no creds received");
+ assert_eq!(msg.bytes, 5);
+@@ -550,7 +1027,7 @@ fn test_too_large_cmsgspace() {
+ fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) {
+ use libc::ucred;
+ use nix::sys::uio::IoVec;
+- use nix::unistd::{pipe, read, write, close, getpid, getuid, getgid};
++ use nix::unistd::{pipe, write, close, getpid, getuid, getgid};
+ use nix::sys::socket::{socketpair, sendmsg, recvmsg, setsockopt,
+ SockType, SockFlag,
+ ControlMessage, ControlMessageOwned, MsgFlags};
+@@ -569,7 +1046,7 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) {
+ pid: getpid().as_raw(),
+ uid: getuid().as_raw(),
+ gid: getgid().as_raw(),
+- };
++ }.into();
+ let fds = [r];
+ let cmsgs = [
+ ControlMessage::ScmCredentials(&cred),
+@@ -597,9 +1074,9 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) {
+ }
+ ControlMessageOwned::ScmCredentials(cred) => {
+ assert!(received_cred.is_none());
+- assert_eq!(cred.pid, getpid().as_raw());
+- assert_eq!(cred.uid, getuid().as_raw());
+- assert_eq!(cred.gid, getgid().as_raw());
++ assert_eq!(cred.pid(), getpid().as_raw());
++ assert_eq!(cred.uid(), getuid().as_raw());
++ assert_eq!(cred.gid(), getgid().as_raw());
+ received_cred = Some(cred);
+ }
+ _ => panic!("unexpected cmsg"),
+@@ -683,7 +1160,7 @@ pub fn test_syscontrol() {
+ target_os = "netbsd",
+ target_os = "openbsd",
+ ))]
+-fn loopback_address(family: AddressFamily) -> Option<InterfaceAddress> {
++fn loopback_address(family: AddressFamily) -> Option<nix::ifaddrs::InterfaceAddress> {
+ use std::io;
+ use std::io::Write;
+ use nix::ifaddrs::getifaddrs;
+@@ -1013,7 +1490,7 @@ pub fn test_recv_ipv6pktinfo() {
+ }
+ }
+
+-#[cfg(target_os = "linux")]
++#[cfg(any(target_os = "android", target_os = "linux"))]
+ #[test]
+ pub fn test_vsock() {
+ use libc;
+@@ -1030,17 +1507,11 @@ pub fn test_vsock() {
+ SockFlag::empty(), None)
+ .expect("socket failed");
+
+- // VMADDR_CID_HYPERVISOR and VMADDR_CID_RESERVED are reserved, so we expect
+- // an EADDRNOTAVAIL error.
++ // VMADDR_CID_HYPERVISOR is reserved, so we expect an EADDRNOTAVAIL error.
+ let sockaddr = SockAddr::new_vsock(libc::VMADDR_CID_HYPERVISOR, port);
+ assert_eq!(bind(s1, &sockaddr).err(),
+ Some(Error::Sys(Errno::EADDRNOTAVAIL)));
+
+- let sockaddr = SockAddr::new_vsock(libc::VMADDR_CID_RESERVED, port);
+- assert_eq!(bind(s1, &sockaddr).err(),
+- Some(Error::Sys(Errno::EADDRNOTAVAIL)));
+-
+-
+ let sockaddr = SockAddr::new_vsock(libc::VMADDR_CID_ANY, port);
+ assert_eq!(bind(s1, &sockaddr), Ok(()));
+ listen(s1, 10).expect("listen failed");
+diff --git a/third_party/rust/nix/test/sys/test_sockopt.rs b/third_party/rust/nix/test/sys/test_sockopt.rs
+index c4860c0d61d3d..56065931322ec 100644
+--- a/third_party/rust/nix/test/sys/test_sockopt.rs
++++ b/third_party/rust/nix/test/sys/test_sockopt.rs
+@@ -1,5 +1,7 @@
+ use rand::{thread_rng, Rng};
+ use nix::sys::socket::{socket, sockopt, getsockopt, setsockopt, AddressFamily, SockType, SockFlag, SockProtocol};
++#[cfg(any(target_os = "android", target_os = "linux"))]
++use crate::*;
+
+ #[cfg(target_os = "linux")]
+ #[test]
+@@ -51,3 +53,44 @@ fn test_tcp_congestion() {
+ val
+ );
+ }
++
++#[test]
++#[cfg(any(target_os = "android", target_os = "linux"))]
++fn test_bindtodevice() {
++ skip_if_not_root!("test_bindtodevice");
++
++ let fd = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap();
++
++ let val = getsockopt(fd, sockopt::BindToDevice).unwrap();
++ setsockopt(fd, sockopt::BindToDevice, &val).unwrap();
++
++ assert_eq!(
++ getsockopt(fd, sockopt::BindToDevice).unwrap(),
++ val
++ );
++}
++
++#[test]
++fn test_so_tcp_keepalive() {
++ let fd = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), SockProtocol::Tcp).unwrap();
++ setsockopt(fd, sockopt::KeepAlive, &true).unwrap();
++ assert_eq!(getsockopt(fd, sockopt::KeepAlive).unwrap(), true);
++
++ #[cfg(any(target_os = "android",
++ target_os = "dragonfly",
++ target_os = "freebsd",
++ target_os = "linux",
++ target_os = "nacl"))] {
++ let x = getsockopt(fd, sockopt::TcpKeepIdle).unwrap();
++ setsockopt(fd, sockopt::TcpKeepIdle, &(x + 1)).unwrap();
++ assert_eq!(getsockopt(fd, sockopt::TcpKeepIdle).unwrap(), x + 1);
++
++ let x = getsockopt(fd, sockopt::TcpKeepCount).unwrap();
++ setsockopt(fd, sockopt::TcpKeepCount, &(x + 1)).unwrap();
++ assert_eq!(getsockopt(fd, sockopt::TcpKeepCount).unwrap(), x + 1);
++
++ let x = getsockopt(fd, sockopt::TcpKeepInterval).unwrap();
++ setsockopt(fd, sockopt::TcpKeepInterval, &(x + 1)).unwrap();
++ assert_eq!(getsockopt(fd, sockopt::TcpKeepInterval).unwrap(), x + 1);
++ }
++}
+diff --git a/third_party/rust/nix/test/sys/test_termios.rs b/third_party/rust/nix/test/sys/test_termios.rs
+index a14b8ce1a23cb..00aeb2fc57f15 100644
+--- a/third_party/rust/nix/test/sys/test_termios.rs
++++ b/third_party/rust/nix/test/sys/test_termios.rs
+@@ -4,7 +4,7 @@ use tempfile::tempfile;
+ use nix::{Error, fcntl};
+ use nix::errno::Errno;
+ use nix::pty::openpty;
+-use nix::sys::termios::{self, LocalFlags, OutputFlags, Termios, tcgetattr};
++use nix::sys::termios::{self, LocalFlags, OutputFlags, tcgetattr};
+ use nix::unistd::{read, write, close};
+
+ /// Helper function analogous to `std::io::Write::write_all`, but for `RawFd`s
+@@ -19,10 +19,10 @@ fn write_all(f: RawFd, buf: &[u8]) {
+ #[test]
+ fn test_tcgetattr_pty() {
+ // openpty uses ptname(3) internally
+- let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++ let _m = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
+
+ let pty = openpty(None, None).expect("openpty failed");
+- assert!(termios::tcgetattr(pty.master).is_ok());
++ assert!(termios::tcgetattr(pty.slave).is_ok());
+ close(pty.master).expect("closing the master failed");
+ close(pty.slave).expect("closing the slave failed");
+ }
+@@ -46,14 +46,14 @@ fn test_tcgetattr_ebadf() {
+ #[test]
+ fn test_output_flags() {
+ // openpty uses ptname(3) internally
+- let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++ let _m = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
+
+ // Open one pty to get attributes for the second one
+ let mut termios = {
+ let pty = openpty(None, None).expect("openpty failed");
+ assert!(pty.master > 0);
+ assert!(pty.slave > 0);
+- let termios = tcgetattr(pty.master).expect("tcgetattr failed");
++ let termios = tcgetattr(pty.slave).expect("tcgetattr failed");
+ close(pty.master).unwrap();
+ close(pty.slave).unwrap();
+ termios
+@@ -77,7 +77,7 @@ fn test_output_flags() {
+
+ // Read from the slave verifying that the output has been properly transformed
+ let mut buf = [0u8; 10];
+- ::read_exact(pty.slave, &mut buf);
++ crate::read_exact(pty.slave, &mut buf);
+ let transformed_string = "foofoofoo\n";
+ close(pty.master).unwrap();
+ close(pty.slave).unwrap();
+@@ -88,14 +88,14 @@ fn test_output_flags() {
+ #[test]
+ fn test_local_flags() {
+ // openpty uses ptname(3) internally
+- let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++ let _m = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
+
+ // Open one pty to get attributes for the second one
+ let mut termios = {
+ let pty = openpty(None, None).unwrap();
+ assert!(pty.master > 0);
+ assert!(pty.slave > 0);
+- let termios = tcgetattr(pty.master).unwrap();
++ let termios = tcgetattr(pty.slave).unwrap();
+ close(pty.master).unwrap();
+ close(pty.slave).unwrap();
+ termios
+@@ -128,9 +128,3 @@ fn test_local_flags() {
+ close(pty.slave).unwrap();
+ assert_eq!(read, Error::Sys(Errno::EAGAIN));
+ }
+-
+-#[test]
+-fn test_cfmakeraw() {
+- let mut termios = unsafe { Termios::default_uninit() };
+- termios::cfmakeraw(&mut termios);
+-}
+diff --git a/third_party/rust/nix/test/sys/test_timerfd.rs b/third_party/rust/nix/test/sys/test_timerfd.rs
+new file mode 100644
+index 0000000000000..24fb2ac002e1d
+--- /dev/null
++++ b/third_party/rust/nix/test/sys/test_timerfd.rs
+@@ -0,0 +1,61 @@
++use nix::sys::time::{TimeSpec, TimeValLike};
++use nix::sys::timerfd::{ClockId, Expiration, TimerFd, TimerFlags, TimerSetTimeFlags};
++use std::time::Instant;
++
++#[test]
++pub fn test_timerfd_oneshot() {
++ let timer = TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty()).unwrap();
++
++ let before = Instant::now();
++
++ timer
++ .set(
++ Expiration::OneShot(TimeSpec::seconds(1)),
++ TimerSetTimeFlags::empty(),
++ )
++ .unwrap();
++
++ timer.wait().unwrap();
++
++ let millis = before.elapsed().as_millis();
++ assert!(millis > 900);
++}
++
++#[test]
++pub fn test_timerfd_interval() {
++ let timer = TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty()).unwrap();
++
++ let before = Instant::now();
++ timer
++ .set(
++ Expiration::IntervalDelayed(TimeSpec::seconds(1), TimeSpec::seconds(2)),
++ TimerSetTimeFlags::empty(),
++ )
++ .unwrap();
++
++ timer.wait().unwrap();
++
++ let start_delay = before.elapsed().as_millis();
++ assert!(start_delay > 900);
++
++ timer.wait().unwrap();
++
++ let interval_delay = before.elapsed().as_millis();
++ assert!(interval_delay > 2900);
++}
++
++#[test]
++pub fn test_timerfd_unset() {
++ let timer = TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty()).unwrap();
++
++ timer
++ .set(
++ Expiration::OneShot(TimeSpec::seconds(1)),
++ TimerSetTimeFlags::empty(),
++ )
++ .unwrap();
++
++ timer.unset().unwrap();
++
++ assert!(timer.get().unwrap() == None);
++}
+diff --git a/third_party/rust/nix/test/sys/test_uio.rs b/third_party/rust/nix/test/sys/test_uio.rs
+index 3e4fc28ceb0e4..8d22bf1755a2c 100644
+--- a/third_party/rust/nix/test/sys/test_uio.rs
++++ b/third_party/rust/nix/test/sys/test_uio.rs
+@@ -6,7 +6,9 @@ use std::{cmp, iter};
+ use std::fs::{OpenOptions};
+ use std::os::unix::io::AsRawFd;
+
+-use tempfile::{tempfile, tempdir};
++#[cfg(not(target_os = "redox"))]
++use tempfile::tempfile;
++use tempfile::tempdir;
+
+ #[test]
+ fn test_writev() {
+@@ -53,6 +55,7 @@ fn test_writev() {
+ }
+
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_readv() {
+ let s:String = thread_rng().sample_iter(&Alphanumeric).take(128).collect();
+ let to_write = s.as_bytes().to_vec();
+@@ -97,6 +100,7 @@ fn test_readv() {
+ }
+
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_pwrite() {
+ use std::io::Read;
+
+@@ -199,15 +203,17 @@ fn test_process_vm_readv() {
+ use nix::unistd::ForkResult::*;
+ use nix::sys::signal::*;
+ use nix::sys::wait::*;
++ use crate::*;
+
+- let _ = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++ require_capability!(CAP_SYS_PTRACE);
++ let _ = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test");
+
+ // Pre-allocate memory in the child, since allocation isn't safe
+ // post-fork (~= async-signal-safe)
+ let mut vector = vec![1u8, 2, 3, 4, 5];
+
+ let (r, w) = pipe().unwrap();
+- match fork().expect("Error: Fork Failed") {
++ match unsafe{fork()}.expect("Error: Fork Failed") {
+ Parent { child } => {
+ close(w).unwrap();
+ // wait for child
+diff --git a/third_party/rust/nix/test/sys/test_wait.rs b/third_party/rust/nix/test/sys/test_wait.rs
+index d07d82f0d9075..5bb298eba4d29 100644
+--- a/third_party/rust/nix/test/sys/test_wait.rs
++++ b/third_party/rust/nix/test/sys/test_wait.rs
+@@ -6,11 +6,12 @@ use nix::sys::wait::*;
+ use libc::_exit;
+
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_wait_signal() {
+- let _ = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++ let _ = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test");
+
+ // Safe: The child only calls `pause` and/or `_exit`, which are async-signal-safe.
+- match fork().expect("Error: Fork Failed") {
++ match unsafe{fork()}.expect("Error: Fork Failed") {
+ Child => {
+ pause();
+ unsafe { _exit(123) }
+@@ -24,10 +25,10 @@ fn test_wait_signal() {
+
+ #[test]
+ fn test_wait_exit() {
+- let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++ let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test");
+
+ // Safe: Child only calls `_exit`, which is async-signal-safe.
+- match fork().expect("Error: Fork Failed") {
++ match unsafe{fork()}.expect("Error: Fork Failed") {
+ Child => unsafe { _exit(12); },
+ Parent { child } => {
+ assert_eq!(waitpid(child, None), Ok(WaitStatus::Exited(child, 12)));
+@@ -45,9 +46,9 @@ fn test_waitstatus_from_raw() {
+
+ #[test]
+ fn test_waitstatus_pid() {
+- let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++ let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test");
+
+- match fork().unwrap() {
++ match unsafe{fork()}.unwrap() {
+ Child => unsafe { _exit(0) },
+ Parent { child } => {
+ let status = waitpid(child, None).unwrap();
+@@ -66,6 +67,7 @@ mod ptrace {
+ use nix::unistd::*;
+ use nix::unistd::ForkResult::*;
+ use libc::_exit;
++ use crate::*;
+
+ fn ptrace_child() -> ! {
+ ptrace::traceme().unwrap();
+@@ -82,7 +84,7 @@ mod ptrace {
+ assert!(ptrace::setoptions(child, Options::PTRACE_O_TRACESYSGOOD | Options::PTRACE_O_TRACEEXIT).is_ok());
+
+ // First, stop on the next system call, which will be exit()
+- assert!(ptrace::syscall(child).is_ok());
++ assert!(ptrace::syscall(child, None).is_ok());
+ assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child)));
+ // Then get the ptrace event for the process exiting
+ assert!(ptrace::cont(child, None).is_ok());
+@@ -94,9 +96,10 @@ mod ptrace {
+
+ #[test]
+ fn test_wait_ptrace() {
+- let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++ require_capability!(CAP_SYS_PTRACE);
++ let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test");
+
+- match fork().expect("Error: Fork Failed") {
++ match unsafe{fork()}.expect("Error: Fork Failed") {
+ Child => ptrace_child(),
+ Parent { child } => ptrace_parent(child),
+ }
+diff --git a/third_party/rust/nix/test/test.rs b/third_party/rust/nix/test/test.rs
+index 6a71d261b5712..5a5330b7e4010 100644
+--- a/third_party/rust/nix/test/test.rs
++++ b/third_party/rust/nix/test/test.rs
+@@ -1,69 +1,13 @@
+-// XXX Allow deprecated items until release 0.16.0. See issue #1096.
+-#![allow(deprecated)]
+-extern crate bytes;
+-#[cfg(any(target_os = "android", target_os = "linux"))]
+-extern crate caps;
+ #[macro_use]
+ extern crate cfg_if;
+-#[macro_use]
++#[cfg_attr(not(target_os = "redox"), macro_use)]
+ extern crate nix;
+ #[macro_use]
+ extern crate lazy_static;
+-extern crate libc;
+-extern crate rand;
+-#[cfg(target_os = "freebsd")]
+-extern crate sysctl;
+-extern crate tempfile;
+-
+-#[cfg(any(target_os = "android", target_os = "linux"))]
+-macro_rules! require_capability {
+- ($capname:ident) => {
+- use ::caps::{Capability, CapSet, has_cap};
+- use ::std::io::{self, Write};
+-
+- if !has_cap(None, CapSet::Effective, Capability::$capname).unwrap() {
+- let stderr = io::stderr();
+- let mut handle = stderr.lock();
+- writeln!(handle, "Insufficient capabilities. Skipping test.")
+- .unwrap();
+- return;
+- }
+- }
+-}
+-
+-#[cfg(target_os = "freebsd")]
+-macro_rules! skip_if_jailed {
+- ($name:expr) => {
+- use ::sysctl::CtlValue;
+-
+- if let CtlValue::Int(1) = ::sysctl::value("security.jail.jailed")
+- .unwrap()
+- {
+- use ::std::io::Write;
+- let stderr = ::std::io::stderr();
+- let mut handle = stderr.lock();
+- writeln!(handle, "{} cannot run in a jail. Skipping test.", $name)
+- .unwrap();
+- return;
+- }
+- }
+-}
+-
+-macro_rules! skip_if_not_root {
+- ($name:expr) => {
+- use nix::unistd::Uid;
+-
+- if !Uid::current().is_root() {
+- use ::std::io::Write;
+- let stderr = ::std::io::stderr();
+- let mut handle = stderr.lock();
+- writeln!(handle, "{} requires root privileges. Skipping test.", $name).unwrap();
+- return;
+- }
+- };
+-}
+
++mod common;
+ mod sys;
++#[cfg(not(target_os = "redox"))]
+ mod test_dir;
+ mod test_fcntl;
+ #[cfg(any(target_os = "android",
+@@ -75,10 +19,15 @@ mod test_kmod;
+ target_os = "linux",
+ target_os = "netbsd"))]
+ mod test_mq;
++#[cfg(not(target_os = "redox"))]
+ mod test_net;
+ mod test_nix_path;
+ mod test_poll;
++#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
+ mod test_pty;
++#[cfg(any(target_os = "android",
++ target_os = "linux"))]
++mod test_sched;
+ #[cfg(any(target_os = "android",
+ target_os = "freebsd",
+ target_os = "ios",
+@@ -86,6 +35,7 @@ mod test_pty;
+ target_os = "macos"))]
+ mod test_sendfile;
+ mod test_stat;
++mod test_time;
+ mod test_unistd;
+
+ use std::os::unix::io::RawFd;
+@@ -93,6 +43,7 @@ use std::path::PathBuf;
+ use std::sync::{Mutex, RwLock, RwLockWriteGuard};
+ use nix::unistd::{chdir, getcwd, read};
+
++
+ /// Helper function analogous to `std::io::Read::read_exact`, but for `RawFD`s
+ fn read_exact(f: RawFd, buf: &mut [u8]) {
+ let mut len = 0;
+@@ -130,7 +81,7 @@ struct DirRestore<'a> {
+
+ impl<'a> DirRestore<'a> {
+ fn new() -> Self {
+- let guard = ::CWD_LOCK.write()
++ let guard = crate::CWD_LOCK.write()
+ .expect("Lock got poisoned by another test");
+ DirRestore{
+ _g: guard,
+diff --git a/third_party/rust/nix/test/test_clearenv.rs b/third_party/rust/nix/test/test_clearenv.rs
+new file mode 100644
+index 0000000000000..28a77680498ca
+--- /dev/null
++++ b/third_party/rust/nix/test/test_clearenv.rs
+@@ -0,0 +1,9 @@
++use std::env;
++
++#[test]
++fn clearenv() {
++ env::set_var("FOO", "BAR");
++ unsafe { nix::env::clearenv() }.unwrap();
++ assert_eq!(env::var("FOO").unwrap_err(), env::VarError::NotPresent);
++ assert_eq!(env::vars().count(), 0);
++}
+diff --git a/third_party/rust/nix/test/test_dir.rs b/third_party/rust/nix/test/test_dir.rs
+index c42fbcd18a29d..505277e7143b7 100644
+--- a/third_party/rust/nix/test/test_dir.rs
++++ b/third_party/rust/nix/test/test_dir.rs
+@@ -1,11 +1,8 @@
+-extern crate nix;
+-extern crate tempfile;
+-
+ use nix::dir::{Dir, Type};
+ use nix::fcntl::OFlag;
+ use nix::sys::stat::Mode;
+ use std::fs::File;
+-use self::tempfile::tempdir;
++use tempfile::tempdir;
+
+ #[test]
+ fn read() {
+@@ -37,7 +34,9 @@ fn rewind() {
+ Mode::empty()).unwrap();
+ let entries1: Vec<_> = dir.iter().map(|e| e.unwrap().file_name().to_owned()).collect();
+ let entries2: Vec<_> = dir.iter().map(|e| e.unwrap().file_name().to_owned()).collect();
++ let entries3: Vec<_> = dir.into_iter().map(|e| e.unwrap().file_name().to_owned()).collect();
+ assert_eq!(entries1, entries2);
++ assert_eq!(entries2, entries3);
+ }
+
+ #[test]
+diff --git a/third_party/rust/nix/test/test_fcntl.rs b/third_party/rust/nix/test/test_fcntl.rs
+index 6b2bbd679fc31..5d1bafebe195f 100644
+--- a/third_party/rust/nix/test/test_fcntl.rs
++++ b/third_party/rust/nix/test/test_fcntl.rs
+@@ -1,14 +1,28 @@
++#[cfg(not(target_os = "redox"))]
+ use nix::Error;
++#[cfg(not(target_os = "redox"))]
+ use nix::errno::*;
+-use nix::fcntl::{openat, open, OFlag, readlink, readlinkat, renameat};
++#[cfg(not(target_os = "redox"))]
++use nix::fcntl::{open, OFlag, readlink};
++#[cfg(not(target_os = "redox"))]
++use nix::fcntl::{openat, readlinkat, renameat};
++#[cfg(not(target_os = "redox"))]
+ use nix::sys::stat::Mode;
++#[cfg(not(target_os = "redox"))]
+ use nix::unistd::{close, read};
++#[cfg(not(target_os = "redox"))]
+ use tempfile::{self, NamedTempFile};
++#[cfg(not(target_os = "redox"))]
+ use std::fs::File;
++#[cfg(not(target_os = "redox"))]
+ use std::io::prelude::*;
++#[cfg(not(target_os = "redox"))]
+ use std::os::unix::fs;
+
++use crate::*;
++
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_openat() {
+ const CONTENTS: &[u8] = b"abcd";
+ let mut tmp = NamedTempFile::new().unwrap();
+@@ -31,6 +45,7 @@ fn test_openat() {
+ }
+
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_renameat() {
+ let old_dir = tempfile::tempdir().unwrap();
+ let old_dirfd = open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap();
+@@ -47,6 +62,7 @@ fn test_renameat() {
+ }
+
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_readlink() {
+ let tempdir = tempfile::tempdir().unwrap();
+ let src = tempdir.path().join("a");
+@@ -56,28 +72,31 @@ fn test_readlink() {
+ let dirfd = open(tempdir.path(),
+ OFlag::empty(),
+ Mode::empty()).unwrap();
++ let expected_dir = src.to_str().unwrap();
++
++ assert_eq!(readlink(&dst).unwrap().to_str().unwrap(), expected_dir);
++ assert_eq!(readlinkat(dirfd, "b").unwrap().to_str().unwrap(), expected_dir);
+
+- let mut buf = vec![0; src.to_str().unwrap().len() + 1];
+- assert_eq!(readlink(&dst, &mut buf).unwrap().to_str().unwrap(),
+- src.to_str().unwrap());
+- assert_eq!(readlinkat(dirfd, "b", &mut buf).unwrap().to_str().unwrap(),
+- src.to_str().unwrap());
+ }
+
+ #[cfg(any(target_os = "linux", target_os = "android"))]
+ mod linux_android {
++ use std::fs::File;
+ use std::io::prelude::*;
+- use std::io::SeekFrom;
++ use std::io::{BufRead, BufReader, SeekFrom};
+ use std::os::unix::prelude::*;
+
+ use libc::loff_t;
+
+ use nix::fcntl::*;
++ use nix::sys::stat::fstat;
+ use nix::sys::uio::IoVec;
+ use nix::unistd::{close, pipe, read, write};
+
+ use tempfile::{tempfile, NamedTempFile};
+
++ use crate::*;
++
+ /// This test creates a temporary file containing the contents
+ /// 'foobarbaz' and uses the `copy_file_range` call to transfer
+ /// 3 bytes at offset 3 (`bar`) to another empty file at offset 0. The
+@@ -198,6 +217,113 @@ mod linux_android {
+ let mut buf = [0u8; 200];
+ assert_eq!(100, read(fd, &mut buf).unwrap());
+ }
++
++ // The tests below are disabled for the listed targets
++ // due to OFD locks not being available in the kernel/libc
++ // versions used in the CI environment, probably because
++ // they run under QEMU.
++
++ #[test]
++ #[cfg(not(any(target_arch = "aarch64",
++ target_arch = "arm",
++ target_arch = "armv7",
++ target_arch = "x86",
++ target_arch = "mips",
++ target_arch = "mips64",
++ target_arch = "mips64el",
++ target_arch = "powerpc64",
++ target_arch = "powerpc64le",
++ target_env = "musl")))]
++ fn test_ofd_write_lock() {
++ let tmp = NamedTempFile::new().unwrap();
++
++ let fd = tmp.as_raw_fd();
++ let statfs = nix::sys::statfs::fstatfs(&tmp).unwrap();
++ if statfs.filesystem_type() == nix::sys::statfs::OVERLAYFS_SUPER_MAGIC {
++ // OverlayFS is a union file system. It returns one inode value in
++ // stat(2), but a different one shows up in /proc/locks. So we must
++ // skip the test.
++ skip!("/proc/locks does not work on overlayfs");
++ }
++ let inode = fstat(fd).expect("fstat failed").st_ino as usize;
++
++ let mut flock = libc::flock {
++ l_type: libc::F_WRLCK as libc::c_short,
++ l_whence: libc::SEEK_SET as libc::c_short,
++ l_start: 0,
++ l_len: 0,
++ l_pid: 0,
++ };
++ fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("write lock failed");
++ assert_eq!(
++ Some(("OFDLCK".to_string(), "WRITE".to_string())),
++ lock_info(inode)
++ );
++
++ flock.l_type = libc::F_UNLCK as libc::c_short;
++ fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("write unlock failed");
++ assert_eq!(None, lock_info(inode));
++ }
++
++ #[test]
++ #[cfg(not(any(target_arch = "aarch64",
++ target_arch = "arm",
++ target_arch = "armv7",
++ target_arch = "x86",
++ target_arch = "mips",
++ target_arch = "mips64",
++ target_arch = "mips64el",
++ target_arch = "powerpc64",
++ target_arch = "powerpc64le",
++ target_env = "musl")))]
++ fn test_ofd_read_lock() {
++ let tmp = NamedTempFile::new().unwrap();
++
++ let fd = tmp.as_raw_fd();
++ let statfs = nix::sys::statfs::fstatfs(&tmp).unwrap();
++ if statfs.filesystem_type() == nix::sys::statfs::OVERLAYFS_SUPER_MAGIC {
++ // OverlayFS is a union file system. It returns one inode value in
++ // stat(2), but a different one shows up in /proc/locks. So we must
++ // skip the test.
++ skip!("/proc/locks does not work on overlayfs");
++ }
++ let inode = fstat(fd).expect("fstat failed").st_ino as usize;
++
++ let mut flock = libc::flock {
++ l_type: libc::F_RDLCK as libc::c_short,
++ l_whence: libc::SEEK_SET as libc::c_short,
++ l_start: 0,
++ l_len: 0,
++ l_pid: 0,
++ };
++ fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("read lock failed");
++ assert_eq!(
++ Some(("OFDLCK".to_string(), "READ".to_string())),
++ lock_info(inode)
++ );
++
++ flock.l_type = libc::F_UNLCK as libc::c_short;
++ fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("read unlock failed");
++ assert_eq!(None, lock_info(inode));
++ }
++
++ fn lock_info(inode: usize) -> Option<(String, String)> {
++ let file = File::open("/proc/locks").expect("open /proc/locks failed");
++ let buf = BufReader::new(file);
++
++ for line in buf.lines() {
++ let line = line.unwrap();
++ let parts: Vec<_> = line.split_whitespace().collect();
++ let lock_type = parts[1];
++ let lock_access = parts[3];
++ let ino_parts: Vec<_> = parts[5].split(':').collect();
++ let ino: usize = ino_parts[2].parse().unwrap();
++ if ino == inode {
++ return Some((lock_type.to_string(), lock_access.to_string()));
++ }
++ }
++ None
++ }
+ }
+
+ #[cfg(any(target_os = "linux",
+@@ -206,7 +332,7 @@ mod linux_android {
+ target_os = "fuchsia",
+ any(target_os = "wasi", target_env = "wasi"),
+ target_env = "uclibc",
+- target_env = "freebsd"))]
++ target_os = "freebsd"))]
+ mod test_posix_fadvise {
+
+ use tempfile::NamedTempFile;
+@@ -232,3 +358,60 @@ mod test_posix_fadvise {
+ assert_eq!(errno, Errno::ESPIPE as i32);
+ }
+ }
++
++#[cfg(any(target_os = "linux",
++ target_os = "android",
++ target_os = "emscripten",
++ target_os = "fuchsia",
++ any(target_os = "wasi", target_env = "wasi"),
++ target_os = "freebsd"))]
++mod test_posix_fallocate {
++
++ use tempfile::NamedTempFile;
++ use std::{io::Read, os::unix::io::{RawFd, AsRawFd}};
++ use nix::errno::Errno;
++ use nix::fcntl::*;
++ use nix::unistd::pipe;
++
++ #[test]
++ fn success() {
++ const LEN: usize = 100;
++ let mut tmp = NamedTempFile::new().unwrap();
++ let fd = tmp.as_raw_fd();
++ let res = posix_fallocate(fd, 0, LEN as libc::off_t);
++ match res {
++ Ok(_) => {
++ let mut data = [1u8; LEN];
++ assert_eq!(tmp.read(&mut data).expect("read failure"), LEN);
++ assert_eq!(&data[..], &[0u8; LEN][..]);
++ }
++ Err(nix::Error::Sys(Errno::EINVAL)) => {
++ // POSIX requires posix_fallocate to return EINVAL both for
++ // invalid arguments (i.e. len < 0) and if the operation is not
++ // supported by the file system.
++ // There's no way to tell for sure whether the file system
++ // supports posix_fallocate, so we must pass the test if it
++ // returns EINVAL.
++ }
++ _ => res.unwrap(),
++ }
++ }
++
++ #[test]
++ fn errno() {
++ let (rd, _wr) = pipe().unwrap();
++ let err = posix_fallocate(rd as RawFd, 0, 100).unwrap_err();
++ use nix::Error::Sys;
++ match err {
++ Sys(Errno::EINVAL)
++ | Sys(Errno::ENODEV)
++ | Sys(Errno::ESPIPE)
++ | Sys(Errno::EBADF) => (),
++ errno =>
++ panic!(
++ "unexpected errno {}",
++ errno,
++ ),
++ }
++ }
++}
+diff --git a/third_party/rust/nix/test/test_kmod/mod.rs b/third_party/rust/nix/test/test_kmod/mod.rs
+index ad406357b06d2..fb7260ba9c9d9 100644
+--- a/third_party/rust/nix/test/test_kmod/mod.rs
++++ b/third_party/rust/nix/test/test_kmod/mod.rs
+@@ -2,9 +2,10 @@ use std::fs::copy;
+ use std::path::PathBuf;
+ use std::process::Command;
+ use tempfile::{tempdir, TempDir};
++use crate::*;
+
+ fn compile_kernel_module() -> (PathBuf, String, TempDir) {
+- let _m = ::FORK_MTX
++ let _m = crate::FORK_MTX
+ .lock()
+ .expect("Mutex got poisoned by another test");
+
+@@ -41,8 +42,8 @@ use std::io::Read;
+ #[test]
+ fn test_finit_and_delete_module() {
+ require_capability!(CAP_SYS_MODULE);
+- let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
+- let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test");
++ let _m0 = crate::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
++ let _m1 = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test");
+
+ let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module();
+
+@@ -59,8 +60,8 @@ fn test_finit_and_delete_module() {
+ #[test]
+ fn test_finit_and_delete_modul_with_params() {
+ require_capability!(CAP_SYS_MODULE);
+- let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
+- let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test");
++ let _m0 = crate::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
++ let _m1 = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test");
+
+ let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module();
+
+@@ -80,8 +81,8 @@ fn test_finit_and_delete_modul_with_params() {
+ #[test]
+ fn test_init_and_delete_module() {
+ require_capability!(CAP_SYS_MODULE);
+- let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
+- let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test");
++ let _m0 = crate::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
++ let _m1 = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test");
+
+ let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module();
+
+@@ -100,8 +101,8 @@ fn test_init_and_delete_module() {
+ #[test]
+ fn test_init_and_delete_module_with_params() {
+ require_capability!(CAP_SYS_MODULE);
+- let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
+- let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test");
++ let _m0 = crate::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
++ let _m1 = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test");
+
+ let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module();
+
+@@ -121,8 +122,8 @@ fn test_init_and_delete_module_with_params() {
+ #[test]
+ fn test_finit_module_invalid() {
+ require_capability!(CAP_SYS_MODULE);
+- let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
+- let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test");
++ let _m0 = crate::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
++ let _m1 = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test");
+
+ let kmod_path = "/dev/zero";
+
+@@ -135,8 +136,8 @@ fn test_finit_module_invalid() {
+ #[test]
+ fn test_finit_module_twice_and_delete_module() {
+ require_capability!(CAP_SYS_MODULE);
+- let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
+- let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test");
++ let _m0 = crate::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
++ let _m1 = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test");
+
+ let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module();
+
+@@ -157,8 +158,8 @@ fn test_finit_module_twice_and_delete_module() {
+ #[test]
+ fn test_delete_module_not_loaded() {
+ require_capability!(CAP_SYS_MODULE);
+- let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
+- let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test");
++ let _m0 = crate::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
++ let _m1 = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test");
+
+ let result = delete_module(&CString::new("hello").unwrap(), DeleteModuleFlags::empty());
+
+diff --git a/third_party/rust/nix/test/test_mount.rs b/third_party/rust/nix/test/test_mount.rs
+index d2e08bc42855d..c1b6c8a3bf2d2 100644
+--- a/third_party/rust/nix/test/test_mount.rs
++++ b/third_party/rust/nix/test/test_mount.rs
+@@ -1,12 +1,10 @@
++mod common;
++
+ // Impelmentation note: to allow unprivileged users to run it, this test makes
+ // use of user and mount namespaces. On systems that allow unprivileged user
+ // namespaces (Linux >= 3.8 compiled with CONFIG_USER_NS), the test should run
+ // without root.
+
+-extern crate libc;
+-extern crate nix;
+-extern crate tempfile;
+-
+ #[cfg(target_os = "linux")]
+ mod test_mount {
+ use std::fs::{self, File};
+@@ -226,6 +224,7 @@ fn main() {
+ use test_mount::{setup_namespaces, test_mount_tmpfs_without_flags_allows_rwx,
+ test_mount_rdonly_disallows_write, test_mount_noexec_disallows_exec,
+ test_mount_bind};
++ skip_if_cirrus!("Fails for an unknown reason Cirrus CI. Bug #1351");
+ setup_namespaces();
+
+ run_tests!(test_mount_tmpfs_without_flags_allows_rwx,
+diff --git a/third_party/rust/nix/test/test_mq.rs b/third_party/rust/nix/test/test_mq.rs
+index caac4fc261cd6..1667a35b1a04b 100644
+--- a/third_party/rust/nix/test/test_mq.rs
++++ b/third_party/rust/nix/test/test_mq.rs
+@@ -1,17 +1,15 @@
+-use libc::c_long;
+-
+ use std::ffi::CString;
+ use std::str;
+
+ use nix::errno::Errno::*;
+ use nix::Error::Sys;
+-use nix::mqueue::{mq_open, mq_close, mq_send, mq_receive};
++use nix::mqueue::{mq_open, mq_close, mq_send, mq_receive, mq_attr_member_t};
+ use nix::mqueue::{MqAttr, MQ_OFlag};
+ use nix::sys::stat::Mode;
+
+ #[test]
+ fn test_mq_send_and_receive() {
+- const MSG_SIZE: c_long = 32;
++ const MSG_SIZE: mq_attr_member_t = 32;
+ let attr = MqAttr::new(0, 10, MSG_SIZE, 0);
+ let mq_name= &CString::new(b"/a_nix_test_queue".as_ref()).unwrap();
+
+@@ -31,7 +29,7 @@ fn test_mq_send_and_receive() {
+ let mut buf = [0u8; 32];
+ let mut prio = 0u32;
+ let len = mq_receive(mqd1, &mut buf, &mut prio).unwrap();
+- assert!(prio == 1);
++ assert_eq!(prio, 1);
+
+ mq_close(mqd1).unwrap();
+ mq_close(mqd0).unwrap();
+@@ -43,7 +41,7 @@ fn test_mq_send_and_receive() {
+ #[cfg(not(any(target_os = "netbsd")))]
+ fn test_mq_getattr() {
+ use nix::mqueue::mq_getattr;
+- const MSG_SIZE: c_long = 32;
++ const MSG_SIZE: mq_attr_member_t = 32;
+ let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0);
+ let mq_name = &CString::new(b"/attr_test_get_attr".as_ref()).unwrap();
+ let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
+@@ -66,7 +64,7 @@ fn test_mq_getattr() {
+ #[cfg_attr(any(target_arch = "mips", target_arch = "mips64"), ignore)]
+ fn test_mq_setattr() {
+ use nix::mqueue::{mq_getattr, mq_setattr};
+- const MSG_SIZE: c_long = 32;
++ const MSG_SIZE: mq_attr_member_t = 32;
+ let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0);
+ let mq_name = &CString::new(b"/attr_test_get_attr".as_ref()).unwrap();
+ let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
+@@ -87,7 +85,7 @@ fn test_mq_setattr() {
+ // O_NONBLOCK can be set (see tests below)
+ assert_ne!(new_attr_get, new_attr);
+
+- let new_attr_non_blocking = MqAttr::new(MQ_OFlag::O_NONBLOCK.bits() as c_long, 10, MSG_SIZE, 0);
++ let new_attr_non_blocking = MqAttr::new(MQ_OFlag::O_NONBLOCK.bits() as mq_attr_member_t, 10, MSG_SIZE, 0);
+ mq_setattr(mqd, &new_attr_non_blocking).unwrap();
+ let new_attr_get = mq_getattr(mqd).unwrap();
+
+@@ -103,7 +101,7 @@ fn test_mq_setattr() {
+ #[cfg_attr(any(target_arch = "mips", target_arch = "mips64"), ignore)]
+ fn test_mq_set_nonblocking() {
+ use nix::mqueue::{mq_getattr, mq_set_nonblock, mq_remove_nonblock};
+- const MSG_SIZE: c_long = 32;
++ const MSG_SIZE: mq_attr_member_t = 32;
+ let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0);
+ let mq_name = &CString::new(b"/attr_test_get_attr".as_ref()).unwrap();
+ let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
+@@ -116,10 +114,10 @@ fn test_mq_set_nonblocking() {
+ let mqd = r.unwrap();
+ mq_set_nonblock(mqd).unwrap();
+ let new_attr = mq_getattr(mqd);
+- assert!(new_attr.unwrap().flags() == MQ_OFlag::O_NONBLOCK.bits() as c_long);
++ assert_eq!(new_attr.unwrap().flags(), MQ_OFlag::O_NONBLOCK.bits() as mq_attr_member_t);
+ mq_remove_nonblock(mqd).unwrap();
+ let new_attr = mq_getattr(mqd);
+- assert!(new_attr.unwrap().flags() == 0);
++ assert_eq!(new_attr.unwrap().flags(), 0);
+ mq_close(mqd).unwrap();
+ }
+
+@@ -127,7 +125,7 @@ fn test_mq_set_nonblocking() {
+ #[cfg(not(any(target_os = "netbsd")))]
+ fn test_mq_unlink() {
+ use nix::mqueue::mq_unlink;
+- const MSG_SIZE: c_long = 32;
++ const MSG_SIZE: mq_attr_member_t = 32;
+ let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0);
+ let mq_name_opened = &CString::new(b"/mq_unlink_test".as_ref()).unwrap();
+ let mq_name_not_opened = &CString::new(b"/mq_unlink_test".as_ref()).unwrap();
+@@ -141,12 +139,12 @@ fn test_mq_unlink() {
+ let mqd = r.unwrap();
+
+ let res_unlink = mq_unlink(mq_name_opened);
+- assert!(res_unlink == Ok(()) );
++ assert_eq!(res_unlink, Ok(()) );
+
+ let res_unlink_not_opened = mq_unlink(mq_name_not_opened);
+- assert!(res_unlink_not_opened == Err(Sys(ENOENT)) );
++ assert_eq!(res_unlink_not_opened, Err(Sys(ENOENT)) );
+
+ mq_close(mqd).unwrap();
+ let res_unlink_after_close = mq_unlink(mq_name_opened);
+- assert!(res_unlink_after_close == Err(Sys(ENOENT)) );
++ assert_eq!(res_unlink_after_close, Err(Sys(ENOENT)) );
+ }
+diff --git a/third_party/rust/nix/test/test_poll.rs b/third_party/rust/nix/test/test_poll.rs
+index aef40e4792b5a..acfaad8bea6c0 100644
+--- a/third_party/rust/nix/test/test_poll.rs
++++ b/third_party/rust/nix/test/test_poll.rs
+@@ -1,5 +1,21 @@
+-use nix::poll::{PollFlags, poll, PollFd};
+-use nix::unistd::{write, pipe};
++use nix::{
++ Error,
++ errno::Errno,
++ poll::{PollFlags, poll, PollFd},
++ unistd::{write, pipe}
++};
++
++macro_rules! loop_while_eintr {
++ ($poll_expr: expr) => {
++ loop {
++ match $poll_expr {
++ Ok(nfds) => break nfds,
++ Err(Error::Sys(Errno::EINTR)) => (),
++ Err(e) => panic!("{}", e)
++ }
++ }
++ }
++}
+
+ #[test]
+ fn test_poll() {
+@@ -7,7 +23,7 @@ fn test_poll() {
+ let mut fds = [PollFd::new(r, PollFlags::POLLIN)];
+
+ // Poll an idle pipe. Should timeout
+- let nfds = poll(&mut fds, 100).unwrap();
++ let nfds = loop_while_eintr!(poll(&mut fds, 100));
+ assert_eq!(nfds, 0);
+ assert!(!fds[0].revents().unwrap().contains(PollFlags::POLLIN));
+
+@@ -37,14 +53,15 @@ fn test_ppoll() {
+ let mut fds = [PollFd::new(r, PollFlags::POLLIN)];
+
+ // Poll an idle pipe. Should timeout
+- let nfds = ppoll(&mut fds, timeout, SigSet::empty()).unwrap();
++ let sigset = SigSet::empty();
++ let nfds = loop_while_eintr!(ppoll(&mut fds, Some(timeout), sigset));
+ assert_eq!(nfds, 0);
+ assert!(!fds[0].revents().unwrap().contains(PollFlags::POLLIN));
+
+ write(w, b".").unwrap();
+
+ // Poll a readable pipe. Should return an event.
+- let nfds = ppoll(&mut fds, timeout, SigSet::empty()).unwrap();
++ let nfds = ppoll(&mut fds, Some(timeout), SigSet::empty()).unwrap();
+ assert_eq!(nfds, 1);
+ assert!(fds[0].revents().unwrap().contains(PollFlags::POLLIN));
+ }
+diff --git a/third_party/rust/nix/test/test_pty.rs b/third_party/rust/nix/test/test_pty.rs
+index 476b15c10128c..ab347bb040f5f 100644
+--- a/third_party/rust/nix/test/test_pty.rs
++++ b/third_party/rust/nix/test/test_pty.rs
+@@ -1,4 +1,5 @@
+-use std::io::Write;
++use std::fs::File;
++use std::io::{Read, Write};
+ use std::path::Path;
+ use std::os::unix::prelude::*;
+ use tempfile::tempfile;
+@@ -28,7 +29,7 @@ fn test_explicit_close() {
+ #[test]
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ fn test_ptsname_equivalence() {
+- let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++ let _m = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
+
+ // Open a new PTTY master
+ let master_fd = posix_openpt(OFlag::O_RDWR).unwrap();
+@@ -45,7 +46,7 @@ fn test_ptsname_equivalence() {
+ #[test]
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ fn test_ptsname_copy() {
+- let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++ let _m = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
+
+ // Open a new PTTY master
+ let master_fd = posix_openpt(OFlag::O_RDWR).unwrap();
+@@ -54,7 +55,7 @@ fn test_ptsname_copy() {
+ // Get the name of the slave
+ let slave_name1 = unsafe { ptsname(&master_fd) }.unwrap();
+ let slave_name2 = unsafe { ptsname(&master_fd) }.unwrap();
+- assert!(slave_name1 == slave_name2);
++ assert_eq!(slave_name1, slave_name2);
+ // Also make sure that the string was actually copied and they point to different parts of
+ // memory.
+ assert!(slave_name1.as_ptr() != slave_name2.as_ptr());
+@@ -71,7 +72,7 @@ fn test_ptsname_r_copy() {
+ // Get the name of the slave
+ let slave_name1 = ptsname_r(&master_fd).unwrap();
+ let slave_name2 = ptsname_r(&master_fd).unwrap();
+- assert!(slave_name1 == slave_name2);
++ assert_eq!(slave_name1, slave_name2);
+ assert!(slave_name1.as_ptr() != slave_name2.as_ptr());
+ }
+
+@@ -79,7 +80,7 @@ fn test_ptsname_r_copy() {
+ #[test]
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ fn test_ptsname_unique() {
+- let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++ let _m = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
+
+ // Open a new PTTY master
+ let master1_fd = posix_openpt(OFlag::O_RDWR).unwrap();
+@@ -95,35 +96,74 @@ fn test_ptsname_unique() {
+ assert!(slave_name1 != slave_name2);
+ }
+
+-/// Test opening a master/slave PTTY pair
+-///
+-/// This is a single larger test because much of these functions aren't useful by themselves. So for
+-/// this test we perform the basic act of getting a file handle for a connect master/slave PTTY
+-/// pair.
+-#[test]
+-fn test_open_ptty_pair() {
+- let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++/// Common setup for testing PTTY pairs
++fn open_ptty_pair() -> (PtyMaster, File) {
++ let _m = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
+
+ // Open a new PTTY master
+- let master_fd = posix_openpt(OFlag::O_RDWR).expect("posix_openpt failed");
+- assert!(master_fd.as_raw_fd() > 0);
++ let master = posix_openpt(OFlag::O_RDWR).expect("posix_openpt failed");
+
+ // Allow a slave to be generated for it
+- grantpt(&master_fd).expect("grantpt failed");
+- unlockpt(&master_fd).expect("unlockpt failed");
++ grantpt(&master).expect("grantpt failed");
++ unlockpt(&master).expect("unlockpt failed");
+
+ // Get the name of the slave
+- let slave_name = unsafe { ptsname(&master_fd) }.expect("ptsname failed");
++ let slave_name = unsafe { ptsname(&master) }.expect("ptsname failed");
+
+ // Open the slave device
+ let slave_fd = open(Path::new(&slave_name), OFlag::O_RDWR, stat::Mode::empty()).unwrap();
+- assert!(slave_fd > 0);
++ let slave = unsafe { File::from_raw_fd(slave_fd) };
++
++ (master, slave)
++}
++
++/// Test opening a master/slave PTTY pair
++///
++/// This uses a common `open_ptty_pair` because much of these functions aren't useful by
++/// themselves. So for this test we perform the basic act of getting a file handle for a
++/// master/slave PTTY pair, then just sanity-check the raw values.
++#[test]
++fn test_open_ptty_pair() {
++ let (master, slave) = open_ptty_pair();
++ assert!(master.as_raw_fd() > 0);
++ assert!(slave.as_raw_fd() > 0);
++}
++
++/// Put the terminal in raw mode.
++fn make_raw(fd: RawFd) {
++ let mut termios = tcgetattr(fd).unwrap();
++ cfmakeraw(&mut termios);
++ tcsetattr(fd, SetArg::TCSANOW, &termios).unwrap();
++}
++
++/// Test `io::Read` on the PTTY master
++#[test]
++fn test_read_ptty_pair() {
++ let (mut master, mut slave) = open_ptty_pair();
++ make_raw(slave.as_raw_fd());
++
++ let mut buf = [0u8; 5];
++ slave.write_all(b"hello").unwrap();
++ master.read_exact(&mut buf).unwrap();
++ assert_eq!(&buf, b"hello");
++}
++
++/// Test `io::Write` on the PTTY master
++#[test]
++fn test_write_ptty_pair() {
++ let (mut master, mut slave) = open_ptty_pair();
++ make_raw(slave.as_raw_fd());
++
++ let mut buf = [0u8; 5];
++ master.write_all(b"adios").unwrap();
++ slave.read_exact(&mut buf).unwrap();
++ assert_eq!(&buf, b"adios");
+ }
+
+ #[test]
+ fn test_openpty() {
+ // openpty uses ptname(3) internally
+- let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++ let _m = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
+
+ let pty = openpty(None, None).unwrap();
+ assert!(pty.master > 0);
+@@ -133,21 +173,21 @@ fn test_openpty() {
+ let string = "foofoofoo\n";
+ let mut buf = [0u8; 10];
+ write(pty.master, string.as_bytes()).unwrap();
+- ::read_exact(pty.slave, &mut buf);
++ crate::read_exact(pty.slave, &mut buf);
+
+ assert_eq!(&buf, string.as_bytes());
+
+ // Read the echo as well
+ let echoed_string = "foofoofoo\r\n";
+ let mut buf = [0u8; 11];
+- ::read_exact(pty.master, &mut buf);
++ crate::read_exact(pty.master, &mut buf);
+ assert_eq!(&buf, echoed_string.as_bytes());
+
+ let string2 = "barbarbarbar\n";
+ let echoed_string2 = "barbarbarbar\r\n";
+ let mut buf = [0u8; 14];
+ write(pty.slave, string2.as_bytes()).unwrap();
+- ::read_exact(pty.master, &mut buf);
++ crate::read_exact(pty.master, &mut buf);
+
+ assert_eq!(&buf, echoed_string2.as_bytes());
+
+@@ -158,14 +198,14 @@ fn test_openpty() {
+ #[test]
+ fn test_openpty_with_termios() {
+ // openpty uses ptname(3) internally
+- let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++ let _m = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
+
+ // Open one pty to get attributes for the second one
+ let mut termios = {
+ let pty = openpty(None, None).unwrap();
+ assert!(pty.master > 0);
+ assert!(pty.slave > 0);
+- let termios = tcgetattr(pty.master).unwrap();
++ let termios = tcgetattr(pty.slave).unwrap();
+ close(pty.master).unwrap();
+ close(pty.slave).unwrap();
+ termios
+@@ -182,20 +222,20 @@ fn test_openpty_with_termios() {
+ let string = "foofoofoo\n";
+ let mut buf = [0u8; 10];
+ write(pty.master, string.as_bytes()).unwrap();
+- ::read_exact(pty.slave, &mut buf);
++ crate::read_exact(pty.slave, &mut buf);
+
+ assert_eq!(&buf, string.as_bytes());
+
+ // read the echo as well
+ let echoed_string = "foofoofoo\n";
+- ::read_exact(pty.master, &mut buf);
++ crate::read_exact(pty.master, &mut buf);
+ assert_eq!(&buf, echoed_string.as_bytes());
+
+ let string2 = "barbarbarbar\n";
+ let echoed_string2 = "barbarbarbar\n";
+ let mut buf = [0u8; 13];
+ write(pty.slave, string2.as_bytes()).unwrap();
+- ::read_exact(pty.master, &mut buf);
++ crate::read_exact(pty.master, &mut buf);
+
+ assert_eq!(&buf, echoed_string2.as_bytes());
+
+@@ -209,9 +249,9 @@ fn test_forkpty() {
+ use nix::sys::signal::*;
+ use nix::sys::wait::wait;
+ // forkpty calls openpty which uses ptname(3) internally.
+- let _m0 = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++ let _m0 = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
+ // forkpty spawns a child process
+- let _m1 = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++ let _m1 = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test");
+
+ let string = "naninani\n";
+ let echoed_string = "naninani\r\n";
+@@ -225,7 +265,7 @@ fn test_forkpty() {
+ Parent { child } => {
+ let mut buf = [0u8; 10];
+ assert!(child.as_raw() > 0);
+- ::read_exact(pty.master, &mut buf);
++ crate::read_exact(pty.master, &mut buf);
+ kill(child, SIGTERM).unwrap();
+ wait().unwrap(); // keep other tests using generic wait from getting our child
+ assert_eq!(&buf, echoed_string.as_bytes());
+diff --git a/third_party/rust/nix/test/test_ptymaster_drop.rs b/third_party/rust/nix/test/test_ptymaster_drop.rs
+index 9b59d66435ed0..ff939b9c63e76 100644
+--- a/third_party/rust/nix/test/test_ptymaster_drop.rs
++++ b/third_party/rust/nix/test/test_ptymaster_drop.rs
+@@ -1,21 +1,24 @@
+-extern crate nix;
++#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
++mod t {
++ use nix::fcntl::OFlag;
++ use nix::pty::*;
++ use nix::unistd::close;
++ use std::os::unix::io::AsRawFd;
+
+-use nix::fcntl::OFlag;
+-use nix::pty::*;
+-use nix::unistd::close;
+-use std::os::unix::io::AsRawFd;
+-
+-/// Regression test for Issue #659
+-/// `PtyMaster` should panic rather than double close the file descriptor
+-/// This must run in its own test process because it deliberately creates a race
+-/// condition.
+-#[test]
+-#[should_panic(expected = "Closing an invalid file descriptor!")]
+-// In Travis on i686-unknown-linux-musl, this test gets SIGABRT. I don't know
+-// why. It doesn't happen on any other target, and it doesn't happen on my PC.
+-#[cfg_attr(all(target_env = "musl", target_arch = "x86"), ignore)]
+-fn test_double_close() {
+- let m = posix_openpt(OFlag::O_RDWR).unwrap();
+- close(m.as_raw_fd()).unwrap();
+- drop(m); // should panic here
++ /// Regression test for Issue #659
++ ///
++ /// `PtyMaster` should panic rather than double close the file descriptor
++ /// This must run in its own test process because it deliberately creates a
++ /// race condition.
++ #[test]
++ #[should_panic(expected = "Closing an invalid file descriptor!")]
++ // In Travis on i686-unknown-linux-musl, this test gets SIGABRT. I don't
++ // know why. It doesn't happen on any other target, and it doesn't happen
++ // on my PC.
++ #[cfg_attr(all(target_env = "musl", target_arch = "x86"), ignore)]
++ fn test_double_close() {
++ let m = posix_openpt(OFlag::O_RDWR).unwrap();
++ close(m.as_raw_fd()).unwrap();
++ drop(m); // should panic here
++ }
+ }
+diff --git a/third_party/rust/nix/test/test_sched.rs b/third_party/rust/nix/test/test_sched.rs
+new file mode 100644
+index 0000000000000..922196a3dba73
+--- /dev/null
++++ b/third_party/rust/nix/test/test_sched.rs
+@@ -0,0 +1,32 @@
++use nix::sched::{sched_getaffinity, sched_setaffinity, CpuSet};
++use nix::unistd::Pid;
++
++#[test]
++fn test_sched_affinity() {
++ // If pid is zero, then the mask of the calling process is returned.
++ let initial_affinity = sched_getaffinity(Pid::from_raw(0)).unwrap();
++ let mut at_least_one_cpu = false;
++ let mut last_valid_cpu = 0;
++ for field in 0..CpuSet::count() {
++ if initial_affinity.is_set(field).unwrap() {
++ at_least_one_cpu = true;
++ last_valid_cpu = field;
++ }
++ }
++ assert!(at_least_one_cpu);
++
++ // Now restrict the running CPU
++ let mut new_affinity = CpuSet::new();
++ new_affinity.set(last_valid_cpu).unwrap();
++ sched_setaffinity(Pid::from_raw(0), &new_affinity).unwrap();
++
++ // And now re-check the affinity which should be only the one we set.
++ let updated_affinity = sched_getaffinity(Pid::from_raw(0)).unwrap();
++ for field in 0..CpuSet::count() {
++ // Should be set only for the CPU we set previously
++ assert_eq!(updated_affinity.is_set(field).unwrap(), field==last_valid_cpu)
++ }
++
++ // Finally, reset the initial CPU set
++ sched_setaffinity(Pid::from_raw(0), &initial_affinity).unwrap();
++}
+diff --git a/third_party/rust/nix/test/test_stat.rs b/third_party/rust/nix/test/test_stat.rs
+index 1173455fae8db..0b9466685607b 100644
+--- a/third_party/rust/nix/test/test_stat.rs
++++ b/third_party/rust/nix/test/test_stat.rs
+@@ -1,15 +1,26 @@
+-use std::fs::{self, File};
++#[cfg(not(target_os = "redox"))]
++use std::fs;
++use std::fs::File;
++#[cfg(not(target_os = "redox"))]
+ use std::os::unix::fs::{symlink, PermissionsExt};
+ use std::os::unix::prelude::AsRawFd;
++#[cfg(not(target_os = "redox"))]
+ use std::time::{Duration, UNIX_EPOCH};
++#[cfg(not(target_os = "redox"))]
+ use std::path::Path;
+
+-#[cfg(not(any(target_os = "netbsd")))]
++#[cfg(not(any(target_os = "netbsd", target_os = "redox")))]
+ use libc::{S_IFMT, S_IFLNK, mode_t};
+
++#[cfg(not(target_os = "redox"))]
+ use nix::{fcntl, Error};
+-use nix::errno::{Errno};
+-use nix::sys::stat::{self, fchmod, fchmodat, futimens, stat, utimes, utimensat, mkdirat};
++#[cfg(not(target_os = "redox"))]
++use nix::errno::Errno;
++#[cfg(not(target_os = "redox"))]
++use nix::sys::stat::{self, futimens, utimes};
++use nix::sys::stat::{fchmod, stat};
++#[cfg(not(target_os = "redox"))]
++use nix::sys::stat::{fchmodat, utimensat, mkdirat};
+ #[cfg(any(target_os = "linux",
+ target_os = "haiku",
+ target_os = "ios",
+@@ -17,15 +28,19 @@ use nix::sys::stat::{self, fchmod, fchmodat, futimens, stat, utimes, utimensat,
+ target_os = "freebsd",
+ target_os = "netbsd"))]
+ use nix::sys::stat::lutimes;
+-use nix::sys::stat::{Mode, FchmodatFlags, UtimensatFlags};
++#[cfg(not(target_os = "redox"))]
++use nix::sys::stat::{FchmodatFlags, UtimensatFlags};
++use nix::sys::stat::Mode;
+
+-#[cfg(not(any(target_os = "netbsd")))]
++#[cfg(not(any(target_os = "netbsd", target_os = "redox")))]
+ use nix::sys::stat::FileStat;
+
++#[cfg(not(target_os = "redox"))]
+ use nix::sys::time::{TimeSpec, TimeVal, TimeValLike};
++#[cfg(not(target_os = "redox"))]
+ use nix::unistd::chdir;
+
+-#[cfg(not(any(target_os = "netbsd")))]
++#[cfg(not(any(target_os = "netbsd", target_os = "redox")))]
+ use nix::Result;
+ use tempfile;
+
+@@ -33,27 +48,27 @@ use tempfile;
+ // uid and gid are signed on Windows, but not on other platforms. This function
+ // allows warning free compiles on all platforms, and can be removed when
+ // expression-level #[allow] is available.
+-#[cfg(not(any(target_os = "netbsd")))]
++#[cfg(not(any(target_os = "netbsd", target_os = "redox")))]
+ fn valid_uid_gid(stat: FileStat) -> bool {
+ // uid could be 0 for the `root` user. This quite possible when
+ // the tests are being run on a rooted Android device.
+ stat.st_uid >= 0 && stat.st_gid >= 0
+ }
+
+-#[cfg(not(any(target_os = "netbsd")))]
++#[cfg(not(any(target_os = "netbsd", target_os = "redox")))]
+ fn assert_stat_results(stat_result: Result<FileStat>) {
+ let stats = stat_result.expect("stat call failed");
+ assert!(stats.st_dev > 0); // must be positive integer, exact number machine dependent
+ assert!(stats.st_ino > 0); // inode is positive integer, exact number machine dependent
+ assert!(stats.st_mode > 0); // must be positive integer
+- assert!(stats.st_nlink == 1); // there links created, must be 1
++ assert_eq!(stats.st_nlink, 1); // there links created, must be 1
+ assert!(valid_uid_gid(stats)); // must be positive integers
+- assert!(stats.st_size == 0); // size is 0 because we did not write anything to the file
++ assert_eq!(stats.st_size, 0); // size is 0 because we did not write anything to the file
+ assert!(stats.st_blksize > 0); // must be positive integer, exact number machine dependent
+ assert!(stats.st_blocks <= 16); // Up to 16 blocks can be allocated for a blank file
+ }
+
+-#[cfg(not(any(target_os = "netbsd")))]
++#[cfg(not(any(target_os = "netbsd", target_os = "redox")))]
+ fn assert_lstat_results(stat_result: Result<FileStat>) {
+ let stats = stat_result.expect("stat call failed");
+ assert!(stats.st_dev > 0); // must be positive integer, exact number machine dependent
+@@ -63,8 +78,8 @@ fn assert_lstat_results(stat_result: Result<FileStat>) {
+ // st_mode is c_uint (u32 on Android) while S_IFMT is mode_t
+ // (u16 on Android), and that will be a compile error.
+ // On other platforms they are the same (either both are u16 or u32).
+- assert!((stats.st_mode as usize) & (S_IFMT as usize) == S_IFLNK as usize); // should be a link
+- assert!(stats.st_nlink == 1); // there links created, must be 1
++ assert_eq!((stats.st_mode as usize) & (S_IFMT as usize), S_IFLNK as usize); // should be a link
++ assert_eq!(stats.st_nlink, 1); // there links created, must be 1
+ assert!(valid_uid_gid(stats)); // must be positive integers
+ assert!(stats.st_size > 0); // size is > 0 because it points to another file
+ assert!(stats.st_blksize > 0); // must be positive integer, exact number machine dependent
+@@ -76,7 +91,7 @@ fn assert_lstat_results(stat_result: Result<FileStat>) {
+ }
+
+ #[test]
+-#[cfg(not(any(target_os = "netbsd")))]
++#[cfg(not(any(target_os = "netbsd", target_os = "redox")))]
+ fn test_stat_and_fstat() {
+ use nix::sys::stat::fstat;
+
+@@ -92,7 +107,7 @@ fn test_stat_and_fstat() {
+ }
+
+ #[test]
+-#[cfg(not(any(target_os = "netbsd")))]
++#[cfg(not(any(target_os = "netbsd", target_os = "redox")))]
+ fn test_fstatat() {
+ let tempdir = tempfile::tempdir().unwrap();
+ let filename = tempdir.path().join("foo.txt");
+@@ -108,7 +123,7 @@ fn test_fstatat() {
+ }
+
+ #[test]
+-#[cfg(not(any(target_os = "netbsd")))]
++#[cfg(not(any(target_os = "netbsd", target_os = "redox")))]
+ fn test_stat_fstat_lstat() {
+ use nix::sys::stat::{fstat, lstat};
+
+@@ -155,8 +170,9 @@ fn test_fchmod() {
+ }
+
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_fchmodat() {
+- let _dr = ::DirRestore::new();
++ let _dr = crate::DirRestore::new();
+ let tempdir = tempfile::tempdir().unwrap();
+ let filename = "foo.txt";
+ let fullpath = tempdir.path().join(filename);
+@@ -186,6 +202,7 @@ fn test_fchmodat() {
+ ///
+ /// The atime and mtime are expressed with a resolution of seconds because some file systems
+ /// (like macOS's HFS+) do not have higher granularity.
++#[cfg(not(target_os = "redox"))]
+ fn assert_times_eq(exp_atime_sec: u64, exp_mtime_sec: u64, attr: &fs::Metadata) {
+ assert_eq!(
+ Duration::new(exp_atime_sec, 0),
+@@ -196,6 +213,7 @@ fn assert_times_eq(exp_atime_sec: u64, exp_mtime_sec: u64, attr: &fs::Metadata)
+ }
+
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_utimes() {
+ let tempdir = tempfile::tempdir().unwrap();
+ let fullpath = tempdir.path().join("file");
+@@ -231,6 +249,7 @@ fn test_lutimes() {
+ }
+
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_futimens() {
+ let tempdir = tempfile::tempdir().unwrap();
+ let fullpath = tempdir.path().join("file");
+@@ -243,8 +262,9 @@ fn test_futimens() {
+ }
+
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_utimensat() {
+- let _dr = ::DirRestore::new();
++ let _dr = crate::DirRestore::new();
+ let tempdir = tempfile::tempdir().unwrap();
+ let filename = "foo.txt";
+ let fullpath = tempdir.path().join(filename);
+@@ -264,6 +284,7 @@ fn test_utimensat() {
+ }
+
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_mkdirat_success_path() {
+ let tempdir = tempfile::tempdir().unwrap();
+ let filename = "example_subdir";
+@@ -273,6 +294,7 @@ fn test_mkdirat_success_path() {
+ }
+
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_mkdirat_success_mode() {
+ let expected_bits = stat::SFlag::S_IFDIR.bits() | stat::Mode::S_IRWXU.bits();
+ let tempdir = tempfile::tempdir().unwrap();
+@@ -285,6 +307,7 @@ fn test_mkdirat_success_mode() {
+ }
+
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_mkdirat_fail() {
+ let tempdir = tempfile::tempdir().unwrap();
+ let not_dir_filename= "example_not_dir";
+diff --git a/third_party/rust/nix/test/test_time.rs b/third_party/rust/nix/test/test_time.rs
+new file mode 100644
+index 0000000000000..c321352d79c16
+--- /dev/null
++++ b/third_party/rust/nix/test/test_time.rs
+@@ -0,0 +1,56 @@
++#[cfg(any(
++ target_os = "freebsd",
++ target_os = "dragonfly",
++ target_os = "linux",
++ target_os = "android",
++ target_os = "emscripten",
++))]
++use nix::time::clock_getcpuclockid;
++use nix::time::{clock_getres, clock_gettime, ClockId};
++
++#[test]
++pub fn test_clock_getres() {
++ assert!(clock_getres(ClockId::CLOCK_REALTIME).is_ok());
++}
++
++#[test]
++pub fn test_clock_gettime() {
++ assert!(clock_gettime(ClockId::CLOCK_REALTIME).is_ok());
++}
++
++#[cfg(any(
++ target_os = "freebsd",
++ target_os = "dragonfly",
++ target_os = "linux",
++ target_os = "android",
++ target_os = "emscripten",
++))]
++#[test]
++pub fn test_clock_getcpuclockid() {
++ let clock_id = clock_getcpuclockid(nix::unistd::Pid::this()).unwrap();
++ assert!(clock_gettime(clock_id).is_ok());
++}
++
++#[test]
++pub fn test_clock_id_res() {
++ assert!(ClockId::CLOCK_REALTIME.res().is_ok());
++}
++
++#[test]
++pub fn test_clock_id_now() {
++ assert!(ClockId::CLOCK_REALTIME.now().is_ok());
++}
++
++#[cfg(any(
++ target_os = "freebsd",
++ target_os = "dragonfly",
++ target_os = "linux",
++ target_os = "android",
++ target_os = "emscripten",
++))]
++#[test]
++pub fn test_clock_id_pid_cpu_clock_id() {
++ assert!(ClockId::pid_cpu_clock_id(nix::unistd::Pid::this())
++ .map(ClockId::now)
++ .is_ok());
++}
+diff --git a/third_party/rust/nix/test/test_unistd.rs b/third_party/rust/nix/test/test_unistd.rs
+index 46196dec7ccce..16a8a05dd6d08 100644
+--- a/third_party/rust/nix/test/test_unistd.rs
++++ b/third_party/rust/nix/test/test_unistd.rs
+@@ -1,26 +1,39 @@
+-use nix::fcntl::{self, fcntl, FcntlArg, FdFlag, open, OFlag, readlink};
++#[cfg(not(target_os = "redox"))]
++use nix::fcntl::{self, open, readlink};
++use nix::fcntl::{fcntl, FcntlArg, FdFlag, OFlag};
+ use nix::unistd::*;
+ use nix::unistd::ForkResult::*;
++#[cfg(not(target_os = "redox"))]
+ use nix::sys::signal::{SaFlags, SigAction, SigHandler, SigSet, Signal, sigaction};
+ use nix::sys::wait::*;
+ use nix::sys::stat::{self, Mode, SFlag};
++#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
++use nix::pty::{posix_openpt, grantpt, unlockpt, ptsname};
+ use nix::errno::Errno;
++#[cfg(not(target_os = "redox"))]
+ use nix::Error;
+ use std::{env, iter};
++#[cfg(not(target_os = "redox"))]
+ use std::ffi::CString;
+-use std::fs::{self, DirBuilder, File};
++#[cfg(not(target_os = "redox"))]
++use std::fs::DirBuilder;
++use std::fs::{self, File};
+ use std::io::Write;
+ use std::os::unix::prelude::*;
+-use tempfile::{self, tempfile};
+-use libc::{self, _exit, off_t};
++#[cfg(not(target_os = "redox"))]
++use std::path::Path;
++use tempfile::{tempdir, tempfile};
++use libc::{_exit, off_t};
++
++use crate::*;
+
+ #[test]
+ #[cfg(not(any(target_os = "netbsd")))]
+ fn test_fork_and_waitpid() {
+- let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++ let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test");
+
+ // Safe: Child only calls `_exit`, which is signal-safe
+- match fork().expect("Error: Fork Failed") {
++ match unsafe{fork()}.expect("Error: Fork Failed") {
+ Child => unsafe { _exit(0) },
+ Parent { child } => {
+ // assert that child was created and pid > 0
+@@ -29,7 +42,7 @@ fn test_fork_and_waitpid() {
+ let wait_status = waitpid(child, None);
+ match wait_status {
+ // assert that waitpid returned correct status and the pid is the one of the child
+- Ok(WaitStatus::Exited(pid_t, _)) => assert!(pid_t == child),
++ Ok(WaitStatus::Exited(pid_t, _)) => assert_eq!(pid_t, child),
+
+ // panic, must never happen
+ s @ Ok(_) => panic!("Child exited {:?}, should never happen", s),
+@@ -45,10 +58,10 @@ fn test_fork_and_waitpid() {
+ #[test]
+ fn test_wait() {
+ // Grab FORK_MTX so wait doesn't reap a different test's child process
+- let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++ let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test");
+
+ // Safe: Child only calls `_exit`, which is signal-safe
+- match fork().expect("Error: Fork Failed") {
++ match unsafe{fork()}.expect("Error: Fork Failed") {
+ Child => unsafe { _exit(0) },
+ Parent { child } => {
+ let wait_status = wait();
+@@ -81,8 +94,9 @@ fn test_mkstemp_directory() {
+ }
+
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_mkfifo() {
+- let tempdir = tempfile::tempdir().unwrap();
++ let tempdir = tempdir().unwrap();
+ let mkfifo_fifo = tempdir.path().join("mkfifo_fifo");
+
+ mkfifo(&mkfifo_fifo, Mode::S_IRUSR).unwrap();
+@@ -93,11 +107,70 @@ fn test_mkfifo() {
+ }
+
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_mkfifo_directory() {
+ // mkfifo should fail if a directory is given
+ assert!(mkfifo(&env::temp_dir(), Mode::S_IRUSR).is_err());
+ }
+
++#[test]
++#[cfg(not(any(
++ target_os = "macos", target_os = "ios",
++ target_os = "android", target_os = "redox")))]
++fn test_mkfifoat_none() {
++ let _m = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test");
++
++ let tempdir = tempdir().unwrap();
++ let mkfifoat_fifo = tempdir.path().join("mkfifoat_fifo");
++
++ mkfifoat(None, &mkfifoat_fifo, Mode::S_IRUSR).unwrap();
++
++ let stats = stat::stat(&mkfifoat_fifo).unwrap();
++ let typ = stat::SFlag::from_bits_truncate(stats.st_mode);
++ assert_eq!(typ, SFlag::S_IFIFO);
++}
++
++#[test]
++#[cfg(not(any(
++ target_os = "macos", target_os = "ios",
++ target_os = "android", target_os = "redox")))]
++fn test_mkfifoat() {
++ let tempdir = tempdir().unwrap();
++ let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap();
++ let mkfifoat_name = "mkfifoat_name";
++
++ mkfifoat(Some(dirfd), mkfifoat_name, Mode::S_IRUSR).unwrap();
++
++ let stats = stat::fstatat(dirfd, mkfifoat_name, fcntl::AtFlags::empty()).unwrap();
++ let typ = stat::SFlag::from_bits_truncate(stats.st_mode);
++ assert_eq!(typ, SFlag::S_IFIFO);
++}
++
++#[test]
++#[cfg(not(any(
++ target_os = "macos", target_os = "ios",
++ target_os = "android", target_os = "redox")))]
++fn test_mkfifoat_directory_none() {
++ let _m = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test");
++
++ // mkfifoat should fail if a directory is given
++ assert!(!mkfifoat(None, &env::temp_dir(), Mode::S_IRUSR).is_ok());
++}
++
++#[test]
++#[cfg(not(any(
++ target_os = "macos", target_os = "ios",
++ target_os = "android", target_os = "redox")))]
++fn test_mkfifoat_directory() {
++ // mkfifoat should fail if a directory is given
++ let tempdir = tempdir().unwrap();
++ let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap();
++ let mkfifoat_dir = "mkfifoat_dir";
++ stat::mkdirat(dirfd, mkfifoat_dir, Mode::S_IRUSR).unwrap();
++
++ assert!(!mkfifoat(Some(dirfd), mkfifoat_dir, Mode::S_IRUSR).is_ok());
++}
++
+ #[test]
+ fn test_getpid() {
+ let pid: ::libc::pid_t = getpid().into();
+@@ -107,11 +180,12 @@ fn test_getpid() {
+ }
+
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_getsid() {
+ let none_sid: ::libc::pid_t = getsid(None).unwrap().into();
+ let pid_sid: ::libc::pid_t = getsid(Some(getpid())).unwrap().into();
+ assert!(none_sid > 0);
+- assert!(none_sid == pid_sid);
++ assert_eq!(none_sid, pid_sid);
+ }
+
+ #[cfg(any(target_os = "linux", target_os = "android"))]
+@@ -127,12 +201,12 @@ mod linux_android {
+
+ #[test]
+ // `getgroups()` and `setgroups()` do not behave as expected on Apple platforms
+-#[cfg(not(any(target_os = "ios", target_os = "macos")))]
++#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox", target_os = "fuchsia")))]
+ fn test_setgroups() {
+ // Skip this test when not run as root as `setgroups()` requires root.
+ skip_if_not_root!("test_setgroups");
+
+- let _m = ::GROUPS_MTX.lock().expect("Mutex got poisoned by another test");
++ let _m = crate::GROUPS_MTX.lock().expect("Mutex got poisoned by another test");
+
+ // Save the existing groups
+ let old_groups = getgroups().unwrap();
+@@ -150,13 +224,13 @@ fn test_setgroups() {
+
+ #[test]
+ // `getgroups()` and `setgroups()` do not behave as expected on Apple platforms
+-#[cfg(not(any(target_os = "ios", target_os = "macos")))]
++#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox", target_os = "fuchsia")))]
+ fn test_initgroups() {
+ // Skip this test when not run as root as `initgroups()` and `setgroups()`
+ // require root.
+ skip_if_not_root!("test_initgroups");
+
+- let _m = ::GROUPS_MTX.lock().expect("Mutex got poisoned by another test");
++ let _m = crate::GROUPS_MTX.lock().expect("Mutex got poisoned by another test");
+
+ // Save the existing groups
+ let old_groups = getgroups().unwrap();
+@@ -180,11 +254,53 @@ fn test_initgroups() {
+ setgroups(&old_groups).unwrap();
+ }
+
++#[cfg(not(target_os = "redox"))]
+ macro_rules! execve_test_factory(
+ ($test_name:ident, $syscall:ident, $exe: expr $(, $pathname:expr, $flags:expr)*) => (
+- #[test]
+- fn $test_name() {
+- let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++
++ #[cfg(test)]
++ mod $test_name {
++ use std::ffi::CStr;
++ use super::*;
++
++ const EMPTY: &'static [u8] = b"\0";
++ const DASH_C: &'static [u8] = b"-c\0";
++ const BIGARG: &'static [u8] = b"echo nix!!! && echo foo=$foo && echo baz=$baz\0";
++ const FOO: &'static [u8] = b"foo=bar\0";
++ const BAZ: &'static [u8] = b"baz=quux\0";
++
++ fn syscall_cstr_ref() -> Result<std::convert::Infallible, nix::Error> {
++ $syscall(
++ $exe,
++ $(CString::new($pathname).unwrap().as_c_str(), )*
++ &[CStr::from_bytes_with_nul(EMPTY).unwrap(),
++ CStr::from_bytes_with_nul(DASH_C).unwrap(),
++ CStr::from_bytes_with_nul(BIGARG).unwrap()],
++ &[CStr::from_bytes_with_nul(FOO).unwrap(),
++ CStr::from_bytes_with_nul(BAZ).unwrap()]
++ $(, $flags)*)
++ }
++
++ fn syscall_cstring() -> Result<std::convert::Infallible, nix::Error> {
++ $syscall(
++ $exe,
++ $(CString::new($pathname).unwrap().as_c_str(), )*
++ &[CString::from(CStr::from_bytes_with_nul(EMPTY).unwrap()),
++ CString::from(CStr::from_bytes_with_nul(DASH_C).unwrap()),
++ CString::from(CStr::from_bytes_with_nul(BIGARG).unwrap())],
++ &[CString::from(CStr::from_bytes_with_nul(FOO).unwrap()),
++ CString::from(CStr::from_bytes_with_nul(BAZ).unwrap())]
++ $(, $flags)*)
++ }
++
++ fn common_test(syscall: fn() -> Result<std::convert::Infallible, nix::Error>) {
++ if "execveat" == stringify!($syscall) {
++ // Though undocumented, Docker's default seccomp profile seems to
++ // block this syscall. https://github.com/nix-rust/nix/issues/1122
++ skip_if_seccomp!($test_name);
++ }
++
++ let m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test");
+ // The `exec`d process will write to `writer`, and we'll read that
+ // data from `reader`.
+ let (reader, writer) = pipe().unwrap();
+@@ -192,27 +308,21 @@ macro_rules! execve_test_factory(
+ // Safe: Child calls `exit`, `dup`, `close` and the provided `exec*` family function.
+ // NOTE: Technically, this makes the macro unsafe to use because you could pass anything.
+ // The tests make sure not to do that, though.
+- match fork().unwrap() {
++ match unsafe{fork()}.unwrap() {
+ Child => {
+- // Close stdout.
+- close(1).unwrap();
+ // Make `writer` be the stdout of the new process.
+- dup(writer).unwrap();
+- // exec!
+- $syscall(
+- $exe,
+- $(&CString::new($pathname).unwrap(), )*
+- &[CString::new(b"".as_ref()).unwrap(),
+- CString::new(b"-c".as_ref()).unwrap(),
+- CString::new(b"echo nix!!! && echo foo=$foo && echo baz=$baz"
+- .as_ref()).unwrap()],
+- &[CString::new(b"foo=bar".as_ref()).unwrap(),
+- CString::new(b"baz=quux".as_ref()).unwrap()]
+- $(, $flags)*).unwrap();
++ dup2(writer, 1).unwrap();
++ let r = syscall();
++ let _ = std::io::stderr()
++ .write_all(format!("{:?}", r).as_bytes());
++ // Should only get here in event of error
++ unsafe{ _exit(1) };
+ },
+ Parent { child } => {
+ // Wait for the child to exit.
+- waitpid(child, None).unwrap();
++ let ws = waitpid(child, None);
++ drop(m);
++ assert_eq!(ws, Ok(WaitStatus::Exited(child, 0)));
+ // Read 1024 bytes.
+ let mut buf = [0u8; 1024];
+ read(reader, &mut buf).unwrap();
+@@ -224,23 +334,43 @@ macro_rules! execve_test_factory(
+ }
+ }
+ }
++
++ // These tests frequently fail on musl, probably due to
++ // https://github.com/nix-rust/nix/issues/555
++ #[cfg_attr(target_env = "musl", ignore)]
++ #[test]
++ fn test_cstr_ref() {
++ common_test(syscall_cstr_ref);
++ }
++
++ // These tests frequently fail on musl, probably due to
++ // https://github.com/nix-rust/nix/issues/555
++ #[cfg_attr(target_env = "musl", ignore)]
++ #[test]
++ fn test_cstring() {
++ common_test(syscall_cstring);
++ }
++ }
++
+ )
+ );
+
+ cfg_if!{
+ if #[cfg(target_os = "android")] {
+- execve_test_factory!(test_execve, execve, &CString::new("/system/bin/sh").unwrap());
++ execve_test_factory!(test_execve, execve, CString::new("/system/bin/sh").unwrap().as_c_str());
+ execve_test_factory!(test_fexecve, fexecve, File::open("/system/bin/sh").unwrap().into_raw_fd());
+ } else if #[cfg(any(target_os = "freebsd",
+ target_os = "linux"))] {
+- execve_test_factory!(test_execve, execve, &CString::new("/bin/sh").unwrap());
++ // These tests frequently fail on musl, probably due to
++ // https://github.com/nix-rust/nix/issues/555
++ execve_test_factory!(test_execve, execve, CString::new("/bin/sh").unwrap().as_c_str());
+ execve_test_factory!(test_fexecve, fexecve, File::open("/bin/sh").unwrap().into_raw_fd());
+ } else if #[cfg(any(target_os = "dragonfly",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))] {
+- execve_test_factory!(test_execve, execve, &CString::new("/bin/sh").unwrap());
++ execve_test_factory!(test_execve, execve, CString::new("/bin/sh").unwrap().as_c_str());
+ // No fexecve() on DragonFly, ios, macos, NetBSD, OpenBSD.
+ //
+ // Note for NetBSD and OpenBSD: although rust-lang/libc includes it
+@@ -255,13 +385,16 @@ execve_test_factory!(test_execvpe, execvpe, &CString::new("sh").unwrap());
+ cfg_if!{
+ if #[cfg(target_os = "android")] {
+ use nix::fcntl::AtFlags;
+- execve_test_factory!(test_execveat_empty, execveat, File::open("/system/bin/sh").unwrap().into_raw_fd(),
++ execve_test_factory!(test_execveat_empty, execveat,
++ File::open("/system/bin/sh").unwrap().into_raw_fd(),
+ "", AtFlags::AT_EMPTY_PATH);
+- execve_test_factory!(test_execveat_relative, execveat, File::open("/system/bin/").unwrap().into_raw_fd(),
++ execve_test_factory!(test_execveat_relative, execveat,
++ File::open("/system/bin/").unwrap().into_raw_fd(),
+ "./sh", AtFlags::empty());
+- execve_test_factory!(test_execveat_absolute, execveat, File::open("/").unwrap().into_raw_fd(),
++ execve_test_factory!(test_execveat_absolute, execveat,
++ File::open("/").unwrap().into_raw_fd(),
+ "/system/bin/sh", AtFlags::empty());
+- } else if #[cfg(all(target_os = "linux"), any(target_arch ="x86_64", target_arch ="x86"))] {
++ } else if #[cfg(all(target_os = "linux", any(target_arch ="x86_64", target_arch ="x86")))] {
+ use nix::fcntl::AtFlags;
+ execve_test_factory!(test_execveat_empty, execveat, File::open("/bin/sh").unwrap().into_raw_fd(),
+ "", AtFlags::AT_EMPTY_PATH);
+@@ -273,11 +406,12 @@ cfg_if!{
+ }
+
+ #[test]
++#[cfg(not(target_os = "fuchsia"))]
+ fn test_fchdir() {
+ // fchdir changes the process's cwd
+- let _dr = ::DirRestore::new();
++ let _dr = crate::DirRestore::new();
+
+- let tmpdir = tempfile::tempdir().unwrap();
++ let tmpdir = tempdir().unwrap();
+ let tmpdir_path = tmpdir.path().canonicalize().unwrap();
+ let tmpdir_fd = File::open(&tmpdir_path).unwrap().into_raw_fd();
+
+@@ -290,9 +424,9 @@ fn test_fchdir() {
+ #[test]
+ fn test_getcwd() {
+ // chdir changes the process's cwd
+- let _dr = ::DirRestore::new();
++ let _dr = crate::DirRestore::new();
+
+- let tmpdir = tempfile::tempdir().unwrap();
++ let tmpdir = tempdir().unwrap();
+ let tmpdir_path = tmpdir.path().canonicalize().unwrap();
+ assert!(chdir(&tmpdir_path).is_ok());
+ assert_eq!(getcwd().unwrap(), tmpdir_path);
+@@ -317,7 +451,7 @@ fn test_chown() {
+ let uid = Some(getuid());
+ let gid = Some(getgid());
+
+- let tempdir = tempfile::tempdir().unwrap();
++ let tempdir = tempdir().unwrap();
+ let path = tempdir.path().join("file");
+ {
+ File::create(&path).unwrap();
+@@ -332,13 +466,29 @@ fn test_chown() {
+ }
+
+ #[test]
++fn test_fchown() {
++ // Testing for anything other than our own UID/GID is hard.
++ let uid = Some(getuid());
++ let gid = Some(getgid());
++
++ let path = tempfile().unwrap();
++ let fd = path.as_raw_fd();
++
++ fchown(fd, uid, gid).unwrap();
++ fchown(fd, uid, None).unwrap();
++ fchown(fd, None, gid).unwrap();
++ fchown(999999999, uid, gid).unwrap_err();
++}
++
++#[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_fchownat() {
+- let _dr = ::DirRestore::new();
++ let _dr = crate::DirRestore::new();
+ // Testing for anything other than our own UID/GID is hard.
+ let uid = Some(getuid());
+ let gid = Some(getgid());
+
+- let tempdir = tempfile::tempdir().unwrap();
++ let tempdir = tempdir().unwrap();
+ let path = tempdir.path().join("file");
+ {
+ File::create(&path).unwrap();
+@@ -366,7 +516,7 @@ fn test_lseek() {
+ lseek(tmpfd, offset, Whence::SeekSet).unwrap();
+
+ let mut buf = [0u8; 7];
+- ::read_exact(tmpfd, &mut buf);
++ crate::read_exact(tmpfd, &mut buf);
+ assert_eq!(b"f123456", &buf);
+
+ close(tmpfd).unwrap();
+@@ -383,7 +533,7 @@ fn test_lseek64() {
+ lseek64(tmpfd, 5, Whence::SeekSet).unwrap();
+
+ let mut buf = [0u8; 7];
+- ::read_exact(tmpfd, &mut buf);
++ crate::read_exact(tmpfd, &mut buf);
+ assert_eq!(b"f123456", &buf);
+
+ close(tmpfd).unwrap();
+@@ -403,7 +553,7 @@ cfg_if!{
+ skip_if_jailed!("test_acct");
+ }
+ }
+- } else {
++ } else if #[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] {
+ macro_rules! require_acct{
+ () => {
+ skip_if_not_root!("test_acct");
+@@ -413,12 +563,13 @@ cfg_if!{
+ }
+
+ #[test]
++#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
+ fn test_acct() {
+ use tempfile::NamedTempFile;
+ use std::process::Command;
+ use std::{thread, time};
+
+- let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++ let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test");
+ require_acct!();
+
+ let file = NamedTempFile::new().unwrap();
+@@ -481,6 +632,14 @@ fn test_pipe() {
+
+ // pipe2(2) is the same as pipe(2), except it allows setting some flags. Check
+ // that we can set a flag.
++#[cfg(any(target_os = "android",
++ target_os = "dragonfly",
++ target_os = "emscripten",
++ target_os = "freebsd",
++ target_os = "linux",
++ target_os = "netbsd",
++ target_os = "openbsd",
++ target_os = "redox"))]
+ #[test]
+ fn test_pipe2() {
+ let (fd0, fd1) = pipe2(OFlag::O_CLOEXEC).unwrap();
+@@ -491,8 +650,9 @@ fn test_pipe2() {
+ }
+
+ #[test]
++#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
+ fn test_truncate() {
+- let tempdir = tempfile::tempdir().unwrap();
++ let tempdir = tempdir().unwrap();
+ let path = tempdir.path().join("file");
+
+ {
+@@ -509,7 +669,7 @@ fn test_truncate() {
+
+ #[test]
+ fn test_ftruncate() {
+- let tempdir = tempfile::tempdir().unwrap();
++ let tempdir = tempdir().unwrap();
+ let path = tempdir.path().join("file");
+
+ let tmpfd = {
+@@ -527,17 +687,26 @@ fn test_ftruncate() {
+ }
+
+ // Used in `test_alarm`.
++#[cfg(not(target_os = "redox"))]
+ static mut ALARM_CALLED: bool = false;
+
+ // Used in `test_alarm`.
++#[cfg(not(target_os = "redox"))]
+ pub extern fn alarm_signal_handler(raw_signal: libc::c_int) {
+ assert_eq!(raw_signal, libc::SIGALRM, "unexpected signal: {}", raw_signal);
+ unsafe { ALARM_CALLED = true };
+ }
+
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_alarm() {
+- let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
++ use std::{
++ time::{Duration, Instant,},
++ thread
++ };
++
++ // Maybe other tests that fork interfere with this one?
++ let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
+
+ let handler = SigHandler::Handler(alarm_signal_handler);
+ let signal_action = SigAction::new(handler, SaFlags::SA_RESTART, SigSet::empty());
+@@ -554,8 +723,16 @@ fn test_alarm() {
+
+ // We should be woken up after 1 second by the alarm, so we'll sleep for 2
+ // seconds to be sure.
+- sleep(2);
+- assert_eq!(unsafe { ALARM_CALLED }, true, "expected our alarm signal handler to be called");
++ let starttime = Instant::now();
++ loop {
++ thread::sleep(Duration::from_millis(100));
++ if unsafe { ALARM_CALLED} {
++ break;
++ }
++ if starttime.elapsed() > Duration::from_secs(3) {
++ panic!("Timeout waiting for SIGALRM");
++ }
++ }
+
+ // Reset the signal.
+ unsafe {
+@@ -565,8 +742,9 @@ fn test_alarm() {
+ }
+
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_canceling_alarm() {
+- let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
++ let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
+
+ assert_eq!(alarm::cancel(), None);
+
+@@ -575,15 +753,17 @@ fn test_canceling_alarm() {
+ }
+
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_symlinkat() {
+- let mut buf = [0; 1024];
+- let tempdir = tempfile::tempdir().unwrap();
++ let _m = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test");
++
++ let tempdir = tempdir().unwrap();
+
+ let target = tempdir.path().join("a");
+ let linkpath = tempdir.path().join("b");
+ symlinkat(&target, None, &linkpath).unwrap();
+ assert_eq!(
+- readlink(&linkpath, &mut buf).unwrap().to_str().unwrap(),
++ readlink(&linkpath).unwrap().to_str().unwrap(),
+ target.to_str().unwrap()
+ );
+
+@@ -592,7 +772,7 @@ fn test_symlinkat() {
+ let linkpath = "d";
+ symlinkat(target, Some(dirfd), linkpath).unwrap();
+ assert_eq!(
+- readlink(&tempdir.path().join(linkpath), &mut buf)
++ readlink(&tempdir.path().join(linkpath))
+ .unwrap()
+ .to_str()
+ .unwrap(),
+@@ -600,10 +780,154 @@ fn test_symlinkat() {
+ );
+ }
+
++#[test]
++#[cfg(not(target_os = "redox"))]
++fn test_linkat_file() {
++ let tempdir = tempdir().unwrap();
++ let oldfilename = "foo.txt";
++ let oldfilepath = tempdir.path().join(oldfilename);
++
++ let newfilename = "bar.txt";
++ let newfilepath = tempdir.path().join(newfilename);
++
++ // Create file
++ File::create(&oldfilepath).unwrap();
++
++ // Get file descriptor for base directory
++ let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap();
++
++ // Attempt hard link file at relative path
++ linkat(Some(dirfd), oldfilename, Some(dirfd), newfilename, LinkatFlags::SymlinkFollow).unwrap();
++ assert!(newfilepath.exists());
++}
++
++#[test]
++#[cfg(not(target_os = "redox"))]
++fn test_linkat_olddirfd_none() {
++ let _dr = crate::DirRestore::new();
++
++ let tempdir_oldfile = tempdir().unwrap();
++ let oldfilename = "foo.txt";
++ let oldfilepath = tempdir_oldfile.path().join(oldfilename);
++
++ let tempdir_newfile = tempdir().unwrap();
++ let newfilename = "bar.txt";
++ let newfilepath = tempdir_newfile.path().join(newfilename);
++
++ // Create file
++ File::create(&oldfilepath).unwrap();
++
++ // Get file descriptor for base directory of new file
++ let dirfd = fcntl::open(tempdir_newfile.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap();
++
++ // Attempt hard link file using curent working directory as relative path for old file path
++ chdir(tempdir_oldfile.path()).unwrap();
++ linkat(None, oldfilename, Some(dirfd), newfilename, LinkatFlags::SymlinkFollow).unwrap();
++ assert!(newfilepath.exists());
++}
++
++#[test]
++#[cfg(not(target_os = "redox"))]
++fn test_linkat_newdirfd_none() {
++ let _dr = crate::DirRestore::new();
++
++ let tempdir_oldfile = tempdir().unwrap();
++ let oldfilename = "foo.txt";
++ let oldfilepath = tempdir_oldfile.path().join(oldfilename);
++
++ let tempdir_newfile = tempdir().unwrap();
++ let newfilename = "bar.txt";
++ let newfilepath = tempdir_newfile.path().join(newfilename);
++
++ // Create file
++ File::create(&oldfilepath).unwrap();
++
++ // Get file descriptor for base directory of old file
++ let dirfd = fcntl::open(tempdir_oldfile.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap();
++
++ // Attempt hard link file using current working directory as relative path for new file path
++ chdir(tempdir_newfile.path()).unwrap();
++ linkat(Some(dirfd), oldfilename, None, newfilename, LinkatFlags::SymlinkFollow).unwrap();
++ assert!(newfilepath.exists());
++}
++
++#[test]
++#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox")))]
++fn test_linkat_no_follow_symlink() {
++ let _m = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test");
++
++ let tempdir = tempdir().unwrap();
++ let oldfilename = "foo.txt";
++ let oldfilepath = tempdir.path().join(oldfilename);
++
++ let symoldfilename = "symfoo.txt";
++ let symoldfilepath = tempdir.path().join(symoldfilename);
++
++ let newfilename = "nofollowsymbar.txt";
++ let newfilepath = tempdir.path().join(newfilename);
++
++ // Create file
++ File::create(&oldfilepath).unwrap();
++
++ // Create symlink to file
++ symlinkat(&oldfilepath, None, &symoldfilepath).unwrap();
++
++ // Get file descriptor for base directory
++ let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap();
++
++ // Attempt link symlink of file at relative path
++ linkat(Some(dirfd), symoldfilename, Some(dirfd), newfilename, LinkatFlags::NoSymlinkFollow).unwrap();
++
++ // Assert newfile is actually a symlink to oldfile.
++ assert_eq!(
++ readlink(&newfilepath)
++ .unwrap()
++ .to_str()
++ .unwrap(),
++ oldfilepath.to_str().unwrap()
++ );
++}
++
++#[test]
++#[cfg(not(target_os = "redox"))]
++fn test_linkat_follow_symlink() {
++ let _m = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test");
++
++ let tempdir = tempdir().unwrap();
++ let oldfilename = "foo.txt";
++ let oldfilepath = tempdir.path().join(oldfilename);
++
++ let symoldfilename = "symfoo.txt";
++ let symoldfilepath = tempdir.path().join(symoldfilename);
++
++ let newfilename = "nofollowsymbar.txt";
++ let newfilepath = tempdir.path().join(newfilename);
++
++ // Create file
++ File::create(&oldfilepath).unwrap();
++
++ // Create symlink to file
++ symlinkat(&oldfilepath, None, &symoldfilepath).unwrap();
++
++ // Get file descriptor for base directory
++ let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap();
++
++ // Attempt link target of symlink of file at relative path
++ linkat(Some(dirfd), symoldfilename, Some(dirfd), newfilename, LinkatFlags::SymlinkFollow).unwrap();
++
++ let newfilestat = stat::stat(&newfilepath).unwrap();
++
++ // Check the file type of the new link
++ assert!((stat::SFlag::from_bits_truncate(newfilestat.st_mode) & SFlag::S_IFMT) == SFlag::S_IFREG);
++
++ // Check the number of hard links to the original file
++ assert_eq!(newfilestat.st_nlink, 2);
++}
+
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_unlinkat_dir_noremovedir() {
+- let tempdir = tempfile::tempdir().unwrap();
++ let tempdir = tempdir().unwrap();
+ let dirname = "foo_dir";
+ let dirpath = tempdir.path().join(dirname);
+
+@@ -619,8 +943,9 @@ fn test_unlinkat_dir_noremovedir() {
+ }
+
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_unlinkat_dir_removedir() {
+- let tempdir = tempfile::tempdir().unwrap();
++ let tempdir = tempdir().unwrap();
+ let dirname = "foo_dir";
+ let dirpath = tempdir.path().join(dirname);
+
+@@ -636,8 +961,9 @@ fn test_unlinkat_dir_removedir() {
+ }
+
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_unlinkat_file() {
+- let tempdir = tempfile::tempdir().unwrap();
++ let tempdir = tempdir().unwrap();
+ let filename = "foo.txt";
+ let filepath = tempdir.path().join(filename);
+
+@@ -654,7 +980,7 @@ fn test_unlinkat_file() {
+
+ #[test]
+ fn test_access_not_existing() {
+- let tempdir = tempfile::tempdir().unwrap();
++ let tempdir = tempdir().unwrap();
+ let dir = tempdir.path().join("does_not_exist.txt");
+ assert_eq!(access(&dir, AccessFlags::F_OK).err().unwrap().as_errno().unwrap(),
+ Errno::ENOENT);
+@@ -662,8 +988,123 @@ fn test_access_not_existing() {
+
+ #[test]
+ fn test_access_file_exists() {
+- let tempdir = tempfile::tempdir().unwrap();
++ let tempdir = tempdir().unwrap();
+ let path = tempdir.path().join("does_exist.txt");
+ let _file = File::create(path.clone()).unwrap();
+ assert!(access(&path, AccessFlags::R_OK | AccessFlags::W_OK).is_ok());
+ }
++
++/// Tests setting the filesystem UID with `setfsuid`.
++#[cfg(any(target_os = "linux", target_os = "android"))]
++#[test]
++fn test_setfsuid() {
++ use std::os::unix::fs::PermissionsExt;
++ use std::{fs, io, thread};
++ require_capability!(CAP_SETUID);
++
++ // get the UID of the "nobody" user
++ let nobody = User::from_name("nobody").unwrap().unwrap();
++
++ // create a temporary file with permissions '-rw-r-----'
++ let file = tempfile::NamedTempFile::new_in("/var/tmp").unwrap();
++ let temp_path = file.into_temp_path();
++ dbg!(&temp_path);
++ let temp_path_2 = (&temp_path).to_path_buf();
++ let mut permissions = fs::metadata(&temp_path).unwrap().permissions();
++ permissions.set_mode(640);
++
++ // spawn a new thread where to test setfsuid
++ thread::spawn(move || {
++ // set filesystem UID
++ let fuid = setfsuid(nobody.uid);
++ // trying to open the temporary file should fail with EACCES
++ let res = fs::File::open(&temp_path);
++ assert!(res.is_err());
++ assert_eq!(res.err().unwrap().kind(), io::ErrorKind::PermissionDenied);
++
++ // assert fuid actually changes
++ let prev_fuid = setfsuid(Uid::from_raw(-1i32 as u32));
++ assert_ne!(prev_fuid, fuid);
++ })
++ .join()
++ .unwrap();
++
++ // open the temporary file with the current thread filesystem UID
++ fs::File::open(temp_path_2).unwrap();
++}
++
++#[test]
++#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
++fn test_ttyname() {
++ let fd = posix_openpt(OFlag::O_RDWR).expect("posix_openpt failed");
++ assert!(fd.as_raw_fd() > 0);
++
++ // on linux, we can just call ttyname on the pty master directly, but
++ // apparently osx requires that ttyname is called on a slave pty (can't
++ // find this documented anywhere, but it seems to empirically be the case)
++ grantpt(&fd).expect("grantpt failed");
++ unlockpt(&fd).expect("unlockpt failed");
++ let sname = unsafe { ptsname(&fd) }.expect("ptsname failed");
++ let fds = open(
++ Path::new(&sname),
++ OFlag::O_RDWR,
++ stat::Mode::empty(),
++ ).expect("open failed");
++ assert!(fds > 0);
++
++ let name = ttyname(fds).expect("ttyname failed");
++ assert!(name.starts_with("/dev"));
++}
++
++#[test]
++#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
++fn test_ttyname_not_pty() {
++ let fd = File::open("/dev/zero").unwrap();
++ assert!(fd.as_raw_fd() > 0);
++ assert_eq!(ttyname(fd.as_raw_fd()), Err(Error::Sys(Errno::ENOTTY)));
++}
++
++#[test]
++#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
++fn test_ttyname_invalid_fd() {
++ assert_eq!(ttyname(-1), Err(Error::Sys(Errno::EBADF)));
++}
++
++#[test]
++#[cfg(any(
++ target_os = "macos",
++ target_os = "ios",
++ target_os = "freebsd",
++ target_os = "openbsd",
++ target_os = "netbsd",
++ target_os = "dragonfly",
++))]
++fn test_getpeereid() {
++ use std::os::unix::net::UnixStream;
++ let (sock_a, sock_b) = UnixStream::pair().unwrap();
++
++ let (uid_a, gid_a) = getpeereid(sock_a.as_raw_fd()).unwrap();
++ let (uid_b, gid_b) = getpeereid(sock_b.as_raw_fd()).unwrap();
++
++ let uid = geteuid();
++ let gid = getegid();
++
++ assert_eq!(uid, uid_a);
++ assert_eq!(gid, gid_a);
++ assert_eq!(uid_a, uid_b);
++ assert_eq!(gid_a, gid_b);
++}
++
++#[test]
++#[cfg(any(
++ target_os = "macos",
++ target_os = "ios",
++ target_os = "freebsd",
++ target_os = "openbsd",
++ target_os = "netbsd",
++ target_os = "dragonfly",
++))]
++fn test_getpeereid_invalid_fd() {
++ // getpeereid is not POSIX, so error codes are inconsistent between different Unices.
++ assert!(getpeereid(-1).is_err());
++}
diff --git a/www-client/firefox/firefox-98.0.2.ebuild b/www-client/firefox/firefox-98.0.2.ebuild
index 4b45248..7eee8fb 100644
--- a/www-client/firefox/firefox-98.0.2.ebuild
+++ b/www-client/firefox/firefox-98.0.2.ebuild
@@ -51,6 +51,8 @@ PATCH_URIS=(
https://dev.gentoo.org/~{juippis,polynomial-c,whissi,slashbeast}/mozilla/patchsets/${FIREFOX_PATCHSET}
)
+PATCHES=${FILESDIR}/makotokato-riscv64-support-and-zenithal-backported.patch
+
SRC_URI="${MOZ_SRC_BASE_URI}/source/${MOZ_P}.source.tar.xz -> ${MOZ_P_DISTFILES}.source.tar.xz
${PATCH_URIS[@]}"
@@ -725,7 +727,7 @@ src_configure() {
# For future keywording: This is currently (97.0) only supported on:
# amd64, arm, arm64 & x86.
# Might want to flip the logic around if Firefox is to support more arches.
- if use ppc64; then
+ if use ppc64 || use riscv; then
mozconfig_add_options_ac '' --disable-sandbox
else
mozconfig_add_options_ac '' --enable-sandbox