diff options
author | Yu Gu <guyu2876@gmail.com> | 2022-04-20 21:11:25 +0800 |
---|---|---|
committer | Yixun Lan <dlan@gentoo.org> | 2022-04-20 21:22:29 +0800 |
commit | 07c4b52e96d933d680ba43f71849bae09abd41f2 (patch) | |
tree | 4188501340620bfdf521812e3aa910f741d9127d | |
parent | www-client/firefox: import ebuild from gentoo's official tree (diff) | |
download | riscv-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.patch | 47126 | ||||
-rw-r--r-- | www-client/firefox/firefox-98.0.2.ebuild | 4 |
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>(), ++ ®s as *const _ as *const c_void) ++ }; ++ Errno::result(res).map(drop) ++} ++ ++/// Function for ptrace requests that return values from the data field. ++/// Some ptrace get requests populate structs or larger elements than `c_long` ++/// and therefore use the data field to return values. This function handles these ++/// requests. ++fn ptrace_get_data<T>(request: Request, pid: Pid) -> Result<T> { ++ // Creates an uninitialized pointer to store result in ++ let data: T = unsafe { mem::uninitialized() }; ++ let res = unsafe { ++ libc::ptrace(request as RequestType, ++ libc::pid_t::from(pid), ++ ptr::null_mut::<T>(), ++ &data as *const _ as *const c_void) ++ }; ++ Errno::result(res)?; ++ Ok(data) ++} ++ ++unsafe fn ptrace_other(request: Request, pid: Pid, addr: AddressType, data: *mut c_void) -> Result<c_long> { ++ Errno::result(libc::ptrace(request as RequestType, libc::pid_t::from(pid), addr, data)).map(|_| 0) ++} ++ ++/// Set options, as with `ptrace(PTRACE_SETOPTIONS,...)`. ++pub fn setoptions(pid: Pid, options: Options) -> Result<()> { ++ let res = unsafe { ++ libc::ptrace(Request::PTRACE_SETOPTIONS as RequestType, ++ libc::pid_t::from(pid), ++ ptr::null_mut::<c_void>(), ++ options.bits() as *mut c_void) ++ }; ++ Errno::result(res).map(drop) ++} ++ ++/// Gets a ptrace event as described by `ptrace(PTRACE_GETEVENTMSG,...)` ++pub fn getevent(pid: Pid) -> Result<c_long> { ++ ptrace_get_data::<c_long>(Request::PTRACE_GETEVENTMSG, pid) ++} ++ ++/// Get siginfo as with `ptrace(PTRACE_GETSIGINFO,...)` ++pub fn getsiginfo(pid: Pid) -> Result<siginfo_t> { ++ ptrace_get_data::<siginfo_t>(Request::PTRACE_GETSIGINFO, pid) ++} ++ ++/// Set siginfo as with `ptrace(PTRACE_SETSIGINFO,...)` ++pub fn setsiginfo(pid: Pid, sig: &siginfo_t) -> Result<()> { ++ let ret = unsafe{ ++ Errno::clear(); ++ libc::ptrace(Request::PTRACE_SETSIGINFO as RequestType, ++ libc::pid_t::from(pid), ++ ptr::null_mut::<c_void>(), ++ sig as *const _ as *const c_void) ++ }; ++ match Errno::result(ret) { ++ Ok(_) => Ok(()), ++ Err(e) => Err(e), ++ } ++} ++ ++/// Sets the process as traceable, as with `ptrace(PTRACE_TRACEME, ...)` ++/// ++/// Indicates that this process is to be traced by its parent. ++/// This is the only ptrace request to be issued by the tracee. ++pub fn traceme() -> Result<()> { ++ unsafe { ++ ptrace_other( ++ Request::PTRACE_TRACEME, ++ Pid::from_raw(0), ++ ptr::null_mut(), ++ ptr::null_mut(), ++ ).map(drop) // ignore the useless return value ++ } ++} ++ ++/// Ask for next syscall, as with `ptrace(PTRACE_SYSCALL, ...)` ++/// ++/// Arranges for the tracee to be stopped at the next entry to or exit from a system call. ++pub fn syscall(pid: Pid) -> Result<()> { ++ unsafe { ++ ptrace_other( ++ Request::PTRACE_SYSCALL, ++ pid, ++ ptr::null_mut(), ++ ptr::null_mut(), ++ ).map(drop) // ignore the useless return value ++ } ++} ++ ++/// Attach to a running process, as with `ptrace(PTRACE_ATTACH, ...)` ++/// ++/// Attaches to the process specified in pid, making it a tracee of the calling process. ++pub fn attach(pid: Pid) -> Result<()> { ++ unsafe { ++ ptrace_other( ++ Request::PTRACE_ATTACH, ++ pid, ++ ptr::null_mut(), ++ ptr::null_mut(), ++ ).map(drop) // ignore the useless return value ++ } ++} ++ ++/// Detaches the current running process, as with `ptrace(PTRACE_DETACH, ...)` ++/// ++/// Detaches from the process specified in pid allowing it to run freely ++pub fn detach(pid: Pid) -> Result<()> { ++ unsafe { ++ ptrace_other( ++ Request::PTRACE_DETACH, ++ pid, ++ ptr::null_mut(), ++ ptr::null_mut() ++ ).map(drop) ++ } ++} ++ ++/// Restart the stopped tracee process, as with `ptrace(PTRACE_CONT, ...)` ++/// ++/// Continues the execution of the process with PID `pid`, optionally ++/// delivering a signal specified by `sig`. ++pub fn cont<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { ++ let data = match sig.into() { ++ Some(s) => s as i32 as *mut c_void, ++ None => ptr::null_mut(), ++ }; ++ unsafe { ++ ptrace_other(Request::PTRACE_CONT, pid, ptr::null_mut(), data).map(drop) // ignore the useless return value ++ } ++} ++ ++/// Issues a kill request as with `ptrace(PTRACE_KILL, ...)` ++/// ++/// This request is equivalent to `ptrace(PTRACE_CONT, ..., SIGKILL);` ++pub fn kill(pid: Pid) -> Result<()> { ++ unsafe { ++ ptrace_other(Request::PTRACE_KILL, pid, ptr::null_mut(), ptr::null_mut()).map(drop) ++ } ++} ++ ++/// Move the stopped tracee process forward by a single step as with ++/// `ptrace(PTRACE_SINGLESTEP, ...)` ++/// ++/// Advances the execution of the process with PID `pid` by a single step optionally delivering a ++/// signal specified by `sig`. ++/// ++/// # Example ++/// ```rust ++/// extern crate nix; ++/// use nix::sys::ptrace::step; ++/// use nix::unistd::Pid; ++/// use nix::sys::signal::Signal; ++/// use nix::sys::wait::*; ++/// fn main() { ++/// // If a process changes state to the stopped state because of a SIGUSR1 ++/// // signal, this will step the process forward and forward the user ++/// // signal to the stopped process ++/// match waitpid(Pid::from_raw(-1), None) { ++/// Ok(WaitStatus::Stopped(pid, Signal::SIGUSR1)) => { ++/// let _ = step(pid, Signal::SIGUSR1); ++/// } ++/// _ => {}, ++/// } ++/// } ++/// ``` ++pub fn step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { ++ let data = match sig.into() { ++ Some(s) => s as i32 as *mut c_void, ++ None => ptr::null_mut(), ++ }; ++ unsafe { ++ ptrace_other(Request::PTRACE_SINGLESTEP, pid, ptr::null_mut(), data).map(drop) ++ } ++} ++ ++ ++/// Reads a word from a processes memory at the given address ++pub fn read(pid: Pid, addr: AddressType) -> Result<c_long> { ++ ptrace_peek(Request::PTRACE_PEEKDATA, pid, addr, ptr::null_mut()) ++} ++ ++/// Writes a word into the processes memory at the given address ++pub fn write(pid: Pid, addr: AddressType, data: *mut c_void) -> Result<()> { ++ unsafe { ++ ptrace_other(Request::PTRACE_POKEDATA, pid, addr, data).map(drop) ++ } ++} +diff --git a/third_party/rust/nix-0.15.0/src/sys/ptrace/mod.rs b/third_party/rust/nix-0.15.0/src/sys/ptrace/mod.rs +new file mode 100644 +index 0000000000000..782c30409bc12 +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/src/sys/ptrace/mod.rs +@@ -0,0 +1,22 @@ ++///! Provides helpers for making ptrace system calls ++ ++#[cfg(any(target_os = "android", target_os = "linux"))] ++mod linux; ++ ++#[cfg(any(target_os = "android", target_os = "linux"))] ++pub use self::linux::*; ++ ++#[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++mod bsd; ++ ++#[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd" ++ ))] ++pub use self::bsd::*; +diff --git a/third_party/rust/nix-0.15.0/src/sys/quota.rs b/third_party/rust/nix-0.15.0/src/sys/quota.rs +new file mode 100644 +index 0000000000000..8946fca2213c8 +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/src/sys/quota.rs +@@ -0,0 +1,273 @@ ++//! Set and configure disk quotas for users, groups, or projects. ++//! ++//! # Examples ++//! ++//! Enabling and setting a quota: ++//! ++//! ```rust,no_run ++//! # use nix::sys::quota::{Dqblk, quotactl_on, quotactl_set, QuotaFmt, QuotaType, QuotaValidFlags}; ++//! quotactl_on(QuotaType::USRQUOTA, "/dev/sda1", QuotaFmt::QFMT_VFS_V1, "aquota.user"); ++//! let mut dqblk: Dqblk = Default::default(); ++//! dqblk.set_blocks_hard_limit(10000); ++//! dqblk.set_blocks_soft_limit(8000); ++//! quotactl_set(QuotaType::USRQUOTA, "/dev/sda1", 50, &dqblk, QuotaValidFlags::QIF_BLIMITS); ++//! ``` ++use std::default::Default; ++use std::{mem, ptr}; ++use libc::{self, c_int, c_char}; ++use {Result, NixPath}; ++use errno::Errno; ++ ++struct QuotaCmd(QuotaSubCmd, QuotaType); ++ ++impl QuotaCmd { ++ fn as_int(&self) -> c_int { ++ unsafe { libc::QCMD(self.0 as i32, self.1 as i32) } ++ } ++} ++ ++// linux quota version >= 2 ++libc_enum!{ ++ #[repr(i32)] ++ enum QuotaSubCmd { ++ Q_SYNC, ++ Q_QUOTAON, ++ Q_QUOTAOFF, ++ Q_GETQUOTA, ++ Q_SETQUOTA, ++ } ++} ++ ++libc_enum!{ ++ /// The scope of the quota. ++ #[repr(i32)] ++ pub enum QuotaType { ++ /// Specify a user quota ++ USRQUOTA, ++ /// Specify a group quota ++ GRPQUOTA, ++ } ++} ++ ++libc_enum!{ ++ /// The type of quota format to use. ++ #[repr(i32)] ++ pub enum QuotaFmt { ++ /// Use the original quota format. ++ QFMT_VFS_OLD, ++ /// Use the standard VFS v0 quota format. ++ /// ++ /// Handles 32-bit UIDs/GIDs and quota limits up to 2<sup>32</sup> bytes/2<sup>32</sup> inodes. ++ QFMT_VFS_V0, ++ /// Use the VFS v1 quota format. ++ /// ++ /// Handles 32-bit UIDs/GIDs and quota limits of 2<sup>64</sup> bytes/2<sup>64</sup> inodes. ++ QFMT_VFS_V1, ++ } ++} ++ ++libc_bitflags!( ++ /// Indicates the quota fields that are valid to read from. ++ #[derive(Default)] ++ pub struct QuotaValidFlags: u32 { ++ /// The block hard & soft limit fields. ++ QIF_BLIMITS; ++ /// The current space field. ++ QIF_SPACE; ++ /// The inode hard & soft limit fields. ++ QIF_ILIMITS; ++ /// The current inodes field. ++ QIF_INODES; ++ /// The disk use time limit field. ++ QIF_BTIME; ++ /// The file quote time limit field. ++ QIF_ITIME; ++ /// All block & inode limits. ++ QIF_LIMITS; ++ /// The space & inodes usage fields. ++ QIF_USAGE; ++ /// The time limit fields. ++ QIF_TIMES; ++ /// All fields. ++ QIF_ALL; ++ } ++); ++ ++/// Wrapper type for `if_dqblk` ++// FIXME: Change to repr(transparent) ++#[repr(C)] ++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] ++pub struct Dqblk(libc::dqblk); ++ ++impl Default for Dqblk { ++ fn default() -> Dqblk { ++ Dqblk(libc::dqblk { ++ dqb_bhardlimit: 0, ++ dqb_bsoftlimit: 0, ++ dqb_curspace: 0, ++ dqb_ihardlimit: 0, ++ dqb_isoftlimit: 0, ++ dqb_curinodes: 0, ++ dqb_btime: 0, ++ dqb_itime: 0, ++ dqb_valid: 0, ++ }) ++ } ++} ++ ++impl Dqblk { ++ /// The absolute limit on disk quota blocks allocated. ++ pub fn blocks_hard_limit(&self) -> Option<u64> { ++ let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); ++ if valid_fields.contains(QuotaValidFlags::QIF_BLIMITS) { ++ Some(self.0.dqb_bhardlimit) ++ } else { ++ None ++ } ++ } ++ ++ /// Set the absolute limit on disk quota blocks allocated. ++ pub fn set_blocks_hard_limit(&mut self, limit: u64) { ++ self.0.dqb_bhardlimit = limit; ++ } ++ ++ /// Preferred limit on disk quota blocks ++ pub fn blocks_soft_limit(&self) -> Option<u64> { ++ let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); ++ if valid_fields.contains(QuotaValidFlags::QIF_BLIMITS) { ++ Some(self.0.dqb_bsoftlimit) ++ } else { ++ None ++ } ++ } ++ ++ /// Set the preferred limit on disk quota blocks allocated. ++ pub fn set_blocks_soft_limit(&mut self, limit: u64) { ++ self.0.dqb_bsoftlimit = limit; ++ } ++ ++ /// Current occupied space (bytes). ++ pub fn occupied_space(&self) -> Option<u64> { ++ let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); ++ if valid_fields.contains(QuotaValidFlags::QIF_SPACE) { ++ Some(self.0.dqb_curspace) ++ } else { ++ None ++ } ++ } ++ ++ /// Maximum number of allocated inodes. ++ pub fn inodes_hard_limit(&self) -> Option<u64> { ++ let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); ++ if valid_fields.contains(QuotaValidFlags::QIF_ILIMITS) { ++ Some(self.0.dqb_ihardlimit) ++ } else { ++ None ++ } ++ } ++ ++ /// Set the maximum number of allocated inodes. ++ pub fn set_inodes_hard_limit(&mut self, limit: u64) { ++ self.0.dqb_ihardlimit = limit; ++ } ++ ++ /// Preferred inode limit ++ pub fn inodes_soft_limit(&self) -> Option<u64> { ++ let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); ++ if valid_fields.contains(QuotaValidFlags::QIF_ILIMITS) { ++ Some(self.0.dqb_isoftlimit) ++ } else { ++ None ++ } ++ } ++ ++ /// Set the preferred limit of allocated inodes. ++ pub fn set_inodes_soft_limit(&mut self, limit: u64) { ++ self.0.dqb_isoftlimit = limit; ++ } ++ ++ /// Current number of allocated inodes. ++ pub fn allocated_inodes(&self) -> Option<u64> { ++ let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); ++ if valid_fields.contains(QuotaValidFlags::QIF_INODES) { ++ Some(self.0.dqb_curinodes) ++ } else { ++ None ++ } ++ } ++ ++ /// Time limit for excessive disk use. ++ pub fn block_time_limit(&self) -> Option<u64> { ++ let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); ++ if valid_fields.contains(QuotaValidFlags::QIF_BTIME) { ++ Some(self.0.dqb_btime) ++ } else { ++ None ++ } ++ } ++ ++ /// Set the time limit for excessive disk use. ++ pub fn set_block_time_limit(&mut self, limit: u64) { ++ self.0.dqb_btime = limit; ++ } ++ ++ /// Time limit for excessive files. ++ pub fn inode_time_limit(&self) -> Option<u64> { ++ let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); ++ if valid_fields.contains(QuotaValidFlags::QIF_ITIME) { ++ Some(self.0.dqb_itime) ++ } else { ++ None ++ } ++ } ++ ++ /// Set the time limit for excessive files. ++ pub fn set_inode_time_limit(&mut self, limit: u64) { ++ self.0.dqb_itime = limit; ++ } ++} ++ ++fn quotactl<P: ?Sized + NixPath>(cmd: QuotaCmd, special: Option<&P>, id: c_int, addr: *mut c_char) -> Result<()> { ++ unsafe { ++ Errno::clear(); ++ let res = match special { ++ Some(dev) => dev.with_nix_path(|path| libc::quotactl(cmd.as_int(), path.as_ptr(), id, addr)), ++ None => Ok(libc::quotactl(cmd.as_int(), ptr::null(), id, addr)), ++ }?; ++ ++ Errno::result(res).map(drop) ++ } ++} ++ ++/// Turn on disk quotas for a block device. ++pub fn quotactl_on<P: ?Sized + NixPath>(which: QuotaType, special: &P, format: QuotaFmt, quota_file: &P) -> Result<()> { ++ quota_file.with_nix_path(|path| { ++ let mut path_copy = path.to_bytes_with_nul().to_owned(); ++ let p: *mut c_char = path_copy.as_mut_ptr() as *mut c_char; ++ quotactl(QuotaCmd(QuotaSubCmd::Q_QUOTAON, which), Some(special), format as c_int, p) ++ })? ++} ++ ++/// Disable disk quotas for a block device. ++pub fn quotactl_off<P: ?Sized + NixPath>(which: QuotaType, special: &P) -> Result<()> { ++ quotactl(QuotaCmd(QuotaSubCmd::Q_QUOTAOFF, which), Some(special), 0, ptr::null_mut()) ++} ++ ++/// Update the on-disk copy of quota usages for a filesystem. ++pub fn quotactl_sync<P: ?Sized + NixPath>(which: QuotaType, special: Option<&P>) -> Result<()> { ++ quotactl(QuotaCmd(QuotaSubCmd::Q_SYNC, which), special, 0, ptr::null_mut()) ++} ++ ++/// Get disk quota limits and current usage for the given user/group id. ++pub fn quotactl_get<P: ?Sized + NixPath>(which: QuotaType, special: &P, id: c_int) -> Result<Dqblk> { ++ let mut dqblk = unsafe { mem::uninitialized() }; ++ quotactl(QuotaCmd(QuotaSubCmd::Q_GETQUOTA, which), Some(special), id, &mut dqblk as *mut _ as *mut c_char)?; ++ dqblk ++} ++ ++/// Configure quota values for the specified fields for a given user/group id. ++pub fn quotactl_set<P: ?Sized + NixPath>(which: QuotaType, special: &P, id: c_int, dqblk: &Dqblk, fields: QuotaValidFlags) -> Result<()> { ++ let mut dqblk_copy = *dqblk; ++ dqblk_copy.0.dqb_valid = fields.bits(); ++ quotactl(QuotaCmd(QuotaSubCmd::Q_SETQUOTA, which), Some(special), id, &mut dqblk_copy as *mut _ as *mut c_char) ++} +diff --git a/third_party/rust/nix-0.15.0/src/sys/reboot.rs b/third_party/rust/nix-0.15.0/src/sys/reboot.rs +new file mode 100644 +index 0000000000000..bafa8fc11996d +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/src/sys/reboot.rs +@@ -0,0 +1,45 @@ ++//! Reboot/shutdown or enable/disable Ctrl-Alt-Delete. ++ ++use {Error, Result}; ++use errno::Errno; ++use libc; ++use void::Void; ++use std::mem::drop; ++ ++libc_enum! { ++ /// How exactly should the system be rebooted. ++ /// ++ /// See [`set_cad_enabled()`](fn.set_cad_enabled.html) for ++ /// enabling/disabling Ctrl-Alt-Delete. ++ #[repr(i32)] ++ pub enum RebootMode { ++ RB_HALT_SYSTEM, ++ RB_KEXEC, ++ RB_POWER_OFF, ++ RB_AUTOBOOT, ++ // we do not support Restart2, ++ RB_SW_SUSPEND, ++ } ++} ++ ++pub fn reboot(how: RebootMode) -> Result<Void> { ++ unsafe { ++ libc::reboot(how as libc::c_int) ++ }; ++ Err(Error::Sys(Errno::last())) ++} ++ ++/// Enable or disable the reboot keystroke (Ctrl-Alt-Delete). ++/// ++/// Corresponds to calling `reboot(RB_ENABLE_CAD)` or `reboot(RB_DISABLE_CAD)` in C. ++pub fn set_cad_enabled(enable: bool) -> Result<()> { ++ let cmd = if enable { ++ libc::RB_ENABLE_CAD ++ } else { ++ libc::RB_DISABLE_CAD ++ }; ++ let res = unsafe { ++ libc::reboot(cmd) ++ }; ++ Errno::result(res).map(drop) ++} +diff --git a/third_party/rust/nix-0.15.0/src/sys/select.rs b/third_party/rust/nix-0.15.0/src/sys/select.rs +new file mode 100644 +index 0000000000000..1b518e29f67a6 +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/src/sys/select.rs +@@ -0,0 +1,334 @@ ++use std::mem; ++use std::os::unix::io::RawFd; ++use std::ptr::{null, null_mut}; ++use libc::{self, c_int}; ++use Result; ++use errno::Errno; ++use sys::signal::SigSet; ++use sys::time::{TimeSpec, TimeVal}; ++ ++pub use libc::FD_SETSIZE; ++ ++// FIXME: Change to repr(transparent) once it's stable ++#[repr(C)] ++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] ++pub struct FdSet(libc::fd_set); ++ ++impl FdSet { ++ pub fn new() -> FdSet { ++ let mut fdset = unsafe { mem::uninitialized() }; ++ unsafe { libc::FD_ZERO(&mut fdset) }; ++ FdSet(fdset) ++ } ++ ++ pub fn insert(&mut self, fd: RawFd) { ++ unsafe { libc::FD_SET(fd, &mut self.0) }; ++ } ++ ++ pub fn remove(&mut self, fd: RawFd) { ++ unsafe { libc::FD_CLR(fd, &mut self.0) }; ++ } ++ ++ pub fn contains(&mut self, fd: RawFd) -> bool { ++ unsafe { libc::FD_ISSET(fd, &mut self.0) } ++ } ++ ++ pub fn clear(&mut self) { ++ unsafe { libc::FD_ZERO(&mut self.0) }; ++ } ++ ++ /// Finds the highest file descriptor in the set. ++ /// ++ /// Returns `None` if the set is empty. ++ /// ++ /// This can be used to calculate the `nfds` parameter of the [`select`] function. ++ /// ++ /// # Example ++ /// ++ /// ``` ++ /// # extern crate nix; ++ /// # use nix::sys::select::FdSet; ++ /// # fn main() { ++ /// let mut set = FdSet::new(); ++ /// set.insert(4); ++ /// set.insert(9); ++ /// assert_eq!(set.highest(), Some(9)); ++ /// # } ++ /// ``` ++ /// ++ /// [`select`]: fn.select.html ++ pub fn highest(&mut self) -> Option<RawFd> { ++ for i in (0..FD_SETSIZE).rev() { ++ let i = i as RawFd; ++ if unsafe { libc::FD_ISSET(i, self as *mut _ as *mut libc::fd_set) } { ++ return Some(i) ++ } ++ } ++ ++ None ++ } ++} ++ ++/// Monitors file descriptors for readiness ++/// ++/// Returns the total number of ready file descriptors in all sets. The sets are changed so that all ++/// file descriptors that are ready for the given operation are set. ++/// ++/// When this function returns, `timeout` has an implementation-defined value. ++/// ++/// # Parameters ++/// ++/// * `nfds`: The highest file descriptor set in any of the passed `FdSet`s, plus 1. If `None`, this ++/// is calculated automatically by calling [`FdSet::highest`] on all descriptor sets and adding 1 ++/// to the maximum of that. ++/// * `readfds`: File descriptors to check for being ready to read. ++/// * `writefds`: File descriptors to check for being ready to write. ++/// * `errorfds`: File descriptors to check for pending error conditions. ++/// * `timeout`: Maximum time to wait for descriptors to become ready (`None` to block ++/// indefinitely). ++/// ++/// # References ++/// ++/// [select(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/select.html) ++/// ++/// [`FdSet::highest`]: struct.FdSet.html#method.highest ++pub fn select<'a, N, R, W, E, T>(nfds: N, ++ readfds: R, ++ writefds: W, ++ errorfds: E, ++ timeout: T) -> Result<c_int> ++where ++ N: Into<Option<c_int>>, ++ R: Into<Option<&'a mut FdSet>>, ++ W: Into<Option<&'a mut FdSet>>, ++ E: Into<Option<&'a mut FdSet>>, ++ T: Into<Option<&'a mut TimeVal>>, ++{ ++ let mut readfds = readfds.into(); ++ let mut writefds = writefds.into(); ++ let mut errorfds = errorfds.into(); ++ let timeout = timeout.into(); ++ ++ let nfds = nfds.into().unwrap_or_else(|| { ++ readfds.iter_mut() ++ .chain(writefds.iter_mut()) ++ .chain(errorfds.iter_mut()) ++ .map(|set| set.highest().unwrap_or(-1)) ++ .max() ++ .unwrap_or(-1) + 1 ++ }); ++ ++ let readfds = readfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut()); ++ let writefds = writefds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut()); ++ let errorfds = errorfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut()); ++ let timeout = timeout.map(|tv| tv as *mut _ as *mut libc::timeval) ++ .unwrap_or(null_mut()); ++ ++ let res = unsafe { ++ libc::select(nfds, readfds, writefds, errorfds, timeout) ++ }; ++ ++ Errno::result(res) ++} ++ ++/// Monitors file descriptors for readiness with an altered signal mask. ++/// ++/// Returns the total number of ready file descriptors in all sets. The sets are changed so that all ++/// file descriptors that are ready for the given operation are set. ++/// ++/// When this function returns, the original signal mask is restored. ++/// ++/// Unlike [`select`](#fn.select), `pselect` does not mutate the `timeout` value. ++/// ++/// # Parameters ++/// ++/// * `nfds`: The highest file descriptor set in any of the passed `FdSet`s, plus 1. If `None`, this ++/// is calculated automatically by calling [`FdSet::highest`] on all descriptor sets and adding 1 ++/// to the maximum of that. ++/// * `readfds`: File descriptors to check for read readiness ++/// * `writefds`: File descriptors to check for write readiness ++/// * `errorfds`: File descriptors to check for pending error conditions. ++/// * `timeout`: Maximum time to wait for descriptors to become ready (`None` to block ++/// indefinitely). ++/// * `sigmask`: Signal mask to activate while waiting for file descriptors to turn ++/// ready (`None` to set no alternative signal mask). ++/// ++/// # References ++/// ++/// [pselect(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pselect.html) ++/// ++/// [The new pselect() system call](https://lwn.net/Articles/176911/) ++/// ++/// [`FdSet::highest`]: struct.FdSet.html#method.highest ++pub fn pselect<'a, N, R, W, E, T, S>(nfds: N, ++ readfds: R, ++ writefds: W, ++ errorfds: E, ++ timeout: T, ++ sigmask: S) -> Result<c_int> ++where ++ N: Into<Option<c_int>>, ++ R: Into<Option<&'a mut FdSet>>, ++ W: Into<Option<&'a mut FdSet>>, ++ E: Into<Option<&'a mut FdSet>>, ++ T: Into<Option<&'a TimeSpec>>, ++ S: Into<Option<&'a SigSet>>, ++{ ++ let mut readfds = readfds.into(); ++ let mut writefds = writefds.into(); ++ let mut errorfds = errorfds.into(); ++ let sigmask = sigmask.into(); ++ let timeout = timeout.into(); ++ ++ let nfds = nfds.into().unwrap_or_else(|| { ++ readfds.iter_mut() ++ .chain(writefds.iter_mut()) ++ .chain(errorfds.iter_mut()) ++ .map(|set| set.highest().unwrap_or(-1)) ++ .max() ++ .unwrap_or(-1) + 1 ++ }); ++ ++ let readfds = readfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut()); ++ let writefds = writefds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut()); ++ let errorfds = errorfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut()); ++ let timeout = timeout.map(|ts| ts.as_ref() as *const libc::timespec).unwrap_or(null()); ++ let sigmask = sigmask.map(|sm| sm.as_ref() as *const libc::sigset_t).unwrap_or(null()); ++ ++ let res = unsafe { ++ libc::pselect(nfds, readfds, writefds, errorfds, timeout, sigmask) ++ }; ++ ++ Errno::result(res) ++} ++ ++ ++#[cfg(test)] ++mod tests { ++ use super::*; ++ use std::os::unix::io::RawFd; ++ use sys::time::{TimeVal, TimeValLike}; ++ use unistd::{write, pipe}; ++ ++ #[test] ++ fn fdset_insert() { ++ let mut fd_set = FdSet::new(); ++ ++ for i in 0..FD_SETSIZE { ++ assert!(!fd_set.contains(i as RawFd)); ++ } ++ ++ fd_set.insert(7); ++ ++ assert!(fd_set.contains(7)); ++ } ++ ++ #[test] ++ fn fdset_remove() { ++ let mut fd_set = FdSet::new(); ++ ++ for i in 0..FD_SETSIZE { ++ assert!(!fd_set.contains(i as RawFd)); ++ } ++ ++ fd_set.insert(7); ++ fd_set.remove(7); ++ ++ for i in 0..FD_SETSIZE { ++ assert!(!fd_set.contains(i as RawFd)); ++ } ++ } ++ ++ #[test] ++ fn fdset_clear() { ++ let mut fd_set = FdSet::new(); ++ fd_set.insert(1); ++ fd_set.insert((FD_SETSIZE / 2) as RawFd); ++ fd_set.insert((FD_SETSIZE - 1) as RawFd); ++ ++ fd_set.clear(); ++ ++ for i in 0..FD_SETSIZE { ++ assert!(!fd_set.contains(i as RawFd)); ++ } ++ } ++ ++ #[test] ++ fn fdset_highest() { ++ let mut set = FdSet::new(); ++ assert_eq!(set.highest(), None); ++ set.insert(0); ++ assert_eq!(set.highest(), Some(0)); ++ set.insert(90); ++ assert_eq!(set.highest(), Some(90)); ++ set.remove(0); ++ assert_eq!(set.highest(), Some(90)); ++ set.remove(90); ++ assert_eq!(set.highest(), None); ++ ++ set.insert(4); ++ set.insert(5); ++ set.insert(7); ++ assert_eq!(set.highest(), Some(7)); ++ } ++ ++ #[test] ++ fn test_select() { ++ let (r1, w1) = pipe().unwrap(); ++ write(w1, b"hi!").unwrap(); ++ let (r2, _w2) = pipe().unwrap(); ++ ++ let mut fd_set = FdSet::new(); ++ fd_set.insert(r1); ++ fd_set.insert(r2); ++ ++ let mut timeout = TimeVal::seconds(10); ++ assert_eq!(1, select(None, ++ &mut fd_set, ++ None, ++ None, ++ &mut timeout).unwrap()); ++ assert!(fd_set.contains(r1)); ++ assert!(!fd_set.contains(r2)); ++ } ++ ++ #[test] ++ fn test_select_nfds() { ++ let (r1, w1) = pipe().unwrap(); ++ write(w1, b"hi!").unwrap(); ++ let (r2, _w2) = pipe().unwrap(); ++ ++ let mut fd_set = FdSet::new(); ++ fd_set.insert(r1); ++ fd_set.insert(r2); ++ ++ let mut timeout = TimeVal::seconds(10); ++ assert_eq!(1, select(Some(fd_set.highest().unwrap() + 1), ++ &mut fd_set, ++ None, ++ None, ++ &mut timeout).unwrap()); ++ assert!(fd_set.contains(r1)); ++ assert!(!fd_set.contains(r2)); ++ } ++ ++ #[test] ++ fn test_select_nfds2() { ++ let (r1, w1) = pipe().unwrap(); ++ write(w1, b"hi!").unwrap(); ++ let (r2, _w2) = pipe().unwrap(); ++ ++ let mut fd_set = FdSet::new(); ++ fd_set.insert(r1); ++ fd_set.insert(r2); ++ ++ let mut timeout = TimeVal::seconds(10); ++ assert_eq!(1, select(::std::cmp::max(r1, r2) + 1, ++ &mut fd_set, ++ None, ++ None, ++ &mut timeout).unwrap()); ++ assert!(fd_set.contains(r1)); ++ assert!(!fd_set.contains(r2)); ++ } ++} +diff --git a/third_party/rust/nix-0.15.0/src/sys/sendfile.rs b/third_party/rust/nix-0.15.0/src/sys/sendfile.rs +new file mode 100644 +index 0000000000000..a47d8962f73fb +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/src/sys/sendfile.rs +@@ -0,0 +1,200 @@ ++use std::os::unix::io::RawFd; ++use std::ptr; ++ ++use libc::{self, off_t}; ++ ++use Result; ++use errno::Errno; ++ ++/// Copy up to `count` bytes to `out_fd` from `in_fd` starting at `offset`. ++/// ++/// Returns a `Result` with the number of bytes written. ++/// ++/// If `offset` is `None`, `sendfile` will begin reading at the current offset of `in_fd`and will ++/// update the offset of `in_fd`. If `offset` is `Some`, `sendfile` will begin at the specified ++/// offset and will not update the offset of `in_fd`. Instead, it will mutate `offset` to point to ++/// the byte after the last byte copied. ++/// ++/// `in_fd` must support `mmap`-like operations and therefore cannot be a socket. ++/// ++/// For more information, see [the sendfile(2) man page.](http://man7.org/linux/man-pages/man2/sendfile.2.html) ++#[cfg(any(target_os = "android", target_os = "linux"))] ++pub fn sendfile( ++ out_fd: RawFd, ++ in_fd: RawFd, ++ offset: Option<&mut off_t>, ++ count: usize, ++) -> Result<usize> { ++ let offset = offset ++ .map(|offset| offset as *mut _) ++ .unwrap_or(ptr::null_mut()); ++ let ret = unsafe { libc::sendfile(out_fd, in_fd, offset, count) }; ++ Errno::result(ret).map(|r| r as usize) ++} ++ ++cfg_if! { ++ if #[cfg(any(target_os = "freebsd", ++ target_os = "ios", ++ target_os = "macos"))] { ++ use sys::uio::IoVec; ++ ++ #[derive(Clone, Debug, Eq, Hash, PartialEq)] ++ struct SendfileHeaderTrailer<'a>( ++ libc::sf_hdtr, ++ Option<Vec<IoVec<&'a [u8]>>>, ++ Option<Vec<IoVec<&'a [u8]>>>, ++ ); ++ ++ impl<'a> SendfileHeaderTrailer<'a> { ++ fn new( ++ headers: Option<&'a [&'a [u8]]>, ++ trailers: Option<&'a [&'a [u8]]> ++ ) -> SendfileHeaderTrailer<'a> { ++ let header_iovecs: Option<Vec<IoVec<&[u8]>>> = ++ headers.map(|s| s.iter().map(|b| IoVec::from_slice(b)).collect()); ++ let trailer_iovecs: Option<Vec<IoVec<&[u8]>>> = ++ trailers.map(|s| s.iter().map(|b| IoVec::from_slice(b)).collect()); ++ SendfileHeaderTrailer( ++ libc::sf_hdtr { ++ headers: { ++ header_iovecs ++ .as_ref() ++ .map_or(ptr::null(), |v| v.as_ptr()) as *mut libc::iovec ++ }, ++ hdr_cnt: header_iovecs.as_ref().map(|v| v.len()).unwrap_or(0) as i32, ++ trailers: { ++ trailer_iovecs ++ .as_ref() ++ .map_or(ptr::null(), |v| v.as_ptr()) as *mut libc::iovec ++ }, ++ trl_cnt: trailer_iovecs.as_ref().map(|v| v.len()).unwrap_or(0) as i32 ++ }, ++ header_iovecs, ++ trailer_iovecs, ++ ) ++ } ++ } ++ } ++} ++ ++cfg_if! { ++ if #[cfg(target_os = "freebsd")] { ++ use libc::c_int; ++ ++ libc_bitflags!{ ++ /// Configuration options for [`sendfile`.](fn.sendfile.html) ++ pub struct SfFlags: c_int { ++ /// Causes `sendfile` to return EBUSY instead of blocking when attempting to read a ++ /// busy page. ++ SF_NODISKIO; ++ /// Causes `sendfile` to sleep until the network stack releases its reference to the ++ /// VM pages read. When `sendfile` returns, the data is not guaranteed to have been ++ /// sent, but it is safe to modify the file. ++ SF_SYNC; ++ /// Causes `sendfile` to cache exactly the number of pages specified in the ++ /// `readahead` parameter, disabling caching heuristics. ++ SF_USER_READAHEAD; ++ /// Causes `sendfile` not to cache the data read. ++ SF_NOCACHE; ++ } ++ } ++ ++ /// Read up to `count` bytes from `in_fd` starting at `offset` and write to `out_sock`. ++ /// ++ /// Returns a `Result` and a count of bytes written. Bytes written may be non-zero even if ++ /// an error occurs. ++ /// ++ /// `in_fd` must describe a regular file or shared memory object. `out_sock` must describe a ++ /// stream socket. ++ /// ++ /// If `offset` falls past the end of the file, the function returns success and zero bytes ++ /// written. ++ /// ++ /// If `count` is `None` or 0, bytes will be read from `in_fd` until reaching the end of ++ /// file (EOF). ++ /// ++ /// `headers` and `trailers` specify optional slices of byte slices to be sent before and ++ /// after the data read from `in_fd`, respectively. The length of headers and trailers sent ++ /// is included in the returned count of bytes written. The values of `offset` and `count` ++ /// do not apply to headers or trailers. ++ /// ++ /// `readahead` specifies the minimum number of pages to cache in memory ahead of the page ++ /// currently being sent. ++ /// ++ /// For more information, see ++ /// [the sendfile(2) man page.](https://www.freebsd.org/cgi/man.cgi?query=sendfile&sektion=2) ++ pub fn sendfile( ++ in_fd: RawFd, ++ out_sock: RawFd, ++ offset: off_t, ++ count: Option<usize>, ++ headers: Option<&[&[u8]]>, ++ trailers: Option<&[&[u8]]>, ++ flags: SfFlags, ++ readahead: u16 ++ ) -> (Result<()>, off_t) { ++ // Readahead goes in upper 16 bits ++ // Flags goes in lower 16 bits ++ // see `man 2 sendfile` ++ let flags: u32 = ((readahead as u32) << 16) | (flags.bits() as u32); ++ let mut bytes_sent: off_t = 0; ++ let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers)); ++ let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr); ++ let return_code = unsafe { ++ libc::sendfile(in_fd, ++ out_sock, ++ offset, ++ count.unwrap_or(0), ++ hdtr_ptr as *mut libc::sf_hdtr, ++ &mut bytes_sent as *mut off_t, ++ flags as c_int) ++ }; ++ (Errno::result(return_code).and(Ok(())), bytes_sent) ++ } ++ } else if #[cfg(any(target_os = "ios", target_os = "macos"))] { ++ /// Read bytes from `in_fd` starting at `offset` and write up to `count` bytes to ++ /// `out_sock`. ++ /// ++ /// Returns a `Result` and a count of bytes written. Bytes written may be non-zero even if ++ /// an error occurs. ++ /// ++ /// `in_fd` must describe a regular file. `out_sock` must describe a stream socket. ++ /// ++ /// If `offset` falls past the end of the file, the function returns success and zero bytes ++ /// written. ++ /// ++ /// If `count` is `None` or 0, bytes will be read from `in_fd` until reaching the end of ++ /// file (EOF). ++ /// ++ /// `hdtr` specifies an optional list of headers and trailers to be sent before and after ++ /// the data read from `in_fd`, respectively. The length of headers and trailers sent is ++ /// included in the returned count of bytes written. If any headers are specified and ++ /// `count` is non-zero, the length of the headers will be counted in the limit of total ++ /// bytes sent. Trailers do not count toward the limit of bytes sent and will always be sent ++ /// regardless. The value of `offset` does not affect headers or trailers. ++ /// ++ /// For more information, see ++ /// [the sendfile(2) man page.](https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man2/sendfile.2.html) ++ pub fn sendfile( ++ in_fd: RawFd, ++ out_sock: RawFd, ++ offset: off_t, ++ count: Option<off_t>, ++ headers: Option<&[&[u8]]>, ++ trailers: Option<&[&[u8]]> ++ ) -> (Result<()>, off_t) { ++ let mut len = count.unwrap_or(0); ++ let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers)); ++ let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr); ++ let return_code = unsafe { ++ libc::sendfile(in_fd, ++ out_sock, ++ offset, ++ &mut len as *mut off_t, ++ hdtr_ptr as *mut libc::sf_hdtr, ++ 0) ++ }; ++ (Errno::result(return_code).and(Ok(())), len) ++ } ++ } ++} +diff --git a/third_party/rust/nix-0.15.0/src/sys/signal.rs b/third_party/rust/nix-0.15.0/src/sys/signal.rs +new file mode 100644 +index 0000000000000..1013a77fd4b40 +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/src/sys/signal.rs +@@ -0,0 +1,966 @@ ++// Portions of this file are Copyright 2014 The Rust Project Developers. ++// See http://rust-lang.org/COPYRIGHT. ++ ++///! Operating system signals. ++ ++use libc; ++use {Error, Result}; ++use errno::Errno; ++use std::mem; ++use std::fmt; ++use std::str::FromStr; ++#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] ++use std::os::unix::io::RawFd; ++use std::ptr; ++ ++#[cfg(not(target_os = "openbsd"))] ++pub use self::sigevent::*; ++ ++libc_enum!{ ++ // Currently there is only one definition of c_int in libc, as well as only one ++ // type for signal constants. ++ // We would prefer to use the libc::c_int alias in the repr attribute. Unfortunately ++ // this is not (yet) possible. ++ #[repr(i32)] ++ pub enum Signal { ++ SIGHUP, ++ SIGINT, ++ SIGQUIT, ++ SIGILL, ++ SIGTRAP, ++ SIGABRT, ++ SIGBUS, ++ SIGFPE, ++ SIGKILL, ++ SIGUSR1, ++ SIGSEGV, ++ SIGUSR2, ++ SIGPIPE, ++ SIGALRM, ++ SIGTERM, ++ #[cfg(all(any(target_os = "android", target_os = "emscripten", target_os = "linux"), ++ not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))] ++ SIGSTKFLT, ++ SIGCHLD, ++ SIGCONT, ++ SIGSTOP, ++ SIGTSTP, ++ SIGTTIN, ++ SIGTTOU, ++ SIGURG, ++ SIGXCPU, ++ SIGXFSZ, ++ SIGVTALRM, ++ SIGPROF, ++ SIGWINCH, ++ SIGIO, ++ #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))] ++ SIGPWR, ++ SIGSYS, ++ #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))] ++ SIGEMT, ++ #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))] ++ SIGINFO, ++ } ++} ++ ++impl FromStr for Signal { ++ type Err = Error; ++ fn from_str(s: &str) -> Result<Signal> { ++ Ok(match s { ++ "SIGHUP" => Signal::SIGHUP, ++ "SIGINT" => Signal::SIGINT, ++ "SIGQUIT" => Signal::SIGQUIT, ++ "SIGILL" => Signal::SIGILL, ++ "SIGTRAP" => Signal::SIGTRAP, ++ "SIGABRT" => Signal::SIGABRT, ++ "SIGBUS" => Signal::SIGBUS, ++ "SIGFPE" => Signal::SIGFPE, ++ "SIGKILL" => Signal::SIGKILL, ++ "SIGUSR1" => Signal::SIGUSR1, ++ "SIGSEGV" => Signal::SIGSEGV, ++ "SIGUSR2" => Signal::SIGUSR2, ++ "SIGPIPE" => Signal::SIGPIPE, ++ "SIGALRM" => Signal::SIGALRM, ++ "SIGTERM" => Signal::SIGTERM, ++ #[cfg(all(any(target_os = "android", target_os = "emscripten", target_os = "linux"), ++ not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))] ++ "SIGSTKFLT" => Signal::SIGSTKFLT, ++ "SIGCHLD" => Signal::SIGCHLD, ++ "SIGCONT" => Signal::SIGCONT, ++ "SIGSTOP" => Signal::SIGSTOP, ++ "SIGTSTP" => Signal::SIGTSTP, ++ "SIGTTIN" => Signal::SIGTTIN, ++ "SIGTTOU" => Signal::SIGTTOU, ++ "SIGURG" => Signal::SIGURG, ++ "SIGXCPU" => Signal::SIGXCPU, ++ "SIGXFSZ" => Signal::SIGXFSZ, ++ "SIGVTALRM" => Signal::SIGVTALRM, ++ "SIGPROF" => Signal::SIGPROF, ++ "SIGWINCH" => Signal::SIGWINCH, ++ "SIGIO" => Signal::SIGIO, ++ #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))] ++ "SIGPWR" => Signal::SIGPWR, ++ "SIGSYS" => Signal::SIGSYS, ++ #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))] ++ "SIGEMT" => Signal::SIGEMT, ++ #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))] ++ "SIGINFO" => Signal::SIGINFO, ++ _ => return Err(Error::invalid_argument()), ++ }) ++ } ++} ++ ++impl AsRef<str> for Signal { ++ fn as_ref(&self) -> &str { ++ match *self { ++ Signal::SIGHUP => "SIGHUP", ++ Signal::SIGINT => "SIGINT", ++ Signal::SIGQUIT => "SIGQUIT", ++ Signal::SIGILL => "SIGILL", ++ Signal::SIGTRAP => "SIGTRAP", ++ Signal::SIGABRT => "SIGABRT", ++ Signal::SIGBUS => "SIGBUS", ++ Signal::SIGFPE => "SIGFPE", ++ Signal::SIGKILL => "SIGKILL", ++ Signal::SIGUSR1 => "SIGUSR1", ++ Signal::SIGSEGV => "SIGSEGV", ++ Signal::SIGUSR2 => "SIGUSR2", ++ Signal::SIGPIPE => "SIGPIPE", ++ Signal::SIGALRM => "SIGALRM", ++ Signal::SIGTERM => "SIGTERM", ++ #[cfg(all(any(target_os = "android", target_os = "emscripten", target_os = "linux"), ++ not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))] ++ Signal::SIGSTKFLT => "SIGSTKFLT", ++ Signal::SIGCHLD => "SIGCHLD", ++ Signal::SIGCONT => "SIGCONT", ++ Signal::SIGSTOP => "SIGSTOP", ++ Signal::SIGTSTP => "SIGTSTP", ++ Signal::SIGTTIN => "SIGTTIN", ++ Signal::SIGTTOU => "SIGTTOU", ++ Signal::SIGURG => "SIGURG", ++ Signal::SIGXCPU => "SIGXCPU", ++ Signal::SIGXFSZ => "SIGXFSZ", ++ Signal::SIGVTALRM => "SIGVTALRM", ++ Signal::SIGPROF => "SIGPROF", ++ Signal::SIGWINCH => "SIGWINCH", ++ Signal::SIGIO => "SIGIO", ++ #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))] ++ Signal::SIGPWR => "SIGPWR", ++ Signal::SIGSYS => "SIGSYS", ++ #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))] ++ Signal::SIGEMT => "SIGEMT", ++ #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))] ++ Signal::SIGINFO => "SIGINFO", ++ } ++ } ++} ++ ++impl fmt::Display for Signal { ++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ++ f.write_str(self.as_ref()) ++ } ++} ++ ++pub use self::Signal::*; ++ ++#[cfg(all(any(target_os = "linux", target_os = "android", target_os = "emscripten"), not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))] ++const SIGNALS: [Signal; 31] = [ ++ SIGHUP, ++ SIGINT, ++ SIGQUIT, ++ SIGILL, ++ SIGTRAP, ++ SIGABRT, ++ SIGBUS, ++ SIGFPE, ++ SIGKILL, ++ SIGUSR1, ++ SIGSEGV, ++ SIGUSR2, ++ SIGPIPE, ++ SIGALRM, ++ SIGTERM, ++ SIGSTKFLT, ++ SIGCHLD, ++ SIGCONT, ++ SIGSTOP, ++ SIGTSTP, ++ SIGTTIN, ++ SIGTTOU, ++ SIGURG, ++ SIGXCPU, ++ SIGXFSZ, ++ SIGVTALRM, ++ SIGPROF, ++ SIGWINCH, ++ SIGIO, ++ SIGPWR, ++ SIGSYS]; ++#[cfg(all(any(target_os = "linux", target_os = "android", target_os = "emscripten"), any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64")))] ++const SIGNALS: [Signal; 30] = [ ++ SIGHUP, ++ SIGINT, ++ SIGQUIT, ++ SIGILL, ++ SIGTRAP, ++ SIGABRT, ++ SIGBUS, ++ SIGFPE, ++ SIGKILL, ++ SIGUSR1, ++ SIGSEGV, ++ SIGUSR2, ++ SIGPIPE, ++ SIGALRM, ++ SIGTERM, ++ SIGCHLD, ++ SIGCONT, ++ SIGSTOP, ++ SIGTSTP, ++ SIGTTIN, ++ SIGTTOU, ++ SIGURG, ++ SIGXCPU, ++ SIGXFSZ, ++ SIGVTALRM, ++ SIGPROF, ++ SIGWINCH, ++ SIGIO, ++ SIGPWR, ++ SIGSYS]; ++#[cfg(not(any(target_os = "linux", target_os = "android", target_os = "emscripten")))] ++const SIGNALS: [Signal; 31] = [ ++ SIGHUP, ++ SIGINT, ++ SIGQUIT, ++ SIGILL, ++ SIGTRAP, ++ SIGABRT, ++ SIGBUS, ++ SIGFPE, ++ SIGKILL, ++ SIGUSR1, ++ SIGSEGV, ++ SIGUSR2, ++ SIGPIPE, ++ SIGALRM, ++ SIGTERM, ++ SIGCHLD, ++ SIGCONT, ++ SIGSTOP, ++ SIGTSTP, ++ SIGTTIN, ++ SIGTTOU, ++ SIGURG, ++ SIGXCPU, ++ SIGXFSZ, ++ SIGVTALRM, ++ SIGPROF, ++ SIGWINCH, ++ SIGIO, ++ SIGSYS, ++ SIGEMT, ++ SIGINFO]; ++ ++pub const NSIG: libc::c_int = 32; ++ ++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] ++pub struct SignalIterator { ++ next: usize, ++} ++ ++impl Iterator for SignalIterator { ++ type Item = Signal; ++ ++ fn next(&mut self) -> Option<Signal> { ++ if self.next < SIGNALS.len() { ++ let next_signal = SIGNALS[self.next]; ++ self.next += 1; ++ Some(next_signal) ++ } else { ++ None ++ } ++ } ++} ++ ++impl Signal { ++ pub fn iterator() -> SignalIterator { ++ SignalIterator{next: 0} ++ } ++ ++ // We do not implement the From trait, because it is supposed to be infallible. ++ // With Rust RFC 1542 comes the appropriate trait TryFrom. Once it is ++ // implemented, we'll replace this function. ++ #[inline] ++ pub fn from_c_int(signum: libc::c_int) -> Result<Signal> { ++ if 0 < signum && signum < NSIG { ++ Ok(unsafe { mem::transmute(signum) }) ++ } else { ++ Err(Error::invalid_argument()) ++ } ++ } ++} ++ ++pub const SIGIOT : Signal = SIGABRT; ++pub const SIGPOLL : Signal = SIGIO; ++pub const SIGUNUSED : Signal = SIGSYS; ++ ++libc_bitflags!{ ++ pub struct SaFlags: libc::c_int { ++ SA_NOCLDSTOP; ++ SA_NOCLDWAIT; ++ SA_NODEFER; ++ SA_ONSTACK; ++ SA_RESETHAND; ++ SA_RESTART; ++ SA_SIGINFO; ++ } ++} ++ ++libc_enum! { ++ #[repr(i32)] ++ pub enum SigmaskHow { ++ SIG_BLOCK, ++ SIG_UNBLOCK, ++ SIG_SETMASK, ++ } ++} ++ ++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] ++pub struct SigSet { ++ sigset: libc::sigset_t ++} ++ ++ ++impl SigSet { ++ pub fn all() -> SigSet { ++ let mut sigset: libc::sigset_t = unsafe { mem::uninitialized() }; ++ let _ = unsafe { libc::sigfillset(&mut sigset as *mut libc::sigset_t) }; ++ ++ SigSet { sigset: sigset } ++ } ++ ++ pub fn empty() -> SigSet { ++ let mut sigset: libc::sigset_t = unsafe { mem::uninitialized() }; ++ let _ = unsafe { libc::sigemptyset(&mut sigset as *mut libc::sigset_t) }; ++ ++ SigSet { sigset: sigset } ++ } ++ ++ pub fn add(&mut self, signal: Signal) { ++ unsafe { libc::sigaddset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) }; ++ } ++ ++ pub fn clear(&mut self) { ++ unsafe { libc::sigemptyset(&mut self.sigset as *mut libc::sigset_t) }; ++ } ++ ++ pub fn remove(&mut self, signal: Signal) { ++ unsafe { libc::sigdelset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) }; ++ } ++ ++ pub fn contains(&self, signal: Signal) -> bool { ++ let res = unsafe { libc::sigismember(&self.sigset as *const libc::sigset_t, signal as libc::c_int) }; ++ ++ match res { ++ 1 => true, ++ 0 => false, ++ _ => unreachable!("unexpected value from sigismember"), ++ } ++ } ++ ++ pub fn extend(&mut self, other: &SigSet) { ++ for signal in Signal::iterator() { ++ if other.contains(signal) { ++ self.add(signal); ++ } ++ } ++ } ++ ++ /// Gets the currently blocked (masked) set of signals for the calling thread. ++ pub fn thread_get_mask() -> Result<SigSet> { ++ let mut oldmask: SigSet = unsafe { mem::uninitialized() }; ++ pthread_sigmask(SigmaskHow::SIG_SETMASK, None, Some(&mut oldmask))?; ++ Ok(oldmask) ++ } ++ ++ /// Sets the set of signals as the signal mask for the calling thread. ++ pub fn thread_set_mask(&self) -> Result<()> { ++ pthread_sigmask(SigmaskHow::SIG_SETMASK, Some(self), None) ++ } ++ ++ /// Adds the set of signals to the signal mask for the calling thread. ++ pub fn thread_block(&self) -> Result<()> { ++ pthread_sigmask(SigmaskHow::SIG_BLOCK, Some(self), None) ++ } ++ ++ /// Removes the set of signals from the signal mask for the calling thread. ++ pub fn thread_unblock(&self) -> Result<()> { ++ pthread_sigmask(SigmaskHow::SIG_UNBLOCK, Some(self), None) ++ } ++ ++ /// Sets the set of signals as the signal mask, and returns the old mask. ++ pub fn thread_swap_mask(&self, how: SigmaskHow) -> Result<SigSet> { ++ let mut oldmask: SigSet = unsafe { mem::uninitialized() }; ++ pthread_sigmask(how, Some(self), Some(&mut oldmask))?; ++ Ok(oldmask) ++ } ++ ++ /// Suspends execution of the calling thread until one of the signals in the ++ /// signal mask becomes pending, and returns the accepted signal. ++ pub fn wait(&self) -> Result<Signal> { ++ let mut signum: libc::c_int = unsafe { mem::uninitialized() }; ++ let res = unsafe { libc::sigwait(&self.sigset as *const libc::sigset_t, &mut signum) }; ++ ++ Errno::result(res).map(|_| Signal::from_c_int(signum).unwrap()) ++ } ++} ++ ++impl AsRef<libc::sigset_t> for SigSet { ++ fn as_ref(&self) -> &libc::sigset_t { ++ &self.sigset ++ } ++} ++ ++/// A signal handler. ++#[allow(unknown_lints)] ++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] ++pub enum SigHandler { ++ /// Default signal handling. ++ SigDfl, ++ /// Request that the signal be ignored. ++ SigIgn, ++ /// Use the given signal-catching function, which takes in the signal. ++ Handler(extern fn(libc::c_int)), ++ /// Use the given signal-catching function, which takes in the signal, information about how ++ /// the signal was generated, and a pointer to the threads `ucontext_t`. ++ SigAction(extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void)) ++} ++ ++/// Action to take on receipt of a signal. Corresponds to `sigaction`. ++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] ++pub struct SigAction { ++ sigaction: libc::sigaction ++} ++ ++impl SigAction { ++ /// Creates a new action. ++ /// ++ /// The `SA_SIGINFO` bit in the `flags` argument is ignored (it will be set only if `handler` ++ /// is the `SigAction` variant). `mask` specifies other signals to block during execution of ++ /// the signal-catching function. ++ pub fn new(handler: SigHandler, flags: SaFlags, mask: SigSet) -> SigAction { ++ let mut s = unsafe { mem::uninitialized::<libc::sigaction>() }; ++ s.sa_sigaction = match handler { ++ SigHandler::SigDfl => libc::SIG_DFL, ++ SigHandler::SigIgn => libc::SIG_IGN, ++ SigHandler::Handler(f) => f as *const extern fn(libc::c_int) as usize, ++ SigHandler::SigAction(f) => f as *const extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void) as usize, ++ }; ++ s.sa_flags = match handler { ++ SigHandler::SigAction(_) => (flags | SaFlags::SA_SIGINFO).bits(), ++ _ => (flags - SaFlags::SA_SIGINFO).bits(), ++ }; ++ s.sa_mask = mask.sigset; ++ ++ SigAction { sigaction: s } ++ } ++ ++ /// Returns the flags set on the action. ++ pub fn flags(&self) -> SaFlags { ++ SaFlags::from_bits_truncate(self.sigaction.sa_flags) ++ } ++ ++ /// Returns the set of signals that are blocked during execution of the action's ++ /// signal-catching function. ++ pub fn mask(&self) -> SigSet { ++ SigSet { sigset: self.sigaction.sa_mask } ++ } ++ ++ /// Returns the action's handler. ++ pub fn handler(&self) -> SigHandler { ++ match self.sigaction.sa_sigaction { ++ libc::SIG_DFL => SigHandler::SigDfl, ++ libc::SIG_IGN => SigHandler::SigIgn, ++ f if self.flags().contains(SaFlags::SA_SIGINFO) => ++ SigHandler::SigAction( unsafe { mem::transmute(f) } ), ++ f => SigHandler::Handler( unsafe { mem::transmute(f) } ), ++ } ++ } ++} ++ ++/// Changes the action taken by a process on receipt of a specific signal. ++/// ++/// `signal` can be any signal except `SIGKILL` or `SIGSTOP`. On success, it returns the previous ++/// action for the given signal. If `sigaction` fails, no new signal handler is installed. ++/// ++/// # Safety ++/// ++/// Signal handlers may be called at any point during execution, which limits what is safe to do in ++/// the body of the signal-catching function. Be certain to only make syscalls that are explicitly ++/// marked safe for signal handlers and only share global data using atomics. ++pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigAction> { ++ let mut oldact = mem::uninitialized::<libc::sigaction>(); ++ ++ let res = ++ libc::sigaction(signal as libc::c_int, &sigaction.sigaction as *const libc::sigaction, &mut oldact as *mut libc::sigaction); ++ ++ Errno::result(res).map(|_| SigAction { sigaction: oldact }) ++} ++ ++/// Signal management (see [signal(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/signal.html)) ++/// ++/// Installs `handler` for the given `signal`, returning the previous signal ++/// handler. `signal` should only be used following another call to `signal` or ++/// if the current handler is the default. The return value of `signal` is ++/// undefined after setting the handler with [`sigaction`][SigActionFn]. ++/// ++/// # Safety ++/// ++/// If the pointer to the previous signal handler is invalid, undefined ++/// behavior could be invoked when casting it back to a [`SigAction`][SigActionStruct]. ++/// ++/// # Examples ++/// ++/// Ignore `SIGINT`: ++/// ++/// ```no_run ++/// # use nix::sys::signal::{self, Signal, SigHandler}; ++/// unsafe { signal::signal(Signal::SIGINT, SigHandler::SigIgn) }.unwrap(); ++/// ``` ++/// ++/// Use a signal handler to set a flag variable: ++/// ++/// ```no_run ++/// # #[macro_use] extern crate lazy_static; ++/// # extern crate libc; ++/// # extern crate nix; ++/// # use std::sync::atomic::{AtomicBool, Ordering}; ++/// # use nix::sys::signal::{self, Signal, SigHandler}; ++/// lazy_static! { ++/// static ref SIGNALED: AtomicBool = AtomicBool::new(false); ++/// } ++/// ++/// extern fn handle_sigint(signal: libc::c_int) { ++/// let signal = Signal::from_c_int(signal).unwrap(); ++/// SIGNALED.store(signal == Signal::SIGINT, Ordering::Relaxed); ++/// } ++/// ++/// fn main() { ++/// let handler = SigHandler::Handler(handle_sigint); ++/// unsafe { signal::signal(Signal::SIGINT, handler) }.unwrap(); ++/// } ++/// ``` ++/// ++/// # Errors ++/// ++/// Returns [`Error::UnsupportedOperation`] if `handler` is ++/// [`SigAction`][SigActionStruct]. Use [`sigaction`][SigActionFn] instead. ++/// ++/// `signal` also returns any error from `libc::signal`, such as when an attempt ++/// is made to catch a signal that cannot be caught or to ignore a signal that ++/// cannot be ignored. ++/// ++/// [`Error::UnsupportedOperation`]: ../../enum.Error.html#variant.UnsupportedOperation ++/// [SigActionStruct]: struct.SigAction.html ++/// [sigactionFn]: fn.sigaction.html ++pub unsafe fn signal(signal: Signal, handler: SigHandler) -> Result<SigHandler> { ++ let signal = signal as libc::c_int; ++ let res = match handler { ++ SigHandler::SigDfl => libc::signal(signal, libc::SIG_DFL), ++ SigHandler::SigIgn => libc::signal(signal, libc::SIG_IGN), ++ SigHandler::Handler(handler) => libc::signal(signal, handler as libc::sighandler_t), ++ SigHandler::SigAction(_) => return Err(Error::UnsupportedOperation), ++ }; ++ Errno::result(res).map(|oldhandler| { ++ match oldhandler { ++ libc::SIG_DFL => SigHandler::SigDfl, ++ libc::SIG_IGN => SigHandler::SigIgn, ++ f => SigHandler::Handler(mem::transmute(f)), ++ } ++ }) ++} ++ ++/// Manages the signal mask (set of blocked signals) for the calling thread. ++/// ++/// If the `set` parameter is `Some(..)`, then the signal mask will be updated with the signal set. ++/// The `how` flag decides the type of update. If `set` is `None`, `how` will be ignored, ++/// and no modification will take place. ++/// ++/// If the 'oldset' parameter is `Some(..)` then the current signal mask will be written into it. ++/// ++/// If both `set` and `oldset` is `Some(..)`, the current signal mask will be written into oldset, ++/// and then it will be updated with `set`. ++/// ++/// If both `set` and `oldset` is None, this function is a no-op. ++/// ++/// For more information, visit the [`pthread_sigmask`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_sigmask.html), ++/// or [`sigprocmask`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html) man pages. ++pub fn pthread_sigmask(how: SigmaskHow, ++ set: Option<&SigSet>, ++ oldset: Option<&mut SigSet>) -> Result<()> { ++ if set.is_none() && oldset.is_none() { ++ return Ok(()) ++ } ++ ++ let res = unsafe { ++ // if set or oldset is None, pass in null pointers instead ++ libc::pthread_sigmask(how as libc::c_int, ++ set.map_or_else(ptr::null::<libc::sigset_t>, ++ |s| &s.sigset as *const libc::sigset_t), ++ oldset.map_or_else(ptr::null_mut::<libc::sigset_t>, ++ |os| &mut os.sigset as *mut libc::sigset_t)) ++ }; ++ ++ Errno::result(res).map(drop) ++} ++ ++/// Examine and change blocked signals. ++/// ++/// For more informations see the [`sigprocmask` man ++/// pages](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html). ++pub fn sigprocmask(how: SigmaskHow, set: Option<&SigSet>, oldset: Option<&mut SigSet>) -> Result<()> { ++ if set.is_none() && oldset.is_none() { ++ return Ok(()) ++ } ++ ++ let res = unsafe { ++ // if set or oldset is None, pass in null pointers instead ++ libc::sigprocmask(how as libc::c_int, ++ set.map_or_else(ptr::null::<libc::sigset_t>, ++ |s| &s.sigset as *const libc::sigset_t), ++ oldset.map_or_else(ptr::null_mut::<libc::sigset_t>, ++ |os| &mut os.sigset as *mut libc::sigset_t)) ++ }; ++ ++ Errno::result(res).map(drop) ++} ++ ++pub fn kill<T: Into<Option<Signal>>>(pid: ::unistd::Pid, signal: T) -> Result<()> { ++ let res = unsafe { libc::kill(pid.into(), ++ match signal.into() { ++ Some(s) => s as libc::c_int, ++ None => 0, ++ }) }; ++ ++ Errno::result(res).map(drop) ++} ++ ++/// Send a signal to a process group [(see ++/// killpg(3))](http://pubs.opengroup.org/onlinepubs/9699919799/functions/killpg.html). ++/// ++/// If `pgrp` less then or equal 1, the behavior is platform-specific. ++/// If `signal` is `None`, `killpg` will only preform error checking and won't ++/// send any signal. ++pub fn killpg<T: Into<Option<Signal>>>(pgrp: ::unistd::Pid, signal: T) -> Result<()> { ++ let res = unsafe { libc::killpg(pgrp.into(), ++ match signal.into() { ++ Some(s) => s as libc::c_int, ++ None => 0, ++ }) }; ++ ++ Errno::result(res).map(drop) ++} ++ ++pub fn raise(signal: Signal) -> Result<()> { ++ let res = unsafe { libc::raise(signal as libc::c_int) }; ++ ++ Errno::result(res).map(drop) ++} ++ ++ ++#[cfg(target_os = "freebsd")] ++pub type type_of_thread_id = libc::lwpid_t; ++#[cfg(target_os = "linux")] ++pub type type_of_thread_id = libc::pid_t; ++ ++/// Used to request asynchronous notification of certain events, for example, ++/// with POSIX AIO, POSIX message queues, and POSIX timers. ++// sigval is actually a union of a int and a void*. But it's never really used ++// as a pointer, because neither libc nor the kernel ever dereference it. nix ++// therefore presents it as an intptr_t, which is how kevent uses it. ++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] ++pub enum SigevNotify { ++ /// No notification will be delivered ++ SigevNone, ++ /// The signal given by `signal` will be delivered to the process. The ++ /// value in `si_value` will be present in the `si_value` field of the ++ /// `siginfo_t` structure of the queued signal. ++ SigevSignal { signal: Signal, si_value: libc::intptr_t }, ++ // Note: SIGEV_THREAD is not implemented because libc::sigevent does not ++ // expose a way to set the union members needed by SIGEV_THREAD. ++ /// A new `kevent` is posted to the kqueue `kq`. The `kevent`'s `udata` ++ /// field will contain the value in `udata`. ++ #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] ++ SigevKevent { kq: RawFd, udata: libc::intptr_t }, ++ /// The signal `signal` is queued to the thread whose LWP ID is given in ++ /// `thread_id`. The value stored in `si_value` will be present in the ++ /// `si_value` of the `siginfo_t` structure of the queued signal. ++ #[cfg(any(target_os = "freebsd", target_os = "linux"))] ++ SigevThreadId { signal: Signal, thread_id: type_of_thread_id, ++ si_value: libc::intptr_t }, ++} ++ ++#[cfg(not(target_os = "openbsd"))] ++mod sigevent { ++ use libc; ++ use std::mem; ++ use std::ptr; ++ use super::SigevNotify; ++ #[cfg(any(target_os = "freebsd", target_os = "linux"))] ++ use super::type_of_thread_id; ++ ++ /// Used to request asynchronous notification of the completion of certain ++ /// events, such as POSIX AIO and timers. ++ #[repr(C)] ++ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] ++ pub struct SigEvent { ++ sigevent: libc::sigevent ++ } ++ ++ impl SigEvent { ++ /// **Note:** this constructor does not allow the user to set the ++ /// `sigev_notify_kevent_flags` field. That's considered ok because on FreeBSD ++ /// at least those flags don't do anything useful. That field is part of a ++ /// union that shares space with the more genuinely useful fields. ++ /// ++ /// **Note:** This constructor also doesn't allow the caller to set the ++ /// `sigev_notify_function` or `sigev_notify_attributes` fields, which are ++ /// required for `SIGEV_THREAD`. That's considered ok because on no operating ++ /// system is `SIGEV_THREAD` the most efficient way to deliver AIO ++ /// notification. FreeBSD and DragonFly BSD programs should prefer `SIGEV_KEVENT`. ++ /// Linux, Solaris, and portable programs should prefer `SIGEV_THREAD_ID` or ++ /// `SIGEV_SIGNAL`. That field is part of a union that shares space with the ++ /// more genuinely useful `sigev_notify_thread_id` ++ pub fn new(sigev_notify: SigevNotify) -> SigEvent { ++ let mut sev = unsafe { mem::zeroed::<libc::sigevent>()}; ++ sev.sigev_notify = match sigev_notify { ++ SigevNotify::SigevNone => libc::SIGEV_NONE, ++ SigevNotify::SigevSignal{..} => libc::SIGEV_SIGNAL, ++ #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] ++ SigevNotify::SigevKevent{..} => libc::SIGEV_KEVENT, ++ #[cfg(target_os = "freebsd")] ++ SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID, ++ #[cfg(all(target_os = "linux", target_env = "gnu", not(target_arch = "mips")))] ++ SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID, ++ #[cfg(any(all(target_os = "linux", target_env = "musl"), target_arch = "mips"))] ++ SigevNotify::SigevThreadId{..} => 4 // No SIGEV_THREAD_ID defined ++ }; ++ sev.sigev_signo = match sigev_notify { ++ SigevNotify::SigevSignal{ signal, .. } => signal as libc::c_int, ++ #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] ++ SigevNotify::SigevKevent{ kq, ..} => kq, ++ #[cfg(any(target_os = "linux", target_os = "freebsd"))] ++ SigevNotify::SigevThreadId{ signal, .. } => signal as libc::c_int, ++ _ => 0 ++ }; ++ sev.sigev_value.sival_ptr = match sigev_notify { ++ SigevNotify::SigevNone => ptr::null_mut::<libc::c_void>(), ++ SigevNotify::SigevSignal{ si_value, .. } => si_value as *mut libc::c_void, ++ #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] ++ SigevNotify::SigevKevent{ udata, .. } => udata as *mut libc::c_void, ++ #[cfg(any(target_os = "freebsd", target_os = "linux"))] ++ SigevNotify::SigevThreadId{ si_value, .. } => si_value as *mut libc::c_void, ++ }; ++ SigEvent::set_tid(&mut sev, &sigev_notify); ++ SigEvent{sigevent: sev} ++ } ++ ++ #[cfg(any(target_os = "freebsd", target_os = "linux"))] ++ fn set_tid(sev: &mut libc::sigevent, sigev_notify: &SigevNotify) { ++ sev.sigev_notify_thread_id = match *sigev_notify { ++ SigevNotify::SigevThreadId { thread_id, .. } => thread_id, ++ _ => 0 as type_of_thread_id ++ }; ++ } ++ ++ #[cfg(not(any(target_os = "freebsd", target_os = "linux")))] ++ fn set_tid(_sev: &mut libc::sigevent, _sigev_notify: &SigevNotify) { ++ } ++ ++ pub fn sigevent(&self) -> libc::sigevent { ++ self.sigevent ++ } ++ } ++ ++ impl<'a> From<&'a libc::sigevent> for SigEvent { ++ fn from(sigevent: &libc::sigevent) -> Self { ++ SigEvent{ sigevent: *sigevent } ++ } ++ } ++} ++ ++#[cfg(test)] ++mod tests { ++ use std::thread; ++ use super::*; ++ ++ #[test] ++ fn test_contains() { ++ let mut mask = SigSet::empty(); ++ mask.add(SIGUSR1); ++ ++ assert!(mask.contains(SIGUSR1)); ++ assert!(!mask.contains(SIGUSR2)); ++ ++ let all = SigSet::all(); ++ assert!(all.contains(SIGUSR1)); ++ assert!(all.contains(SIGUSR2)); ++ } ++ ++ #[test] ++ fn test_clear() { ++ let mut set = SigSet::all(); ++ set.clear(); ++ for signal in Signal::iterator() { ++ assert!(!set.contains(signal)); ++ } ++ } ++ ++ #[test] ++ fn test_from_str_round_trips() { ++ for signal in Signal::iterator() { ++ assert_eq!(signal.as_ref().parse::<Signal>().unwrap(), signal); ++ assert_eq!(signal.to_string().parse::<Signal>().unwrap(), signal); ++ } ++ } ++ ++ #[test] ++ fn test_from_str_invalid_value() { ++ let errval = Err(Error::Sys(Errno::EINVAL)); ++ assert_eq!("NOSIGNAL".parse::<Signal>(), errval); ++ assert_eq!("kill".parse::<Signal>(), errval); ++ assert_eq!("9".parse::<Signal>(), errval); ++ } ++ ++ #[test] ++ fn test_extend() { ++ let mut one_signal = SigSet::empty(); ++ one_signal.add(SIGUSR1); ++ ++ let mut two_signals = SigSet::empty(); ++ two_signals.add(SIGUSR2); ++ two_signals.extend(&one_signal); ++ ++ assert!(two_signals.contains(SIGUSR1)); ++ assert!(two_signals.contains(SIGUSR2)); ++ } ++ ++ #[test] ++ fn test_thread_signal_set_mask() { ++ thread::spawn(|| { ++ let prev_mask = SigSet::thread_get_mask() ++ .expect("Failed to get existing signal mask!"); ++ ++ let mut test_mask = prev_mask; ++ test_mask.add(SIGUSR1); ++ ++ assert!(test_mask.thread_set_mask().is_ok()); ++ let new_mask = SigSet::thread_get_mask() ++ .expect("Failed to get new mask!"); ++ ++ assert!(new_mask.contains(SIGUSR1)); ++ assert!(!new_mask.contains(SIGUSR2)); ++ ++ prev_mask.thread_set_mask().expect("Failed to revert signal mask!"); ++ }).join().unwrap(); ++ } ++ ++ #[test] ++ fn test_thread_signal_block() { ++ thread::spawn(|| { ++ let mut mask = SigSet::empty(); ++ mask.add(SIGUSR1); ++ ++ assert!(mask.thread_block().is_ok()); ++ ++ assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1)); ++ }).join().unwrap(); ++ } ++ ++ #[test] ++ fn test_thread_signal_unblock() { ++ thread::spawn(|| { ++ let mut mask = SigSet::empty(); ++ mask.add(SIGUSR1); ++ ++ assert!(mask.thread_unblock().is_ok()); ++ ++ assert!(!SigSet::thread_get_mask().unwrap().contains(SIGUSR1)); ++ }).join().unwrap(); ++ } ++ ++ #[test] ++ fn test_thread_signal_swap() { ++ thread::spawn(|| { ++ let mut mask = SigSet::empty(); ++ mask.add(SIGUSR1); ++ mask.thread_block().unwrap(); ++ ++ assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1)); ++ ++ let mut mask2 = SigSet::empty(); ++ mask2.add(SIGUSR2); ++ ++ let oldmask = mask2.thread_swap_mask(SigmaskHow::SIG_SETMASK) ++ .unwrap(); ++ ++ assert!(oldmask.contains(SIGUSR1)); ++ assert!(!oldmask.contains(SIGUSR2)); ++ ++ assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR2)); ++ }).join().unwrap(); ++ } ++ ++ #[test] ++ fn test_sigaction() { ++ use libc; ++ thread::spawn(|| { ++ extern fn test_sigaction_handler(_: libc::c_int) {} ++ extern fn test_sigaction_action(_: libc::c_int, ++ _: *mut libc::siginfo_t, _: *mut libc::c_void) {} ++ ++ let handler_sig = SigHandler::Handler(test_sigaction_handler); ++ ++ let flags = SaFlags::SA_ONSTACK | SaFlags::SA_RESTART | ++ SaFlags::SA_SIGINFO; ++ ++ let mut mask = SigSet::empty(); ++ mask.add(SIGUSR1); ++ ++ let action_sig = SigAction::new(handler_sig, flags, mask); ++ ++ assert_eq!(action_sig.flags(), ++ SaFlags::SA_ONSTACK | SaFlags::SA_RESTART); ++ assert_eq!(action_sig.handler(), handler_sig); ++ ++ mask = action_sig.mask(); ++ assert!(mask.contains(SIGUSR1)); ++ assert!(!mask.contains(SIGUSR2)); ++ ++ let handler_act = SigHandler::SigAction(test_sigaction_action); ++ let action_act = SigAction::new(handler_act, flags, mask); ++ assert_eq!(action_act.handler(), handler_act); ++ ++ let action_dfl = SigAction::new(SigHandler::SigDfl, flags, mask); ++ assert_eq!(action_dfl.handler(), SigHandler::SigDfl); ++ ++ let action_ign = SigAction::new(SigHandler::SigIgn, flags, mask); ++ assert_eq!(action_ign.handler(), SigHandler::SigIgn); ++ }).join().unwrap(); ++ } ++ ++ #[test] ++ fn test_sigwait() { ++ thread::spawn(|| { ++ let mut mask = SigSet::empty(); ++ mask.add(SIGUSR1); ++ mask.add(SIGUSR2); ++ mask.thread_block().unwrap(); ++ ++ raise(SIGUSR1).unwrap(); ++ assert_eq!(mask.wait().unwrap(), SIGUSR1); ++ }).join().unwrap(); ++ } ++} +diff --git a/third_party/rust/nix-0.15.0/src/sys/signalfd.rs b/third_party/rust/nix-0.15.0/src/sys/signalfd.rs +new file mode 100644 +index 0000000000000..5425a27be9e52 +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/src/sys/signalfd.rs +@@ -0,0 +1,170 @@ ++//! Interface for the `signalfd` syscall. ++//! ++//! # Signal discarding ++//! When a signal can't be delivered to a process (or thread), it will become a pending signal. ++//! Failure to deliver could happen if the signal is blocked by every thread in the process or if ++//! the signal handler is still handling a previous signal. ++//! ++//! If a signal is sent to a process (or thread) that already has a pending signal of the same ++//! type, it will be discarded. This means that if signals of the same type are received faster than ++//! they are processed, some of those signals will be dropped. Because of this limitation, ++//! `signalfd` in itself cannot be used for reliable communication between processes or threads. ++//! ++//! Once the signal is unblocked, or the signal handler is finished, and a signal is still pending ++//! (ie. not consumed from a signalfd) it will be delivered to the signal handler. ++//! ++//! Please note that signal discarding is not specific to `signalfd`, but also happens with regular ++//! signal handlers. ++use libc; ++use unistd; ++use {Error, Result}; ++use errno::Errno; ++pub use sys::signal::{self, SigSet}; ++pub use libc::signalfd_siginfo as siginfo; ++ ++use std::os::unix::io::{RawFd, AsRawFd}; ++use std::mem; ++ ++ ++libc_bitflags!{ ++ pub struct SfdFlags: libc::c_int { ++ SFD_NONBLOCK; ++ SFD_CLOEXEC; ++ } ++} ++ ++pub const SIGNALFD_NEW: RawFd = -1; ++pub const SIGNALFD_SIGINFO_SIZE: usize = 128; ++ ++/// Creates a new file descriptor for reading signals. ++/// ++/// **Important:** please read the module level documentation about signal discarding before using ++/// this function! ++/// ++/// The `mask` parameter specifies the set of signals that can be accepted via this file descriptor. ++/// ++/// A signal must be blocked on every thread in a process, otherwise it won't be visible from ++/// signalfd (the default handler will be invoked instead). ++/// ++/// See [the signalfd man page for more information](http://man7.org/linux/man-pages/man2/signalfd.2.html) ++pub fn signalfd(fd: RawFd, mask: &SigSet, flags: SfdFlags) -> Result<RawFd> { ++ unsafe { ++ Errno::result(libc::signalfd(fd as libc::c_int, mask.as_ref(), flags.bits())) ++ } ++} ++ ++/// A helper struct for creating, reading and closing a `signalfd` instance. ++/// ++/// **Important:** please read the module level documentation about signal discarding before using ++/// this struct! ++/// ++/// # Examples ++/// ++/// ``` ++/// # use nix::sys::signalfd::*; ++/// // Set the thread to block the SIGUSR1 signal, otherwise the default handler will be used ++/// let mut mask = SigSet::empty(); ++/// mask.add(signal::SIGUSR1); ++/// mask.thread_block().unwrap(); ++/// ++/// // Signals are queued up on the file descriptor ++/// let mut sfd = SignalFd::with_flags(&mask, SfdFlags::SFD_NONBLOCK).unwrap(); ++/// ++/// match sfd.read_signal() { ++/// // we caught a signal ++/// Ok(Some(sig)) => (), ++/// // there were no signals waiting (only happens when the SFD_NONBLOCK flag is set, ++/// // otherwise the read_signal call blocks) ++/// Ok(None) => (), ++/// Err(err) => (), // some error happend ++/// } ++/// ``` ++#[derive(Clone, Debug, Eq, Hash, PartialEq)] ++pub struct SignalFd(RawFd); ++ ++impl SignalFd { ++ pub fn new(mask: &SigSet) -> Result<SignalFd> { ++ Self::with_flags(mask, SfdFlags::empty()) ++ } ++ ++ pub fn with_flags(mask: &SigSet, flags: SfdFlags) -> Result<SignalFd> { ++ let fd = signalfd(SIGNALFD_NEW, mask, flags)?; ++ ++ Ok(SignalFd(fd)) ++ } ++ ++ pub fn set_mask(&mut self, mask: &SigSet) -> Result<()> { ++ signalfd(self.0, mask, SfdFlags::empty()).map(drop) ++ } ++ ++ pub fn read_signal(&mut self) -> Result<Option<siginfo>> { ++ let mut buffer: [u8; SIGNALFD_SIGINFO_SIZE] = unsafe { mem::uninitialized() }; ++ ++ match unistd::read(self.0, &mut buffer) { ++ Ok(SIGNALFD_SIGINFO_SIZE) => Ok(Some(unsafe { mem::transmute(buffer) })), ++ Ok(_) => unreachable!("partial read on signalfd"), ++ Err(Error::Sys(Errno::EAGAIN)) => Ok(None), ++ Err(error) => Err(error) ++ } ++ } ++} ++ ++impl Drop for SignalFd { ++ fn drop(&mut self) { ++ let _ = unistd::close(self.0); ++ } ++} ++ ++impl AsRawFd for SignalFd { ++ fn as_raw_fd(&self) -> RawFd { ++ self.0 ++ } ++} ++ ++impl Iterator for SignalFd { ++ type Item = siginfo; ++ ++ fn next(&mut self) -> Option<Self::Item> { ++ match self.read_signal() { ++ Ok(Some(sig)) => Some(sig), ++ Ok(None) | Err(_) => None, ++ } ++ } ++} ++ ++ ++#[cfg(test)] ++mod tests { ++ use super::*; ++ use std::mem; ++ use libc; ++ ++ ++ #[test] ++ fn check_siginfo_size() { ++ assert_eq!(mem::size_of::<libc::signalfd_siginfo>(), SIGNALFD_SIGINFO_SIZE); ++ } ++ ++ #[test] ++ fn create_signalfd() { ++ let mask = SigSet::empty(); ++ let fd = SignalFd::new(&mask); ++ assert!(fd.is_ok()); ++ } ++ ++ #[test] ++ fn create_signalfd_with_opts() { ++ let mask = SigSet::empty(); ++ let fd = SignalFd::with_flags(&mask, SfdFlags::SFD_CLOEXEC | SfdFlags::SFD_NONBLOCK); ++ assert!(fd.is_ok()); ++ } ++ ++ #[test] ++ fn read_empty_signalfd() { ++ let mask = SigSet::empty(); ++ let mut fd = SignalFd::with_flags(&mask, SfdFlags::SFD_NONBLOCK).unwrap(); ++ ++ let res = fd.read_signal(); ++ assert!(res.unwrap().is_none()); ++ } ++} +diff --git a/third_party/rust/nix-0.15.0/src/sys/socket/addr.rs b/third_party/rust/nix-0.15.0/src/sys/socket/addr.rs +new file mode 100644 +index 0000000000000..ed41441155361 +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/src/sys/socket/addr.rs +@@ -0,0 +1,1278 @@ ++use super::sa_family_t; ++use {Error, Result, NixPath}; ++use errno::Errno; ++use libc; ++use std::{fmt, mem, net, ptr, slice}; ++use std::ffi::OsStr; ++use std::hash::{Hash, Hasher}; ++use std::path::Path; ++use std::os::unix::ffi::OsStrExt; ++#[cfg(any(target_os = "android", target_os = "linux"))] ++use ::sys::socket::addr::netlink::NetlinkAddr; ++#[cfg(any(target_os = "android", target_os = "linux"))] ++use ::sys::socket::addr::alg::AlgAddr; ++#[cfg(any(target_os = "ios", target_os = "macos"))] ++use std::os::unix::io::RawFd; ++#[cfg(any(target_os = "ios", target_os = "macos"))] ++use ::sys::socket::addr::sys_control::SysControlAddr; ++#[cfg(any(target_os = "android", ++ target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++pub use self::datalink::LinkAddr; ++#[cfg(target_os = "linux")] ++pub use self::vsock::VsockAddr; ++ ++/// These constants specify the protocol family to be used ++/// in [`socket`](fn.socket.html) and [`socketpair`](fn.socketpair.html) ++#[repr(i32)] ++#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] ++pub enum AddressFamily { ++ /// Local communication (see [`unix(7)`](http://man7.org/linux/man-pages/man7/unix.7.html)) ++ Unix = libc::AF_UNIX, ++ /// IPv4 Internet protocols (see [`ip(7)`](http://man7.org/linux/man-pages/man7/ip.7.html)) ++ Inet = libc::AF_INET, ++ /// IPv6 Internet protocols (see [`ipv6(7)`](http://man7.org/linux/man-pages/man7/ipv6.7.html)) ++ Inet6 = libc::AF_INET6, ++ /// Kernel user interface device (see [`netlink(7)`](http://man7.org/linux/man-pages/man7/netlink.7.html)) ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ Netlink = libc::AF_NETLINK, ++ /// Low level packet interface (see [`packet(7)`](http://man7.org/linux/man-pages/man7/packet.7.html)) ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ Packet = libc::AF_PACKET, ++ /// KEXT Controls and Notifications ++ #[cfg(any(target_os = "ios", target_os = "macos"))] ++ System = libc::AF_SYSTEM, ++ /// Amateur radio AX.25 protocol ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ Ax25 = libc::AF_AX25, ++ /// IPX - Novell protocols ++ Ipx = libc::AF_IPX, ++ /// AppleTalk ++ AppleTalk = libc::AF_APPLETALK, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ NetRom = libc::AF_NETROM, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ Bridge = libc::AF_BRIDGE, ++ /// Access to raw ATM PVCs ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ AtmPvc = libc::AF_ATMPVC, ++ /// ITU-T X.25 / ISO-8208 protocol (see [`x25(7)`](http://man7.org/linux/man-pages/man7/x25.7.html)) ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ X25 = libc::AF_X25, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ Rose = libc::AF_ROSE, ++ Decnet = libc::AF_DECnet, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ NetBeui = libc::AF_NETBEUI, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ Security = libc::AF_SECURITY, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ Key = libc::AF_KEY, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ Ash = libc::AF_ASH, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ Econet = libc::AF_ECONET, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ AtmSvc = libc::AF_ATMSVC, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ Rds = libc::AF_RDS, ++ Sna = libc::AF_SNA, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ Irda = libc::AF_IRDA, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ Pppox = libc::AF_PPPOX, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ Wanpipe = libc::AF_WANPIPE, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ Llc = libc::AF_LLC, ++ #[cfg(target_os = "linux")] ++ Ib = libc::AF_IB, ++ #[cfg(target_os = "linux")] ++ Mpls = libc::AF_MPLS, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ Can = libc::AF_CAN, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ Tipc = libc::AF_TIPC, ++ #[cfg(not(any(target_os = "ios", target_os = "macos")))] ++ Bluetooth = libc::AF_BLUETOOTH, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ Iucv = libc::AF_IUCV, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ RxRpc = libc::AF_RXRPC, ++ Isdn = libc::AF_ISDN, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ Phonet = libc::AF_PHONET, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ Ieee802154 = libc::AF_IEEE802154, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ Caif = libc::AF_CAIF, ++ /// Interface to kernel crypto API ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ Alg = libc::AF_ALG, ++ #[cfg(target_os = "linux")] ++ Nfc = libc::AF_NFC, ++ #[cfg(target_os = "linux")] ++ Vsock = libc::AF_VSOCK, ++ #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ ImpLink = libc::AF_IMPLINK, ++ #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ Pup = libc::AF_PUP, ++ #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ Chaos = libc::AF_CHAOS, ++ #[cfg(any(target_os = "ios", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ Ns = libc::AF_NS, ++ #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ Iso = libc::AF_ISO, ++ #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ Datakit = libc::AF_DATAKIT, ++ #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ Ccitt = libc::AF_CCITT, ++ #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ Dli = libc::AF_DLI, ++ #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ Lat = libc::AF_LAT, ++ #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ Hylink = libc::AF_HYLINK, ++ #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ Link = libc::AF_LINK, ++ #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ Coip = libc::AF_COIP, ++ #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ Cnt = libc::AF_CNT, ++ #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ Natm = libc::AF_NATM, ++ /// Unspecified address family, (see [`getaddrinfo(3)`](http://man7.org/linux/man-pages/man3/getaddrinfo.3.html)) ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ Unspec = libc::AF_UNSPEC, ++} ++ ++impl AddressFamily { ++ /// Create a new `AddressFamily` from an integer value retrieved from `libc`, usually from ++ /// the `sa_family` field of a `sockaddr`. ++ /// ++ /// Currently only supports these address families: Unix, Inet (v4 & v6), Netlink, Link/Packet ++ /// and System. Returns None for unsupported or unknown address families. ++ pub fn from_i32(family: i32) -> Option<AddressFamily> { ++ match family { ++ libc::AF_UNIX => Some(AddressFamily::Unix), ++ libc::AF_INET => Some(AddressFamily::Inet), ++ libc::AF_INET6 => Some(AddressFamily::Inet6), ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ libc::AF_NETLINK => Some(AddressFamily::Netlink), ++ #[cfg(any(target_os = "macos", target_os = "macos"))] ++ libc::AF_SYSTEM => Some(AddressFamily::System), ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ libc::AF_PACKET => Some(AddressFamily::Packet), ++ #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ libc::AF_LINK => Some(AddressFamily::Link), ++ #[cfg(target_os = "linux")] ++ libc::AF_VSOCK => Some(AddressFamily::Vsock), ++ _ => None ++ } ++ } ++} ++ ++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] ++pub enum InetAddr { ++ V4(libc::sockaddr_in), ++ V6(libc::sockaddr_in6), ++} ++ ++impl InetAddr { ++ pub fn from_std(std: &net::SocketAddr) -> InetAddr { ++ match *std { ++ net::SocketAddr::V4(ref addr) => { ++ InetAddr::V4(libc::sockaddr_in { ++ sin_family: AddressFamily::Inet as sa_family_t, ++ sin_port: addr.port().to_be(), // network byte order ++ sin_addr: Ipv4Addr::from_std(addr.ip()).0, ++ .. unsafe { mem::zeroed() } ++ }) ++ } ++ net::SocketAddr::V6(ref addr) => { ++ InetAddr::V6(libc::sockaddr_in6 { ++ sin6_family: AddressFamily::Inet6 as sa_family_t, ++ sin6_port: addr.port().to_be(), // network byte order ++ sin6_addr: Ipv6Addr::from_std(addr.ip()).0, ++ sin6_flowinfo: addr.flowinfo(), // host byte order ++ sin6_scope_id: addr.scope_id(), // host byte order ++ .. unsafe { mem::zeroed() } ++ }) ++ } ++ } ++ } ++ ++ pub fn new(ip: IpAddr, port: u16) -> InetAddr { ++ match ip { ++ IpAddr::V4(ref ip) => { ++ InetAddr::V4(libc::sockaddr_in { ++ sin_family: AddressFamily::Inet as sa_family_t, ++ sin_port: port.to_be(), ++ sin_addr: ip.0, ++ .. unsafe { mem::zeroed() } ++ }) ++ } ++ IpAddr::V6(ref ip) => { ++ InetAddr::V6(libc::sockaddr_in6 { ++ sin6_family: AddressFamily::Inet6 as sa_family_t, ++ sin6_port: port.to_be(), ++ sin6_addr: ip.0, ++ .. unsafe { mem::zeroed() } ++ }) ++ } ++ } ++ } ++ /// Gets the IP address associated with this socket address. ++ pub fn ip(&self) -> IpAddr { ++ match *self { ++ InetAddr::V4(ref sa) => IpAddr::V4(Ipv4Addr(sa.sin_addr)), ++ InetAddr::V6(ref sa) => IpAddr::V6(Ipv6Addr(sa.sin6_addr)), ++ } ++ } ++ ++ /// Gets the port number associated with this socket address ++ pub fn port(&self) -> u16 { ++ match *self { ++ InetAddr::V6(ref sa) => u16::from_be(sa.sin6_port), ++ InetAddr::V4(ref sa) => u16::from_be(sa.sin_port), ++ } ++ } ++ ++ pub fn to_std(&self) -> net::SocketAddr { ++ match *self { ++ InetAddr::V4(ref sa) => net::SocketAddr::V4( ++ net::SocketAddrV4::new( ++ Ipv4Addr(sa.sin_addr).to_std(), ++ self.port())), ++ InetAddr::V6(ref sa) => net::SocketAddr::V6( ++ net::SocketAddrV6::new( ++ Ipv6Addr(sa.sin6_addr).to_std(), ++ self.port(), ++ sa.sin6_flowinfo, ++ sa.sin6_scope_id)), ++ } ++ } ++ ++ pub fn to_str(&self) -> String { ++ format!("{}", self) ++ } ++} ++ ++impl fmt::Display for InetAddr { ++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ++ match *self { ++ InetAddr::V4(_) => write!(f, "{}:{}", self.ip(), self.port()), ++ InetAddr::V6(_) => write!(f, "[{}]:{}", self.ip(), self.port()), ++ } ++ } ++} ++ ++/* ++ * ++ * ===== IpAddr ===== ++ * ++ */ ++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] ++pub enum IpAddr { ++ V4(Ipv4Addr), ++ V6(Ipv6Addr), ++} ++ ++impl IpAddr { ++ /// Create a new IpAddr that contains an IPv4 address. ++ /// ++ /// The result will represent the IP address a.b.c.d ++ pub fn new_v4(a: u8, b: u8, c: u8, d: u8) -> IpAddr { ++ IpAddr::V4(Ipv4Addr::new(a, b, c, d)) ++ } ++ ++ /// Create a new IpAddr that contains an IPv6 address. ++ /// ++ /// The result will represent the IP address a:b:c:d:e:f ++ pub fn new_v6(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> IpAddr { ++ IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g, h)) ++ } ++ ++ pub fn from_std(std: &net::IpAddr) -> IpAddr { ++ match *std { ++ net::IpAddr::V4(ref std) => IpAddr::V4(Ipv4Addr::from_std(std)), ++ net::IpAddr::V6(ref std) => IpAddr::V6(Ipv6Addr::from_std(std)), ++ } ++ } ++ ++ pub fn to_std(&self) -> net::IpAddr { ++ match *self { ++ IpAddr::V4(ref ip) => net::IpAddr::V4(ip.to_std()), ++ IpAddr::V6(ref ip) => net::IpAddr::V6(ip.to_std()), ++ } ++ } ++} ++ ++impl fmt::Display for IpAddr { ++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ++ match *self { ++ IpAddr::V4(ref v4) => v4.fmt(f), ++ IpAddr::V6(ref v6) => v6.fmt(f) ++ } ++ } ++} ++ ++/* ++ * ++ * ===== Ipv4Addr ===== ++ * ++ */ ++ ++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] ++pub struct Ipv4Addr(pub libc::in_addr); ++ ++impl Ipv4Addr { ++ pub fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr { ++ let ip = (((a as u32) << 24) | ++ ((b as u32) << 16) | ++ ((c as u32) << 8) | ++ ((d as u32) << 0)).to_be(); ++ ++ Ipv4Addr(libc::in_addr { s_addr: ip }) ++ } ++ ++ pub fn from_std(std: &net::Ipv4Addr) -> Ipv4Addr { ++ let bits = std.octets(); ++ Ipv4Addr::new(bits[0], bits[1], bits[2], bits[3]) ++ } ++ ++ pub fn any() -> Ipv4Addr { ++ Ipv4Addr(libc::in_addr { s_addr: libc::INADDR_ANY }) ++ } ++ ++ pub fn octets(&self) -> [u8; 4] { ++ let bits = u32::from_be(self.0.s_addr); ++ [(bits >> 24) as u8, (bits >> 16) as u8, (bits >> 8) as u8, bits as u8] ++ } ++ ++ pub fn to_std(&self) -> net::Ipv4Addr { ++ let bits = self.octets(); ++ net::Ipv4Addr::new(bits[0], bits[1], bits[2], bits[3]) ++ } ++} ++ ++impl fmt::Display for Ipv4Addr { ++ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { ++ let octets = self.octets(); ++ write!(fmt, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]) ++ } ++} ++ ++/* ++ * ++ * ===== Ipv6Addr ===== ++ * ++ */ ++ ++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] ++pub struct Ipv6Addr(pub libc::in6_addr); ++ ++// Note that IPv6 addresses are stored in big endian order on all architectures. ++// See https://tools.ietf.org/html/rfc1700 or consult your favorite search ++// engine. ++ ++macro_rules! to_u8_array { ++ ($($num:ident),*) => { ++ [ $(($num>>8) as u8, ($num&0xff) as u8,)* ] ++ } ++} ++ ++macro_rules! to_u16_array { ++ ($slf:ident, $($first:expr, $second:expr),*) => { ++ [$( (($slf.0.s6_addr[$first] as u16) << 8) + $slf.0.s6_addr[$second] as u16,)*] ++ } ++} ++ ++impl Ipv6Addr { ++ pub fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr { ++ let mut in6_addr_var: libc::in6_addr = unsafe{mem::uninitialized()}; ++ in6_addr_var.s6_addr = to_u8_array!(a,b,c,d,e,f,g,h); ++ Ipv6Addr(in6_addr_var) ++ } ++ ++ pub fn from_std(std: &net::Ipv6Addr) -> Ipv6Addr { ++ let s = std.segments(); ++ Ipv6Addr::new(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7]) ++ } ++ ++ /// Return the eight 16-bit segments that make up this address ++ pub fn segments(&self) -> [u16; 8] { ++ to_u16_array!(self, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15) ++ } ++ ++ pub fn to_std(&self) -> net::Ipv6Addr { ++ let s = self.segments(); ++ net::Ipv6Addr::new(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7]) ++ } ++} ++ ++impl fmt::Display for Ipv6Addr { ++ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { ++ self.to_std().fmt(fmt) ++ } ++} ++ ++/// A wrapper around `sockaddr_un`. ++/// ++/// This also tracks the length of `sun_path` address (excluding ++/// a terminating null), because it may not be null-terminated. For example, ++/// unconnected and Linux abstract sockets are never null-terminated, and POSIX ++/// does not require that `sun_len` include the terminating null even for normal ++/// sockets. Note that the actual sockaddr length is greater by ++/// `offset_of!(libc::sockaddr_un, sun_path)` ++#[derive(Clone, Copy, Debug)] ++pub struct UnixAddr(pub libc::sockaddr_un, pub usize); ++ ++impl UnixAddr { ++ /// Create a new sockaddr_un representing a filesystem path. ++ pub fn new<P: ?Sized + NixPath>(path: &P) -> Result<UnixAddr> { ++ path.with_nix_path(|cstr| { ++ unsafe { ++ let mut ret = libc::sockaddr_un { ++ sun_family: AddressFamily::Unix as sa_family_t, ++ .. mem::zeroed() ++ }; ++ ++ let bytes = cstr.to_bytes(); ++ ++ if bytes.len() > ret.sun_path.len() { ++ return Err(Error::Sys(Errno::ENAMETOOLONG)); ++ } ++ ++ ptr::copy_nonoverlapping(bytes.as_ptr(), ++ ret.sun_path.as_mut_ptr() as *mut u8, ++ bytes.len()); ++ ++ Ok(UnixAddr(ret, bytes.len())) ++ } ++ })? ++ } ++ ++ /// Create a new `sockaddr_un` representing an address in the "abstract namespace". ++ /// ++ /// The leading null byte for the abstract namespace is automatically added; ++ /// thus the input `path` is expected to be the bare name, not null-prefixed. ++ /// This is a Linux-specific extension, primarily used to allow chrooted ++ /// processes to communicate with processes having a different filesystem view. ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ pub fn new_abstract(path: &[u8]) -> Result<UnixAddr> { ++ unsafe { ++ let mut ret = libc::sockaddr_un { ++ sun_family: AddressFamily::Unix as sa_family_t, ++ .. mem::zeroed() ++ }; ++ ++ if path.len() + 1 > ret.sun_path.len() { ++ return Err(Error::Sys(Errno::ENAMETOOLONG)); ++ } ++ ++ // Abstract addresses are represented by sun_path[0] == ++ // b'\0', so copy starting one byte in. ++ ptr::copy_nonoverlapping(path.as_ptr(), ++ ret.sun_path.as_mut_ptr().offset(1) as *mut u8, ++ path.len()); ++ ++ Ok(UnixAddr(ret, ret.sun_path.len())) ++ } ++ } ++ ++ fn sun_path(&self) -> &[u8] { ++ unsafe { slice::from_raw_parts(self.0.sun_path.as_ptr() as *const u8, self.1) } ++ } ++ ++ /// If this address represents a filesystem path, return that path. ++ pub fn path(&self) -> Option<&Path> { ++ if self.1 == 0 || self.0.sun_path[0] == 0 { ++ // unnamed or abstract ++ None ++ } else { ++ let p = self.sun_path(); ++ // POSIX only requires that `sun_len` be at least long enough to ++ // contain the pathname, and it need not be null-terminated. So we ++ // need to create a string that is the shorter of the ++ // null-terminated length or the full length. ++ let ptr = &self.0.sun_path as *const libc::c_char; ++ let reallen = unsafe { libc::strnlen(ptr, p.len()) }; ++ Some(Path::new(<OsStr as OsStrExt>::from_bytes(&p[..reallen]))) ++ } ++ } ++ ++ /// If this address represents an abstract socket, return its name. ++ /// ++ /// For abstract sockets only the bare name is returned, without the ++ /// leading null byte. `None` is returned for unnamed or path-backed sockets. ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ pub fn as_abstract(&self) -> Option<&[u8]> { ++ if self.1 >= 1 && self.0.sun_path[0] == 0 { ++ Some(&self.sun_path()[1..]) ++ } else { ++ // unnamed or filesystem path ++ None ++ } ++ } ++} ++ ++impl fmt::Display for UnixAddr { ++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ++ if self.1 == 0 { ++ f.write_str("<unbound UNIX socket>") ++ } else if let Some(path) = self.path() { ++ path.display().fmt(f) ++ } else { ++ let display = String::from_utf8_lossy(&self.sun_path()[1..]); ++ write!(f, "@{}", display) ++ } ++ } ++} ++ ++impl PartialEq for UnixAddr { ++ fn eq(&self, other: &UnixAddr) -> bool { ++ self.sun_path() == other.sun_path() ++ } ++} ++ ++impl Eq for UnixAddr {} ++ ++impl Hash for UnixAddr { ++ fn hash<H: Hasher>(&self, s: &mut H) { ++ ( self.0.sun_family, self.sun_path() ).hash(s) ++ } ++} ++ ++/// Represents a socket address ++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] ++pub enum SockAddr { ++ Inet(InetAddr), ++ Unix(UnixAddr), ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ Netlink(NetlinkAddr), ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ Alg(AlgAddr), ++ #[cfg(any(target_os = "ios", target_os = "macos"))] ++ SysControl(SysControlAddr), ++ /// Datalink address (MAC) ++ #[cfg(any(target_os = "android", ++ target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ Link(LinkAddr), ++ #[cfg(target_os = "linux")] ++ Vsock(VsockAddr), ++} ++ ++impl SockAddr { ++ pub fn new_inet(addr: InetAddr) -> SockAddr { ++ SockAddr::Inet(addr) ++ } ++ ++ pub fn new_unix<P: ?Sized + NixPath>(path: &P) -> Result<SockAddr> { ++ Ok(SockAddr::Unix(UnixAddr::new(path)?)) ++ } ++ ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ pub fn new_netlink(pid: u32, groups: u32) -> SockAddr { ++ SockAddr::Netlink(NetlinkAddr::new(pid, groups)) ++ } ++ ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ pub fn new_alg(alg_type: &str, alg_name: &str) -> SockAddr { ++ SockAddr::Alg(AlgAddr::new(alg_type, alg_name)) ++ } ++ ++ #[cfg(any(target_os = "ios", target_os = "macos"))] ++ pub fn new_sys_control(sockfd: RawFd, name: &str, unit: u32) -> Result<SockAddr> { ++ SysControlAddr::from_name(sockfd, name, unit).map(|a| SockAddr::SysControl(a)) ++ } ++ ++ #[cfg(target_os = "linux")] ++ pub fn new_vsock(cid: u32, port: u32) -> SockAddr { ++ SockAddr::Vsock(VsockAddr::new(cid, port)) ++ } ++ ++ pub fn family(&self) -> AddressFamily { ++ match *self { ++ SockAddr::Inet(InetAddr::V4(..)) => AddressFamily::Inet, ++ SockAddr::Inet(InetAddr::V6(..)) => AddressFamily::Inet6, ++ SockAddr::Unix(..) => AddressFamily::Unix, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ SockAddr::Netlink(..) => AddressFamily::Netlink, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ SockAddr::Alg(..) => AddressFamily::Alg, ++ #[cfg(any(target_os = "ios", target_os = "macos"))] ++ SockAddr::SysControl(..) => AddressFamily::System, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ SockAddr::Link(..) => AddressFamily::Packet, ++ #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ SockAddr::Link(..) => AddressFamily::Link, ++ #[cfg(target_os = "linux")] ++ SockAddr::Vsock(..) => AddressFamily::Vsock, ++ } ++ } ++ ++ pub fn to_str(&self) -> String { ++ format!("{}", self) ++ } ++ ++ /// Creates a `SockAddr` struct from libc's sockaddr. ++ /// ++ /// Supports only the following address families: Unix, Inet (v4 & v6), Netlink and System. ++ /// Returns None for unsupported families. ++ pub unsafe fn from_libc_sockaddr(addr: *const libc::sockaddr) -> Option<SockAddr> { ++ if addr.is_null() { ++ None ++ } else { ++ match AddressFamily::from_i32((*addr).sa_family as i32) { ++ Some(AddressFamily::Unix) => None, ++ Some(AddressFamily::Inet) => Some(SockAddr::Inet( ++ InetAddr::V4(*(addr as *const libc::sockaddr_in)))), ++ Some(AddressFamily::Inet6) => Some(SockAddr::Inet( ++ InetAddr::V6(*(addr as *const libc::sockaddr_in6)))), ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ Some(AddressFamily::Netlink) => Some(SockAddr::Netlink( ++ NetlinkAddr(*(addr as *const libc::sockaddr_nl)))), ++ #[cfg(any(target_os = "ios", target_os = "macos"))] ++ Some(AddressFamily::System) => Some(SockAddr::SysControl( ++ SysControlAddr(*(addr as *const libc::sockaddr_ctl)))), ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ Some(AddressFamily::Packet) => Some(SockAddr::Link( ++ LinkAddr(*(addr as *const libc::sockaddr_ll)))), ++ #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ Some(AddressFamily::Link) => { ++ let ether_addr = LinkAddr(*(addr as *const libc::sockaddr_dl)); ++ if ether_addr.is_empty() { ++ None ++ } else { ++ Some(SockAddr::Link(ether_addr)) ++ } ++ }, ++ #[cfg(target_os = "linux")] ++ Some(AddressFamily::Vsock) => Some(SockAddr::Vsock( ++ VsockAddr(*(addr as *const libc::sockaddr_vm)))), ++ // Other address families are currently not supported and simply yield a None ++ // entry instead of a proper conversion to a `SockAddr`. ++ Some(_) | None => None, ++ } ++ } ++ } ++ ++ /// Conversion from nix's SockAddr type to the underlying libc sockaddr type. ++ /// ++ /// This is useful for interfacing with other libc functions that don't yet have nix wrappers. ++ /// Returns a reference to the underlying data type (as a sockaddr reference) along ++ /// with the size of the actual data type. sockaddr is commonly used as a proxy for ++ /// a superclass as C doesn't support inheritance, so many functions that take ++ /// a sockaddr * need to take the size of the underlying type as well and then internally cast it back. ++ pub unsafe fn as_ffi_pair(&self) -> (&libc::sockaddr, libc::socklen_t) { ++ match *self { ++ SockAddr::Inet(InetAddr::V4(ref addr)) => (mem::transmute(addr), mem::size_of::<libc::sockaddr_in>() as libc::socklen_t), ++ SockAddr::Inet(InetAddr::V6(ref addr)) => (mem::transmute(addr), mem::size_of::<libc::sockaddr_in6>() as libc::socklen_t), ++ SockAddr::Unix(UnixAddr(ref addr, len)) => (mem::transmute(addr), (len + offset_of!(libc::sockaddr_un, sun_path)) as libc::socklen_t), ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ SockAddr::Netlink(NetlinkAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<libc::sockaddr_nl>() as libc::socklen_t), ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ SockAddr::Alg(AlgAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<libc::sockaddr_alg>() as libc::socklen_t), ++ #[cfg(any(target_os = "ios", target_os = "macos"))] ++ SockAddr::SysControl(SysControlAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<libc::sockaddr_ctl>() as libc::socklen_t), ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ SockAddr::Link(LinkAddr(ref ether_addr)) => (mem::transmute(ether_addr), mem::size_of::<libc::sockaddr_ll>() as libc::socklen_t), ++ #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ SockAddr::Link(LinkAddr(ref ether_addr)) => (mem::transmute(ether_addr), mem::size_of::<libc::sockaddr_dl>() as libc::socklen_t), ++ #[cfg(target_os = "linux")] ++ SockAddr::Vsock(VsockAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<libc::sockaddr_vm>() as libc::socklen_t), ++ } ++ } ++} ++ ++impl fmt::Display for SockAddr { ++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ++ match *self { ++ SockAddr::Inet(ref inet) => inet.fmt(f), ++ SockAddr::Unix(ref unix) => unix.fmt(f), ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ SockAddr::Netlink(ref nl) => nl.fmt(f), ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ SockAddr::Alg(ref nl) => nl.fmt(f), ++ #[cfg(any(target_os = "ios", target_os = "macos"))] ++ SockAddr::SysControl(ref sc) => sc.fmt(f), ++ #[cfg(any(target_os = "android", ++ target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ SockAddr::Link(ref ether_addr) => ether_addr.fmt(f), ++ #[cfg(target_os = "linux")] ++ SockAddr::Vsock(ref svm) => svm.fmt(f), ++ } ++ } ++} ++ ++#[cfg(any(target_os = "android", target_os = "linux"))] ++pub mod netlink { ++ use ::sys::socket::addr::AddressFamily; ++ use libc::{sa_family_t, sockaddr_nl}; ++ use std::{fmt, mem}; ++ ++ #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)] ++ pub struct NetlinkAddr(pub sockaddr_nl); ++ ++ impl NetlinkAddr { ++ pub fn new(pid: u32, groups: u32) -> NetlinkAddr { ++ let mut addr: sockaddr_nl = unsafe { mem::zeroed() }; ++ addr.nl_family = AddressFamily::Netlink as sa_family_t; ++ addr.nl_pid = pid; ++ addr.nl_groups = groups; ++ ++ NetlinkAddr(addr) ++ } ++ ++ pub fn pid(&self) -> u32 { ++ self.0.nl_pid ++ } ++ ++ pub fn groups(&self) -> u32 { ++ self.0.nl_groups ++ } ++ } ++ ++ impl fmt::Display for NetlinkAddr { ++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ++ write!(f, "pid: {} groups: {}", self.pid(), self.groups()) ++ } ++ } ++} ++ ++#[cfg(any(target_os = "android", target_os = "linux"))] ++pub mod alg { ++ use libc::{AF_ALG, sockaddr_alg, c_char}; ++ use std::{fmt, mem, str}; ++ use std::hash::{Hash, Hasher}; ++ use std::ffi::CStr; ++ ++ #[derive(Copy, Clone)] ++ pub struct AlgAddr(pub sockaddr_alg); ++ ++ // , PartialEq, Eq, Debug, Hash ++ impl PartialEq for AlgAddr { ++ fn eq(&self, other: &Self) -> bool { ++ let (inner, other) = (self.0, other.0); ++ (inner.salg_family, &inner.salg_type[..], inner.salg_feat, inner.salg_mask, &inner.salg_name[..]) == ++ (other.salg_family, &other.salg_type[..], other.salg_feat, other.salg_mask, &other.salg_name[..]) ++ } ++ } ++ ++ impl Eq for AlgAddr {} ++ ++ impl Hash for AlgAddr { ++ fn hash<H: Hasher>(&self, s: &mut H) { ++ let inner = self.0; ++ (inner.salg_family, &inner.salg_type[..], inner.salg_feat, inner.salg_mask, &inner.salg_name[..]).hash(s); ++ } ++ } ++ ++ impl AlgAddr { ++ pub fn new(alg_type: &str, alg_name: &str) -> AlgAddr { ++ let mut addr: sockaddr_alg = unsafe { mem::zeroed() }; ++ addr.salg_family = AF_ALG as u16; ++ addr.salg_type[..alg_type.len()].copy_from_slice(alg_type.to_string().as_bytes()); ++ addr.salg_name[..alg_name.len()].copy_from_slice(alg_name.to_string().as_bytes()); ++ ++ AlgAddr(addr) ++ } ++ ++ ++ pub fn alg_type(&self) -> &CStr { ++ unsafe { CStr::from_ptr(self.0.salg_type.as_ptr() as *const c_char) } ++ } ++ ++ pub fn alg_name(&self) -> &CStr { ++ unsafe { CStr::from_ptr(self.0.salg_name.as_ptr() as *const c_char) } ++ } ++ } ++ ++ impl fmt::Display for AlgAddr { ++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ++ write!(f, "type: {} alg: {}", ++ self.alg_name().to_string_lossy(), ++ self.alg_type().to_string_lossy()) ++ } ++ } ++ ++ impl fmt::Debug for AlgAddr { ++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ++ fmt::Display::fmt(self, f) ++ } ++ } ++} ++ ++#[cfg(any(target_os = "ios", target_os = "macos"))] ++pub mod sys_control { ++ use ::sys::socket::addr::AddressFamily; ++ use libc::{self, c_uchar}; ++ use std::{fmt, mem}; ++ use std::os::unix::io::RawFd; ++ use {Errno, Error, Result}; ++ ++ // FIXME: Move type into `libc` ++ #[repr(C)] ++ #[derive(Clone, Copy)] ++ #[allow(missing_debug_implementations)] ++ pub struct ctl_ioc_info { ++ pub ctl_id: u32, ++ pub ctl_name: [c_uchar; MAX_KCTL_NAME], ++ } ++ ++ const CTL_IOC_MAGIC: u8 = 'N' as u8; ++ const CTL_IOC_INFO: u8 = 3; ++ const MAX_KCTL_NAME: usize = 96; ++ ++ ioctl_readwrite!(ctl_info, CTL_IOC_MAGIC, CTL_IOC_INFO, ctl_ioc_info); ++ ++ #[repr(C)] ++ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] ++ pub struct SysControlAddr(pub libc::sockaddr_ctl); ++ ++ impl SysControlAddr { ++ pub fn new(id: u32, unit: u32) -> SysControlAddr { ++ let addr = libc::sockaddr_ctl { ++ sc_len: mem::size_of::<libc::sockaddr_ctl>() as c_uchar, ++ sc_family: AddressFamily::System as c_uchar, ++ ss_sysaddr: libc::AF_SYS_CONTROL as u16, ++ sc_id: id, ++ sc_unit: unit, ++ sc_reserved: [0; 5] ++ }; ++ ++ SysControlAddr(addr) ++ } ++ ++ pub fn from_name(sockfd: RawFd, name: &str, unit: u32) -> Result<SysControlAddr> { ++ if name.len() > MAX_KCTL_NAME { ++ return Err(Error::Sys(Errno::ENAMETOOLONG)); ++ } ++ ++ let mut ctl_name = [0; MAX_KCTL_NAME]; ++ ctl_name[..name.len()].clone_from_slice(name.as_bytes()); ++ let mut info = ctl_ioc_info { ctl_id: 0, ctl_name: ctl_name }; ++ ++ unsafe { ctl_info(sockfd, &mut info)?; } ++ ++ Ok(SysControlAddr::new(info.ctl_id, unit)) ++ } ++ ++ pub fn id(&self) -> u32 { ++ self.0.sc_id ++ } ++ ++ pub fn unit(&self) -> u32 { ++ self.0.sc_unit ++ } ++ } ++ ++ impl fmt::Display for SysControlAddr { ++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ++ fmt::Debug::fmt(self, f) ++ } ++ } ++} ++ ++ ++#[cfg(any(target_os = "android", target_os = "linux"))] ++mod datalink { ++ use super::{libc, fmt, AddressFamily}; ++ ++ /// Hardware Address ++ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] ++ pub struct LinkAddr(pub libc::sockaddr_ll); ++ ++ impl LinkAddr { ++ /// Always AF_PACKET ++ pub fn family(&self) -> AddressFamily { ++ assert_eq!(self.0.sll_family as i32, libc::AF_PACKET); ++ AddressFamily::Packet ++ } ++ ++ /// Physical-layer protocol ++ pub fn protocol(&self) -> u16 { ++ self.0.sll_protocol ++ } ++ ++ /// Interface number ++ pub fn ifindex(&self) -> usize { ++ self.0.sll_ifindex as usize ++ } ++ ++ /// ARP hardware type ++ pub fn hatype(&self) -> u16 { ++ self.0.sll_hatype ++ } ++ ++ /// Packet type ++ pub fn pkttype(&self) -> u8 { ++ self.0.sll_pkttype ++ } ++ ++ /// Length of MAC address ++ pub fn halen(&self) -> usize { ++ self.0.sll_halen as usize ++ } ++ ++ /// Physical-layer address (MAC) ++ pub fn addr(&self) -> [u8; 6] { ++ let a = self.0.sll_addr[0] as u8; ++ let b = self.0.sll_addr[1] as u8; ++ let c = self.0.sll_addr[2] as u8; ++ let d = self.0.sll_addr[3] as u8; ++ let e = self.0.sll_addr[4] as u8; ++ let f = self.0.sll_addr[5] as u8; ++ ++ [a, b, c, d, e, f] ++ } ++ } ++ ++ impl fmt::Display for LinkAddr { ++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ++ let addr = self.addr(); ++ write!(f, "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", ++ addr[0], ++ addr[1], ++ addr[2], ++ addr[3], ++ addr[4], ++ addr[5]) ++ } ++ } ++} ++ ++#[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++mod datalink { ++ use super::{libc, fmt, AddressFamily}; ++ ++ /// Hardware Address ++ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] ++ pub struct LinkAddr(pub libc::sockaddr_dl); ++ ++ impl LinkAddr { ++ /// Total length of sockaddr ++ pub fn len(&self) -> usize { ++ self.0.sdl_len as usize ++ } ++ ++ /// always == AF_LINK ++ pub fn family(&self) -> AddressFamily { ++ assert_eq!(self.0.sdl_family as i32, libc::AF_LINK); ++ AddressFamily::Link ++ } ++ ++ /// interface index, if != 0, system given index for interface ++ pub fn ifindex(&self) -> usize { ++ self.0.sdl_index as usize ++ } ++ ++ /// Datalink type ++ pub fn datalink_type(&self) -> u8 { ++ self.0.sdl_type ++ } ++ ++ // MAC address start position ++ pub fn nlen(&self) -> usize { ++ self.0.sdl_nlen as usize ++ } ++ ++ /// link level address length ++ pub fn alen(&self) -> usize { ++ self.0.sdl_alen as usize ++ } ++ ++ /// link layer selector length ++ pub fn slen(&self) -> usize { ++ self.0.sdl_slen as usize ++ } ++ ++ /// if link level address length == 0, ++ /// or `sdl_data` not be larger. ++ pub fn is_empty(&self) -> bool { ++ let nlen = self.nlen(); ++ let alen = self.alen(); ++ let data_len = self.0.sdl_data.len(); ++ ++ if alen > 0 && nlen + alen < data_len { ++ false ++ } else { ++ true ++ } ++ } ++ ++ /// Physical-layer address (MAC) ++ pub fn addr(&self) -> [u8; 6] { ++ let nlen = self.nlen(); ++ let data = self.0.sdl_data; ++ ++ assert!(!self.is_empty()); ++ ++ let a = data[nlen] as u8; ++ let b = data[nlen + 1] as u8; ++ let c = data[nlen + 2] as u8; ++ let d = data[nlen + 3] as u8; ++ let e = data[nlen + 4] as u8; ++ let f = data[nlen + 5] as u8; ++ ++ [a, b, c, d, e, f] ++ } ++ } ++ ++ impl fmt::Display for LinkAddr { ++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ++ let addr = self.addr(); ++ write!(f, "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", ++ addr[0], ++ addr[1], ++ addr[2], ++ addr[3], ++ addr[4], ++ addr[5]) ++ } ++ } ++} ++ ++#[cfg(target_os = "linux")] ++pub mod vsock { ++ use ::sys::socket::addr::AddressFamily; ++ use libc::{sa_family_t, sockaddr_vm}; ++ use std::{fmt, mem}; ++ use std::hash::{Hash, Hasher}; ++ ++ #[derive(Copy, Clone)] ++ pub struct VsockAddr(pub sockaddr_vm); ++ ++ impl PartialEq for VsockAddr { ++ fn eq(&self, other: &Self) -> bool { ++ let (inner, other) = (self.0, other.0); ++ (inner.svm_family, inner.svm_cid, inner.svm_port) == ++ (other.svm_family, other.svm_cid, other.svm_port) ++ } ++ } ++ ++ impl Eq for VsockAddr {} ++ ++ impl Hash for VsockAddr { ++ fn hash<H: Hasher>(&self, s: &mut H) { ++ let inner = self.0; ++ (inner.svm_family, inner.svm_cid, inner.svm_port).hash(s); ++ } ++ } ++ ++ /// VSOCK Address ++ /// ++ /// The address for AF_VSOCK socket is defined as a combination of a ++ /// 32-bit Context Identifier (CID) and a 32-bit port number. ++ impl VsockAddr { ++ pub fn new(cid: u32, port: u32) -> VsockAddr { ++ let mut addr: sockaddr_vm = unsafe { mem::zeroed() }; ++ addr.svm_family = AddressFamily::Vsock as sa_family_t; ++ addr.svm_cid = cid; ++ addr.svm_port = port; ++ ++ VsockAddr(addr) ++ } ++ ++ /// Context Identifier (CID) ++ pub fn cid(&self) -> u32 { ++ self.0.svm_cid ++ } ++ ++ /// Port number ++ pub fn port(&self) -> u32 { ++ self.0.svm_port ++ } ++ } ++ ++ impl fmt::Display for VsockAddr { ++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ++ write!(f, "cid: {} port: {}", self.cid(), self.port()) ++ } ++ } ++ ++ impl fmt::Debug for VsockAddr { ++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ++ fmt::Display::fmt(self, f) ++ } ++ } ++} ++ ++#[cfg(test)] ++mod tests { ++ #[cfg(any(target_os = "android", ++ target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ use super::*; ++ ++ #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ #[test] ++ fn test_macos_loopback_datalink_addr() { ++ let bytes = [20i8, 18, 1, 0, 24, 3, 0, 0, 108, 111, 48, 0, 0, 0, 0, 0]; ++ let sa = bytes.as_ptr() as *const libc::sockaddr; ++ let _sock_addr = unsafe { SockAddr::from_libc_sockaddr(sa) }; ++ assert!(_sock_addr.is_none()); ++ } ++ ++ #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ #[test] ++ fn test_macos_tap_datalink_addr() { ++ let bytes = [20i8, 18, 7, 0, 6, 3, 6, 0, 101, 110, 48, 24, 101, -112, -35, 76, -80]; ++ let ptr = bytes.as_ptr(); ++ let sa = ptr as *const libc::sockaddr; ++ let _sock_addr = unsafe { SockAddr::from_libc_sockaddr(sa) }; ++ ++ assert!(_sock_addr.is_some()); ++ ++ let sock_addr = _sock_addr.unwrap(); ++ ++ assert_eq!(sock_addr.family(), AddressFamily::Link); ++ ++ match sock_addr { ++ SockAddr::Link(ether_addr) => { ++ assert_eq!(ether_addr.addr(), [24u8, 101, 144, 221, 76, 176]); ++ }, ++ _ => { unreachable!() } ++ }; ++ } ++ ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ #[test] ++ fn test_abstract_sun_path() { ++ let name = String::from("nix\0abstract\0test"); ++ let addr = UnixAddr::new_abstract(name.as_bytes()).unwrap(); ++ ++ let sun_path1 = addr.sun_path(); ++ let sun_path2 = [0u8, 110, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, 116, 101, 115, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; ++ assert_eq!(sun_path1.len(), sun_path2.len()); ++ for i in 0..sun_path1.len() { ++ assert_eq!(sun_path1[i], sun_path2[i]); ++ } ++ } ++} +diff --git a/third_party/rust/nix-0.15.0/src/sys/socket/mod.rs b/third_party/rust/nix-0.15.0/src/sys/socket/mod.rs +new file mode 100644 +index 0000000000000..1c12c5f851734 +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/src/sys/socket/mod.rs +@@ -0,0 +1,1294 @@ ++//! Socket interface functions ++//! ++//! [Further reading](http://man7.org/linux/man-pages/man7/socket.7.html) ++use {Error, Result}; ++use errno::Errno; ++use libc::{self, c_void, c_int, iovec, socklen_t, size_t, ++ CMSG_FIRSTHDR, CMSG_NXTHDR, CMSG_DATA, CMSG_LEN}; ++use std::{mem, ptr, slice}; ++use std::os::unix::io::RawFd; ++use sys::time::TimeVal; ++use sys::uio::IoVec; ++ ++mod addr; ++pub mod sockopt; ++ ++/* ++ * ++ * ===== Re-exports ===== ++ * ++ */ ++ ++pub use self::addr::{ ++ AddressFamily, ++ SockAddr, ++ InetAddr, ++ UnixAddr, ++ IpAddr, ++ Ipv4Addr, ++ Ipv6Addr, ++ LinkAddr, ++}; ++#[cfg(any(target_os = "android", target_os = "linux"))] ++pub use ::sys::socket::addr::netlink::NetlinkAddr; ++#[cfg(any(target_os = "android", target_os = "linux"))] ++pub use sys::socket::addr::alg::AlgAddr; ++#[cfg(target_os = "linux")] ++pub use sys::socket::addr::vsock::VsockAddr; ++ ++pub use libc::{ ++ cmsghdr, ++ msghdr, ++ sa_family_t, ++ sockaddr, ++ sockaddr_in, ++ sockaddr_in6, ++ sockaddr_storage, ++ sockaddr_un, ++}; ++ ++// Needed by the cmsg_space macro ++#[doc(hidden)] ++pub use libc::{c_uint, CMSG_SPACE}; ++ ++/// These constants are used to specify the communication semantics ++/// when creating a socket with [`socket()`](fn.socket.html) ++#[derive(Clone, Copy, PartialEq, Eq, Debug)] ++#[repr(i32)] ++pub enum SockType { ++ /// Provides sequenced, reliable, two-way, connection- ++ /// based byte streams. An out-of-band data transmission ++ /// mechanism may be supported. ++ Stream = libc::SOCK_STREAM, ++ /// Supports datagrams (connectionless, unreliable ++ /// messages of a fixed maximum length). ++ Datagram = libc::SOCK_DGRAM, ++ /// Provides a sequenced, reliable, two-way connection- ++ /// based data transmission path for datagrams of fixed ++ /// maximum length; a consumer is required to read an ++ /// entire packet with each input system call. ++ SeqPacket = libc::SOCK_SEQPACKET, ++ /// Provides raw network protocol access. ++ Raw = libc::SOCK_RAW, ++ /// Provides a reliable datagram layer that does not ++ /// guarantee ordering. ++ Rdm = libc::SOCK_RDM, ++} ++ ++/// Constants used in [`socket`](fn.socket.html) and [`socketpair`](fn.socketpair.html) ++/// to specify the protocol to use. ++#[repr(i32)] ++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] ++pub enum SockProtocol { ++ /// TCP protocol ([ip(7)](http://man7.org/linux/man-pages/man7/ip.7.html)) ++ Tcp = libc::IPPROTO_TCP, ++ /// UDP protocol ([ip(7)](http://man7.org/linux/man-pages/man7/ip.7.html)) ++ Udp = libc::IPPROTO_UDP, ++ /// Allows applications and other KEXTs to be notified when certain kernel events occur ++ /// ([ref](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/control/control.html)) ++ #[cfg(any(target_os = "ios", target_os = "macos"))] ++ KextEvent = libc::SYSPROTO_EVENT, ++ /// Allows applications to configure and control a KEXT ++ /// ([ref](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/control/control.html)) ++ #[cfg(any(target_os = "ios", target_os = "macos"))] ++ KextControl = libc::SYSPROTO_CONTROL, ++} ++ ++libc_bitflags!{ ++ /// Additional socket options ++ pub struct SockFlag: c_int { ++ /// Set non-blocking mode on the new socket ++ #[cfg(any(target_os = "android", ++ target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "linux", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ SOCK_NONBLOCK; ++ /// Set close-on-exec on the new descriptor ++ #[cfg(any(target_os = "android", ++ target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "linux", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ SOCK_CLOEXEC; ++ /// Return `EPIPE` instead of raising `SIGPIPE` ++ #[cfg(target_os = "netbsd")] ++ SOCK_NOSIGPIPE; ++ /// For domains `AF_INET(6)`, only allow `connect(2)`, `sendto(2)`, or `sendmsg(2)` ++ /// to the DNS port (typically 53) ++ #[cfg(target_os = "openbsd")] ++ SOCK_DNS; ++ } ++} ++ ++libc_bitflags!{ ++ /// Flags for send/recv and their relatives ++ pub struct MsgFlags: c_int { ++ /// Sends or requests out-of-band data on sockets that support this notion ++ /// (e.g., of type [`Stream`](enum.SockType.html)); the underlying protocol must also ++ /// support out-of-band data. ++ MSG_OOB; ++ /// Peeks at an incoming message. The data is treated as unread and the next ++ /// [`recv()`](fn.recv.html) ++ /// or similar function shall still return this data. ++ MSG_PEEK; ++ /// Receive operation blocks until the full amount of data can be ++ /// returned. The function may return smaller amount of data if a signal ++ /// is caught, an error or disconnect occurs. ++ MSG_WAITALL; ++ /// Enables nonblocking operation; if the operation would block, ++ /// `EAGAIN` or `EWOULDBLOCK` is returned. This provides similar ++ /// behavior to setting the `O_NONBLOCK` flag ++ /// (via the [`fcntl`](../../fcntl/fn.fcntl.html) ++ /// `F_SETFL` operation), but differs in that `MSG_DONTWAIT` is a per- ++ /// call option, whereas `O_NONBLOCK` is a setting on the open file ++ /// description (see [open(2)](http://man7.org/linux/man-pages/man2/open.2.html)), ++ /// which will affect all threads in ++ /// the calling process and as well as other processes that hold ++ /// file descriptors referring to the same open file description. ++ MSG_DONTWAIT; ++ /// Receive flags: Control Data was discarded (buffer too small) ++ MSG_CTRUNC; ++ /// For raw ([`Packet`](addr/enum.AddressFamily.html)), Internet datagram ++ /// (since Linux 2.4.27/2.6.8), ++ /// netlink (since Linux 2.6.22) and UNIX datagram (since Linux 3.4) ++ /// sockets: return the real length of the packet or datagram, even ++ /// when it was longer than the passed buffer. Not implemented for UNIX ++ /// domain ([unix(7)](https://linux.die.net/man/7/unix)) sockets. ++ /// ++ /// For use with Internet stream sockets, see [tcp(7)](https://linux.die.net/man/7/tcp). ++ MSG_TRUNC; ++ /// Terminates a record (when this notion is supported, as for ++ /// sockets of type [`SeqPacket`](enum.SockType.html)). ++ MSG_EOR; ++ /// This flag specifies that queued errors should be received from ++ /// the socket error queue. (For more details, see ++ /// [recvfrom(2)](https://linux.die.net/man/2/recvfrom)) ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ MSG_ERRQUEUE; ++ /// Set the `close-on-exec` flag for the file descriptor received via a UNIX domain ++ /// file descriptor using the `SCM_RIGHTS` operation (described in ++ /// [unix(7)](https://linux.die.net/man/7/unix)). ++ /// This flag is useful for the same reasons as the `O_CLOEXEC` flag of ++ /// [open(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html). ++ /// ++ /// Only used in [`recvmsg`](fn.recvmsg.html) function. ++ #[cfg(any(target_os = "android", ++ target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "linux", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ MSG_CMSG_CLOEXEC; ++ } ++} ++ ++cfg_if! { ++ if #[cfg(any(target_os = "android", target_os = "linux"))] { ++ /// Unix credentials of the sending process. ++ /// ++ /// This struct is used with the `SO_PEERCRED` ancillary message for UNIX sockets. ++ #[repr(C)] ++ #[derive(Clone, Copy, Debug, Eq, PartialEq)] ++ pub struct UnixCredentials(libc::ucred); ++ ++ impl UnixCredentials { ++ /// Returns the process identifier ++ pub fn pid(&self) -> libc::pid_t { ++ self.0.pid ++ } ++ ++ /// Returns the user identifier ++ pub fn uid(&self) -> libc::uid_t { ++ self.0.uid ++ } ++ ++ /// Returns the group identifier ++ pub fn gid(&self) -> libc::gid_t { ++ self.0.gid ++ } ++ } ++ ++ impl From<libc::ucred> for UnixCredentials { ++ fn from(cred: libc::ucred) -> Self { ++ UnixCredentials(cred) ++ } ++ } ++ ++ impl Into<libc::ucred> for UnixCredentials { ++ fn into(self) -> libc::ucred { ++ self.0 ++ } ++ } ++ } ++} ++ ++/// Request for multicast socket operations ++/// ++/// This is a wrapper type around `ip_mreq`. ++#[repr(C)] ++#[derive(Clone, Copy, Debug, Eq, PartialEq)] ++pub struct IpMembershipRequest(libc::ip_mreq); ++ ++impl IpMembershipRequest { ++ /// Instantiate a new `IpMembershipRequest` ++ /// ++ /// If `interface` is `None`, then `Ipv4Addr::any()` will be used for the interface. ++ pub fn new(group: Ipv4Addr, interface: Option<Ipv4Addr>) -> Self { ++ IpMembershipRequest(libc::ip_mreq { ++ imr_multiaddr: group.0, ++ imr_interface: interface.unwrap_or_else(Ipv4Addr::any).0, ++ }) ++ } ++} ++ ++/// Request for ipv6 multicast socket operations ++/// ++/// This is a wrapper type around `ipv6_mreq`. ++#[repr(C)] ++#[derive(Clone, Copy, Debug, Eq, PartialEq)] ++pub struct Ipv6MembershipRequest(libc::ipv6_mreq); ++ ++impl Ipv6MembershipRequest { ++ /// Instantiate a new `Ipv6MembershipRequest` ++ pub fn new(group: Ipv6Addr) -> Self { ++ Ipv6MembershipRequest(libc::ipv6_mreq { ++ ipv6mr_multiaddr: group.0, ++ ipv6mr_interface: 0, ++ }) ++ } ++} ++ ++cfg_if! { ++ // Darwin and DragonFly BSD always align struct cmsghdr to 32-bit only. ++ if #[cfg(any(target_os = "dragonfly", target_os = "ios", target_os = "macos"))] { ++ type align_of_cmsg_data = u32; ++ } else { ++ type align_of_cmsg_data = size_t; ++ } ++} ++ ++/// A type that can be used to store ancillary data received by ++/// [`recvmsg`](fn.recvmsg.html) ++pub trait CmsgBuffer { ++ fn as_bytes_mut(&mut self) -> &mut [u8]; ++} ++ ++/// Create a buffer large enough for storing some control messages as returned ++/// by [`recvmsg`](fn.recvmsg.html). ++/// ++/// # Examples ++/// ++/// ``` ++/// # #[macro_use] extern crate nix; ++/// # use nix::sys::time::TimeVal; ++/// # use std::os::unix::io::RawFd; ++/// # fn main() { ++/// // Create a buffer for a `ControlMessageOwned::ScmTimestamp` message ++/// let _ = cmsg_space!(TimeVal); ++/// // Create a buffer big enough for a `ControlMessageOwned::ScmRights` message ++/// // with two file descriptors ++/// let _ = cmsg_space!([RawFd; 2]); ++/// // Create a buffer big enough for a `ControlMessageOwned::ScmRights` message ++/// // and a `ControlMessageOwned::ScmTimestamp` message ++/// let _ = cmsg_space!(RawFd, TimeVal); ++/// # } ++/// ``` ++// Unfortunately, CMSG_SPACE isn't a const_fn, or else we could return a ++// stack-allocated array. ++#[macro_export] ++macro_rules! cmsg_space { ++ ( $( $x:ty ),* ) => { ++ { ++ use nix::sys::socket::{c_uint, CMSG_SPACE}; ++ use std::mem; ++ let mut space = 0; ++ $( ++ // CMSG_SPACE is always safe ++ space += unsafe { ++ CMSG_SPACE(mem::size_of::<$x>() as c_uint) ++ } as usize; ++ )* ++ let mut v = Vec::<u8>::with_capacity(space); ++ // safe because any bit pattern is a valid u8 ++ unsafe {v.set_len(space)}; ++ v ++ } ++ } ++} ++ ++/// A structure used to make room in a cmsghdr passed to recvmsg. The ++/// size and alignment match that of a cmsghdr followed by a T, but the ++/// fields are not accessible, as the actual types will change on a call ++/// to recvmsg. ++/// ++/// To make room for multiple messages, nest the type parameter with ++/// tuples: ++/// ++/// ``` ++/// use std::os::unix::io::RawFd; ++/// use nix::sys::socket::CmsgSpace; ++/// let cmsg: CmsgSpace<([RawFd; 3], CmsgSpace<[RawFd; 2]>)> = CmsgSpace::new(); ++/// ``` ++#[repr(C)] ++#[derive(Clone, Copy, Debug, Eq, PartialEq)] ++pub struct CmsgSpace<T> { ++ _hdr: cmsghdr, ++ _pad: [align_of_cmsg_data; 0], ++ _data: T, ++} ++ ++impl<T> CmsgSpace<T> { ++ /// Create a CmsgSpace<T>. The structure is used only for space, so ++ /// the fields are uninitialized. ++ #[deprecated( since="0.14.0", note="Use the cmsg_space! macro instead")] ++ pub fn new() -> Self { ++ // Safe because the fields themselves aren't accessible. ++ unsafe { mem::uninitialized() } ++ } ++} ++ ++impl<T> CmsgBuffer for CmsgSpace<T> { ++ fn as_bytes_mut(&mut self) -> &mut [u8] { ++ // Safe because nothing ever attempts to access CmsgSpace's fields ++ unsafe { ++ slice::from_raw_parts_mut(self as *mut CmsgSpace<T> as *mut u8, ++ mem::size_of::<Self>()) ++ } ++ } ++} ++ ++impl CmsgBuffer for Vec<u8> { ++ fn as_bytes_mut(&mut self) -> &mut [u8] { ++ &mut self[..] ++ } ++} ++ ++#[derive(Clone, Copy, Debug, Eq, PartialEq)] ++pub struct RecvMsg<'a> { ++ pub bytes: usize, ++ cmsghdr: Option<&'a cmsghdr>, ++ pub address: Option<SockAddr>, ++ pub flags: MsgFlags, ++ mhdr: msghdr, ++} ++ ++impl<'a> RecvMsg<'a> { ++ /// Iterate over the valid control messages pointed to by this ++ /// msghdr. ++ pub fn cmsgs(&self) -> CmsgIterator { ++ CmsgIterator { ++ cmsghdr: self.cmsghdr, ++ mhdr: &self.mhdr ++ } ++ } ++} ++ ++#[derive(Clone, Copy, Debug, Eq, PartialEq)] ++pub struct CmsgIterator<'a> { ++ /// Control message buffer to decode from. Must adhere to cmsg alignment. ++ cmsghdr: Option<&'a cmsghdr>, ++ mhdr: &'a msghdr ++} ++ ++impl<'a> Iterator for CmsgIterator<'a> { ++ type Item = ControlMessageOwned; ++ ++ fn next(&mut self) -> Option<ControlMessageOwned> { ++ match self.cmsghdr { ++ None => None, // No more messages ++ Some(hdr) => { ++ // Get the data. ++ // Safe if cmsghdr points to valid data returned by recvmsg(2) ++ let cm = unsafe { Some(ControlMessageOwned::decode_from(hdr))}; ++ // Advance the internal pointer. Safe if mhdr and cmsghdr point ++ // to valid data returned by recvmsg(2) ++ self.cmsghdr = unsafe { ++ let p = CMSG_NXTHDR(self.mhdr as *const _, hdr as *const _); ++ p.as_ref() ++ }; ++ cm ++ } ++ } ++ } ++} ++ ++/// A type-safe wrapper around a single control message, as used with ++/// [`recvmsg`](#fn.recvmsg). ++/// ++/// [Further reading](http://man7.org/linux/man-pages/man3/cmsg.3.html) ++// Nix version 0.13.0 and earlier used ControlMessage for both recvmsg and ++// sendmsg. However, on some platforms the messages returned by recvmsg may be ++// unaligned. ControlMessageOwned takes those messages by copy, obviating any ++// alignment issues. ++// ++// See https://github.com/nix-rust/nix/issues/999 ++#[derive(Clone, Debug, Eq, PartialEq)] ++pub enum ControlMessageOwned { ++ /// Received version of ++ /// [`ControlMessage::ScmRights`][#enum.ControlMessage.html#variant.ScmRights] ++ ScmRights(Vec<RawFd>), ++ /// Received version of ++ /// [`ControlMessage::ScmCredentials`][#enum.ControlMessage.html#variant.ScmCredentials] ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ ScmCredentials(libc::ucred), ++ /// A message of type `SCM_TIMESTAMP`, containing the time the ++ /// packet was received by the kernel. ++ /// ++ /// See the kernel's explanation in "SO_TIMESTAMP" of ++ /// [networking/timestamping](https://www.kernel.org/doc/Documentation/networking/timestamping.txt). ++ /// ++ /// # Examples ++ /// ++ // Disable this test on FreeBSD i386 ++ // https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=222039 ++ #[cfg_attr(not(all(target_os = "freebsd", target_arch = "x86")), doc = " ```")] ++ #[cfg_attr(all(target_os = "freebsd", target_arch = "x86"), doc = " ```no_run")] ++ /// # #[macro_use] extern crate nix; ++ /// # use nix::sys::socket::*; ++ /// # use nix::sys::uio::IoVec; ++ /// # use nix::sys::time::*; ++ /// # use std::time::*; ++ /// # fn main() { ++ /// // Set up ++ /// let message = "Ohayō!".as_bytes(); ++ /// let in_socket = socket( ++ /// AddressFamily::Inet, ++ /// SockType::Datagram, ++ /// SockFlag::empty(), ++ /// None).unwrap(); ++ /// setsockopt(in_socket, sockopt::ReceiveTimestamp, &true).unwrap(); ++ /// let localhost = InetAddr::new(IpAddr::new_v4(127, 0, 0, 1), 0); ++ /// bind(in_socket, &SockAddr::new_inet(localhost)).unwrap(); ++ /// let address = getsockname(in_socket).unwrap(); ++ /// // Get initial time ++ /// let time0 = SystemTime::now(); ++ /// // Send the message ++ /// let iov = [IoVec::from_slice(message)]; ++ /// let flags = MsgFlags::empty(); ++ /// let l = sendmsg(in_socket, &iov, &[], flags, Some(&address)).unwrap(); ++ /// assert_eq!(message.len(), l); ++ /// // Receive the message ++ /// let mut buffer = vec![0u8; message.len()]; ++ /// let mut cmsgspace = cmsg_space!(TimeVal); ++ /// let iov = [IoVec::from_mut_slice(&mut buffer)]; ++ /// let r = recvmsg(in_socket, &iov, Some(&mut cmsgspace), flags).unwrap(); ++ /// let rtime = match r.cmsgs().next() { ++ /// Some(ControlMessageOwned::ScmTimestamp(rtime)) => rtime, ++ /// Some(_) => panic!("Unexpected control message"), ++ /// None => panic!("No control message") ++ /// }; ++ /// // Check the final time ++ /// let time1 = SystemTime::now(); ++ /// // the packet's received timestamp should lie in-between the two system ++ /// // times, unless the system clock was adjusted in the meantime. ++ /// let rduration = Duration::new(rtime.tv_sec() as u64, ++ /// rtime.tv_usec() as u32 * 1000); ++ /// assert!(time0.duration_since(UNIX_EPOCH).unwrap() <= rduration); ++ /// assert!(rduration <= time1.duration_since(UNIX_EPOCH).unwrap()); ++ /// // Close socket ++ /// nix::unistd::close(in_socket).unwrap(); ++ /// # } ++ /// ``` ++ ScmTimestamp(TimeVal), ++ #[cfg(any( ++ target_os = "android", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos", ++ target_os = "netbsd", ++ ))] ++ Ipv4PacketInfo(libc::in_pktinfo), ++ #[cfg(any( ++ target_os = "android", ++ target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos", ++ target_os = "openbsd", ++ target_os = "netbsd", ++ ))] ++ Ipv6PacketInfo(libc::in6_pktinfo), ++ #[cfg(any( ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd", ++ ))] ++ Ipv4RecvIf(libc::sockaddr_dl), ++ #[cfg(any( ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd", ++ ))] ++ Ipv4RecvDstAddr(libc::in_addr), ++ /// Catch-all variant for unimplemented cmsg types. ++ #[doc(hidden)] ++ Unknown(UnknownCmsg), ++} ++ ++impl ControlMessageOwned { ++ /// Decodes a `ControlMessageOwned` from raw bytes. ++ /// ++ /// This is only safe to call if the data is correct for the message type ++ /// specified in the header. Normally, the kernel ensures that this is the ++ /// case. "Correct" in this case includes correct length, alignment and ++ /// actual content. ++ /// ++ /// Returns `None` if the data may be unaligned. In that case use ++ /// `ControlMessageOwned::decode_from`. ++ unsafe fn decode_from(header: &cmsghdr) -> ControlMessageOwned ++ { ++ let p = CMSG_DATA(header); ++ let len = header as *const _ as usize + header.cmsg_len as usize ++ - p as usize; ++ match (header.cmsg_level, header.cmsg_type) { ++ (libc::SOL_SOCKET, libc::SCM_RIGHTS) => { ++ let n = len / mem::size_of::<RawFd>(); ++ let mut fds = Vec::with_capacity(n); ++ for i in 0..n { ++ let fdp = (p as *const RawFd).offset(i as isize); ++ fds.push(ptr::read_unaligned(fdp)); ++ } ++ let cmo = ControlMessageOwned::ScmRights(fds); ++ cmo ++ }, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ (libc::SOL_SOCKET, libc::SCM_CREDENTIALS) => { ++ let cred: libc::ucred = ptr::read_unaligned(p as *const _); ++ ControlMessageOwned::ScmCredentials(cred) ++ } ++ (libc::SOL_SOCKET, libc::SCM_TIMESTAMP) => { ++ let tv: libc::timeval = ptr::read_unaligned(p as *const _); ++ ControlMessageOwned::ScmTimestamp(TimeVal::from(tv)) ++ }, ++ #[cfg(any( ++ target_os = "android", ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos" ++ ))] ++ (libc::IPPROTO_IPV6, libc::IPV6_PKTINFO) => { ++ let info = ptr::read_unaligned(p as *const libc::in6_pktinfo); ++ ControlMessageOwned::Ipv6PacketInfo(info) ++ } ++ #[cfg(any( ++ target_os = "android", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos", ++ target_os = "netbsd", ++ ))] ++ (libc::IPPROTO_IP, libc::IP_PKTINFO) => { ++ let info = ptr::read_unaligned(p as *const libc::in_pktinfo); ++ ControlMessageOwned::Ipv4PacketInfo(info) ++ } ++ #[cfg(any( ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd", ++ ))] ++ (libc::IPPROTO_IP, libc::IP_RECVIF) => { ++ let dl = ptr::read_unaligned(p as *const libc::sockaddr_dl); ++ ControlMessageOwned::Ipv4RecvIf(dl) ++ }, ++ #[cfg(any( ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd", ++ ))] ++ (libc::IPPROTO_IP, libc::IP_RECVDSTADDR) => { ++ let dl = ptr::read_unaligned(p as *const libc::in_addr); ++ ControlMessageOwned::Ipv4RecvDstAddr(dl) ++ }, ++ (_, _) => { ++ let sl = slice::from_raw_parts(p, len); ++ let ucmsg = UnknownCmsg(*header, Vec::<u8>::from(&sl[..])); ++ ControlMessageOwned::Unknown(ucmsg) ++ } ++ } ++ } ++} ++ ++/// A type-safe zero-copy wrapper around a single control message, as used wih ++/// [`sendmsg`](#fn.sendmsg). More types may be added to this enum; do not ++/// exhaustively pattern-match it. ++/// ++/// [Further reading](http://man7.org/linux/man-pages/man3/cmsg.3.html) ++#[derive(Clone, Copy, Debug, Eq, PartialEq)] ++pub enum ControlMessage<'a> { ++ /// A message of type `SCM_RIGHTS`, containing an array of file ++ /// descriptors passed between processes. ++ /// ++ /// See the description in the "Ancillary messages" section of the ++ /// [unix(7) man page](http://man7.org/linux/man-pages/man7/unix.7.html). ++ /// ++ /// Using multiple `ScmRights` messages for a single `sendmsg` call isn't ++ /// recommended since it causes platform-dependent behaviour: It might ++ /// swallow all but the first `ScmRights` message or fail with `EINVAL`. ++ /// Instead, you can put all fds to be passed into a single `ScmRights` ++ /// message. ++ ScmRights(&'a [RawFd]), ++ /// A message of type `SCM_CREDENTIALS`, containing the pid, uid and gid of ++ /// a process connected to the socket. ++ /// ++ /// This is similar to the socket option `SO_PEERCRED`, but requires a ++ /// process to explicitly send its credentials. A process running as root is ++ /// allowed to specify any credentials, while credentials sent by other ++ /// processes are verified by the kernel. ++ /// ++ /// For further information, please refer to the ++ /// [`unix(7)`](http://man7.org/linux/man-pages/man7/unix.7.html) man page. ++ // FIXME: When `#[repr(transparent)]` is stable, use it on `UnixCredentials` ++ // and put that in here instead of a raw ucred. ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ ScmCredentials(&'a libc::ucred), ++ ++ /// Set IV for `AF_ALG` crypto API. ++ /// ++ /// For further information, please refer to the ++ /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html) ++ #[cfg(any( ++ target_os = "android", ++ target_os = "linux", ++ ))] ++ AlgSetIv(&'a [u8]), ++ /// Set crypto operation for `AF_ALG` crypto API. It may be one of ++ /// `ALG_OP_ENCRYPT` or `ALG_OP_DECRYPT` ++ /// ++ /// For further information, please refer to the ++ /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html) ++ #[cfg(any( ++ target_os = "android", ++ target_os = "linux", ++ ))] ++ AlgSetOp(&'a libc::c_int), ++ /// Set the length of associated authentication data (AAD) (applicable only to AEAD algorithms) ++ /// for `AF_ALG` crypto API. ++ /// ++ /// For further information, please refer to the ++ /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html) ++ #[cfg(any( ++ target_os = "android", ++ target_os = "linux", ++ ))] ++ AlgSetAeadAssoclen(&'a u32), ++ ++} ++ ++// An opaque structure used to prevent cmsghdr from being a public type ++#[doc(hidden)] ++#[derive(Clone, Debug, Eq, PartialEq)] ++pub struct UnknownCmsg(cmsghdr, Vec<u8>); ++ ++impl<'a> ControlMessage<'a> { ++ /// The value of CMSG_SPACE on this message. ++ /// Safe because CMSG_SPACE is always safe ++ fn space(&self) -> usize { ++ unsafe{CMSG_SPACE(self.len() as libc::c_uint) as usize} ++ } ++ ++ /// The value of CMSG_LEN on this message. ++ /// Safe because CMSG_LEN is always safe ++ #[cfg(any(target_os = "android", ++ all(target_os = "linux", not(target_env = "musl"))))] ++ fn cmsg_len(&self) -> usize { ++ unsafe{CMSG_LEN(self.len() as libc::c_uint) as usize} ++ } ++ ++ #[cfg(not(any(target_os = "android", ++ all(target_os = "linux", not(target_env = "musl")))))] ++ fn cmsg_len(&self) -> libc::c_uint { ++ unsafe{CMSG_LEN(self.len() as libc::c_uint)} ++ } ++ ++ /// Return a reference to the payload data as a byte pointer ++ fn copy_to_cmsg_data(&self, cmsg_data: *mut u8) { ++ let data_ptr = match self { ++ &ControlMessage::ScmRights(fds) => { ++ fds as *const _ as *const u8 ++ }, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ &ControlMessage::ScmCredentials(creds) => { ++ creds as *const libc::ucred as *const u8 ++ } ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ &ControlMessage::AlgSetIv(iv) => { ++ unsafe { ++ let alg_iv = cmsg_data as *mut libc::af_alg_iv; ++ (*alg_iv).ivlen = iv.len() as u32; ++ ptr::copy_nonoverlapping( ++ iv.as_ptr(), ++ (*alg_iv).iv.as_mut_ptr(), ++ iv.len() ++ ); ++ }; ++ return ++ }, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ &ControlMessage::AlgSetOp(op) => { ++ op as *const _ as *const u8 ++ }, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ &ControlMessage::AlgSetAeadAssoclen(len) => { ++ len as *const _ as *const u8 ++ }, ++ }; ++ unsafe { ++ ptr::copy_nonoverlapping( ++ data_ptr, ++ cmsg_data, ++ self.len() ++ ) ++ }; ++ } ++ ++ /// The size of the payload, excluding its cmsghdr ++ fn len(&self) -> usize { ++ match self { ++ &ControlMessage::ScmRights(fds) => { ++ mem::size_of_val(fds) ++ }, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ &ControlMessage::ScmCredentials(creds) => { ++ mem::size_of_val(creds) ++ } ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ &ControlMessage::AlgSetIv(iv) => { ++ mem::size_of::<libc::af_alg_iv>() + iv.len() ++ }, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ &ControlMessage::AlgSetOp(op) => { ++ mem::size_of_val(op) ++ }, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ &ControlMessage::AlgSetAeadAssoclen(len) => { ++ mem::size_of_val(len) ++ }, ++ } ++ } ++ ++ /// Returns the value to put into the `cmsg_level` field of the header. ++ fn cmsg_level(&self) -> libc::c_int { ++ match self { ++ &ControlMessage::ScmRights(_) => libc::SOL_SOCKET, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ &ControlMessage::ScmCredentials(_) => libc::SOL_SOCKET, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ &ControlMessage::AlgSetIv(_) | &ControlMessage::AlgSetOp(_) | &ControlMessage::AlgSetAeadAssoclen(_) => { ++ libc::SOL_ALG ++ }, ++ } ++ } ++ ++ /// Returns the value to put into the `cmsg_type` field of the header. ++ fn cmsg_type(&self) -> libc::c_int { ++ match self { ++ &ControlMessage::ScmRights(_) => libc::SCM_RIGHTS, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ &ControlMessage::ScmCredentials(_) => libc::SCM_CREDENTIALS, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ &ControlMessage::AlgSetIv(_) => { ++ libc::ALG_SET_IV ++ }, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ &ControlMessage::AlgSetOp(_) => { ++ libc::ALG_SET_OP ++ }, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ &ControlMessage::AlgSetAeadAssoclen(_) => { ++ libc::ALG_SET_AEAD_ASSOCLEN ++ }, ++ } ++ } ++ ++ // Unsafe: cmsg must point to a valid cmsghdr with enough space to ++ // encode self. ++ unsafe fn encode_into(&self, cmsg: *mut cmsghdr) { ++ (*cmsg).cmsg_level = self.cmsg_level(); ++ (*cmsg).cmsg_type = self.cmsg_type(); ++ (*cmsg).cmsg_len = self.cmsg_len(); ++ self.copy_to_cmsg_data(CMSG_DATA(cmsg)); ++ } ++} ++ ++ ++/// Send data in scatter-gather vectors to a socket, possibly accompanied ++/// by ancillary data. Optionally direct the message at the given address, ++/// as with sendto. ++/// ++/// Allocates if cmsgs is nonempty. ++pub fn sendmsg(fd: RawFd, iov: &[IoVec<&[u8]>], cmsgs: &[ControlMessage], ++ flags: MsgFlags, addr: Option<&SockAddr>) -> Result<usize> ++{ ++ let capacity = cmsgs.iter().map(|c| c.space()).sum(); ++ ++ // First size the buffer needed to hold the cmsgs. It must be zeroed, ++ // because subsequent code will not clear the padding bytes. ++ let cmsg_buffer = vec![0u8; capacity]; ++ ++ // Next encode the sending address, if provided ++ let (name, namelen) = match addr { ++ Some(addr) => { ++ let (x, y) = unsafe { addr.as_ffi_pair() }; ++ (x as *const _, y) ++ }, ++ None => (ptr::null(), 0), ++ }; ++ ++ // The message header must be initialized before the individual cmsgs. ++ let cmsg_ptr = if capacity > 0 { ++ cmsg_buffer.as_ptr() as *mut c_void ++ } else { ++ ptr::null_mut() ++ }; ++ ++ let mhdr = { ++ // Musl's msghdr has private fields, so this is the only way to ++ // initialize it. ++ let mut mhdr: msghdr = unsafe{mem::uninitialized()}; ++ mhdr.msg_name = name as *mut _; ++ mhdr.msg_namelen = namelen; ++ // transmute iov into a mutable pointer. sendmsg doesn't really mutate ++ // the buffer, but the standard says that it takes a mutable pointer ++ mhdr.msg_iov = iov.as_ptr() as *mut _; ++ mhdr.msg_iovlen = iov.len() as _; ++ mhdr.msg_control = cmsg_ptr; ++ mhdr.msg_controllen = capacity as _; ++ mhdr.msg_flags = 0; ++ mhdr ++ }; ++ ++ // Encode each cmsg. This must happen after initializing the header because ++ // CMSG_NEXT_HDR and friends read the msg_control and msg_controllen fields. ++ // CMSG_FIRSTHDR is always safe ++ let mut pmhdr: *mut cmsghdr = unsafe{CMSG_FIRSTHDR(&mhdr as *const msghdr)}; ++ for cmsg in cmsgs { ++ assert_ne!(pmhdr, ptr::null_mut()); ++ // Safe because we know that pmhdr is valid, and we initialized it with ++ // sufficient space ++ unsafe { cmsg.encode_into(pmhdr) }; ++ // Safe because mhdr is valid ++ pmhdr = unsafe{CMSG_NXTHDR(&mhdr as *const msghdr, pmhdr)}; ++ } ++ ++ let ret = unsafe { libc::sendmsg(fd, &mhdr, flags.bits()) }; ++ ++ Errno::result(ret).map(|r| r as usize) ++} ++ ++/// Receive message in scatter-gather vectors from a socket, and ++/// optionally receive ancillary data into the provided buffer. ++/// If no ancillary data is desired, use () as the type parameter. ++/// ++/// # References ++/// [recvmsg(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html) ++pub fn recvmsg<'a>(fd: RawFd, iov: &[IoVec<&mut [u8]>], ++ cmsg_buffer: Option<&'a mut dyn CmsgBuffer>, ++ flags: MsgFlags) -> Result<RecvMsg<'a>> ++{ ++ let mut address: sockaddr_storage = unsafe { mem::uninitialized() }; ++ let (msg_control, msg_controllen) = match cmsg_buffer { ++ Some(cmsgspace) => { ++ let msg_buf = cmsgspace.as_bytes_mut(); ++ (msg_buf.as_mut_ptr(), msg_buf.len()) ++ }, ++ None => (ptr::null_mut(), 0), ++ }; ++ let mut mhdr = { ++ // Musl's msghdr has private fields, so this is the only way to ++ // initialize it. ++ let mut mhdr: msghdr = unsafe{mem::uninitialized()}; ++ mhdr.msg_name = &mut address as *mut sockaddr_storage as *mut c_void; ++ mhdr.msg_namelen = mem::size_of::<sockaddr_storage>() as socklen_t; ++ mhdr.msg_iov = iov.as_ptr() as *mut iovec; ++ mhdr.msg_iovlen = iov.len() as _; ++ mhdr.msg_control = msg_control as *mut c_void; ++ mhdr.msg_controllen = msg_controllen as _; ++ mhdr.msg_flags = 0; ++ mhdr ++ }; ++ ++ let ret = unsafe { libc::recvmsg(fd, &mut mhdr, flags.bits()) }; ++ ++ Errno::result(ret).map(|r| { ++ let cmsghdr = unsafe { ++ if mhdr.msg_controllen > 0 { ++ // got control message(s) ++ debug_assert!(!mhdr.msg_control.is_null()); ++ debug_assert!(msg_controllen >= mhdr.msg_controllen as usize); ++ CMSG_FIRSTHDR(&mhdr as *const msghdr) ++ } else { ++ ptr::null() ++ }.as_ref() ++ }; ++ ++ let address = unsafe { ++ sockaddr_storage_to_addr(&address, mhdr.msg_namelen as usize).ok() ++ }; ++ RecvMsg { ++ bytes: r as usize, ++ cmsghdr, ++ address, ++ flags: MsgFlags::from_bits_truncate(mhdr.msg_flags), ++ mhdr, ++ } ++ }) ++} ++ ++ ++/// Create an endpoint for communication ++/// ++/// The `protocol` specifies a particular protocol to be used with the ++/// socket. Normally only a single protocol exists to support a ++/// particular socket type within a given protocol family, in which case ++/// protocol can be specified as `None`. However, it is possible that many ++/// protocols may exist, in which case a particular protocol must be ++/// specified in this manner. ++/// ++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html) ++pub fn socket<T: Into<Option<SockProtocol>>>(domain: AddressFamily, ty: SockType, flags: SockFlag, protocol: T) -> Result<RawFd> { ++ let protocol = match protocol.into() { ++ None => 0, ++ Some(p) => p as c_int, ++ }; ++ ++ // SockFlags are usually embedded into `ty`, but we don't do that in `nix` because it's a ++ // little easier to understand by separating it out. So we have to merge these bitfields ++ // here. ++ let mut ty = ty as c_int; ++ ty |= flags.bits(); ++ ++ let res = unsafe { libc::socket(domain as c_int, ty, protocol) }; ++ ++ Errno::result(res) ++} ++ ++/// Create a pair of connected sockets ++/// ++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/socketpair.html) ++pub fn socketpair<T: Into<Option<SockProtocol>>>(domain: AddressFamily, ty: SockType, protocol: T, ++ flags: SockFlag) -> Result<(RawFd, RawFd)> { ++ let protocol = match protocol.into() { ++ None => 0, ++ Some(p) => p as c_int, ++ }; ++ ++ // SockFlags are usually embedded into `ty`, but we don't do that in `nix` because it's a ++ // little easier to understand by separating it out. So we have to merge these bitfields ++ // here. ++ let mut ty = ty as c_int; ++ ty |= flags.bits(); ++ ++ let mut fds = [-1, -1]; ++ ++ let res = unsafe { libc::socketpair(domain as c_int, ty, protocol, fds.as_mut_ptr()) }; ++ Errno::result(res)?; ++ ++ Ok((fds[0], fds[1])) ++} ++ ++/// Listen for connections on a socket ++/// ++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html) ++pub fn listen(sockfd: RawFd, backlog: usize) -> Result<()> { ++ let res = unsafe { libc::listen(sockfd, backlog as c_int) }; ++ ++ Errno::result(res).map(drop) ++} ++ ++/// Bind a name to a socket ++/// ++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html) ++pub fn bind(fd: RawFd, addr: &SockAddr) -> Result<()> { ++ let res = unsafe { ++ let (ptr, len) = addr.as_ffi_pair(); ++ libc::bind(fd, ptr, len) ++ }; ++ ++ Errno::result(res).map(drop) ++} ++ ++/// Accept a connection on a socket ++/// ++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.html) ++pub fn accept(sockfd: RawFd) -> Result<RawFd> { ++ let res = unsafe { libc::accept(sockfd, ptr::null_mut(), ptr::null_mut()) }; ++ ++ Errno::result(res) ++} ++ ++/// Accept a connection on a socket ++/// ++/// [Further reading](http://man7.org/linux/man-pages/man2/accept.2.html) ++#[cfg(any(target_os = "android", ++ target_os = "freebsd", ++ target_os = "linux", ++ target_os = "openbsd"))] ++pub fn accept4(sockfd: RawFd, flags: SockFlag) -> Result<RawFd> { ++ let res = unsafe { libc::accept4(sockfd, ptr::null_mut(), ptr::null_mut(), flags.bits()) }; ++ ++ Errno::result(res) ++} ++ ++/// Initiate a connection on a socket ++/// ++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html) ++pub fn connect(fd: RawFd, addr: &SockAddr) -> Result<()> { ++ let res = unsafe { ++ let (ptr, len) = addr.as_ffi_pair(); ++ libc::connect(fd, ptr, len) ++ }; ++ ++ Errno::result(res).map(drop) ++} ++ ++/// Receive data from a connection-oriented socket. Returns the number of ++/// bytes read ++/// ++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/recv.html) ++pub fn recv(sockfd: RawFd, buf: &mut [u8], flags: MsgFlags) -> Result<usize> { ++ unsafe { ++ let ret = libc::recv( ++ sockfd, ++ buf.as_ptr() as *mut c_void, ++ buf.len() as size_t, ++ flags.bits()); ++ ++ Errno::result(ret).map(|r| r as usize) ++ } ++} ++ ++/// Receive data from a connectionless or connection-oriented socket. Returns ++/// the number of bytes read and the socket address of the sender. ++/// ++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/recvfrom.html) ++pub fn recvfrom(sockfd: RawFd, buf: &mut [u8]) -> Result<(usize, SockAddr)> { ++ unsafe { ++ let addr: sockaddr_storage = mem::zeroed(); ++ let mut len = mem::size_of::<sockaddr_storage>() as socklen_t; ++ ++ let ret = Errno::result(libc::recvfrom( ++ sockfd, ++ buf.as_ptr() as *mut c_void, ++ buf.len() as size_t, ++ 0, ++ mem::transmute(&addr), ++ &mut len as *mut socklen_t))?; ++ ++ sockaddr_storage_to_addr(&addr, len as usize) ++ .map(|addr| (ret as usize, addr)) ++ } ++} ++ ++/// Send a message to a socket ++/// ++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html) ++pub fn sendto(fd: RawFd, buf: &[u8], addr: &SockAddr, flags: MsgFlags) -> Result<usize> { ++ let ret = unsafe { ++ let (ptr, len) = addr.as_ffi_pair(); ++ libc::sendto(fd, buf.as_ptr() as *const c_void, buf.len() as size_t, flags.bits(), ptr, len) ++ }; ++ ++ Errno::result(ret).map(|r| r as usize) ++} ++ ++/// Send data to a connection-oriented socket. Returns the number of bytes read ++/// ++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/send.html) ++pub fn send(fd: RawFd, buf: &[u8], flags: MsgFlags) -> Result<usize> { ++ let ret = unsafe { ++ libc::send(fd, buf.as_ptr() as *const c_void, buf.len() as size_t, flags.bits()) ++ }; ++ ++ Errno::result(ret).map(|r| r as usize) ++} ++ ++/* ++ * ++ * ===== Socket Options ===== ++ * ++ */ ++ ++/// The protocol level at which to get / set socket options. Used as an ++/// argument to `getsockopt` and `setsockopt`. ++/// ++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html) ++#[repr(i32)] ++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] ++pub enum SockLevel { ++ Socket = libc::SOL_SOCKET, ++ Tcp = libc::IPPROTO_TCP, ++ Ip = libc::IPPROTO_IP, ++ Ipv6 = libc::IPPROTO_IPV6, ++ Udp = libc::IPPROTO_UDP, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ Netlink = libc::SOL_NETLINK, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ Alg = libc::SOL_ALG, ++} ++ ++/// Represents a socket option that can be accessed or set. Used as an argument ++/// to `getsockopt` ++pub trait GetSockOpt : Copy { ++ type Val; ++ ++ #[doc(hidden)] ++ fn get(&self, fd: RawFd) -> Result<Self::Val>; ++} ++ ++/// Represents a socket option that can be accessed or set. Used as an argument ++/// to `setsockopt` ++pub trait SetSockOpt : Clone { ++ type Val; ++ ++ #[doc(hidden)] ++ fn set(&self, fd: RawFd, val: &Self::Val) -> Result<()>; ++} ++ ++/// Get the current value for the requested socket option ++/// ++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html) ++pub fn getsockopt<O: GetSockOpt>(fd: RawFd, opt: O) -> Result<O::Val> { ++ opt.get(fd) ++} ++ ++/// Sets the value for the requested socket option ++/// ++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html) ++/// ++/// # Examples ++/// ++/// ``` ++/// use nix::sys::socket::setsockopt; ++/// use nix::sys::socket::sockopt::KeepAlive; ++/// use std::net::TcpListener; ++/// use std::os::unix::io::AsRawFd; ++/// ++/// let listener = TcpListener::bind("0.0.0.0:0").unwrap(); ++/// let fd = listener.as_raw_fd(); ++/// let res = setsockopt(fd, KeepAlive, &true); ++/// assert!(res.is_ok()); ++/// ``` ++pub fn setsockopt<O: SetSockOpt>(fd: RawFd, opt: O, val: &O::Val) -> Result<()> { ++ opt.set(fd, val) ++} ++ ++/// Get the address of the peer connected to the socket `fd`. ++/// ++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpeername.html) ++pub fn getpeername(fd: RawFd) -> Result<SockAddr> { ++ unsafe { ++ let addr: sockaddr_storage = mem::uninitialized(); ++ let mut len = mem::size_of::<sockaddr_storage>() as socklen_t; ++ ++ let ret = libc::getpeername(fd, mem::transmute(&addr), &mut len); ++ ++ Errno::result(ret)?; ++ ++ sockaddr_storage_to_addr(&addr, len as usize) ++ } ++} ++ ++/// Get the current address to which the socket `fd` is bound. ++/// ++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockname.html) ++pub fn getsockname(fd: RawFd) -> Result<SockAddr> { ++ unsafe { ++ let addr: sockaddr_storage = mem::uninitialized(); ++ let mut len = mem::size_of::<sockaddr_storage>() as socklen_t; ++ ++ let ret = libc::getsockname(fd, mem::transmute(&addr), &mut len); ++ ++ Errno::result(ret)?; ++ ++ sockaddr_storage_to_addr(&addr, len as usize) ++ } ++} ++ ++/// Return the appropriate `SockAddr` type from a `sockaddr_storage` of a certain ++/// size. In C this would usually be done by casting. The `len` argument ++/// should be the number of bytes in the `sockaddr_storage` that are actually ++/// allocated and valid. It must be at least as large as all the useful parts ++/// of the structure. Note that in the case of a `sockaddr_un`, `len` need not ++/// include the terminating null. ++pub unsafe fn sockaddr_storage_to_addr( ++ addr: &sockaddr_storage, ++ len: usize) -> Result<SockAddr> { ++ ++ if len < mem::size_of_val(&addr.ss_family) { ++ return Err(Error::Sys(Errno::ENOTCONN)); ++ } ++ ++ match addr.ss_family as c_int { ++ libc::AF_INET => { ++ assert!(len as usize == mem::size_of::<sockaddr_in>()); ++ let ret = *(addr as *const _ as *const sockaddr_in); ++ Ok(SockAddr::Inet(InetAddr::V4(ret))) ++ } ++ libc::AF_INET6 => { ++ assert!(len as usize == mem::size_of::<sockaddr_in6>()); ++ Ok(SockAddr::Inet(InetAddr::V6(*(addr as *const _ as *const sockaddr_in6)))) ++ } ++ libc::AF_UNIX => { ++ let sun = *(addr as *const _ as *const sockaddr_un); ++ let pathlen = len - offset_of!(sockaddr_un, sun_path); ++ Ok(SockAddr::Unix(UnixAddr(sun, pathlen))) ++ } ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ libc::AF_NETLINK => { ++ use libc::sockaddr_nl; ++ Ok(SockAddr::Netlink(NetlinkAddr(*(addr as *const _ as *const sockaddr_nl)))) ++ } ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ libc::AF_ALG => { ++ use libc::sockaddr_alg; ++ Ok(SockAddr::Alg(AlgAddr(*(addr as *const _ as *const sockaddr_alg)))) ++ } ++ #[cfg(target_os = "linux")] ++ libc::AF_VSOCK => { ++ use libc::sockaddr_vm; ++ Ok(SockAddr::Vsock(VsockAddr(*(addr as *const _ as *const sockaddr_vm)))) ++ } ++ af => panic!("unexpected address family {}", af), ++ } ++} ++ ++ ++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] ++pub enum Shutdown { ++ /// Further receptions will be disallowed. ++ Read, ++ /// Further transmissions will be disallowed. ++ Write, ++ /// Further receptions and transmissions will be disallowed. ++ Both, ++} ++ ++/// Shut down part of a full-duplex connection. ++/// ++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/shutdown.html) ++pub fn shutdown(df: RawFd, how: Shutdown) -> Result<()> { ++ unsafe { ++ use libc::shutdown; ++ ++ let how = match how { ++ Shutdown::Read => libc::SHUT_RD, ++ Shutdown::Write => libc::SHUT_WR, ++ Shutdown::Both => libc::SHUT_RDWR, ++ }; ++ ++ Errno::result(shutdown(df, how)).map(drop) ++ } ++} +diff --git a/third_party/rust/nix-0.15.0/src/sys/socket/sockopt.rs b/third_party/rust/nix-0.15.0/src/sys/socket/sockopt.rs +new file mode 100644 +index 0000000000000..a996010018d5b +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/src/sys/socket/sockopt.rs +@@ -0,0 +1,680 @@ ++use super::{GetSockOpt, SetSockOpt}; ++use Result; ++use errno::Errno; ++use sys::time::TimeVal; ++use libc::{self, c_int, c_void, socklen_t}; ++use std::mem; ++use std::os::unix::io::RawFd; ++use std::ffi::{OsStr, OsString}; ++#[cfg(target_family = "unix")] ++use std::os::unix::ffi::OsStrExt; ++ ++// Constants ++// TCP_CA_NAME_MAX isn't defined in user space include files ++#[cfg(any(target_os = "freebsd", target_os = "linux"))] ++const TCP_CA_NAME_MAX: usize = 16; ++ ++/// Helper for implementing `SetSockOpt` for a given socket option. See ++/// [`::sys::socket::SetSockOpt`](sys/socket/trait.SetSockOpt.html). ++/// ++/// This macro aims to help implementing `SetSockOpt` for different socket options that accept ++/// different kinds of data to be used with `setsockopt`. ++/// ++/// Instead of using this macro directly consider using `sockopt_impl!`, especially if the option ++/// you are implementing represents a simple type. ++/// ++/// # Arguments ++/// ++/// * `$name:ident`: name of the type you want to implement `SetSockOpt` for. ++/// * `$level:path` : socket layer, or a `protocol level`: could be *raw sockets* ++/// (`libc::SOL_SOCKET`), *ip protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`), ++/// and more. Please refer to your system manual for more options. Will be passed as the second ++/// argument (`level`) to the `setsockopt` call. ++/// * `$flag:path`: a flag name to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`, ++/// `libc::IP_ADD_MEMBERSHIP` and others. Will be passed as the third argument (`option_name`) ++/// to the `setsockopt` call. ++/// * Type of the value that you are going to set. ++/// * Type that implements the `Set` trait for the type from the previous item (like `SetBool` for ++/// `bool`, `SetUsize` for `usize`, etc.). ++macro_rules! setsockopt_impl { ++ ($name:ident, $level:path, $flag:path, $ty:ty, $setter:ty) => { ++ impl SetSockOpt for $name { ++ type Val = $ty; ++ ++ fn set(&self, fd: RawFd, val: &$ty) -> Result<()> { ++ unsafe { ++ let setter: $setter = Set::new(val); ++ ++ let res = libc::setsockopt(fd, $level, $flag, ++ setter.ffi_ptr(), ++ setter.ffi_len()); ++ Errno::result(res).map(drop) ++ } ++ } ++ } ++ } ++} ++ ++/// Helper for implementing `GetSockOpt` for a given socket option. See ++/// [`::sys::socket::GetSockOpt`](sys/socket/trait.GetSockOpt.html). ++/// ++/// This macro aims to help implementing `GetSockOpt` for different socket options that accept ++/// different kinds of data to be use with `getsockopt`. ++/// ++/// Instead of using this macro directly consider using `sockopt_impl!`, especially if the option ++/// you are implementing represents a simple type. ++/// ++/// # Arguments ++/// ++/// * Name of the type you want to implement `GetSockOpt` for. ++/// * Socket layer, or a `protocol level`: could be *raw sockets* (`lic::SOL_SOCKET`), *ip ++/// protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`), and more. Please refer ++/// to your system manual for more options. Will be passed as the second argument (`level`) to ++/// the `getsockopt` call. ++/// * A flag to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`, ++/// `libc::SO_ORIGINAL_DST` and others. Will be passed as the third argument (`option_name`) to ++/// the `getsockopt` call. ++/// * Type of the value that you are going to get. ++/// * Type that implements the `Get` trait for the type from the previous item (`GetBool` for ++/// `bool`, `GetUsize` for `usize`, etc.). ++macro_rules! getsockopt_impl { ++ ($name:ident, $level:path, $flag:path, $ty:ty, $getter:ty) => { ++ impl GetSockOpt for $name { ++ type Val = $ty; ++ ++ fn get(&self, fd: RawFd) -> Result<$ty> { ++ unsafe { ++ let mut getter: $getter = Get::blank(); ++ ++ let res = libc::getsockopt(fd, $level, $flag, ++ getter.ffi_ptr(), ++ getter.ffi_len()); ++ Errno::result(res)?; ++ ++ Ok(getter.unwrap()) ++ } ++ } ++ } ++ } ++} ++ ++/// Helper to generate the sockopt accessors. See ++/// [`::sys::socket::GetSockOpt`](sys/socket/trait.GetSockOpt.html) and ++/// [`::sys::socket::SetSockOpt`](sys/socket/trait.SetSockOpt.html). ++/// ++/// This macro aims to help implementing `GetSockOpt` and `SetSockOpt` for different socket options ++/// that accept different kinds of data to be use with `getsockopt` and `setsockopt` respectively. ++/// ++/// Basically this macro wraps up the [`getsockopt_impl!`](macro.getsockopt_impl.html) and ++/// [`setsockopt_impl!`](macro.setsockopt_impl.html) macros. ++/// ++/// # Arguments ++/// ++/// * `GetOnly`, `SetOnly` or `Both`: whether you want to implement only getter, only setter or ++/// both of them. ++/// * `$name:ident`: name of type `GetSockOpt`/`SetSockOpt` will be implemented for. ++/// * `$level:path` : socket layer, or a `protocol level`: could be *raw sockets* ++/// (`lic::SOL_SOCKET`), *ip protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`), ++/// and more. Please refer to your system manual for more options. Will be passed as the second ++/// argument (`level`) to the `getsockopt`/`setsockopt` call. ++/// * `$flag:path`: a flag name to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`, ++/// `libc::IP_ADD_MEMBERSHIP` and others. Will be passed as the third argument (`option_name`) ++/// to the `setsockopt`/`getsockopt` call. ++/// * `$ty:ty`: type of the value that will be get/set. ++/// * `$getter:ty`: `Get` implementation; optional; only for `GetOnly` and `Both`. ++/// * `$setter:ty`: `Set` implementation; optional; only for `SetOnly` and `Both`. ++macro_rules! sockopt_impl { ++ (GetOnly, $name:ident, $level:path, $flag:path, bool) => { ++ sockopt_impl!(GetOnly, $name, $level, $flag, bool, GetBool); ++ }; ++ ++ (GetOnly, $name:ident, $level:path, $flag:path, u8) => { ++ sockopt_impl!(GetOnly, $name, $level, $flag, u8, GetU8); ++ }; ++ ++ (GetOnly, $name:ident, $level:path, $flag:path, usize) => { ++ sockopt_impl!(GetOnly, $name, $level, $flag, usize, GetUsize); ++ }; ++ ++ (SetOnly, $name:ident, $level:path, $flag:path, bool) => { ++ sockopt_impl!(SetOnly, $name, $level, $flag, bool, SetBool); ++ }; ++ ++ (SetOnly, $name:ident, $level:path, $flag:path, u8) => { ++ sockopt_impl!(SetOnly, $name, $level, $flag, u8, SetU8); ++ }; ++ ++ (SetOnly, $name:ident, $level:path, $flag:path, usize) => { ++ sockopt_impl!(SetOnly, $name, $level, $flag, usize, SetUsize); ++ }; ++ ++ (Both, $name:ident, $level:path, $flag:path, bool) => { ++ sockopt_impl!(Both, $name, $level, $flag, bool, GetBool, SetBool); ++ }; ++ ++ (Both, $name:ident, $level:path, $flag:path, u8) => { ++ sockopt_impl!(Both, $name, $level, $flag, u8, GetU8, SetU8); ++ }; ++ ++ (Both, $name:ident, $level:path, $flag:path, usize) => { ++ sockopt_impl!(Both, $name, $level, $flag, usize, GetUsize, SetUsize); ++ }; ++ ++ (Both, $name:ident, $level:path, $flag:path, OsString<$array:ty>) => { ++ sockopt_impl!(Both, $name, $level, $flag, OsString, GetOsString<$array>, SetOsString); ++ }; ++ ++ /* ++ * Matchers with generic getter types must be placed at the end, so ++ * they'll only match _after_ specialized matchers fail ++ */ ++ (GetOnly, $name:ident, $level:path, $flag:path, $ty:ty) => { ++ sockopt_impl!(GetOnly, $name, $level, $flag, $ty, GetStruct<$ty>); ++ }; ++ ++ (GetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty) => { ++ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] ++ pub struct $name; ++ ++ getsockopt_impl!($name, $level, $flag, $ty, $getter); ++ }; ++ ++ (SetOnly, $name:ident, $level:path, $flag:path, $ty:ty) => { ++ sockopt_impl!(SetOnly, $name, $level, $flag, $ty, SetStruct<$ty>); ++ }; ++ ++ (SetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $setter:ty) => { ++ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] ++ pub struct $name; ++ ++ setsockopt_impl!($name, $level, $flag, $ty, $setter); ++ }; ++ ++ (Both, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty, $setter:ty) => { ++ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] ++ pub struct $name; ++ ++ setsockopt_impl!($name, $level, $flag, $ty, $setter); ++ getsockopt_impl!($name, $level, $flag, $ty, $getter); ++ }; ++ ++ (Both, $name:ident, $level:path, $flag:path, $ty:ty) => { ++ sockopt_impl!(Both, $name, $level, $flag, $ty, GetStruct<$ty>, SetStruct<$ty>); ++ }; ++} ++ ++/* ++ * ++ * ===== Define sockopts ===== ++ * ++ */ ++ ++sockopt_impl!(Both, ReuseAddr, libc::SOL_SOCKET, libc::SO_REUSEADDR, bool); ++sockopt_impl!(Both, ReusePort, libc::SOL_SOCKET, libc::SO_REUSEPORT, bool); ++sockopt_impl!(Both, TcpNoDelay, libc::IPPROTO_TCP, libc::TCP_NODELAY, bool); ++sockopt_impl!(Both, Linger, libc::SOL_SOCKET, libc::SO_LINGER, libc::linger); ++sockopt_impl!(SetOnly, IpAddMembership, libc::IPPROTO_IP, libc::IP_ADD_MEMBERSHIP, super::IpMembershipRequest); ++sockopt_impl!(SetOnly, IpDropMembership, libc::IPPROTO_IP, libc::IP_DROP_MEMBERSHIP, super::IpMembershipRequest); ++cfg_if! { ++ if #[cfg(any(target_os = "android", target_os = "linux"))] { ++ sockopt_impl!(SetOnly, Ipv6AddMembership, libc::IPPROTO_IPV6, libc::IPV6_ADD_MEMBERSHIP, super::Ipv6MembershipRequest); ++ sockopt_impl!(SetOnly, Ipv6DropMembership, libc::IPPROTO_IPV6, libc::IPV6_DROP_MEMBERSHIP, super::Ipv6MembershipRequest); ++ } else if #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] { ++ sockopt_impl!(SetOnly, Ipv6AddMembership, libc::IPPROTO_IPV6, libc::IPV6_JOIN_GROUP, super::Ipv6MembershipRequest); ++ sockopt_impl!(SetOnly, Ipv6DropMembership, libc::IPPROTO_IPV6, libc::IPV6_LEAVE_GROUP, super::Ipv6MembershipRequest); ++ } ++} ++sockopt_impl!(Both, IpMulticastTtl, libc::IPPROTO_IP, libc::IP_MULTICAST_TTL, u8); ++sockopt_impl!(Both, IpMulticastLoop, libc::IPPROTO_IP, libc::IP_MULTICAST_LOOP, bool); ++sockopt_impl!(Both, ReceiveTimeout, libc::SOL_SOCKET, libc::SO_RCVTIMEO, TimeVal); ++sockopt_impl!(Both, SendTimeout, libc::SOL_SOCKET, libc::SO_SNDTIMEO, TimeVal); ++sockopt_impl!(Both, Broadcast, libc::SOL_SOCKET, libc::SO_BROADCAST, bool); ++sockopt_impl!(Both, OobInline, libc::SOL_SOCKET, libc::SO_OOBINLINE, bool); ++sockopt_impl!(GetOnly, SocketError, libc::SOL_SOCKET, libc::SO_ERROR, i32); ++sockopt_impl!(Both, KeepAlive, libc::SOL_SOCKET, libc::SO_KEEPALIVE, bool); ++#[cfg(any(target_os = "android", target_os = "linux"))] ++sockopt_impl!(GetOnly, PeerCredentials, libc::SOL_SOCKET, libc::SO_PEERCRED, super::UnixCredentials); ++#[cfg(any(target_os = "ios", ++ target_os = "macos"))] ++sockopt_impl!(Both, TcpKeepAlive, libc::IPPROTO_TCP, libc::TCP_KEEPALIVE, u32); ++#[cfg(any(target_os = "android", ++ target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "linux", ++ target_os = "nacl"))] ++sockopt_impl!(Both, TcpKeepIdle, libc::IPPROTO_TCP, libc::TCP_KEEPIDLE, u32); ++sockopt_impl!(Both, RcvBuf, libc::SOL_SOCKET, libc::SO_RCVBUF, usize); ++sockopt_impl!(Both, SndBuf, libc::SOL_SOCKET, libc::SO_SNDBUF, usize); ++#[cfg(any(target_os = "android", target_os = "linux"))] ++sockopt_impl!(SetOnly, RcvBufForce, libc::SOL_SOCKET, libc::SO_RCVBUFFORCE, usize); ++#[cfg(any(target_os = "android", target_os = "linux"))] ++sockopt_impl!(SetOnly, SndBufForce, libc::SOL_SOCKET, libc::SO_SNDBUFFORCE, usize); ++sockopt_impl!(GetOnly, SockType, libc::SOL_SOCKET, libc::SO_TYPE, super::SockType); ++sockopt_impl!(GetOnly, AcceptConn, libc::SOL_SOCKET, libc::SO_ACCEPTCONN, bool); ++#[cfg(any(target_os = "android", target_os = "linux"))] ++sockopt_impl!(GetOnly, OriginalDst, libc::SOL_IP, libc::SO_ORIGINAL_DST, libc::sockaddr_in); ++sockopt_impl!(Both, ReceiveTimestamp, libc::SOL_SOCKET, libc::SO_TIMESTAMP, bool); ++#[cfg(any(target_os = "android", target_os = "linux"))] ++sockopt_impl!(Both, IpTransparent, libc::SOL_IP, libc::IP_TRANSPARENT, bool); ++#[cfg(target_os = "openbsd")] ++sockopt_impl!(Both, BindAny, libc::SOL_SOCKET, libc::SO_BINDANY, bool); ++#[cfg(target_os = "freebsd")] ++sockopt_impl!(Both, BindAny, libc::IPPROTO_IP, libc::IP_BINDANY, bool); ++#[cfg(target_os = "linux")] ++sockopt_impl!(Both, Mark, libc::SOL_SOCKET, libc::SO_MARK, u32); ++#[cfg(any(target_os = "android", target_os = "linux"))] ++sockopt_impl!(Both, PassCred, libc::SOL_SOCKET, libc::SO_PASSCRED, bool); ++#[cfg(any(target_os = "freebsd", target_os = "linux"))] ++sockopt_impl!(Both, TcpCongestion, libc::IPPROTO_TCP, libc::TCP_CONGESTION, OsString<[u8; TCP_CA_NAME_MAX]>); ++#[cfg(any( ++ target_os = "android", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos", ++ target_os = "netbsd", ++))] ++sockopt_impl!(Both, Ipv4PacketInfo, libc::IPPROTO_IP, libc::IP_PKTINFO, bool); ++#[cfg(any( ++ target_os = "android", ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd", ++))] ++sockopt_impl!(Both, Ipv6RecvPacketInfo, libc::IPPROTO_IPV6, libc::IPV6_RECVPKTINFO, bool); ++#[cfg(any( ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd", ++))] ++sockopt_impl!(Both, Ipv4RecvIf, libc::IPPROTO_IP, libc::IP_RECVIF, bool); ++#[cfg(any( ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd", ++))] ++sockopt_impl!(Both, Ipv4RecvDstAddr, libc::IPPROTO_IP, libc::IP_RECVDSTADDR, bool); ++ ++ ++#[cfg(any(target_os = "android", target_os = "linux"))] ++#[derive(Copy, Clone, Debug)] ++pub struct AlgSetAeadAuthSize; ++ ++// ALG_SET_AEAD_AUTH_SIZE read the length from passed `option_len` ++// See https://elixir.bootlin.com/linux/v4.4/source/crypto/af_alg.c#L222 ++#[cfg(any(target_os = "android", target_os = "linux"))] ++impl SetSockOpt for AlgSetAeadAuthSize { ++ type Val = usize; ++ ++ fn set(&self, fd: RawFd, val: &usize) -> Result<()> { ++ unsafe { ++ let res = libc::setsockopt(fd, ++ libc::SOL_ALG, ++ libc::ALG_SET_AEAD_AUTHSIZE, ++ ::std::ptr::null(), ++ *val as libc::socklen_t); ++ Errno::result(res).map(drop) ++ } ++ } ++} ++ ++#[cfg(any(target_os = "android", target_os = "linux"))] ++#[derive(Clone, Debug)] ++pub struct AlgSetKey<T>(::std::marker::PhantomData<T>); ++ ++#[cfg(any(target_os = "android", target_os = "linux"))] ++impl<T> Default for AlgSetKey<T> { ++ fn default() -> Self { ++ AlgSetKey(Default::default()) ++ } ++} ++ ++#[cfg(any(target_os = "android", target_os = "linux"))] ++impl<T> SetSockOpt for AlgSetKey<T> where T: AsRef<[u8]> + Clone { ++ type Val = T; ++ ++ fn set(&self, fd: RawFd, val: &T) -> Result<()> { ++ unsafe { ++ let res = libc::setsockopt(fd, ++ libc::SOL_ALG, ++ libc::ALG_SET_KEY, ++ val.as_ref().as_ptr() as *const _, ++ val.as_ref().len() as libc::socklen_t); ++ Errno::result(res).map(drop) ++ } ++ } ++} ++ ++/* ++ * ++ * ===== Accessor helpers ===== ++ * ++ */ ++ ++/// Helper trait that describes what is expected from a `GetSockOpt` getter. ++unsafe trait Get<T> { ++ /// Returns an empty value. ++ unsafe fn blank() -> Self; ++ /// Returns a pointer to the stored value. This pointer will be passed to the system's ++ /// `getsockopt` call (`man 3p getsockopt`, argument `option_value`). ++ fn ffi_ptr(&mut self) -> *mut c_void; ++ /// Returns length of the stored value. This pointer will be passed to the system's ++ /// `getsockopt` call (`man 3p getsockopt`, argument `option_len`). ++ fn ffi_len(&mut self) -> *mut socklen_t; ++ /// Returns the stored value. ++ unsafe fn unwrap(self) -> T; ++} ++ ++/// Helper trait that describes what is expected from a `SetSockOpt` setter. ++unsafe trait Set<'a, T> { ++ /// Initialize the setter with a given value. ++ fn new(val: &'a T) -> Self; ++ /// Returns a pointer to the stored value. This pointer will be passed to the system's ++ /// `setsockopt` call (`man 3p setsockopt`, argument `option_value`). ++ fn ffi_ptr(&self) -> *const c_void; ++ /// Returns length of the stored value. This pointer will be passed to the system's ++ /// `setsockopt` call (`man 3p setsockopt`, argument `option_len`). ++ fn ffi_len(&self) -> socklen_t; ++} ++ ++/// Getter for an arbitrary `struct`. ++struct GetStruct<T> { ++ len: socklen_t, ++ val: T, ++} ++ ++unsafe impl<T> Get<T> for GetStruct<T> { ++ unsafe fn blank() -> Self { ++ GetStruct { ++ len: mem::size_of::<T>() as socklen_t, ++ val: mem::zeroed(), ++ } ++ } ++ ++ fn ffi_ptr(&mut self) -> *mut c_void { ++ &mut self.val as *mut T as *mut c_void ++ } ++ ++ fn ffi_len(&mut self) -> *mut socklen_t { ++ &mut self.len ++ } ++ ++ unsafe fn unwrap(self) -> T { ++ assert!(self.len as usize == mem::size_of::<T>(), "invalid getsockopt implementation"); ++ self.val ++ } ++} ++ ++/// Setter for an arbitrary `struct`. ++struct SetStruct<'a, T: 'static> { ++ ptr: &'a T, ++} ++ ++unsafe impl<'a, T> Set<'a, T> for SetStruct<'a, T> { ++ fn new(ptr: &'a T) -> SetStruct<'a, T> { ++ SetStruct { ptr: ptr } ++ } ++ ++ fn ffi_ptr(&self) -> *const c_void { ++ self.ptr as *const T as *const c_void ++ } ++ ++ fn ffi_len(&self) -> socklen_t { ++ mem::size_of::<T>() as socklen_t ++ } ++} ++ ++/// Getter for a boolean value. ++struct GetBool { ++ len: socklen_t, ++ val: c_int, ++} ++ ++unsafe impl Get<bool> for GetBool { ++ unsafe fn blank() -> Self { ++ GetBool { ++ len: mem::size_of::<c_int>() as socklen_t, ++ val: mem::zeroed(), ++ } ++ } ++ ++ fn ffi_ptr(&mut self) -> *mut c_void { ++ &mut self.val as *mut c_int as *mut c_void ++ } ++ ++ fn ffi_len(&mut self) -> *mut socklen_t { ++ &mut self.len ++ } ++ ++ unsafe fn unwrap(self) -> bool { ++ assert!(self.len as usize == mem::size_of::<c_int>(), "invalid getsockopt implementation"); ++ self.val != 0 ++ } ++} ++ ++/// Setter for a boolean value. ++struct SetBool { ++ val: c_int, ++} ++ ++unsafe impl<'a> Set<'a, bool> for SetBool { ++ fn new(val: &'a bool) -> SetBool { ++ SetBool { val: if *val { 1 } else { 0 } } ++ } ++ ++ fn ffi_ptr(&self) -> *const c_void { ++ &self.val as *const c_int as *const c_void ++ } ++ ++ fn ffi_len(&self) -> socklen_t { ++ mem::size_of::<c_int>() as socklen_t ++ } ++} ++ ++/// Getter for an `u8` value. ++struct GetU8 { ++ len: socklen_t, ++ val: u8, ++} ++ ++unsafe impl Get<u8> for GetU8 { ++ unsafe fn blank() -> Self { ++ GetU8 { ++ len: mem::size_of::<u8>() as socklen_t, ++ val: mem::zeroed(), ++ } ++ } ++ ++ fn ffi_ptr(&mut self) -> *mut c_void { ++ &mut self.val as *mut u8 as *mut c_void ++ } ++ ++ fn ffi_len(&mut self) -> *mut socklen_t { ++ &mut self.len ++ } ++ ++ unsafe fn unwrap(self) -> u8 { ++ assert!(self.len as usize == mem::size_of::<u8>(), "invalid getsockopt implementation"); ++ self.val as u8 ++ } ++} ++ ++/// Setter for an `u8` value. ++struct SetU8 { ++ val: u8, ++} ++ ++unsafe impl<'a> Set<'a, u8> for SetU8 { ++ fn new(val: &'a u8) -> SetU8 { ++ SetU8 { val: *val as u8 } ++ } ++ ++ fn ffi_ptr(&self) -> *const c_void { ++ &self.val as *const u8 as *const c_void ++ } ++ ++ fn ffi_len(&self) -> socklen_t { ++ mem::size_of::<c_int>() as socklen_t ++ } ++} ++ ++/// Getter for an `usize` value. ++struct GetUsize { ++ len: socklen_t, ++ val: c_int, ++} ++ ++unsafe impl Get<usize> for GetUsize { ++ unsafe fn blank() -> Self { ++ GetUsize { ++ len: mem::size_of::<c_int>() as socklen_t, ++ val: mem::zeroed(), ++ } ++ } ++ ++ fn ffi_ptr(&mut self) -> *mut c_void { ++ &mut self.val as *mut c_int as *mut c_void ++ } ++ ++ fn ffi_len(&mut self) -> *mut socklen_t { ++ &mut self.len ++ } ++ ++ unsafe fn unwrap(self) -> usize { ++ assert!(self.len as usize == mem::size_of::<c_int>(), "invalid getsockopt implementation"); ++ self.val as usize ++ } ++} ++ ++/// Setter for an `usize` value. ++struct SetUsize { ++ val: c_int, ++} ++ ++unsafe impl<'a> Set<'a, usize> for SetUsize { ++ fn new(val: &'a usize) -> SetUsize { ++ SetUsize { val: *val as c_int } ++ } ++ ++ fn ffi_ptr(&self) -> *const c_void { ++ &self.val as *const c_int as *const c_void ++ } ++ ++ fn ffi_len(&self) -> socklen_t { ++ mem::size_of::<c_int>() as socklen_t ++ } ++} ++ ++/// Getter for a `OsString` value. ++struct GetOsString<T: AsMut<[u8]>> { ++ len: socklen_t, ++ val: T, ++} ++ ++unsafe impl<T: AsMut<[u8]>> Get<OsString> for GetOsString<T> { ++ unsafe fn blank() -> Self { ++ GetOsString { ++ len: mem::size_of::<T>() as socklen_t, ++ val: mem::zeroed(), ++ } ++ } ++ ++ fn ffi_ptr(&mut self) -> *mut c_void { ++ &mut self.val as *mut T as *mut c_void ++ } ++ ++ fn ffi_len(&mut self) -> *mut socklen_t { ++ &mut self.len ++ } ++ ++ unsafe fn unwrap(mut self) -> OsString { ++ OsStr::from_bytes(self.val.as_mut()).to_owned() ++ } ++} ++ ++/// Setter for a `OsString` value. ++struct SetOsString<'a> { ++ val: &'a OsStr, ++} ++ ++unsafe impl<'a> Set<'a, OsString> for SetOsString<'a> { ++ fn new(val: &'a OsString) -> SetOsString { ++ SetOsString { val: val.as_os_str() } ++ } ++ ++ fn ffi_ptr(&self) -> *const c_void { ++ self.val.as_bytes().as_ptr() as *const c_void ++ } ++ ++ fn ffi_len(&self) -> socklen_t { ++ self.val.len() as socklen_t ++ } ++} ++ ++ ++#[cfg(test)] ++mod test { ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ #[test] ++ fn can_get_peercred_on_unix_socket() { ++ use super::super::*; ++ ++ let (a, b) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()).unwrap(); ++ let a_cred = getsockopt(a, super::PeerCredentials).unwrap(); ++ let b_cred = getsockopt(b, super::PeerCredentials).unwrap(); ++ assert_eq!(a_cred, b_cred); ++ assert!(a_cred.pid() != 0); ++ } ++ ++ #[test] ++ fn is_socket_type_unix() { ++ use super::super::*; ++ use ::unistd::close; ++ ++ let (a, b) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()).unwrap(); ++ let a_type = getsockopt(a, super::SockType).unwrap(); ++ assert!(a_type == SockType::Stream); ++ close(a).unwrap(); ++ close(b).unwrap(); ++ } ++ ++ #[test] ++ fn is_socket_type_dgram() { ++ use super::super::*; ++ use ::unistd::close; ++ ++ let s = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), None).unwrap(); ++ let s_type = getsockopt(s, super::SockType).unwrap(); ++ assert!(s_type == SockType::Datagram); ++ close(s).unwrap(); ++ } ++ ++ #[cfg(any(target_os = "freebsd", ++ target_os = "linux", ++ target_os = "nacl"))] ++ #[test] ++ fn can_get_listen_on_tcp_socket() { ++ use super::super::*; ++ use ::unistd::close; ++ ++ let s = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap(); ++ let s_listening = getsockopt(s, super::AcceptConn).unwrap(); ++ assert!(!s_listening); ++ listen(s, 10).unwrap(); ++ let s_listening2 = getsockopt(s, super::AcceptConn).unwrap(); ++ assert!(s_listening2); ++ close(s).unwrap(); ++ } ++ ++} +diff --git a/third_party/rust/nix-0.15.0/src/sys/stat.rs b/third_party/rust/nix-0.15.0/src/sys/stat.rs +new file mode 100644 +index 0000000000000..66c8c9dd1b720 +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/src/sys/stat.rs +@@ -0,0 +1,294 @@ ++pub use libc::{dev_t, mode_t}; ++pub use libc::stat as FileStat; ++ ++use {Result, NixPath}; ++use errno::Errno; ++use fcntl::{AtFlags, at_rawfd}; ++use libc; ++use std::mem; ++use std::os::unix::io::RawFd; ++use sys::time::{TimeSpec, TimeVal}; ++ ++libc_bitflags!( ++ pub struct SFlag: mode_t { ++ S_IFIFO; ++ S_IFCHR; ++ S_IFDIR; ++ S_IFBLK; ++ S_IFREG; ++ S_IFLNK; ++ S_IFSOCK; ++ S_IFMT; ++ } ++); ++ ++libc_bitflags! { ++ pub struct Mode: mode_t { ++ S_IRWXU; ++ S_IRUSR; ++ S_IWUSR; ++ S_IXUSR; ++ S_IRWXG; ++ S_IRGRP; ++ S_IWGRP; ++ S_IXGRP; ++ S_IRWXO; ++ S_IROTH; ++ S_IWOTH; ++ S_IXOTH; ++ S_ISUID as mode_t; ++ S_ISGID as mode_t; ++ S_ISVTX as mode_t; ++ } ++} ++ ++pub fn mknod<P: ?Sized + NixPath>(path: &P, kind: SFlag, perm: Mode, dev: dev_t) -> Result<()> { ++ let res = path.with_nix_path(|cstr| { ++ unsafe { ++ libc::mknod(cstr.as_ptr(), kind.bits | perm.bits() as mode_t, dev) ++ } ++ })?; ++ ++ Errno::result(res).map(drop) ++} ++ ++#[cfg(target_os = "linux")] ++pub fn major(dev: dev_t) -> u64 { ++ ((dev >> 32) & 0xffff_f000) | ++ ((dev >> 8) & 0x0000_0fff) ++} ++ ++#[cfg(target_os = "linux")] ++pub fn minor(dev: dev_t) -> u64 { ++ ((dev >> 12) & 0xffff_ff00) | ++ ((dev ) & 0x0000_00ff) ++} ++ ++#[cfg(target_os = "linux")] ++pub fn makedev(major: u64, minor: u64) -> dev_t { ++ ((major & 0xffff_f000) << 32) | ++ ((major & 0x0000_0fff) << 8) | ++ ((minor & 0xffff_ff00) << 12) | ++ (minor & 0x0000_00ff) ++} ++ ++pub fn umask(mode: Mode) -> Mode { ++ let prev = unsafe { libc::umask(mode.bits() as mode_t) }; ++ Mode::from_bits(prev).expect("[BUG] umask returned invalid Mode") ++} ++ ++pub fn stat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> { ++ let mut dst = unsafe { mem::uninitialized() }; ++ let res = path.with_nix_path(|cstr| { ++ unsafe { ++ libc::stat(cstr.as_ptr(), &mut dst as *mut FileStat) ++ } ++ })?; ++ ++ Errno::result(res)?; ++ ++ Ok(dst) ++} ++ ++pub fn lstat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> { ++ let mut dst = unsafe { mem::uninitialized() }; ++ let res = path.with_nix_path(|cstr| { ++ unsafe { ++ libc::lstat(cstr.as_ptr(), &mut dst as *mut FileStat) ++ } ++ })?; ++ ++ Errno::result(res)?; ++ ++ Ok(dst) ++} ++ ++pub fn fstat(fd: RawFd) -> Result<FileStat> { ++ let mut dst = unsafe { mem::uninitialized() }; ++ let res = unsafe { libc::fstat(fd, &mut dst as *mut FileStat) }; ++ ++ Errno::result(res)?; ++ ++ Ok(dst) ++} ++ ++pub fn fstatat<P: ?Sized + NixPath>(dirfd: RawFd, pathname: &P, f: AtFlags) -> Result<FileStat> { ++ let mut dst = unsafe { mem::uninitialized() }; ++ let res = pathname.with_nix_path(|cstr| { ++ unsafe { libc::fstatat(dirfd, cstr.as_ptr(), &mut dst as *mut FileStat, f.bits() as libc::c_int) } ++ })?; ++ ++ Errno::result(res)?; ++ ++ Ok(dst) ++} ++ ++/// Change the file permission bits of the file specified by a file descriptor. ++/// ++/// # References ++/// ++/// [fchmod(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmod.html). ++pub fn fchmod(fd: RawFd, mode: Mode) -> Result<()> { ++ let res = unsafe { libc::fchmod(fd, mode.bits() as mode_t) }; ++ ++ Errno::result(res).map(drop) ++} ++ ++/// Flags for `fchmodat` function. ++#[derive(Clone, Copy, Debug)] ++pub enum FchmodatFlags { ++ FollowSymlink, ++ NoFollowSymlink, ++} ++ ++/// Change the file permission bits. ++/// ++/// The file to be changed is determined relative to the directory associated ++/// with the file descriptor `dirfd` or the current working directory ++/// if `dirfd` is `None`. ++/// ++/// If `flag` is `FchmodatFlags::NoFollowSymlink` and `path` names a symbolic link, ++/// then the mode of the symbolic link is changed. ++/// ++/// `fchmod(None, path, mode, FchmodatFlags::FollowSymlink)` is identical to ++/// a call `libc::chmod(path, mode)`. That's why `chmod` is unimplemented ++/// in the `nix` crate. ++/// ++/// # References ++/// ++/// [fchmodat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmodat.html). ++pub fn fchmodat<P: ?Sized + NixPath>( ++ dirfd: Option<RawFd>, ++ path: &P, ++ mode: Mode, ++ flag: FchmodatFlags, ++) -> Result<()> { ++ let atflag = ++ match flag { ++ FchmodatFlags::FollowSymlink => AtFlags::empty(), ++ FchmodatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW, ++ }; ++ let res = path.with_nix_path(|cstr| unsafe { ++ libc::fchmodat( ++ at_rawfd(dirfd), ++ cstr.as_ptr(), ++ mode.bits() as mode_t, ++ atflag.bits() as libc::c_int, ++ ) ++ })?; ++ ++ Errno::result(res).map(drop) ++} ++ ++/// Change the access and modification times of a file. ++/// ++/// `utimes(path, times)` is identical to ++/// `utimensat(None, path, times, UtimensatFlags::FollowSymlink)`. The former ++/// is a deprecated API so prefer using the latter if the platforms you care ++/// about support it. ++/// ++/// # References ++/// ++/// [utimes(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/utimes.html). ++pub fn utimes<P: ?Sized + NixPath>(path: &P, atime: &TimeVal, mtime: &TimeVal) -> Result<()> { ++ let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()]; ++ let res = path.with_nix_path(|cstr| unsafe { ++ libc::utimes(cstr.as_ptr(), ×[0]) ++ })?; ++ ++ Errno::result(res).map(drop) ++} ++ ++/// Change the access and modification times of a file without following symlinks. ++/// ++/// `lutimes(path, times)` is identical to ++/// `utimensat(None, path, times, UtimensatFlags::NoFollowSymlink)`. The former ++/// is a deprecated API so prefer using the latter if the platforms you care ++/// about support it. ++/// ++/// # References ++/// ++/// [lutimes(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/lutimes.html). ++#[cfg(any(target_os = "linux", ++ target_os = "haiku", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "freebsd", ++ target_os = "netbsd"))] ++pub fn lutimes<P: ?Sized + NixPath>(path: &P, atime: &TimeVal, mtime: &TimeVal) -> Result<()> { ++ let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()]; ++ let res = path.with_nix_path(|cstr| unsafe { ++ libc::lutimes(cstr.as_ptr(), ×[0]) ++ })?; ++ ++ Errno::result(res).map(drop) ++} ++ ++/// Change the access and modification times of the file specified by a file descriptor. ++/// ++/// # References ++/// ++/// [futimens(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html). ++#[inline] ++pub fn futimens(fd: RawFd, atime: &TimeSpec, mtime: &TimeSpec) -> Result<()> { ++ let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()]; ++ let res = unsafe { libc::futimens(fd, ×[0]) }; ++ ++ Errno::result(res).map(drop) ++} ++ ++/// Flags for `utimensat` function. ++#[derive(Clone, Copy, Debug)] ++pub enum UtimensatFlags { ++ FollowSymlink, ++ NoFollowSymlink, ++} ++ ++/// Change the access and modification times of a file. ++/// ++/// The file to be changed is determined relative to the directory associated ++/// with the file descriptor `dirfd` or the current working directory ++/// if `dirfd` is `None`. ++/// ++/// If `flag` is `UtimensatFlags::NoFollowSymlink` and `path` names a symbolic link, ++/// then the mode of the symbolic link is changed. ++/// ++/// `utimensat(None, path, times, UtimensatFlags::FollowSymlink)` is identical to ++/// `utimes(path, times)`. The latter is a deprecated API so prefer using the ++/// former if the platforms you care about support it. ++/// ++/// # References ++/// ++/// [utimensat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/utimens.html). ++pub fn utimensat<P: ?Sized + NixPath>( ++ dirfd: Option<RawFd>, ++ path: &P, ++ atime: &TimeSpec, ++ mtime: &TimeSpec, ++ flag: UtimensatFlags ++) -> Result<()> { ++ let atflag = ++ match flag { ++ UtimensatFlags::FollowSymlink => AtFlags::empty(), ++ UtimensatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW, ++ }; ++ let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()]; ++ let res = path.with_nix_path(|cstr| unsafe { ++ libc::utimensat( ++ at_rawfd(dirfd), ++ cstr.as_ptr(), ++ ×[0], ++ atflag.bits() as libc::c_int, ++ ) ++ })?; ++ ++ Errno::result(res).map(drop) ++} ++ ++pub fn mkdirat<P: ?Sized + NixPath>(fd: RawFd, path: &P, mode: Mode) -> Result<()> { ++ let res = path.with_nix_path(|cstr| { ++ unsafe { libc::mkdirat(fd, cstr.as_ptr(), mode.bits() as mode_t) } ++ })?; ++ ++ Errno::result(res).map(drop) ++} +diff --git a/third_party/rust/nix-0.15.0/src/sys/statfs.rs b/third_party/rust/nix-0.15.0/src/sys/statfs.rs +new file mode 100644 +index 0000000000000..d4596bf336958 +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/src/sys/statfs.rs +@@ -0,0 +1,548 @@ ++use std::fmt::{self, Debug}; ++use std::mem; ++use std::os::unix::io::AsRawFd; ++#[cfg(not(any(target_os = "linux", target_os = "android")))] ++use std::ffi::CStr; ++ ++use libc; ++ ++use {NixPath, Result}; ++use errno::Errno; ++ ++#[cfg(target_os = "android")] ++pub type fsid_t = libc::__fsid_t; ++#[cfg(not(target_os = "android"))] ++pub type fsid_t = libc::fsid_t; ++ ++#[derive(Clone, Copy)] ++pub struct Statfs(libc::statfs); ++ ++#[cfg(target_os = "freebsd")] ++#[derive(Eq, Copy, Clone, PartialEq, Debug)] ++pub struct FsType(u32); ++#[cfg(target_os = "android")] ++#[derive(Eq, Copy, Clone, PartialEq, Debug)] ++pub struct FsType(libc::c_ulong); ++#[cfg(all(target_os = "linux", target_arch = "s390x"))] ++#[derive(Eq, Copy, Clone, PartialEq, Debug)] ++pub struct FsType(u32); ++#[cfg(all(target_os = "linux", target_env = "musl"))] ++#[derive(Eq, Copy, Clone, PartialEq, Debug)] ++pub struct FsType(libc::c_ulong); ++#[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))] ++#[derive(Eq, Copy, Clone, PartialEq, Debug)] ++pub struct FsType(libc::c_long); ++ ++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))] ++pub const ADFS_SUPER_MAGIC: FsType = FsType(libc::ADFS_SUPER_MAGIC); ++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))] ++pub const AFFS_SUPER_MAGIC: FsType = FsType(libc::AFFS_SUPER_MAGIC); ++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))] ++pub const CODA_SUPER_MAGIC: FsType = FsType(libc::CODA_SUPER_MAGIC); ++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))] ++pub const CRAMFS_MAGIC: FsType = FsType(libc::CRAMFS_MAGIC); ++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))] ++pub const EFS_SUPER_MAGIC: FsType = FsType(libc::EFS_SUPER_MAGIC); ++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))] ++pub const EXT2_SUPER_MAGIC: FsType = FsType(libc::EXT2_SUPER_MAGIC); ++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))] ++pub const EXT3_SUPER_MAGIC: FsType = FsType(libc::EXT3_SUPER_MAGIC); ++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))] ++pub const EXT4_SUPER_MAGIC: FsType = FsType(libc::EXT4_SUPER_MAGIC); ++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))] ++pub const HPFS_SUPER_MAGIC: FsType = FsType(libc::HPFS_SUPER_MAGIC); ++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))] ++pub const HUGETLBFS_MAGIC: FsType = FsType(libc::HUGETLBFS_MAGIC); ++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))] ++pub const ISOFS_SUPER_MAGIC: FsType = FsType(libc::ISOFS_SUPER_MAGIC); ++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))] ++pub const JFFS2_SUPER_MAGIC: FsType = FsType(libc::JFFS2_SUPER_MAGIC); ++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))] ++pub const MINIX_SUPER_MAGIC: FsType = FsType(libc::MINIX_SUPER_MAGIC); ++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))] ++pub const MINIX_SUPER_MAGIC2: FsType = FsType(libc::MINIX_SUPER_MAGIC2); ++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))] ++pub const MINIX2_SUPER_MAGIC: FsType = FsType(libc::MINIX2_SUPER_MAGIC); ++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))] ++pub const MINIX2_SUPER_MAGIC2: FsType = FsType(libc::MINIX2_SUPER_MAGIC2); ++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))] ++pub const MSDOS_SUPER_MAGIC: FsType = FsType(libc::MSDOS_SUPER_MAGIC); ++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))] ++pub const NCP_SUPER_MAGIC: FsType = FsType(libc::NCP_SUPER_MAGIC); ++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))] ++pub const NFS_SUPER_MAGIC: FsType = FsType(libc::NFS_SUPER_MAGIC); ++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))] ++pub const OPENPROM_SUPER_MAGIC: FsType = FsType(libc::OPENPROM_SUPER_MAGIC); ++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))] ++pub const PROC_SUPER_MAGIC: FsType = FsType(libc::PROC_SUPER_MAGIC); ++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))] ++pub const QNX4_SUPER_MAGIC: FsType = FsType(libc::QNX4_SUPER_MAGIC); ++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))] ++pub const REISERFS_SUPER_MAGIC: FsType = FsType(libc::REISERFS_SUPER_MAGIC); ++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))] ++pub const SMB_SUPER_MAGIC: FsType = FsType(libc::SMB_SUPER_MAGIC); ++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))] ++pub const TMPFS_MAGIC: FsType = FsType(libc::TMPFS_MAGIC); ++#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))] ++pub const USBDEVICE_SUPER_MAGIC: FsType = FsType(libc::USBDEVICE_SUPER_MAGIC); ++ ++impl Statfs { ++ /// Magic code defining system type ++ #[cfg(not(any( ++ target_os = "openbsd", ++ target_os = "ios", ++ target_os = "macos" ++ )))] ++ pub fn filesystem_type(&self) -> FsType { ++ FsType(self.0.f_type) ++ } ++ ++ /// Magic code defining system type ++ #[cfg(not(any(target_os = "linux", target_os = "android")))] ++ pub fn filesystem_type_name(&self) -> &str { ++ let c_str = unsafe { CStr::from_ptr(self.0.f_fstypename.as_ptr()) }; ++ c_str.to_str().unwrap() ++ } ++ ++ /// Optimal transfer block size ++ #[cfg(any(target_os = "ios", target_os = "macos", target_os = "openbsd"))] ++ pub fn optimal_transfer_size(&self) -> i32 { ++ self.0.f_iosize ++ } ++ ++ /// Optimal transfer block size ++ #[cfg(all(target_os = "linux", target_arch = "s390x"))] ++ pub fn optimal_transfer_size(&self) -> u32 { ++ self.0.f_bsize ++ } ++ ++ /// Optimal transfer block size ++ #[cfg(all(target_os = "linux", target_env = "musl"))] ++ pub fn optimal_transfer_size(&self) -> libc::c_ulong { ++ self.0.f_bsize ++ } ++ ++ /// Optimal transfer block size ++ #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))] ++ pub fn optimal_transfer_size(&self) -> libc::c_long { ++ self.0.f_bsize ++ } ++ ++ /// Optimal transfer block size ++ #[cfg(target_os = "android")] ++ pub fn optimal_transfer_size(&self) -> libc::c_ulong { ++ self.0.f_bsize ++ } ++ ++ /// Optimal transfer block size ++ #[cfg(target_os = "dragonfly")] ++ pub fn optimal_transfer_size(&self) -> libc::c_long { ++ self.0.f_iosize ++ } ++ ++ /// Optimal transfer block size ++ #[cfg(target_os = "freebsd")] ++ pub fn optimal_transfer_size(&self) -> u64 { ++ self.0.f_iosize ++ } ++ ++ /// Size of a block ++ #[cfg(any(target_os = "ios", target_os = "macos", target_os = "openbsd"))] ++ pub fn block_size(&self) -> u32 { ++ self.0.f_bsize ++ } ++ ++ /// Size of a block ++ // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471 ++ #[cfg(all(target_os = "linux", target_arch = "s390x"))] ++ pub fn block_size(&self) -> u32 { ++ self.0.f_bsize ++ } ++ ++ /// Size of a block ++ // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471 ++ #[cfg(all(target_os = "linux", target_env = "musl"))] ++ pub fn block_size(&self) -> libc::c_ulong { ++ self.0.f_bsize ++ } ++ ++ /// Size of a block ++ // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471 ++ #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))] ++ pub fn block_size(&self) -> libc::c_long { ++ self.0.f_bsize ++ } ++ ++ /// Size of a block ++ #[cfg(target_os = "freebsd")] ++ pub fn block_size(&self) -> u64 { ++ self.0.f_bsize ++ } ++ ++ /// Size of a block ++ #[cfg(target_os = "android")] ++ pub fn block_size(&self) -> libc::c_ulong { ++ self.0.f_bsize ++ } ++ ++ /// Size of a block ++ #[cfg(target_os = "dragonfly")] ++ pub fn block_size(&self) -> libc::c_long { ++ self.0.f_bsize ++ } ++ ++ /// Maximum length of filenames ++ #[cfg(any(target_os = "freebsd", target_os = "openbsd"))] ++ pub fn maximum_name_length(&self) -> u32 { ++ self.0.f_namemax ++ } ++ ++ /// Maximum length of filenames ++ #[cfg(all(target_os = "linux", target_arch = "s390x"))] ++ pub fn maximum_name_length(&self) -> u32 { ++ self.0.f_namelen ++ } ++ ++ /// Maximum length of filenames ++ #[cfg(all(target_os = "linux", target_env = "musl"))] ++ pub fn maximum_name_length(&self) -> libc::c_ulong { ++ self.0.f_namelen ++ } ++ ++ /// Maximum length of filenames ++ #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))] ++ pub fn maximum_name_length(&self) -> libc::c_long { ++ self.0.f_namelen ++ } ++ ++ /// Maximum length of filenames ++ #[cfg(target_os = "android")] ++ pub fn maximum_name_length(&self) -> libc::c_ulong { ++ self.0.f_namelen ++ } ++ ++ /// Total data blocks in filesystem ++ #[cfg(any( ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "android", ++ target_os = "freebsd", ++ target_os = "openbsd", ++ ))] ++ pub fn blocks(&self) -> u64 { ++ self.0.f_blocks ++ } ++ ++ /// Total data blocks in filesystem ++ #[cfg(target_os = "dragonfly")] ++ pub fn blocks(&self) -> libc::c_long { ++ self.0.f_blocks ++ } ++ ++ /// Total data blocks in filesystem ++ #[cfg(all(target_os = "linux", target_env = "musl"))] ++ pub fn blocks(&self) -> u64 { ++ self.0.f_blocks ++ } ++ ++ /// Total data blocks in filesystem ++ #[cfg(not(any( ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "android", ++ target_os = "freebsd", ++ target_os = "openbsd", ++ target_os = "dragonfly", ++ all(target_os = "linux", target_env = "musl") ++ )))] ++ pub fn blocks(&self) -> libc::c_ulong { ++ self.0.f_blocks ++ } ++ ++ /// Free blocks in filesystem ++ #[cfg(any( ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "android", ++ target_os = "freebsd", ++ target_os = "openbsd", ++ ))] ++ pub fn blocks_free(&self) -> u64 { ++ self.0.f_bfree ++ } ++ ++ /// Free blocks in filesystem ++ #[cfg(target_os = "dragonfly")] ++ pub fn blocks_free(&self) -> libc::c_long { ++ self.0.f_bfree ++ } ++ ++ /// Free blocks in filesystem ++ #[cfg(all(target_os = "linux", target_env = "musl"))] ++ pub fn blocks_free(&self) -> u64 { ++ self.0.f_bfree ++ } ++ ++ /// Free blocks in filesystem ++ #[cfg(not(any( ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "android", ++ target_os = "freebsd", ++ target_os = "openbsd", ++ target_os = "dragonfly", ++ all(target_os = "linux", target_env = "musl") ++ )))] ++ pub fn blocks_free(&self) -> libc::c_ulong { ++ self.0.f_bfree ++ } ++ ++ /// Free blocks available to unprivileged user ++ #[cfg(any(target_os = "ios", target_os = "macos", target_os = "android"))] ++ pub fn blocks_available(&self) -> u64 { ++ self.0.f_bavail ++ } ++ ++ /// Free blocks available to unprivileged user ++ #[cfg(target_os = "dragonfly")] ++ pub fn blocks_available(&self) -> libc::c_long { ++ self.0.f_bavail ++ } ++ ++ /// Free blocks available to unprivileged user ++ #[cfg(any(target_os = "freebsd", target_os = "openbsd"))] ++ pub fn blocks_available(&self) -> i64 { ++ self.0.f_bavail ++ } ++ ++ /// Free blocks available to unprivileged user ++ #[cfg(all(target_os = "linux", target_env = "musl"))] ++ pub fn blocks_available(&self) -> u64 { ++ self.0.f_bavail ++ } ++ ++ /// Free blocks available to unprivileged user ++ #[cfg(not(any( ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "android", ++ target_os = "freebsd", ++ target_os = "openbsd", ++ target_os = "dragonfly", ++ all(target_os = "linux", target_env = "musl") ++ )))] ++ pub fn blocks_available(&self) -> libc::c_ulong { ++ self.0.f_bavail ++ } ++ ++ /// Total file nodes in filesystem ++ #[cfg(any( ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "android", ++ target_os = "freebsd", ++ target_os = "openbsd", ++ ))] ++ pub fn files(&self) -> u64 { ++ self.0.f_files ++ } ++ ++ /// Total file nodes in filesystem ++ #[cfg(target_os = "dragonfly")] ++ pub fn files(&self) -> libc::c_long { ++ self.0.f_files ++ } ++ ++ /// Total file nodes in filesystem ++ #[cfg(all(target_os = "linux", target_env = "musl"))] ++ pub fn files(&self) -> u64 { ++ self.0.f_files ++ } ++ ++ /// Total file nodes in filesystem ++ #[cfg(not(any( ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "android", ++ target_os = "freebsd", ++ target_os = "openbsd", ++ target_os = "dragonfly", ++ all(target_os = "linux", target_env = "musl") ++ )))] ++ pub fn files(&self) -> libc::c_ulong { ++ self.0.f_files ++ } ++ ++ /// Free file nodes in filesystem ++ #[cfg(any(target_os = "ios", target_os = "macos", target_os = "android"))] ++ pub fn files_free(&self) -> u64 { ++ self.0.f_ffree ++ } ++ ++ /// Free file nodes in filesystem ++ #[cfg(target_os = "dragonfly")] ++ pub fn files_free(&self) -> libc::c_long { ++ self.0.f_ffree ++ } ++ ++ /// Free file nodes in filesystem ++ #[cfg(any(target_os = "freebsd", target_os = "openbsd"))] ++ pub fn files_free(&self) -> i64 { ++ self.0.f_ffree ++ } ++ ++ /// Free file nodes in filesystem ++ #[cfg(all(target_os = "linux", target_env = "musl"))] ++ pub fn files_free(&self) -> u64 { ++ self.0.f_ffree ++ } ++ ++ /// Free file nodes in filesystem ++ #[cfg(not(any( ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "android", ++ target_os = "freebsd", ++ target_os = "openbsd", ++ target_os = "dragonfly", ++ all(target_os = "linux", target_env = "musl") ++ )))] ++ pub fn files_free(&self) -> libc::c_ulong { ++ self.0.f_ffree ++ } ++ ++ /// Filesystem ID ++ pub fn filesystem_id(&self) -> fsid_t { ++ self.0.f_fsid ++ } ++} ++ ++impl Debug for Statfs { ++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ++ f.debug_struct("Statfs") ++ .field("optimal_transfer_size", &self.optimal_transfer_size()) ++ .field("block_size", &self.block_size()) ++ .field("blocks", &self.blocks()) ++ .field("blocks_free", &self.blocks_free()) ++ .field("blocks_available", &self.blocks_available()) ++ .field("files", &self.files()) ++ .field("files_free", &self.files_free()) ++ .field("filesystem_id", &self.filesystem_id()) ++ .finish() ++ } ++} ++ ++pub fn statfs<P: ?Sized + NixPath>(path: &P) -> Result<Statfs> { ++ unsafe { ++ let mut stat: Statfs = mem::uninitialized(); ++ let res = path.with_nix_path(|path| libc::statfs(path.as_ptr(), &mut stat.0))?; ++ Errno::result(res).map(|_| stat) ++ } ++} ++ ++pub fn fstatfs<T: AsRawFd>(fd: &T) -> Result<Statfs> { ++ unsafe { ++ let mut stat: Statfs = mem::uninitialized(); ++ Errno::result(libc::fstatfs(fd.as_raw_fd(), &mut stat.0)).map(|_| stat) ++ } ++} ++ ++#[cfg(test)] ++mod test { ++ use std::fs::File; ++ ++ use sys::statfs::*; ++ use sys::statvfs::*; ++ use std::path::Path; ++ ++ #[test] ++ fn statfs_call() { ++ check_statfs("/tmp"); ++ check_statfs("/dev"); ++ check_statfs("/run"); ++ check_statfs("/"); ++ } ++ ++ #[test] ++ fn fstatfs_call() { ++ check_fstatfs("/tmp"); ++ check_fstatfs("/dev"); ++ check_fstatfs("/run"); ++ check_fstatfs("/"); ++ } ++ ++ fn check_fstatfs(path: &str) { ++ if !Path::new(path).exists() { ++ return; ++ } ++ let vfs = statvfs(path.as_bytes()).unwrap(); ++ let file = File::open(path).unwrap(); ++ let fs = fstatfs(&file).unwrap(); ++ assert_fs_equals(fs, vfs); ++ } ++ ++ fn check_statfs(path: &str) { ++ if !Path::new(path).exists() { ++ return; ++ } ++ let vfs = statvfs(path.as_bytes()).unwrap(); ++ let fs = statfs(path.as_bytes()).unwrap(); ++ assert_fs_equals(fs, vfs); ++ } ++ ++ fn assert_fs_equals(fs: Statfs, vfs: Statvfs) { ++ assert_eq!(fs.files() as u64, vfs.files() as u64); ++ assert_eq!(fs.blocks() as u64, vfs.blocks() as u64); ++ assert_eq!(fs.block_size() as u64, vfs.fragment_size() as u64); ++ } ++ ++ // This test is ignored because files_free/blocks_free can change after statvfs call and before ++ // statfs call. ++ #[test] ++ #[ignore] ++ fn statfs_call_strict() { ++ check_statfs_strict("/tmp"); ++ check_statfs_strict("/dev"); ++ check_statfs_strict("/run"); ++ check_statfs_strict("/"); ++ } ++ ++ // This test is ignored because files_free/blocks_free can change after statvfs call and before ++ // fstatfs call. ++ #[test] ++ #[ignore] ++ fn fstatfs_call_strict() { ++ check_fstatfs_strict("/tmp"); ++ check_fstatfs_strict("/dev"); ++ check_fstatfs_strict("/run"); ++ check_fstatfs_strict("/"); ++ } ++ ++ fn check_fstatfs_strict(path: &str) { ++ if !Path::new(path).exists() { ++ return; ++ } ++ let vfs = statvfs(path.as_bytes()); ++ let file = File::open(path).unwrap(); ++ let fs = fstatfs(&file); ++ assert_fs_equals_strict(fs.unwrap(), vfs.unwrap()) ++ } ++ ++ fn check_statfs_strict(path: &str) { ++ if !Path::new(path).exists() { ++ return; ++ } ++ let vfs = statvfs(path.as_bytes()); ++ let fs = statfs(path.as_bytes()); ++ assert_fs_equals_strict(fs.unwrap(), vfs.unwrap()) ++ } ++ ++ fn assert_fs_equals_strict(fs: Statfs, vfs: Statvfs) { ++ assert_eq!(fs.files_free() as u64, vfs.files_free() as u64); ++ assert_eq!(fs.blocks_free() as u64, vfs.blocks_free() as u64); ++ assert_eq!(fs.blocks_available() as u64, vfs.blocks_available() as u64); ++ assert_eq!(fs.files() as u64, vfs.files() as u64); ++ assert_eq!(fs.blocks() as u64, vfs.blocks() as u64); ++ assert_eq!(fs.block_size() as u64, vfs.fragment_size() as u64); ++ } ++} +diff --git a/third_party/rust/nix-0.15.0/src/sys/statvfs.rs b/third_party/rust/nix-0.15.0/src/sys/statvfs.rs +new file mode 100644 +index 0000000000000..e5980369d5119 +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/src/sys/statvfs.rs +@@ -0,0 +1,160 @@ ++//! Get filesystem statistics ++//! ++//! See [the man pages](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fstatvfs.html) ++//! for more details. ++use std::mem; ++use std::os::unix::io::AsRawFd; ++ ++use libc::{self, c_ulong}; ++ ++use {Result, NixPath}; ++use errno::Errno; ++ ++libc_bitflags!( ++ /// File system mount Flags ++ #[repr(C)] ++ #[derive(Default)] ++ pub struct FsFlags: c_ulong { ++ /// Read Only ++ ST_RDONLY; ++ /// Do not allow the set-uid bits to have an effect ++ ST_NOSUID; ++ /// Do not interpret character or block-special devices ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ ST_NODEV; ++ /// Do not allow execution of binaries on the filesystem ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ ST_NOEXEC; ++ /// All IO should be done synchronously ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ ST_SYNCHRONOUS; ++ /// Allow mandatory locks on the filesystem ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ ST_MANDLOCK; ++ /// Write on file/directory/symlink ++ #[cfg(target_os = "linux")] ++ ST_WRITE; ++ /// Append-only file ++ #[cfg(target_os = "linux")] ++ ST_APPEND; ++ /// Immutable file ++ #[cfg(target_os = "linux")] ++ ST_IMMUTABLE; ++ /// Do not update access times on files ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ ST_NOATIME; ++ /// Do not update access times on files ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ ST_NODIRATIME; ++ /// Update access time relative to modify/change time ++ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_env = "musl"))))] ++ ST_RELATIME; ++ } ++); ++ ++/// Wrapper around the POSIX `statvfs` struct ++/// ++/// For more information see the [`statvfs(3)` man pages](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_statvfs.h.html). ++// FIXME: Replace with repr(transparent) ++#[repr(C)] ++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] ++pub struct Statvfs(libc::statvfs); ++ ++impl Statvfs { ++ /// get the file system block size ++ pub fn block_size(&self) -> c_ulong { ++ self.0.f_bsize ++ } ++ ++ /// Get the fundamental file system block size ++ pub fn fragment_size(&self) -> c_ulong { ++ self.0.f_frsize ++ } ++ ++ /// Get the number of blocks. ++ /// ++ /// Units are in units of `fragment_size()` ++ pub fn blocks(&self) -> libc::fsblkcnt_t { ++ self.0.f_blocks ++ } ++ ++ /// Get the number of free blocks in the file system ++ pub fn blocks_free(&self) -> libc::fsblkcnt_t { ++ self.0.f_bfree ++ } ++ ++ /// Get the number of free blocks for unprivileged users ++ pub fn blocks_available(&self) -> libc::fsblkcnt_t { ++ self.0.f_bavail ++ } ++ ++ /// Get the total number of file inodes ++ pub fn files(&self) -> libc::fsfilcnt_t { ++ self.0.f_files ++ } ++ ++ /// Get the number of free file inodes ++ pub fn files_free(&self) -> libc::fsfilcnt_t { ++ self.0.f_ffree ++ } ++ ++ /// Get the number of free file inodes for unprivileged users ++ pub fn files_available(&self) -> libc::fsfilcnt_t { ++ self.0.f_favail ++ } ++ ++ /// Get the file system id ++ pub fn filesystem_id(&self) -> c_ulong { ++ self.0.f_fsid ++ } ++ ++ /// Get the mount flags ++ pub fn flags(&self) -> FsFlags { ++ FsFlags::from_bits_truncate(self.0.f_flag) ++ } ++ ++ /// Get the maximum filename length ++ pub fn name_max(&self) -> c_ulong { ++ self.0.f_namemax ++ } ++ ++} ++ ++/// Return a `Statvfs` object with information about the `path` ++pub fn statvfs<P: ?Sized + NixPath>(path: &P) -> Result<Statvfs> { ++ unsafe { ++ Errno::clear(); ++ let mut stat: Statvfs = mem::uninitialized(); ++ let res = path.with_nix_path(|path| ++ libc::statvfs(path.as_ptr(), &mut stat.0) ++ )?; ++ ++ Errno::result(res).map(|_| stat) ++ } ++} ++ ++/// Return a `Statvfs` object with information about `fd` ++pub fn fstatvfs<T: AsRawFd>(fd: &T) -> Result<Statvfs> { ++ unsafe { ++ Errno::clear(); ++ let mut stat: Statvfs = mem::uninitialized(); ++ Errno::result(libc::fstatvfs(fd.as_raw_fd(), &mut stat.0)).map(|_| stat) ++ } ++} ++ ++#[cfg(test)] ++mod test { ++ use std::fs::File; ++ use sys::statvfs::*; ++ ++ #[test] ++ fn statvfs_call() { ++ statvfs("/".as_bytes()).unwrap(); ++ } ++ ++ #[test] ++ fn fstatvfs_call() { ++ let root = File::open("/").unwrap(); ++ fstatvfs(&root).unwrap(); ++ } ++} +diff --git a/third_party/rust/nix-0.15.0/src/sys/sysinfo.rs b/third_party/rust/nix-0.15.0/src/sys/sysinfo.rs +new file mode 100644 +index 0000000000000..4c8e38988886d +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/src/sys/sysinfo.rs +@@ -0,0 +1,72 @@ ++use libc::{self, SI_LOAD_SHIFT}; ++use std::{cmp, mem}; ++use std::time::Duration; ++ ++use Result; ++use errno::Errno; ++ ++/// System info structure returned by `sysinfo`. ++#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)] ++pub struct SysInfo(libc::sysinfo); ++ ++impl SysInfo { ++ /// Returns the load average tuple. ++ /// ++ /// The returned values represent the load average over time intervals of ++ /// 1, 5, and 15 minutes, respectively. ++ pub fn load_average(&self) -> (f64, f64, f64) { ++ ( ++ self.0.loads[0] as f64 / (1 << SI_LOAD_SHIFT) as f64, ++ self.0.loads[1] as f64 / (1 << SI_LOAD_SHIFT) as f64, ++ self.0.loads[2] as f64 / (1 << SI_LOAD_SHIFT) as f64, ++ ) ++ } ++ ++ /// Returns the time since system boot. ++ pub fn uptime(&self) -> Duration { ++ // Truncate negative values to 0 ++ Duration::from_secs(cmp::max(self.0.uptime, 0) as u64) ++ } ++ ++ /// Current number of processes. ++ pub fn process_count(&self) -> u16 { ++ self.0.procs ++ } ++ ++ /// Returns the amount of swap memory in Bytes. ++ pub fn swap_total(&self) -> u64 { ++ self.scale_mem(self.0.totalswap) ++ } ++ ++ /// Returns the amount of unused swap memory in Bytes. ++ pub fn swap_free(&self) -> u64 { ++ self.scale_mem(self.0.freeswap) ++ } ++ ++ /// Returns the total amount of installed RAM in Bytes. ++ pub fn ram_total(&self) -> u64 { ++ self.scale_mem(self.0.totalram) ++ } ++ ++ /// Returns the amount of completely unused RAM in Bytes. ++ /// ++ /// "Unused" in this context means that the RAM in neither actively used by ++ /// programs, nor by the operating system as disk cache or buffer. It is ++ /// "wasted" RAM since it currently serves no purpose. ++ pub fn ram_unused(&self) -> u64 { ++ self.scale_mem(self.0.freeram) ++ } ++ ++ fn scale_mem(&self, units: libc::c_ulong) -> u64 { ++ units as u64 * self.0.mem_unit as u64 ++ } ++} ++ ++/// Returns system information. ++/// ++/// [See `sysinfo(2)`](http://man7.org/linux/man-pages/man2/sysinfo.2.html). ++pub fn sysinfo() -> Result<SysInfo> { ++ let mut info: libc::sysinfo = unsafe { mem::uninitialized() }; ++ let res = unsafe { libc::sysinfo(&mut info) }; ++ Errno::result(res).map(|_| SysInfo(info)) ++} +diff --git a/third_party/rust/nix-0.15.0/src/sys/termios.rs b/third_party/rust/nix-0.15.0/src/sys/termios.rs +new file mode 100644 +index 0000000000000..c7cdf10b461c1 +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/src/sys/termios.rs +@@ -0,0 +1,1107 @@ ++//! An interface for controlling asynchronous communication ports ++//! ++//! This interface provides a safe wrapper around the termios subsystem defined by POSIX. The ++//! underlying types are all implemented in libc for most platforms and either wrapped in safer ++//! types here or exported directly. ++//! ++//! If you are unfamiliar with the `termios` API, you should first read the ++//! [API documentation](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/termios.h.html) and ++//! then come back to understand how `nix` safely wraps it. ++//! ++//! It should be noted that this API incurs some runtime overhead above the base `libc` definitions. ++//! As this interface is not used with high-bandwidth information, this should be fine in most ++//! cases. The primary cost when using this API is that the `Termios` datatype here duplicates the ++//! standard fields of the underlying `termios` struct and uses safe type wrappers for those fields. ++//! This means that when crossing the FFI interface to the underlying C library, data is first ++//! copied into the underlying `termios` struct, then the operation is done, and the data is copied ++//! back (with additional sanity checking) into the safe wrapper types. The `termios` struct is ++//! relatively small across all platforms (on the order of 32-64 bytes). ++//! ++//! The following examples highlight some of the API use cases such that users coming from using C ++//! or reading the standard documentation will understand how to use the safe API exposed here. ++//! ++//! Example disabling processing of the end-of-file control character: ++//! ++//! ``` ++//! # use self::nix::sys::termios::SpecialCharacterIndices::VEOF; ++//! # use self::nix::sys::termios::{_POSIX_VDISABLE, Termios}; ++//! # let mut termios = unsafe { Termios::default_uninit() }; ++//! termios.control_chars[VEOF as usize] = _POSIX_VDISABLE; ++//! ``` ++//! ++//! The flags within `Termios` are defined as bitfields using the `bitflags` crate. This provides ++//! an interface for working with bitfields that is similar to working with the raw unsigned ++//! integer types but offers type safety because of the internal checking that values will always ++//! be a valid combination of the defined flags. ++//! ++//! An example showing some of the basic operations for interacting with the control flags: ++//! ++//! ``` ++//! # use self::nix::sys::termios::{ControlFlags, Termios}; ++//! # let mut termios = unsafe { Termios::default_uninit() }; ++//! termios.control_flags & ControlFlags::CSIZE == ControlFlags::CS5; ++//! termios.control_flags |= ControlFlags::CS5; ++//! ``` ++//! ++//! # Baud rates ++//! ++//! This API is not consistent across platforms when it comes to `BaudRate`: Android and Linux both ++//! only support the rates specified by the `BaudRate` enum through their termios API while the BSDs ++//! support arbitrary baud rates as the values of the `BaudRate` enum constants are the same integer ++//! value of the constant (`B9600` == `9600`). Therefore the `nix::termios` API uses the following ++//! conventions: ++//! ++//! * `cfgetispeed()` - Returns `u32` on BSDs, `BaudRate` on Android/Linux ++//! * `cfgetospeed()` - Returns `u32` on BSDs, `BaudRate` on Android/Linux ++//! * `cfsetispeed()` - Takes `u32` or `BaudRate` on BSDs, `BaudRate` on Android/Linux ++//! * `cfsetospeed()` - Takes `u32` or `BaudRate` on BSDs, `BaudRate` on Android/Linux ++//! * `cfsetspeed()` - Takes `u32` or `BaudRate` on BSDs, `BaudRate` on Android/Linux ++//! ++//! The most common use case of specifying a baud rate using the enum will work the same across ++//! platforms: ++//! ++//! ```rust ++//! # #[macro_use] extern crate nix; ++//! # use nix::sys::termios::{BaudRate, cfsetispeed, cfsetospeed, cfsetspeed, Termios}; ++//! # fn main() { ++//! # let mut t = unsafe { Termios::default_uninit() }; ++//! cfsetispeed(&mut t, BaudRate::B9600); ++//! cfsetospeed(&mut t, BaudRate::B9600); ++//! cfsetspeed(&mut t, BaudRate::B9600); ++//! # } ++//! ``` ++//! ++//! Additionally round-tripping baud rates is consistent across platforms: ++//! ++//! ```rust ++//! # extern crate nix; ++//! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetispeed, cfsetspeed, Termios}; ++//! # fn main() { ++//! # let mut t = unsafe { Termios::default_uninit() }; ++//! # cfsetspeed(&mut t, BaudRate::B9600); ++//! let speed = cfgetispeed(&t); ++//! assert!(speed == cfgetospeed(&t)); ++//! cfsetispeed(&mut t, speed); ++//! # } ++//! ``` ++//! ++//! On non-BSDs, `cfgetispeed()` and `cfgetospeed()` both return a `BaudRate`: ++//! ++// FIXME: Replace `ignore` with `compile_fail` once 1.22 is the minimum support Rust version ++#![cfg_attr(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios", ++ target_os = "macos", target_os = "netbsd", target_os = "openbsd"), ++ doc = " ```rust,ignore")] ++#![cfg_attr(not(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios", ++ target_os = "macos", target_os = "netbsd", target_os = "openbsd")), ++ doc = " ```rust")] ++//! # extern crate nix; ++//! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetspeed, Termios}; ++//! # fn main() { ++//! # let mut t = unsafe { Termios::default_uninit() }; ++//! # cfsetspeed(&mut t, BaudRate::B9600); ++//! assert!(cfgetispeed(&t) == BaudRate::B9600); ++//! assert!(cfgetospeed(&t) == BaudRate::B9600); ++//! # } ++//! ``` ++//! ++//! But on the BSDs, `cfgetispeed()` and `cfgetospeed()` both return `u32`s: ++//! ++// FIXME: Replace `ignore` with `compile_fail` once 1.22 is the minimum support Rust version ++#![cfg_attr(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios", ++ target_os = "macos", target_os = "netbsd", target_os = "openbsd"), ++ doc = " ```rust")] ++#![cfg_attr(not(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios", ++ target_os = "macos", target_os = "netbsd", target_os = "openbsd")), ++ doc = " ```rust,ignore")] ++//! # extern crate nix; ++//! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetspeed, Termios}; ++//! # fn main() { ++//! # let mut t = unsafe { Termios::default_uninit() }; ++//! # cfsetspeed(&mut t, 9600u32); ++//! assert!(cfgetispeed(&t) == 9600u32); ++//! assert!(cfgetospeed(&t) == 9600u32); ++//! # } ++//! ``` ++//! ++//! It's trivial to convert from a `BaudRate` to a `u32` on BSDs: ++//! ++// FIXME: Replace `ignore` with `compile_fail` once 1.22 is the minimum support Rust version ++#![cfg_attr(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios", ++ target_os = "macos", target_os = "netbsd", target_os = "openbsd"), ++ doc = " ```rust")] ++#![cfg_attr(not(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios", ++ target_os = "macos", target_os = "netbsd", target_os = "openbsd")), ++ doc = " ```rust,ignore")] ++//! # extern crate nix; ++//! # use nix::sys::termios::{BaudRate, cfgetispeed, cfsetspeed, Termios}; ++//! # fn main() { ++//! # let mut t = unsafe { Termios::default_uninit() }; ++//! # cfsetspeed(&mut t, 9600u32); ++//! assert!(cfgetispeed(&t) == BaudRate::B9600.into()); ++//! assert!(u32::from(BaudRate::B9600) == 9600u32); ++//! # } ++//! ``` ++//! ++//! And on BSDs you can specify arbitrary baud rates (**note** this depends on hardware support) ++//! by specifying baud rates directly using `u32`s: ++//! ++// FIXME: Replace `ignore` with `compile_fail` once 1.22 is the minimum support Rust version ++#![cfg_attr(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios", ++ target_os = "macos", target_os = "netbsd", target_os = "openbsd"), ++ doc = " ```rust")] ++#![cfg_attr(not(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios", ++ target_os = "macos", target_os = "netbsd", target_os = "openbsd")), ++ doc = " ```rust,ignore")] ++//! # extern crate nix; ++//! # use nix::sys::termios::{cfsetispeed, cfsetospeed, cfsetspeed, Termios}; ++//! # fn main() { ++//! # let mut t = unsafe { Termios::default_uninit() }; ++//! cfsetispeed(&mut t, 9600u32); ++//! cfsetospeed(&mut t, 9600u32); ++//! cfsetspeed(&mut t, 9600u32); ++//! # } ++//! ``` ++use Result; ++use errno::Errno; ++use libc::{self, c_int, tcflag_t}; ++use std::cell::{Ref, RefCell}; ++use std::convert::From; ++use std::mem; ++use std::os::unix::io::RawFd; ++ ++use ::unistd::Pid; ++ ++/// Stores settings for the termios API ++/// ++/// This is a wrapper around the `libc::termios` struct that provides a safe interface for the ++/// standard fields. The only safe way to obtain an instance of this struct is to extract it from ++/// an open port using `tcgetattr()`. ++#[derive(Clone, Debug, Eq, PartialEq)] ++pub struct Termios { ++ inner: RefCell<libc::termios>, ++ /// Input mode flags (see `termios.c_iflag` documentation) ++ pub input_flags: InputFlags, ++ /// Output mode flags (see `termios.c_oflag` documentation) ++ pub output_flags: OutputFlags, ++ /// Control mode flags (see `termios.c_cflag` documentation) ++ pub control_flags: ControlFlags, ++ /// Local mode flags (see `termios.c_lflag` documentation) ++ pub local_flags: LocalFlags, ++ /// Control characters (see `termios.c_cc` documentation) ++ pub control_chars: [libc::cc_t; NCCS], ++} ++ ++impl Termios { ++ /// Exposes an immutable reference to the underlying `libc::termios` data structure. ++ /// ++ /// This can be used for interfacing with other FFI functions like: ++ /// ++ /// ```rust ++ /// # extern crate libc; ++ /// # extern crate nix; ++ /// # fn main() { ++ /// # use nix::sys::termios::Termios; ++ /// # let mut termios = unsafe { Termios::default_uninit() }; ++ /// let inner_termios = termios.get_libc_termios(); ++ /// unsafe { libc::cfgetispeed(&*inner_termios) }; ++ /// # } ++ /// ``` ++ /// ++ /// There is no public API exposed for functions that modify the underlying `libc::termios` ++ /// data because it requires additional work to maintain type safety. ++ // FIXME: Switch this over to use pub(crate) ++ #[doc(hidden)] ++ pub fn get_libc_termios(&self) -> Ref<libc::termios> { ++ { ++ let mut termios = self.inner.borrow_mut(); ++ termios.c_iflag = self.input_flags.bits(); ++ termios.c_oflag = self.output_flags.bits(); ++ termios.c_cflag = self.control_flags.bits(); ++ termios.c_lflag = self.local_flags.bits(); ++ termios.c_cc = self.control_chars; ++ } ++ self.inner.borrow() ++ } ++ ++ /// Exposes the inner `libc::termios` datastore within `Termios`. ++ /// ++ /// This is unsafe because if this is used to modify the inner libc::termios struct, it will not ++ /// automatically update the safe wrapper type around it. Therefore we disable docs to ++ /// effectively limit its use to nix internals. In this case it should also be paired with a ++ /// call to `update_wrapper()` so that the wrapper-type and internal representation stay ++ /// consistent. ++ unsafe fn get_libc_termios_mut(&mut self) -> *mut libc::termios { ++ { ++ let mut termios = self.inner.borrow_mut(); ++ termios.c_iflag = self.input_flags.bits(); ++ termios.c_oflag = self.output_flags.bits(); ++ termios.c_cflag = self.control_flags.bits(); ++ termios.c_lflag = self.local_flags.bits(); ++ termios.c_cc = self.control_chars; ++ } ++ self.inner.as_ptr() ++ } ++ ++ /// Allows for easily creating new `Termios` structs that will be overwritten with real data. ++ /// ++ /// This should only be used when the inner libc::termios struct will be overwritten before it's ++ /// read. ++ // FIXME: Switch this over to use pub(crate) ++ #[doc(hidden)] ++ pub unsafe fn default_uninit() -> Self { ++ Termios { ++ inner: RefCell::new(mem::uninitialized()), ++ input_flags: InputFlags::empty(), ++ output_flags: OutputFlags::empty(), ++ control_flags: ControlFlags::empty(), ++ local_flags: LocalFlags::empty(), ++ control_chars: [0 as libc::cc_t; NCCS], ++ } ++ } ++ ++ /// Updates the wrapper values from the internal `libc::termios` data structure. ++ #[doc(hidden)] ++ pub fn update_wrapper(&mut self) { ++ let termios = *self.inner.borrow_mut(); ++ self.input_flags = InputFlags::from_bits_truncate(termios.c_iflag); ++ self.output_flags = OutputFlags::from_bits_truncate(termios.c_oflag); ++ self.control_flags = ControlFlags::from_bits_truncate(termios.c_cflag); ++ self.local_flags = LocalFlags::from_bits_truncate(termios.c_lflag); ++ self.control_chars = termios.c_cc; ++ } ++} ++ ++impl From<libc::termios> for Termios { ++ fn from(termios: libc::termios) -> Self { ++ Termios { ++ inner: RefCell::new(termios), ++ input_flags: InputFlags::from_bits_truncate(termios.c_iflag), ++ output_flags: OutputFlags::from_bits_truncate(termios.c_oflag), ++ control_flags: ControlFlags::from_bits_truncate(termios.c_cflag), ++ local_flags: LocalFlags::from_bits_truncate(termios.c_lflag), ++ control_chars: termios.c_cc, ++ } ++ } ++} ++ ++impl From<Termios> for libc::termios { ++ fn from(termios: Termios) -> Self { ++ termios.inner.into_inner() ++ } ++} ++ ++libc_enum!{ ++ /// Baud rates supported by the system. ++ /// ++ /// For the BSDs, arbitrary baud rates can be specified by using `u32`s directly instead of this ++ /// enum. ++ /// ++ /// B0 is special and will disable the port. ++ #[cfg_attr(all(any(target_os = "ios", target_os = "macos"), target_pointer_width = "64"), repr(u64))] ++ #[cfg_attr(not(all(any(target_os = "ios", target_os = "macos"), target_pointer_width = "64")), repr(u32))] ++ pub enum BaudRate { ++ B0, ++ B50, ++ B75, ++ B110, ++ B134, ++ B150, ++ B200, ++ B300, ++ B600, ++ B1200, ++ B1800, ++ B2400, ++ B4800, ++ #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ B7200, ++ B9600, ++ #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ B14400, ++ B19200, ++ #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ B28800, ++ B38400, ++ B57600, ++ #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ B76800, ++ B115200, ++ B230400, ++ #[cfg(any(target_os = "android", ++ target_os = "freebsd", ++ target_os = "linux", ++ target_os = "netbsd"))] ++ B460800, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ B500000, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ B576000, ++ #[cfg(any(target_os = "android", ++ target_os = "freebsd", ++ target_os = "linux", ++ target_os = "netbsd"))] ++ B921600, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ B1000000, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ B1152000, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ B1500000, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ B2000000, ++ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] ++ B2500000, ++ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] ++ B3000000, ++ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] ++ B3500000, ++ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] ++ B4000000, ++ } ++} ++ ++impl From<libc::speed_t> for BaudRate { ++ fn from(s: libc::speed_t) -> BaudRate { ++ ++ use libc::{B0, B50, B75, B110, B134, B150, B200, B300, B600, B1200, B1800, B2400, B4800, ++ B9600, B19200, B38400, B57600, B115200, B230400}; ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ use libc::{B500000, B576000, B1000000, B1152000, B1500000, B2000000}; ++ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] ++ use libc::{B2500000, B3000000, B3500000, B4000000}; ++ #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ use libc::{B7200, B14400, B28800, B76800}; ++ #[cfg(any(target_os = "android", ++ target_os = "freebsd", ++ target_os = "linux", ++ target_os = "netbsd"))] ++ use libc::{B460800, B921600}; ++ ++ match s { ++ B0 => BaudRate::B0, ++ B50 => BaudRate::B50, ++ B75 => BaudRate::B75, ++ B110 => BaudRate::B110, ++ B134 => BaudRate::B134, ++ B150 => BaudRate::B150, ++ B200 => BaudRate::B200, ++ B300 => BaudRate::B300, ++ B600 => BaudRate::B600, ++ B1200 => BaudRate::B1200, ++ B1800 => BaudRate::B1800, ++ B2400 => BaudRate::B2400, ++ B4800 => BaudRate::B4800, ++ #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ B7200 => BaudRate::B7200, ++ B9600 => BaudRate::B9600, ++ #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ B14400 => BaudRate::B14400, ++ B19200 => BaudRate::B19200, ++ #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ B28800 => BaudRate::B28800, ++ B38400 => BaudRate::B38400, ++ B57600 => BaudRate::B57600, ++ #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ B76800 => BaudRate::B76800, ++ B115200 => BaudRate::B115200, ++ B230400 => BaudRate::B230400, ++ #[cfg(any(target_os = "android", ++ target_os = "freebsd", ++ target_os = "linux", ++ target_os = "netbsd"))] ++ B460800 => BaudRate::B460800, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ B500000 => BaudRate::B500000, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ B576000 => BaudRate::B576000, ++ #[cfg(any(target_os = "android", ++ target_os = "freebsd", ++ target_os = "linux", ++ target_os = "netbsd"))] ++ B921600 => BaudRate::B921600, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ B1000000 => BaudRate::B1000000, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ B1152000 => BaudRate::B1152000, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ B1500000 => BaudRate::B1500000, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ B2000000 => BaudRate::B2000000, ++ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] ++ B2500000 => BaudRate::B2500000, ++ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] ++ B3000000 => BaudRate::B3000000, ++ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] ++ B3500000 => BaudRate::B3500000, ++ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] ++ B4000000 => BaudRate::B4000000, ++ b => unreachable!("Invalid baud constant: {}", b), ++ } ++ } ++} ++ ++// TODO: Include `TryFrom<u32> for BaudRate` once that API stabilizes ++#[cfg(any(target_os = "freebsd", ++ target_os = "dragonfly", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++impl From<BaudRate> for u32 { ++ fn from(b: BaudRate) -> u32 { ++ b as u32 ++ } ++} ++ ++// TODO: Add TCSASOFT, which will require treating this as a bitfield. ++libc_enum! { ++ /// Specify when a port configuration change should occur. ++ /// ++ /// Used as an argument to `tcsetattr()` ++ #[repr(i32)] ++ pub enum SetArg { ++ /// The change will occur immediately ++ TCSANOW, ++ /// The change occurs after all output has been written ++ TCSADRAIN, ++ /// Same as `TCSADRAIN`, but will also flush the input buffer ++ TCSAFLUSH, ++ } ++} ++ ++libc_enum! { ++ /// Specify a combination of the input and output buffers to flush ++ /// ++ /// Used as an argument to `tcflush()`. ++ #[repr(i32)] ++ pub enum FlushArg { ++ /// Flush data that was received but not read ++ TCIFLUSH, ++ /// Flush data written but not transmitted ++ TCOFLUSH, ++ /// Flush both received data not read and written data not transmitted ++ TCIOFLUSH, ++ } ++} ++ ++libc_enum! { ++ /// Specify how transmission flow should be altered ++ /// ++ /// Used as an argument to `tcflow()`. ++ #[repr(i32)] ++ pub enum FlowArg { ++ /// Suspend transmission ++ TCOOFF, ++ /// Resume transmission ++ TCOON, ++ /// Transmit a STOP character, which should disable a connected terminal device ++ TCIOFF, ++ /// Transmit a START character, which should re-enable a connected terminal device ++ TCION, ++ } ++} ++ ++// TODO: Make this usable directly as a slice index. ++libc_enum! { ++ /// Indices into the `termios.c_cc` array for special characters. ++ #[repr(usize)] ++ pub enum SpecialCharacterIndices { ++ VDISCARD, ++ #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ VDSUSP, ++ VEOF, ++ VEOL, ++ VEOL2, ++ VERASE, ++ #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] ++ VERASE2, ++ VINTR, ++ VKILL, ++ VLNEXT, ++ #[cfg(not(all(target_os = "linux", target_arch = "sparc64")))] ++ VMIN, ++ VQUIT, ++ VREPRINT, ++ VSTART, ++ #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ VSTATUS, ++ VSTOP, ++ VSUSP, ++ #[cfg(target_os = "linux")] ++ VSWTC, ++ #[cfg(target_os = "haiku")] ++ VSWTCH, ++ #[cfg(not(all(target_os = "linux", target_arch = "sparc64")))] ++ VTIME, ++ VWERASE, ++ #[cfg(target_os = "dragonfly")] ++ VCHECKPT, ++ } ++} ++ ++pub use libc::NCCS; ++#[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "linux", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++pub use libc::_POSIX_VDISABLE; ++ ++libc_bitflags! { ++ /// Flags for configuring the input mode of a terminal ++ pub struct InputFlags: tcflag_t { ++ IGNBRK; ++ BRKINT; ++ IGNPAR; ++ PARMRK; ++ INPCK; ++ ISTRIP; ++ INLCR; ++ IGNCR; ++ ICRNL; ++ IXON; ++ IXOFF; ++ IXANY; ++ IMAXBEL; ++ #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] ++ IUTF8; ++ } ++} ++ ++libc_bitflags! { ++ /// Flags for configuring the output mode of a terminal ++ pub struct OutputFlags: tcflag_t { ++ OPOST; ++ #[cfg(any(target_os = "android", ++ target_os = "haiku", ++ target_os = "linux", ++ target_os = "openbsd"))] ++ OLCUC; ++ ONLCR; ++ OCRNL as tcflag_t; ++ ONOCR as tcflag_t; ++ ONLRET as tcflag_t; ++ #[cfg(any(target_os = "android", ++ target_os = "haiku", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos"))] ++ OFILL as tcflag_t; ++ #[cfg(any(target_os = "android", ++ target_os = "haiku", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos"))] ++ OFDEL as tcflag_t; ++ #[cfg(any(target_os = "android", ++ target_os = "haiku", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos"))] ++ NL0 as tcflag_t; ++ #[cfg(any(target_os = "android", ++ target_os = "haiku", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos"))] ++ NL1 as tcflag_t; ++ #[cfg(any(target_os = "android", ++ target_os = "haiku", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos"))] ++ CR0 as tcflag_t; ++ #[cfg(any(target_os = "android", ++ target_os = "haiku", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos"))] ++ CR1 as tcflag_t; ++ #[cfg(any(target_os = "android", ++ target_os = "haiku", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos"))] ++ CR2 as tcflag_t; ++ #[cfg(any(target_os = "android", ++ target_os = "haiku", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos"))] ++ CR3 as tcflag_t; ++ #[cfg(any(target_os = "android", ++ target_os = "freebsd", ++ target_os = "haiku", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos"))] ++ TAB0 as tcflag_t; ++ #[cfg(any(target_os = "android", ++ target_os = "haiku", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos"))] ++ TAB1 as tcflag_t; ++ #[cfg(any(target_os = "android", ++ target_os = "haiku", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos"))] ++ TAB2 as tcflag_t; ++ #[cfg(any(target_os = "android", ++ target_os = "freebsd", ++ target_os = "haiku", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos"))] ++ TAB3 as tcflag_t; ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ XTABS; ++ #[cfg(any(target_os = "android", ++ target_os = "haiku", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos"))] ++ BS0 as tcflag_t; ++ #[cfg(any(target_os = "android", ++ target_os = "haiku", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos"))] ++ BS1 as tcflag_t; ++ #[cfg(any(target_os = "android", ++ target_os = "haiku", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos"))] ++ VT0 as tcflag_t; ++ #[cfg(any(target_os = "android", ++ target_os = "haiku", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos"))] ++ VT1 as tcflag_t; ++ #[cfg(any(target_os = "android", ++ target_os = "haiku", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos"))] ++ FF0 as tcflag_t; ++ #[cfg(any(target_os = "android", ++ target_os = "haiku", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos"))] ++ FF1 as tcflag_t; ++ #[cfg(any(target_os = "freebsd", ++ target_os = "dragonfly", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ OXTABS; ++ #[cfg(any(target_os = "freebsd", ++ target_os = "dragonfly", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ ONOEOT as tcflag_t; ++ ++ // Bitmasks for use with OutputFlags to select specific settings ++ // These should be moved to be a mask once https://github.com/rust-lang-nursery/bitflags/issues/110 ++ // is resolved. ++ ++ #[cfg(any(target_os = "android", ++ target_os = "haiku", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos"))] ++ NLDLY as tcflag_t; // FIXME: Datatype needs to be corrected in libc for mac ++ #[cfg(any(target_os = "android", ++ target_os = "haiku", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos"))] ++ CRDLY as tcflag_t; ++ #[cfg(any(target_os = "android", ++ target_os = "freebsd", ++ target_os = "haiku", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos"))] ++ TABDLY as tcflag_t; ++ #[cfg(any(target_os = "android", ++ target_os = "haiku", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos"))] ++ BSDLY as tcflag_t; ++ #[cfg(any(target_os = "android", ++ target_os = "haiku", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos"))] ++ VTDLY as tcflag_t; ++ #[cfg(any(target_os = "android", ++ target_os = "haiku", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos"))] ++ FFDLY as tcflag_t; ++ } ++} ++ ++libc_bitflags! { ++ /// Flags for setting the control mode of a terminal ++ pub struct ControlFlags: tcflag_t { ++ #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ CIGNORE; ++ CS5; ++ CS6; ++ CS7; ++ CS8; ++ CSTOPB; ++ CREAD; ++ PARENB; ++ PARODD; ++ HUPCL; ++ CLOCAL; ++ CRTSCTS; ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ CBAUD; ++ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "mips"))))] ++ CMSPAR; ++ #[cfg(any(target_os = "android", ++ all(target_os = "linux", ++ not(any(target_arch = "powerpc", target_arch = "powerpc64")))))] ++ CIBAUD; ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ CBAUDEX; ++ #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ MDMBUF; ++ #[cfg(any(target_os = "netbsd", target_os = "openbsd"))] ++ CHWFLOW; ++ #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ CCTS_OFLOW; ++ #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ CRTS_IFLOW; ++ #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd"))] ++ CDTR_IFLOW; ++ #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd"))] ++ CDSR_OFLOW; ++ #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd"))] ++ CCAR_OFLOW; ++ ++ // Bitmasks for use with ControlFlags to select specific settings ++ // These should be moved to be a mask once https://github.com/rust-lang-nursery/bitflags/issues/110 ++ // is resolved. ++ ++ CSIZE; ++ } ++} ++ ++libc_bitflags! { ++ /// Flags for setting any local modes ++ pub struct LocalFlags: tcflag_t { ++ ECHOKE; ++ ECHOE; ++ ECHOK; ++ ECHO; ++ ECHONL; ++ ECHOPRT; ++ ECHOCTL; ++ ISIG; ++ ICANON; ++ #[cfg(any(target_os = "freebsd", ++ target_os = "dragonfly", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ ALTWERASE; ++ IEXTEN; ++ EXTPROC; ++ TOSTOP; ++ FLUSHO; ++ #[cfg(any(target_os = "freebsd", ++ target_os = "dragonfly", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++ NOKERNINFO; ++ PENDIN; ++ NOFLSH; ++ } ++} ++ ++cfg_if!{ ++ if #[cfg(any(target_os = "freebsd", ++ target_os = "dragonfly", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] { ++ /// Get input baud rate (see ++ /// [cfgetispeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetispeed.html)). ++ /// ++ /// `cfgetispeed()` extracts the input baud rate from the given `Termios` structure. ++ pub fn cfgetispeed(termios: &Termios) -> u32 { ++ let inner_termios = termios.get_libc_termios(); ++ unsafe { libc::cfgetispeed(&*inner_termios) as u32 } ++ } ++ ++ /// Get output baud rate (see ++ /// [cfgetospeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetospeed.html)). ++ /// ++ /// `cfgetospeed()` extracts the output baud rate from the given `Termios` structure. ++ pub fn cfgetospeed(termios: &Termios) -> u32 { ++ let inner_termios = termios.get_libc_termios(); ++ unsafe { libc::cfgetospeed(&*inner_termios) as u32 } ++ } ++ ++ /// Set input baud rate (see ++ /// [cfsetispeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetispeed.html)). ++ /// ++ /// `cfsetispeed()` sets the intput baud rate in the given `Termios` structure. ++ pub fn cfsetispeed<T: Into<u32>>(termios: &mut Termios, baud: T) -> Result<()> { ++ let inner_termios = unsafe { termios.get_libc_termios_mut() }; ++ let res = unsafe { libc::cfsetispeed(inner_termios, baud.into() as libc::speed_t) }; ++ termios.update_wrapper(); ++ Errno::result(res).map(drop) ++ } ++ ++ /// Set output baud rate (see ++ /// [cfsetospeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetospeed.html)). ++ /// ++ /// `cfsetospeed()` sets the output baud rate in the given termios structure. ++ pub fn cfsetospeed<T: Into<u32>>(termios: &mut Termios, baud: T) -> Result<()> { ++ let inner_termios = unsafe { termios.get_libc_termios_mut() }; ++ let res = unsafe { libc::cfsetospeed(inner_termios, baud.into() as libc::speed_t) }; ++ termios.update_wrapper(); ++ Errno::result(res).map(drop) ++ } ++ ++ /// Set both the input and output baud rates (see ++ /// [termios(3)](https://www.freebsd.org/cgi/man.cgi?query=cfsetspeed)). ++ /// ++ /// `cfsetspeed()` sets the input and output baud rate in the given termios structure. Note that ++ /// this is part of the 4.4BSD standard and not part of POSIX. ++ pub fn cfsetspeed<T: Into<u32>>(termios: &mut Termios, baud: T) -> Result<()> { ++ let inner_termios = unsafe { termios.get_libc_termios_mut() }; ++ let res = unsafe { libc::cfsetspeed(inner_termios, baud.into() as libc::speed_t) }; ++ termios.update_wrapper(); ++ Errno::result(res).map(drop) ++ } ++ } else { ++ /// Get input baud rate (see ++ /// [cfgetispeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetispeed.html)). ++ /// ++ /// `cfgetispeed()` extracts the input baud rate from the given `Termios` structure. ++ pub fn cfgetispeed(termios: &Termios) -> BaudRate { ++ let inner_termios = termios.get_libc_termios(); ++ unsafe { libc::cfgetispeed(&*inner_termios) }.into() ++ } ++ ++ /// Get output baud rate (see ++ /// [cfgetospeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetospeed.html)). ++ /// ++ /// `cfgetospeed()` extracts the output baud rate from the given `Termios` structure. ++ pub fn cfgetospeed(termios: &Termios) -> BaudRate { ++ let inner_termios = termios.get_libc_termios(); ++ unsafe { libc::cfgetospeed(&*inner_termios) }.into() ++ } ++ ++ /// Set input baud rate (see ++ /// [cfsetispeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetispeed.html)). ++ /// ++ /// `cfsetispeed()` sets the intput baud rate in the given `Termios` structure. ++ pub fn cfsetispeed(termios: &mut Termios, baud: BaudRate) -> Result<()> { ++ let inner_termios = unsafe { termios.get_libc_termios_mut() }; ++ let res = unsafe { libc::cfsetispeed(inner_termios, baud as libc::speed_t) }; ++ termios.update_wrapper(); ++ Errno::result(res).map(drop) ++ } ++ ++ /// Set output baud rate (see ++ /// [cfsetospeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetospeed.html)). ++ /// ++ /// `cfsetospeed()` sets the output baud rate in the given `Termios` structure. ++ pub fn cfsetospeed(termios: &mut Termios, baud: BaudRate) -> Result<()> { ++ let inner_termios = unsafe { termios.get_libc_termios_mut() }; ++ let res = unsafe { libc::cfsetospeed(inner_termios, baud as libc::speed_t) }; ++ termios.update_wrapper(); ++ Errno::result(res).map(drop) ++ } ++ ++ /// Set both the input and output baud rates (see ++ /// [termios(3)](https://www.freebsd.org/cgi/man.cgi?query=cfsetspeed)). ++ /// ++ /// `cfsetspeed()` sets the input and output baud rate in the given `Termios` structure. Note that ++ /// this is part of the 4.4BSD standard and not part of POSIX. ++ pub fn cfsetspeed(termios: &mut Termios, baud: BaudRate) -> Result<()> { ++ let inner_termios = unsafe { termios.get_libc_termios_mut() }; ++ let res = unsafe { libc::cfsetspeed(inner_termios, baud as libc::speed_t) }; ++ termios.update_wrapper(); ++ Errno::result(res).map(drop) ++ } ++ } ++} ++ ++/// Configures the port to something like the "raw" mode of the old Version 7 terminal driver (see ++/// [termios(3)](http://man7.org/linux/man-pages/man3/termios.3.html)). ++/// ++/// `cfmakeraw()` configures the termios structure such that input is available character-by- ++/// character, echoing is disabled, and all special input and output processing is disabled. Note ++/// that this is a non-standard function, but is available on Linux and BSDs. ++pub fn cfmakeraw(termios: &mut Termios) { ++ let inner_termios = unsafe { termios.get_libc_termios_mut() }; ++ unsafe { ++ libc::cfmakeraw(inner_termios); ++ } ++ termios.update_wrapper(); ++} ++ ++/// Configures the port to "sane" mode (like the configuration of a newly created terminal) (see ++/// [tcsetattr(3)](https://www.freebsd.org/cgi/man.cgi?query=tcsetattr)). ++/// ++/// Note that this is a non-standard function, available on FreeBSD. ++#[cfg(target_os = "freebsd")] ++pub fn cfmakesane(termios: &mut Termios) { ++ let inner_termios = unsafe { termios.get_libc_termios_mut() }; ++ unsafe { ++ libc::cfmakesane(inner_termios); ++ } ++ termios.update_wrapper(); ++} ++ ++/// Return the configuration of a port ++/// [tcgetattr(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetattr.html)). ++/// ++/// `tcgetattr()` returns a `Termios` structure with the current configuration for a port. Modifying ++/// this structure *will not* reconfigure the port, instead the modifications should be done to ++/// the `Termios` structure and then the port should be reconfigured using `tcsetattr()`. ++pub fn tcgetattr(fd: RawFd) -> Result<Termios> { ++ let mut termios: libc::termios = unsafe { mem::uninitialized() }; ++ ++ let res = unsafe { libc::tcgetattr(fd, &mut termios) }; ++ ++ Errno::result(res)?; ++ ++ Ok(termios.into()) ++} ++ ++/// Set the configuration for a terminal (see ++/// [tcsetattr(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsetattr.html)). ++/// ++/// `tcsetattr()` reconfigures the given port based on a given `Termios` structure. This change ++/// takes affect at a time specified by `actions`. Note that this function may return success if ++/// *any* of the parameters were successfully set, not only if all were set successfully. ++pub fn tcsetattr(fd: RawFd, actions: SetArg, termios: &Termios) -> Result<()> { ++ let inner_termios = termios.get_libc_termios(); ++ Errno::result(unsafe { libc::tcsetattr(fd, actions as c_int, &*inner_termios) }).map(drop) ++} ++ ++/// Block until all output data is written (see ++/// [tcdrain(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcdrain.html)). ++pub fn tcdrain(fd: RawFd) -> Result<()> { ++ Errno::result(unsafe { libc::tcdrain(fd) }).map(drop) ++} ++ ++/// Suspend or resume the transmission or reception of data (see ++/// [tcflow(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcflow.html)). ++/// ++/// `tcflow()` suspends of resumes the transmission or reception of data for the given port ++/// depending on the value of `action`. ++pub fn tcflow(fd: RawFd, action: FlowArg) -> Result<()> { ++ Errno::result(unsafe { libc::tcflow(fd, action as c_int) }).map(drop) ++} ++ ++/// Discard data in the output or input queue (see ++/// [tcflush(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcflush.html)). ++/// ++/// `tcflush()` will discard data for a terminal port in the input queue, output queue, or both ++/// depending on the value of `action`. ++pub fn tcflush(fd: RawFd, action: FlushArg) -> Result<()> { ++ Errno::result(unsafe { libc::tcflush(fd, action as c_int) }).map(drop) ++} ++ ++/// Send a break for a specific duration (see ++/// [tcsendbreak(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsendbreak.html)). ++/// ++/// When using asynchronous data transmission `tcsendbreak()` will transmit a continuous stream ++/// of zero-valued bits for an implementation-defined duration. ++pub fn tcsendbreak(fd: RawFd, duration: c_int) -> Result<()> { ++ Errno::result(unsafe { libc::tcsendbreak(fd, duration) }).map(drop) ++} ++ ++/// Get the session controlled by the given terminal (see ++/// [tcgetsid(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetsid.html)). ++pub fn tcgetsid(fd: RawFd) -> Result<Pid> { ++ let res = unsafe { libc::tcgetsid(fd) }; ++ ++ Errno::result(res).map(Pid::from_raw) ++} +diff --git a/third_party/rust/nix-0.15.0/src/sys/time.rs b/third_party/rust/nix-0.15.0/src/sys/time.rs +new file mode 100644 +index 0000000000000..3ad57543b18a7 +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/src/sys/time.rs +@@ -0,0 +1,542 @@ ++use std::{cmp, fmt, ops}; ++use std::convert::From; ++use libc::{c_long, timespec, timeval}; ++pub use libc::{time_t, suseconds_t}; ++ ++pub trait TimeValLike: Sized { ++ #[inline] ++ fn zero() -> Self { ++ Self::seconds(0) ++ } ++ ++ #[inline] ++ fn hours(hours: i64) -> Self { ++ let secs = hours.checked_mul(SECS_PER_HOUR) ++ .expect("TimeValLike::hours ouf of bounds"); ++ Self::seconds(secs) ++ } ++ ++ #[inline] ++ fn minutes(minutes: i64) -> Self { ++ let secs = minutes.checked_mul(SECS_PER_MINUTE) ++ .expect("TimeValLike::minutes out of bounds"); ++ Self::seconds(secs) ++ } ++ ++ fn seconds(seconds: i64) -> Self; ++ fn milliseconds(milliseconds: i64) -> Self; ++ fn microseconds(microseconds: i64) -> Self; ++ fn nanoseconds(nanoseconds: i64) -> Self; ++ ++ #[inline] ++ fn num_hours(&self) -> i64 { ++ self.num_seconds() / 3600 ++ } ++ ++ #[inline] ++ fn num_minutes(&self) -> i64 { ++ self.num_seconds() / 60 ++ } ++ ++ fn num_seconds(&self) -> i64; ++ fn num_milliseconds(&self) -> i64; ++ fn num_microseconds(&self) -> i64; ++ fn num_nanoseconds(&self) -> i64; ++} ++ ++#[repr(C)] ++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] ++pub struct TimeSpec(timespec); ++ ++const NANOS_PER_SEC: i64 = 1_000_000_000; ++const SECS_PER_MINUTE: i64 = 60; ++const SECS_PER_HOUR: i64 = 3600; ++ ++#[cfg(target_pointer_width = "64")] ++const TS_MAX_SECONDS: i64 = (::std::i64::MAX / NANOS_PER_SEC) - 1; ++ ++#[cfg(target_pointer_width = "32")] ++const TS_MAX_SECONDS: i64 = ::std::isize::MAX as i64; ++ ++const TS_MIN_SECONDS: i64 = -TS_MAX_SECONDS; ++ ++ ++impl AsRef<timespec> for TimeSpec { ++ fn as_ref(&self) -> ×pec { ++ &self.0 ++ } ++} ++ ++impl Ord for TimeSpec { ++ // The implementation of cmp is simplified by assuming that the struct is ++ // normalized. That is, tv_nsec must always be within [0, 1_000_000_000) ++ fn cmp(&self, other: &TimeSpec) -> cmp::Ordering { ++ if self.tv_sec() == other.tv_sec() { ++ self.tv_nsec().cmp(&other.tv_nsec()) ++ } else { ++ self.tv_sec().cmp(&other.tv_sec()) ++ } ++ } ++} ++ ++impl PartialOrd for TimeSpec { ++ fn partial_cmp(&self, other: &TimeSpec) -> Option<cmp::Ordering> { ++ Some(self.cmp(other)) ++ } ++} ++ ++impl TimeValLike for TimeSpec { ++ #[inline] ++ fn seconds(seconds: i64) -> TimeSpec { ++ assert!(seconds >= TS_MIN_SECONDS && seconds <= TS_MAX_SECONDS, ++ "TimeSpec out of bounds; seconds={}", seconds); ++ TimeSpec(timespec {tv_sec: seconds as time_t, tv_nsec: 0 }) ++ } ++ ++ #[inline] ++ fn milliseconds(milliseconds: i64) -> TimeSpec { ++ let nanoseconds = milliseconds.checked_mul(1_000_000) ++ .expect("TimeSpec::milliseconds out of bounds"); ++ ++ TimeSpec::nanoseconds(nanoseconds) ++ } ++ ++ /// Makes a new `TimeSpec` with given number of microseconds. ++ #[inline] ++ fn microseconds(microseconds: i64) -> TimeSpec { ++ let nanoseconds = microseconds.checked_mul(1_000) ++ .expect("TimeSpec::milliseconds out of bounds"); ++ ++ TimeSpec::nanoseconds(nanoseconds) ++ } ++ ++ /// Makes a new `TimeSpec` with given number of nanoseconds. ++ #[inline] ++ fn nanoseconds(nanoseconds: i64) -> TimeSpec { ++ let (secs, nanos) = div_mod_floor_64(nanoseconds, NANOS_PER_SEC); ++ assert!(secs >= TS_MIN_SECONDS && secs <= TS_MAX_SECONDS, ++ "TimeSpec out of bounds"); ++ TimeSpec(timespec {tv_sec: secs as time_t, ++ tv_nsec: nanos as c_long }) ++ } ++ ++ fn num_seconds(&self) -> i64 { ++ if self.tv_sec() < 0 && self.tv_nsec() > 0 { ++ (self.tv_sec() + 1) as i64 ++ } else { ++ self.tv_sec() as i64 ++ } ++ } ++ ++ fn num_milliseconds(&self) -> i64 { ++ self.num_nanoseconds() / 1_000_000 ++ } ++ ++ fn num_microseconds(&self) -> i64 { ++ self.num_nanoseconds() / 1_000_000_000 ++ } ++ ++ fn num_nanoseconds(&self) -> i64 { ++ let secs = self.num_seconds() * 1_000_000_000; ++ let nsec = self.nanos_mod_sec(); ++ secs + nsec as i64 ++ } ++} ++ ++impl TimeSpec { ++ fn nanos_mod_sec(&self) -> c_long { ++ if self.tv_sec() < 0 && self.tv_nsec() > 0 { ++ self.tv_nsec() - NANOS_PER_SEC as c_long ++ } else { ++ self.tv_nsec() ++ } ++ } ++ ++ pub fn tv_sec(&self) -> time_t { ++ self.0.tv_sec ++ } ++ ++ pub fn tv_nsec(&self) -> c_long { ++ self.0.tv_nsec ++ } ++} ++ ++impl ops::Neg for TimeSpec { ++ type Output = TimeSpec; ++ ++ fn neg(self) -> TimeSpec { ++ TimeSpec::nanoseconds(-self.num_nanoseconds()) ++ } ++} ++ ++impl ops::Add for TimeSpec { ++ type Output = TimeSpec; ++ ++ fn add(self, rhs: TimeSpec) -> TimeSpec { ++ TimeSpec::nanoseconds( ++ self.num_nanoseconds() + rhs.num_nanoseconds()) ++ } ++} ++ ++impl ops::Sub for TimeSpec { ++ type Output = TimeSpec; ++ ++ fn sub(self, rhs: TimeSpec) -> TimeSpec { ++ TimeSpec::nanoseconds( ++ self.num_nanoseconds() - rhs.num_nanoseconds()) ++ } ++} ++ ++impl ops::Mul<i32> for TimeSpec { ++ type Output = TimeSpec; ++ ++ fn mul(self, rhs: i32) -> TimeSpec { ++ let usec = self.num_nanoseconds().checked_mul(rhs as i64) ++ .expect("TimeSpec multiply out of bounds"); ++ ++ TimeSpec::nanoseconds(usec) ++ } ++} ++ ++impl ops::Div<i32> for TimeSpec { ++ type Output = TimeSpec; ++ ++ fn div(self, rhs: i32) -> TimeSpec { ++ let usec = self.num_nanoseconds() / rhs as i64; ++ TimeSpec::nanoseconds(usec) ++ } ++} ++ ++impl fmt::Display for TimeSpec { ++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ++ let (abs, sign) = if self.tv_sec() < 0 { ++ (-*self, "-") ++ } else { ++ (*self, "") ++ }; ++ ++ let sec = abs.tv_sec(); ++ ++ write!(f, "{}", sign)?; ++ ++ if abs.tv_nsec() == 0 { ++ if abs.tv_sec() == 1 { ++ write!(f, "{} second", sec)?; ++ } else { ++ write!(f, "{} seconds", sec)?; ++ } ++ } else if abs.tv_nsec() % 1_000_000 == 0 { ++ write!(f, "{}.{:03} seconds", sec, abs.tv_nsec() / 1_000_000)?; ++ } else if abs.tv_nsec() % 1_000 == 0 { ++ write!(f, "{}.{:06} seconds", sec, abs.tv_nsec() / 1_000)?; ++ } else { ++ write!(f, "{}.{:09} seconds", sec, abs.tv_nsec())?; ++ } ++ ++ Ok(()) ++ } ++} ++ ++ ++ ++#[repr(C)] ++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] ++pub struct TimeVal(timeval); ++ ++const MICROS_PER_SEC: i64 = 1_000_000; ++ ++#[cfg(target_pointer_width = "64")] ++const TV_MAX_SECONDS: i64 = (::std::i64::MAX / MICROS_PER_SEC) - 1; ++ ++#[cfg(target_pointer_width = "32")] ++const TV_MAX_SECONDS: i64 = ::std::isize::MAX as i64; ++ ++const TV_MIN_SECONDS: i64 = -TV_MAX_SECONDS; ++ ++impl AsRef<timeval> for TimeVal { ++ fn as_ref(&self) -> &timeval { ++ &self.0 ++ } ++} ++ ++impl Ord for TimeVal { ++ // The implementation of cmp is simplified by assuming that the struct is ++ // normalized. That is, tv_usec must always be within [0, 1_000_000) ++ fn cmp(&self, other: &TimeVal) -> cmp::Ordering { ++ if self.tv_sec() == other.tv_sec() { ++ self.tv_usec().cmp(&other.tv_usec()) ++ } else { ++ self.tv_sec().cmp(&other.tv_sec()) ++ } ++ } ++} ++ ++impl PartialOrd for TimeVal { ++ fn partial_cmp(&self, other: &TimeVal) -> Option<cmp::Ordering> { ++ Some(self.cmp(other)) ++ } ++} ++ ++impl TimeValLike for TimeVal { ++ #[inline] ++ fn seconds(seconds: i64) -> TimeVal { ++ assert!(seconds >= TV_MIN_SECONDS && seconds <= TV_MAX_SECONDS, ++ "TimeVal out of bounds; seconds={}", seconds); ++ TimeVal(timeval {tv_sec: seconds as time_t, tv_usec: 0 }) ++ } ++ ++ #[inline] ++ fn milliseconds(milliseconds: i64) -> TimeVal { ++ let microseconds = milliseconds.checked_mul(1_000) ++ .expect("TimeVal::milliseconds out of bounds"); ++ ++ TimeVal::microseconds(microseconds) ++ } ++ ++ /// Makes a new `TimeVal` with given number of microseconds. ++ #[inline] ++ fn microseconds(microseconds: i64) -> TimeVal { ++ let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC); ++ assert!(secs >= TV_MIN_SECONDS && secs <= TV_MAX_SECONDS, ++ "TimeVal out of bounds"); ++ TimeVal(timeval {tv_sec: secs as time_t, ++ tv_usec: micros as suseconds_t }) ++ } ++ ++ /// Makes a new `TimeVal` with given number of nanoseconds. Some precision ++ /// will be lost ++ #[inline] ++ fn nanoseconds(nanoseconds: i64) -> TimeVal { ++ let microseconds = nanoseconds / 1000; ++ let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC); ++ assert!(secs >= TV_MIN_SECONDS && secs <= TV_MAX_SECONDS, ++ "TimeVal out of bounds"); ++ TimeVal(timeval {tv_sec: secs as time_t, ++ tv_usec: micros as suseconds_t }) ++ } ++ ++ fn num_seconds(&self) -> i64 { ++ if self.tv_sec() < 0 && self.tv_usec() > 0 { ++ (self.tv_sec() + 1) as i64 ++ } else { ++ self.tv_sec() as i64 ++ } ++ } ++ ++ fn num_milliseconds(&self) -> i64 { ++ self.num_microseconds() / 1_000 ++ } ++ ++ fn num_microseconds(&self) -> i64 { ++ let secs = self.num_seconds() * 1_000_000; ++ let usec = self.micros_mod_sec(); ++ secs + usec as i64 ++ } ++ ++ fn num_nanoseconds(&self) -> i64 { ++ self.num_microseconds() * 1_000 ++ } ++} ++ ++impl TimeVal { ++ fn micros_mod_sec(&self) -> suseconds_t { ++ if self.tv_sec() < 0 && self.tv_usec() > 0 { ++ self.tv_usec() - MICROS_PER_SEC as suseconds_t ++ } else { ++ self.tv_usec() ++ } ++ } ++ ++ pub fn tv_sec(&self) -> time_t { ++ self.0.tv_sec ++ } ++ ++ pub fn tv_usec(&self) -> suseconds_t { ++ self.0.tv_usec ++ } ++} ++ ++impl ops::Neg for TimeVal { ++ type Output = TimeVal; ++ ++ fn neg(self) -> TimeVal { ++ TimeVal::microseconds(-self.num_microseconds()) ++ } ++} ++ ++impl ops::Add for TimeVal { ++ type Output = TimeVal; ++ ++ fn add(self, rhs: TimeVal) -> TimeVal { ++ TimeVal::microseconds( ++ self.num_microseconds() + rhs.num_microseconds()) ++ } ++} ++ ++impl ops::Sub for TimeVal { ++ type Output = TimeVal; ++ ++ fn sub(self, rhs: TimeVal) -> TimeVal { ++ TimeVal::microseconds( ++ self.num_microseconds() - rhs.num_microseconds()) ++ } ++} ++ ++impl ops::Mul<i32> for TimeVal { ++ type Output = TimeVal; ++ ++ fn mul(self, rhs: i32) -> TimeVal { ++ let usec = self.num_microseconds().checked_mul(rhs as i64) ++ .expect("TimeVal multiply out of bounds"); ++ ++ TimeVal::microseconds(usec) ++ } ++} ++ ++impl ops::Div<i32> for TimeVal { ++ type Output = TimeVal; ++ ++ fn div(self, rhs: i32) -> TimeVal { ++ let usec = self.num_microseconds() / rhs as i64; ++ TimeVal::microseconds(usec) ++ } ++} ++ ++impl fmt::Display for TimeVal { ++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ++ let (abs, sign) = if self.tv_sec() < 0 { ++ (-*self, "-") ++ } else { ++ (*self, "") ++ }; ++ ++ let sec = abs.tv_sec(); ++ ++ write!(f, "{}", sign)?; ++ ++ if abs.tv_usec() == 0 { ++ if abs.tv_sec() == 1 { ++ write!(f, "{} second", sec)?; ++ } else { ++ write!(f, "{} seconds", sec)?; ++ } ++ } else if abs.tv_usec() % 1000 == 0 { ++ write!(f, "{}.{:03} seconds", sec, abs.tv_usec() / 1000)?; ++ } else { ++ write!(f, "{}.{:06} seconds", sec, abs.tv_usec())?; ++ } ++ ++ Ok(()) ++ } ++} ++ ++impl From<timeval> for TimeVal { ++ fn from(tv: timeval) -> Self { ++ TimeVal(tv) ++ } ++} ++ ++#[inline] ++fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) { ++ (div_floor_64(this, other), mod_floor_64(this, other)) ++} ++ ++#[inline] ++fn div_floor_64(this: i64, other: i64) -> i64 { ++ match div_rem_64(this, other) { ++ (d, r) if (r > 0 && other < 0) ++ || (r < 0 && other > 0) => d - 1, ++ (d, _) => d, ++ } ++} ++ ++#[inline] ++fn mod_floor_64(this: i64, other: i64) -> i64 { ++ match this % other { ++ r if (r > 0 && other < 0) ++ || (r < 0 && other > 0) => r + other, ++ r => r, ++ } ++} ++ ++#[inline] ++fn div_rem_64(this: i64, other: i64) -> (i64, i64) { ++ (this / other, this % other) ++} ++ ++#[cfg(test)] ++mod test { ++ use super::{TimeSpec, TimeVal, TimeValLike}; ++ ++ #[test] ++ pub fn test_timespec() { ++ assert!(TimeSpec::seconds(1) != TimeSpec::zero()); ++ assert_eq!(TimeSpec::seconds(1) + TimeSpec::seconds(2), ++ TimeSpec::seconds(3)); ++ assert_eq!(TimeSpec::minutes(3) + TimeSpec::seconds(2), ++ TimeSpec::seconds(182)); ++ } ++ ++ #[test] ++ pub fn test_timespec_neg() { ++ let a = TimeSpec::seconds(1) + TimeSpec::nanoseconds(123); ++ let b = TimeSpec::seconds(-1) + TimeSpec::nanoseconds(-123); ++ ++ assert_eq!(a, -b); ++ } ++ ++ #[test] ++ pub fn test_timespec_ord() { ++ assert!(TimeSpec::seconds(1) == TimeSpec::nanoseconds(1_000_000_000)); ++ assert!(TimeSpec::seconds(1) < TimeSpec::nanoseconds(1_000_000_001)); ++ assert!(TimeSpec::seconds(1) > TimeSpec::nanoseconds(999_999_999)); ++ assert!(TimeSpec::seconds(-1) < TimeSpec::nanoseconds(-999_999_999)); ++ assert!(TimeSpec::seconds(-1) > TimeSpec::nanoseconds(-1_000_000_001)); ++ } ++ ++ #[test] ++ pub fn test_timespec_fmt() { ++ assert_eq!(TimeSpec::zero().to_string(), "0 seconds"); ++ assert_eq!(TimeSpec::seconds(42).to_string(), "42 seconds"); ++ assert_eq!(TimeSpec::milliseconds(42).to_string(), "0.042 seconds"); ++ assert_eq!(TimeSpec::microseconds(42).to_string(), "0.000042 seconds"); ++ assert_eq!(TimeSpec::nanoseconds(42).to_string(), "0.000000042 seconds"); ++ assert_eq!(TimeSpec::seconds(-86401).to_string(), "-86401 seconds"); ++ } ++ ++ #[test] ++ pub fn test_timeval() { ++ assert!(TimeVal::seconds(1) != TimeVal::zero()); ++ assert_eq!(TimeVal::seconds(1) + TimeVal::seconds(2), ++ TimeVal::seconds(3)); ++ assert_eq!(TimeVal::minutes(3) + TimeVal::seconds(2), ++ TimeVal::seconds(182)); ++ } ++ ++ #[test] ++ pub fn test_timeval_ord() { ++ assert!(TimeVal::seconds(1) == TimeVal::microseconds(1_000_000)); ++ assert!(TimeVal::seconds(1) < TimeVal::microseconds(1_000_001)); ++ assert!(TimeVal::seconds(1) > TimeVal::microseconds(999_999)); ++ assert!(TimeVal::seconds(-1) < TimeVal::microseconds(-999_999)); ++ assert!(TimeVal::seconds(-1) > TimeVal::microseconds(-1_000_001)); ++ } ++ ++ #[test] ++ pub fn test_timeval_neg() { ++ let a = TimeVal::seconds(1) + TimeVal::microseconds(123); ++ let b = TimeVal::seconds(-1) + TimeVal::microseconds(-123); ++ ++ assert_eq!(a, -b); ++ } ++ ++ #[test] ++ pub fn test_timeval_fmt() { ++ assert_eq!(TimeVal::zero().to_string(), "0 seconds"); ++ assert_eq!(TimeVal::seconds(42).to_string(), "42 seconds"); ++ assert_eq!(TimeVal::milliseconds(42).to_string(), "0.042 seconds"); ++ assert_eq!(TimeVal::microseconds(42).to_string(), "0.000042 seconds"); ++ assert_eq!(TimeVal::nanoseconds(1402).to_string(), "0.000001 seconds"); ++ assert_eq!(TimeVal::seconds(-86401).to_string(), "-86401 seconds"); ++ } ++} +diff --git a/third_party/rust/nix-0.15.0/src/sys/uio.rs b/third_party/rust/nix-0.15.0/src/sys/uio.rs +new file mode 100644 +index 0000000000000..d089084eed711 +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/src/sys/uio.rs +@@ -0,0 +1,194 @@ ++// Silence invalid warnings due to rust-lang/rust#16719 ++#![allow(improper_ctypes)] ++ ++use Result; ++use errno::Errno; ++use libc::{self, c_int, c_void, size_t, off_t}; ++use std::marker::PhantomData; ++use std::os::unix::io::RawFd; ++ ++pub fn writev(fd: RawFd, iov: &[IoVec<&[u8]>]) -> Result<usize> { ++ let res = unsafe { libc::writev(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int) }; ++ ++ Errno::result(res).map(|r| r as usize) ++} ++ ++pub fn readv(fd: RawFd, iov: &mut [IoVec<&mut [u8]>]) -> Result<usize> { ++ let res = unsafe { libc::readv(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int) }; ++ ++ Errno::result(res).map(|r| r as usize) ++} ++ ++/// Write to `fd` at `offset` from buffers in `iov`. ++/// ++/// Buffers in `iov` will be written in order until all buffers have been written ++/// or an error occurs. The file offset is not changed. ++/// ++/// See also: [`writev`](fn.writev.html) and [`pwrite`](fn.pwrite.html) ++#[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "linux", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++pub fn pwritev(fd: RawFd, iov: &[IoVec<&[u8]>], ++ offset: off_t) -> Result<usize> { ++ let res = unsafe { ++ libc::pwritev(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int, offset) ++ }; ++ ++ Errno::result(res).map(|r| r as usize) ++} ++ ++/// Read from `fd` at `offset` filling buffers in `iov`. ++/// ++/// Buffers in `iov` will be filled in order until all buffers have been filled, ++/// no more bytes are available, or an error occurs. The file offset is not ++/// changed. ++/// ++/// See also: [`readv`](fn.readv.html) and [`pread`](fn.pread.html) ++#[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "linux", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++pub fn preadv(fd: RawFd, iov: &[IoVec<&mut [u8]>], ++ offset: off_t) -> Result<usize> { ++ let res = unsafe { ++ libc::preadv(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int, offset) ++ }; ++ ++ Errno::result(res).map(|r| r as usize) ++} ++ ++pub fn pwrite(fd: RawFd, buf: &[u8], offset: off_t) -> Result<usize> { ++ let res = unsafe { ++ libc::pwrite(fd, buf.as_ptr() as *const c_void, buf.len() as size_t, ++ offset) ++ }; ++ ++ Errno::result(res).map(|r| r as usize) ++} ++ ++pub fn pread(fd: RawFd, buf: &mut [u8], offset: off_t) -> Result<usize>{ ++ let res = unsafe { ++ libc::pread(fd, buf.as_mut_ptr() as *mut c_void, buf.len() as size_t, ++ offset) ++ }; ++ ++ Errno::result(res).map(|r| r as usize) ++} ++ ++/// A slice of memory in a remote process, starting at address `base` ++/// and consisting of `len` bytes. ++/// ++/// This is the same underlying C structure as [`IoVec`](struct.IoVec.html), ++/// except that it refers to memory in some other process, and is ++/// therefore not represented in Rust by an actual slice as `IoVec` is. It ++/// is used with [`process_vm_readv`](fn.process_vm_readv.html) ++/// and [`process_vm_writev`](fn.process_vm_writev.html). ++#[cfg(target_os = "linux")] ++#[repr(C)] ++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] ++pub struct RemoteIoVec { ++ /// The starting address of this slice (`iov_base`). ++ pub base: usize, ++ /// The number of bytes in this slice (`iov_len`). ++ pub len: usize, ++} ++ ++/// Write data directly to another process's virtual memory ++/// (see [`process_vm_writev`(2)]). ++/// ++/// `local_iov` is a list of [`IoVec`]s containing the data to be written, ++/// and `remote_iov` is a list of [`RemoteIoVec`]s identifying where the ++/// data should be written in the target process. On success, returns the ++/// number of bytes written, which will always be a whole ++/// number of `remote_iov` chunks. ++/// ++/// This requires the same permissions as debugging the process using ++/// [ptrace]: you must either be a privileged process (with ++/// `CAP_SYS_PTRACE`), or you must be running as the same user as the ++/// target process and the OS must have unprivileged debugging enabled. ++/// ++/// This function is only available on Linux. ++/// ++/// [`process_vm_writev`(2)]: http://man7.org/linux/man-pages/man2/process_vm_writev.2.html ++/// [ptrace]: ../ptrace/index.html ++/// [`IoVec`]: struct.IoVec.html ++/// [`RemoteIoVec`]: struct.RemoteIoVec.html ++#[cfg(target_os = "linux")] ++pub fn process_vm_writev(pid: ::unistd::Pid, local_iov: &[IoVec<&[u8]>], remote_iov: &[RemoteIoVec]) -> Result<usize> { ++ let res = unsafe { ++ libc::process_vm_writev(pid.into(), ++ local_iov.as_ptr() as *const libc::iovec, local_iov.len() as libc::c_ulong, ++ remote_iov.as_ptr() as *const libc::iovec, remote_iov.len() as libc::c_ulong, 0) ++ }; ++ ++ Errno::result(res).map(|r| r as usize) ++} ++ ++/// Read data directly from another process's virtual memory ++/// (see [`process_vm_readv`(2)]). ++/// ++/// `local_iov` is a list of [`IoVec`]s containing the buffer to copy ++/// data into, and `remote_iov` is a list of [`RemoteIoVec`]s identifying ++/// where the source data is in the target process. On success, ++/// returns the number of bytes written, which will always be a whole ++/// number of `remote_iov` chunks. ++/// ++/// This requires the same permissions as debugging the process using ++/// [`ptrace`]: you must either be a privileged process (with ++/// `CAP_SYS_PTRACE`), or you must be running as the same user as the ++/// target process and the OS must have unprivileged debugging enabled. ++/// ++/// This function is only available on Linux. ++/// ++/// [`process_vm_readv`(2)]: http://man7.org/linux/man-pages/man2/process_vm_readv.2.html ++/// [`ptrace`]: ../ptrace/index.html ++/// [`IoVec`]: struct.IoVec.html ++/// [`RemoteIoVec`]: struct.RemoteIoVec.html ++#[cfg(any(target_os = "linux"))] ++pub fn process_vm_readv(pid: ::unistd::Pid, local_iov: &[IoVec<&mut [u8]>], remote_iov: &[RemoteIoVec]) -> Result<usize> { ++ let res = unsafe { ++ libc::process_vm_readv(pid.into(), ++ local_iov.as_ptr() as *const libc::iovec, local_iov.len() as libc::c_ulong, ++ remote_iov.as_ptr() as *const libc::iovec, remote_iov.len() as libc::c_ulong, 0) ++ }; ++ ++ Errno::result(res).map(|r| r as usize) ++} ++ ++#[repr(C)] ++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] ++pub struct IoVec<T>(libc::iovec, PhantomData<T>); ++ ++impl<T> IoVec<T> { ++ #[inline] ++ pub fn as_slice(&self) -> &[u8] { ++ use std::slice; ++ ++ unsafe { ++ slice::from_raw_parts( ++ self.0.iov_base as *const u8, ++ self.0.iov_len as usize) ++ } ++ } ++} ++ ++impl<'a> IoVec<&'a [u8]> { ++ pub fn from_slice(buf: &'a [u8]) -> IoVec<&'a [u8]> { ++ IoVec(libc::iovec { ++ iov_base: buf.as_ptr() as *mut c_void, ++ iov_len: buf.len() as size_t, ++ }, PhantomData) ++ } ++} ++ ++impl<'a> IoVec<&'a mut [u8]> { ++ pub fn from_mut_slice(buf: &'a mut [u8]) -> IoVec<&'a mut [u8]> { ++ IoVec(libc::iovec { ++ iov_base: buf.as_ptr() as *mut c_void, ++ iov_len: buf.len() as size_t, ++ }, PhantomData) ++ } ++} +diff --git a/third_party/rust/nix-0.15.0/src/sys/utsname.rs b/third_party/rust/nix-0.15.0/src/sys/utsname.rs +new file mode 100644 +index 0000000000000..ab09c7d23232a +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/src/sys/utsname.rs +@@ -0,0 +1,67 @@ ++use std::mem; ++use libc::{self, c_char}; ++use std::ffi::CStr; ++use std::str::from_utf8_unchecked; ++ ++#[repr(C)] ++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] ++pub struct UtsName(libc::utsname); ++ ++impl UtsName { ++ pub fn sysname(&self) -> &str { ++ to_str(&(&self.0.sysname as *const c_char ) as *const *const c_char) ++ } ++ ++ pub fn nodename(&self) -> &str { ++ to_str(&(&self.0.nodename as *const c_char ) as *const *const c_char) ++ } ++ ++ pub fn release(&self) -> &str { ++ to_str(&(&self.0.release as *const c_char ) as *const *const c_char) ++ } ++ ++ pub fn version(&self) -> &str { ++ to_str(&(&self.0.version as *const c_char ) as *const *const c_char) ++ } ++ ++ pub fn machine(&self) -> &str { ++ to_str(&(&self.0.machine as *const c_char ) as *const *const c_char) ++ } ++} ++ ++pub fn uname() -> UtsName { ++ unsafe { ++ let mut ret: UtsName = mem::uninitialized(); ++ libc::uname(&mut ret.0); ++ ret ++ } ++} ++ ++#[inline] ++fn to_str<'a>(s: *const *const c_char) -> &'a str { ++ unsafe { ++ let res = CStr::from_ptr(*s).to_bytes(); ++ from_utf8_unchecked(res) ++ } ++} ++ ++#[cfg(test)] ++mod test { ++ #[cfg(target_os = "linux")] ++ #[test] ++ pub fn test_uname_linux() { ++ assert_eq!(super::uname().sysname(), "Linux"); ++ } ++ ++ #[cfg(any(target_os = "macos", target_os = "ios"))] ++ #[test] ++ pub fn test_uname_darwin() { ++ assert_eq!(super::uname().sysname(), "Darwin"); ++ } ++ ++ #[cfg(target_os = "freebsd")] ++ #[test] ++ pub fn test_uname_freebsd() { ++ assert_eq!(super::uname().sysname(), "FreeBSD"); ++ } ++} +diff --git a/third_party/rust/nix-0.15.0/src/sys/wait.rs b/third_party/rust/nix-0.15.0/src/sys/wait.rs +new file mode 100644 +index 0000000000000..c54f7ec579667 +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/src/sys/wait.rs +@@ -0,0 +1,239 @@ ++use libc::{self, c_int}; ++use Result; ++use errno::Errno; ++use unistd::Pid; ++ ++use sys::signal::Signal; ++ ++libc_bitflags!( ++ pub struct WaitPidFlag: c_int { ++ WNOHANG; ++ WUNTRACED; ++ #[cfg(any(target_os = "android", ++ target_os = "freebsd", ++ target_os = "haiku", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos", ++ target_os = "netbsd"))] ++ WEXITED; ++ WCONTINUED; ++ #[cfg(any(target_os = "android", ++ target_os = "freebsd", ++ target_os = "haiku", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos", ++ target_os = "netbsd"))] ++ WSTOPPED; ++ /// Don't reap, just poll status. ++ #[cfg(any(target_os = "android", ++ target_os = "freebsd", ++ target_os = "haiku", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos", ++ target_os = "netbsd"))] ++ WNOWAIT; ++ /// Don't wait on children of other threads in this group ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ __WNOTHREAD; ++ /// Wait on all children, regardless of type ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ __WALL; ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ __WCLONE; ++ } ++); ++ ++/// Possible return values from `wait()` or `waitpid()`. ++/// ++/// Each status (other than `StillAlive`) describes a state transition ++/// in a child process `Pid`, such as the process exiting or stopping, ++/// plus additional data about the transition if any. ++/// ++/// Note that there are two Linux-specific enum variants, `PtraceEvent` ++/// and `PtraceSyscall`. Portable code should avoid exhaustively ++/// matching on `WaitStatus`. ++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] ++pub enum WaitStatus { ++ /// The process exited normally (as with `exit()` or returning from ++ /// `main`) with the given exit code. This case matches the C macro ++ /// `WIFEXITED(status)`; the second field is `WEXITSTATUS(status)`. ++ Exited(Pid, i32), ++ /// The process was killed by the given signal. The third field ++ /// indicates whether the signal generated a core dump. This case ++ /// matches the C macro `WIFSIGNALED(status)`; the last two fields ++ /// correspond to `WTERMSIG(status)` and `WCOREDUMP(status)`. ++ Signaled(Pid, Signal, bool), ++ /// The process is alive, but was stopped by the given signal. This ++ /// is only reported if `WaitPidFlag::WUNTRACED` was passed. This ++ /// case matches the C macro `WIFSTOPPED(status)`; the second field ++ /// is `WSTOPSIG(status)`. ++ Stopped(Pid, Signal), ++ /// The traced process was stopped by a `PTRACE_EVENT_*` event. See ++ /// [`nix::sys::ptrace`] and [`ptrace`(2)] for more information. All ++ /// currently-defined events use `SIGTRAP` as the signal; the third ++ /// field is the `PTRACE_EVENT_*` value of the event. ++ /// ++ /// [`nix::sys::ptrace`]: ../ptrace/index.html ++ /// [`ptrace`(2)]: http://man7.org/linux/man-pages/man2/ptrace.2.html ++ #[cfg(any(target_os = "linux", target_os = "android"))] ++ PtraceEvent(Pid, Signal, c_int), ++ /// The traced process was stopped by execution of a system call, ++ /// and `PTRACE_O_TRACESYSGOOD` is in effect. See [`ptrace`(2)] for ++ /// more information. ++ /// ++ /// [`ptrace`(2)]: http://man7.org/linux/man-pages/man2/ptrace.2.html ++ #[cfg(any(target_os = "linux", target_os = "android"))] ++ PtraceSyscall(Pid), ++ /// The process was previously stopped but has resumed execution ++ /// after receiving a `SIGCONT` signal. This is only reported if ++ /// `WaitPidFlag::WCONTINUED` was passed. This case matches the C ++ /// macro `WIFCONTINUED(status)`. ++ Continued(Pid), ++ /// There are currently no state changes to report in any awaited ++ /// child process. This is only returned if `WaitPidFlag::WNOHANG` ++ /// was used (otherwise `wait()` or `waitpid()` would block until ++ /// there was something to report). ++ StillAlive, ++} ++ ++impl WaitStatus { ++ /// Extracts the PID from the WaitStatus unless it equals StillAlive. ++ pub fn pid(&self) -> Option<Pid> { ++ use self::WaitStatus::*; ++ match *self { ++ Exited(p, _) | Signaled(p, _, _) | ++ Stopped(p, _) | Continued(p) => Some(p), ++ StillAlive => None, ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ PtraceEvent(p, _, _) | PtraceSyscall(p) => Some(p), ++ } ++ } ++} ++ ++fn exited(status: i32) -> bool { ++ unsafe { libc::WIFEXITED(status) } ++} ++ ++fn exit_status(status: i32) -> i32 { ++ unsafe { libc::WEXITSTATUS(status) } ++} ++ ++fn signaled(status: i32) -> bool { ++ unsafe { libc::WIFSIGNALED(status) } ++} ++ ++fn term_signal(status: i32) -> Result<Signal> { ++ Signal::from_c_int(unsafe { libc::WTERMSIG(status) }) ++} ++ ++fn dumped_core(status: i32) -> bool { ++ unsafe { libc::WCOREDUMP(status) } ++} ++ ++fn stopped(status: i32) -> bool { ++ unsafe { libc::WIFSTOPPED(status) } ++} ++ ++fn stop_signal(status: i32) -> Result<Signal> { ++ Signal::from_c_int(unsafe { libc::WSTOPSIG(status) }) ++} ++ ++#[cfg(any(target_os = "android", target_os = "linux"))] ++fn syscall_stop(status: i32) -> bool { ++ // From ptrace(2), setting PTRACE_O_TRACESYSGOOD has the effect ++ // of delivering SIGTRAP | 0x80 as the signal number for syscall ++ // stops. This allows easily distinguishing syscall stops from ++ // genuine SIGTRAP signals. ++ unsafe { libc::WSTOPSIG(status) == libc::SIGTRAP | 0x80 } ++} ++ ++#[cfg(any(target_os = "android", target_os = "linux"))] ++fn stop_additional(status: i32) -> c_int { ++ (status >> 16) as c_int ++} ++ ++fn continued(status: i32) -> bool { ++ unsafe { libc::WIFCONTINUED(status) } ++} ++ ++impl WaitStatus { ++ /// Convert a raw `wstatus` as returned by `waitpid`/`wait` into a `WaitStatus` ++ /// ++ /// # Errors ++ /// ++ /// Returns an `Error` corresponding to `EINVAL` for invalid status values. ++ /// ++ /// # Examples ++ /// ++ /// Convert a `wstatus` obtained from `libc::waitpid` into a `WaitStatus`: ++ /// ++ /// ``` ++ /// use nix::sys::wait::WaitStatus; ++ /// use nix::sys::signal::Signal; ++ /// let pid = nix::unistd::Pid::from_raw(1); ++ /// let status = WaitStatus::from_raw(pid, 0x0002); ++ /// assert_eq!(status, Ok(WaitStatus::Signaled(pid, Signal::SIGINT, false))); ++ /// ``` ++ pub fn from_raw(pid: Pid, status: i32) -> Result<WaitStatus> { ++ Ok(if exited(status) { ++ WaitStatus::Exited(pid, exit_status(status)) ++ } else if signaled(status) { ++ WaitStatus::Signaled(pid, term_signal(status)?, dumped_core(status)) ++ } else if stopped(status) { ++ cfg_if! { ++ if #[cfg(any(target_os = "android", target_os = "linux"))] { ++ fn decode_stopped(pid: Pid, status: i32) -> Result<WaitStatus> { ++ let status_additional = stop_additional(status); ++ Ok(if syscall_stop(status) { ++ WaitStatus::PtraceSyscall(pid) ++ } else if status_additional == 0 { ++ WaitStatus::Stopped(pid, stop_signal(status)?) ++ } else { ++ WaitStatus::PtraceEvent(pid, stop_signal(status)?, ++ stop_additional(status)) ++ }) ++ } ++ } else { ++ fn decode_stopped(pid: Pid, status: i32) -> Result<WaitStatus> { ++ Ok(WaitStatus::Stopped(pid, stop_signal(status)?)) ++ } ++ } ++ } ++ return decode_stopped(pid, status); ++ } else { ++ assert!(continued(status)); ++ WaitStatus::Continued(pid) ++ }) ++ } ++} ++ ++pub fn waitpid<P: Into<Option<Pid>>>(pid: P, options: Option<WaitPidFlag>) -> Result<WaitStatus> { ++ use self::WaitStatus::*; ++ ++ let mut status: i32 = 0; ++ ++ let option_bits = match options { ++ Some(bits) => bits.bits(), ++ None => 0, ++ }; ++ ++ let res = unsafe { ++ libc::waitpid( ++ pid.into().unwrap_or(Pid::from_raw(-1)).into(), ++ &mut status as *mut c_int, ++ option_bits, ++ ) ++ }; ++ ++ match Errno::result(res)? { ++ 0 => Ok(StillAlive), ++ res => WaitStatus::from_raw(Pid::from_raw(res), status), ++ } ++} ++ ++pub fn wait() -> Result<WaitStatus> { ++ waitpid(None, None) ++} +diff --git a/third_party/rust/nix-0.15.0/src/ucontext.rs b/third_party/rust/nix-0.15.0/src/ucontext.rs +new file mode 100644 +index 0000000000000..5e10e7d1f8934 +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/src/ucontext.rs +@@ -0,0 +1,39 @@ ++use libc; ++#[cfg(not(target_env = "musl"))] ++use Result; ++#[cfg(not(target_env = "musl"))] ++use errno::Errno; ++use std::mem; ++use sys::signal::SigSet; ++ ++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] ++pub struct UContext { ++ context: libc::ucontext_t, ++} ++ ++impl UContext { ++ #[cfg(not(target_env = "musl"))] ++ pub fn get() -> Result<UContext> { ++ let mut context: libc::ucontext_t = unsafe { mem::uninitialized() }; ++ let res = unsafe { ++ libc::getcontext(&mut context as *mut libc::ucontext_t) ++ }; ++ Errno::result(res).map(|_| UContext { context: context }) ++ } ++ ++ #[cfg(not(target_env = "musl"))] ++ pub fn set(&self) -> Result<()> { ++ let res = unsafe { ++ libc::setcontext(&self.context as *const libc::ucontext_t) ++ }; ++ Errno::result(res).map(drop) ++ } ++ ++ pub fn sigmask_mut(&mut self) -> &mut SigSet { ++ unsafe { mem::transmute(&mut self.context.uc_sigmask) } ++ } ++ ++ pub fn sigmask(&self) -> &SigSet { ++ unsafe { mem::transmute(&self.context.uc_sigmask) } ++ } ++} +diff --git a/third_party/rust/nix-0.15.0/src/unistd.rs b/third_party/rust/nix-0.15.0/src/unistd.rs +new file mode 100644 +index 0000000000000..f422f09198655 +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/src/unistd.rs +@@ -0,0 +1,2394 @@ ++//! Safe wrappers around functions found in libc "unistd.h" header ++ ++use errno::{self, Errno}; ++use {Error, Result, NixPath}; ++use fcntl::{AtFlags, at_rawfd, fcntl, FdFlag, OFlag}; ++use fcntl::FcntlArg::F_SETFD; ++use libc::{self, c_char, c_void, c_int, c_long, c_uint, size_t, pid_t, off_t, ++ uid_t, gid_t, mode_t}; ++use std::{fmt, mem, ptr}; ++use std::ffi::{CString, CStr, OsString, OsStr}; ++use std::os::unix::ffi::{OsStringExt, OsStrExt}; ++use std::os::unix::io::RawFd; ++use std::path::PathBuf; ++use void::Void; ++use sys::stat::Mode; ++ ++#[cfg(any(target_os = "android", target_os = "linux"))] ++pub use self::pivot_root::*; ++ ++#[cfg(any(target_os = "android", target_os = "freebsd", ++ target_os = "linux", target_os = "openbsd"))] ++pub use self::setres::*; ++ ++/// User identifier ++/// ++/// Newtype pattern around `uid_t` (which is just alias). It prevents bugs caused by accidentally ++/// passing wrong value. ++#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] ++pub struct Uid(uid_t); ++ ++impl Uid { ++ /// Creates `Uid` from raw `uid_t`. ++ pub fn from_raw(uid: uid_t) -> Self { ++ Uid(uid) ++ } ++ ++ /// Returns Uid of calling process. This is practically a more Rusty alias for `getuid`. ++ pub fn current() -> Self { ++ getuid() ++ } ++ ++ /// Returns effective Uid of calling process. This is practically a more Rusty alias for `geteuid`. ++ pub fn effective() -> Self { ++ geteuid() ++ } ++ ++ /// Returns true if the `Uid` represents privileged user - root. (If it equals zero.) ++ pub fn is_root(&self) -> bool { ++ *self == ROOT ++ } ++ ++ /// Get the raw `uid_t` wrapped by `self`. ++ pub fn as_raw(&self) -> uid_t { ++ self.0 ++ } ++} ++ ++impl From<Uid> for uid_t { ++ fn from(uid: Uid) -> Self { ++ uid.0 ++ } ++} ++ ++impl fmt::Display for Uid { ++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ++ fmt::Display::fmt(&self.0, f) ++ } ++} ++ ++/// Constant for UID = 0 ++pub const ROOT: Uid = Uid(0); ++ ++/// Group identifier ++/// ++/// Newtype pattern around `gid_t` (which is just alias). It prevents bugs caused by accidentally ++/// passing wrong value. ++#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] ++pub struct Gid(gid_t); ++ ++impl Gid { ++ /// Creates `Gid` from raw `gid_t`. ++ pub fn from_raw(gid: gid_t) -> Self { ++ Gid(gid) ++ } ++ ++ /// Returns Gid of calling process. This is practically a more Rusty alias for `getgid`. ++ pub fn current() -> Self { ++ getgid() ++ } ++ ++ /// Returns effective Gid of calling process. This is practically a more Rusty alias for `getgid`. ++ pub fn effective() -> Self { ++ getegid() ++ } ++ ++ /// Get the raw `gid_t` wrapped by `self`. ++ pub fn as_raw(&self) -> gid_t { ++ self.0 ++ } ++} ++ ++impl From<Gid> for gid_t { ++ fn from(gid: Gid) -> Self { ++ gid.0 ++ } ++} ++ ++impl fmt::Display for Gid { ++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ++ fmt::Display::fmt(&self.0, f) ++ } ++} ++ ++/// Process identifier ++/// ++/// Newtype pattern around `pid_t` (which is just alias). It prevents bugs caused by accidentally ++/// passing wrong value. ++#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] ++pub struct Pid(pid_t); ++ ++impl Pid { ++ /// Creates `Pid` from raw `pid_t`. ++ pub fn from_raw(pid: pid_t) -> Self { ++ Pid(pid) ++ } ++ ++ /// Returns PID of calling process ++ pub fn this() -> Self { ++ getpid() ++ } ++ ++ /// Returns PID of parent of calling process ++ pub fn parent() -> Self { ++ getppid() ++ } ++ ++ /// Get the raw `pid_t` wrapped by `self`. ++ pub fn as_raw(&self) -> pid_t { ++ self.0 ++ } ++} ++ ++impl From<Pid> for pid_t { ++ fn from(pid: Pid) -> Self { ++ pid.0 ++ } ++} ++ ++impl fmt::Display for Pid { ++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ++ fmt::Display::fmt(&self.0, f) ++ } ++} ++ ++ ++/// Represents the successful result of calling `fork` ++/// ++/// When `fork` is called, the process continues execution in the parent process ++/// and in the new child. This return type can be examined to determine whether ++/// you are now executing in the parent process or in the child. ++#[derive(Clone, Copy, Debug)] ++pub enum ForkResult { ++ Parent { child: Pid }, ++ Child, ++} ++ ++impl ForkResult { ++ ++ /// Return `true` if this is the child process of the `fork()` ++ #[inline] ++ pub fn is_child(&self) -> bool { ++ match *self { ++ ForkResult::Child => true, ++ _ => false ++ } ++ } ++ ++ /// Returns `true` if this is the parent process of the `fork()` ++ #[inline] ++ pub fn is_parent(&self) -> bool { ++ !self.is_child() ++ } ++} ++ ++/// Create a new child process duplicating the parent process ([see ++/// fork(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html)). ++/// ++/// After calling the fork system call (successfully) two processes will ++/// be created that are identical with the exception of their pid and the ++/// return value of this function. As an example: ++/// ++/// ```no_run ++/// use nix::unistd::{fork, ForkResult}; ++/// ++/// match fork() { ++/// Ok(ForkResult::Parent { child, .. }) => { ++/// println!("Continuing execution in parent process, new child has pid: {}", child); ++/// } ++/// Ok(ForkResult::Child) => println!("I'm a new child process"), ++/// Err(_) => println!("Fork failed"), ++/// } ++/// ``` ++/// ++/// This will print something like the following (order indeterministic). The ++/// thing to note is that you end up with two processes continuing execution ++/// immediately after the fork call but with different match arms. ++/// ++/// ```text ++/// Continuing execution in parent process, new child has pid: 1234 ++/// I'm a new child process ++/// ``` ++/// ++/// # Safety ++/// ++/// In a multithreaded program, only [async-signal-safe] functions like `pause` ++/// and `_exit` may be called by the child (the parent isn't restricted). Note ++/// that memory allocation may **not** be async-signal-safe and thus must be ++/// prevented. ++/// ++/// Those functions are only a small subset of your operating system's API, so ++/// special care must be taken to only invoke code you can control and audit. ++/// ++/// [async-signal-safe]: http://man7.org/linux/man-pages/man7/signal-safety.7.html ++#[inline] ++pub fn fork() -> Result<ForkResult> { ++ use self::ForkResult::*; ++ let res = unsafe { libc::fork() }; ++ ++ Errno::result(res).map(|res| match res { ++ 0 => Child, ++ res => Parent { child: Pid(res) }, ++ }) ++} ++ ++/// Get the pid of this process (see ++/// [getpid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpid.html)). ++/// ++/// Since you are running code, there is always a pid to return, so there ++/// is no error case that needs to be handled. ++#[inline] ++pub fn getpid() -> Pid { ++ Pid(unsafe { libc::getpid() }) ++} ++ ++/// Get the pid of this processes' parent (see ++/// [getpid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getppid.html)). ++/// ++/// There is always a parent pid to return, so there is no error case that needs ++/// to be handled. ++#[inline] ++pub fn getppid() -> Pid { ++ Pid(unsafe { libc::getppid() }) // no error handling, according to man page: "These functions are always successful." ++} ++ ++/// Set a process group ID (see ++/// [setpgid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setpgid.html)). ++/// ++/// Set the process group id (PGID) of a particular process. If a pid of zero ++/// is specified, then the pid of the calling process is used. Process groups ++/// may be used to group together a set of processes in order for the OS to ++/// apply some operations across the group. ++/// ++/// `setsid()` may be used to create a new process group. ++#[inline] ++pub fn setpgid(pid: Pid, pgid: Pid) -> Result<()> { ++ let res = unsafe { libc::setpgid(pid.into(), pgid.into()) }; ++ Errno::result(res).map(drop) ++} ++#[inline] ++pub fn getpgid(pid: Option<Pid>) -> Result<Pid> { ++ let res = unsafe { libc::getpgid(pid.unwrap_or(Pid(0)).into()) }; ++ Errno::result(res).map(Pid) ++} ++ ++/// Create new session and set process group id (see ++/// [setsid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setsid.html)). ++#[inline] ++pub fn setsid() -> Result<Pid> { ++ Errno::result(unsafe { libc::setsid() }).map(Pid) ++} ++ ++/// Get the process group ID of a session leader ++/// [getsid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getsid.html). ++/// ++/// Obtain the process group ID of the process that is the session leader of the process specified ++/// by pid. If pid is zero, it specifies the calling process. ++#[inline] ++pub fn getsid(pid: Option<Pid>) -> Result<Pid> { ++ let res = unsafe { libc::getsid(pid.unwrap_or(Pid(0)).into()) }; ++ Errno::result(res).map(Pid) ++} ++ ++ ++/// Get the terminal foreground process group (see ++/// [tcgetpgrp(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetpgrp.html)). ++/// ++/// Get the group process id (GPID) of the foreground process group on the ++/// terminal associated to file descriptor (FD). ++#[inline] ++pub fn tcgetpgrp(fd: c_int) -> Result<Pid> { ++ let res = unsafe { libc::tcgetpgrp(fd) }; ++ Errno::result(res).map(Pid) ++} ++/// Set the terminal foreground process group (see ++/// [tcgetpgrp(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsetpgrp.html)). ++/// ++/// Get the group process id (PGID) to the foreground process group on the ++/// terminal associated to file descriptor (FD). ++#[inline] ++pub fn tcsetpgrp(fd: c_int, pgrp: Pid) -> Result<()> { ++ let res = unsafe { libc::tcsetpgrp(fd, pgrp.into()) }; ++ Errno::result(res).map(drop) ++} ++ ++ ++/// Get the group id of the calling process (see ++///[getpgrp(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpgrp.html)). ++/// ++/// Get the process group id (PGID) of the calling process. ++/// According to the man page it is always successful. ++#[inline] ++pub fn getpgrp() -> Pid { ++ Pid(unsafe { libc::getpgrp() }) ++} ++ ++/// Get the caller's thread ID (see ++/// [gettid(2)](http://man7.org/linux/man-pages/man2/gettid.2.html). ++/// ++/// This function is only available on Linux based systems. In a single ++/// threaded process, the main thread will have the same ID as the process. In ++/// a multithreaded process, each thread will have a unique thread id but the ++/// same process ID. ++/// ++/// No error handling is required as a thread id should always exist for any ++/// process, even if threads are not being used. ++#[cfg(any(target_os = "linux", target_os = "android"))] ++#[inline] ++pub fn gettid() -> Pid { ++ Pid(unsafe { libc::syscall(libc::SYS_gettid) as pid_t }) ++} ++ ++/// Create a copy of the specified file descriptor (see ++/// [dup(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/dup.html)). ++/// ++/// The new file descriptor will be have a new index but refer to the same ++/// resource as the old file descriptor and the old and new file descriptors may ++/// be used interchangeably. The new and old file descriptor share the same ++/// underlying resource, offset, and file status flags. The actual index used ++/// for the file descriptor will be the lowest fd index that is available. ++/// ++/// The two file descriptors do not share file descriptor flags (e.g. `OFlag::FD_CLOEXEC`). ++#[inline] ++pub fn dup(oldfd: RawFd) -> Result<RawFd> { ++ let res = unsafe { libc::dup(oldfd) }; ++ ++ Errno::result(res) ++} ++ ++/// Create a copy of the specified file descriptor using the specified fd (see ++/// [dup(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/dup.html)). ++/// ++/// This function behaves similar to `dup()` except that it will try to use the ++/// specified fd instead of allocating a new one. See the man pages for more ++/// detail on the exact behavior of this function. ++#[inline] ++pub fn dup2(oldfd: RawFd, newfd: RawFd) -> Result<RawFd> { ++ let res = unsafe { libc::dup2(oldfd, newfd) }; ++ ++ Errno::result(res) ++} ++ ++/// Create a new copy of the specified file descriptor using the specified fd ++/// and flags (see [dup(2)](http://man7.org/linux/man-pages/man2/dup.2.html)). ++/// ++/// This function behaves similar to `dup2()` but allows for flags to be ++/// specified. ++pub fn dup3(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd> { ++ dup3_polyfill(oldfd, newfd, flags) ++} ++ ++#[inline] ++fn dup3_polyfill(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd> { ++ if oldfd == newfd { ++ return Err(Error::Sys(Errno::EINVAL)); ++ } ++ ++ let fd = dup2(oldfd, newfd)?; ++ ++ if flags.contains(OFlag::O_CLOEXEC) { ++ if let Err(e) = fcntl(fd, F_SETFD(FdFlag::FD_CLOEXEC)) { ++ let _ = close(fd); ++ return Err(e); ++ } ++ } ++ ++ Ok(fd) ++} ++ ++/// Change the current working directory of the calling process (see ++/// [chdir(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/chdir.html)). ++/// ++/// This function may fail in a number of different scenarios. See the man ++/// pages for additional details on possible failure cases. ++#[inline] ++pub fn chdir<P: ?Sized + NixPath>(path: &P) -> Result<()> { ++ let res = path.with_nix_path(|cstr| { ++ unsafe { libc::chdir(cstr.as_ptr()) } ++ })?; ++ ++ Errno::result(res).map(drop) ++} ++ ++/// Change the current working directory of the process to the one ++/// given as an open file descriptor (see ++/// [fchdir(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fchdir.html)). ++/// ++/// This function may fail in a number of different scenarios. See the man ++/// pages for additional details on possible failure cases. ++#[inline] ++pub fn fchdir(dirfd: RawFd) -> Result<()> { ++ let res = unsafe { libc::fchdir(dirfd) }; ++ ++ Errno::result(res).map(drop) ++} ++ ++/// Creates new directory `path` with access rights `mode`. (see [mkdir(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mkdir.html)) ++/// ++/// # Errors ++/// ++/// There are several situations where mkdir might fail: ++/// ++/// - current user has insufficient rights in the parent directory ++/// - the path already exists ++/// - the path name is too long (longer than `PATH_MAX`, usually 4096 on linux, 1024 on OS X) ++/// ++/// # Example ++/// ++/// ```rust ++/// extern crate tempfile; ++/// extern crate nix; ++/// ++/// use nix::unistd; ++/// use nix::sys::stat; ++/// use tempfile::tempdir; ++/// ++/// fn main() { ++/// let tmp_dir1 = tempdir().unwrap(); ++/// let tmp_dir2 = tmp_dir1.path().join("new_dir"); ++/// ++/// // create new directory and give read, write and execute rights to the owner ++/// match unistd::mkdir(&tmp_dir2, stat::Mode::S_IRWXU) { ++/// Ok(_) => println!("created {:?}", tmp_dir2), ++/// Err(err) => println!("Error creating directory: {}", err), ++/// } ++/// } ++/// ``` ++#[inline] ++pub fn mkdir<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> { ++ let res = path.with_nix_path(|cstr| { ++ unsafe { libc::mkdir(cstr.as_ptr(), mode.bits() as mode_t) } ++ })?; ++ ++ Errno::result(res).map(drop) ++} ++ ++/// Creates new fifo special file (named pipe) with path `path` and access rights `mode`. ++/// ++/// # Errors ++/// ++/// There are several situations where mkfifo might fail: ++/// ++/// - current user has insufficient rights in the parent directory ++/// - the path already exists ++/// - the path name is too long (longer than `PATH_MAX`, usually 4096 on linux, 1024 on OS X) ++/// ++/// For a full list consult ++/// [posix specification](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mkfifo.html) ++/// ++/// # Example ++/// ++/// ```rust ++/// extern crate tempfile; ++/// extern crate nix; ++/// ++/// use nix::unistd; ++/// use nix::sys::stat; ++/// use tempfile::tempdir; ++/// ++/// fn main() { ++/// let tmp_dir = tempdir().unwrap(); ++/// let fifo_path = tmp_dir.path().join("foo.pipe"); ++/// ++/// // create new fifo and give read, write and execute rights to the owner ++/// match unistd::mkfifo(&fifo_path, stat::Mode::S_IRWXU) { ++/// Ok(_) => println!("created {:?}", fifo_path), ++/// Err(err) => println!("Error creating fifo: {}", err), ++/// } ++/// } ++/// ``` ++#[inline] ++pub fn mkfifo<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> { ++ let res = path.with_nix_path(|cstr| { ++ unsafe { libc::mkfifo(cstr.as_ptr(), mode.bits() as mode_t) } ++ })?; ++ ++ Errno::result(res).map(drop) ++} ++ ++/// Creates a symbolic link at `path2` which points to `path1`. ++/// ++/// If `dirfd` has a value, then `path2` is relative to directory associated ++/// with the file descriptor. ++/// ++/// If `dirfd` is `None`, then `path2` is relative to the current working ++/// directory. This is identical to `libc::symlink(path1, path2)`. ++/// ++/// See also [symlinkat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/symlinkat.html). ++pub fn symlinkat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>( ++ path1: &P1, ++ dirfd: Option<RawFd>, ++ path2: &P2) -> Result<()> { ++ let res = ++ path1.with_nix_path(|path1| { ++ path2.with_nix_path(|path2| { ++ unsafe { ++ libc::symlinkat( ++ path1.as_ptr(), ++ dirfd.unwrap_or(libc::AT_FDCWD), ++ path2.as_ptr() ++ ) ++ } ++ }) ++ })??; ++ Errno::result(res).map(drop) ++} ++ ++/// Returns the current directory as a `PathBuf` ++/// ++/// Err is returned if the current user doesn't have the permission to read or search a component ++/// of the current path. ++/// ++/// # Example ++/// ++/// ```rust ++/// extern crate nix; ++/// ++/// use nix::unistd; ++/// ++/// fn main() { ++/// // assume that we are allowed to get current directory ++/// let dir = unistd::getcwd().unwrap(); ++/// println!("The current directory is {:?}", dir); ++/// } ++/// ``` ++#[inline] ++pub fn getcwd() -> Result<PathBuf> { ++ let mut buf = Vec::with_capacity(512); ++ loop { ++ unsafe { ++ let ptr = buf.as_mut_ptr() as *mut c_char; ++ ++ // The buffer must be large enough to store the absolute pathname plus ++ // a terminating null byte, or else null is returned. ++ // To safely handle this we start with a reasonable size (512 bytes) ++ // and double the buffer size upon every error ++ if !libc::getcwd(ptr, buf.capacity()).is_null() { ++ let len = CStr::from_ptr(buf.as_ptr() as *const c_char).to_bytes().len(); ++ buf.set_len(len); ++ buf.shrink_to_fit(); ++ return Ok(PathBuf::from(OsString::from_vec(buf))); ++ } else { ++ let error = Errno::last(); ++ // ERANGE means buffer was too small to store directory name ++ if error != Errno::ERANGE { ++ return Err(Error::Sys(error)); ++ } ++ } ++ ++ // Trigger the internal buffer resizing logic of `Vec` by requiring ++ // more space than the current capacity. ++ let cap = buf.capacity(); ++ buf.set_len(cap); ++ buf.reserve(1); ++ } ++ } ++} ++ ++/// Computes the raw UID and GID values to pass to a `*chown` call. ++fn chown_raw_ids(owner: Option<Uid>, group: Option<Gid>) -> (libc::uid_t, libc::gid_t) { ++ // According to the POSIX specification, -1 is used to indicate that owner and group ++ // are not to be changed. Since uid_t and gid_t are unsigned types, we have to wrap ++ // around to get -1. ++ let uid = owner.map(Into::into).unwrap_or((0 as uid_t).wrapping_sub(1)); ++ let gid = group.map(Into::into).unwrap_or((0 as gid_t).wrapping_sub(1)); ++ (uid, gid) ++} ++ ++/// Change the ownership of the file at `path` to be owned by the specified ++/// `owner` (user) and `group` (see ++/// [chown(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/chown.html)). ++/// ++/// The owner/group for the provided path name will not be modified if `None` is ++/// provided for that argument. Ownership change will be attempted for the path ++/// only if `Some` owner/group is provided. ++#[inline] ++pub fn chown<P: ?Sized + NixPath>(path: &P, owner: Option<Uid>, group: Option<Gid>) -> Result<()> { ++ let res = path.with_nix_path(|cstr| { ++ let (uid, gid) = chown_raw_ids(owner, group); ++ unsafe { libc::chown(cstr.as_ptr(), uid, gid) } ++ })?; ++ ++ Errno::result(res).map(drop) ++} ++ ++/// Flags for `fchownat` function. ++#[derive(Clone, Copy, Debug)] ++pub enum FchownatFlags { ++ FollowSymlink, ++ NoFollowSymlink, ++} ++ ++/// Change the ownership of the file at `path` to be owned by the specified ++/// `owner` (user) and `group`. ++/// ++/// The owner/group for the provided path name will not be modified if `None` is ++/// provided for that argument. Ownership change will be attempted for the path ++/// only if `Some` owner/group is provided. ++/// ++/// The file to be changed is determined relative to the directory associated ++/// with the file descriptor `dirfd` or the current working directory ++/// if `dirfd` is `None`. ++/// ++/// If `flag` is `FchownatFlags::NoFollowSymlink` and `path` names a symbolic link, ++/// then the mode of the symbolic link is changed. ++/// ++/// `fchownat(None, path, mode, FchownatFlags::NoFollowSymlink)` is identical to ++/// a call `libc::lchown(path, mode)`. That's why `lchmod` is unimplemented in ++/// the `nix` crate. ++/// ++/// # References ++/// ++/// [fchownat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fchownat.html). ++pub fn fchownat<P: ?Sized + NixPath>( ++ dirfd: Option<RawFd>, ++ path: &P, ++ owner: Option<Uid>, ++ group: Option<Gid>, ++ flag: FchownatFlags, ++) -> Result<()> { ++ let atflag = ++ match flag { ++ FchownatFlags::FollowSymlink => AtFlags::empty(), ++ FchownatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW, ++ }; ++ let res = path.with_nix_path(|cstr| unsafe { ++ let (uid, gid) = chown_raw_ids(owner, group); ++ libc::fchownat(at_rawfd(dirfd), cstr.as_ptr(), uid, gid, ++ atflag.bits() as libc::c_int) ++ })?; ++ ++ Errno::result(res).map(drop) ++} ++ ++fn to_exec_array(args: &[CString]) -> Vec<*const c_char> { ++ let mut args_p: Vec<*const c_char> = args.iter().map(|s| s.as_ptr()).collect(); ++ args_p.push(ptr::null()); ++ args_p ++} ++ ++/// Replace the current process image with a new one (see ++/// [exec(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html)). ++/// ++/// See the `::nix::unistd::execve` system call for additional details. `execv` ++/// performs the same action but does not allow for customization of the ++/// environment for the new process. ++#[inline] ++pub fn execv(path: &CString, argv: &[CString]) -> Result<Void> { ++ let args_p = to_exec_array(argv); ++ ++ unsafe { ++ libc::execv(path.as_ptr(), args_p.as_ptr()) ++ }; ++ ++ Err(Error::Sys(Errno::last())) ++} ++ ++ ++/// Replace the current process image with a new one (see ++/// [execve(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html)). ++/// ++/// The execve system call allows for another process to be "called" which will ++/// replace the current process image. That is, this process becomes the new ++/// command that is run. On success, this function will not return. Instead, ++/// the new program will run until it exits. ++/// ++/// `::nix::unistd::execv` and `::nix::unistd::execve` take as arguments a slice ++/// of `::std::ffi::CString`s for `args` and `env` (for `execve`). Each element ++/// in the `args` list is an argument to the new process. Each element in the ++/// `env` list should be a string in the form "key=value". ++#[inline] ++pub fn execve(path: &CString, args: &[CString], env: &[CString]) -> Result<Void> { ++ let args_p = to_exec_array(args); ++ let env_p = to_exec_array(env); ++ ++ unsafe { ++ libc::execve(path.as_ptr(), args_p.as_ptr(), env_p.as_ptr()) ++ }; ++ ++ Err(Error::Sys(Errno::last())) ++} ++ ++/// Replace the current process image with a new one and replicate shell `PATH` ++/// searching behavior (see ++/// [exec(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html)). ++/// ++/// See `::nix::unistd::execve` for additional details. `execvp` behaves the ++/// same as execv except that it will examine the `PATH` environment variables ++/// for file names not specified with a leading slash. For example, `execv` ++/// would not work if "bash" was specified for the path argument, but `execvp` ++/// would assuming that a bash executable was on the system `PATH`. ++#[inline] ++pub fn execvp(filename: &CString, args: &[CString]) -> Result<Void> { ++ let args_p = to_exec_array(args); ++ ++ unsafe { ++ libc::execvp(filename.as_ptr(), args_p.as_ptr()) ++ }; ++ ++ Err(Error::Sys(Errno::last())) ++} ++ ++/// Replace the current process image with a new one and replicate shell `PATH` ++/// searching behavior (see ++/// [`execvpe(3)`](http://man7.org/linux/man-pages/man3/exec.3.html)). ++/// ++/// This functions like a combination of `execvp(2)` and `execve(2)` to pass an ++/// environment and have a search path. See these two for additional ++/// information. ++#[cfg(any(target_os = "haiku", ++ target_os = "linux", ++ target_os = "openbsd"))] ++pub fn execvpe(filename: &CString, args: &[CString], env: &[CString]) -> Result<Void> { ++ let args_p = to_exec_array(args); ++ let env_p = to_exec_array(env); ++ ++ unsafe { ++ libc::execvpe(filename.as_ptr(), args_p.as_ptr(), env_p.as_ptr()) ++ }; ++ ++ Err(Error::Sys(Errno::last())) ++} ++ ++/// Replace the current process image with a new one (see ++/// [fexecve(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fexecve.html)). ++/// ++/// The `fexecve` function allows for another process to be "called" which will ++/// replace the current process image. That is, this process becomes the new ++/// command that is run. On success, this function will not return. Instead, ++/// the new program will run until it exits. ++/// ++/// This function is similar to `execve`, except that the program to be executed ++/// is referenced as a file descriptor instead of a path. ++// Note for NetBSD and OpenBSD: although rust-lang/libc includes it (under ++// unix/bsd/netbsdlike/) fexecve is not currently implemented on NetBSD nor on ++// OpenBSD. ++#[cfg(any(target_os = "android", ++ target_os = "linux", ++ target_os = "freebsd"))] ++#[inline] ++pub fn fexecve(fd: RawFd, args: &[CString], env: &[CString]) -> Result<Void> { ++ let args_p = to_exec_array(args); ++ let env_p = to_exec_array(env); ++ ++ unsafe { ++ libc::fexecve(fd, args_p.as_ptr(), env_p.as_ptr()) ++ }; ++ ++ Err(Error::Sys(Errno::last())) ++} ++ ++/// Execute program relative to a directory file descriptor (see ++/// [execveat(2)](http://man7.org/linux/man-pages/man2/execveat.2.html)). ++/// ++/// The `execveat` function allows for another process to be "called" which will ++/// replace the current process image. That is, this process becomes the new ++/// command that is run. On success, this function will not return. Instead, ++/// the new program will run until it exits. ++/// ++/// This function is similar to `execve`, except that the program to be executed ++/// is referenced as a file descriptor to the base directory plus a path. ++#[cfg(any(target_os = "android", target_os = "linux"))] ++#[inline] ++pub fn execveat(dirfd: RawFd, pathname: &CString, args: &[CString], ++ env: &[CString], flags: super::fcntl::AtFlags) -> Result<Void> { ++ let args_p = to_exec_array(args); ++ let env_p = to_exec_array(env); ++ ++ unsafe { ++ libc::syscall(libc::SYS_execveat, dirfd, pathname.as_ptr(), ++ args_p.as_ptr(), env_p.as_ptr(), flags); ++ }; ++ ++ Err(Error::Sys(Errno::last())) ++} ++ ++/// Daemonize this process by detaching from the controlling terminal (see ++/// [daemon(3)](http://man7.org/linux/man-pages/man3/daemon.3.html)). ++/// ++/// When a process is launched it is typically associated with a parent and it, ++/// in turn, by its controlling terminal/process. In order for a process to run ++/// in the "background" it must daemonize itself by detaching itself. Under ++/// posix, this is done by doing the following: ++/// ++/// 1. Parent process (this one) forks ++/// 2. Parent process exits ++/// 3. Child process continues to run. ++/// ++/// `nochdir`: ++/// ++/// * `nochdir = true`: The current working directory after daemonizing will ++/// be the current working directory. ++/// * `nochdir = false`: The current working directory after daemonizing will ++/// be the root direcory, `/`. ++/// ++/// `noclose`: ++/// ++/// * `noclose = true`: The process' current stdin, stdout, and stderr file ++/// descriptors will remain identical after daemonizing. ++/// * `noclose = false`: The process' stdin, stdout, and stderr will point to ++/// `/dev/null` after daemonizing. ++#[cfg_attr(any(target_os = "macos", target_os = "ios"), deprecated( ++ since="0.14.0", ++ note="Deprecated in MacOSX 10.5" ++))] ++#[cfg_attr(any(target_os = "macos", target_os = "ios"), allow(deprecated))] ++pub fn daemon(nochdir: bool, noclose: bool) -> Result<()> { ++ let res = unsafe { libc::daemon(nochdir as c_int, noclose as c_int) }; ++ Errno::result(res).map(drop) ++} ++ ++/// Set the system host name (see ++/// [sethostname(2)](http://man7.org/linux/man-pages/man2/gethostname.2.html)). ++/// ++/// Given a name, attempt to update the system host name to the given string. ++/// On some systems, the host name is limited to as few as 64 bytes. An error ++/// will be return if the name is not valid or the current process does not have ++/// permissions to update the host name. ++pub fn sethostname<S: AsRef<OsStr>>(name: S) -> Result<()> { ++ // Handle some differences in type of the len arg across platforms. ++ cfg_if! { ++ if #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "macos", ))] { ++ type sethostname_len_t = c_int; ++ } else { ++ type sethostname_len_t = size_t; ++ } ++ } ++ let ptr = name.as_ref().as_bytes().as_ptr() as *const c_char; ++ let len = name.as_ref().len() as sethostname_len_t; ++ ++ let res = unsafe { libc::sethostname(ptr, len) }; ++ Errno::result(res).map(drop) ++} ++ ++/// Get the host name and store it in the provided buffer, returning a pointer ++/// the `CStr` in that buffer on success (see ++/// [gethostname(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/gethostname.html)). ++/// ++/// This function call attempts to get the host name for the running system and ++/// store it in a provided buffer. The buffer will be populated with bytes up ++/// to the length of the provided slice including a NUL terminating byte. If ++/// the hostname is longer than the length provided, no error will be provided. ++/// The posix specification does not specify whether implementations will ++/// null-terminate in this case, but the nix implementation will ensure that the ++/// buffer is null terminated in this case. ++/// ++/// ```no_run ++/// use nix::unistd; ++/// ++/// let mut buf = [0u8; 64]; ++/// let hostname_cstr = unistd::gethostname(&mut buf).expect("Failed getting hostname"); ++/// let hostname = hostname_cstr.to_str().expect("Hostname wasn't valid UTF-8"); ++/// println!("Hostname: {}", hostname); ++/// ``` ++pub fn gethostname(buffer: &mut [u8]) -> Result<&CStr> { ++ let ptr = buffer.as_mut_ptr() as *mut c_char; ++ let len = buffer.len() as size_t; ++ ++ let res = unsafe { libc::gethostname(ptr, len) }; ++ Errno::result(res).map(|_| { ++ buffer[len - 1] = 0; // ensure always null-terminated ++ unsafe { CStr::from_ptr(buffer.as_ptr() as *const c_char) } ++ }) ++} ++ ++/// Close a raw file descriptor ++/// ++/// Be aware that many Rust types implicitly close-on-drop, including ++/// `std::fs::File`. Explicitly closing them with this method too can result in ++/// a double-close condition, which can cause confusing `EBADF` errors in ++/// seemingly unrelated code. Caveat programmer. See also ++/// [close(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html). ++/// ++/// # Examples ++/// ++/// ```no_run ++/// extern crate tempfile; ++/// extern crate nix; ++/// ++/// use std::os::unix::io::AsRawFd; ++/// use nix::unistd::close; ++/// ++/// fn main() { ++/// let f = tempfile::tempfile().unwrap(); ++/// close(f.as_raw_fd()).unwrap(); // Bad! f will also close on drop! ++/// } ++/// ``` ++/// ++/// ```rust ++/// extern crate tempfile; ++/// extern crate nix; ++/// ++/// use std::os::unix::io::IntoRawFd; ++/// use nix::unistd::close; ++/// ++/// fn main() { ++/// let f = tempfile::tempfile().unwrap(); ++/// close(f.into_raw_fd()).unwrap(); // Good. into_raw_fd consumes f ++/// } ++/// ``` ++pub fn close(fd: RawFd) -> Result<()> { ++ let res = unsafe { libc::close(fd) }; ++ Errno::result(res).map(drop) ++} ++ ++/// Read from a raw file descriptor. ++/// ++/// See also [read(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html) ++pub fn read(fd: RawFd, buf: &mut [u8]) -> Result<usize> { ++ let res = unsafe { libc::read(fd, buf.as_mut_ptr() as *mut c_void, buf.len() as size_t) }; ++ ++ Errno::result(res).map(|r| r as usize) ++} ++ ++/// Write to a raw file descriptor. ++/// ++/// See also [write(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html) ++pub fn write(fd: RawFd, buf: &[u8]) -> Result<usize> { ++ let res = unsafe { libc::write(fd, buf.as_ptr() as *const c_void, buf.len() as size_t) }; ++ ++ Errno::result(res).map(|r| r as usize) ++} ++ ++/// Directive that tells [`lseek`] and [`lseek64`] what the offset is relative to. ++/// ++/// [`lseek`]: ./fn.lseek.html ++/// [`lseek64`]: ./fn.lseek64.html ++#[repr(i32)] ++#[derive(Clone, Copy, Debug)] ++pub enum Whence { ++ /// Specify an offset relative to the start of the file. ++ SeekSet = libc::SEEK_SET, ++ /// Specify an offset relative to the current file location. ++ SeekCur = libc::SEEK_CUR, ++ /// Specify an offset relative to the end of the file. ++ SeekEnd = libc::SEEK_END, ++ /// Specify an offset relative to the next location in the file greater than or ++ /// equal to offset that contains some data. If offset points to ++ /// some data, then the file offset is set to offset. ++ #[cfg(any(target_os = "dragonfly", target_os = "freebsd", ++ all(target_os = "linux", not(any(target_env = "musl", ++ target_arch = "mips", ++ target_arch = "mips64")))))] ++ SeekData = libc::SEEK_DATA, ++ /// Specify an offset relative to the next hole in the file greater than ++ /// or equal to offset. If offset points into the middle of a hole, then ++ /// the file offset should be set to offset. If there is no hole past offset, ++ /// then the file offset should be adjusted to the end of the file (i.e., there ++ /// is an implicit hole at the end of any file). ++ #[cfg(any(target_os = "dragonfly", target_os = "freebsd", ++ all(target_os = "linux", not(any(target_env = "musl", ++ target_arch = "mips", ++ target_arch = "mips64")))))] ++ SeekHole = libc::SEEK_HOLE ++} ++ ++/// Move the read/write file offset. ++/// ++/// See also [lseek(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/lseek.html) ++pub fn lseek(fd: RawFd, offset: off_t, whence: Whence) -> Result<off_t> { ++ let res = unsafe { libc::lseek(fd, offset, whence as i32) }; ++ ++ Errno::result(res).map(|r| r as off_t) ++} ++ ++#[cfg(any(target_os = "linux", target_os = "android"))] ++pub fn lseek64(fd: RawFd, offset: libc::off64_t, whence: Whence) -> Result<libc::off64_t> { ++ let res = unsafe { libc::lseek64(fd, offset, whence as i32) }; ++ ++ Errno::result(res).map(|r| r as libc::off64_t) ++} ++ ++/// Create an interprocess channel. ++/// ++/// See also [pipe(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pipe.html) ++pub fn pipe() -> Result<(RawFd, RawFd)> { ++ unsafe { ++ let mut fds: [c_int; 2] = mem::uninitialized(); ++ ++ let res = libc::pipe(fds.as_mut_ptr()); ++ ++ Errno::result(res)?; ++ ++ Ok((fds[0], fds[1])) ++ } ++} ++ ++/// Like `pipe`, but allows setting certain file descriptor flags. ++/// ++/// The following flags are supported, and will be set atomically as the pipe is ++/// created: ++/// ++/// `O_CLOEXEC`: Set the close-on-exec flag for the new file descriptors. ++/// `O_NONBLOCK`: Set the non-blocking flag for the ends of the pipe. ++/// ++/// See also [pipe(2)](http://man7.org/linux/man-pages/man2/pipe.2.html) ++#[cfg(any(target_os = "android", ++ target_os = "dragonfly", ++ target_os = "emscripten", ++ target_os = "freebsd", ++ target_os = "linux", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> { ++ let mut fds: [c_int; 2] = unsafe { mem::uninitialized() }; ++ ++ let res = unsafe { libc::pipe2(fds.as_mut_ptr(), flags.bits()) }; ++ ++ Errno::result(res)?; ++ ++ Ok((fds[0], fds[1])) ++} ++ ++/// Like `pipe`, but allows setting certain file descriptor flags. ++/// ++/// The following flags are supported, and will be set after the pipe is ++/// created: ++/// ++/// `O_CLOEXEC`: Set the close-on-exec flag for the new file descriptors. ++/// `O_NONBLOCK`: Set the non-blocking flag for the ends of the pipe. ++#[cfg(any(target_os = "ios", target_os = "macos"))] ++#[deprecated( ++ since="0.10.0", ++ note="pipe2(2) is not actually atomic on these platforms. Use pipe(2) and fcntl(2) instead" ++)] ++pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> { ++ let mut fds: [c_int; 2] = unsafe { mem::uninitialized() }; ++ ++ let res = unsafe { libc::pipe(fds.as_mut_ptr()) }; ++ ++ Errno::result(res)?; ++ ++ pipe2_setflags(fds[0], fds[1], flags)?; ++ ++ Ok((fds[0], fds[1])) ++} ++ ++#[cfg(any(target_os = "ios", target_os = "macos"))] ++fn pipe2_setflags(fd1: RawFd, fd2: RawFd, flags: OFlag) -> Result<()> { ++ use fcntl::FcntlArg::F_SETFL; ++ ++ let mut res = Ok(0); ++ ++ if flags.contains(OFlag::O_CLOEXEC) { ++ res = res ++ .and_then(|_| fcntl(fd1, F_SETFD(FdFlag::FD_CLOEXEC))) ++ .and_then(|_| fcntl(fd2, F_SETFD(FdFlag::FD_CLOEXEC))); ++ } ++ ++ if flags.contains(OFlag::O_NONBLOCK) { ++ res = res ++ .and_then(|_| fcntl(fd1, F_SETFL(OFlag::O_NONBLOCK))) ++ .and_then(|_| fcntl(fd2, F_SETFL(OFlag::O_NONBLOCK))); ++ } ++ ++ match res { ++ Ok(_) => Ok(()), ++ Err(e) => { ++ let _ = close(fd1); ++ let _ = close(fd2); ++ Err(e) ++ } ++ } ++} ++ ++/// Truncate a file to a specified length ++/// ++/// See also ++/// [truncate(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/truncate.html) ++pub fn truncate<P: ?Sized + NixPath>(path: &P, len: off_t) -> Result<()> { ++ let res = path.with_nix_path(|cstr| { ++ unsafe { ++ libc::truncate(cstr.as_ptr(), len) ++ } ++ })?; ++ ++ Errno::result(res).map(drop) ++} ++ ++/// Truncate a file to a specified length ++/// ++/// See also ++/// [ftruncate(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html) ++pub fn ftruncate(fd: RawFd, len: off_t) -> Result<()> { ++ Errno::result(unsafe { libc::ftruncate(fd, len) }).map(drop) ++} ++ ++pub fn isatty(fd: RawFd) -> Result<bool> { ++ unsafe { ++ // ENOTTY means `fd` is a valid file descriptor, but not a TTY, so ++ // we return `Ok(false)` ++ if libc::isatty(fd) == 1 { ++ Ok(true) ++ } else { ++ match Errno::last() { ++ Errno::ENOTTY => Ok(false), ++ err => Err(Error::Sys(err)), ++ } ++ } ++ } ++} ++ ++/// Remove a directory entry ++/// ++/// See also [unlink(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/unlink.html) ++pub fn unlink<P: ?Sized + NixPath>(path: &P) -> Result<()> { ++ let res = path.with_nix_path(|cstr| { ++ unsafe { ++ libc::unlink(cstr.as_ptr()) ++ } ++ })?; ++ Errno::result(res).map(drop) ++} ++ ++/// Flags for `unlinkat` function. ++#[derive(Clone, Copy, Debug)] ++pub enum UnlinkatFlags { ++ RemoveDir, ++ NoRemoveDir, ++} ++ ++/// Remove a directory entry ++/// ++/// In the case of a relative path, the directory entry to be removed is determined relative to ++/// the directory associated with the file descriptor `dirfd` or the current working directory ++/// if `dirfd` is `None`. In the case of an absolute `path` `dirfd` is ignored. If `flag` is ++/// `UnlinkatFlags::RemoveDir` then removal of the directory entry specified by `dirfd` and `path` ++/// is performed. ++/// ++/// # References ++/// See also [unlinkat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/unlinkat.html) ++pub fn unlinkat<P: ?Sized + NixPath>( ++ dirfd: Option<RawFd>, ++ path: &P, ++ flag: UnlinkatFlags, ++) -> Result<()> { ++ let atflag = ++ match flag { ++ UnlinkatFlags::RemoveDir => AtFlags::AT_REMOVEDIR, ++ UnlinkatFlags::NoRemoveDir => AtFlags::empty(), ++ }; ++ let res = path.with_nix_path(|cstr| { ++ unsafe { ++ libc::unlinkat(at_rawfd(dirfd), cstr.as_ptr(), atflag.bits() as libc::c_int) ++ } ++ })?; ++ Errno::result(res).map(drop) ++} ++ ++ ++#[inline] ++pub fn chroot<P: ?Sized + NixPath>(path: &P) -> Result<()> { ++ let res = path.with_nix_path(|cstr| { ++ unsafe { libc::chroot(cstr.as_ptr()) } ++ })?; ++ ++ Errno::result(res).map(drop) ++} ++ ++/// Commit filesystem caches to disk ++/// ++/// See also [sync(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sync.html) ++#[cfg(any( ++ target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "linux", ++ target_os = "netbsd", ++ target_os = "openbsd" ++))] ++pub fn sync() -> () { ++ unsafe { libc::sync() }; ++} ++ ++/// Synchronize changes to a file ++/// ++/// See also [fsync(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html) ++#[inline] ++pub fn fsync(fd: RawFd) -> Result<()> { ++ let res = unsafe { libc::fsync(fd) }; ++ ++ Errno::result(res).map(drop) ++} ++ ++/// Synchronize the data of a file ++/// ++/// See also ++/// [fdatasync(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fdatasync.html) ++// `fdatasync(2) is in POSIX, but in libc it is only defined in `libc::notbsd`. ++// TODO: exclude only Apple systems after https://github.com/rust-lang/libc/pull/211 ++#[cfg(any(target_os = "linux", ++ target_os = "android", ++ target_os = "emscripten"))] ++#[inline] ++pub fn fdatasync(fd: RawFd) -> Result<()> { ++ let res = unsafe { libc::fdatasync(fd) }; ++ ++ Errno::result(res).map(drop) ++} ++ ++/// Get a real user ID ++/// ++/// See also [getuid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getuid.html) ++// POSIX requires that getuid is always successful, so no need to check return ++// value or errno. ++#[inline] ++pub fn getuid() -> Uid { ++ Uid(unsafe { libc::getuid() }) ++} ++ ++/// Get the effective user ID ++/// ++/// See also [geteuid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/geteuid.html) ++// POSIX requires that geteuid is always successful, so no need to check return ++// value or errno. ++#[inline] ++pub fn geteuid() -> Uid { ++ Uid(unsafe { libc::geteuid() }) ++} ++ ++/// Get the real group ID ++/// ++/// See also [getgid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getgid.html) ++// POSIX requires that getgid is always successful, so no need to check return ++// value or errno. ++#[inline] ++pub fn getgid() -> Gid { ++ Gid(unsafe { libc::getgid() }) ++} ++ ++/// Get the effective group ID ++/// ++/// See also [getegid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getegid.html) ++// POSIX requires that getegid is always successful, so no need to check return ++// value or errno. ++#[inline] ++pub fn getegid() -> Gid { ++ Gid(unsafe { libc::getegid() }) ++} ++ ++/// Set the effective user ID ++/// ++/// See also [seteuid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/seteuid.html) ++#[inline] ++pub fn seteuid(euid: Uid) -> Result<()> { ++ let res = unsafe { libc::seteuid(euid.into()) }; ++ ++ Errno::result(res).map(drop) ++} ++ ++/// Set the effective group ID ++/// ++/// See also [setegid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setegid.html) ++#[inline] ++pub fn setegid(egid: Gid) -> Result<()> { ++ let res = unsafe { libc::setegid(egid.into()) }; ++ ++ Errno::result(res).map(drop) ++} ++ ++/// Set the user ID ++/// ++/// See also [setuid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setuid.html) ++#[inline] ++pub fn setuid(uid: Uid) -> Result<()> { ++ let res = unsafe { libc::setuid(uid.into()) }; ++ ++ Errno::result(res).map(drop) ++} ++ ++/// Set the group ID ++/// ++/// See also [setgid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setgid.html) ++#[inline] ++pub fn setgid(gid: Gid) -> Result<()> { ++ let res = unsafe { libc::setgid(gid.into()) }; ++ ++ Errno::result(res).map(drop) ++} ++ ++/// Get the list of supplementary group IDs of the calling process. ++/// ++/// [Further reading](http://pubs.opengroup.org/onlinepubs/009695399/functions/getgroups.html) ++/// ++/// **Note:** This function is not available for Apple platforms. On those ++/// platforms, checking group membership should be achieved via communication ++/// with the `opendirectoryd` service. ++#[cfg(not(any(target_os = "ios", target_os = "macos")))] ++pub fn getgroups() -> Result<Vec<Gid>> { ++ // First get the number of groups so we can size our Vec ++ let ret = unsafe { libc::getgroups(0, ptr::null_mut()) }; ++ ++ // Now actually get the groups. We try multiple times in case the number of ++ // groups has changed since the first call to getgroups() and the buffer is ++ // now too small. ++ let mut groups = Vec::<Gid>::with_capacity(Errno::result(ret)? as usize); ++ loop { ++ // FIXME: On the platforms we currently support, the `Gid` struct has ++ // the same representation in memory as a bare `gid_t`. This is not ++ // necessarily the case on all Rust platforms, though. See RFC 1785. ++ let ret = unsafe { ++ libc::getgroups(groups.capacity() as c_int, groups.as_mut_ptr() as *mut gid_t) ++ }; ++ ++ match Errno::result(ret) { ++ Ok(s) => { ++ unsafe { groups.set_len(s as usize) }; ++ return Ok(groups); ++ }, ++ Err(Error::Sys(Errno::EINVAL)) => { ++ // EINVAL indicates that the buffer size was too small. Trigger ++ // the internal buffer resizing logic of `Vec` by requiring ++ // more space than the current capacity. ++ let cap = groups.capacity(); ++ unsafe { groups.set_len(cap) }; ++ groups.reserve(1); ++ }, ++ Err(e) => return Err(e) ++ } ++ } ++} ++ ++/// Set the list of supplementary group IDs for the calling process. ++/// ++/// [Further reading](http://man7.org/linux/man-pages/man2/getgroups.2.html) ++/// ++/// **Note:** This function is not available for Apple platforms. On those ++/// platforms, group membership management should be achieved via communication ++/// with the `opendirectoryd` service. ++/// ++/// # Examples ++/// ++/// `setgroups` can be used when dropping privileges from the root user to a ++/// specific user and group. For example, given the user `www-data` with UID ++/// `33` and the group `backup` with the GID `34`, one could switch the user as ++/// follows: ++/// ++/// ```rust,no_run ++/// # use std::error::Error; ++/// # use nix::unistd::*; ++/// # ++/// # fn try_main() -> Result<(), Box<Error>> { ++/// let uid = Uid::from_raw(33); ++/// let gid = Gid::from_raw(34); ++/// setgroups(&[gid])?; ++/// setgid(gid)?; ++/// setuid(uid)?; ++/// # ++/// # Ok(()) ++/// # } ++/// # ++/// # fn main() { ++/// # try_main().unwrap(); ++/// # } ++/// ``` ++#[cfg(not(any(target_os = "ios", target_os = "macos")))] ++pub fn setgroups(groups: &[Gid]) -> Result<()> { ++ cfg_if! { ++ if #[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] { ++ type setgroups_ngroups_t = c_int; ++ } else { ++ type setgroups_ngroups_t = size_t; ++ } ++ } ++ // FIXME: On the platforms we currently support, the `Gid` struct has the ++ // same representation in memory as a bare `gid_t`. This is not necessarily ++ // the case on all Rust platforms, though. See RFC 1785. ++ let res = unsafe { ++ libc::setgroups(groups.len() as setgroups_ngroups_t, groups.as_ptr() as *const gid_t) ++ }; ++ ++ Errno::result(res).map(drop) ++} ++ ++/// Calculate the supplementary group access list. ++/// ++/// Gets the group IDs of all groups that `user` is a member of. The additional ++/// group `group` is also added to the list. ++/// ++/// [Further reading](http://man7.org/linux/man-pages/man3/getgrouplist.3.html) ++/// ++/// **Note:** This function is not available for Apple platforms. On those ++/// platforms, checking group membership should be achieved via communication ++/// with the `opendirectoryd` service. ++/// ++/// # Errors ++/// ++/// Although the `getgrouplist()` call does not return any specific ++/// errors on any known platforms, this implementation will return a system ++/// error of `EINVAL` if the number of groups to be fetched exceeds the ++/// `NGROUPS_MAX` sysconf value. This mimics the behaviour of `getgroups()` ++/// and `setgroups()`. Additionally, while some implementations will return a ++/// partial list of groups when `NGROUPS_MAX` is exceeded, this implementation ++/// will only ever return the complete list or else an error. ++#[cfg(not(any(target_os = "ios", target_os = "macos")))] ++pub fn getgrouplist(user: &CStr, group: Gid) -> Result<Vec<Gid>> { ++ let ngroups_max = match sysconf(SysconfVar::NGROUPS_MAX) { ++ Ok(Some(n)) => n as c_int, ++ Ok(None) | Err(_) => <c_int>::max_value(), ++ }; ++ use std::cmp::min; ++ let mut ngroups = min(ngroups_max, 8); ++ let mut groups = Vec::<Gid>::with_capacity(ngroups as usize); ++ cfg_if! { ++ if #[cfg(any(target_os = "ios", target_os = "macos"))] { ++ type getgrouplist_group_t = c_int; ++ } else { ++ type getgrouplist_group_t = gid_t; ++ } ++ } ++ let gid: gid_t = group.into(); ++ loop { ++ let ret = unsafe { ++ libc::getgrouplist(user.as_ptr(), ++ gid as getgrouplist_group_t, ++ groups.as_mut_ptr() as *mut getgrouplist_group_t, ++ &mut ngroups) ++ }; ++ ++ // BSD systems only return 0 or -1, Linux returns ngroups on success. ++ if ret >= 0 { ++ unsafe { groups.set_len(ngroups as usize) }; ++ return Ok(groups); ++ } else if ret == -1 { ++ // Returns -1 if ngroups is too small, but does not set errno. ++ // BSD systems will still fill the groups buffer with as many ++ // groups as possible, but Linux manpages do not mention this ++ // behavior. ++ ++ let cap = groups.capacity(); ++ if cap >= ngroups_max as usize { ++ // We already have the largest capacity we can, give up ++ return Err(Error::invalid_argument()); ++ } ++ ++ // Reserve space for at least ngroups ++ groups.reserve(ngroups as usize); ++ ++ // Even if the buffer gets resized to bigger than ngroups_max, ++ // don't ever ask for more than ngroups_max groups ++ ngroups = min(ngroups_max, groups.capacity() as c_int); ++ } ++ } ++} ++ ++/// Initialize the supplementary group access list. ++/// ++/// Sets the supplementary group IDs for the calling process using all groups ++/// that `user` is a member of. The additional group `group` is also added to ++/// the list. ++/// ++/// [Further reading](http://man7.org/linux/man-pages/man3/initgroups.3.html) ++/// ++/// **Note:** This function is not available for Apple platforms. On those ++/// platforms, group membership management should be achieved via communication ++/// with the `opendirectoryd` service. ++/// ++/// # Examples ++/// ++/// `initgroups` can be used when dropping privileges from the root user to ++/// another user. For example, given the user `www-data`, we could look up the ++/// UID and GID for the user in the system's password database (usually found ++/// in `/etc/passwd`). If the `www-data` user's UID and GID were `33` and `33`, ++/// respectively, one could switch the user as follows: ++/// ++/// ```rust,no_run ++/// # use std::error::Error; ++/// # use std::ffi::CString; ++/// # use nix::unistd::*; ++/// # ++/// # fn try_main() -> Result<(), Box<Error>> { ++/// let user = CString::new("www-data").unwrap(); ++/// let uid = Uid::from_raw(33); ++/// let gid = Gid::from_raw(33); ++/// initgroups(&user, gid)?; ++/// setgid(gid)?; ++/// setuid(uid)?; ++/// # ++/// # Ok(()) ++/// # } ++/// # ++/// # fn main() { ++/// # try_main().unwrap(); ++/// # } ++/// ``` ++#[cfg(not(any(target_os = "ios", target_os = "macos")))] ++pub fn initgroups(user: &CStr, group: Gid) -> Result<()> { ++ cfg_if! { ++ if #[cfg(any(target_os = "ios", target_os = "macos"))] { ++ type initgroups_group_t = c_int; ++ } else { ++ type initgroups_group_t = gid_t; ++ } ++ } ++ let gid: gid_t = group.into(); ++ let res = unsafe { libc::initgroups(user.as_ptr(), gid as initgroups_group_t) }; ++ ++ Errno::result(res).map(drop) ++} ++ ++/// Suspend the thread until a signal is received. ++/// ++/// See also [pause(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pause.html). ++#[inline] ++pub fn pause() { ++ unsafe { libc::pause() }; ++} ++ ++pub mod alarm { ++ //! Alarm signal scheduling. ++ //! ++ //! Scheduling an alarm will trigger a `SIGALRM` signal when the time has ++ //! elapsed, which has to be caught, because the default action for the ++ //! signal is to terminate the program. This signal also can't be ignored ++ //! because the system calls like `pause` will not be interrupted, see the ++ //! second example below. ++ //! ++ //! # Examples ++ //! ++ //! Canceling an alarm: ++ //! ++ //! ``` ++ //! use nix::unistd::alarm; ++ //! ++ //! // Set an alarm for 60 seconds from now. ++ //! alarm::set(60); ++ //! ++ //! // Cancel the above set alarm, which returns the number of seconds left ++ //! // of the previously set alarm. ++ //! assert_eq!(alarm::cancel(), Some(60)); ++ //! ``` ++ //! ++ //! Scheduling an alarm and waiting for the signal: ++ //! ++ //! ``` ++ //! use std::time::{Duration, Instant}; ++ //! ++ //! use nix::unistd::{alarm, pause}; ++ //! use nix::sys::signal::*; ++ //! ++ //! // We need to setup an empty signal handler to catch the alarm signal, ++ //! // otherwise the program will be terminated once the signal is delivered. ++ //! extern fn signal_handler(_: nix::libc::c_int) { } ++ //! unsafe { sigaction(Signal::SIGALRM, &SigAction::new(SigHandler::Handler(signal_handler), SaFlags::empty(), SigSet::empty())); } ++ //! ++ //! // Set an alarm for 1 second from now. ++ //! alarm::set(1); ++ //! ++ //! let start = Instant::now(); ++ //! // Pause the process until the alarm signal is received. ++ //! pause(); ++ //! ++ //! assert!(start.elapsed() >= Duration::from_secs(1)); ++ //! ``` ++ //! ++ //! # References ++ //! ++ //! See also [alarm(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/alarm.html). ++ ++ use libc; ++ ++ /// Schedule an alarm signal. ++ /// ++ /// This will cause the system to generate a `SIGALRM` signal for the ++ /// process after the specified number of seconds have elapsed. ++ /// ++ /// Returns the leftover time of a previously set alarm if there was one. ++ pub fn set(secs: libc::c_uint) -> Option<libc::c_uint> { ++ assert!(secs != 0, "passing 0 to `alarm::set` is not allowed, to cancel an alarm use `alarm::cancel`"); ++ alarm(secs) ++ } ++ ++ /// Cancel an previously set alarm signal. ++ /// ++ /// Returns the leftover time of a previously set alarm if there was one. ++ pub fn cancel() -> Option<libc::c_uint> { ++ alarm(0) ++ } ++ ++ fn alarm(secs: libc::c_uint) -> Option<libc::c_uint> { ++ match unsafe { libc::alarm(secs) } { ++ 0 => None, ++ secs => Some(secs), ++ } ++ } ++} ++ ++/// Suspend execution for an interval of time ++/// ++/// See also [sleep(2)](http://pubs.opengroup.org/onlinepubs/009695399/functions/sleep.html#tag_03_705_05) ++// Per POSIX, does not fail ++#[inline] ++pub fn sleep(seconds: c_uint) -> c_uint { ++ unsafe { libc::sleep(seconds) } ++} ++ ++pub mod acct { ++ use libc; ++ use {Result, NixPath}; ++ use errno::Errno; ++ use std::ptr; ++ ++ /// Enable process accounting ++ /// ++ /// See also [acct(2)](https://linux.die.net/man/2/acct) ++ pub fn enable<P: ?Sized + NixPath>(filename: &P) -> Result<()> { ++ let res = filename.with_nix_path(|cstr| { ++ unsafe { libc::acct(cstr.as_ptr()) } ++ })?; ++ ++ Errno::result(res).map(drop) ++ } ++ ++ /// Disable process accounting ++ pub fn disable() -> Result<()> { ++ let res = unsafe { libc::acct(ptr::null()) }; ++ ++ Errno::result(res).map(drop) ++ } ++} ++ ++/// Creates a regular file which persists even after process termination ++/// ++/// * `template`: a path whose 6 rightmost characters must be X, e.g. `/tmp/tmpfile_XXXXXX` ++/// * returns: tuple of file descriptor and filename ++/// ++/// Err is returned either if no temporary filename could be created or the template doesn't ++/// end with XXXXXX ++/// ++/// See also [mkstemp(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mkstemp.html) ++/// ++/// # Example ++/// ++/// ```rust ++/// use nix::unistd; ++/// ++/// let _ = match unistd::mkstemp("/tmp/tempfile_XXXXXX") { ++/// Ok((fd, path)) => { ++/// unistd::unlink(path.as_path()).unwrap(); // flag file to be deleted at app termination ++/// fd ++/// } ++/// Err(e) => panic!("mkstemp failed: {}", e) ++/// }; ++/// // do something with fd ++/// ``` ++#[inline] ++pub fn mkstemp<P: ?Sized + NixPath>(template: &P) -> Result<(RawFd, PathBuf)> { ++ let mut path = template.with_nix_path(|path| {path.to_bytes_with_nul().to_owned()})?; ++ let p = path.as_mut_ptr() as *mut _; ++ let fd = unsafe { libc::mkstemp(p) }; ++ let last = path.pop(); // drop the trailing nul ++ debug_assert!(last == Some(b'\0')); ++ let pathname = OsString::from_vec(path); ++ Errno::result(fd)?; ++ Ok((fd, PathBuf::from(pathname))) ++} ++ ++/// Variable names for `pathconf` ++/// ++/// Nix uses the same naming convention for these variables as the ++/// [getconf(1)](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/getconf.html) utility. ++/// That is, `PathconfVar` variables have the same name as the abstract ++/// variables shown in the `pathconf(2)` man page. Usually, it's the same as ++/// the C variable name without the leading `_PC_`. ++/// ++/// POSIX 1003.1-2008 standardizes all of these variables, but some OSes choose ++/// not to implement variables that cannot change at runtime. ++/// ++/// # References ++/// ++/// - [pathconf(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html) ++/// - [limits.h](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html) ++/// - [unistd.h](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/unistd.h.html) ++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] ++#[repr(i32)] ++pub enum PathconfVar { ++ #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "linux", ++ target_os = "netbsd", target_os = "openbsd"))] ++ /// Minimum number of bits needed to represent, as a signed integer value, ++ /// the maximum size of a regular file allowed in the specified directory. ++ FILESIZEBITS = libc::_PC_FILESIZEBITS, ++ /// Maximum number of links to a single file. ++ LINK_MAX = libc::_PC_LINK_MAX, ++ /// Maximum number of bytes in a terminal canonical input line. ++ MAX_CANON = libc::_PC_MAX_CANON, ++ /// Minimum number of bytes for which space is available in a terminal input ++ /// queue; therefore, the maximum number of bytes a conforming application ++ /// may require to be typed as input before reading them. ++ MAX_INPUT = libc::_PC_MAX_INPUT, ++ /// Maximum number of bytes in a filename (not including the terminating ++ /// null of a filename string). ++ NAME_MAX = libc::_PC_NAME_MAX, ++ /// Maximum number of bytes the implementation will store as a pathname in a ++ /// user-supplied buffer of unspecified size, including the terminating null ++ /// character. Minimum number the implementation will accept as the maximum ++ /// number of bytes in a pathname. ++ PATH_MAX = libc::_PC_PATH_MAX, ++ /// Maximum number of bytes that is guaranteed to be atomic when writing to ++ /// a pipe. ++ PIPE_BUF = libc::_PC_PIPE_BUF, ++ #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "linux", ++ target_os = "netbsd", target_os = "openbsd"))] ++ /// Symbolic links can be created. ++ POSIX2_SYMLINKS = libc::_PC_2_SYMLINKS, ++ #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", ++ target_os = "linux", target_os = "openbsd"))] ++ /// Minimum number of bytes of storage actually allocated for any portion of ++ /// a file. ++ POSIX_ALLOC_SIZE_MIN = libc::_PC_ALLOC_SIZE_MIN, ++ #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", ++ target_os = "linux", target_os = "openbsd"))] ++ /// Recommended increment for file transfer sizes between the ++ /// `POSIX_REC_MIN_XFER_SIZE` and `POSIX_REC_MAX_XFER_SIZE` values. ++ POSIX_REC_INCR_XFER_SIZE = libc::_PC_REC_INCR_XFER_SIZE, ++ #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", ++ target_os = "linux", target_os = "openbsd"))] ++ /// Maximum recommended file transfer size. ++ POSIX_REC_MAX_XFER_SIZE = libc::_PC_REC_MAX_XFER_SIZE, ++ #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", ++ target_os = "linux", target_os = "openbsd"))] ++ /// Minimum recommended file transfer size. ++ POSIX_REC_MIN_XFER_SIZE = libc::_PC_REC_MIN_XFER_SIZE, ++ #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", ++ target_os = "linux", target_os = "openbsd"))] ++ /// Recommended file transfer buffer alignment. ++ POSIX_REC_XFER_ALIGN = libc::_PC_REC_XFER_ALIGN, ++ #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", ++ target_os = "linux", target_os = "netbsd", target_os = "openbsd"))] ++ /// Maximum number of bytes in a symbolic link. ++ SYMLINK_MAX = libc::_PC_SYMLINK_MAX, ++ /// The use of `chown` and `fchown` is restricted to a process with ++ /// appropriate privileges, and to changing the group ID of a file only to ++ /// the effective group ID of the process or to one of its supplementary ++ /// group IDs. ++ _POSIX_CHOWN_RESTRICTED = libc::_PC_CHOWN_RESTRICTED, ++ /// Pathname components longer than {NAME_MAX} generate an error. ++ _POSIX_NO_TRUNC = libc::_PC_NO_TRUNC, ++ /// This symbol shall be defined to be the value of a character that shall ++ /// disable terminal special character handling. ++ _POSIX_VDISABLE = libc::_PC_VDISABLE, ++ #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", ++ target_os = "linux", target_os = "openbsd"))] ++ /// Asynchronous input or output operations may be performed for the ++ /// associated file. ++ _POSIX_ASYNC_IO = libc::_PC_ASYNC_IO, ++ #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", ++ target_os = "linux", target_os = "openbsd"))] ++ /// Prioritized input or output operations may be performed for the ++ /// associated file. ++ _POSIX_PRIO_IO = libc::_PC_PRIO_IO, ++ #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", ++ target_os = "linux", target_os = "netbsd", target_os = "openbsd"))] ++ /// Synchronized input or output operations may be performed for the ++ /// associated file. ++ _POSIX_SYNC_IO = libc::_PC_SYNC_IO, ++ #[cfg(any(target_os = "dragonfly", target_os = "openbsd"))] ++ /// The resolution in nanoseconds for all file timestamps. ++ _POSIX_TIMESTAMP_RESOLUTION = libc::_PC_TIMESTAMP_RESOLUTION ++} ++ ++/// Like `pathconf`, but works with file descriptors instead of paths (see ++/// [fpathconf(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html)) ++/// ++/// # Parameters ++/// ++/// - `fd`: The file descriptor whose variable should be interrogated ++/// - `var`: The pathconf variable to lookup ++/// ++/// # Returns ++/// ++/// - `Ok(Some(x))`: the variable's limit (for limit variables) or its ++/// implementation level (for option variables). Implementation levels are ++/// usually a decimal-coded date, such as 200112 for POSIX 2001.12 ++/// - `Ok(None)`: the variable has no limit (for limit variables) or is ++/// unsupported (for option variables) ++/// - `Err(x)`: an error occurred ++pub fn fpathconf(fd: RawFd, var: PathconfVar) -> Result<Option<c_long>> { ++ let raw = unsafe { ++ Errno::clear(); ++ libc::fpathconf(fd, var as c_int) ++ }; ++ if raw == -1 { ++ if errno::errno() == 0 { ++ Ok(None) ++ } else { ++ Err(Error::Sys(Errno::last())) ++ } ++ } else { ++ Ok(Some(raw)) ++ } ++} ++ ++/// Get path-dependent configurable system variables (see ++/// [pathconf(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html)) ++/// ++/// Returns the value of a path-dependent configurable system variable. Most ++/// supported variables also have associated compile-time constants, but POSIX ++/// allows their values to change at runtime. There are generally two types of ++/// `pathconf` variables: options and limits. See [pathconf(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html) for more details. ++/// ++/// # Parameters ++/// ++/// - `path`: Lookup the value of `var` for this file or directory ++/// - `var`: The `pathconf` variable to lookup ++/// ++/// # Returns ++/// ++/// - `Ok(Some(x))`: the variable's limit (for limit variables) or its ++/// implementation level (for option variables). Implementation levels are ++/// usually a decimal-coded date, such as 200112 for POSIX 2001.12 ++/// - `Ok(None)`: the variable has no limit (for limit variables) or is ++/// unsupported (for option variables) ++/// - `Err(x)`: an error occurred ++pub fn pathconf<P: ?Sized + NixPath>(path: &P, var: PathconfVar) -> Result<Option<c_long>> { ++ let raw = path.with_nix_path(|cstr| { ++ unsafe { ++ Errno::clear(); ++ libc::pathconf(cstr.as_ptr(), var as c_int) ++ } ++ })?; ++ if raw == -1 { ++ if errno::errno() == 0 { ++ Ok(None) ++ } else { ++ Err(Error::Sys(Errno::last())) ++ } ++ } else { ++ Ok(Some(raw)) ++ } ++} ++ ++/// Variable names for `sysconf` ++/// ++/// Nix uses the same naming convention for these variables as the ++/// [getconf(1)](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/getconf.html) utility. ++/// That is, `SysconfVar` variables have the same name as the abstract variables ++/// shown in the `sysconf(3)` man page. Usually, it's the same as the C ++/// variable name without the leading `_SC_`. ++/// ++/// All of these symbols are standardized by POSIX 1003.1-2008, but haven't been ++/// implemented by all platforms. ++/// ++/// # References ++/// ++/// - [sysconf(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sysconf.html) ++/// - [unistd.h](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/unistd.h.html) ++/// - [limits.h](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html) ++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] ++#[repr(i32)] ++pub enum SysconfVar { ++ /// Maximum number of I/O operations in a single list I/O call supported by ++ /// the implementation. ++ AIO_LISTIO_MAX = libc::_SC_AIO_LISTIO_MAX, ++ /// Maximum number of outstanding asynchronous I/O operations supported by ++ /// the implementation. ++ AIO_MAX = libc::_SC_AIO_MAX, ++ #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", ++ target_os = "ios", target_os="linux", target_os = "macos", ++ target_os="openbsd"))] ++ /// The maximum amount by which a process can decrease its asynchronous I/O ++ /// priority level from its own scheduling priority. ++ AIO_PRIO_DELTA_MAX = libc::_SC_AIO_PRIO_DELTA_MAX, ++ /// Maximum length of argument to the exec functions including environment data. ++ ARG_MAX = libc::_SC_ARG_MAX, ++ /// Maximum number of functions that may be registered with `atexit`. ++ ATEXIT_MAX = libc::_SC_ATEXIT_MAX, ++ /// Maximum obase values allowed by the bc utility. ++ BC_BASE_MAX = libc::_SC_BC_BASE_MAX, ++ /// Maximum number of elements permitted in an array by the bc utility. ++ BC_DIM_MAX = libc::_SC_BC_DIM_MAX, ++ /// Maximum scale value allowed by the bc utility. ++ BC_SCALE_MAX = libc::_SC_BC_SCALE_MAX, ++ /// Maximum length of a string constant accepted by the bc utility. ++ BC_STRING_MAX = libc::_SC_BC_STRING_MAX, ++ /// Maximum number of simultaneous processes per real user ID. ++ CHILD_MAX = libc::_SC_CHILD_MAX, ++ // _SC_CLK_TCK is obsolete ++ /// Maximum number of weights that can be assigned to an entry of the ++ /// LC_COLLATE order keyword in the locale definition file ++ COLL_WEIGHTS_MAX = libc::_SC_COLL_WEIGHTS_MAX, ++ /// Maximum number of timer expiration overruns. ++ DELAYTIMER_MAX = libc::_SC_DELAYTIMER_MAX, ++ /// Maximum number of expressions that can be nested within parentheses by ++ /// the expr utility. ++ EXPR_NEST_MAX = libc::_SC_EXPR_NEST_MAX, ++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", ++ target_os="linux", target_os = "macos", target_os="netbsd", ++ target_os="openbsd"))] ++ /// Maximum length of a host name (not including the terminating null) as ++ /// returned from the `gethostname` function ++ HOST_NAME_MAX = libc::_SC_HOST_NAME_MAX, ++ /// Maximum number of iovec structures that one process has available for ++ /// use with `readv` or `writev`. ++ IOV_MAX = libc::_SC_IOV_MAX, ++ /// Unless otherwise noted, the maximum length, in bytes, of a utility's ++ /// input line (either standard input or another file), when the utility is ++ /// described as processing text files. The length includes room for the ++ /// trailing <newline>. ++ LINE_MAX = libc::_SC_LINE_MAX, ++ /// Maximum length of a login name. ++ LOGIN_NAME_MAX = libc::_SC_LOGIN_NAME_MAX, ++ /// Maximum number of simultaneous supplementary group IDs per process. ++ NGROUPS_MAX = libc::_SC_NGROUPS_MAX, ++ /// Initial size of `getgrgid_r` and `getgrnam_r` data buffers ++ GETGR_R_SIZE_MAX = libc::_SC_GETGR_R_SIZE_MAX, ++ /// Initial size of `getpwuid_r` and `getpwnam_r` data buffers ++ GETPW_R_SIZE_MAX = libc::_SC_GETPW_R_SIZE_MAX, ++ /// The maximum number of open message queue descriptors a process may hold. ++ MQ_OPEN_MAX = libc::_SC_MQ_OPEN_MAX, ++ /// The maximum number of message priorities supported by the implementation. ++ MQ_PRIO_MAX = libc::_SC_MQ_PRIO_MAX, ++ /// A value one greater than the maximum value that the system may assign to ++ /// a newly-created file descriptor. ++ OPEN_MAX = libc::_SC_OPEN_MAX, ++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", ++ target_os="linux", target_os = "macos", target_os="openbsd"))] ++ /// The implementation supports the Advisory Information option. ++ _POSIX_ADVISORY_INFO = libc::_SC_ADVISORY_INFO, ++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", ++ target_os="linux", target_os = "macos", target_os="netbsd", ++ target_os="openbsd"))] ++ /// The implementation supports barriers. ++ _POSIX_BARRIERS = libc::_SC_BARRIERS, ++ /// The implementation supports asynchronous input and output. ++ _POSIX_ASYNCHRONOUS_IO = libc::_SC_ASYNCHRONOUS_IO, ++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", ++ target_os="linux", target_os = "macos", target_os="netbsd", ++ target_os="openbsd"))] ++ /// The implementation supports clock selection. ++ _POSIX_CLOCK_SELECTION = libc::_SC_CLOCK_SELECTION, ++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", ++ target_os="linux", target_os = "macos", target_os="netbsd", ++ target_os="openbsd"))] ++ /// The implementation supports the Process CPU-Time Clocks option. ++ _POSIX_CPUTIME = libc::_SC_CPUTIME, ++ /// The implementation supports the File Synchronization option. ++ _POSIX_FSYNC = libc::_SC_FSYNC, ++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", ++ target_os="linux", target_os = "macos", target_os="openbsd"))] ++ /// The implementation supports the IPv6 option. ++ _POSIX_IPV6 = libc::_SC_IPV6, ++ /// The implementation supports job control. ++ _POSIX_JOB_CONTROL = libc::_SC_JOB_CONTROL, ++ /// The implementation supports memory mapped Files. ++ _POSIX_MAPPED_FILES = libc::_SC_MAPPED_FILES, ++ /// The implementation supports the Process Memory Locking option. ++ _POSIX_MEMLOCK = libc::_SC_MEMLOCK, ++ /// The implementation supports the Range Memory Locking option. ++ _POSIX_MEMLOCK_RANGE = libc::_SC_MEMLOCK_RANGE, ++ /// The implementation supports memory protection. ++ _POSIX_MEMORY_PROTECTION = libc::_SC_MEMORY_PROTECTION, ++ /// The implementation supports the Message Passing option. ++ _POSIX_MESSAGE_PASSING = libc::_SC_MESSAGE_PASSING, ++ /// The implementation supports the Monotonic Clock option. ++ _POSIX_MONOTONIC_CLOCK = libc::_SC_MONOTONIC_CLOCK, ++ #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", ++ target_os = "ios", target_os="linux", target_os = "macos", ++ target_os="openbsd"))] ++ /// The implementation supports the Prioritized Input and Output option. ++ _POSIX_PRIORITIZED_IO = libc::_SC_PRIORITIZED_IO, ++ /// The implementation supports the Process Scheduling option. ++ _POSIX_PRIORITY_SCHEDULING = libc::_SC_PRIORITY_SCHEDULING, ++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", ++ target_os="linux", target_os = "macos", target_os="openbsd"))] ++ /// The implementation supports the Raw Sockets option. ++ _POSIX_RAW_SOCKETS = libc::_SC_RAW_SOCKETS, ++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", ++ target_os="linux", target_os = "macos", target_os="netbsd", ++ target_os="openbsd"))] ++ /// The implementation supports read-write locks. ++ _POSIX_READER_WRITER_LOCKS = libc::_SC_READER_WRITER_LOCKS, ++ #[cfg(any(target_os = "android", target_os="dragonfly", target_os="freebsd", ++ target_os = "ios", target_os="linux", target_os = "macos", ++ target_os = "openbsd"))] ++ /// The implementation supports realtime signals. ++ _POSIX_REALTIME_SIGNALS = libc::_SC_REALTIME_SIGNALS, ++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", ++ target_os="linux", target_os = "macos", target_os="netbsd", ++ target_os="openbsd"))] ++ /// The implementation supports the Regular Expression Handling option. ++ _POSIX_REGEXP = libc::_SC_REGEXP, ++ /// Each process has a saved set-user-ID and a saved set-group-ID. ++ _POSIX_SAVED_IDS = libc::_SC_SAVED_IDS, ++ /// The implementation supports semaphores. ++ _POSIX_SEMAPHORES = libc::_SC_SEMAPHORES, ++ /// The implementation supports the Shared Memory Objects option. ++ _POSIX_SHARED_MEMORY_OBJECTS = libc::_SC_SHARED_MEMORY_OBJECTS, ++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", ++ target_os="linux", target_os = "macos", target_os="netbsd", ++ target_os="openbsd"))] ++ /// The implementation supports the POSIX shell. ++ _POSIX_SHELL = libc::_SC_SHELL, ++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", ++ target_os="linux", target_os = "macos", target_os="netbsd", ++ target_os="openbsd"))] ++ /// The implementation supports the Spawn option. ++ _POSIX_SPAWN = libc::_SC_SPAWN, ++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", ++ target_os="linux", target_os = "macos", target_os="netbsd", ++ target_os="openbsd"))] ++ /// The implementation supports spin locks. ++ _POSIX_SPIN_LOCKS = libc::_SC_SPIN_LOCKS, ++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", ++ target_os="linux", target_os = "macos", target_os="openbsd"))] ++ /// The implementation supports the Process Sporadic Server option. ++ _POSIX_SPORADIC_SERVER = libc::_SC_SPORADIC_SERVER, ++ #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos", ++ target_os="openbsd"))] ++ _POSIX_SS_REPL_MAX = libc::_SC_SS_REPL_MAX, ++ /// The implementation supports the Synchronized Input and Output option. ++ _POSIX_SYNCHRONIZED_IO = libc::_SC_SYNCHRONIZED_IO, ++ /// The implementation supports the Thread Stack Address Attribute option. ++ _POSIX_THREAD_ATTR_STACKADDR = libc::_SC_THREAD_ATTR_STACKADDR, ++ /// The implementation supports the Thread Stack Size Attribute option. ++ _POSIX_THREAD_ATTR_STACKSIZE = libc::_SC_THREAD_ATTR_STACKSIZE, ++ #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos", ++ target_os="netbsd", target_os="openbsd"))] ++ /// The implementation supports the Thread CPU-Time Clocks option. ++ _POSIX_THREAD_CPUTIME = libc::_SC_THREAD_CPUTIME, ++ /// The implementation supports the Non-Robust Mutex Priority Inheritance ++ /// option. ++ _POSIX_THREAD_PRIO_INHERIT = libc::_SC_THREAD_PRIO_INHERIT, ++ /// The implementation supports the Non-Robust Mutex Priority Protection option. ++ _POSIX_THREAD_PRIO_PROTECT = libc::_SC_THREAD_PRIO_PROTECT, ++ /// The implementation supports the Thread Execution Scheduling option. ++ _POSIX_THREAD_PRIORITY_SCHEDULING = libc::_SC_THREAD_PRIORITY_SCHEDULING, ++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", ++ target_os="linux", target_os = "macos", target_os="netbsd", ++ target_os="openbsd"))] ++ /// The implementation supports the Thread Process-Shared Synchronization ++ /// option. ++ _POSIX_THREAD_PROCESS_SHARED = libc::_SC_THREAD_PROCESS_SHARED, ++ #[cfg(any(target_os="dragonfly", target_os="linux", target_os="openbsd"))] ++ /// The implementation supports the Robust Mutex Priority Inheritance option. ++ _POSIX_THREAD_ROBUST_PRIO_INHERIT = libc::_SC_THREAD_ROBUST_PRIO_INHERIT, ++ #[cfg(any(target_os="dragonfly", target_os="linux", target_os="openbsd"))] ++ /// The implementation supports the Robust Mutex Priority Protection option. ++ _POSIX_THREAD_ROBUST_PRIO_PROTECT = libc::_SC_THREAD_ROBUST_PRIO_PROTECT, ++ /// The implementation supports thread-safe functions. ++ _POSIX_THREAD_SAFE_FUNCTIONS = libc::_SC_THREAD_SAFE_FUNCTIONS, ++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", ++ target_os="linux", target_os = "macos", target_os="openbsd"))] ++ /// The implementation supports the Thread Sporadic Server option. ++ _POSIX_THREAD_SPORADIC_SERVER = libc::_SC_THREAD_SPORADIC_SERVER, ++ /// The implementation supports threads. ++ _POSIX_THREADS = libc::_SC_THREADS, ++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", ++ target_os="linux", target_os = "macos", target_os="openbsd"))] ++ /// The implementation supports timeouts. ++ _POSIX_TIMEOUTS = libc::_SC_TIMEOUTS, ++ /// The implementation supports timers. ++ _POSIX_TIMERS = libc::_SC_TIMERS, ++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", ++ target_os="linux", target_os = "macos", target_os="openbsd"))] ++ /// The implementation supports the Trace option. ++ _POSIX_TRACE = libc::_SC_TRACE, ++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", ++ target_os="linux", target_os = "macos", target_os="openbsd"))] ++ /// The implementation supports the Trace Event Filter option. ++ _POSIX_TRACE_EVENT_FILTER = libc::_SC_TRACE_EVENT_FILTER, ++ #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos", ++ target_os="openbsd"))] ++ _POSIX_TRACE_EVENT_NAME_MAX = libc::_SC_TRACE_EVENT_NAME_MAX, ++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", ++ target_os="linux", target_os = "macos", target_os="openbsd"))] ++ /// The implementation supports the Trace Inherit option. ++ _POSIX_TRACE_INHERIT = libc::_SC_TRACE_INHERIT, ++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", ++ target_os="linux", target_os = "macos", target_os="openbsd"))] ++ /// The implementation supports the Trace Log option. ++ _POSIX_TRACE_LOG = libc::_SC_TRACE_LOG, ++ #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos", ++ target_os="openbsd"))] ++ _POSIX_TRACE_NAME_MAX = libc::_SC_TRACE_NAME_MAX, ++ #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos", ++ target_os="openbsd"))] ++ _POSIX_TRACE_SYS_MAX = libc::_SC_TRACE_SYS_MAX, ++ #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos", ++ target_os="openbsd"))] ++ _POSIX_TRACE_USER_EVENT_MAX = libc::_SC_TRACE_USER_EVENT_MAX, ++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", ++ target_os="linux", target_os = "macos", target_os="openbsd"))] ++ /// The implementation supports the Typed Memory Objects option. ++ _POSIX_TYPED_MEMORY_OBJECTS = libc::_SC_TYPED_MEMORY_OBJECTS, ++ /// Integer value indicating version of this standard (C-language binding) ++ /// to which the implementation conforms. For implementations conforming to ++ /// POSIX.1-2008, the value shall be 200809L. ++ _POSIX_VERSION = libc::_SC_VERSION, ++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", ++ target_os="linux", target_os = "macos", target_os="netbsd", ++ target_os="openbsd"))] ++ /// The implementation provides a C-language compilation environment with ++ /// 32-bit `int`, `long`, `pointer`, and `off_t` types. ++ _POSIX_V6_ILP32_OFF32 = libc::_SC_V6_ILP32_OFF32, ++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", ++ target_os="linux", target_os = "macos", target_os="netbsd", ++ target_os="openbsd"))] ++ /// The implementation provides a C-language compilation environment with ++ /// 32-bit `int`, `long`, and pointer types and an `off_t` type using at ++ /// least 64 bits. ++ _POSIX_V6_ILP32_OFFBIG = libc::_SC_V6_ILP32_OFFBIG, ++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", ++ target_os="linux", target_os = "macos", target_os="netbsd", ++ target_os="openbsd"))] ++ /// The implementation provides a C-language compilation environment with ++ /// 32-bit `int` and 64-bit `long`, `pointer`, and `off_t` types. ++ _POSIX_V6_LP64_OFF64 = libc::_SC_V6_LP64_OFF64, ++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", ++ target_os="linux", target_os = "macos", target_os="netbsd", ++ target_os="openbsd"))] ++ /// The implementation provides a C-language compilation environment with an ++ /// `int` type using at least 32 bits and `long`, pointer, and `off_t` types ++ /// using at least 64 bits. ++ _POSIX_V6_LPBIG_OFFBIG = libc::_SC_V6_LPBIG_OFFBIG, ++ /// The implementation supports the C-Language Binding option. ++ _POSIX2_C_BIND = libc::_SC_2_C_BIND, ++ /// The implementation supports the C-Language Development Utilities option. ++ _POSIX2_C_DEV = libc::_SC_2_C_DEV, ++ /// The implementation supports the Terminal Characteristics option. ++ _POSIX2_CHAR_TERM = libc::_SC_2_CHAR_TERM, ++ /// The implementation supports the FORTRAN Development Utilities option. ++ _POSIX2_FORT_DEV = libc::_SC_2_FORT_DEV, ++ /// The implementation supports the FORTRAN Runtime Utilities option. ++ _POSIX2_FORT_RUN = libc::_SC_2_FORT_RUN, ++ /// The implementation supports the creation of locales by the localedef ++ /// utility. ++ _POSIX2_LOCALEDEF = libc::_SC_2_LOCALEDEF, ++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", ++ target_os="linux", target_os = "macos", target_os="netbsd", ++ target_os="openbsd"))] ++ /// The implementation supports the Batch Environment Services and Utilities ++ /// option. ++ _POSIX2_PBS = libc::_SC_2_PBS, ++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", ++ target_os="linux", target_os = "macos", target_os="netbsd", ++ target_os="openbsd"))] ++ /// The implementation supports the Batch Accounting option. ++ _POSIX2_PBS_ACCOUNTING = libc::_SC_2_PBS_ACCOUNTING, ++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", ++ target_os="linux", target_os = "macos", target_os="netbsd", ++ target_os="openbsd"))] ++ /// The implementation supports the Batch Checkpoint/Restart option. ++ _POSIX2_PBS_CHECKPOINT = libc::_SC_2_PBS_CHECKPOINT, ++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", ++ target_os="linux", target_os = "macos", target_os="netbsd", ++ target_os="openbsd"))] ++ /// The implementation supports the Locate Batch Job Request option. ++ _POSIX2_PBS_LOCATE = libc::_SC_2_PBS_LOCATE, ++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", ++ target_os="linux", target_os = "macos", target_os="netbsd", ++ target_os="openbsd"))] ++ /// The implementation supports the Batch Job Message Request option. ++ _POSIX2_PBS_MESSAGE = libc::_SC_2_PBS_MESSAGE, ++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", ++ target_os="linux", target_os = "macos", target_os="netbsd", ++ target_os="openbsd"))] ++ /// The implementation supports the Track Batch Job Request option. ++ _POSIX2_PBS_TRACK = libc::_SC_2_PBS_TRACK, ++ /// The implementation supports the Software Development Utilities option. ++ _POSIX2_SW_DEV = libc::_SC_2_SW_DEV, ++ /// The implementation supports the User Portability Utilities option. ++ _POSIX2_UPE = libc::_SC_2_UPE, ++ /// Integer value indicating version of the Shell and Utilities volume of ++ /// POSIX.1 to which the implementation conforms. ++ _POSIX2_VERSION = libc::_SC_2_VERSION, ++ /// The size of a system page in bytes. ++ /// ++ /// POSIX also defines an alias named `PAGESIZE`, but Rust does not allow two ++ /// enum constants to have the same value, so nix omits `PAGESIZE`. ++ PAGE_SIZE = libc::_SC_PAGE_SIZE, ++ PTHREAD_DESTRUCTOR_ITERATIONS = libc::_SC_THREAD_DESTRUCTOR_ITERATIONS, ++ PTHREAD_KEYS_MAX = libc::_SC_THREAD_KEYS_MAX, ++ PTHREAD_STACK_MIN = libc::_SC_THREAD_STACK_MIN, ++ PTHREAD_THREADS_MAX = libc::_SC_THREAD_THREADS_MAX, ++ RE_DUP_MAX = libc::_SC_RE_DUP_MAX, ++ #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", ++ target_os = "ios", target_os="linux", target_os = "macos", ++ target_os="openbsd"))] ++ RTSIG_MAX = libc::_SC_RTSIG_MAX, ++ SEM_NSEMS_MAX = libc::_SC_SEM_NSEMS_MAX, ++ #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", ++ target_os = "ios", target_os="linux", target_os = "macos", ++ target_os="openbsd"))] ++ SEM_VALUE_MAX = libc::_SC_SEM_VALUE_MAX, ++ #[cfg(any(target_os = "android", target_os="dragonfly", target_os="freebsd", ++ target_os = "ios", target_os="linux", target_os = "macos", ++ target_os = "openbsd"))] ++ SIGQUEUE_MAX = libc::_SC_SIGQUEUE_MAX, ++ STREAM_MAX = libc::_SC_STREAM_MAX, ++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", ++ target_os="linux", target_os = "macos", target_os="netbsd", ++ target_os="openbsd"))] ++ SYMLOOP_MAX = libc::_SC_SYMLOOP_MAX, ++ TIMER_MAX = libc::_SC_TIMER_MAX, ++ TTY_NAME_MAX = libc::_SC_TTY_NAME_MAX, ++ TZNAME_MAX = libc::_SC_TZNAME_MAX, ++ #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", ++ target_os = "ios", target_os="linux", target_os = "macos", ++ target_os="openbsd"))] ++ /// The implementation supports the X/Open Encryption Option Group. ++ _XOPEN_CRYPT = libc::_SC_XOPEN_CRYPT, ++ #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", ++ target_os = "ios", target_os="linux", target_os = "macos", ++ target_os="openbsd"))] ++ /// The implementation supports the Issue 4, Version 2 Enhanced ++ /// Internationalization Option Group. ++ _XOPEN_ENH_I18N = libc::_SC_XOPEN_ENH_I18N, ++ #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", ++ target_os = "ios", target_os="linux", target_os = "macos", ++ target_os="openbsd"))] ++ _XOPEN_LEGACY = libc::_SC_XOPEN_LEGACY, ++ #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", ++ target_os = "ios", target_os="linux", target_os = "macos", ++ target_os="openbsd"))] ++ /// The implementation supports the X/Open Realtime Option Group. ++ _XOPEN_REALTIME = libc::_SC_XOPEN_REALTIME, ++ #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", ++ target_os = "ios", target_os="linux", target_os = "macos", ++ target_os="openbsd"))] ++ /// The implementation supports the X/Open Realtime Threads Option Group. ++ _XOPEN_REALTIME_THREADS = libc::_SC_XOPEN_REALTIME_THREADS, ++ /// The implementation supports the Issue 4, Version 2 Shared Memory Option ++ /// Group. ++ _XOPEN_SHM = libc::_SC_XOPEN_SHM, ++ #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", ++ target_os="linux", target_os = "macos", target_os="openbsd"))] ++ /// The implementation supports the XSI STREAMS Option Group. ++ _XOPEN_STREAMS = libc::_SC_XOPEN_STREAMS, ++ #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", ++ target_os = "ios", target_os="linux", target_os = "macos", ++ target_os="openbsd"))] ++ /// The implementation supports the XSI option ++ _XOPEN_UNIX = libc::_SC_XOPEN_UNIX, ++ #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", ++ target_os = "ios", target_os="linux", target_os = "macos", ++ target_os="openbsd"))] ++ /// Integer value indicating version of the X/Open Portability Guide to ++ /// which the implementation conforms. ++ _XOPEN_VERSION = libc::_SC_XOPEN_VERSION, ++} ++ ++/// Get configurable system variables (see ++/// [sysconf(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sysconf.html)) ++/// ++/// Returns the value of a configurable system variable. Most supported ++/// variables also have associated compile-time constants, but POSIX ++/// allows their values to change at runtime. There are generally two types of ++/// sysconf variables: options and limits. See sysconf(3) for more details. ++/// ++/// # Returns ++/// ++/// - `Ok(Some(x))`: the variable's limit (for limit variables) or its ++/// implementation level (for option variables). Implementation levels are ++/// usually a decimal-coded date, such as 200112 for POSIX 2001.12 ++/// - `Ok(None)`: the variable has no limit (for limit variables) or is ++/// unsupported (for option variables) ++/// - `Err(x)`: an error occurred ++pub fn sysconf(var: SysconfVar) -> Result<Option<c_long>> { ++ let raw = unsafe { ++ Errno::clear(); ++ libc::sysconf(var as c_int) ++ }; ++ if raw == -1 { ++ if errno::errno() == 0 { ++ Ok(None) ++ } else { ++ Err(Error::Sys(Errno::last())) ++ } ++ } else { ++ Ok(Some(raw)) ++ } ++} ++ ++#[cfg(any(target_os = "android", target_os = "linux"))] ++mod pivot_root { ++ use libc; ++ use {Result, NixPath}; ++ use errno::Errno; ++ ++ pub fn pivot_root<P1: ?Sized + NixPath, P2: ?Sized + NixPath>( ++ new_root: &P1, put_old: &P2) -> Result<()> { ++ let res = new_root.with_nix_path(|new_root| { ++ put_old.with_nix_path(|put_old| { ++ unsafe { ++ libc::syscall(libc::SYS_pivot_root, new_root.as_ptr(), put_old.as_ptr()) ++ } ++ }) ++ })??; ++ ++ Errno::result(res).map(drop) ++ } ++} ++ ++#[cfg(any(target_os = "android", target_os = "freebsd", ++ target_os = "linux", target_os = "openbsd"))] ++mod setres { ++ use libc; ++ use Result; ++ use errno::Errno; ++ use super::{Uid, Gid}; ++ ++ /// Sets the real, effective, and saved uid. ++ /// ([see setresuid(2)](http://man7.org/linux/man-pages/man2/setresuid.2.html)) ++ /// ++ /// * `ruid`: real user id ++ /// * `euid`: effective user id ++ /// * `suid`: saved user id ++ /// * returns: Ok or libc error code. ++ /// ++ /// Err is returned if the user doesn't have permission to set this UID. ++ #[inline] ++ pub fn setresuid(ruid: Uid, euid: Uid, suid: Uid) -> Result<()> { ++ let res = unsafe { libc::setresuid(ruid.into(), euid.into(), suid.into()) }; ++ ++ Errno::result(res).map(drop) ++ } ++ ++ /// Sets the real, effective, and saved gid. ++ /// ([see setresuid(2)](http://man7.org/linux/man-pages/man2/setresuid.2.html)) ++ /// ++ /// * `rgid`: real group id ++ /// * `egid`: effective group id ++ /// * `sgid`: saved group id ++ /// * returns: Ok or libc error code. ++ /// ++ /// Err is returned if the user doesn't have permission to set this GID. ++ #[inline] ++ pub fn setresgid(rgid: Gid, egid: Gid, sgid: Gid) -> Result<()> { ++ let res = unsafe { libc::setresgid(rgid.into(), egid.into(), sgid.into()) }; ++ ++ Errno::result(res).map(drop) ++ } ++} ++ ++libc_bitflags!{ ++ /// Options for access() ++ pub struct AccessFlags : c_int { ++ /// Test for existence of file. ++ F_OK; ++ /// Test for read permission. ++ R_OK; ++ /// Test for write permission. ++ W_OK; ++ /// Test for execute (search) permission. ++ X_OK; ++ } ++} ++ ++/// Checks the file named by `path` for accessibility according to the flags given by `amode` ++/// See [access(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/access.html) ++pub fn access<P: ?Sized + NixPath>(path: &P, amode: AccessFlags) -> Result<()> { ++ let res = path.with_nix_path(|cstr| { ++ unsafe { ++ libc::access(cstr.as_ptr(), amode.bits) ++ } ++ })?; ++ Errno::result(res).map(drop) ++} +diff --git a/third_party/rust/nix-0.15.0/test/sys/mod.rs b/third_party/rust/nix-0.15.0/test/sys/mod.rs +new file mode 100644 +index 0000000000000..60a58dd106f19 +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/test/sys/mod.rs +@@ -0,0 +1,38 @@ ++mod test_signal; ++ ++// NOTE: DragonFly lacks a kernel-level implementation of Posix AIO as of ++// this writing. There is an user-level implementation, but whether aio ++// works or not heavily depends on which pthread implementation is chosen ++// by the user at link time. For this reason we do not want to run aio test ++// cases on DragonFly. ++#[cfg(any(target_os = "freebsd", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos", ++ target_os = "netbsd"))] ++mod test_aio; ++#[cfg(target_os = "linux")] ++mod test_signalfd; ++mod test_socket; ++mod test_sockopt; ++mod test_select; ++#[cfg(any(target_os = "android", target_os = "linux"))] ++mod test_sysinfo; ++mod test_termios; ++mod test_ioctl; ++mod test_wait; ++mod test_uio; ++ ++#[cfg(target_os = "linux")] ++mod test_epoll; ++#[cfg(target_os = "linux")] ++mod test_inotify; ++mod test_pthread; ++#[cfg(any(target_os = "android", ++ target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "linux", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++mod test_ptrace; +diff --git a/third_party/rust/nix-0.15.0/test/sys/test_aio.rs b/third_party/rust/nix-0.15.0/test/sys/test_aio.rs +new file mode 100644 +index 0000000000000..d4b09b0b81905 +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/test/sys/test_aio.rs +@@ -0,0 +1,654 @@ ++use bytes::{Bytes, BytesMut}; ++use libc::{c_int, c_void}; ++use nix::{Error, Result}; ++use nix::errno::*; ++use nix::sys::aio::*; ++use nix::sys::signal::{SaFlags, SigAction, sigaction, SigevNotify, SigHandler, Signal, SigSet}; ++use nix::sys::time::{TimeSpec, TimeValLike}; ++use std::io::{Write, Read, Seek, SeekFrom}; ++use std::ops::Deref; ++use std::os::unix::io::AsRawFd; ++use std::sync::atomic::{AtomicBool, Ordering}; ++use std::{thread, time}; ++use tempfile::tempfile; ++ ++// Helper that polls an AioCb for completion or error ++fn poll_aio(aiocb: &mut AioCb) -> Result<()> { ++ loop { ++ let err = aiocb.error(); ++ if err != Err(Error::from(Errno::EINPROGRESS)) { return err; }; ++ thread::sleep(time::Duration::from_millis(10)); ++ } ++} ++ ++#[test] ++fn test_accessors() { ++ let mut rbuf = vec![0; 4]; ++ let aiocb = AioCb::from_mut_slice( 1001, ++ 2, //offset ++ &mut rbuf, ++ 42, //priority ++ SigevNotify::SigevSignal { ++ signal: Signal::SIGUSR2, ++ si_value: 99 ++ }, ++ LioOpcode::LIO_NOP); ++ assert_eq!(1001, aiocb.fd()); ++ assert_eq!(Some(LioOpcode::LIO_NOP), aiocb.lio_opcode()); ++ assert_eq!(4, aiocb.nbytes()); ++ assert_eq!(2, aiocb.offset()); ++ assert_eq!(42, aiocb.priority()); ++ let sev = aiocb.sigevent().sigevent(); ++ assert_eq!(Signal::SIGUSR2 as i32, sev.sigev_signo); ++ assert_eq!(99, sev.sigev_value.sival_ptr as i64); ++} ++ ++// Tests AioCb.cancel. We aren't trying to test the OS's implementation, only ++// our bindings. So it's sufficient to check that AioCb.cancel returned any ++// AioCancelStat value. ++#[test] ++#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] ++fn test_cancel() { ++ let wbuf: &[u8] = b"CDEF"; ++ ++ let f = tempfile().unwrap(); ++ let mut aiocb = AioCb::from_slice( f.as_raw_fd(), ++ 0, //offset ++ wbuf, ++ 0, //priority ++ SigevNotify::SigevNone, ++ LioOpcode::LIO_NOP); ++ aiocb.write().unwrap(); ++ let err = aiocb.error(); ++ assert!(err == Ok(()) || err == Err(Error::from(Errno::EINPROGRESS))); ++ ++ let cancelstat = aiocb.cancel(); ++ assert!(cancelstat.is_ok()); ++ ++ // Wait for aiocb to complete, but don't care whether it succeeded ++ let _ = poll_aio(&mut aiocb); ++ let _ = aiocb.aio_return(); ++} ++ ++// Tests using aio_cancel_all for all outstanding IOs. ++#[test] ++#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] ++fn test_aio_cancel_all() { ++ let wbuf: &[u8] = b"CDEF"; ++ ++ let f = tempfile().unwrap(); ++ let mut aiocb = AioCb::from_slice(f.as_raw_fd(), ++ 0, //offset ++ wbuf, ++ 0, //priority ++ SigevNotify::SigevNone, ++ LioOpcode::LIO_NOP); ++ aiocb.write().unwrap(); ++ let err = aiocb.error(); ++ assert!(err == Ok(()) || err == Err(Error::from(Errno::EINPROGRESS))); ++ ++ let cancelstat = aio_cancel_all(f.as_raw_fd()); ++ assert!(cancelstat.is_ok()); ++ ++ // Wait for aiocb to complete, but don't care whether it succeeded ++ let _ = poll_aio(&mut aiocb); ++ let _ = aiocb.aio_return(); ++} ++ ++#[test] ++#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] ++fn test_fsync() { ++ const INITIAL: &[u8] = b"abcdef123456"; ++ let mut f = tempfile().unwrap(); ++ f.write_all(INITIAL).unwrap(); ++ let mut aiocb = AioCb::from_fd( f.as_raw_fd(), ++ 0, //priority ++ SigevNotify::SigevNone); ++ let err = aiocb.fsync(AioFsyncMode::O_SYNC); ++ assert!(err.is_ok()); ++ poll_aio(&mut aiocb).unwrap(); ++ aiocb.aio_return().unwrap(); ++} ++ ++/// `AioCb::fsync` should not modify the `AioCb` object if `libc::aio_fsync` returns ++/// an error ++// Skip on Linux, because Linux's AIO implementation can't detect errors ++// synchronously ++#[test] ++#[cfg(any(target_os = "freebsd", target_os = "macos"))] ++fn test_fsync_error() { ++ use std::mem; ++ ++ const INITIAL: &[u8] = b"abcdef123456"; ++ // Create an invalid AioFsyncMode ++ let mode = unsafe { mem::transmute(666) }; ++ let mut f = tempfile().unwrap(); ++ f.write_all(INITIAL).unwrap(); ++ let mut aiocb = AioCb::from_fd( f.as_raw_fd(), ++ 0, //priority ++ SigevNotify::SigevNone); ++ let err = aiocb.fsync(mode); ++ assert!(err.is_err()); ++} ++ ++#[test] ++#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] ++fn test_aio_suspend() { ++ const INITIAL: &[u8] = b"abcdef123456"; ++ const WBUF: &[u8] = b"CDEFG"; ++ let timeout = TimeSpec::seconds(10); ++ let mut rbuf = vec![0; 4]; ++ let rlen = rbuf.len(); ++ let mut f = tempfile().unwrap(); ++ f.write_all(INITIAL).unwrap(); ++ ++ let mut wcb = AioCb::from_slice( f.as_raw_fd(), ++ 2, //offset ++ WBUF, ++ 0, //priority ++ SigevNotify::SigevNone, ++ LioOpcode::LIO_WRITE); ++ ++ let mut rcb = AioCb::from_mut_slice( f.as_raw_fd(), ++ 8, //offset ++ &mut rbuf, ++ 0, //priority ++ SigevNotify::SigevNone, ++ LioOpcode::LIO_READ); ++ wcb.write().unwrap(); ++ rcb.read().unwrap(); ++ loop { ++ { ++ let cbbuf = [&wcb, &rcb]; ++ assert!(aio_suspend(&cbbuf[..], Some(timeout)).is_ok()); ++ } ++ if rcb.error() != Err(Error::from(Errno::EINPROGRESS)) && ++ wcb.error() != Err(Error::from(Errno::EINPROGRESS)) { ++ break ++ } ++ } ++ ++ assert!(wcb.aio_return().unwrap() as usize == WBUF.len()); ++ assert!(rcb.aio_return().unwrap() as usize == rlen); ++} ++ ++// Test a simple aio operation with no completion notification. We must poll ++// for completion ++#[test] ++#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] ++fn test_read() { ++ const INITIAL: &[u8] = b"abcdef123456"; ++ let mut rbuf = vec![0; 4]; ++ const EXPECT: &[u8] = b"cdef"; ++ let mut f = tempfile().unwrap(); ++ f.write_all(INITIAL).unwrap(); ++ { ++ let mut aiocb = AioCb::from_mut_slice( f.as_raw_fd(), ++ 2, //offset ++ &mut rbuf, ++ 0, //priority ++ SigevNotify::SigevNone, ++ LioOpcode::LIO_NOP); ++ aiocb.read().unwrap(); ++ ++ let err = poll_aio(&mut aiocb); ++ assert!(err == Ok(())); ++ assert!(aiocb.aio_return().unwrap() as usize == EXPECT.len()); ++ } ++ ++ assert!(EXPECT == rbuf.deref().deref()); ++} ++ ++/// `AioCb::read` should not modify the `AioCb` object if `libc::aio_read` ++/// returns an error ++// Skip on Linux, because Linux's AIO implementation can't detect errors ++// synchronously ++#[test] ++#[cfg(any(target_os = "freebsd", target_os = "macos"))] ++fn test_read_error() { ++ const INITIAL: &[u8] = b"abcdef123456"; ++ let mut rbuf = vec![0; 4]; ++ let mut f = tempfile().unwrap(); ++ f.write_all(INITIAL).unwrap(); ++ let mut aiocb = AioCb::from_mut_slice( f.as_raw_fd(), ++ -1, //an invalid offset ++ &mut rbuf, ++ 0, //priority ++ SigevNotify::SigevNone, ++ LioOpcode::LIO_NOP); ++ assert!(aiocb.read().is_err()); ++} ++ ++// Tests from_mut_slice ++#[test] ++#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] ++fn test_read_into_mut_slice() { ++ const INITIAL: &[u8] = b"abcdef123456"; ++ let mut rbuf = vec![0; 4]; ++ const EXPECT: &[u8] = b"cdef"; ++ let mut f = tempfile().unwrap(); ++ f.write_all(INITIAL).unwrap(); ++ { ++ let mut aiocb = AioCb::from_mut_slice( f.as_raw_fd(), ++ 2, //offset ++ &mut rbuf, ++ 0, //priority ++ SigevNotify::SigevNone, ++ LioOpcode::LIO_NOP); ++ aiocb.read().unwrap(); ++ ++ let err = poll_aio(&mut aiocb); ++ assert!(err == Ok(())); ++ assert!(aiocb.aio_return().unwrap() as usize == EXPECT.len()); ++ } ++ ++ assert!(rbuf == EXPECT); ++} ++ ++// Tests from_ptr ++#[test] ++#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] ++fn test_read_into_pointer() { ++ const INITIAL: &[u8] = b"abcdef123456"; ++ let mut rbuf = vec![0; 4]; ++ const EXPECT: &[u8] = b"cdef"; ++ let mut f = tempfile().unwrap(); ++ f.write_all(INITIAL).unwrap(); ++ { ++ // Safety: ok because rbuf lives until after poll_aio ++ let mut aiocb = unsafe { ++ AioCb::from_mut_ptr( f.as_raw_fd(), ++ 2, //offset ++ rbuf.as_mut_ptr() as *mut c_void, ++ rbuf.len(), ++ 0, //priority ++ SigevNotify::SigevNone, ++ LioOpcode::LIO_NOP) ++ }; ++ aiocb.read().unwrap(); ++ ++ let err = poll_aio(&mut aiocb); ++ assert!(err == Ok(())); ++ assert!(aiocb.aio_return().unwrap() as usize == EXPECT.len()); ++ } ++ ++ assert!(rbuf == EXPECT); ++} ++ ++// Test reading into an immutable buffer. It should fail ++// FIXME: This test fails to panic on Linux/musl ++#[test] ++#[should_panic(expected = "Can't read into an immutable buffer")] ++#[cfg_attr(target_env = "musl", ignore)] ++fn test_read_immutable_buffer() { ++ let rbuf: &[u8] = b"CDEF"; ++ let f = tempfile().unwrap(); ++ let mut aiocb = AioCb::from_slice( f.as_raw_fd(), ++ 2, //offset ++ rbuf, ++ 0, //priority ++ SigevNotify::SigevNone, ++ LioOpcode::LIO_NOP); ++ aiocb.read().unwrap(); ++} ++ ++ ++// Test a simple aio operation with no completion notification. We must poll ++// for completion. Unlike test_aio_read, this test uses AioCb::from_slice ++#[test] ++#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] ++fn test_write() { ++ const INITIAL: &[u8] = b"abcdef123456"; ++ let wbuf = "CDEF".to_string().into_bytes(); ++ let mut rbuf = Vec::new(); ++ const EXPECT: &[u8] = b"abCDEF123456"; ++ ++ let mut f = tempfile().unwrap(); ++ f.write_all(INITIAL).unwrap(); ++ let mut aiocb = AioCb::from_slice( f.as_raw_fd(), ++ 2, //offset ++ &wbuf, ++ 0, //priority ++ SigevNotify::SigevNone, ++ LioOpcode::LIO_NOP); ++ aiocb.write().unwrap(); ++ ++ let err = poll_aio(&mut aiocb); ++ assert!(err == Ok(())); ++ assert!(aiocb.aio_return().unwrap() as usize == wbuf.len()); ++ ++ f.seek(SeekFrom::Start(0)).unwrap(); ++ let len = f.read_to_end(&mut rbuf).unwrap(); ++ assert!(len == EXPECT.len()); ++ assert!(rbuf == EXPECT); ++} ++ ++// Tests `AioCb::from_boxed_slice` with `Bytes` ++#[test] ++#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] ++fn test_write_bytes() { ++ const INITIAL: &[u8] = b"abcdef123456"; ++ let wbuf = Box::new(Bytes::from(&b"CDEF"[..])); ++ let mut rbuf = Vec::new(); ++ const EXPECT: &[u8] = b"abCDEF123456"; ++ let expected_len = wbuf.len(); ++ ++ let mut f = tempfile().unwrap(); ++ f.write_all(INITIAL).unwrap(); ++ let mut aiocb = AioCb::from_boxed_slice( f.as_raw_fd(), ++ 2, //offset ++ wbuf, ++ 0, //priority ++ SigevNotify::SigevNone, ++ LioOpcode::LIO_NOP); ++ aiocb.write().unwrap(); ++ ++ let err = poll_aio(&mut aiocb); ++ assert!(err == Ok(())); ++ assert!(aiocb.aio_return().unwrap() as usize == expected_len); ++ ++ f.seek(SeekFrom::Start(0)).unwrap(); ++ let len = f.read_to_end(&mut rbuf).unwrap(); ++ assert!(len == EXPECT.len()); ++ assert!(rbuf == EXPECT); ++} ++ ++// Tests `AioCb::from_boxed_mut_slice` with `BytesMut` ++#[test] ++#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] ++fn test_read_bytes_mut_small() { ++ const INITIAL: &[u8] = b"abcdef"; ++ let rbuf = Box::new(BytesMut::from(vec![0; 4])); ++ const EXPECT: &[u8] = b"cdef"; ++ let mut f = tempfile().unwrap(); ++ f.write_all(INITIAL).unwrap(); ++ ++ let mut aiocb = AioCb::from_boxed_mut_slice( f.as_raw_fd(), ++ 2, //offset ++ rbuf, ++ 0, //priority ++ SigevNotify::SigevNone, ++ LioOpcode::LIO_NOP); ++ aiocb.read().unwrap(); ++ ++ let err = poll_aio(&mut aiocb); ++ assert_eq!(err, Ok(())); ++ assert_eq!(aiocb.aio_return().unwrap() as usize, EXPECT.len()); ++ let buffer = aiocb.boxed_mut_slice().unwrap(); ++ assert_eq!(buffer.borrow(), EXPECT); ++} ++ ++// Tests `AioCb::from_ptr` ++#[test] ++#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] ++fn test_write_from_pointer() { ++ const INITIAL: &[u8] = b"abcdef123456"; ++ let wbuf = "CDEF".to_string().into_bytes(); ++ let mut rbuf = Vec::new(); ++ const EXPECT: &[u8] = b"abCDEF123456"; ++ ++ let mut f = tempfile().unwrap(); ++ f.write_all(INITIAL).unwrap(); ++ // Safety: ok because aiocb outlives poll_aio ++ let mut aiocb = unsafe { ++ AioCb::from_ptr( f.as_raw_fd(), ++ 2, //offset ++ wbuf.as_ptr() as *const c_void, ++ wbuf.len(), ++ 0, //priority ++ SigevNotify::SigevNone, ++ LioOpcode::LIO_NOP) ++ }; ++ aiocb.write().unwrap(); ++ ++ let err = poll_aio(&mut aiocb); ++ assert!(err == Ok(())); ++ assert!(aiocb.aio_return().unwrap() as usize == wbuf.len()); ++ ++ f.seek(SeekFrom::Start(0)).unwrap(); ++ let len = f.read_to_end(&mut rbuf).unwrap(); ++ assert!(len == EXPECT.len()); ++ assert!(rbuf == EXPECT); ++} ++ ++/// `AioCb::write` should not modify the `AioCb` object if `libc::aio_write` ++/// returns an error ++// Skip on Linux, because Linux's AIO implementation can't detect errors ++// synchronously ++#[test] ++#[cfg(any(target_os = "freebsd", target_os = "macos"))] ++fn test_write_error() { ++ let wbuf = "CDEF".to_string().into_bytes(); ++ let mut aiocb = AioCb::from_slice( 666, // An invalid file descriptor ++ 0, //offset ++ &wbuf, ++ 0, //priority ++ SigevNotify::SigevNone, ++ LioOpcode::LIO_NOP); ++ assert!(aiocb.write().is_err()); ++} ++ ++lazy_static! { ++ pub static ref SIGNALED: AtomicBool = AtomicBool::new(false); ++} ++ ++extern fn sigfunc(_: c_int) { ++ SIGNALED.store(true, Ordering::Relaxed); ++} ++ ++// Test an aio operation with completion delivered by a signal ++// FIXME: This test is ignored on mips because of failures in qemu in CI ++#[test] ++#[cfg_attr(any(all(target_env = "musl", target_arch = "x86_64"), target_arch = "mips", target_arch = "mips64"), ignore)] ++fn test_write_sigev_signal() { ++ let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); ++ let sa = SigAction::new(SigHandler::Handler(sigfunc), ++ SaFlags::SA_RESETHAND, ++ SigSet::empty()); ++ SIGNALED.store(false, Ordering::Relaxed); ++ unsafe { sigaction(Signal::SIGUSR2, &sa) }.unwrap(); ++ ++ const INITIAL: &[u8] = b"abcdef123456"; ++ const WBUF: &[u8] = b"CDEF"; ++ let mut rbuf = Vec::new(); ++ const EXPECT: &[u8] = b"abCDEF123456"; ++ ++ let mut f = tempfile().unwrap(); ++ f.write_all(INITIAL).unwrap(); ++ let mut aiocb = AioCb::from_slice( f.as_raw_fd(), ++ 2, //offset ++ WBUF, ++ 0, //priority ++ SigevNotify::SigevSignal { ++ signal: Signal::SIGUSR2, ++ si_value: 0 //TODO: validate in sigfunc ++ }, ++ LioOpcode::LIO_NOP); ++ aiocb.write().unwrap(); ++ while !SIGNALED.load(Ordering::Relaxed) { ++ thread::sleep(time::Duration::from_millis(10)); ++ } ++ ++ assert!(aiocb.aio_return().unwrap() as usize == WBUF.len()); ++ f.seek(SeekFrom::Start(0)).unwrap(); ++ let len = f.read_to_end(&mut rbuf).unwrap(); ++ assert!(len == EXPECT.len()); ++ assert!(rbuf == EXPECT); ++} ++ ++// Test LioCb::listio with LIO_WAIT, so all AIO ops should be complete by the ++// time listio returns. ++#[test] ++#[cfg(not(any(target_os = "ios", target_os = "macos")))] ++#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] ++fn test_liocb_listio_wait() { ++ const INITIAL: &[u8] = b"abcdef123456"; ++ const WBUF: &[u8] = b"CDEF"; ++ let mut rbuf = vec![0; 4]; ++ let rlen = rbuf.len(); ++ let mut rbuf2 = Vec::new(); ++ const EXPECT: &[u8] = b"abCDEF123456"; ++ let mut f = tempfile().unwrap(); ++ ++ f.write_all(INITIAL).unwrap(); ++ ++ { ++ let wcb = AioCb::from_slice( f.as_raw_fd(), ++ 2, //offset ++ WBUF, ++ 0, //priority ++ SigevNotify::SigevNone, ++ LioOpcode::LIO_WRITE); ++ ++ let rcb = AioCb::from_mut_slice( f.as_raw_fd(), ++ 8, //offset ++ &mut rbuf, ++ 0, //priority ++ SigevNotify::SigevNone, ++ LioOpcode::LIO_READ); ++ let mut liocb = LioCb::with_capacity(2); ++ liocb.aiocbs.push(wcb); ++ liocb.aiocbs.push(rcb); ++ let err = liocb.listio(LioMode::LIO_WAIT, SigevNotify::SigevNone); ++ err.expect("lio_listio"); ++ ++ assert!(liocb.aio_return(0).unwrap() as usize == WBUF.len()); ++ assert!(liocb.aio_return(1).unwrap() as usize == rlen); ++ } ++ assert!(rbuf.deref().deref() == b"3456"); ++ ++ f.seek(SeekFrom::Start(0)).unwrap(); ++ let len = f.read_to_end(&mut rbuf2).unwrap(); ++ assert!(len == EXPECT.len()); ++ assert!(rbuf2 == EXPECT); ++} ++ ++// Test LioCb::listio with LIO_NOWAIT and no SigEvent, so we must use some other ++// mechanism to check for the individual AioCb's completion. ++#[test] ++#[cfg(not(any(target_os = "ios", target_os = "macos")))] ++#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] ++fn test_liocb_listio_nowait() { ++ const INITIAL: &[u8] = b"abcdef123456"; ++ const WBUF: &[u8] = b"CDEF"; ++ let mut rbuf = vec![0; 4]; ++ let rlen = rbuf.len(); ++ let mut rbuf2 = Vec::new(); ++ const EXPECT: &[u8] = b"abCDEF123456"; ++ let mut f = tempfile().unwrap(); ++ ++ f.write_all(INITIAL).unwrap(); ++ ++ { ++ let wcb = AioCb::from_slice( f.as_raw_fd(), ++ 2, //offset ++ WBUF, ++ 0, //priority ++ SigevNotify::SigevNone, ++ LioOpcode::LIO_WRITE); ++ ++ let rcb = AioCb::from_mut_slice( f.as_raw_fd(), ++ 8, //offset ++ &mut rbuf, ++ 0, //priority ++ SigevNotify::SigevNone, ++ LioOpcode::LIO_READ); ++ let mut liocb = LioCb::with_capacity(2); ++ liocb.aiocbs.push(wcb); ++ liocb.aiocbs.push(rcb); ++ let err = liocb.listio(LioMode::LIO_NOWAIT, SigevNotify::SigevNone); ++ err.expect("lio_listio"); ++ ++ poll_aio(&mut liocb.aiocbs[0]).unwrap(); ++ poll_aio(&mut liocb.aiocbs[1]).unwrap(); ++ assert!(liocb.aiocbs[0].aio_return().unwrap() as usize == WBUF.len()); ++ assert!(liocb.aiocbs[1].aio_return().unwrap() as usize == rlen); ++ } ++ assert!(rbuf.deref().deref() == b"3456"); ++ ++ f.seek(SeekFrom::Start(0)).unwrap(); ++ let len = f.read_to_end(&mut rbuf2).unwrap(); ++ assert!(len == EXPECT.len()); ++ assert!(rbuf2 == EXPECT); ++} ++ ++// Test LioCb::listio with LIO_NOWAIT and a SigEvent to indicate when all ++// AioCb's are complete. ++// FIXME: This test is ignored on mips/mips64 because of failures in qemu in CI. ++#[test] ++#[cfg(not(any(target_os = "ios", target_os = "macos")))] ++#[cfg_attr(any(target_arch = "mips", target_arch = "mips64", target_env = "musl"), ignore)] ++fn test_liocb_listio_signal() { ++ let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); ++ const INITIAL: &[u8] = b"abcdef123456"; ++ const WBUF: &[u8] = b"CDEF"; ++ let mut rbuf = vec![0; 4]; ++ let rlen = rbuf.len(); ++ let mut rbuf2 = Vec::new(); ++ const EXPECT: &[u8] = b"abCDEF123456"; ++ let mut f = tempfile().unwrap(); ++ let sa = SigAction::new(SigHandler::Handler(sigfunc), ++ SaFlags::SA_RESETHAND, ++ SigSet::empty()); ++ let sigev_notify = SigevNotify::SigevSignal { signal: Signal::SIGUSR2, ++ si_value: 0 }; ++ ++ f.write_all(INITIAL).unwrap(); ++ ++ { ++ let wcb = AioCb::from_slice( f.as_raw_fd(), ++ 2, //offset ++ WBUF, ++ 0, //priority ++ SigevNotify::SigevNone, ++ LioOpcode::LIO_WRITE); ++ ++ let rcb = AioCb::from_mut_slice( f.as_raw_fd(), ++ 8, //offset ++ &mut rbuf, ++ 0, //priority ++ SigevNotify::SigevNone, ++ LioOpcode::LIO_READ); ++ let mut liocb = LioCb::with_capacity(2); ++ liocb.aiocbs.push(wcb); ++ liocb.aiocbs.push(rcb); ++ SIGNALED.store(false, Ordering::Relaxed); ++ unsafe { sigaction(Signal::SIGUSR2, &sa) }.unwrap(); ++ let err = liocb.listio(LioMode::LIO_NOWAIT, sigev_notify); ++ err.expect("lio_listio"); ++ while !SIGNALED.load(Ordering::Relaxed) { ++ thread::sleep(time::Duration::from_millis(10)); ++ } ++ ++ assert!(liocb.aiocbs[0].aio_return().unwrap() as usize == WBUF.len()); ++ assert!(liocb.aiocbs[1].aio_return().unwrap() as usize == rlen); ++ } ++ assert!(rbuf.deref().deref() == b"3456"); ++ ++ f.seek(SeekFrom::Start(0)).unwrap(); ++ let len = f.read_to_end(&mut rbuf2).unwrap(); ++ assert!(len == EXPECT.len()); ++ assert!(rbuf2 == EXPECT); ++} ++ ++// Try to use LioCb::listio to read into an immutable buffer. It should fail ++// FIXME: This test fails to panic on Linux/musl ++#[test] ++#[cfg(not(any(target_os = "ios", target_os = "macos")))] ++#[should_panic(expected = "Can't read into an immutable buffer")] ++#[cfg_attr(target_env = "musl", ignore)] ++fn test_liocb_listio_read_immutable() { ++ let rbuf: &[u8] = b"abcd"; ++ let f = tempfile().unwrap(); ++ ++ ++ let mut liocb = LioCb::from(vec![ ++ AioCb::from_slice( f.as_raw_fd(), ++ 2, //offset ++ rbuf, ++ 0, //priority ++ SigevNotify::SigevNone, ++ LioOpcode::LIO_READ) ++ ]); ++ let _ = liocb.listio(LioMode::LIO_NOWAIT, SigevNotify::SigevNone); ++} +diff --git a/third_party/rust/nix-0.15.0/test/sys/test_aio_drop.rs b/third_party/rust/nix-0.15.0/test/sys/test_aio_drop.rs +new file mode 100644 +index 0000000000000..492da401ef726 +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/test/sys/test_aio_drop.rs +@@ -0,0 +1,32 @@ ++extern crate nix; ++extern crate tempfile; ++ ++// Test dropping an AioCb that hasn't yet finished. ++// This must happen in its own process, because on OSX this test seems to hose ++// the AIO subsystem and causes subsequent tests to fail ++#[test] ++#[should_panic(expected = "Dropped an in-progress AioCb")] ++#[cfg(all(not(target_env = "musl"), ++ any(target_os = "linux", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "freebsd", ++ target_os = "netbsd")))] ++fn test_drop() { ++ use nix::sys::aio::*; ++ use nix::sys::signal::*; ++ use std::os::unix::io::AsRawFd; ++ use tempfile::tempfile; ++ ++ const WBUF: &[u8] = b"CDEF"; ++ ++ let f = tempfile().unwrap(); ++ f.set_len(6).unwrap(); ++ let mut aiocb = AioCb::from_slice( f.as_raw_fd(), ++ 2, //offset ++ WBUF, ++ 0, //priority ++ SigevNotify::SigevNone, ++ LioOpcode::LIO_NOP); ++ aiocb.write().unwrap(); ++} +diff --git a/third_party/rust/nix-0.15.0/test/sys/test_epoll.rs b/third_party/rust/nix-0.15.0/test/sys/test_epoll.rs +new file mode 100644 +index 0000000000000..e0dc5131defe0 +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/test/sys/test_epoll.rs +@@ -0,0 +1,24 @@ ++use nix::sys::epoll::{EpollCreateFlags, EpollFlags, EpollOp, EpollEvent}; ++use nix::sys::epoll::{epoll_create1, epoll_ctl}; ++use nix::Error; ++use nix::errno::Errno; ++ ++#[test] ++pub fn test_epoll_errno() { ++ let efd = epoll_create1(EpollCreateFlags::empty()).unwrap(); ++ let result = epoll_ctl(efd, EpollOp::EpollCtlDel, 1, None); ++ assert!(result.is_err()); ++ assert_eq!(result.unwrap_err(), Error::Sys(Errno::ENOENT)); ++ ++ let result = epoll_ctl(efd, EpollOp::EpollCtlAdd, 1, None); ++ assert!(result.is_err()); ++ assert_eq!(result.unwrap_err(), Error::Sys(Errno::EINVAL)); ++} ++ ++#[test] ++pub fn test_epoll_ctl() { ++ let efd = epoll_create1(EpollCreateFlags::empty()).unwrap(); ++ let mut event = EpollEvent::new(EpollFlags::EPOLLIN | EpollFlags::EPOLLERR, 1); ++ epoll_ctl(efd, EpollOp::EpollCtlAdd, 1, &mut event).unwrap(); ++ epoll_ctl(efd, EpollOp::EpollCtlDel, 1, None).unwrap(); ++} +diff --git a/third_party/rust/nix-0.15.0/test/sys/test_inotify.rs b/third_party/rust/nix-0.15.0/test/sys/test_inotify.rs +new file mode 100644 +index 0000000000000..a8ead46d487ba +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/test/sys/test_inotify.rs +@@ -0,0 +1,65 @@ ++use nix::sys::inotify::{AddWatchFlags,InitFlags,Inotify}; ++use nix::Error; ++use nix::errno::Errno; ++use tempfile; ++use std::ffi::OsString; ++use std::fs::{rename, File}; ++ ++#[test] ++pub fn test_inotify() { ++ let instance = Inotify::init(InitFlags::IN_NONBLOCK) ++ .unwrap(); ++ let tempdir = tempfile::tempdir().unwrap(); ++ ++ instance.add_watch(tempdir.path(), AddWatchFlags::IN_ALL_EVENTS).unwrap(); ++ ++ let events = instance.read_events(); ++ assert_eq!(events.unwrap_err(), Error::Sys(Errno::EAGAIN)); ++ ++ File::create(tempdir.path().join("test")).unwrap(); ++ ++ let events = instance.read_events().unwrap(); ++ assert_eq!(events[0].name, Some(OsString::from("test"))); ++} ++ ++#[test] ++pub fn test_inotify_multi_events() { ++ let instance = Inotify::init(InitFlags::IN_NONBLOCK) ++ .unwrap(); ++ let tempdir = tempfile::tempdir().unwrap(); ++ ++ instance.add_watch(tempdir.path(), AddWatchFlags::IN_ALL_EVENTS).unwrap(); ++ ++ let events = instance.read_events(); ++ assert_eq!(events.unwrap_err(), Error::Sys(Errno::EAGAIN)); ++ ++ File::create(tempdir.path().join("test")).unwrap(); ++ rename(tempdir.path().join("test"), tempdir.path().join("test2")).unwrap(); ++ ++ // Now there should be 5 events in queue: ++ // - IN_CREATE on test ++ // - IN_OPEN on test ++ // - IN_CLOSE_WRITE on test ++ // - IN_MOVED_FROM on test with a cookie ++ // - IN_MOVED_TO on test2 with the same cookie ++ ++ let events = instance.read_events().unwrap(); ++ assert_eq!(events.len(), 5); ++ ++ assert_eq!(events[0].mask, AddWatchFlags::IN_CREATE); ++ assert_eq!(events[0].name, Some(OsString::from("test"))); ++ ++ assert_eq!(events[1].mask, AddWatchFlags::IN_OPEN); ++ assert_eq!(events[1].name, Some(OsString::from("test"))); ++ ++ assert_eq!(events[2].mask, AddWatchFlags::IN_CLOSE_WRITE); ++ assert_eq!(events[2].name, Some(OsString::from("test"))); ++ ++ assert_eq!(events[3].mask, AddWatchFlags::IN_MOVED_FROM); ++ assert_eq!(events[3].name, Some(OsString::from("test"))); ++ ++ assert_eq!(events[4].mask, AddWatchFlags::IN_MOVED_TO); ++ assert_eq!(events[4].name, Some(OsString::from("test2"))); ++ ++ assert_eq!(events[3].cookie, events[4].cookie); ++} +diff --git a/third_party/rust/nix-0.15.0/test/sys/test_ioctl.rs b/third_party/rust/nix-0.15.0/test/sys/test_ioctl.rs +new file mode 100644 +index 0000000000000..0a439b3346f53 +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/test/sys/test_ioctl.rs +@@ -0,0 +1,334 @@ ++#![allow(dead_code)] ++ ++// Simple tests to ensure macro generated fns compile ++ioctl_none_bad!(do_bad, 0x1234); ++ioctl_read_bad!(do_bad_read, 0x1234, u16); ++ioctl_write_int_bad!(do_bad_write_int, 0x1234); ++ioctl_write_ptr_bad!(do_bad_write_ptr, 0x1234, u8); ++ioctl_readwrite_bad!(do_bad_readwrite, 0x1234, u32); ++ioctl_none!(do_none, 0, 0); ++ioctl_read!(read_test, 0, 0, u32); ++ioctl_write_int!(write_ptr_int, 0, 0); ++ioctl_write_ptr!(write_ptr_u8, 0, 0, u8); ++ioctl_write_ptr!(write_ptr_u32, 0, 0, u32); ++ioctl_write_ptr!(write_ptr_u64, 0, 0, u64); ++ioctl_readwrite!(readwrite_test, 0, 0, u64); ++ioctl_read_buf!(readbuf_test, 0, 0, u32); ++const SPI_IOC_MAGIC: u8 = b'k'; ++const SPI_IOC_MESSAGE: u8 = 0; ++ioctl_write_buf!(writebuf_test_consts, SPI_IOC_MAGIC, SPI_IOC_MESSAGE, u8); ++ioctl_write_buf!(writebuf_test_u8, 0, 0, u8); ++ioctl_write_buf!(writebuf_test_u32, 0, 0, u32); ++ioctl_write_buf!(writebuf_test_u64, 0, 0, u64); ++ioctl_readwrite_buf!(readwritebuf_test, 0, 0, u32); ++ ++// See C code for source of values for op calculations (does NOT work for mips/powerpc): ++// https://gist.github.com/posborne/83ea6880770a1aef332e ++// ++// TODO: Need a way to compute these constants at test time. Using precomputed ++// values is fragile and needs to be maintained. ++ ++#[cfg(any(target_os = "linux", target_os = "android"))] ++mod linux { ++ #[test] ++ fn test_op_none() { ++ if cfg!(any(target_arch = "mips", target_arch = "mips64", target_arch="powerpc", target_arch="powerpc64")){ ++ assert_eq!(request_code_none!(b'q', 10), 0x2000_710A); ++ assert_eq!(request_code_none!(b'a', 255), 0x2000_61FF); ++ } else { ++ assert_eq!(request_code_none!(b'q', 10), 0x0000_710A); ++ assert_eq!(request_code_none!(b'a', 255), 0x0000_61FF); ++ } ++ } ++ ++ #[test] ++ fn test_op_write() { ++ if cfg!(any(target_arch = "mips", target_arch = "mips64", target_arch="powerpc", target_arch="powerpc64")){ ++ assert_eq!(request_code_write!(b'z', 10, 1), 0x8001_7A0A); ++ assert_eq!(request_code_write!(b'z', 10, 512), 0x8200_7A0A); ++ } else { ++ assert_eq!(request_code_write!(b'z', 10, 1), 0x4001_7A0A); ++ assert_eq!(request_code_write!(b'z', 10, 512), 0x4200_7A0A); ++ } ++ } ++ ++ #[cfg(target_pointer_width = "64")] ++ #[test] ++ fn test_op_write_64() { ++ if cfg!(any(target_arch = "mips64", target_arch="powerpc64")){ ++ assert_eq!(request_code_write!(b'z', 10, (1 as u64) << 32), 0x8000_7A0A); ++ } else { ++ assert_eq!(request_code_write!(b'z', 10, (1 as u64) << 32), 0x4000_7A0A); ++ } ++ ++ } ++ ++ #[test] ++ fn test_op_read() { ++ if cfg!(any(target_arch = "mips", target_arch = "mips64", target_arch="powerpc", target_arch="powerpc64")){ ++ assert_eq!(request_code_read!(b'z', 10, 1), 0x4001_7A0A); ++ assert_eq!(request_code_read!(b'z', 10, 512), 0x4200_7A0A); ++ } else { ++ assert_eq!(request_code_read!(b'z', 10, 1), 0x8001_7A0A); ++ assert_eq!(request_code_read!(b'z', 10, 512), 0x8200_7A0A); ++ } ++ } ++ ++ #[cfg(target_pointer_width = "64")] ++ #[test] ++ fn test_op_read_64() { ++ if cfg!(any(target_arch = "mips64", target_arch="powerpc64")){ ++ assert_eq!(request_code_read!(b'z', 10, (1 as u64) << 32), 0x4000_7A0A); ++ } else { ++ assert_eq!(request_code_read!(b'z', 10, (1 as u64) << 32), 0x8000_7A0A); ++ } ++ } ++ ++ #[test] ++ fn test_op_read_write() { ++ assert_eq!(request_code_readwrite!(b'z', 10, 1), 0xC001_7A0A); ++ assert_eq!(request_code_readwrite!(b'z', 10, 512), 0xC200_7A0A); ++ } ++ ++ #[cfg(target_pointer_width = "64")] ++ #[test] ++ fn test_op_read_write_64() { ++ assert_eq!(request_code_readwrite!(b'z', 10, (1 as u64) << 32), 0xC000_7A0A); ++ } ++} ++ ++#[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] ++mod bsd { ++ #[test] ++ fn test_op_none() { ++ assert_eq!(request_code_none!(b'q', 10), 0x2000_710A); ++ assert_eq!(request_code_none!(b'a', 255), 0x2000_61FF); ++ } ++ ++ #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] ++ #[test] ++ fn test_op_write_int() { ++ assert_eq!(request_code_write_int!(b'v', 4), 0x2004_7604); ++ assert_eq!(request_code_write_int!(b'p', 2), 0x2004_7002); ++ } ++ ++ #[test] ++ fn test_op_write() { ++ assert_eq!(request_code_write!(b'z', 10, 1), 0x8001_7A0A); ++ assert_eq!(request_code_write!(b'z', 10, 512), 0x8200_7A0A); ++ } ++ ++ #[cfg(target_pointer_width = "64")] ++ #[test] ++ fn test_op_write_64() { ++ assert_eq!(request_code_write!(b'z', 10, (1 as u64) << 32), 0x8000_7A0A); ++ } ++ ++ #[test] ++ fn test_op_read() { ++ assert_eq!(request_code_read!(b'z', 10, 1), 0x4001_7A0A); ++ assert_eq!(request_code_read!(b'z', 10, 512), 0x4200_7A0A); ++ } ++ ++ #[cfg(target_pointer_width = "64")] ++ #[test] ++ fn test_op_read_64() { ++ assert_eq!(request_code_read!(b'z', 10, (1 as u64) << 32), 0x4000_7A0A); ++ } ++ ++ #[test] ++ fn test_op_read_write() { ++ assert_eq!(request_code_readwrite!(b'z', 10, 1), 0xC001_7A0A); ++ assert_eq!(request_code_readwrite!(b'z', 10, 512), 0xC200_7A0A); ++ } ++ ++ #[cfg(target_pointer_width = "64")] ++ #[test] ++ fn test_op_read_write_64() { ++ assert_eq!(request_code_readwrite!(b'z', 10, (1 as u64) << 32), 0xC000_7A0A); ++ } ++} ++ ++#[cfg(any(target_os = "android", target_os = "linux"))] ++mod linux_ioctls { ++ use std::mem; ++ use std::os::unix::io::AsRawFd; ++ ++ use tempfile::tempfile; ++ use libc::{TCGETS, TCSBRK, TCSETS, TIOCNXCL, termios}; ++ ++ use nix::Error::Sys; ++ use nix::errno::Errno::{ENOTTY, ENOSYS}; ++ ++ ioctl_none_bad!(tiocnxcl, TIOCNXCL); ++ #[test] ++ fn test_ioctl_none_bad() { ++ let file = tempfile().unwrap(); ++ let res = unsafe { tiocnxcl(file.as_raw_fd()) }; ++ assert_eq!(res, Err(Sys(ENOTTY))); ++ } ++ ++ ioctl_read_bad!(tcgets, TCGETS, termios); ++ #[test] ++ fn test_ioctl_read_bad() { ++ let file = tempfile().unwrap(); ++ let mut termios = unsafe { mem::uninitialized() }; ++ let res = unsafe { tcgets(file.as_raw_fd(), &mut termios) }; ++ assert_eq!(res, Err(Sys(ENOTTY))); ++ } ++ ++ ioctl_write_int_bad!(tcsbrk, TCSBRK); ++ #[test] ++ fn test_ioctl_write_int_bad() { ++ let file = tempfile().unwrap(); ++ let res = unsafe { tcsbrk(file.as_raw_fd(), 0) }; ++ assert_eq!(res, Err(Sys(ENOTTY))); ++ } ++ ++ ioctl_write_ptr_bad!(tcsets, TCSETS, termios); ++ #[test] ++ fn test_ioctl_write_ptr_bad() { ++ let file = tempfile().unwrap(); ++ let termios: termios = unsafe { mem::uninitialized() }; ++ let res = unsafe { tcsets(file.as_raw_fd(), &termios) }; ++ assert_eq!(res, Err(Sys(ENOTTY))); ++ } ++ ++ // FIXME: Find a suitable example for `ioctl_readwrite_bad` ++ ++ // From linux/videodev2.h ++ ioctl_none!(log_status, b'V', 70); ++ #[test] ++ fn test_ioctl_none() { ++ let file = tempfile().unwrap(); ++ let res = unsafe { log_status(file.as_raw_fd()) }; ++ assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS))); ++ } ++ ++ #[repr(C)] ++ pub struct v4l2_audio { ++ index: u32, ++ name: [u8; 32], ++ capability: u32, ++ mode: u32, ++ reserved: [u32; 2], ++ } ++ ++ // From linux/videodev2.h ++ ioctl_write_ptr!(s_audio, b'V', 34, v4l2_audio); ++ #[test] ++ fn test_ioctl_write_ptr() { ++ let file = tempfile().unwrap(); ++ let data: v4l2_audio = unsafe { mem::zeroed() }; ++ let res = unsafe { s_audio(file.as_raw_fd(), &data) }; ++ assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS))); ++ } ++ ++ // From linux/net/bluetooth/hci_sock.h ++ const HCI_IOC_MAGIC: u8 = b'H'; ++ const HCI_IOC_HCIDEVUP: u8 = 201; ++ ioctl_write_int!(hcidevup, HCI_IOC_MAGIC, HCI_IOC_HCIDEVUP); ++ #[test] ++ fn test_ioctl_write_int() { ++ let file = tempfile().unwrap(); ++ let res = unsafe { hcidevup(file.as_raw_fd(), 0) }; ++ assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS))); ++ } ++ ++ // From linux/videodev2.h ++ ioctl_read!(g_audio, b'V', 33, v4l2_audio); ++ #[test] ++ fn test_ioctl_read() { ++ let file = tempfile().unwrap(); ++ let mut data: v4l2_audio = unsafe { mem::uninitialized() }; ++ let res = unsafe { g_audio(file.as_raw_fd(), &mut data) }; ++ assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS))); ++ } ++ ++ // From linux/videodev2.h ++ ioctl_readwrite!(enum_audio, b'V', 65, v4l2_audio); ++ #[test] ++ fn test_ioctl_readwrite() { ++ let file = tempfile().unwrap(); ++ let mut data: v4l2_audio = unsafe { mem::uninitialized() }; ++ let res = unsafe { enum_audio(file.as_raw_fd(), &mut data) }; ++ assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS))); ++ } ++ ++ // FIXME: Find a suitable example for `ioctl_read_buf`. ++ ++ #[repr(C)] ++ pub struct spi_ioc_transfer { ++ tx_buf: u64, ++ rx_buf: u64, ++ len: u32, ++ speed_hz: u32, ++ delay_usecs: u16, ++ bits_per_word: u8, ++ cs_change: u8, ++ tx_nbits: u8, ++ rx_nbits: u8, ++ pad: u16, ++ } ++ ++ // From linux/spi/spidev.h ++ ioctl_write_buf!(spi_ioc_message, super::SPI_IOC_MAGIC, super::SPI_IOC_MESSAGE, spi_ioc_transfer); ++ #[test] ++ fn test_ioctl_write_buf() { ++ let file = tempfile().unwrap(); ++ let data: [spi_ioc_transfer; 4] = unsafe { mem::zeroed() }; ++ let res = unsafe { spi_ioc_message(file.as_raw_fd(), &data[..]) }; ++ assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS))); ++ } ++ ++ // FIXME: Find a suitable example for `ioctl_readwrite_buf`. ++} ++ ++#[cfg(target_os = "freebsd")] ++mod freebsd_ioctls { ++ use std::mem; ++ use std::os::unix::io::AsRawFd; ++ ++ use tempfile::tempfile; ++ use libc::termios; ++ ++ use nix::Error::Sys; ++ use nix::errno::Errno::ENOTTY; ++ ++ // From sys/sys/ttycom.h ++ const TTY_IOC_MAGIC: u8 = b't'; ++ const TTY_IOC_TYPE_NXCL: u8 = 14; ++ const TTY_IOC_TYPE_GETA: u8 = 19; ++ const TTY_IOC_TYPE_SETA: u8 = 20; ++ ++ ioctl_none!(tiocnxcl, TTY_IOC_MAGIC, TTY_IOC_TYPE_NXCL); ++ #[test] ++ fn test_ioctl_none() { ++ let file = tempfile().unwrap(); ++ let res = unsafe { tiocnxcl(file.as_raw_fd()) }; ++ assert_eq!(res, Err(Sys(ENOTTY))); ++ } ++ ++ ioctl_read!(tiocgeta, TTY_IOC_MAGIC, TTY_IOC_TYPE_GETA, termios); ++ #[test] ++ fn test_ioctl_read() { ++ let file = tempfile().unwrap(); ++ let mut termios = unsafe { mem::uninitialized() }; ++ let res = unsafe { tiocgeta(file.as_raw_fd(), &mut termios) }; ++ assert_eq!(res, Err(Sys(ENOTTY))); ++ } ++ ++ ioctl_write_ptr!(tiocseta, TTY_IOC_MAGIC, TTY_IOC_TYPE_SETA, termios); ++ #[test] ++ fn test_ioctl_write_ptr() { ++ let file = tempfile().unwrap(); ++ let termios: termios = unsafe { mem::uninitialized() }; ++ let res = unsafe { tiocseta(file.as_raw_fd(), &termios) }; ++ assert_eq!(res, Err(Sys(ENOTTY))); ++ } ++} +diff --git a/third_party/rust/nix-0.15.0/test/sys/test_lio_listio_resubmit.rs b/third_party/rust/nix-0.15.0/test/sys/test_lio_listio_resubmit.rs +new file mode 100644 +index 0000000000000..19ee3facf87d7 +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/test/sys/test_lio_listio_resubmit.rs +@@ -0,0 +1,111 @@ ++// vim: tw=80 ++ ++// Annoyingly, Cargo is unable to conditionally build an entire test binary. So ++// we must disable the test here rather than in Cargo.toml ++#![cfg(target_os = "freebsd")] ++ ++extern crate nix; ++extern crate sysctl; ++extern crate tempfile; ++ ++use nix::Error; ++use nix::errno::*; ++use nix::libc::off_t; ++use nix::sys::aio::*; ++use nix::sys::signal::SigevNotify; ++use nix::unistd::{SysconfVar, sysconf}; ++use std::os::unix::io::AsRawFd; ++use std::{thread, time}; ++use sysctl::CtlValue; ++use tempfile::tempfile; ++ ++const BYTES_PER_OP: usize = 512; ++ ++/// Attempt to collect final status for all of `liocb`'s operations, freeing ++/// system resources ++fn finish_liocb(liocb: &mut LioCb) { ++ for j in 0..liocb.aiocbs.len() { ++ loop { ++ let e = liocb.error(j); ++ match e { ++ Ok(()) => break, ++ Err(Error::Sys(Errno::EINPROGRESS)) => ++ thread::sleep(time::Duration::from_millis(10)), ++ Err(x) => panic!("aio_error({:?})", x) ++ } ++ } ++ assert_eq!(liocb.aio_return(j).unwrap(), BYTES_PER_OP as isize); ++ } ++} ++ ++// Deliberately exceed system resource limits, causing lio_listio to return EIO. ++// This test must run in its own process since it deliberately uses all AIO ++// resources. ATM it is only enabled on FreeBSD, because I don't know how to ++// check system AIO limits on other operating systems. ++#[test] ++fn test_lio_listio_resubmit() { ++ let mut resubmit_count = 0; ++ ++ // Lookup system resource limits ++ let alm = sysconf(SysconfVar::AIO_LISTIO_MAX) ++ .expect("sysconf").unwrap() as usize; ++ let maqpp = if let CtlValue::Int(x) = sysctl::value( ++ "vfs.aio.max_aio_queue_per_proc").unwrap(){ ++ x as usize ++ } else { ++ panic!("unknown sysctl"); ++ }; ++ ++ // Find lio_listio sizes that satisfy the AIO_LISTIO_MAX constraint and also ++ // result in a final lio_listio call that can only partially be queued ++ let target_ops = maqpp + alm / 2; ++ let num_listios = (target_ops + alm - 3) / (alm - 2); ++ let ops_per_listio = (target_ops + num_listios - 1) / num_listios; ++ assert!((num_listios - 1) * ops_per_listio < maqpp, ++ "the last lio_listio won't make any progress; fix the algorithm"); ++ println!("Using {:?} LioCbs of {:?} operations apiece", num_listios, ++ ops_per_listio); ++ ++ let f = tempfile().unwrap(); ++ let buffer_set = (0..num_listios).map(|_| { ++ (0..ops_per_listio).map(|_| { ++ vec![0u8; BYTES_PER_OP] ++ }).collect::<Vec<_>>() ++ }).collect::<Vec<_>>(); ++ ++ let mut liocbs = (0..num_listios).map(|i| { ++ let mut liocb = LioCb::with_capacity(ops_per_listio); ++ for j in 0..ops_per_listio { ++ let offset = (BYTES_PER_OP * (i * ops_per_listio + j)) as off_t; ++ let wcb = AioCb::from_slice( f.as_raw_fd(), ++ offset, ++ &buffer_set[i][j][..], ++ 0, //priority ++ SigevNotify::SigevNone, ++ LioOpcode::LIO_WRITE); ++ liocb.aiocbs.push(wcb); ++ } ++ let mut err = liocb.listio(LioMode::LIO_NOWAIT, SigevNotify::SigevNone); ++ while err == Err(Error::Sys(Errno::EIO)) || ++ err == Err(Error::Sys(Errno::EAGAIN)) || ++ err == Err(Error::Sys(Errno::EINTR)) { ++ // ++ thread::sleep(time::Duration::from_millis(10)); ++ resubmit_count += 1; ++ err = liocb.listio_resubmit(LioMode::LIO_NOWAIT, ++ SigevNotify::SigevNone); ++ } ++ liocb ++ }).collect::<Vec<_>>(); ++ ++ // Ensure that every AioCb completed ++ for liocb in liocbs.iter_mut() { ++ finish_liocb(liocb); ++ } ++ ++ if resubmit_count > 0 { ++ println!("Resubmitted {:?} times, test passed", resubmit_count); ++ } else { ++ println!("Never resubmitted. Test ambiguous"); ++ } ++} +diff --git a/third_party/rust/nix-0.15.0/test/sys/test_pthread.rs b/third_party/rust/nix-0.15.0/test/sys/test_pthread.rs +new file mode 100644 +index 0000000000000..8928010087a13 +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/test/sys/test_pthread.rs +@@ -0,0 +1,15 @@ ++use nix::sys::pthread::*; ++ ++#[cfg(target_env = "musl")] ++#[test] ++fn test_pthread_self() { ++ let tid = pthread_self(); ++ assert!(tid != ::std::ptr::null_mut()); ++} ++ ++#[cfg(not(target_env = "musl"))] ++#[test] ++fn test_pthread_self() { ++ let tid = pthread_self(); ++ assert!(tid != 0); ++} +diff --git a/third_party/rust/nix-0.15.0/test/sys/test_ptrace.rs b/third_party/rust/nix-0.15.0/test/sys/test_ptrace.rs +new file mode 100644 +index 0000000000000..24d9b522ee4e5 +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/test/sys/test_ptrace.rs +@@ -0,0 +1,107 @@ ++use nix::Error; ++use nix::errno::Errno; ++use nix::unistd::getpid; ++use nix::sys::ptrace; ++#[cfg(any(target_os = "android", target_os = "linux"))] ++use nix::sys::ptrace::Options; ++ ++#[cfg(any(target_os = "android", target_os = "linux"))] ++use std::mem; ++ ++#[test] ++fn test_ptrace() { ++ // Just make sure ptrace can be called at all, for now. ++ // FIXME: qemu-user doesn't implement ptrace on all arches, so permit ENOSYS ++ let err = ptrace::attach(getpid()).unwrap_err(); ++ assert!(err == Error::Sys(Errno::EPERM) || err == Error::Sys(Errno::EINVAL) || ++ err == Error::Sys(Errno::ENOSYS)); ++} ++ ++// Just make sure ptrace_setoptions can be called at all, for now. ++#[test] ++#[cfg(any(target_os = "android", target_os = "linux"))] ++fn test_ptrace_setoptions() { ++ let err = ptrace::setoptions(getpid(), Options::PTRACE_O_TRACESYSGOOD).unwrap_err(); ++ assert!(err != Error::UnsupportedOperation); ++} ++ ++// Just make sure ptrace_getevent can be called at all, for now. ++#[test] ++#[cfg(any(target_os = "android", target_os = "linux"))] ++fn test_ptrace_getevent() { ++ let err = ptrace::getevent(getpid()).unwrap_err(); ++ assert!(err != Error::UnsupportedOperation); ++} ++ ++// Just make sure ptrace_getsiginfo can be called at all, for now. ++#[test] ++#[cfg(any(target_os = "android", target_os = "linux"))] ++fn test_ptrace_getsiginfo() { ++ if let Err(Error::UnsupportedOperation) = ptrace::getsiginfo(getpid()) { ++ panic!("ptrace_getsiginfo returns Error::UnsupportedOperation!"); ++ } ++} ++ ++// Just make sure ptrace_setsiginfo can be called at all, for now. ++#[test] ++#[cfg(any(target_os = "android", target_os = "linux"))] ++fn test_ptrace_setsiginfo() { ++ let siginfo = unsafe { mem::uninitialized() }; ++ if let Err(Error::UnsupportedOperation) = ptrace::setsiginfo(getpid(), &siginfo) { ++ panic!("ptrace_setsiginfo returns Error::UnsupportedOperation!"); ++ } ++} ++ ++ ++#[test] ++fn test_ptrace_cont() { ++ use nix::sys::ptrace; ++ use nix::sys::signal::{raise, Signal}; ++ use nix::sys::wait::{waitpid, WaitPidFlag, WaitStatus}; ++ use nix::unistd::fork; ++ use nix::unistd::ForkResult::*; ++ ++ let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test"); ++ ++ // FIXME: qemu-user doesn't implement ptrace on all architectures ++ // and retunrs ENOSYS in this case. ++ // We (ab)use this behavior to detect the affected platforms ++ // and skip the test then. ++ // On valid platforms the ptrace call should return Errno::EPERM, this ++ // is already tested by `test_ptrace`. ++ let err = ptrace::attach(getpid()).unwrap_err(); ++ if err == Error::Sys(Errno::ENOSYS) { ++ return; ++ } ++ ++ match fork().expect("Error: Fork Failed") { ++ Child => { ++ ptrace::traceme().unwrap(); ++ // As recommended by ptrace(2), raise SIGTRAP to pause the child ++ // until the parent is ready to continue ++ loop { ++ raise(Signal::SIGTRAP).unwrap(); ++ } ++ ++ }, ++ Parent { child } => { ++ assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGTRAP))); ++ ptrace::cont(child, None).unwrap(); ++ assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGTRAP))); ++ ptrace::cont(child, Some(Signal::SIGKILL)).unwrap(); ++ match waitpid(child, None) { ++ Ok(WaitStatus::Signaled(pid, Signal::SIGKILL, _)) if pid == child => { ++ // FIXME It's been observed on some systems (apple) the ++ // tracee may not be killed but remain as a zombie process ++ // affecting other wait based tests. Add an extra kill just ++ // to make sure there are no zombies. ++ let _ = waitpid(child, Some(WaitPidFlag::WNOHANG)); ++ while ptrace::cont(child, Some(Signal::SIGKILL)).is_ok() { ++ let _ = waitpid(child, Some(WaitPidFlag::WNOHANG)); ++ } ++ } ++ _ => panic!("The process should have been killed"), ++ } ++ }, ++ } ++} +diff --git a/third_party/rust/nix-0.15.0/test/sys/test_select.rs b/third_party/rust/nix-0.15.0/test/sys/test_select.rs +new file mode 100644 +index 0000000000000..cf68700c5e16f +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/test/sys/test_select.rs +@@ -0,0 +1,54 @@ ++use nix::sys::select::*; ++use nix::unistd::{pipe, write}; ++use nix::sys::signal::SigSet; ++use nix::sys::time::{TimeSpec, TimeValLike}; ++ ++#[test] ++pub fn test_pselect() { ++ let _mtx = ::SIGNAL_MTX ++ .lock() ++ .expect("Mutex got poisoned by another test"); ++ ++ let (r1, w1) = pipe().unwrap(); ++ write(w1, b"hi!").unwrap(); ++ let (r2, _w2) = pipe().unwrap(); ++ ++ let mut fd_set = FdSet::new(); ++ fd_set.insert(r1); ++ fd_set.insert(r2); ++ ++ let timeout = TimeSpec::seconds(10); ++ let sigmask = SigSet::empty(); ++ assert_eq!( ++ 1, ++ pselect(None, &mut fd_set, None, None, &timeout, &sigmask).unwrap() ++ ); ++ assert!(fd_set.contains(r1)); ++ assert!(!fd_set.contains(r2)); ++} ++ ++#[test] ++pub fn test_pselect_nfds2() { ++ let (r1, w1) = pipe().unwrap(); ++ write(w1, b"hi!").unwrap(); ++ let (r2, _w2) = pipe().unwrap(); ++ ++ let mut fd_set = FdSet::new(); ++ fd_set.insert(r1); ++ fd_set.insert(r2); ++ ++ let timeout = TimeSpec::seconds(10); ++ assert_eq!( ++ 1, ++ pselect( ++ ::std::cmp::max(r1, r2) + 1, ++ &mut fd_set, ++ None, ++ None, ++ &timeout, ++ None ++ ).unwrap() ++ ); ++ assert!(fd_set.contains(r1)); ++ assert!(!fd_set.contains(r2)); ++} +diff --git a/third_party/rust/nix-0.15.0/test/sys/test_signal.rs b/third_party/rust/nix-0.15.0/test/sys/test_signal.rs +new file mode 100644 +index 0000000000000..8780763f773ef +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/test/sys/test_signal.rs +@@ -0,0 +1,104 @@ ++use libc; ++use nix::Error; ++use nix::sys::signal::*; ++use nix::unistd::*; ++use std::sync::atomic::{AtomicBool, Ordering}; ++ ++#[test] ++fn test_kill_none() { ++ kill(getpid(), None).expect("Should be able to send signal to myself."); ++} ++ ++#[test] ++fn test_killpg_none() { ++ killpg(getpgrp(), None) ++ .expect("Should be able to send signal to my process group."); ++} ++ ++#[test] ++fn test_old_sigaction_flags() { ++ extern "C" fn handler(_: ::libc::c_int) {} ++ let act = SigAction::new( ++ SigHandler::Handler(handler), ++ SaFlags::empty(), ++ SigSet::empty(), ++ ); ++ let oact = unsafe { sigaction(SIGINT, &act) }.unwrap(); ++ let _flags = oact.flags(); ++ let oact = unsafe { sigaction(SIGINT, &act) }.unwrap(); ++ let _flags = oact.flags(); ++} ++ ++#[test] ++fn test_sigprocmask_noop() { ++ sigprocmask(SigmaskHow::SIG_BLOCK, None, None) ++ .expect("this should be an effective noop"); ++} ++ ++#[test] ++fn test_sigprocmask() { ++ let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); ++ ++ // This needs to be a signal that rust doesn't use in the test harness. ++ const SIGNAL: Signal = Signal::SIGCHLD; ++ ++ let mut old_signal_set = SigSet::empty(); ++ sigprocmask(SigmaskHow::SIG_BLOCK, None, Some(&mut old_signal_set)) ++ .expect("expect to be able to retrieve old signals"); ++ ++ // Make sure the old set doesn't contain the signal, otherwise the following ++ // test don't make sense. ++ assert_eq!(old_signal_set.contains(SIGNAL), false, ++ "the {:?} signal is already blocked, please change to a \ ++ different one", SIGNAL); ++ ++ // Now block the signal. ++ let mut signal_set = SigSet::empty(); ++ signal_set.add(SIGNAL); ++ sigprocmask(SigmaskHow::SIG_BLOCK, Some(&signal_set), None) ++ .expect("expect to be able to block signals"); ++ ++ // And test it again, to make sure the change was effective. ++ old_signal_set.clear(); ++ sigprocmask(SigmaskHow::SIG_BLOCK, None, Some(&mut old_signal_set)) ++ .expect("expect to be able to retrieve old signals"); ++ assert_eq!(old_signal_set.contains(SIGNAL), true, ++ "expected the {:?} to be blocked", SIGNAL); ++ ++ // Reset the signal. ++ sigprocmask(SigmaskHow::SIG_UNBLOCK, Some(&signal_set), None) ++ .expect("expect to be able to block signals"); ++} ++ ++lazy_static! { ++ static ref SIGNALED: AtomicBool = AtomicBool::new(false); ++} ++ ++extern fn test_sigaction_handler(signal: libc::c_int) { ++ let signal = Signal::from_c_int(signal).unwrap(); ++ SIGNALED.store(signal == Signal::SIGINT, Ordering::Relaxed); ++} ++ ++extern fn test_sigaction_action(_: libc::c_int, _: *mut libc::siginfo_t, _: *mut libc::c_void) { ++} ++ ++#[test] ++fn test_signal() { ++ let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); ++ ++ unsafe { signal(Signal::SIGINT, SigHandler::SigIgn) }.unwrap(); ++ raise(Signal::SIGINT).unwrap(); ++ assert_eq!(unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(), SigHandler::SigIgn); ++ ++ let handler = SigHandler::Handler(test_sigaction_handler); ++ assert_eq!(unsafe { signal(Signal::SIGINT, handler) }.unwrap(), SigHandler::SigDfl); ++ raise(Signal::SIGINT).unwrap(); ++ assert!(SIGNALED.load(Ordering::Relaxed)); ++ assert_eq!(unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(), handler); ++ ++ let action_handler = SigHandler::SigAction(test_sigaction_action); ++ assert_eq!(unsafe { signal(Signal::SIGINT, action_handler) }.unwrap_err(), Error::UnsupportedOperation); ++ ++ // Restore default signal handler ++ unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(); ++} +diff --git a/third_party/rust/nix-0.15.0/test/sys/test_signalfd.rs b/third_party/rust/nix-0.15.0/test/sys/test_signalfd.rs +new file mode 100644 +index 0000000000000..a3b6098841f1c +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/test/sys/test_signalfd.rs +@@ -0,0 +1,25 @@ ++#[test] ++fn test_signalfd() { ++ use nix::sys::signalfd::SignalFd; ++ use nix::sys::signal::{self, raise, Signal, SigSet}; ++ ++ // Grab the mutex for altering signals so we don't interfere with other tests. ++ let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); ++ ++ // Block the SIGUSR1 signal from automatic processing for this thread ++ let mut mask = SigSet::empty(); ++ mask.add(signal::SIGUSR1); ++ mask.thread_block().unwrap(); ++ ++ let mut fd = SignalFd::new(&mask).unwrap(); ++ ++ // Send a SIGUSR1 signal to the current process. Note that this uses `raise` instead of `kill` ++ // because `kill` with `getpid` isn't correct during multi-threaded execution like during a ++ // cargo test session. Instead use `raise` which does the correct thing by default. ++ raise(signal::SIGUSR1).expect("Error: raise(SIGUSR1) failed"); ++ ++ // And now catch that same signal. ++ let res = fd.read_signal().unwrap().unwrap(); ++ let signo = Signal::from_c_int(res.ssi_signo as i32).unwrap(); ++ assert_eq!(signo, signal::SIGUSR1); ++} +diff --git a/third_party/rust/nix-0.15.0/test/sys/test_socket.rs b/third_party/rust/nix-0.15.0/test/sys/test_socket.rs +new file mode 100644 +index 0000000000000..7e64d2b77f071 +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/test/sys/test_socket.rs +@@ -0,0 +1,1066 @@ ++use nix::ifaddrs::InterfaceAddress; ++use nix::sys::socket::{AddressFamily, InetAddr, UnixAddr, getsockname}; ++use std::collections::hash_map::DefaultHasher; ++use std::hash::{Hash, Hasher}; ++use std::net::{self, Ipv6Addr, SocketAddr, SocketAddrV6}; ++use std::os::unix::io::RawFd; ++use std::path::Path; ++use std::slice; ++use std::str::FromStr; ++use libc::c_char; ++use tempfile; ++ ++#[test] ++pub fn test_inetv4_addr_to_sock_addr() { ++ let actual: net::SocketAddr = FromStr::from_str("127.0.0.1:3000").unwrap(); ++ let addr = InetAddr::from_std(&actual); ++ ++ match addr { ++ InetAddr::V4(addr) => { ++ let ip: u32 = 0x7f00_0001; ++ let port: u16 = 3000; ++ let saddr = addr.sin_addr.s_addr; ++ ++ assert_eq!(saddr, ip.to_be()); ++ assert_eq!(addr.sin_port, port.to_be()); ++ } ++ _ => panic!("nope"), ++ } ++ ++ assert_eq!(addr.to_str(), "127.0.0.1:3000"); ++ ++ let inet = addr.to_std(); ++ assert_eq!(actual, inet); ++} ++ ++#[test] ++pub fn test_inetv6_addr_to_sock_addr() { ++ let port: u16 = 3000; ++ let flowinfo: u32 = 1; ++ let scope_id: u32 = 2; ++ let ip: Ipv6Addr = "fe80::1".parse().unwrap(); ++ ++ let actual = SocketAddr::V6(SocketAddrV6::new(ip, port, flowinfo, scope_id)); ++ let addr = InetAddr::from_std(&actual); ++ ++ match addr { ++ InetAddr::V6(addr) => { ++ assert_eq!(addr.sin6_port, port.to_be()); ++ assert_eq!(addr.sin6_flowinfo, flowinfo); ++ assert_eq!(addr.sin6_scope_id, scope_id); ++ } ++ _ => panic!("nope"), ++ } ++ ++ assert_eq!(actual, addr.to_std()); ++} ++ ++#[test] ++pub fn test_path_to_sock_addr() { ++ let path = "/foo/bar"; ++ let actual = Path::new(path); ++ let addr = UnixAddr::new(actual).unwrap(); ++ ++ let expect: &[c_char] = unsafe { ++ slice::from_raw_parts(path.as_bytes().as_ptr() as *const c_char, path.len()) ++ }; ++ assert_eq!(&addr.0.sun_path[..8], expect); ++ ++ assert_eq!(addr.path(), Some(actual)); ++} ++ ++fn calculate_hash<T: Hash>(t: &T) -> u64 { ++ let mut s = DefaultHasher::new(); ++ t.hash(&mut s); ++ s.finish() ++} ++ ++#[test] ++pub fn test_addr_equality_path() { ++ let path = "/foo/bar"; ++ let actual = Path::new(path); ++ let addr1 = UnixAddr::new(actual).unwrap(); ++ let mut addr2 = addr1.clone(); ++ ++ addr2.0.sun_path[10] = 127; ++ ++ assert_eq!(addr1, addr2); ++ assert_eq!(calculate_hash(&addr1), calculate_hash(&addr2)); ++} ++ ++#[cfg(any(target_os = "android", target_os = "linux"))] ++#[test] ++pub fn test_abstract_sun_path_too_long() { ++ let name = String::from("nix\0abstract\0tesnix\0abstract\0tesnix\0abstract\0tesnix\0abstract\0tesnix\0abstract\0testttttnix\0abstract\0test\0make\0sure\0this\0is\0long\0enough"); ++ let addr = UnixAddr::new_abstract(name.as_bytes()); ++ assert!(addr.is_err()); ++} ++ ++#[cfg(any(target_os = "android", target_os = "linux"))] ++#[test] ++pub fn test_addr_equality_abstract() { ++ let name = String::from("nix\0abstract\0test"); ++ let addr1 = UnixAddr::new_abstract(name.as_bytes()).unwrap(); ++ let mut addr2 = addr1.clone(); ++ ++ assert_eq!(addr1, addr2); ++ assert_eq!(calculate_hash(&addr1), calculate_hash(&addr2)); ++ ++ addr2.0.sun_path[18] = 127; ++ assert_ne!(addr1, addr2); ++ assert_ne!(calculate_hash(&addr1), calculate_hash(&addr2)); ++} ++ ++// Test getting/setting abstract addresses (without unix socket creation) ++#[cfg(target_os = "linux")] ++#[test] ++pub fn test_abstract_uds_addr() { ++ let empty = String::new(); ++ let addr = UnixAddr::new_abstract(empty.as_bytes()).unwrap(); ++ let sun_path = [0u8; 107]; ++ assert_eq!(addr.as_abstract(), Some(&sun_path[..])); ++ ++ let name = String::from("nix\0abstract\0test"); ++ let addr = UnixAddr::new_abstract(name.as_bytes()).unwrap(); ++ let sun_path = [ ++ 110u8, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, 116, 101, 115, 116, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ ]; ++ assert_eq!(addr.as_abstract(), Some(&sun_path[..])); ++ assert_eq!(addr.path(), None); ++ ++ // Internally, name is null-prefixed (abstract namespace) ++ assert_eq!(addr.0.sun_path[0], 0); ++} ++ ++#[test] ++pub fn test_getsockname() { ++ use nix::sys::socket::{socket, AddressFamily, SockType, SockFlag}; ++ use nix::sys::socket::{bind, SockAddr}; ++ ++ let tempdir = tempfile::tempdir().unwrap(); ++ let sockname = tempdir.path().join("sock"); ++ let sock = socket(AddressFamily::Unix, SockType::Stream, SockFlag::empty(), None) ++ .expect("socket failed"); ++ let sockaddr = SockAddr::new_unix(&sockname).unwrap(); ++ bind(sock, &sockaddr).expect("bind failed"); ++ assert_eq!(sockaddr.to_str(), ++ getsockname(sock).expect("getsockname failed").to_str()); ++} ++ ++#[test] ++pub fn test_socketpair() { ++ use nix::unistd::{read, write}; ++ use nix::sys::socket::{socketpair, AddressFamily, SockType, SockFlag}; ++ ++ let (fd1, fd2) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()) ++ .unwrap(); ++ write(fd1, b"hello").unwrap(); ++ let mut buf = [0;5]; ++ read(fd2, &mut buf).unwrap(); ++ ++ assert_eq!(&buf[..], b"hello"); ++} ++ ++// Test error handling of our recvmsg wrapper ++#[test] ++pub fn test_recvmsg_ebadf() { ++ use nix::Error; ++ use nix::errno::Errno; ++ use nix::sys::socket::{MsgFlags, recvmsg}; ++ use nix::sys::uio::IoVec; ++ ++ let mut buf = [0u8; 5]; ++ let iov = [IoVec::from_mut_slice(&mut buf[..])]; ++ let fd = -1; // Bad file descriptor ++ let r = recvmsg(fd, &iov, None, MsgFlags::empty()); ++ assert_eq!(r.err().unwrap(), Error::Sys(Errno::EBADF)); ++} ++ ++// Disable the test on emulated platforms due to a bug in QEMU versions < ++// 2.12.0. https://bugs.launchpad.net/qemu/+bug/1701808 ++#[cfg_attr(not(any(target_arch = "x86_64", target_arch="i686")), ignore)] ++#[test] ++pub fn test_scm_rights() { ++ use nix::sys::uio::IoVec; ++ use nix::unistd::{pipe, read, write, close}; ++ use nix::sys::socket::{socketpair, sendmsg, recvmsg, ++ AddressFamily, SockType, SockFlag, ++ ControlMessage, ControlMessageOwned, MsgFlags}; ++ ++ let (fd1, fd2) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()) ++ .unwrap(); ++ let (r, w) = pipe().unwrap(); ++ let mut received_r: Option<RawFd> = None; ++ ++ { ++ let iov = [IoVec::from_slice(b"hello")]; ++ let fds = [r]; ++ let cmsg = ControlMessage::ScmRights(&fds); ++ assert_eq!(sendmsg(fd1, &iov, &[cmsg], MsgFlags::empty(), None).unwrap(), 5); ++ close(r).unwrap(); ++ close(fd1).unwrap(); ++ } ++ ++ { ++ let mut buf = [0u8; 5]; ++ let iov = [IoVec::from_mut_slice(&mut buf[..])]; ++ let mut cmsgspace = cmsg_space!([RawFd; 1]); ++ let msg = recvmsg(fd2, &iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap(); ++ ++ for cmsg in msg.cmsgs() { ++ if let ControlMessageOwned::ScmRights(fd) = cmsg { ++ assert_eq!(received_r, None); ++ assert_eq!(fd.len(), 1); ++ received_r = Some(fd[0]); ++ } else { ++ panic!("unexpected cmsg"); ++ } ++ } ++ assert_eq!(msg.bytes, 5); ++ assert!(!msg.flags.intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); ++ close(fd2).unwrap(); ++ } ++ ++ let received_r = received_r.expect("Did not receive passed fd"); ++ // Ensure that the received file descriptor works ++ write(w, b"world").unwrap(); ++ let mut buf = [0u8; 5]; ++ read(received_r, &mut buf).unwrap(); ++ assert_eq!(&buf[..], b"world"); ++ close(received_r).unwrap(); ++ close(w).unwrap(); ++} ++ ++// Disable the test on emulated platforms due to not enabled support of AF_ALG in QEMU from rust cross ++#[cfg_attr(not(any(target_arch = "x86_64", target_arch = "i686")), ignore)] ++#[cfg(any(target_os = "linux", target_os= "android"))] ++#[test] ++pub fn test_af_alg_cipher() { ++ use libc; ++ use nix::sys::uio::IoVec; ++ use nix::unistd::read; ++ use nix::sys::socket::{socket, sendmsg, bind, accept, setsockopt, ++ AddressFamily, SockType, SockFlag, SockAddr, ++ ControlMessage, MsgFlags}; ++ use nix::sys::socket::sockopt::AlgSetKey; ++ ++ let alg_type = "skcipher"; ++ let alg_name = "ctr(aes)"; ++ // 256-bits secret key ++ let key = vec![0u8; 32]; ++ // 16-bytes IV ++ let iv_len = 16; ++ let iv = vec![1u8; iv_len]; ++ // 256-bytes plain payload ++ let payload_len = 256; ++ let payload = vec![2u8; payload_len]; ++ ++ let sock = socket(AddressFamily::Alg, SockType::SeqPacket, SockFlag::empty(), None) ++ .expect("socket failed"); ++ ++ let sockaddr = SockAddr::new_alg(alg_type, alg_name); ++ bind(sock, &sockaddr).expect("bind failed"); ++ ++ if let SockAddr::Alg(alg) = sockaddr { ++ assert_eq!(alg.alg_name().to_string_lossy(), alg_name); ++ assert_eq!(alg.alg_type().to_string_lossy(), alg_type); ++ } else { ++ panic!("unexpected SockAddr"); ++ } ++ ++ setsockopt(sock, AlgSetKey::default(), &key).expect("setsockopt"); ++ let session_socket = accept(sock).expect("accept failed"); ++ ++ let msgs = [ControlMessage::AlgSetOp(&libc::ALG_OP_ENCRYPT), ControlMessage::AlgSetIv(iv.as_slice())]; ++ let iov = IoVec::from_slice(&payload); ++ sendmsg(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg encrypt"); ++ ++ // allocate buffer for encrypted data ++ let mut encrypted = vec![0u8; payload_len]; ++ let num_bytes = read(session_socket, &mut encrypted).expect("read encrypt"); ++ assert_eq!(num_bytes, payload_len); ++ ++ let iov = IoVec::from_slice(&encrypted); ++ ++ let iv = vec![1u8; iv_len]; ++ ++ let msgs = [ControlMessage::AlgSetOp(&libc::ALG_OP_DECRYPT), ControlMessage::AlgSetIv(iv.as_slice())]; ++ sendmsg(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg decrypt"); ++ ++ // allocate buffer for decrypted data ++ let mut decrypted = vec![0u8; payload_len]; ++ let num_bytes = read(session_socket, &mut decrypted).expect("read decrypt"); ++ ++ assert_eq!(num_bytes, payload_len); ++ assert_eq!(decrypted, payload); ++} ++ ++// Disable the test on emulated platforms due to not enabled support of AF_ALG in QEMU from rust cross ++#[cfg_attr(not(any(target_arch = "x86_64", target_arch = "i686")), ignore)] ++#[cfg(any(target_os = "linux", target_os= "android"))] ++#[test] ++pub fn test_af_alg_aead() { ++ use libc::{ALG_OP_DECRYPT, ALG_OP_ENCRYPT}; ++ use nix::sys::uio::IoVec; ++ use nix::unistd::{read, close}; ++ use nix::sys::socket::{socket, sendmsg, bind, accept, setsockopt, ++ AddressFamily, SockType, SockFlag, SockAddr, ++ ControlMessage, MsgFlags}; ++ use nix::sys::socket::sockopt::{AlgSetKey, AlgSetAeadAuthSize}; ++ ++ let auth_size = 4usize; ++ let assoc_size = 16u32; ++ ++ let alg_type = "aead"; ++ let alg_name = "gcm(aes)"; ++ // 256-bits secret key ++ let key = vec![0u8; 32]; ++ // 12-bytes IV ++ let iv_len = 12; ++ let iv = vec![1u8; iv_len]; ++ // 256-bytes plain payload ++ let payload_len = 256; ++ let mut payload = vec![2u8; payload_len + (assoc_size as usize) + auth_size]; ++ ++ for i in 0..assoc_size { ++ payload[i as usize] = 10; ++ } ++ ++ let len = payload.len(); ++ ++ for i in 0..auth_size { ++ payload[len - 1 - i] = 0; ++ } ++ ++ let sock = socket(AddressFamily::Alg, SockType::SeqPacket, SockFlag::empty(), None) ++ .expect("socket failed"); ++ ++ let sockaddr = SockAddr::new_alg(alg_type, alg_name); ++ bind(sock, &sockaddr).expect("bind failed"); ++ ++ setsockopt(sock, AlgSetAeadAuthSize, &auth_size).expect("setsockopt AlgSetAeadAuthSize"); ++ setsockopt(sock, AlgSetKey::default(), &key).expect("setsockopt AlgSetKey"); ++ let session_socket = accept(sock).expect("accept failed"); ++ ++ let msgs = [ ++ ControlMessage::AlgSetOp(&ALG_OP_ENCRYPT), ++ ControlMessage::AlgSetIv(iv.as_slice()), ++ ControlMessage::AlgSetAeadAssoclen(&assoc_size)]; ++ let iov = IoVec::from_slice(&payload); ++ sendmsg(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg encrypt"); ++ ++ // allocate buffer for encrypted data ++ let mut encrypted = vec![0u8; (assoc_size as usize) + payload_len + auth_size]; ++ let num_bytes = read(session_socket, &mut encrypted).expect("read encrypt"); ++ assert_eq!(num_bytes, payload_len + auth_size + (assoc_size as usize)); ++ close(session_socket).expect("close"); ++ ++ for i in 0..assoc_size { ++ encrypted[i as usize] = 10; ++ } ++ ++ let iov = IoVec::from_slice(&encrypted); ++ ++ let iv = vec![1u8; iv_len]; ++ ++ let session_socket = accept(sock).expect("accept failed"); ++ ++ let msgs = [ ++ ControlMessage::AlgSetOp(&ALG_OP_DECRYPT), ++ ControlMessage::AlgSetIv(iv.as_slice()), ++ ControlMessage::AlgSetAeadAssoclen(&assoc_size), ++ ]; ++ sendmsg(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg decrypt"); ++ ++ // allocate buffer for decrypted data ++ let mut decrypted = vec![0u8; payload_len + (assoc_size as usize) + auth_size]; ++ let num_bytes = read(session_socket, &mut decrypted).expect("read decrypt"); ++ ++ assert!(num_bytes >= payload_len + (assoc_size as usize)); ++ assert_eq!(decrypted[(assoc_size as usize)..(payload_len + (assoc_size as usize))], payload[(assoc_size as usize)..payload_len + (assoc_size as usize)]); ++} ++ ++/// Tests that passing multiple fds using a single `ControlMessage` works. ++// Disable the test on emulated platforms due to a bug in QEMU versions < ++// 2.12.0. https://bugs.launchpad.net/qemu/+bug/1701808 ++#[cfg_attr(not(any(target_arch = "x86_64", target_arch="i686")), ignore)] ++#[test] ++fn test_scm_rights_single_cmsg_multiple_fds() { ++ use std::os::unix::net::UnixDatagram; ++ use std::os::unix::io::{RawFd, AsRawFd}; ++ use std::thread; ++ use nix::sys::socket::{ControlMessage, ControlMessageOwned, MsgFlags, ++ sendmsg, recvmsg}; ++ use nix::sys::uio::IoVec; ++ use libc; ++ ++ let (send, receive) = UnixDatagram::pair().unwrap(); ++ let thread = thread::spawn(move || { ++ let mut buf = [0u8; 8]; ++ let iovec = [IoVec::from_mut_slice(&mut buf)]; ++ let mut space = cmsg_space!([RawFd; 2]); ++ let msg = recvmsg( ++ receive.as_raw_fd(), ++ &iovec, ++ Some(&mut space), ++ MsgFlags::empty() ++ ).unwrap(); ++ assert!(!msg.flags.intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); ++ ++ let mut cmsgs = msg.cmsgs(); ++ match cmsgs.next() { ++ Some(ControlMessageOwned::ScmRights(fds)) => { ++ assert_eq!(fds.len(), 2, ++ "unexpected fd count (expected 2 fds, got {})", ++ fds.len()); ++ }, ++ _ => panic!(), ++ } ++ assert!(cmsgs.next().is_none(), "unexpected control msg"); ++ ++ assert_eq!(msg.bytes, 8); ++ assert_eq!(iovec[0].as_slice(), [1u8, 2, 3, 4, 5, 6, 7, 8]); ++ }); ++ ++ let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; ++ let iov = [IoVec::from_slice(&slice)]; ++ let fds = [libc::STDIN_FILENO, libc::STDOUT_FILENO]; // pass stdin and stdout ++ let cmsg = [ControlMessage::ScmRights(&fds)]; ++ sendmsg(send.as_raw_fd(), &iov, &cmsg, MsgFlags::empty(), None).unwrap(); ++ thread.join().unwrap(); ++} ++ ++// Verify `sendmsg` builds a valid `msghdr` when passing an empty ++// `cmsgs` argument. This should result in a msghdr with a nullptr ++// msg_control field and a msg_controllen of 0 when calling into the ++// raw `sendmsg`. ++#[test] ++pub fn test_sendmsg_empty_cmsgs() { ++ use nix::sys::uio::IoVec; ++ use nix::unistd::close; ++ use nix::sys::socket::{socketpair, sendmsg, recvmsg, ++ AddressFamily, SockType, SockFlag, MsgFlags}; ++ ++ let (fd1, fd2) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()) ++ .unwrap(); ++ ++ { ++ let iov = [IoVec::from_slice(b"hello")]; ++ assert_eq!(sendmsg(fd1, &iov, &[], MsgFlags::empty(), None).unwrap(), 5); ++ close(fd1).unwrap(); ++ } ++ ++ { ++ let mut buf = [0u8; 5]; ++ let iov = [IoVec::from_mut_slice(&mut buf[..])]; ++ let mut cmsgspace = cmsg_space!([RawFd; 1]); ++ let msg = recvmsg(fd2, &iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap(); ++ ++ for _ in msg.cmsgs() { ++ panic!("unexpected cmsg"); ++ } ++ assert!(!msg.flags.intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); ++ assert_eq!(msg.bytes, 5); ++ close(fd2).unwrap(); ++ } ++} ++ ++#[cfg(any(target_os = "android", target_os = "linux"))] ++#[test] ++fn test_scm_credentials() { ++ use libc; ++ use nix::sys::uio::IoVec; ++ use nix::unistd::{close, getpid, getuid, getgid}; ++ use nix::sys::socket::{socketpair, sendmsg, recvmsg, setsockopt, ++ AddressFamily, SockType, SockFlag, ++ ControlMessage, ControlMessageOwned, MsgFlags}; ++ use nix::sys::socket::sockopt::PassCred; ++ ++ let (send, recv) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()) ++ .unwrap(); ++ setsockopt(recv, PassCred, &true).unwrap(); ++ ++ { ++ let iov = [IoVec::from_slice(b"hello")]; ++ let cred = libc::ucred { ++ pid: getpid().as_raw(), ++ uid: getuid().as_raw(), ++ gid: getgid().as_raw(), ++ }; ++ let cmsg = ControlMessage::ScmCredentials(&cred); ++ assert_eq!(sendmsg(send, &iov, &[cmsg], MsgFlags::empty(), None).unwrap(), 5); ++ close(send).unwrap(); ++ } ++ ++ { ++ let mut buf = [0u8; 5]; ++ let iov = [IoVec::from_mut_slice(&mut buf[..])]; ++ let mut cmsgspace = cmsg_space!(libc::ucred); ++ let msg = recvmsg(recv, &iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap(); ++ let mut received_cred = None; ++ ++ for cmsg in msg.cmsgs() { ++ if let ControlMessageOwned::ScmCredentials(cred) = cmsg { ++ assert!(received_cred.is_none()); ++ assert_eq!(cred.pid, getpid().as_raw()); ++ assert_eq!(cred.uid, getuid().as_raw()); ++ assert_eq!(cred.gid, getgid().as_raw()); ++ received_cred = Some(cred); ++ } else { ++ panic!("unexpected cmsg"); ++ } ++ } ++ received_cred.expect("no creds received"); ++ assert_eq!(msg.bytes, 5); ++ assert!(!msg.flags.intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); ++ close(recv).unwrap(); ++ } ++} ++ ++/// Ensure that we can send `SCM_CREDENTIALS` and `SCM_RIGHTS` with a single ++/// `sendmsg` call. ++#[cfg(any(target_os = "android", target_os = "linux"))] ++// qemu's handling of multiple cmsgs is bugged, ignore tests on non-x86 ++// see https://bugs.launchpad.net/qemu/+bug/1781280 ++#[cfg_attr(not(any(target_arch = "x86_64", target_arch = "x86")), ignore)] ++#[test] ++fn test_scm_credentials_and_rights() { ++ use libc; ++ ++ let space = cmsg_space!(libc::ucred, RawFd); ++ test_impl_scm_credentials_and_rights(space); ++} ++ ++/// Ensure that passing a an oversized control message buffer to recvmsg ++/// still works. ++#[cfg(any(target_os = "android", target_os = "linux"))] ++// qemu's handling of multiple cmsgs is bugged, ignore tests on non-x86 ++// see https://bugs.launchpad.net/qemu/+bug/1781280 ++#[cfg_attr(not(any(target_arch = "x86_64", target_arch = "x86")), ignore)] ++#[test] ++fn test_too_large_cmsgspace() { ++ let space = vec![0u8; 1024]; ++ test_impl_scm_credentials_and_rights(space); ++} ++ ++#[cfg(any(target_os = "android", target_os = "linux"))] ++fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) { ++ use libc::ucred; ++ use nix::sys::uio::IoVec; ++ use nix::unistd::{pipe, read, write, close, getpid, getuid, getgid}; ++ use nix::sys::socket::{socketpair, sendmsg, recvmsg, setsockopt, ++ SockType, SockFlag, ++ ControlMessage, ControlMessageOwned, MsgFlags}; ++ use nix::sys::socket::sockopt::PassCred; ++ ++ let (send, recv) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()) ++ .unwrap(); ++ setsockopt(recv, PassCred, &true).unwrap(); ++ ++ let (r, w) = pipe().unwrap(); ++ let mut received_r: Option<RawFd> = None; ++ ++ { ++ let iov = [IoVec::from_slice(b"hello")]; ++ let cred = ucred { ++ pid: getpid().as_raw(), ++ uid: getuid().as_raw(), ++ gid: getgid().as_raw(), ++ }; ++ let fds = [r]; ++ let cmsgs = [ ++ ControlMessage::ScmCredentials(&cred), ++ ControlMessage::ScmRights(&fds), ++ ]; ++ assert_eq!(sendmsg(send, &iov, &cmsgs, MsgFlags::empty(), None).unwrap(), 5); ++ close(r).unwrap(); ++ close(send).unwrap(); ++ } ++ ++ { ++ let mut buf = [0u8; 5]; ++ let iov = [IoVec::from_mut_slice(&mut buf[..])]; ++ let msg = recvmsg(recv, &iov, Some(&mut space), MsgFlags::empty()).unwrap(); ++ let mut received_cred = None; ++ ++ assert_eq!(msg.cmsgs().count(), 2, "expected 2 cmsgs"); ++ ++ for cmsg in msg.cmsgs() { ++ match cmsg { ++ ControlMessageOwned::ScmRights(fds) => { ++ assert_eq!(received_r, None, "already received fd"); ++ assert_eq!(fds.len(), 1); ++ received_r = Some(fds[0]); ++ } ++ ControlMessageOwned::ScmCredentials(cred) => { ++ assert!(received_cred.is_none()); ++ assert_eq!(cred.pid, getpid().as_raw()); ++ assert_eq!(cred.uid, getuid().as_raw()); ++ assert_eq!(cred.gid, getgid().as_raw()); ++ received_cred = Some(cred); ++ } ++ _ => panic!("unexpected cmsg"), ++ } ++ } ++ received_cred.expect("no creds received"); ++ assert_eq!(msg.bytes, 5); ++ assert!(!msg.flags.intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); ++ close(recv).unwrap(); ++ } ++ ++ let received_r = received_r.expect("Did not receive passed fd"); ++ // Ensure that the received file descriptor works ++ write(w, b"world").unwrap(); ++ let mut buf = [0u8; 5]; ++ read(received_r, &mut buf).unwrap(); ++ assert_eq!(&buf[..], b"world"); ++ close(received_r).unwrap(); ++ close(w).unwrap(); ++} ++ ++// Test creating and using named unix domain sockets ++#[test] ++pub fn test_unixdomain() { ++ use nix::sys::socket::{SockType, SockFlag}; ++ use nix::sys::socket::{bind, socket, connect, listen, accept, SockAddr}; ++ use nix::unistd::{read, write, close}; ++ use std::thread; ++ ++ let tempdir = tempfile::tempdir().unwrap(); ++ let sockname = tempdir.path().join("sock"); ++ let s1 = socket(AddressFamily::Unix, SockType::Stream, ++ SockFlag::empty(), None).expect("socket failed"); ++ let sockaddr = SockAddr::new_unix(&sockname).unwrap(); ++ bind(s1, &sockaddr).expect("bind failed"); ++ listen(s1, 10).expect("listen failed"); ++ ++ let thr = thread::spawn(move || { ++ let s2 = socket(AddressFamily::Unix, SockType::Stream, SockFlag::empty(), None) ++ .expect("socket failed"); ++ connect(s2, &sockaddr).expect("connect failed"); ++ write(s2, b"hello").expect("write failed"); ++ close(s2).unwrap(); ++ }); ++ ++ let s3 = accept(s1).expect("accept failed"); ++ ++ let mut buf = [0;5]; ++ read(s3, &mut buf).unwrap(); ++ close(s3).unwrap(); ++ close(s1).unwrap(); ++ thr.join().unwrap(); ++ ++ assert_eq!(&buf[..], b"hello"); ++} ++ ++// Test creating and using named system control sockets ++#[cfg(any(target_os = "macos", target_os = "ios"))] ++#[test] ++pub fn test_syscontrol() { ++ use nix::Error; ++ use nix::errno::Errno; ++ use nix::sys::socket::{socket, SockAddr, SockType, SockFlag, SockProtocol}; ++ ++ let fd = socket(AddressFamily::System, SockType::Datagram, ++ SockFlag::empty(), SockProtocol::KextControl) ++ .expect("socket failed"); ++ let _sockaddr = SockAddr::new_sys_control(fd, "com.apple.net.utun_control", 0).expect("resolving sys_control name failed"); ++ assert_eq!(SockAddr::new_sys_control(fd, "foo.bar.lol", 0).err(), Some(Error::Sys(Errno::ENOENT))); ++ ++ // requires root privileges ++ // connect(fd, &sockaddr).expect("connect failed"); ++} ++ ++#[cfg(any( ++ target_os = "android", ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd", ++))] ++fn loopback_address(family: AddressFamily) -> Option<InterfaceAddress> { ++ use std::io; ++ use std::io::Write; ++ use nix::ifaddrs::getifaddrs; ++ use nix::sys::socket::SockAddr; ++ use nix::net::if_::*; ++ ++ let addrs = match getifaddrs() { ++ Ok(iter) => iter, ++ Err(e) => { ++ let stdioerr = io::stderr(); ++ let mut handle = stdioerr.lock(); ++ writeln!(handle, "getifaddrs: {:?}", e).unwrap(); ++ return None; ++ }, ++ }; ++ // return first address matching family ++ for ifaddr in addrs { ++ if ifaddr.flags.contains(InterfaceFlags::IFF_LOOPBACK) { ++ match ifaddr.address { ++ Some(SockAddr::Inet(InetAddr::V4(..))) => { ++ match family { ++ AddressFamily::Inet => return Some(ifaddr), ++ _ => continue ++ } ++ }, ++ Some(SockAddr::Inet(InetAddr::V6(..))) => { ++ match family { ++ AddressFamily::Inet6 => return Some(ifaddr), ++ _ => continue ++ } ++ }, ++ _ => continue, ++ } ++ } ++ } ++ None ++} ++ ++#[cfg(any( ++ target_os = "android", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos", ++ target_os = "netbsd", ++))] ++// qemu doesn't seem to be emulating this correctly in these architectures ++#[cfg_attr(any( ++ target_arch = "mips", ++ target_arch = "mips64", ++ target_arch = "powerpc64", ++), ignore)] ++#[test] ++pub fn test_recv_ipv4pktinfo() { ++ use libc; ++ use nix::sys::socket::sockopt::Ipv4PacketInfo; ++ use nix::sys::socket::{bind, SockFlag, SockType}; ++ use nix::sys::socket::{getsockname, setsockopt, socket}; ++ use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags}; ++ use nix::sys::uio::IoVec; ++ use nix::net::if_::*; ++ ++ let lo_ifaddr = loopback_address(AddressFamily::Inet); ++ let (lo_name, lo) = match lo_ifaddr { ++ Some(ifaddr) => (ifaddr.interface_name, ++ ifaddr.address.expect("Expect IPv4 address on interface")), ++ None => return, ++ }; ++ let receive = socket( ++ AddressFamily::Inet, ++ SockType::Datagram, ++ SockFlag::empty(), ++ None, ++ ).expect("receive socket failed"); ++ bind(receive, &lo).expect("bind failed"); ++ let sa = getsockname(receive).expect("getsockname failed"); ++ setsockopt(receive, Ipv4PacketInfo, &true).expect("setsockopt failed"); ++ ++ { ++ let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; ++ let iov = [IoVec::from_slice(&slice)]; ++ ++ let send = socket( ++ AddressFamily::Inet, ++ SockType::Datagram, ++ SockFlag::empty(), ++ None, ++ ).expect("send socket failed"); ++ sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa)).expect("sendmsg failed"); ++ } ++ ++ { ++ let mut buf = [0u8; 8]; ++ let iovec = [IoVec::from_mut_slice(&mut buf)]; ++ let mut space = cmsg_space!(libc::in_pktinfo); ++ let msg = recvmsg( ++ receive, ++ &iovec, ++ Some(&mut space), ++ MsgFlags::empty(), ++ ).expect("recvmsg failed"); ++ assert!( ++ !msg.flags ++ .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC) ++ ); ++ ++ let mut cmsgs = msg.cmsgs(); ++ match cmsgs.next() { ++ Some(ControlMessageOwned::Ipv4PacketInfo(pktinfo)) => { ++ let i = if_nametoindex(lo_name.as_bytes()).expect("if_nametoindex"); ++ assert_eq!( ++ pktinfo.ipi_ifindex as libc::c_uint, ++ i, ++ "unexpected ifindex (expected {}, got {})", ++ i, ++ pktinfo.ipi_ifindex ++ ); ++ } ++ _ => (), ++ } ++ assert!(cmsgs.next().is_none(), "unexpected additional control msg"); ++ assert_eq!(msg.bytes, 8); ++ assert_eq!( ++ iovec[0].as_slice(), ++ [1u8, 2, 3, 4, 5, 6, 7, 8] ++ ); ++ } ++} ++ ++#[cfg(any( ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd", ++))] ++// qemu doesn't seem to be emulating this correctly in these architectures ++#[cfg_attr(any( ++ target_arch = "mips", ++ target_arch = "mips64", ++ target_arch = "powerpc64", ++), ignore)] ++#[test] ++pub fn test_recvif() { ++ use libc; ++ use nix::net::if_::*; ++ use nix::sys::socket::sockopt::{Ipv4RecvIf, Ipv4RecvDstAddr}; ++ use nix::sys::socket::{bind, SockFlag, SockType}; ++ use nix::sys::socket::{getsockname, setsockopt, socket, SockAddr}; ++ use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags}; ++ use nix::sys::uio::IoVec; ++ ++ let lo_ifaddr = loopback_address(AddressFamily::Inet); ++ let (lo_name, lo) = match lo_ifaddr { ++ Some(ifaddr) => (ifaddr.interface_name, ++ ifaddr.address.expect("Expect IPv4 address on interface")), ++ None => return, ++ }; ++ let receive = socket( ++ AddressFamily::Inet, ++ SockType::Datagram, ++ SockFlag::empty(), ++ None, ++ ).expect("receive socket failed"); ++ bind(receive, &lo).expect("bind failed"); ++ let sa = getsockname(receive).expect("getsockname failed"); ++ setsockopt(receive, Ipv4RecvIf, &true).expect("setsockopt IP_RECVIF failed"); ++ setsockopt(receive, Ipv4RecvDstAddr, &true).expect("setsockopt IP_RECVDSTADDR failed"); ++ ++ { ++ let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; ++ let iov = [IoVec::from_slice(&slice)]; ++ ++ let send = socket( ++ AddressFamily::Inet, ++ SockType::Datagram, ++ SockFlag::empty(), ++ None, ++ ).expect("send socket failed"); ++ sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa)).expect("sendmsg failed"); ++ } ++ ++ { ++ let mut buf = [0u8; 8]; ++ let iovec = [IoVec::from_mut_slice(&mut buf)]; ++ let mut space = cmsg_space!(libc::sockaddr_dl, libc::in_addr); ++ let msg = recvmsg( ++ receive, ++ &iovec, ++ Some(&mut space), ++ MsgFlags::empty(), ++ ).expect("recvmsg failed"); ++ assert!( ++ !msg.flags ++ .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC) ++ ); ++ assert_eq!(msg.cmsgs().count(), 2, "expected 2 cmsgs"); ++ ++ let mut rx_recvif = false; ++ let mut rx_recvdstaddr = false; ++ for cmsg in msg.cmsgs() { ++ match cmsg { ++ ControlMessageOwned::Ipv4RecvIf(dl) => { ++ rx_recvif = true; ++ let i = if_nametoindex(lo_name.as_bytes()).expect("if_nametoindex"); ++ assert_eq!( ++ dl.sdl_index as libc::c_uint, ++ i, ++ "unexpected ifindex (expected {}, got {})", ++ i, ++ dl.sdl_index ++ ); ++ }, ++ ControlMessageOwned::Ipv4RecvDstAddr(addr) => { ++ rx_recvdstaddr = true; ++ if let SockAddr::Inet(InetAddr::V4(a)) = lo { ++ assert_eq!(a.sin_addr.s_addr, ++ addr.s_addr, ++ "unexpected destination address (expected {}, got {})", ++ a.sin_addr.s_addr, ++ addr.s_addr); ++ } else { ++ panic!("unexpected Sockaddr"); ++ } ++ }, ++ _ => panic!("unexpected additional control msg"), ++ } ++ } ++ assert_eq!(rx_recvif, true); ++ assert_eq!(rx_recvdstaddr, true); ++ assert_eq!(msg.bytes, 8); ++ assert_eq!( ++ iovec[0].as_slice(), ++ [1u8, 2, 3, 4, 5, 6, 7, 8] ++ ); ++ } ++} ++ ++#[cfg(any( ++ target_os = "android", ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd", ++))] ++// qemu doesn't seem to be emulating this correctly in these architectures ++#[cfg_attr(any( ++ target_arch = "mips", ++ target_arch = "mips64", ++ target_arch = "powerpc64", ++), ignore)] ++#[test] ++pub fn test_recv_ipv6pktinfo() { ++ use libc; ++ use nix::net::if_::*; ++ use nix::sys::socket::sockopt::Ipv6RecvPacketInfo; ++ use nix::sys::socket::{bind, SockFlag, SockType}; ++ use nix::sys::socket::{getsockname, setsockopt, socket}; ++ use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags}; ++ use nix::sys::uio::IoVec; ++ ++ let lo_ifaddr = loopback_address(AddressFamily::Inet6); ++ let (lo_name, lo) = match lo_ifaddr { ++ Some(ifaddr) => (ifaddr.interface_name, ++ ifaddr.address.expect("Expect IPv4 address on interface")), ++ None => return, ++ }; ++ let receive = socket( ++ AddressFamily::Inet6, ++ SockType::Datagram, ++ SockFlag::empty(), ++ None, ++ ).expect("receive socket failed"); ++ bind(receive, &lo).expect("bind failed"); ++ let sa = getsockname(receive).expect("getsockname failed"); ++ setsockopt(receive, Ipv6RecvPacketInfo, &true).expect("setsockopt failed"); ++ ++ { ++ let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; ++ let iov = [IoVec::from_slice(&slice)]; ++ ++ let send = socket( ++ AddressFamily::Inet6, ++ SockType::Datagram, ++ SockFlag::empty(), ++ None, ++ ).expect("send socket failed"); ++ sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa)).expect("sendmsg failed"); ++ } ++ ++ { ++ let mut buf = [0u8; 8]; ++ let iovec = [IoVec::from_mut_slice(&mut buf)]; ++ let mut space = cmsg_space!(libc::in6_pktinfo); ++ let msg = recvmsg( ++ receive, ++ &iovec, ++ Some(&mut space), ++ MsgFlags::empty(), ++ ).expect("recvmsg failed"); ++ assert!( ++ !msg.flags ++ .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC) ++ ); ++ ++ let mut cmsgs = msg.cmsgs(); ++ match cmsgs.next() { ++ Some(ControlMessageOwned::Ipv6PacketInfo(pktinfo)) => { ++ let i = if_nametoindex(lo_name.as_bytes()).expect("if_nametoindex"); ++ assert_eq!( ++ pktinfo.ipi6_ifindex, ++ i, ++ "unexpected ifindex (expected {}, got {})", ++ i, ++ pktinfo.ipi6_ifindex ++ ); ++ } ++ _ => (), ++ } ++ assert!(cmsgs.next().is_none(), "unexpected additional control msg"); ++ assert_eq!(msg.bytes, 8); ++ assert_eq!( ++ iovec[0].as_slice(), ++ [1u8, 2, 3, 4, 5, 6, 7, 8] ++ ); ++ } ++} ++ ++#[cfg(target_os = "linux")] ++#[test] ++pub fn test_vsock() { ++ use libc; ++ use nix::Error; ++ use nix::errno::Errno; ++ use nix::sys::socket::{AddressFamily, socket, bind, connect, listen, ++ SockAddr, SockType, SockFlag}; ++ use nix::unistd::{close}; ++ use std::thread; ++ ++ let port: u32 = 3000; ++ ++ let s1 = socket(AddressFamily::Vsock, SockType::Stream, ++ SockFlag::empty(), None) ++ .expect("socket failed"); ++ ++ // VMADDR_CID_HYPERVISOR and VMADDR_CID_RESERVED are reserved, so we expect ++ // an EADDRNOTAVAIL error. ++ let sockaddr = SockAddr::new_vsock(libc::VMADDR_CID_HYPERVISOR, port); ++ assert_eq!(bind(s1, &sockaddr).err(), ++ Some(Error::Sys(Errno::EADDRNOTAVAIL))); ++ ++ let sockaddr = SockAddr::new_vsock(libc::VMADDR_CID_RESERVED, port); ++ assert_eq!(bind(s1, &sockaddr).err(), ++ Some(Error::Sys(Errno::EADDRNOTAVAIL))); ++ ++ ++ let sockaddr = SockAddr::new_vsock(libc::VMADDR_CID_ANY, port); ++ assert_eq!(bind(s1, &sockaddr), Ok(())); ++ listen(s1, 10).expect("listen failed"); ++ ++ let thr = thread::spawn(move || { ++ let cid: u32 = libc::VMADDR_CID_HOST; ++ ++ let s2 = socket(AddressFamily::Vsock, SockType::Stream, ++ SockFlag::empty(), None) ++ .expect("socket failed"); ++ ++ let sockaddr = SockAddr::new_vsock(cid, port); ++ ++ // The current implementation does not support loopback devices, so, ++ // for now, we expect a failure on the connect. ++ assert_ne!(connect(s2, &sockaddr), Ok(())); ++ ++ close(s2).unwrap(); ++ }); ++ ++ close(s1).unwrap(); ++ thr.join().unwrap(); ++} +diff --git a/third_party/rust/nix-0.15.0/test/sys/test_sockopt.rs b/third_party/rust/nix-0.15.0/test/sys/test_sockopt.rs +new file mode 100644 +index 0000000000000..c4860c0d61d3d +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/test/sys/test_sockopt.rs +@@ -0,0 +1,53 @@ ++use rand::{thread_rng, Rng}; ++use nix::sys::socket::{socket, sockopt, getsockopt, setsockopt, AddressFamily, SockType, SockFlag, SockProtocol}; ++ ++#[cfg(target_os = "linux")] ++#[test] ++fn is_so_mark_functional() { ++ use nix::sys::socket::sockopt; ++ ++ require_capability!(CAP_NET_ADMIN); ++ ++ let s = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap(); ++ setsockopt(s, sockopt::Mark, &1337).unwrap(); ++ let mark = getsockopt(s, sockopt::Mark).unwrap(); ++ assert_eq!(mark, 1337); ++} ++ ++#[test] ++fn test_so_buf() { ++ let fd = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), SockProtocol::Udp) ++ .unwrap(); ++ let bufsize: usize = thread_rng().gen_range(4096, 131_072); ++ setsockopt(fd, sockopt::SndBuf, &bufsize).unwrap(); ++ let actual = getsockopt(fd, sockopt::SndBuf).unwrap(); ++ assert!(actual >= bufsize); ++ setsockopt(fd, sockopt::RcvBuf, &bufsize).unwrap(); ++ let actual = getsockopt(fd, sockopt::RcvBuf).unwrap(); ++ assert!(actual >= bufsize); ++} ++ ++// The CI doesn't supported getsockopt and setsockopt on emulated processors. ++// It's beleived that a QEMU issue, the tests run ok on a fully emulated system. ++// Current CI just run the binary with QEMU but the Kernel remains the same as the host. ++// So the syscall doesn't work properly unless the kernel is also emulated. ++#[test] ++#[cfg(all( ++ any(target_arch = "x86", target_arch = "x86_64"), ++ any(target_os = "freebsd", target_os = "linux") ++))] ++fn test_tcp_congestion() { ++ use std::ffi::OsString; ++ ++ let fd = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap(); ++ ++ let val = getsockopt(fd, sockopt::TcpCongestion).unwrap(); ++ setsockopt(fd, sockopt::TcpCongestion, &val).unwrap(); ++ ++ setsockopt(fd, sockopt::TcpCongestion, &OsString::from("tcp_congestion_does_not_exist")).unwrap_err(); ++ ++ assert_eq!( ++ getsockopt(fd, sockopt::TcpCongestion).unwrap(), ++ val ++ ); ++} +diff --git a/third_party/rust/nix-0.15.0/test/sys/test_sysinfo.rs b/third_party/rust/nix-0.15.0/test/sys/test_sysinfo.rs +new file mode 100644 +index 0000000000000..73e6586f6223e +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/test/sys/test_sysinfo.rs +@@ -0,0 +1,18 @@ ++use nix::sys::sysinfo::*; ++ ++#[test] ++fn sysinfo_works() { ++ let info = sysinfo().unwrap(); ++ ++ let (l1, l5, l15) = info.load_average(); ++ assert!(l1 >= 0.0); ++ assert!(l5 >= 0.0); ++ assert!(l15 >= 0.0); ++ ++ info.uptime(); // just test Duration construction ++ ++ assert!(info.swap_free() <= info.swap_total(), ++ "more swap available than installed (free: {}, total: {})", ++ info.swap_free(), ++ info.swap_total()); ++} +diff --git a/third_party/rust/nix-0.15.0/test/sys/test_termios.rs b/third_party/rust/nix-0.15.0/test/sys/test_termios.rs +new file mode 100644 +index 0000000000000..a14b8ce1a23cb +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/test/sys/test_termios.rs +@@ -0,0 +1,136 @@ ++use std::os::unix::prelude::*; ++use tempfile::tempfile; ++ ++use nix::{Error, fcntl}; ++use nix::errno::Errno; ++use nix::pty::openpty; ++use nix::sys::termios::{self, LocalFlags, OutputFlags, Termios, tcgetattr}; ++use nix::unistd::{read, write, close}; ++ ++/// Helper function analogous to `std::io::Write::write_all`, but for `RawFd`s ++fn write_all(f: RawFd, buf: &[u8]) { ++ let mut len = 0; ++ while len < buf.len() { ++ len += write(f, &buf[len..]).unwrap(); ++ } ++} ++ ++// Test tcgetattr on a terminal ++#[test] ++fn test_tcgetattr_pty() { ++ // openpty uses ptname(3) internally ++ let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); ++ ++ let pty = openpty(None, None).expect("openpty failed"); ++ assert!(termios::tcgetattr(pty.master).is_ok()); ++ close(pty.master).expect("closing the master failed"); ++ close(pty.slave).expect("closing the slave failed"); ++} ++ ++// Test tcgetattr on something that isn't a terminal ++#[test] ++fn test_tcgetattr_enotty() { ++ let file = tempfile().unwrap(); ++ assert_eq!(termios::tcgetattr(file.as_raw_fd()).err(), ++ Some(Error::Sys(Errno::ENOTTY))); ++} ++ ++// Test tcgetattr on an invalid file descriptor ++#[test] ++fn test_tcgetattr_ebadf() { ++ assert_eq!(termios::tcgetattr(-1).err(), ++ Some(Error::Sys(Errno::EBADF))); ++} ++ ++// Test modifying output flags ++#[test] ++fn test_output_flags() { ++ // openpty uses ptname(3) internally ++ let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); ++ ++ // Open one pty to get attributes for the second one ++ let mut termios = { ++ let pty = openpty(None, None).expect("openpty failed"); ++ assert!(pty.master > 0); ++ assert!(pty.slave > 0); ++ let termios = tcgetattr(pty.master).expect("tcgetattr failed"); ++ close(pty.master).unwrap(); ++ close(pty.slave).unwrap(); ++ termios ++ }; ++ ++ // Make sure postprocessing '\r' isn't specified by default or this test is useless. ++ assert!(!termios.output_flags.contains(OutputFlags::OPOST | OutputFlags::OCRNL)); ++ ++ // Specify that '\r' characters should be transformed to '\n' ++ // OPOST is specified to enable post-processing ++ termios.output_flags.insert(OutputFlags::OPOST | OutputFlags::OCRNL); ++ ++ // Open a pty ++ let pty = openpty(None, &termios).unwrap(); ++ assert!(pty.master > 0); ++ assert!(pty.slave > 0); ++ ++ // Write into the master ++ let string = "foofoofoo\r"; ++ write_all(pty.master, string.as_bytes()); ++ ++ // Read from the slave verifying that the output has been properly transformed ++ let mut buf = [0u8; 10]; ++ ::read_exact(pty.slave, &mut buf); ++ let transformed_string = "foofoofoo\n"; ++ close(pty.master).unwrap(); ++ close(pty.slave).unwrap(); ++ assert_eq!(&buf, transformed_string.as_bytes()); ++} ++ ++// Test modifying local flags ++#[test] ++fn test_local_flags() { ++ // openpty uses ptname(3) internally ++ let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); ++ ++ // Open one pty to get attributes for the second one ++ let mut termios = { ++ let pty = openpty(None, None).unwrap(); ++ assert!(pty.master > 0); ++ assert!(pty.slave > 0); ++ let termios = tcgetattr(pty.master).unwrap(); ++ close(pty.master).unwrap(); ++ close(pty.slave).unwrap(); ++ termios ++ }; ++ ++ // Make sure echo is specified by default or this test is useless. ++ assert!(termios.local_flags.contains(LocalFlags::ECHO)); ++ ++ // Disable local echo ++ termios.local_flags.remove(LocalFlags::ECHO); ++ ++ // Open a new pty with our modified termios settings ++ let pty = openpty(None, &termios).unwrap(); ++ assert!(pty.master > 0); ++ assert!(pty.slave > 0); ++ ++ // Set the master is in nonblocking mode or reading will never return. ++ let flags = fcntl::fcntl(pty.master, fcntl::F_GETFL).unwrap(); ++ let new_flags = fcntl::OFlag::from_bits_truncate(flags) | fcntl::OFlag::O_NONBLOCK; ++ fcntl::fcntl(pty.master, fcntl::F_SETFL(new_flags)).unwrap(); ++ ++ // Write into the master ++ let string = "foofoofoo\r"; ++ write_all(pty.master, string.as_bytes()); ++ ++ // Try to read from the master, which should not have anything as echoing was disabled. ++ let mut buf = [0u8; 10]; ++ let read = read(pty.master, &mut buf).unwrap_err(); ++ close(pty.master).unwrap(); ++ close(pty.slave).unwrap(); ++ assert_eq!(read, Error::Sys(Errno::EAGAIN)); ++} ++ ++#[test] ++fn test_cfmakeraw() { ++ let mut termios = unsafe { Termios::default_uninit() }; ++ termios::cfmakeraw(&mut termios); ++} +diff --git a/third_party/rust/nix-0.15.0/test/sys/test_uio.rs b/third_party/rust/nix-0.15.0/test/sys/test_uio.rs +new file mode 100644 +index 0000000000000..3e4fc28ceb0e4 +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/test/sys/test_uio.rs +@@ -0,0 +1,241 @@ ++use nix::sys::uio::*; ++use nix::unistd::*; ++use rand::{thread_rng, Rng}; ++use rand::distributions::Alphanumeric; ++use std::{cmp, iter}; ++use std::fs::{OpenOptions}; ++use std::os::unix::io::AsRawFd; ++ ++use tempfile::{tempfile, tempdir}; ++ ++#[test] ++fn test_writev() { ++ let mut to_write = Vec::with_capacity(16 * 128); ++ for _ in 0..16 { ++ let s: String = thread_rng().sample_iter(&Alphanumeric).take(128).collect(); ++ let b = s.as_bytes(); ++ to_write.extend(b.iter().cloned()); ++ } ++ // Allocate and fill iovecs ++ let mut iovecs = Vec::new(); ++ let mut consumed = 0; ++ while consumed < to_write.len() { ++ let left = to_write.len() - consumed; ++ let slice_len = if left <= 64 { left } else { thread_rng().gen_range(64, cmp::min(256, left)) }; ++ let b = &to_write[consumed..consumed+slice_len]; ++ iovecs.push(IoVec::from_slice(b)); ++ consumed += slice_len; ++ } ++ let pipe_res = pipe(); ++ assert!(pipe_res.is_ok()); ++ let (reader, writer) = pipe_res.ok().unwrap(); ++ // FileDesc will close its filedesc (reader). ++ let mut read_buf: Vec<u8> = iter::repeat(0u8).take(128 * 16).collect(); ++ // Blocking io, should write all data. ++ let write_res = writev(writer, &iovecs); ++ // Successful write ++ assert!(write_res.is_ok()); ++ let written = write_res.ok().unwrap(); ++ // Check whether we written all data ++ assert_eq!(to_write.len(), written); ++ let read_res = read(reader, &mut read_buf[..]); ++ // Successful read ++ assert!(read_res.is_ok()); ++ let read = read_res.ok().unwrap() as usize; ++ // Check we have read as much as we written ++ assert_eq!(read, written); ++ // Check equality of written and read data ++ assert_eq!(&to_write, &read_buf); ++ let close_res = close(writer); ++ assert!(close_res.is_ok()); ++ let close_res = close(reader); ++ assert!(close_res.is_ok()); ++} ++ ++#[test] ++fn test_readv() { ++ let s:String = thread_rng().sample_iter(&Alphanumeric).take(128).collect(); ++ let to_write = s.as_bytes().to_vec(); ++ let mut storage = Vec::new(); ++ let mut allocated = 0; ++ while allocated < to_write.len() { ++ let left = to_write.len() - allocated; ++ let vec_len = if left <= 64 { left } else { thread_rng().gen_range(64, cmp::min(256, left)) }; ++ let v: Vec<u8> = iter::repeat(0u8).take(vec_len).collect(); ++ storage.push(v); ++ allocated += vec_len; ++ } ++ let mut iovecs = Vec::with_capacity(storage.len()); ++ for v in &mut storage { ++ iovecs.push(IoVec::from_mut_slice(&mut v[..])); ++ } ++ let pipe_res = pipe(); ++ assert!(pipe_res.is_ok()); ++ let (reader, writer) = pipe_res.ok().unwrap(); ++ // Blocking io, should write all data. ++ let write_res = write(writer, &to_write); ++ // Successful write ++ assert!(write_res.is_ok()); ++ let read_res = readv(reader, &mut iovecs[..]); ++ assert!(read_res.is_ok()); ++ let read = read_res.ok().unwrap(); ++ // Check whether we've read all data ++ assert_eq!(to_write.len(), read); ++ // Cccumulate data from iovecs ++ let mut read_buf = Vec::with_capacity(to_write.len()); ++ for iovec in &iovecs { ++ read_buf.extend(iovec.as_slice().iter().cloned()); ++ } ++ // Check whether iovecs contain all written data ++ assert_eq!(read_buf.len(), to_write.len()); ++ // Check equality of written and read data ++ assert_eq!(&read_buf, &to_write); ++ let close_res = close(reader); ++ assert!(close_res.is_ok()); ++ let close_res = close(writer); ++ assert!(close_res.is_ok()); ++} ++ ++#[test] ++fn test_pwrite() { ++ use std::io::Read; ++ ++ let mut file = tempfile().unwrap(); ++ let buf = [1u8;8]; ++ assert_eq!(Ok(8), pwrite(file.as_raw_fd(), &buf, 8)); ++ let mut file_content = Vec::new(); ++ file.read_to_end(&mut file_content).unwrap(); ++ let mut expected = vec![0u8;8]; ++ expected.extend(vec![1;8]); ++ assert_eq!(file_content, expected); ++} ++ ++#[test] ++fn test_pread() { ++ use std::io::Write; ++ ++ let tempdir = tempdir().unwrap(); ++ ++ let path = tempdir.path().join("pread_test_file"); ++ let mut file = OpenOptions::new().write(true).read(true).create(true) ++ .truncate(true).open(path).unwrap(); ++ let file_content: Vec<u8> = (0..64).collect(); ++ file.write_all(&file_content).unwrap(); ++ ++ let mut buf = [0u8;16]; ++ assert_eq!(Ok(16), pread(file.as_raw_fd(), &mut buf, 16)); ++ let expected: Vec<_> = (16..32).collect(); ++ assert_eq!(&buf[..], &expected[..]); ++} ++ ++#[test] ++#[cfg(target_os = "linux")] ++fn test_pwritev() { ++ use std::io::Read; ++ ++ let to_write: Vec<u8> = (0..128).collect(); ++ let expected: Vec<u8> = [vec![0;100], to_write.clone()].concat(); ++ ++ let iovecs = [ ++ IoVec::from_slice(&to_write[0..17]), ++ IoVec::from_slice(&to_write[17..64]), ++ IoVec::from_slice(&to_write[64..128]), ++ ]; ++ ++ let tempdir = tempdir().unwrap(); ++ ++ // pwritev them into a temporary file ++ let path = tempdir.path().join("pwritev_test_file"); ++ let mut file = OpenOptions::new().write(true).read(true).create(true) ++ .truncate(true).open(path).unwrap(); ++ ++ let written = pwritev(file.as_raw_fd(), &iovecs, 100).ok().unwrap(); ++ assert_eq!(written, to_write.len()); ++ ++ // Read the data back and make sure it matches ++ let mut contents = Vec::new(); ++ file.read_to_end(&mut contents).unwrap(); ++ assert_eq!(contents, expected); ++} ++ ++#[test] ++#[cfg(target_os = "linux")] ++fn test_preadv() { ++ use std::io::Write; ++ ++ let to_write: Vec<u8> = (0..200).collect(); ++ let expected: Vec<u8> = (100..200).collect(); ++ ++ let tempdir = tempdir().unwrap(); ++ ++ let path = tempdir.path().join("preadv_test_file"); ++ ++ let mut file = OpenOptions::new().read(true).write(true).create(true) ++ .truncate(true).open(path).unwrap(); ++ file.write_all(&to_write).unwrap(); ++ ++ let mut buffers: Vec<Vec<u8>> = vec![ ++ vec![0; 24], ++ vec![0; 1], ++ vec![0; 75], ++ ]; ++ ++ { ++ // Borrow the buffers into IoVecs and preadv into them ++ let iovecs: Vec<_> = buffers.iter_mut().map( ++ |buf| IoVec::from_mut_slice(&mut buf[..])).collect(); ++ assert_eq!(Ok(100), preadv(file.as_raw_fd(), &iovecs, 100)); ++ } ++ ++ let all = buffers.concat(); ++ assert_eq!(all, expected); ++} ++ ++#[test] ++#[cfg(target_os = "linux")] ++// FIXME: qemu-user doesn't implement process_vm_readv/writev on most arches ++#[cfg_attr(not(any(target_arch = "x86", target_arch = "x86_64")), ignore)] ++fn test_process_vm_readv() { ++ use nix::unistd::ForkResult::*; ++ use nix::sys::signal::*; ++ use nix::sys::wait::*; ++ ++ let _ = ::FORK_MTX.lock().expect("Mutex got poisoned by another test"); ++ ++ // Pre-allocate memory in the child, since allocation isn't safe ++ // post-fork (~= async-signal-safe) ++ let mut vector = vec![1u8, 2, 3, 4, 5]; ++ ++ let (r, w) = pipe().unwrap(); ++ match fork().expect("Error: Fork Failed") { ++ Parent { child } => { ++ close(w).unwrap(); ++ // wait for child ++ read(r, &mut [0u8]).unwrap(); ++ close(r).unwrap(); ++ ++ let ptr = vector.as_ptr() as usize; ++ let remote_iov = RemoteIoVec { base: ptr, len: 5 }; ++ let mut buf = vec![0u8; 5]; ++ ++ let ret = process_vm_readv(child, ++ &[IoVec::from_mut_slice(&mut buf)], ++ &[remote_iov]); ++ ++ kill(child, SIGTERM).unwrap(); ++ waitpid(child, None).unwrap(); ++ ++ assert_eq!(Ok(5), ret); ++ assert_eq!(20u8, buf.iter().sum()); ++ }, ++ Child => { ++ let _ = close(r); ++ for i in &mut vector { ++ *i += 1; ++ } ++ let _ = write(w, b"\0"); ++ let _ = close(w); ++ loop { let _ = pause(); } ++ }, ++ } ++} +diff --git a/third_party/rust/nix-0.15.0/test/sys/test_wait.rs b/third_party/rust/nix-0.15.0/test/sys/test_wait.rs +new file mode 100644 +index 0000000000000..d07d82f0d9075 +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/test/sys/test_wait.rs +@@ -0,0 +1,104 @@ ++use nix::Error; ++use nix::unistd::*; ++use nix::unistd::ForkResult::*; ++use nix::sys::signal::*; ++use nix::sys::wait::*; ++use libc::_exit; ++ ++#[test] ++fn test_wait_signal() { ++ let _ = ::FORK_MTX.lock().expect("Mutex got poisoned by another test"); ++ ++ // Safe: The child only calls `pause` and/or `_exit`, which are async-signal-safe. ++ match fork().expect("Error: Fork Failed") { ++ Child => { ++ pause(); ++ unsafe { _exit(123) } ++ }, ++ Parent { child } => { ++ kill(child, Some(SIGKILL)).expect("Error: Kill Failed"); ++ assert_eq!(waitpid(child, None), Ok(WaitStatus::Signaled(child, SIGKILL, false))); ++ }, ++ } ++} ++ ++#[test] ++fn test_wait_exit() { ++ let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test"); ++ ++ // Safe: Child only calls `_exit`, which is async-signal-safe. ++ match fork().expect("Error: Fork Failed") { ++ Child => unsafe { _exit(12); }, ++ Parent { child } => { ++ assert_eq!(waitpid(child, None), Ok(WaitStatus::Exited(child, 12))); ++ }, ++ } ++} ++ ++#[test] ++fn test_waitstatus_from_raw() { ++ let pid = Pid::from_raw(1); ++ assert_eq!(WaitStatus::from_raw(pid, 0x0002), Ok(WaitStatus::Signaled(pid, Signal::SIGINT, false))); ++ assert_eq!(WaitStatus::from_raw(pid, 0x0200), Ok(WaitStatus::Exited(pid, 2))); ++ assert_eq!(WaitStatus::from_raw(pid, 0x7f7f), Err(Error::invalid_argument())); ++} ++ ++#[test] ++fn test_waitstatus_pid() { ++ let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test"); ++ ++ match fork().unwrap() { ++ Child => unsafe { _exit(0) }, ++ Parent { child } => { ++ let status = waitpid(child, None).unwrap(); ++ assert_eq!(status.pid(), Some(child)); ++ } ++ } ++} ++ ++#[cfg(any(target_os = "linux", target_os = "android"))] ++// FIXME: qemu-user doesn't implement ptrace on most arches ++#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++mod ptrace { ++ use nix::sys::ptrace::{self, Options, Event}; ++ use nix::sys::signal::*; ++ use nix::sys::wait::*; ++ use nix::unistd::*; ++ use nix::unistd::ForkResult::*; ++ use libc::_exit; ++ ++ fn ptrace_child() -> ! { ++ ptrace::traceme().unwrap(); ++ // As recommended by ptrace(2), raise SIGTRAP to pause the child ++ // until the parent is ready to continue ++ raise(SIGTRAP).unwrap(); ++ unsafe { _exit(0) } ++ } ++ ++ fn ptrace_parent(child: Pid) { ++ // Wait for the raised SIGTRAP ++ assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, SIGTRAP))); ++ // We want to test a syscall stop and a PTRACE_EVENT stop ++ assert!(ptrace::setoptions(child, Options::PTRACE_O_TRACESYSGOOD | Options::PTRACE_O_TRACEEXIT).is_ok()); ++ ++ // First, stop on the next system call, which will be exit() ++ assert!(ptrace::syscall(child).is_ok()); ++ assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child))); ++ // Then get the ptrace event for the process exiting ++ assert!(ptrace::cont(child, None).is_ok()); ++ assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceEvent(child, SIGTRAP, Event::PTRACE_EVENT_EXIT as i32))); ++ // Finally get the normal wait() result, now that the process has exited ++ assert!(ptrace::cont(child, None).is_ok()); ++ assert_eq!(waitpid(child, None), Ok(WaitStatus::Exited(child, 0))); ++ } ++ ++ #[test] ++ fn test_wait_ptrace() { ++ let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test"); ++ ++ match fork().expect("Error: Fork Failed") { ++ Child => ptrace_child(), ++ Parent { child } => ptrace_parent(child), ++ } ++ } ++} +diff --git a/third_party/rust/nix-0.15.0/test/test.rs b/third_party/rust/nix-0.15.0/test/test.rs +new file mode 100644 +index 0000000000000..6a71d261b5712 +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/test/test.rs +@@ -0,0 +1,149 @@ ++// XXX Allow deprecated items until release 0.16.0. See issue #1096. ++#![allow(deprecated)] ++extern crate bytes; ++#[cfg(any(target_os = "android", target_os = "linux"))] ++extern crate caps; ++#[macro_use] ++extern crate cfg_if; ++#[macro_use] ++extern crate nix; ++#[macro_use] ++extern crate lazy_static; ++extern crate libc; ++extern crate rand; ++#[cfg(target_os = "freebsd")] ++extern crate sysctl; ++extern crate tempfile; ++ ++#[cfg(any(target_os = "android", target_os = "linux"))] ++macro_rules! require_capability { ++ ($capname:ident) => { ++ use ::caps::{Capability, CapSet, has_cap}; ++ use ::std::io::{self, Write}; ++ ++ if !has_cap(None, CapSet::Effective, Capability::$capname).unwrap() { ++ let stderr = io::stderr(); ++ let mut handle = stderr.lock(); ++ writeln!(handle, "Insufficient capabilities. Skipping test.") ++ .unwrap(); ++ return; ++ } ++ } ++} ++ ++#[cfg(target_os = "freebsd")] ++macro_rules! skip_if_jailed { ++ ($name:expr) => { ++ use ::sysctl::CtlValue; ++ ++ if let CtlValue::Int(1) = ::sysctl::value("security.jail.jailed") ++ .unwrap() ++ { ++ use ::std::io::Write; ++ let stderr = ::std::io::stderr(); ++ let mut handle = stderr.lock(); ++ writeln!(handle, "{} cannot run in a jail. Skipping test.", $name) ++ .unwrap(); ++ return; ++ } ++ } ++} ++ ++macro_rules! skip_if_not_root { ++ ($name:expr) => { ++ use nix::unistd::Uid; ++ ++ if !Uid::current().is_root() { ++ use ::std::io::Write; ++ let stderr = ::std::io::stderr(); ++ let mut handle = stderr.lock(); ++ writeln!(handle, "{} requires root privileges. Skipping test.", $name).unwrap(); ++ return; ++ } ++ }; ++} ++ ++mod sys; ++mod test_dir; ++mod test_fcntl; ++#[cfg(any(target_os = "android", ++ target_os = "linux"))] ++mod test_kmod; ++#[cfg(any(target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "fushsia", ++ target_os = "linux", ++ target_os = "netbsd"))] ++mod test_mq; ++mod test_net; ++mod test_nix_path; ++mod test_poll; ++mod test_pty; ++#[cfg(any(target_os = "android", ++ target_os = "freebsd", ++ target_os = "ios", ++ target_os = "linux", ++ target_os = "macos"))] ++mod test_sendfile; ++mod test_stat; ++mod test_unistd; ++ ++use std::os::unix::io::RawFd; ++use std::path::PathBuf; ++use std::sync::{Mutex, RwLock, RwLockWriteGuard}; ++use nix::unistd::{chdir, getcwd, read}; ++ ++/// Helper function analogous to `std::io::Read::read_exact`, but for `RawFD`s ++fn read_exact(f: RawFd, buf: &mut [u8]) { ++ let mut len = 0; ++ while len < buf.len() { ++ // get_mut would be better than split_at_mut, but it requires nightly ++ let (_, remaining) = buf.split_at_mut(len); ++ len += read(f, remaining).unwrap(); ++ } ++} ++ ++lazy_static! { ++ /// Any test that changes the process's current working directory must grab ++ /// the RwLock exclusively. Any process that cares about the current ++ /// working directory must grab it shared. ++ pub static ref CWD_LOCK: RwLock<()> = RwLock::new(()); ++ /// Any test that creates child processes must grab this mutex, regardless ++ /// of what it does with those children. ++ pub static ref FORK_MTX: Mutex<()> = Mutex::new(()); ++ /// Any test that changes the process's supplementary groups must grab this ++ /// mutex ++ pub static ref GROUPS_MTX: Mutex<()> = Mutex::new(()); ++ /// Any tests that loads or unloads kernel modules must grab this mutex ++ pub static ref KMOD_MTX: Mutex<()> = Mutex::new(()); ++ /// Any test that calls ptsname(3) must grab this mutex. ++ pub static ref PTSNAME_MTX: Mutex<()> = Mutex::new(()); ++ /// Any test that alters signal handling must grab this mutex. ++ pub static ref SIGNAL_MTX: Mutex<()> = Mutex::new(()); ++} ++ ++/// RAII object that restores a test's original directory on drop ++struct DirRestore<'a> { ++ d: PathBuf, ++ _g: RwLockWriteGuard<'a, ()> ++} ++ ++impl<'a> DirRestore<'a> { ++ fn new() -> Self { ++ let guard = ::CWD_LOCK.write() ++ .expect("Lock got poisoned by another test"); ++ DirRestore{ ++ _g: guard, ++ d: getcwd().unwrap(), ++ } ++ } ++} ++ ++impl<'a> Drop for DirRestore<'a> { ++ fn drop(&mut self) { ++ let r = chdir(&self.d); ++ if std::thread::panicking() { ++ r.unwrap(); ++ } ++ } ++} +diff --git a/third_party/rust/nix-0.15.0/test/test_dir.rs b/third_party/rust/nix-0.15.0/test/test_dir.rs +new file mode 100644 +index 0000000000000..c42fbcd18a29d +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/test/test_dir.rs +@@ -0,0 +1,46 @@ ++extern crate nix; ++extern crate tempfile; ++ ++use nix::dir::{Dir, Type}; ++use nix::fcntl::OFlag; ++use nix::sys::stat::Mode; ++use std::fs::File; ++use self::tempfile::tempdir; ++ ++#[test] ++fn read() { ++ let tmp = tempdir().unwrap(); ++ File::create(&tmp.path().join("foo")).unwrap(); ++ ::std::os::unix::fs::symlink("foo", tmp.path().join("bar")).unwrap(); ++ let mut dir = Dir::open(tmp.path(), OFlag::O_DIRECTORY | OFlag::O_RDONLY | OFlag::O_CLOEXEC, ++ Mode::empty()).unwrap(); ++ let mut entries: Vec<_> = dir.iter().map(|e| e.unwrap()).collect(); ++ entries.sort_by(|a, b| a.file_name().cmp(b.file_name())); ++ let entry_names: Vec<_> = entries ++ .iter() ++ .map(|e| e.file_name().to_str().unwrap().to_owned()) ++ .collect(); ++ assert_eq!(&entry_names[..], &[".", "..", "bar", "foo"]); ++ ++ // Check file types. The system is allowed to return DT_UNKNOWN (aka None here) but if it does ++ // return a type, ensure it's correct. ++ assert!(&[Some(Type::Directory), None].contains(&entries[0].file_type())); // .: dir ++ assert!(&[Some(Type::Directory), None].contains(&entries[1].file_type())); // ..: dir ++ assert!(&[Some(Type::Symlink), None].contains(&entries[2].file_type())); // bar: symlink ++ assert!(&[Some(Type::File), None].contains(&entries[3].file_type())); // foo: regular file ++} ++ ++#[test] ++fn rewind() { ++ let tmp = tempdir().unwrap(); ++ let mut dir = Dir::open(tmp.path(), OFlag::O_DIRECTORY | OFlag::O_RDONLY | OFlag::O_CLOEXEC, ++ Mode::empty()).unwrap(); ++ let entries1: Vec<_> = dir.iter().map(|e| e.unwrap().file_name().to_owned()).collect(); ++ let entries2: Vec<_> = dir.iter().map(|e| e.unwrap().file_name().to_owned()).collect(); ++ assert_eq!(entries1, entries2); ++} ++ ++#[test] ++fn ebadf() { ++ assert_eq!(Dir::from_fd(-1).unwrap_err(), nix::Error::Sys(nix::errno::Errno::EBADF)); ++} +diff --git a/third_party/rust/nix-0.15.0/test/test_fcntl.rs b/third_party/rust/nix-0.15.0/test/test_fcntl.rs +new file mode 100644 +index 0000000000000..6b2bbd679fc31 +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/test/test_fcntl.rs +@@ -0,0 +1,234 @@ ++use nix::Error; ++use nix::errno::*; ++use nix::fcntl::{openat, open, OFlag, readlink, readlinkat, renameat}; ++use nix::sys::stat::Mode; ++use nix::unistd::{close, read}; ++use tempfile::{self, NamedTempFile}; ++use std::fs::File; ++use std::io::prelude::*; ++use std::os::unix::fs; ++ ++#[test] ++fn test_openat() { ++ const CONTENTS: &[u8] = b"abcd"; ++ let mut tmp = NamedTempFile::new().unwrap(); ++ tmp.write_all(CONTENTS).unwrap(); ++ ++ let dirfd = open(tmp.path().parent().unwrap(), ++ OFlag::empty(), ++ Mode::empty()).unwrap(); ++ let fd = openat(dirfd, ++ tmp.path().file_name().unwrap(), ++ OFlag::O_RDONLY, ++ Mode::empty()).unwrap(); ++ ++ let mut buf = [0u8; 1024]; ++ assert_eq!(4, read(fd, &mut buf).unwrap()); ++ assert_eq!(CONTENTS, &buf[0..4]); ++ ++ close(fd).unwrap(); ++ close(dirfd).unwrap(); ++} ++ ++#[test] ++fn test_renameat() { ++ let old_dir = tempfile::tempdir().unwrap(); ++ let old_dirfd = open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); ++ let old_path = old_dir.path().join("old"); ++ File::create(&old_path).unwrap(); ++ let new_dir = tempfile::tempdir().unwrap(); ++ let new_dirfd = open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); ++ renameat(Some(old_dirfd), "old", Some(new_dirfd), "new").unwrap(); ++ assert_eq!(renameat(Some(old_dirfd), "old", Some(new_dirfd), "new").unwrap_err(), ++ Error::Sys(Errno::ENOENT)); ++ close(old_dirfd).unwrap(); ++ close(new_dirfd).unwrap(); ++ assert!(new_dir.path().join("new").exists()); ++} ++ ++#[test] ++fn test_readlink() { ++ let tempdir = tempfile::tempdir().unwrap(); ++ let src = tempdir.path().join("a"); ++ let dst = tempdir.path().join("b"); ++ println!("a: {:?}, b: {:?}", &src, &dst); ++ fs::symlink(&src.as_path(), &dst.as_path()).unwrap(); ++ let dirfd = open(tempdir.path(), ++ OFlag::empty(), ++ Mode::empty()).unwrap(); ++ ++ let mut buf = vec![0; src.to_str().unwrap().len() + 1]; ++ assert_eq!(readlink(&dst, &mut buf).unwrap().to_str().unwrap(), ++ src.to_str().unwrap()); ++ assert_eq!(readlinkat(dirfd, "b", &mut buf).unwrap().to_str().unwrap(), ++ src.to_str().unwrap()); ++} ++ ++#[cfg(any(target_os = "linux", target_os = "android"))] ++mod linux_android { ++ use std::io::prelude::*; ++ use std::io::SeekFrom; ++ use std::os::unix::prelude::*; ++ ++ use libc::loff_t; ++ ++ use nix::fcntl::*; ++ use nix::sys::uio::IoVec; ++ use nix::unistd::{close, pipe, read, write}; ++ ++ use tempfile::{tempfile, NamedTempFile}; ++ ++ /// This test creates a temporary file containing the contents ++ /// 'foobarbaz' and uses the `copy_file_range` call to transfer ++ /// 3 bytes at offset 3 (`bar`) to another empty file at offset 0. The ++ /// resulting file is read and should contain the contents `bar`. ++ /// The from_offset should be updated by the call to reflect ++ /// the 3 bytes read (6). ++ /// ++ /// FIXME: This test is disabled for linux based builds, because Travis ++ /// Linux version is too old for `copy_file_range`. ++ #[test] ++ #[ignore] ++ fn test_copy_file_range() { ++ const CONTENTS: &[u8] = b"foobarbaz"; ++ ++ let mut tmp1 = tempfile().unwrap(); ++ let mut tmp2 = tempfile().unwrap(); ++ ++ tmp1.write_all(CONTENTS).unwrap(); ++ tmp1.flush().unwrap(); ++ ++ let mut from_offset: i64 = 3; ++ copy_file_range( ++ tmp1.as_raw_fd(), ++ Some(&mut from_offset), ++ tmp2.as_raw_fd(), ++ None, ++ 3, ++ ) ++ .unwrap(); ++ ++ let mut res: String = String::new(); ++ tmp2.seek(SeekFrom::Start(0)).unwrap(); ++ tmp2.read_to_string(&mut res).unwrap(); ++ ++ assert_eq!(res, String::from("bar")); ++ assert_eq!(from_offset, 6); ++ } ++ ++ #[test] ++ fn test_splice() { ++ const CONTENTS: &[u8] = b"abcdef123456"; ++ let mut tmp = tempfile().unwrap(); ++ tmp.write_all(CONTENTS).unwrap(); ++ ++ let (rd, wr) = pipe().unwrap(); ++ let mut offset: loff_t = 5; ++ let res = splice(tmp.as_raw_fd(), Some(&mut offset), ++ wr, None, 2, SpliceFFlags::empty()).unwrap(); ++ ++ assert_eq!(2, res); ++ ++ let mut buf = [0u8; 1024]; ++ assert_eq!(2, read(rd, &mut buf).unwrap()); ++ assert_eq!(b"f1", &buf[0..2]); ++ assert_eq!(7, offset); ++ ++ close(rd).unwrap(); ++ close(wr).unwrap(); ++ } ++ ++ #[test] ++ fn test_tee() { ++ let (rd1, wr1) = pipe().unwrap(); ++ let (rd2, wr2) = pipe().unwrap(); ++ ++ write(wr1, b"abc").unwrap(); ++ let res = tee(rd1, wr2, 2, SpliceFFlags::empty()).unwrap(); ++ ++ assert_eq!(2, res); ++ ++ let mut buf = [0u8; 1024]; ++ ++ // Check the tee'd bytes are at rd2. ++ assert_eq!(2, read(rd2, &mut buf).unwrap()); ++ assert_eq!(b"ab", &buf[0..2]); ++ ++ // Check all the bytes are still at rd1. ++ assert_eq!(3, read(rd1, &mut buf).unwrap()); ++ assert_eq!(b"abc", &buf[0..3]); ++ ++ close(rd1).unwrap(); ++ close(wr1).unwrap(); ++ close(rd2).unwrap(); ++ close(wr2).unwrap(); ++ } ++ ++ #[test] ++ fn test_vmsplice() { ++ let (rd, wr) = pipe().unwrap(); ++ ++ let buf1 = b"abcdef"; ++ let buf2 = b"defghi"; ++ let mut iovecs = Vec::with_capacity(2); ++ iovecs.push(IoVec::from_slice(&buf1[0..3])); ++ iovecs.push(IoVec::from_slice(&buf2[0..3])); ++ ++ let res = vmsplice(wr, &iovecs[..], SpliceFFlags::empty()).unwrap(); ++ ++ assert_eq!(6, res); ++ ++ // Check the bytes can be read at rd. ++ let mut buf = [0u8; 32]; ++ assert_eq!(6, read(rd, &mut buf).unwrap()); ++ assert_eq!(b"abcdef", &buf[0..6]); ++ ++ close(rd).unwrap(); ++ close(wr).unwrap(); ++ } ++ ++ #[test] ++ fn test_fallocate() { ++ let tmp = NamedTempFile::new().unwrap(); ++ ++ let fd = tmp.as_raw_fd(); ++ fallocate(fd, FallocateFlags::empty(), 0, 100).unwrap(); ++ ++ // Check if we read exactly 100 bytes ++ let mut buf = [0u8; 200]; ++ assert_eq!(100, read(fd, &mut buf).unwrap()); ++ } ++} ++ ++#[cfg(any(target_os = "linux", ++ target_os = "android", ++ target_os = "emscripten", ++ target_os = "fuchsia", ++ any(target_os = "wasi", target_env = "wasi"), ++ target_env = "uclibc", ++ target_env = "freebsd"))] ++mod test_posix_fadvise { ++ ++ use tempfile::NamedTempFile; ++ use std::os::unix::io::{RawFd, AsRawFd}; ++ use nix::errno::Errno; ++ use nix::fcntl::*; ++ use nix::unistd::pipe; ++ ++ #[test] ++ fn test_success() { ++ let tmp = NamedTempFile::new().unwrap(); ++ let fd = tmp.as_raw_fd(); ++ let res = posix_fadvise(fd, 0, 100, PosixFadviseAdvice::POSIX_FADV_WILLNEED).unwrap(); ++ ++ assert_eq!(res, 0); ++ } ++ ++ #[test] ++ fn test_errno() { ++ let (rd, _wr) = pipe().unwrap(); ++ let errno = posix_fadvise(rd as RawFd, 0, 100, PosixFadviseAdvice::POSIX_FADV_WILLNEED) ++ .unwrap(); ++ assert_eq!(errno, Errno::ESPIPE as i32); ++ } ++} +diff --git a/third_party/rust/nix-0.15.0/test/test_kmod/hello_mod/Makefile b/third_party/rust/nix-0.15.0/test/test_kmod/hello_mod/Makefile +new file mode 100644 +index 0000000000000..74c99b77e96e1 +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/test/test_kmod/hello_mod/Makefile +@@ -0,0 +1,7 @@ ++obj-m += hello.o ++ ++all: ++ make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modules ++ ++clean: ++ make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) clean +diff --git a/third_party/rust/nix-0.15.0/test/test_kmod/hello_mod/hello.c b/third_party/rust/nix-0.15.0/test/test_kmod/hello_mod/hello.c +new file mode 100644 +index 0000000000000..1c34987d2ac39 +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/test/test_kmod/hello_mod/hello.c +@@ -0,0 +1,26 @@ ++/* ++ * SPDX-License-Identifier: GPL-2.0+ or MIT ++ */ ++#include <linux/module.h> ++#include <linux/kernel.h> ++ ++static int number= 1; ++static char *who = "World"; ++ ++module_param(number, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); ++MODULE_PARM_DESC(myint, "Just some number"); ++module_param(who, charp, 0000); ++MODULE_PARM_DESC(who, "Whot to greet"); ++ ++int init_module(void) ++{ ++ printk(KERN_INFO "Hello %s (%d)!\n", who, number); ++ return 0; ++} ++ ++void cleanup_module(void) ++{ ++ printk(KERN_INFO "Goodbye %s (%d)!\n", who, number); ++} ++ ++MODULE_LICENSE("Dual MIT/GPL"); +diff --git a/third_party/rust/nix-0.15.0/test/test_kmod/mod.rs b/third_party/rust/nix-0.15.0/test/test_kmod/mod.rs +new file mode 100644 +index 0000000000000..ad406357b06d2 +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/test/test_kmod/mod.rs +@@ -0,0 +1,166 @@ ++use std::fs::copy; ++use std::path::PathBuf; ++use std::process::Command; ++use tempfile::{tempdir, TempDir}; ++ ++fn compile_kernel_module() -> (PathBuf, String, TempDir) { ++ let _m = ::FORK_MTX ++ .lock() ++ .expect("Mutex got poisoned by another test"); ++ ++ let tmp_dir = tempdir().expect("unable to create temporary build directory"); ++ ++ copy( ++ "test/test_kmod/hello_mod/hello.c", ++ &tmp_dir.path().join("hello.c"), ++ ).expect("unable to copy hello.c to temporary build directory"); ++ copy( ++ "test/test_kmod/hello_mod/Makefile", ++ &tmp_dir.path().join("Makefile"), ++ ).expect("unable to copy Makefile to temporary build directory"); ++ ++ let status = Command::new("make") ++ .current_dir(tmp_dir.path()) ++ .status() ++ .expect("failed to run make"); ++ ++ assert!(status.success()); ++ ++ // Return the relative path of the build kernel module ++ (tmp_dir.path().join("hello.ko"), "hello".to_owned(), tmp_dir) ++} ++ ++use nix::errno::Errno; ++use nix::kmod::{delete_module, DeleteModuleFlags}; ++use nix::kmod::{finit_module, init_module, ModuleInitFlags}; ++use nix::Error; ++use std::ffi::CString; ++use std::fs::File; ++use std::io::Read; ++ ++#[test] ++fn test_finit_and_delete_module() { ++ require_capability!(CAP_SYS_MODULE); ++ let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); ++ let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test"); ++ ++ let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module(); ++ ++ let f = File::open(kmod_path).expect("unable to open kernel module"); ++ finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty()) ++ .expect("unable to load kernel module"); ++ ++ delete_module( ++ &CString::new(kmod_name).unwrap(), ++ DeleteModuleFlags::empty(), ++ ).expect("unable to unload kernel module"); ++} ++ ++#[test] ++fn test_finit_and_delete_modul_with_params() { ++ require_capability!(CAP_SYS_MODULE); ++ let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); ++ let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test"); ++ ++ let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module(); ++ ++ let f = File::open(kmod_path).expect("unable to open kernel module"); ++ finit_module( ++ &f, ++ &CString::new("who=Rust number=2018").unwrap(), ++ ModuleInitFlags::empty(), ++ ).expect("unable to load kernel module"); ++ ++ delete_module( ++ &CString::new(kmod_name).unwrap(), ++ DeleteModuleFlags::empty(), ++ ).expect("unable to unload kernel module"); ++} ++ ++#[test] ++fn test_init_and_delete_module() { ++ require_capability!(CAP_SYS_MODULE); ++ let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); ++ let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test"); ++ ++ let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module(); ++ ++ let mut f = File::open(kmod_path).expect("unable to open kernel module"); ++ let mut contents: Vec<u8> = Vec::new(); ++ f.read_to_end(&mut contents) ++ .expect("unable to read kernel module content to buffer"); ++ init_module(&mut contents, &CString::new("").unwrap()).expect("unable to load kernel module"); ++ ++ delete_module( ++ &CString::new(kmod_name).unwrap(), ++ DeleteModuleFlags::empty(), ++ ).expect("unable to unload kernel module"); ++} ++ ++#[test] ++fn test_init_and_delete_module_with_params() { ++ require_capability!(CAP_SYS_MODULE); ++ let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); ++ let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test"); ++ ++ let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module(); ++ ++ let mut f = File::open(kmod_path).expect("unable to open kernel module"); ++ let mut contents: Vec<u8> = Vec::new(); ++ f.read_to_end(&mut contents) ++ .expect("unable to read kernel module content to buffer"); ++ init_module(&mut contents, &CString::new("who=Nix number=2015").unwrap()) ++ .expect("unable to load kernel module"); ++ ++ delete_module( ++ &CString::new(kmod_name).unwrap(), ++ DeleteModuleFlags::empty(), ++ ).expect("unable to unload kernel module"); ++} ++ ++#[test] ++fn test_finit_module_invalid() { ++ require_capability!(CAP_SYS_MODULE); ++ let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); ++ let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test"); ++ ++ let kmod_path = "/dev/zero"; ++ ++ let f = File::open(kmod_path).expect("unable to open kernel module"); ++ let result = finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty()); ++ ++ assert_eq!(result.unwrap_err(), Error::Sys(Errno::EINVAL)); ++} ++ ++#[test] ++fn test_finit_module_twice_and_delete_module() { ++ require_capability!(CAP_SYS_MODULE); ++ let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); ++ let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test"); ++ ++ let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module(); ++ ++ let f = File::open(kmod_path).expect("unable to open kernel module"); ++ finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty()) ++ .expect("unable to load kernel module"); ++ ++ let result = finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty()); ++ ++ assert_eq!(result.unwrap_err(), Error::Sys(Errno::EEXIST)); ++ ++ delete_module( ++ &CString::new(kmod_name).unwrap(), ++ DeleteModuleFlags::empty(), ++ ).expect("unable to unload kernel module"); ++} ++ ++#[test] ++fn test_delete_module_not_loaded() { ++ require_capability!(CAP_SYS_MODULE); ++ let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); ++ let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test"); ++ ++ let result = delete_module(&CString::new("hello").unwrap(), DeleteModuleFlags::empty()); ++ ++ assert_eq!(result.unwrap_err(), Error::Sys(Errno::ENOENT)); ++} +diff --git a/third_party/rust/nix-0.15.0/test/test_mount.rs b/third_party/rust/nix-0.15.0/test/test_mount.rs +new file mode 100644 +index 0000000000000..d2e08bc42855d +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/test/test_mount.rs +@@ -0,0 +1,238 @@ ++// Impelmentation note: to allow unprivileged users to run it, this test makes ++// use of user and mount namespaces. On systems that allow unprivileged user ++// namespaces (Linux >= 3.8 compiled with CONFIG_USER_NS), the test should run ++// without root. ++ ++extern crate libc; ++extern crate nix; ++extern crate tempfile; ++ ++#[cfg(target_os = "linux")] ++mod test_mount { ++ use std::fs::{self, File}; ++ use std::io::{self, Read, Write}; ++ use std::os::unix::fs::OpenOptionsExt; ++ use std::os::unix::fs::PermissionsExt; ++ use std::process::{self, Command}; ++ ++ use libc::{EACCES, EROFS}; ++ ++ use nix::errno::Errno; ++ use nix::mount::{mount, umount, MsFlags}; ++ use nix::sched::{unshare, CloneFlags}; ++ use nix::sys::stat::{self, Mode}; ++ use nix::unistd::getuid; ++ ++ use tempfile; ++ ++ static SCRIPT_CONTENTS: &'static [u8] = b"#!/bin/sh ++exit 23"; ++ ++ const EXPECTED_STATUS: i32 = 23; ++ ++ const NONE: Option<&'static [u8]> = None; ++ pub fn test_mount_tmpfs_without_flags_allows_rwx() { ++ let tempdir = tempfile::tempdir().unwrap(); ++ ++ mount(NONE, ++ tempdir.path(), ++ Some(b"tmpfs".as_ref()), ++ MsFlags::empty(), ++ NONE) ++ .unwrap_or_else(|e| panic!("mount failed: {}", e)); ++ ++ let test_path = tempdir.path().join("test"); ++ ++ // Verify write. ++ fs::OpenOptions::new() ++ .create(true) ++ .write(true) ++ .mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits()) ++ .open(&test_path) ++ .or_else(|e| ++ if Errno::from_i32(e.raw_os_error().unwrap()) == Errno::EOVERFLOW { ++ // Skip tests on certain Linux kernels which have a bug ++ // regarding tmpfs in namespaces. ++ // Ubuntu 14.04 and 16.04 are known to be affected; 16.10 is ++ // not. There is no legitimate reason for open(2) to return ++ // EOVERFLOW here. ++ // https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1659087 ++ let stderr = io::stderr(); ++ let mut handle = stderr.lock(); ++ writeln!(handle, "Buggy Linux kernel detected. Skipping test.") ++ .unwrap(); ++ process::exit(0); ++ } else { ++ panic!("open failed: {}", e); ++ } ++ ) ++ .and_then(|mut f| f.write(SCRIPT_CONTENTS)) ++ .unwrap_or_else(|e| panic!("write failed: {}", e)); ++ ++ // Verify read. ++ let mut buf = Vec::new(); ++ File::open(&test_path) ++ .and_then(|mut f| f.read_to_end(&mut buf)) ++ .unwrap_or_else(|e| panic!("read failed: {}", e)); ++ assert_eq!(buf, SCRIPT_CONTENTS); ++ ++ // Verify execute. ++ assert_eq!(EXPECTED_STATUS, ++ Command::new(&test_path) ++ .status() ++ .unwrap_or_else(|e| panic!("exec failed: {}", e)) ++ .code() ++ .unwrap_or_else(|| panic!("child killed by signal"))); ++ ++ umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {}", e)); ++ } ++ ++ pub fn test_mount_rdonly_disallows_write() { ++ let tempdir = tempfile::tempdir().unwrap(); ++ ++ mount(NONE, ++ tempdir.path(), ++ Some(b"tmpfs".as_ref()), ++ MsFlags::MS_RDONLY, ++ NONE) ++ .unwrap_or_else(|e| panic!("mount failed: {}", e)); ++ ++ // EROFS: Read-only file system ++ assert_eq!(EROFS as i32, ++ File::create(tempdir.path().join("test")).unwrap_err().raw_os_error().unwrap()); ++ ++ umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {}", e)); ++ } ++ ++ pub fn test_mount_noexec_disallows_exec() { ++ let tempdir = tempfile::tempdir().unwrap(); ++ ++ mount(NONE, ++ tempdir.path(), ++ Some(b"tmpfs".as_ref()), ++ MsFlags::MS_NOEXEC, ++ NONE) ++ .unwrap_or_else(|e| panic!("mount failed: {}", e)); ++ ++ let test_path = tempdir.path().join("test"); ++ ++ fs::OpenOptions::new() ++ .create(true) ++ .write(true) ++ .mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits()) ++ .open(&test_path) ++ .and_then(|mut f| f.write(SCRIPT_CONTENTS)) ++ .unwrap_or_else(|e| panic!("write failed: {}", e)); ++ ++ // Verify that we cannot execute despite a+x permissions being set. ++ let mode = stat::Mode::from_bits_truncate(fs::metadata(&test_path) ++ .map(|md| md.permissions().mode()) ++ .unwrap_or_else(|e| { ++ panic!("metadata failed: {}", e) ++ })); ++ ++ assert!(mode.contains(Mode::S_IXUSR | Mode::S_IXGRP | Mode::S_IXOTH), ++ "{:?} did not have execute permissions", ++ &test_path); ++ ++ // EACCES: Permission denied ++ assert_eq!(EACCES as i32, ++ Command::new(&test_path).status().unwrap_err().raw_os_error().unwrap()); ++ ++ umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {}", e)); ++ } ++ ++ pub fn test_mount_bind() { ++ let tempdir = tempfile::tempdir().unwrap(); ++ let file_name = "test"; ++ ++ { ++ let mount_point = tempfile::tempdir().unwrap(); ++ ++ mount(Some(tempdir.path()), ++ mount_point.path(), ++ NONE, ++ MsFlags::MS_BIND, ++ NONE) ++ .unwrap_or_else(|e| panic!("mount failed: {}", e)); ++ ++ fs::OpenOptions::new() ++ .create(true) ++ .write(true) ++ .mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits()) ++ .open(mount_point.path().join(file_name)) ++ .and_then(|mut f| f.write(SCRIPT_CONTENTS)) ++ .unwrap_or_else(|e| panic!("write failed: {}", e)); ++ ++ umount(mount_point.path()).unwrap_or_else(|e| panic!("umount failed: {}", e)); ++ } ++ ++ // Verify the file written in the mount shows up in source directory, even ++ // after unmounting. ++ ++ let mut buf = Vec::new(); ++ File::open(tempdir.path().join(file_name)) ++ .and_then(|mut f| f.read_to_end(&mut buf)) ++ .unwrap_or_else(|e| panic!("read failed: {}", e)); ++ assert_eq!(buf, SCRIPT_CONTENTS); ++ } ++ ++ pub fn setup_namespaces() { ++ // Hold on to the uid in the parent namespace. ++ let uid = getuid(); ++ ++ unshare(CloneFlags::CLONE_NEWNS | CloneFlags::CLONE_NEWUSER).unwrap_or_else(|e| { ++ let stderr = io::stderr(); ++ let mut handle = stderr.lock(); ++ writeln!(handle, ++ "unshare failed: {}. Are unprivileged user namespaces available?", ++ e).unwrap(); ++ writeln!(handle, "mount is not being tested").unwrap(); ++ // Exit with success because not all systems support unprivileged user namespaces, and ++ // that's not what we're testing for. ++ process::exit(0); ++ }); ++ ++ // Map user as uid 1000. ++ fs::OpenOptions::new() ++ .write(true) ++ .open("/proc/self/uid_map") ++ .and_then(|mut f| f.write(format!("1000 {} 1\n", uid).as_bytes())) ++ .unwrap_or_else(|e| panic!("could not write uid map: {}", e)); ++ } ++} ++ ++ ++// Test runner ++ ++/// Mimic normal test output (hackishly). ++#[cfg(target_os = "linux")] ++macro_rules! run_tests { ++ ( $($test_fn:ident),* ) => {{ ++ println!(); ++ ++ $( ++ print!("test test_mount::{} ... ", stringify!($test_fn)); ++ $test_fn(); ++ println!("ok"); ++ )* ++ ++ println!(); ++ }} ++} ++ ++#[cfg(target_os = "linux")] ++fn main() { ++ use test_mount::{setup_namespaces, test_mount_tmpfs_without_flags_allows_rwx, ++ test_mount_rdonly_disallows_write, test_mount_noexec_disallows_exec, ++ test_mount_bind}; ++ setup_namespaces(); ++ ++ run_tests!(test_mount_tmpfs_without_flags_allows_rwx, ++ test_mount_rdonly_disallows_write, ++ test_mount_noexec_disallows_exec, ++ test_mount_bind); ++} ++ ++#[cfg(not(target_os = "linux"))] ++fn main() {} +diff --git a/third_party/rust/nix-0.15.0/test/test_mq.rs b/third_party/rust/nix-0.15.0/test/test_mq.rs +new file mode 100644 +index 0000000000000..caac4fc261cd6 +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/test/test_mq.rs +@@ -0,0 +1,152 @@ ++use libc::c_long; ++ ++use std::ffi::CString; ++use std::str; ++ ++use nix::errno::Errno::*; ++use nix::Error::Sys; ++use nix::mqueue::{mq_open, mq_close, mq_send, mq_receive}; ++use nix::mqueue::{MqAttr, MQ_OFlag}; ++use nix::sys::stat::Mode; ++ ++#[test] ++fn test_mq_send_and_receive() { ++ const MSG_SIZE: c_long = 32; ++ let attr = MqAttr::new(0, 10, MSG_SIZE, 0); ++ let mq_name= &CString::new(b"/a_nix_test_queue".as_ref()).unwrap(); ++ ++ let oflag0 = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; ++ let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH; ++ let r0 = mq_open(mq_name, oflag0, mode, Some(&attr)); ++ if let Err(Sys(ENOSYS)) = r0 { ++ println!("message queues not supported or module not loaded?"); ++ return; ++ }; ++ let mqd0 = r0.unwrap(); ++ let msg_to_send = "msg_1"; ++ mq_send(mqd0, msg_to_send.as_bytes(), 1).unwrap(); ++ ++ let oflag1 = MQ_OFlag::O_CREAT | MQ_OFlag::O_RDONLY; ++ let mqd1 = mq_open(mq_name, oflag1, mode, Some(&attr)).unwrap(); ++ let mut buf = [0u8; 32]; ++ let mut prio = 0u32; ++ let len = mq_receive(mqd1, &mut buf, &mut prio).unwrap(); ++ assert!(prio == 1); ++ ++ mq_close(mqd1).unwrap(); ++ mq_close(mqd0).unwrap(); ++ assert_eq!(msg_to_send, str::from_utf8(&buf[0..len]).unwrap()); ++} ++ ++ ++#[test] ++#[cfg(not(any(target_os = "netbsd")))] ++fn test_mq_getattr() { ++ use nix::mqueue::mq_getattr; ++ const MSG_SIZE: c_long = 32; ++ let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0); ++ let mq_name = &CString::new(b"/attr_test_get_attr".as_ref()).unwrap(); ++ let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; ++ let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH; ++ let r = mq_open(mq_name, oflag, mode, Some(&initial_attr)); ++ if let Err(Sys(ENOSYS)) = r { ++ println!("message queues not supported or module not loaded?"); ++ return; ++ }; ++ let mqd = r.unwrap(); ++ ++ let read_attr = mq_getattr(mqd).unwrap(); ++ assert_eq!(read_attr, initial_attr); ++ mq_close(mqd).unwrap(); ++} ++ ++// FIXME: Fix failures for mips in QEMU ++#[test] ++#[cfg(not(any(target_os = "netbsd")))] ++#[cfg_attr(any(target_arch = "mips", target_arch = "mips64"), ignore)] ++fn test_mq_setattr() { ++ use nix::mqueue::{mq_getattr, mq_setattr}; ++ const MSG_SIZE: c_long = 32; ++ let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0); ++ let mq_name = &CString::new(b"/attr_test_get_attr".as_ref()).unwrap(); ++ let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; ++ let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH; ++ let r = mq_open(mq_name, oflag, mode, Some(&initial_attr)); ++ if let Err(Sys(ENOSYS)) = r { ++ println!("message queues not supported or module not loaded?"); ++ return; ++ }; ++ let mqd = r.unwrap(); ++ ++ let new_attr = MqAttr::new(0, 20, MSG_SIZE * 2, 100); ++ let old_attr = mq_setattr(mqd, &new_attr).unwrap(); ++ assert_eq!(old_attr, initial_attr); ++ ++ let new_attr_get = mq_getattr(mqd).unwrap(); ++ // The following tests make sense. No changes here because according to the Linux man page only ++ // O_NONBLOCK can be set (see tests below) ++ assert_ne!(new_attr_get, new_attr); ++ ++ let new_attr_non_blocking = MqAttr::new(MQ_OFlag::O_NONBLOCK.bits() as c_long, 10, MSG_SIZE, 0); ++ mq_setattr(mqd, &new_attr_non_blocking).unwrap(); ++ let new_attr_get = mq_getattr(mqd).unwrap(); ++ ++ // now the O_NONBLOCK flag has been set ++ assert_ne!(new_attr_get, initial_attr); ++ assert_eq!(new_attr_get, new_attr_non_blocking); ++ mq_close(mqd).unwrap(); ++} ++ ++// FIXME: Fix failures for mips in QEMU ++#[test] ++#[cfg(not(any(target_os = "netbsd")))] ++#[cfg_attr(any(target_arch = "mips", target_arch = "mips64"), ignore)] ++fn test_mq_set_nonblocking() { ++ use nix::mqueue::{mq_getattr, mq_set_nonblock, mq_remove_nonblock}; ++ const MSG_SIZE: c_long = 32; ++ let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0); ++ let mq_name = &CString::new(b"/attr_test_get_attr".as_ref()).unwrap(); ++ let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; ++ let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH; ++ let r = mq_open(mq_name, oflag, mode, Some(&initial_attr)); ++ if let Err(Sys(ENOSYS)) = r { ++ println!("message queues not supported or module not loaded?"); ++ return; ++ }; ++ let mqd = r.unwrap(); ++ mq_set_nonblock(mqd).unwrap(); ++ let new_attr = mq_getattr(mqd); ++ assert!(new_attr.unwrap().flags() == MQ_OFlag::O_NONBLOCK.bits() as c_long); ++ mq_remove_nonblock(mqd).unwrap(); ++ let new_attr = mq_getattr(mqd); ++ assert!(new_attr.unwrap().flags() == 0); ++ mq_close(mqd).unwrap(); ++} ++ ++#[test] ++#[cfg(not(any(target_os = "netbsd")))] ++fn test_mq_unlink() { ++ use nix::mqueue::mq_unlink; ++ const MSG_SIZE: c_long = 32; ++ let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0); ++ let mq_name_opened = &CString::new(b"/mq_unlink_test".as_ref()).unwrap(); ++ let mq_name_not_opened = &CString::new(b"/mq_unlink_test".as_ref()).unwrap(); ++ let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; ++ let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH; ++ let r = mq_open(mq_name_opened, oflag, mode, Some(&initial_attr)); ++ if let Err(Sys(ENOSYS)) = r { ++ println!("message queues not supported or module not loaded?"); ++ return; ++ }; ++ let mqd = r.unwrap(); ++ ++ let res_unlink = mq_unlink(mq_name_opened); ++ assert!(res_unlink == Ok(()) ); ++ ++ let res_unlink_not_opened = mq_unlink(mq_name_not_opened); ++ assert!(res_unlink_not_opened == Err(Sys(ENOENT)) ); ++ ++ mq_close(mqd).unwrap(); ++ let res_unlink_after_close = mq_unlink(mq_name_opened); ++ assert!(res_unlink_after_close == Err(Sys(ENOENT)) ); ++} +diff --git a/third_party/rust/nix-0.15.0/test/test_net.rs b/third_party/rust/nix-0.15.0/test/test_net.rs +new file mode 100644 +index 0000000000000..b8940e718bdf3 +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/test/test_net.rs +@@ -0,0 +1,12 @@ ++use nix::net::if_::*; ++ ++#[cfg(any(target_os = "android", target_os = "linux"))] ++const LOOPBACK: &[u8] = b"lo"; ++ ++#[cfg(not(any(target_os = "android", target_os = "linux")))] ++const LOOPBACK: &[u8] = b"lo0"; ++ ++#[test] ++fn test_if_nametoindex() { ++ assert!(if_nametoindex(&LOOPBACK[..]).is_ok()); ++} +diff --git a/third_party/rust/nix-0.15.0/test/test_nix_path.rs b/third_party/rust/nix-0.15.0/test/test_nix_path.rs +new file mode 100644 +index 0000000000000..e69de29bb2d1d +diff --git a/third_party/rust/nix-0.15.0/test/test_poll.rs b/third_party/rust/nix-0.15.0/test/test_poll.rs +new file mode 100644 +index 0000000000000..aef40e4792b5a +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/test/test_poll.rs +@@ -0,0 +1,50 @@ ++use nix::poll::{PollFlags, poll, PollFd}; ++use nix::unistd::{write, pipe}; ++ ++#[test] ++fn test_poll() { ++ let (r, w) = pipe().unwrap(); ++ let mut fds = [PollFd::new(r, PollFlags::POLLIN)]; ++ ++ // Poll an idle pipe. Should timeout ++ let nfds = poll(&mut fds, 100).unwrap(); ++ assert_eq!(nfds, 0); ++ assert!(!fds[0].revents().unwrap().contains(PollFlags::POLLIN)); ++ ++ write(w, b".").unwrap(); ++ ++ // Poll a readable pipe. Should return an event. ++ let nfds = poll(&mut fds, 100).unwrap(); ++ assert_eq!(nfds, 1); ++ assert!(fds[0].revents().unwrap().contains(PollFlags::POLLIN)); ++} ++ ++// ppoll(2) is the same as poll except for how it handles timeouts and signals. ++// Repeating the test for poll(2) should be sufficient to check that our ++// bindings are correct. ++#[cfg(any(target_os = "android", ++ target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "linux"))] ++#[test] ++fn test_ppoll() { ++ use nix::poll::ppoll; ++ use nix::sys::signal::SigSet; ++ use nix::sys::time::{TimeSpec, TimeValLike}; ++ ++ let timeout = TimeSpec::milliseconds(1); ++ let (r, w) = pipe().unwrap(); ++ let mut fds = [PollFd::new(r, PollFlags::POLLIN)]; ++ ++ // Poll an idle pipe. Should timeout ++ let nfds = ppoll(&mut fds, timeout, SigSet::empty()).unwrap(); ++ assert_eq!(nfds, 0); ++ assert!(!fds[0].revents().unwrap().contains(PollFlags::POLLIN)); ++ ++ write(w, b".").unwrap(); ++ ++ // Poll a readable pipe. Should return an event. ++ let nfds = ppoll(&mut fds, timeout, SigSet::empty()).unwrap(); ++ assert_eq!(nfds, 1); ++ assert!(fds[0].revents().unwrap().contains(PollFlags::POLLIN)); ++} +diff --git a/third_party/rust/nix-0.15.0/test/test_pty.rs b/third_party/rust/nix-0.15.0/test/test_pty.rs +new file mode 100644 +index 0000000000000..476b15c10128c +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/test/test_pty.rs +@@ -0,0 +1,235 @@ ++use std::io::Write; ++use std::path::Path; ++use std::os::unix::prelude::*; ++use tempfile::tempfile; ++ ++use libc::{_exit, STDOUT_FILENO}; ++use nix::fcntl::{OFlag, open}; ++use nix::pty::*; ++use nix::sys::stat; ++use nix::sys::termios::*; ++use nix::unistd::{write, close, pause}; ++ ++/// Regression test for Issue #659 ++/// This is the correct way to explicitly close a `PtyMaster` ++#[test] ++fn test_explicit_close() { ++ let mut f = { ++ let m = posix_openpt(OFlag::O_RDWR).unwrap(); ++ close(m.into_raw_fd()).unwrap(); ++ tempfile().unwrap() ++ }; ++ // This should work. But if there's been a double close, then it will ++ // return EBADF ++ f.write_all(b"whatever").unwrap(); ++} ++ ++/// Test equivalence of `ptsname` and `ptsname_r` ++#[test] ++#[cfg(any(target_os = "android", target_os = "linux"))] ++fn test_ptsname_equivalence() { ++ let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); ++ ++ // Open a new PTTY master ++ let master_fd = posix_openpt(OFlag::O_RDWR).unwrap(); ++ assert!(master_fd.as_raw_fd() > 0); ++ ++ // Get the name of the slave ++ let slave_name = unsafe { ptsname(&master_fd) }.unwrap() ; ++ let slave_name_r = ptsname_r(&master_fd).unwrap(); ++ assert_eq!(slave_name, slave_name_r); ++} ++ ++/// Test data copying of `ptsname` ++// TODO need to run in a subprocess, since ptsname is non-reentrant ++#[test] ++#[cfg(any(target_os = "android", target_os = "linux"))] ++fn test_ptsname_copy() { ++ let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); ++ ++ // Open a new PTTY master ++ let master_fd = posix_openpt(OFlag::O_RDWR).unwrap(); ++ assert!(master_fd.as_raw_fd() > 0); ++ ++ // Get the name of the slave ++ let slave_name1 = unsafe { ptsname(&master_fd) }.unwrap(); ++ let slave_name2 = unsafe { ptsname(&master_fd) }.unwrap(); ++ assert!(slave_name1 == slave_name2); ++ // Also make sure that the string was actually copied and they point to different parts of ++ // memory. ++ assert!(slave_name1.as_ptr() != slave_name2.as_ptr()); ++} ++ ++/// Test data copying of `ptsname_r` ++#[test] ++#[cfg(any(target_os = "android", target_os = "linux"))] ++fn test_ptsname_r_copy() { ++ // Open a new PTTY master ++ let master_fd = posix_openpt(OFlag::O_RDWR).unwrap(); ++ assert!(master_fd.as_raw_fd() > 0); ++ ++ // Get the name of the slave ++ let slave_name1 = ptsname_r(&master_fd).unwrap(); ++ let slave_name2 = ptsname_r(&master_fd).unwrap(); ++ assert!(slave_name1 == slave_name2); ++ assert!(slave_name1.as_ptr() != slave_name2.as_ptr()); ++} ++ ++/// Test that `ptsname` returns different names for different devices ++#[test] ++#[cfg(any(target_os = "android", target_os = "linux"))] ++fn test_ptsname_unique() { ++ let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); ++ ++ // Open a new PTTY master ++ let master1_fd = posix_openpt(OFlag::O_RDWR).unwrap(); ++ assert!(master1_fd.as_raw_fd() > 0); ++ ++ // Open a second PTTY master ++ let master2_fd = posix_openpt(OFlag::O_RDWR).unwrap(); ++ assert!(master2_fd.as_raw_fd() > 0); ++ ++ // Get the name of the slave ++ let slave_name1 = unsafe { ptsname(&master1_fd) }.unwrap(); ++ let slave_name2 = unsafe { ptsname(&master2_fd) }.unwrap(); ++ assert!(slave_name1 != slave_name2); ++} ++ ++/// Test opening a master/slave PTTY pair ++/// ++/// This is a single larger test because much of these functions aren't useful by themselves. So for ++/// this test we perform the basic act of getting a file handle for a connect master/slave PTTY ++/// pair. ++#[test] ++fn test_open_ptty_pair() { ++ let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); ++ ++ // Open a new PTTY master ++ let master_fd = posix_openpt(OFlag::O_RDWR).expect("posix_openpt failed"); ++ assert!(master_fd.as_raw_fd() > 0); ++ ++ // Allow a slave to be generated for it ++ grantpt(&master_fd).expect("grantpt failed"); ++ unlockpt(&master_fd).expect("unlockpt failed"); ++ ++ // Get the name of the slave ++ let slave_name = unsafe { ptsname(&master_fd) }.expect("ptsname failed"); ++ ++ // Open the slave device ++ let slave_fd = open(Path::new(&slave_name), OFlag::O_RDWR, stat::Mode::empty()).unwrap(); ++ assert!(slave_fd > 0); ++} ++ ++#[test] ++fn test_openpty() { ++ // openpty uses ptname(3) internally ++ let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); ++ ++ let pty = openpty(None, None).unwrap(); ++ assert!(pty.master > 0); ++ assert!(pty.slave > 0); ++ ++ // Writing to one should be readable on the other one ++ let string = "foofoofoo\n"; ++ let mut buf = [0u8; 10]; ++ write(pty.master, string.as_bytes()).unwrap(); ++ ::read_exact(pty.slave, &mut buf); ++ ++ assert_eq!(&buf, string.as_bytes()); ++ ++ // Read the echo as well ++ let echoed_string = "foofoofoo\r\n"; ++ let mut buf = [0u8; 11]; ++ ::read_exact(pty.master, &mut buf); ++ assert_eq!(&buf, echoed_string.as_bytes()); ++ ++ let string2 = "barbarbarbar\n"; ++ let echoed_string2 = "barbarbarbar\r\n"; ++ let mut buf = [0u8; 14]; ++ write(pty.slave, string2.as_bytes()).unwrap(); ++ ::read_exact(pty.master, &mut buf); ++ ++ assert_eq!(&buf, echoed_string2.as_bytes()); ++ ++ close(pty.master).unwrap(); ++ close(pty.slave).unwrap(); ++} ++ ++#[test] ++fn test_openpty_with_termios() { ++ // openpty uses ptname(3) internally ++ let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); ++ ++ // Open one pty to get attributes for the second one ++ let mut termios = { ++ let pty = openpty(None, None).unwrap(); ++ assert!(pty.master > 0); ++ assert!(pty.slave > 0); ++ let termios = tcgetattr(pty.master).unwrap(); ++ close(pty.master).unwrap(); ++ close(pty.slave).unwrap(); ++ termios ++ }; ++ // Make sure newlines are not transformed so the data is preserved when sent. ++ termios.output_flags.remove(OutputFlags::ONLCR); ++ ++ let pty = openpty(None, &termios).unwrap(); ++ // Must be valid file descriptors ++ assert!(pty.master > 0); ++ assert!(pty.slave > 0); ++ ++ // Writing to one should be readable on the other one ++ let string = "foofoofoo\n"; ++ let mut buf = [0u8; 10]; ++ write(pty.master, string.as_bytes()).unwrap(); ++ ::read_exact(pty.slave, &mut buf); ++ ++ assert_eq!(&buf, string.as_bytes()); ++ ++ // read the echo as well ++ let echoed_string = "foofoofoo\n"; ++ ::read_exact(pty.master, &mut buf); ++ assert_eq!(&buf, echoed_string.as_bytes()); ++ ++ let string2 = "barbarbarbar\n"; ++ let echoed_string2 = "barbarbarbar\n"; ++ let mut buf = [0u8; 13]; ++ write(pty.slave, string2.as_bytes()).unwrap(); ++ ::read_exact(pty.master, &mut buf); ++ ++ assert_eq!(&buf, echoed_string2.as_bytes()); ++ ++ close(pty.master).unwrap(); ++ close(pty.slave).unwrap(); ++} ++ ++#[test] ++fn test_forkpty() { ++ use nix::unistd::ForkResult::*; ++ use nix::sys::signal::*; ++ use nix::sys::wait::wait; ++ // forkpty calls openpty which uses ptname(3) internally. ++ let _m0 = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); ++ // forkpty spawns a child process ++ let _m1 = ::FORK_MTX.lock().expect("Mutex got poisoned by another test"); ++ ++ let string = "naninani\n"; ++ let echoed_string = "naninani\r\n"; ++ let pty = forkpty(None, None).unwrap(); ++ match pty.fork_result { ++ Child => { ++ write(STDOUT_FILENO, string.as_bytes()).unwrap(); ++ pause(); // we need the child to stay alive until the parent calls read ++ unsafe { _exit(0); } ++ }, ++ Parent { child } => { ++ let mut buf = [0u8; 10]; ++ assert!(child.as_raw() > 0); ++ ::read_exact(pty.master, &mut buf); ++ kill(child, SIGTERM).unwrap(); ++ wait().unwrap(); // keep other tests using generic wait from getting our child ++ assert_eq!(&buf, echoed_string.as_bytes()); ++ close(pty.master).unwrap(); ++ }, ++ } ++} +diff --git a/third_party/rust/nix-0.15.0/test/test_ptymaster_drop.rs b/third_party/rust/nix-0.15.0/test/test_ptymaster_drop.rs +new file mode 100644 +index 0000000000000..9b59d66435ed0 +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/test/test_ptymaster_drop.rs +@@ -0,0 +1,21 @@ ++extern crate nix; ++ ++use nix::fcntl::OFlag; ++use nix::pty::*; ++use nix::unistd::close; ++use std::os::unix::io::AsRawFd; ++ ++/// Regression test for Issue #659 ++/// `PtyMaster` should panic rather than double close the file descriptor ++/// This must run in its own test process because it deliberately creates a race ++/// condition. ++#[test] ++#[should_panic(expected = "Closing an invalid file descriptor!")] ++// In Travis on i686-unknown-linux-musl, this test gets SIGABRT. I don't know ++// why. It doesn't happen on any other target, and it doesn't happen on my PC. ++#[cfg_attr(all(target_env = "musl", target_arch = "x86"), ignore)] ++fn test_double_close() { ++ let m = posix_openpt(OFlag::O_RDWR).unwrap(); ++ close(m.as_raw_fd()).unwrap(); ++ drop(m); // should panic here ++} +diff --git a/third_party/rust/nix-0.15.0/test/test_sendfile.rs b/third_party/rust/nix-0.15.0/test/test_sendfile.rs +new file mode 100644 +index 0000000000000..3bc7932f4c84f +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/test/test_sendfile.rs +@@ -0,0 +1,129 @@ ++use std::io::prelude::*; ++use std::os::unix::prelude::*; ++ ++use libc::off_t; ++use nix::sys::sendfile::*; ++use tempfile::tempfile; ++ ++cfg_if! { ++ if #[cfg(any(target_os = "android", target_os = "linux"))] { ++ use nix::unistd::{close, pipe, read}; ++ } else if #[cfg(any(target_os = "freebsd", target_os = "ios", target_os = "macos"))] { ++ use std::net::Shutdown; ++ use std::os::unix::net::UnixStream; ++ } ++} ++ ++#[cfg(any(target_os = "android", target_os = "linux"))] ++#[test] ++fn test_sendfile_linux() { ++ const CONTENTS: &[u8] = b"abcdef123456"; ++ let mut tmp = tempfile().unwrap(); ++ tmp.write_all(CONTENTS).unwrap(); ++ ++ let (rd, wr) = pipe().unwrap(); ++ let mut offset: off_t = 5; ++ let res = sendfile(wr, tmp.as_raw_fd(), Some(&mut offset), 2).unwrap(); ++ ++ assert_eq!(2, res); ++ ++ let mut buf = [0u8; 1024]; ++ assert_eq!(2, read(rd, &mut buf).unwrap()); ++ assert_eq!(b"f1", &buf[0..2]); ++ assert_eq!(7, offset); ++ ++ close(rd).unwrap(); ++ close(wr).unwrap(); ++} ++ ++#[cfg(target_os = "freebsd")] ++#[test] ++fn test_sendfile_freebsd() { ++ // Declare the content ++ let header_strings = vec!["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"]; ++ let body = "Xabcdef123456"; ++ let body_offset = 1; ++ let trailer_strings = vec!["\n", "Served by Make Believe\n"]; ++ ++ // Write the body to a file ++ let mut tmp = tempfile().unwrap(); ++ tmp.write_all(body.as_bytes()).unwrap(); ++ ++ // Prepare headers and trailers for sendfile ++ let headers: Vec<&[u8]> = header_strings.iter().map(|s| s.as_bytes()).collect(); ++ let trailers: Vec<&[u8]> = trailer_strings.iter().map(|s| s.as_bytes()).collect(); ++ ++ // Prepare socket pair ++ let (mut rd, wr) = UnixStream::pair().unwrap(); ++ ++ // Call the test method ++ let (res, bytes_written) = sendfile( ++ tmp.as_raw_fd(), ++ wr.as_raw_fd(), ++ body_offset as off_t, ++ None, ++ Some(headers.as_slice()), ++ Some(trailers.as_slice()), ++ SfFlags::empty(), ++ 0, ++ ); ++ assert!(res.is_ok()); ++ wr.shutdown(Shutdown::Both).unwrap(); ++ ++ // Prepare the expected result ++ let expected_string = ++ header_strings.concat() + &body[body_offset..] + &trailer_strings.concat(); ++ ++ // Verify the message that was sent ++ assert_eq!(bytes_written as usize, expected_string.as_bytes().len()); ++ ++ let mut read_string = String::new(); ++ let bytes_read = rd.read_to_string(&mut read_string).unwrap(); ++ assert_eq!(bytes_written as usize, bytes_read); ++ assert_eq!(expected_string, read_string); ++} ++ ++#[cfg(any(target_os = "ios", target_os = "macos"))] ++#[test] ++fn test_sendfile_darwin() { ++ // Declare the content ++ let header_strings = vec!["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"]; ++ let body = "Xabcdef123456"; ++ let body_offset = 1; ++ let trailer_strings = vec!["\n", "Served by Make Believe\n"]; ++ ++ // Write the body to a file ++ let mut tmp = tempfile().unwrap(); ++ tmp.write_all(body.as_bytes()).unwrap(); ++ ++ // Prepare headers and trailers for sendfile ++ let headers: Vec<&[u8]> = header_strings.iter().map(|s| s.as_bytes()).collect(); ++ let trailers: Vec<&[u8]> = trailer_strings.iter().map(|s| s.as_bytes()).collect(); ++ ++ // Prepare socket pair ++ let (mut rd, wr) = UnixStream::pair().unwrap(); ++ ++ // Call the test method ++ let (res, bytes_written) = sendfile( ++ tmp.as_raw_fd(), ++ wr.as_raw_fd(), ++ body_offset as off_t, ++ None, ++ Some(headers.as_slice()), ++ Some(trailers.as_slice()), ++ ); ++ assert!(res.is_ok()); ++ wr.shutdown(Shutdown::Both).unwrap(); ++ ++ // Prepare the expected result ++ let expected_string = ++ header_strings.concat() + &body[body_offset..] + &trailer_strings.concat(); ++ ++ // Verify the message that was sent ++ assert_eq!(bytes_written as usize, expected_string.as_bytes().len()); ++ ++ let mut read_string = String::new(); ++ let bytes_read = rd.read_to_string(&mut read_string).unwrap(); ++ assert_eq!(bytes_written as usize, bytes_read); ++ assert_eq!(expected_string, read_string); ++} +diff --git a/third_party/rust/nix-0.15.0/test/test_stat.rs b/third_party/rust/nix-0.15.0/test/test_stat.rs +new file mode 100644 +index 0000000000000..1173455fae8db +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/test/test_stat.rs +@@ -0,0 +1,296 @@ ++use std::fs::{self, File}; ++use std::os::unix::fs::{symlink, PermissionsExt}; ++use std::os::unix::prelude::AsRawFd; ++use std::time::{Duration, UNIX_EPOCH}; ++use std::path::Path; ++ ++#[cfg(not(any(target_os = "netbsd")))] ++use libc::{S_IFMT, S_IFLNK, mode_t}; ++ ++use nix::{fcntl, Error}; ++use nix::errno::{Errno}; ++use nix::sys::stat::{self, fchmod, fchmodat, futimens, stat, utimes, utimensat, mkdirat}; ++#[cfg(any(target_os = "linux", ++ target_os = "haiku", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "freebsd", ++ target_os = "netbsd"))] ++use nix::sys::stat::lutimes; ++use nix::sys::stat::{Mode, FchmodatFlags, UtimensatFlags}; ++ ++#[cfg(not(any(target_os = "netbsd")))] ++use nix::sys::stat::FileStat; ++ ++use nix::sys::time::{TimeSpec, TimeVal, TimeValLike}; ++use nix::unistd::chdir; ++ ++#[cfg(not(any(target_os = "netbsd")))] ++use nix::Result; ++use tempfile; ++ ++#[allow(unused_comparisons)] ++// uid and gid are signed on Windows, but not on other platforms. This function ++// allows warning free compiles on all platforms, and can be removed when ++// expression-level #[allow] is available. ++#[cfg(not(any(target_os = "netbsd")))] ++fn valid_uid_gid(stat: FileStat) -> bool { ++ // uid could be 0 for the `root` user. This quite possible when ++ // the tests are being run on a rooted Android device. ++ stat.st_uid >= 0 && stat.st_gid >= 0 ++} ++ ++#[cfg(not(any(target_os = "netbsd")))] ++fn assert_stat_results(stat_result: Result<FileStat>) { ++ let stats = stat_result.expect("stat call failed"); ++ assert!(stats.st_dev > 0); // must be positive integer, exact number machine dependent ++ assert!(stats.st_ino > 0); // inode is positive integer, exact number machine dependent ++ assert!(stats.st_mode > 0); // must be positive integer ++ assert!(stats.st_nlink == 1); // there links created, must be 1 ++ assert!(valid_uid_gid(stats)); // must be positive integers ++ assert!(stats.st_size == 0); // size is 0 because we did not write anything to the file ++ assert!(stats.st_blksize > 0); // must be positive integer, exact number machine dependent ++ assert!(stats.st_blocks <= 16); // Up to 16 blocks can be allocated for a blank file ++} ++ ++#[cfg(not(any(target_os = "netbsd")))] ++fn assert_lstat_results(stat_result: Result<FileStat>) { ++ let stats = stat_result.expect("stat call failed"); ++ assert!(stats.st_dev > 0); // must be positive integer, exact number machine dependent ++ assert!(stats.st_ino > 0); // inode is positive integer, exact number machine dependent ++ assert!(stats.st_mode > 0); // must be positive integer ++ ++ // st_mode is c_uint (u32 on Android) while S_IFMT is mode_t ++ // (u16 on Android), and that will be a compile error. ++ // On other platforms they are the same (either both are u16 or u32). ++ assert!((stats.st_mode as usize) & (S_IFMT as usize) == S_IFLNK as usize); // should be a link ++ assert!(stats.st_nlink == 1); // there links created, must be 1 ++ assert!(valid_uid_gid(stats)); // must be positive integers ++ assert!(stats.st_size > 0); // size is > 0 because it points to another file ++ assert!(stats.st_blksize > 0); // must be positive integer, exact number machine dependent ++ ++ // st_blocks depends on whether the machine's file system uses fast ++ // or slow symlinks, so just make sure it's not negative ++ // (Android's st_blocks is ulonglong which is always non-negative.) ++ assert!(stats.st_blocks >= 0); ++} ++ ++#[test] ++#[cfg(not(any(target_os = "netbsd")))] ++fn test_stat_and_fstat() { ++ use nix::sys::stat::fstat; ++ ++ let tempdir = tempfile::tempdir().unwrap(); ++ let filename = tempdir.path().join("foo.txt"); ++ let file = File::create(&filename).unwrap(); ++ ++ let stat_result = stat(&filename); ++ assert_stat_results(stat_result); ++ ++ let fstat_result = fstat(file.as_raw_fd()); ++ assert_stat_results(fstat_result); ++} ++ ++#[test] ++#[cfg(not(any(target_os = "netbsd")))] ++fn test_fstatat() { ++ let tempdir = tempfile::tempdir().unwrap(); ++ let filename = tempdir.path().join("foo.txt"); ++ File::create(&filename).unwrap(); ++ let dirfd = fcntl::open(tempdir.path(), ++ fcntl::OFlag::empty(), ++ stat::Mode::empty()); ++ ++ let result = stat::fstatat(dirfd.unwrap(), ++ &filename, ++ fcntl::AtFlags::empty()); ++ assert_stat_results(result); ++} ++ ++#[test] ++#[cfg(not(any(target_os = "netbsd")))] ++fn test_stat_fstat_lstat() { ++ use nix::sys::stat::{fstat, lstat}; ++ ++ let tempdir = tempfile::tempdir().unwrap(); ++ let filename = tempdir.path().join("bar.txt"); ++ let linkname = tempdir.path().join("barlink"); ++ ++ File::create(&filename).unwrap(); ++ symlink("bar.txt", &linkname).unwrap(); ++ let link = File::open(&linkname).unwrap(); ++ ++ // should be the same result as calling stat, ++ // since it's a regular file ++ let stat_result = stat(&filename); ++ assert_stat_results(stat_result); ++ ++ let lstat_result = lstat(&linkname); ++ assert_lstat_results(lstat_result); ++ ++ let fstat_result = fstat(link.as_raw_fd()); ++ assert_stat_results(fstat_result); ++} ++ ++#[test] ++fn test_fchmod() { ++ let tempdir = tempfile::tempdir().unwrap(); ++ let filename = tempdir.path().join("foo.txt"); ++ let file = File::create(&filename).unwrap(); ++ ++ let mut mode1 = Mode::empty(); ++ mode1.insert(Mode::S_IRUSR); ++ mode1.insert(Mode::S_IWUSR); ++ fchmod(file.as_raw_fd(), mode1).unwrap(); ++ ++ let file_stat1 = stat(&filename).unwrap(); ++ assert_eq!(file_stat1.st_mode & 0o7777, mode1.bits()); ++ ++ let mut mode2 = Mode::empty(); ++ mode2.insert(Mode::S_IROTH); ++ fchmod(file.as_raw_fd(), mode2).unwrap(); ++ ++ let file_stat2 = stat(&filename).unwrap(); ++ assert_eq!(file_stat2.st_mode & 0o7777, mode2.bits()); ++} ++ ++#[test] ++fn test_fchmodat() { ++ let _dr = ::DirRestore::new(); ++ let tempdir = tempfile::tempdir().unwrap(); ++ let filename = "foo.txt"; ++ let fullpath = tempdir.path().join(filename); ++ File::create(&fullpath).unwrap(); ++ ++ let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap(); ++ ++ let mut mode1 = Mode::empty(); ++ mode1.insert(Mode::S_IRUSR); ++ mode1.insert(Mode::S_IWUSR); ++ fchmodat(Some(dirfd), filename, mode1, FchmodatFlags::FollowSymlink).unwrap(); ++ ++ let file_stat1 = stat(&fullpath).unwrap(); ++ assert_eq!(file_stat1.st_mode & 0o7777, mode1.bits()); ++ ++ chdir(tempdir.path()).unwrap(); ++ ++ let mut mode2 = Mode::empty(); ++ mode2.insert(Mode::S_IROTH); ++ fchmodat(None, filename, mode2, FchmodatFlags::FollowSymlink).unwrap(); ++ ++ let file_stat2 = stat(&fullpath).unwrap(); ++ assert_eq!(file_stat2.st_mode & 0o7777, mode2.bits()); ++} ++ ++/// Asserts that the atime and mtime in a file's metadata match expected values. ++/// ++/// The atime and mtime are expressed with a resolution of seconds because some file systems ++/// (like macOS's HFS+) do not have higher granularity. ++fn assert_times_eq(exp_atime_sec: u64, exp_mtime_sec: u64, attr: &fs::Metadata) { ++ assert_eq!( ++ Duration::new(exp_atime_sec, 0), ++ attr.accessed().unwrap().duration_since(UNIX_EPOCH).unwrap()); ++ assert_eq!( ++ Duration::new(exp_mtime_sec, 0), ++ attr.modified().unwrap().duration_since(UNIX_EPOCH).unwrap()); ++} ++ ++#[test] ++fn test_utimes() { ++ let tempdir = tempfile::tempdir().unwrap(); ++ let fullpath = tempdir.path().join("file"); ++ drop(File::create(&fullpath).unwrap()); ++ ++ utimes(&fullpath, &TimeVal::seconds(9990), &TimeVal::seconds(5550)).unwrap(); ++ assert_times_eq(9990, 5550, &fs::metadata(&fullpath).unwrap()); ++} ++ ++#[test] ++#[cfg(any(target_os = "linux", ++ target_os = "haiku", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "freebsd", ++ target_os = "netbsd"))] ++fn test_lutimes() { ++ let tempdir = tempfile::tempdir().unwrap(); ++ let target = tempdir.path().join("target"); ++ let fullpath = tempdir.path().join("symlink"); ++ drop(File::create(&target).unwrap()); ++ symlink(&target, &fullpath).unwrap(); ++ ++ let exp_target_metadata = fs::symlink_metadata(&target).unwrap(); ++ lutimes(&fullpath, &TimeVal::seconds(4560), &TimeVal::seconds(1230)).unwrap(); ++ assert_times_eq(4560, 1230, &fs::symlink_metadata(&fullpath).unwrap()); ++ ++ let target_metadata = fs::symlink_metadata(&target).unwrap(); ++ assert_eq!(exp_target_metadata.accessed().unwrap(), target_metadata.accessed().unwrap(), ++ "atime of symlink target was unexpectedly modified"); ++ assert_eq!(exp_target_metadata.modified().unwrap(), target_metadata.modified().unwrap(), ++ "mtime of symlink target was unexpectedly modified"); ++} ++ ++#[test] ++fn test_futimens() { ++ let tempdir = tempfile::tempdir().unwrap(); ++ let fullpath = tempdir.path().join("file"); ++ drop(File::create(&fullpath).unwrap()); ++ ++ let fd = fcntl::open(&fullpath, fcntl::OFlag::empty(), stat::Mode::empty()).unwrap(); ++ ++ futimens(fd, &TimeSpec::seconds(10), &TimeSpec::seconds(20)).unwrap(); ++ assert_times_eq(10, 20, &fs::metadata(&fullpath).unwrap()); ++} ++ ++#[test] ++fn test_utimensat() { ++ let _dr = ::DirRestore::new(); ++ let tempdir = tempfile::tempdir().unwrap(); ++ let filename = "foo.txt"; ++ let fullpath = tempdir.path().join(filename); ++ drop(File::create(&fullpath).unwrap()); ++ ++ let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap(); ++ ++ utimensat(Some(dirfd), filename, &TimeSpec::seconds(12345), &TimeSpec::seconds(678), ++ UtimensatFlags::FollowSymlink).unwrap(); ++ assert_times_eq(12345, 678, &fs::metadata(&fullpath).unwrap()); ++ ++ chdir(tempdir.path()).unwrap(); ++ ++ utimensat(None, filename, &TimeSpec::seconds(500), &TimeSpec::seconds(800), ++ UtimensatFlags::FollowSymlink).unwrap(); ++ assert_times_eq(500, 800, &fs::metadata(&fullpath).unwrap()); ++} ++ ++#[test] ++fn test_mkdirat_success_path() { ++ let tempdir = tempfile::tempdir().unwrap(); ++ let filename = "example_subdir"; ++ let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap(); ++ assert!((mkdirat(dirfd, filename, Mode::S_IRWXU)).is_ok()); ++ assert!(Path::exists(&tempdir.path().join(filename))); ++} ++ ++#[test] ++fn test_mkdirat_success_mode() { ++ let expected_bits = stat::SFlag::S_IFDIR.bits() | stat::Mode::S_IRWXU.bits(); ++ let tempdir = tempfile::tempdir().unwrap(); ++ let filename = "example_subdir"; ++ let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap(); ++ assert!((mkdirat(dirfd, filename, Mode::S_IRWXU)).is_ok()); ++ let permissions = fs::metadata(tempdir.path().join(filename)).unwrap().permissions(); ++ let mode = permissions.mode(); ++ assert_eq!(mode as mode_t, expected_bits) ++} ++ ++#[test] ++fn test_mkdirat_fail() { ++ let tempdir = tempfile::tempdir().unwrap(); ++ let not_dir_filename= "example_not_dir"; ++ let filename = "example_subdir_dir"; ++ let dirfd = fcntl::open(&tempdir.path().join(not_dir_filename), fcntl::OFlag::O_CREAT, ++ stat::Mode::empty()).unwrap(); ++ let result = mkdirat(dirfd, filename, Mode::S_IRWXU).unwrap_err(); ++ assert_eq!(result, Error::Sys(Errno::ENOTDIR)); ++} +diff --git a/third_party/rust/nix-0.15.0/test/test_unistd.rs b/third_party/rust/nix-0.15.0/test/test_unistd.rs +new file mode 100644 +index 0000000000000..46196dec7ccce +--- /dev/null ++++ b/third_party/rust/nix-0.15.0/test/test_unistd.rs +@@ -0,0 +1,669 @@ ++use nix::fcntl::{self, fcntl, FcntlArg, FdFlag, open, OFlag, readlink}; ++use nix::unistd::*; ++use nix::unistd::ForkResult::*; ++use nix::sys::signal::{SaFlags, SigAction, SigHandler, SigSet, Signal, sigaction}; ++use nix::sys::wait::*; ++use nix::sys::stat::{self, Mode, SFlag}; ++use nix::errno::Errno; ++use nix::Error; ++use std::{env, iter}; ++use std::ffi::CString; ++use std::fs::{self, DirBuilder, File}; ++use std::io::Write; ++use std::os::unix::prelude::*; ++use tempfile::{self, tempfile}; ++use libc::{self, _exit, off_t}; ++ ++#[test] ++#[cfg(not(any(target_os = "netbsd")))] ++fn test_fork_and_waitpid() { ++ let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test"); ++ ++ // Safe: Child only calls `_exit`, which is signal-safe ++ match fork().expect("Error: Fork Failed") { ++ Child => unsafe { _exit(0) }, ++ Parent { child } => { ++ // assert that child was created and pid > 0 ++ let child_raw: ::libc::pid_t = child.into(); ++ assert!(child_raw > 0); ++ let wait_status = waitpid(child, None); ++ match wait_status { ++ // assert that waitpid returned correct status and the pid is the one of the child ++ Ok(WaitStatus::Exited(pid_t, _)) => assert!(pid_t == child), ++ ++ // panic, must never happen ++ s @ Ok(_) => panic!("Child exited {:?}, should never happen", s), ++ ++ // panic, waitpid should never fail ++ Err(s) => panic!("Error: waitpid returned Err({:?}", s) ++ } ++ ++ }, ++ } ++} ++ ++#[test] ++fn test_wait() { ++ // Grab FORK_MTX so wait doesn't reap a different test's child process ++ let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test"); ++ ++ // Safe: Child only calls `_exit`, which is signal-safe ++ match fork().expect("Error: Fork Failed") { ++ Child => unsafe { _exit(0) }, ++ Parent { child } => { ++ let wait_status = wait(); ++ ++ // just assert that (any) one child returns with WaitStatus::Exited ++ assert_eq!(wait_status, Ok(WaitStatus::Exited(child, 0))); ++ }, ++ } ++} ++ ++#[test] ++fn test_mkstemp() { ++ let mut path = env::temp_dir(); ++ path.push("nix_tempfile.XXXXXX"); ++ ++ let result = mkstemp(&path); ++ match result { ++ Ok((fd, path)) => { ++ close(fd).unwrap(); ++ unlink(path.as_path()).unwrap(); ++ }, ++ Err(e) => panic!("mkstemp failed: {}", e) ++ } ++} ++ ++#[test] ++fn test_mkstemp_directory() { ++ // mkstemp should fail if a directory is given ++ assert!(mkstemp(&env::temp_dir()).is_err()); ++} ++ ++#[test] ++fn test_mkfifo() { ++ let tempdir = tempfile::tempdir().unwrap(); ++ let mkfifo_fifo = tempdir.path().join("mkfifo_fifo"); ++ ++ mkfifo(&mkfifo_fifo, Mode::S_IRUSR).unwrap(); ++ ++ let stats = stat::stat(&mkfifo_fifo).unwrap(); ++ let typ = stat::SFlag::from_bits_truncate(stats.st_mode); ++ assert!(typ == SFlag::S_IFIFO); ++} ++ ++#[test] ++fn test_mkfifo_directory() { ++ // mkfifo should fail if a directory is given ++ assert!(mkfifo(&env::temp_dir(), Mode::S_IRUSR).is_err()); ++} ++ ++#[test] ++fn test_getpid() { ++ let pid: ::libc::pid_t = getpid().into(); ++ let ppid: ::libc::pid_t = getppid().into(); ++ assert!(pid > 0); ++ assert!(ppid > 0); ++} ++ ++#[test] ++fn test_getsid() { ++ let none_sid: ::libc::pid_t = getsid(None).unwrap().into(); ++ let pid_sid: ::libc::pid_t = getsid(Some(getpid())).unwrap().into(); ++ assert!(none_sid > 0); ++ assert!(none_sid == pid_sid); ++} ++ ++#[cfg(any(target_os = "linux", target_os = "android"))] ++mod linux_android { ++ use nix::unistd::gettid; ++ ++ #[test] ++ fn test_gettid() { ++ let tid: ::libc::pid_t = gettid().into(); ++ assert!(tid > 0); ++ } ++} ++ ++#[test] ++// `getgroups()` and `setgroups()` do not behave as expected on Apple platforms ++#[cfg(not(any(target_os = "ios", target_os = "macos")))] ++fn test_setgroups() { ++ // Skip this test when not run as root as `setgroups()` requires root. ++ skip_if_not_root!("test_setgroups"); ++ ++ let _m = ::GROUPS_MTX.lock().expect("Mutex got poisoned by another test"); ++ ++ // Save the existing groups ++ let old_groups = getgroups().unwrap(); ++ ++ // Set some new made up groups ++ let groups = [Gid::from_raw(123), Gid::from_raw(456)]; ++ setgroups(&groups).unwrap(); ++ ++ let new_groups = getgroups().unwrap(); ++ assert_eq!(new_groups, groups); ++ ++ // Revert back to the old groups ++ setgroups(&old_groups).unwrap(); ++} ++ ++#[test] ++// `getgroups()` and `setgroups()` do not behave as expected on Apple platforms ++#[cfg(not(any(target_os = "ios", target_os = "macos")))] ++fn test_initgroups() { ++ // Skip this test when not run as root as `initgroups()` and `setgroups()` ++ // require root. ++ skip_if_not_root!("test_initgroups"); ++ ++ let _m = ::GROUPS_MTX.lock().expect("Mutex got poisoned by another test"); ++ ++ // Save the existing groups ++ let old_groups = getgroups().unwrap(); ++ ++ // It doesn't matter if the root user is not called "root" or if a user ++ // called "root" doesn't exist. We are just checking that the extra, ++ // made-up group, `123`, is set. ++ // FIXME: Test the other half of initgroups' functionality: whether the ++ // groups that the user belongs to are also set. ++ let user = CString::new("root").unwrap(); ++ let group = Gid::from_raw(123); ++ let group_list = getgrouplist(&user, group).unwrap(); ++ assert!(group_list.contains(&group)); ++ ++ initgroups(&user, group).unwrap(); ++ ++ let new_groups = getgroups().unwrap(); ++ assert_eq!(new_groups, group_list); ++ ++ // Revert back to the old groups ++ setgroups(&old_groups).unwrap(); ++} ++ ++macro_rules! execve_test_factory( ++ ($test_name:ident, $syscall:ident, $exe: expr $(, $pathname:expr, $flags:expr)*) => ( ++ #[test] ++ fn $test_name() { ++ let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test"); ++ // The `exec`d process will write to `writer`, and we'll read that ++ // data from `reader`. ++ let (reader, writer) = pipe().unwrap(); ++ ++ // Safe: Child calls `exit`, `dup`, `close` and the provided `exec*` family function. ++ // NOTE: Technically, this makes the macro unsafe to use because you could pass anything. ++ // The tests make sure not to do that, though. ++ match fork().unwrap() { ++ Child => { ++ // Close stdout. ++ close(1).unwrap(); ++ // Make `writer` be the stdout of the new process. ++ dup(writer).unwrap(); ++ // exec! ++ $syscall( ++ $exe, ++ $(&CString::new($pathname).unwrap(), )* ++ &[CString::new(b"".as_ref()).unwrap(), ++ CString::new(b"-c".as_ref()).unwrap(), ++ CString::new(b"echo nix!!! && echo foo=$foo && echo baz=$baz" ++ .as_ref()).unwrap()], ++ &[CString::new(b"foo=bar".as_ref()).unwrap(), ++ CString::new(b"baz=quux".as_ref()).unwrap()] ++ $(, $flags)*).unwrap(); ++ }, ++ Parent { child } => { ++ // Wait for the child to exit. ++ waitpid(child, None).unwrap(); ++ // Read 1024 bytes. ++ let mut buf = [0u8; 1024]; ++ read(reader, &mut buf).unwrap(); ++ // It should contain the things we printed using `/bin/sh`. ++ let string = String::from_utf8_lossy(&buf); ++ assert!(string.contains("nix!!!")); ++ assert!(string.contains("foo=bar")); ++ assert!(string.contains("baz=quux")); ++ } ++ } ++ } ++ ) ++); ++ ++cfg_if!{ ++ if #[cfg(target_os = "android")] { ++ execve_test_factory!(test_execve, execve, &CString::new("/system/bin/sh").unwrap()); ++ execve_test_factory!(test_fexecve, fexecve, File::open("/system/bin/sh").unwrap().into_raw_fd()); ++ } else if #[cfg(any(target_os = "freebsd", ++ target_os = "linux"))] { ++ execve_test_factory!(test_execve, execve, &CString::new("/bin/sh").unwrap()); ++ execve_test_factory!(test_fexecve, fexecve, File::open("/bin/sh").unwrap().into_raw_fd()); ++ } else if #[cfg(any(target_os = "dragonfly", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "openbsd"))] { ++ execve_test_factory!(test_execve, execve, &CString::new("/bin/sh").unwrap()); ++ // No fexecve() on DragonFly, ios, macos, NetBSD, OpenBSD. ++ // ++ // Note for NetBSD and OpenBSD: although rust-lang/libc includes it ++ // (under unix/bsd/netbsdlike/) fexecve is not currently implemented on ++ // NetBSD nor on OpenBSD. ++ } ++} ++ ++#[cfg(any(target_os = "haiku", target_os = "linux", target_os = "openbsd"))] ++execve_test_factory!(test_execvpe, execvpe, &CString::new("sh").unwrap()); ++ ++cfg_if!{ ++ if #[cfg(target_os = "android")] { ++ use nix::fcntl::AtFlags; ++ execve_test_factory!(test_execveat_empty, execveat, File::open("/system/bin/sh").unwrap().into_raw_fd(), ++ "", AtFlags::AT_EMPTY_PATH); ++ execve_test_factory!(test_execveat_relative, execveat, File::open("/system/bin/").unwrap().into_raw_fd(), ++ "./sh", AtFlags::empty()); ++ execve_test_factory!(test_execveat_absolute, execveat, File::open("/").unwrap().into_raw_fd(), ++ "/system/bin/sh", AtFlags::empty()); ++ } else if #[cfg(all(target_os = "linux"), any(target_arch ="x86_64", target_arch ="x86"))] { ++ use nix::fcntl::AtFlags; ++ execve_test_factory!(test_execveat_empty, execveat, File::open("/bin/sh").unwrap().into_raw_fd(), ++ "", AtFlags::AT_EMPTY_PATH); ++ execve_test_factory!(test_execveat_relative, execveat, File::open("/bin/").unwrap().into_raw_fd(), ++ "./sh", AtFlags::empty()); ++ execve_test_factory!(test_execveat_absolute, execveat, File::open("/").unwrap().into_raw_fd(), ++ "/bin/sh", AtFlags::empty()); ++ } ++} ++ ++#[test] ++fn test_fchdir() { ++ // fchdir changes the process's cwd ++ let _dr = ::DirRestore::new(); ++ ++ let tmpdir = tempfile::tempdir().unwrap(); ++ let tmpdir_path = tmpdir.path().canonicalize().unwrap(); ++ let tmpdir_fd = File::open(&tmpdir_path).unwrap().into_raw_fd(); ++ ++ assert!(fchdir(tmpdir_fd).is_ok()); ++ assert_eq!(getcwd().unwrap(), tmpdir_path); ++ ++ assert!(close(tmpdir_fd).is_ok()); ++} ++ ++#[test] ++fn test_getcwd() { ++ // chdir changes the process's cwd ++ let _dr = ::DirRestore::new(); ++ ++ let tmpdir = tempfile::tempdir().unwrap(); ++ let tmpdir_path = tmpdir.path().canonicalize().unwrap(); ++ assert!(chdir(&tmpdir_path).is_ok()); ++ assert_eq!(getcwd().unwrap(), tmpdir_path); ++ ++ // make path 500 chars longer so that buffer doubling in getcwd ++ // kicks in. Note: One path cannot be longer than 255 bytes ++ // (NAME_MAX) whole path cannot be longer than PATH_MAX (usually ++ // 4096 on linux, 1024 on macos) ++ let mut inner_tmp_dir = tmpdir_path.to_path_buf(); ++ for _ in 0..5 { ++ let newdir = iter::repeat("a").take(100).collect::<String>(); ++ inner_tmp_dir.push(newdir); ++ assert!(mkdir(inner_tmp_dir.as_path(), Mode::S_IRWXU).is_ok()); ++ } ++ assert!(chdir(inner_tmp_dir.as_path()).is_ok()); ++ assert_eq!(getcwd().unwrap(), inner_tmp_dir.as_path()); ++} ++ ++#[test] ++fn test_chown() { ++ // Testing for anything other than our own UID/GID is hard. ++ let uid = Some(getuid()); ++ let gid = Some(getgid()); ++ ++ let tempdir = tempfile::tempdir().unwrap(); ++ let path = tempdir.path().join("file"); ++ { ++ File::create(&path).unwrap(); ++ } ++ ++ chown(&path, uid, gid).unwrap(); ++ chown(&path, uid, None).unwrap(); ++ chown(&path, None, gid).unwrap(); ++ ++ fs::remove_file(&path).unwrap(); ++ chown(&path, uid, gid).unwrap_err(); ++} ++ ++#[test] ++fn test_fchownat() { ++ let _dr = ::DirRestore::new(); ++ // Testing for anything other than our own UID/GID is hard. ++ let uid = Some(getuid()); ++ let gid = Some(getgid()); ++ ++ let tempdir = tempfile::tempdir().unwrap(); ++ let path = tempdir.path().join("file"); ++ { ++ File::create(&path).unwrap(); ++ } ++ ++ let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); ++ ++ fchownat(Some(dirfd), "file", uid, gid, FchownatFlags::FollowSymlink).unwrap(); ++ ++ chdir(tempdir.path()).unwrap(); ++ fchownat(None, "file", uid, gid, FchownatFlags::FollowSymlink).unwrap(); ++ ++ fs::remove_file(&path).unwrap(); ++ fchownat(None, "file", uid, gid, FchownatFlags::FollowSymlink).unwrap_err(); ++} ++ ++#[test] ++fn test_lseek() { ++ const CONTENTS: &[u8] = b"abcdef123456"; ++ let mut tmp = tempfile().unwrap(); ++ tmp.write_all(CONTENTS).unwrap(); ++ let tmpfd = tmp.into_raw_fd(); ++ ++ let offset: off_t = 5; ++ lseek(tmpfd, offset, Whence::SeekSet).unwrap(); ++ ++ let mut buf = [0u8; 7]; ++ ::read_exact(tmpfd, &mut buf); ++ assert_eq!(b"f123456", &buf); ++ ++ close(tmpfd).unwrap(); ++} ++ ++#[cfg(any(target_os = "linux", target_os = "android"))] ++#[test] ++fn test_lseek64() { ++ const CONTENTS: &[u8] = b"abcdef123456"; ++ let mut tmp = tempfile().unwrap(); ++ tmp.write_all(CONTENTS).unwrap(); ++ let tmpfd = tmp.into_raw_fd(); ++ ++ lseek64(tmpfd, 5, Whence::SeekSet).unwrap(); ++ ++ let mut buf = [0u8; 7]; ++ ::read_exact(tmpfd, &mut buf); ++ assert_eq!(b"f123456", &buf); ++ ++ close(tmpfd).unwrap(); ++} ++ ++cfg_if!{ ++ if #[cfg(any(target_os = "android", target_os = "linux"))] { ++ macro_rules! require_acct{ ++ () => { ++ require_capability!(CAP_SYS_PACCT); ++ } ++ } ++ } else if #[cfg(target_os = "freebsd")] { ++ macro_rules! require_acct{ ++ () => { ++ skip_if_not_root!("test_acct"); ++ skip_if_jailed!("test_acct"); ++ } ++ } ++ } else { ++ macro_rules! require_acct{ ++ () => { ++ skip_if_not_root!("test_acct"); ++ } ++ } ++ } ++} ++ ++#[test] ++fn test_acct() { ++ use tempfile::NamedTempFile; ++ use std::process::Command; ++ use std::{thread, time}; ++ ++ let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test"); ++ require_acct!(); ++ ++ let file = NamedTempFile::new().unwrap(); ++ let path = file.path().to_str().unwrap(); ++ ++ acct::enable(path).unwrap(); ++ ++ loop { ++ Command::new("echo").arg("Hello world"); ++ let len = fs::metadata(path).unwrap().len(); ++ if len > 0 { break; } ++ thread::sleep(time::Duration::from_millis(10)); ++ } ++ acct::disable().unwrap(); ++} ++ ++#[test] ++fn test_fpathconf_limited() { ++ let f = tempfile().unwrap(); ++ // AFAIK, PATH_MAX is limited on all platforms, so it makes a good test ++ let path_max = fpathconf(f.as_raw_fd(), PathconfVar::PATH_MAX); ++ assert!(path_max.expect("fpathconf failed").expect("PATH_MAX is unlimited") > 0); ++} ++ ++#[test] ++fn test_pathconf_limited() { ++ // AFAIK, PATH_MAX is limited on all platforms, so it makes a good test ++ let path_max = pathconf("/", PathconfVar::PATH_MAX); ++ assert!(path_max.expect("pathconf failed").expect("PATH_MAX is unlimited") > 0); ++} ++ ++#[test] ++fn test_sysconf_limited() { ++ // AFAIK, OPEN_MAX is limited on all platforms, so it makes a good test ++ let open_max = sysconf(SysconfVar::OPEN_MAX); ++ assert!(open_max.expect("sysconf failed").expect("OPEN_MAX is unlimited") > 0); ++} ++ ++#[cfg(target_os = "freebsd")] ++#[test] ++fn test_sysconf_unsupported() { ++ // I know of no sysconf variables that are unsupported everywhere, but ++ // _XOPEN_CRYPT is unsupported on FreeBSD 11.0, which is one of the platforms ++ // we test. ++ let open_max = sysconf(SysconfVar::_XOPEN_CRYPT); ++ assert!(open_max.expect("sysconf failed").is_none()) ++} ++ ++// Test that we can create a pair of pipes. No need to verify that they pass ++// data; that's the domain of the OS, not nix. ++#[test] ++fn test_pipe() { ++ let (fd0, fd1) = pipe().unwrap(); ++ let m0 = stat::SFlag::from_bits_truncate(stat::fstat(fd0).unwrap().st_mode); ++ // S_IFIFO means it's a pipe ++ assert_eq!(m0, SFlag::S_IFIFO); ++ let m1 = stat::SFlag::from_bits_truncate(stat::fstat(fd1).unwrap().st_mode); ++ assert_eq!(m1, SFlag::S_IFIFO); ++} ++ ++// pipe2(2) is the same as pipe(2), except it allows setting some flags. Check ++// that we can set a flag. ++#[test] ++fn test_pipe2() { ++ let (fd0, fd1) = pipe2(OFlag::O_CLOEXEC).unwrap(); ++ let f0 = FdFlag::from_bits_truncate(fcntl(fd0, FcntlArg::F_GETFD).unwrap()); ++ assert!(f0.contains(FdFlag::FD_CLOEXEC)); ++ let f1 = FdFlag::from_bits_truncate(fcntl(fd1, FcntlArg::F_GETFD).unwrap()); ++ assert!(f1.contains(FdFlag::FD_CLOEXEC)); ++} ++ ++#[test] ++fn test_truncate() { ++ let tempdir = tempfile::tempdir().unwrap(); ++ let path = tempdir.path().join("file"); ++ ++ { ++ let mut tmp = File::create(&path).unwrap(); ++ const CONTENTS: &[u8] = b"12345678"; ++ tmp.write_all(CONTENTS).unwrap(); ++ } ++ ++ truncate(&path, 4).unwrap(); ++ ++ let metadata = fs::metadata(&path).unwrap(); ++ assert_eq!(4, metadata.len()); ++} ++ ++#[test] ++fn test_ftruncate() { ++ let tempdir = tempfile::tempdir().unwrap(); ++ let path = tempdir.path().join("file"); ++ ++ let tmpfd = { ++ let mut tmp = File::create(&path).unwrap(); ++ const CONTENTS: &[u8] = b"12345678"; ++ tmp.write_all(CONTENTS).unwrap(); ++ tmp.into_raw_fd() ++ }; ++ ++ ftruncate(tmpfd, 2).unwrap(); ++ close(tmpfd).unwrap(); ++ ++ let metadata = fs::metadata(&path).unwrap(); ++ assert_eq!(2, metadata.len()); ++} ++ ++// Used in `test_alarm`. ++static mut ALARM_CALLED: bool = false; ++ ++// Used in `test_alarm`. ++pub extern fn alarm_signal_handler(raw_signal: libc::c_int) { ++ assert_eq!(raw_signal, libc::SIGALRM, "unexpected signal: {}", raw_signal); ++ unsafe { ALARM_CALLED = true }; ++} ++ ++#[test] ++fn test_alarm() { ++ let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); ++ ++ let handler = SigHandler::Handler(alarm_signal_handler); ++ let signal_action = SigAction::new(handler, SaFlags::SA_RESTART, SigSet::empty()); ++ let old_handler = unsafe { ++ sigaction(Signal::SIGALRM, &signal_action) ++ .expect("unable to set signal handler for alarm") ++ }; ++ ++ // Set an alarm. ++ assert_eq!(alarm::set(60), None); ++ ++ // Overwriting an alarm should return the old alarm. ++ assert_eq!(alarm::set(1), Some(60)); ++ ++ // We should be woken up after 1 second by the alarm, so we'll sleep for 2 ++ // seconds to be sure. ++ sleep(2); ++ assert_eq!(unsafe { ALARM_CALLED }, true, "expected our alarm signal handler to be called"); ++ ++ // Reset the signal. ++ unsafe { ++ sigaction(Signal::SIGALRM, &old_handler) ++ .expect("unable to set signal handler for alarm"); ++ } ++} ++ ++#[test] ++fn test_canceling_alarm() { ++ let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); ++ ++ assert_eq!(alarm::cancel(), None); ++ ++ assert_eq!(alarm::set(60), None); ++ assert_eq!(alarm::cancel(), Some(60)); ++} ++ ++#[test] ++fn test_symlinkat() { ++ let mut buf = [0; 1024]; ++ let tempdir = tempfile::tempdir().unwrap(); ++ ++ let target = tempdir.path().join("a"); ++ let linkpath = tempdir.path().join("b"); ++ symlinkat(&target, None, &linkpath).unwrap(); ++ assert_eq!( ++ readlink(&linkpath, &mut buf).unwrap().to_str().unwrap(), ++ target.to_str().unwrap() ++ ); ++ ++ let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); ++ let target = "c"; ++ let linkpath = "d"; ++ symlinkat(target, Some(dirfd), linkpath).unwrap(); ++ assert_eq!( ++ readlink(&tempdir.path().join(linkpath), &mut buf) ++ .unwrap() ++ .to_str() ++ .unwrap(), ++ target ++ ); ++} ++ ++ ++#[test] ++fn test_unlinkat_dir_noremovedir() { ++ let tempdir = tempfile::tempdir().unwrap(); ++ let dirname = "foo_dir"; ++ let dirpath = tempdir.path().join(dirname); ++ ++ // Create dir ++ DirBuilder::new().recursive(true).create(&dirpath).unwrap(); ++ ++ // Get file descriptor for base directory ++ let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap(); ++ ++ // Attempt unlink dir at relative path without proper flag ++ let err_result = unlinkat(Some(dirfd), dirname, UnlinkatFlags::NoRemoveDir).unwrap_err(); ++ assert!(err_result == Error::Sys(Errno::EISDIR) || err_result == Error::Sys(Errno::EPERM)); ++ } ++ ++#[test] ++fn test_unlinkat_dir_removedir() { ++ let tempdir = tempfile::tempdir().unwrap(); ++ let dirname = "foo_dir"; ++ let dirpath = tempdir.path().join(dirname); ++ ++ // Create dir ++ DirBuilder::new().recursive(true).create(&dirpath).unwrap(); ++ ++ // Get file descriptor for base directory ++ let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap(); ++ ++ // Attempt unlink dir at relative path with proper flag ++ unlinkat(Some(dirfd), dirname, UnlinkatFlags::RemoveDir).unwrap(); ++ assert!(!dirpath.exists()); ++ } ++ ++#[test] ++fn test_unlinkat_file() { ++ let tempdir = tempfile::tempdir().unwrap(); ++ let filename = "foo.txt"; ++ let filepath = tempdir.path().join(filename); ++ ++ // Create file ++ File::create(&filepath).unwrap(); ++ ++ // Get file descriptor for base directory ++ let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap(); ++ ++ // Attempt unlink file at relative path ++ unlinkat(Some(dirfd), filename, UnlinkatFlags::NoRemoveDir).unwrap(); ++ assert!(!filepath.exists()); ++ } ++ ++#[test] ++fn test_access_not_existing() { ++ let tempdir = tempfile::tempdir().unwrap(); ++ let dir = tempdir.path().join("does_not_exist.txt"); ++ assert_eq!(access(&dir, AccessFlags::F_OK).err().unwrap().as_errno().unwrap(), ++ Errno::ENOENT); ++} ++ ++#[test] ++fn test_access_file_exists() { ++ let tempdir = tempfile::tempdir().unwrap(); ++ let path = tempdir.path().join("does_exist.txt"); ++ let _file = File::create(path.clone()).unwrap(); ++ assert!(access(&path, AccessFlags::R_OK | AccessFlags::W_OK).is_ok()); ++} +diff --git a/third_party/rust/nix/.cargo-checksum.json b/third_party/rust/nix/.cargo-checksum.json +index e5f2bc789185a..85adbc1eae931 100644 +--- a/third_party/rust/nix/.cargo-checksum.json ++++ b/third_party/rust/nix/.cargo-checksum.json +@@ -1 +1 @@ +-{"files":{"CHANGELOG.md":"91af9fd5f2d9cdb9c8bb750e24b625742e95a6c74bcff419f3de70eb26578281","CONTRIBUTING.md":"a9101e3d1487170d691d5f062ff49a433c167582ac8984dd41a744be92652f74","CONVENTIONS.md":"e150ce43c1d188c392c1a3bf7f2e08e3cf84906705c7bef43f319037d29ea385","Cargo.toml":"af0cc0ae7ff4bf6c2e5b35fe062f54fe2d619f70ba67795f4f43a981420b5de0","LICENSE":"66e3ee1fa7f909ad3c612d556f2a0cdabcd809ad6e66f3b0605015ac64841b70","README.md":"80d71b9eaac7bf7f0d307372592ed1467f994291e6fad816a44f3c70e2887d0f","build.rs":"14c9c678c33f5894509da47f77d6a326b14aecb4190ce87a24cce98687ca63b2","src/dir.rs":"21e330cbe6594274335b94d9e9b6059f1fa8e53d2e5b5c697058c52ec6b3c5ff","src/errno.rs":"a009ccf18b45c0a4c9319c65b0dc5bc322d9ad43cfe462ec4661559f44162451","src/errno_dragonfly.c":"a857e47b114acb85fddcb252a610ab5734d225c26b7bedd7c35d7789d46c8526","src/fcntl.rs":"6ae2f7f01dd2568b82a4e57f86e02b1d63eec6c26111c5adb2ca5d78a2a99fe7","src/features.rs":"22ff626ff8287a07dd55bcfc63c9f518c19c56144e15f9b6f9e3bbdcda51c2a8","src/ifaddrs.rs":"9a93de176edcca4613e668b8ccc2c3e3b6b711aa2d8d94ccb0ba08694d1ef35f","src/kmod.rs":"4d8a695d3d761f351a39d654303a1bd168e74295b7d142b918737e355b24f34d","src/lib.rs":"fdd8049a79ffb92384c72f0a6b0bab717001ddfa9b01f2b33413c83f424f2ac8","src/macros.rs":"aec27fa0fd98900913fada926c9a4581cd28f2640e3a7b5480707f923c9200f8","src/mount.rs":"cdf5db8409017483132db9d7493b5d6cc96df5560d0fa5ad8f385aff72db10ca","src/mqueue.rs":"82af42b31381af73e7966f845d1ed93957f0b9976bf2da524b178fad15b2b08d","src/net/if_.rs":"f7e02076fcf3cadf3fdf141884c9bd2c468a7047ba60bc490f0057df802b53ce","src/net/mod.rs":"577f70170e53d4a6de1abb70bf8f1031ec3e65c0e63ef5fcf05c907125e7ac17","src/poll.rs":"7305e250066cd1a7318cd239ed3db787937ee98426fe9289cf00fa874d76b6c7","src/pty.rs":"6b965b586579933af47d4efef4c82c391b927037eaa08d8c83fc974ef17fc7c8","src/sched.rs":"f9b214fa60006b5450ffb3589a55ec59c3694bd49597c65c38ac813fcd96c7dd","src/sys/aio.rs":"a1ba629258b3ce1268e5fe8e5b41dce3581f77d415dc5e2455c1f82f26dd3085","src/sys/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) -> ×pec { +@@ -67,6 +97,12 @@ impl AsRef<timespec> for TimeSpec { + } + } + ++impl AsMut<timespec> for TimeSpec { ++ fn as_mut(&mut self) -> &mut timespec { ++ &mut self.0 ++ } ++} ++ + impl Ord for TimeSpec { + // The implementation of cmp is simplified by assuming that the struct is + // normalized. That is, tv_nsec must always be within [0, 1_000_000_000) +@@ -90,6 +126,7 @@ impl TimeValLike for TimeSpec { + fn seconds(seconds: i64) -> TimeSpec { + assert!(seconds >= TS_MIN_SECONDS && seconds <= TS_MAX_SECONDS, + "TimeSpec out of bounds; seconds={}", seconds); ++ #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 + TimeSpec(timespec {tv_sec: seconds as time_t, tv_nsec: 0 }) + } + +@@ -116,8 +153,9 @@ impl TimeValLike for TimeSpec { + let (secs, nanos) = div_mod_floor_64(nanoseconds, NANOS_PER_SEC); + assert!(secs >= TS_MIN_SECONDS && secs <= TS_MAX_SECONDS, + "TimeSpec out of bounds"); ++ #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 + TimeSpec(timespec {tv_sec: secs as time_t, +- tv_nsec: nanos as c_long }) ++ tv_nsec: nanos as timespec_tv_nsec_t }) + } + + fn num_seconds(&self) -> i64 { +@@ -144,19 +182,20 @@ impl TimeValLike for TimeSpec { + } + + impl TimeSpec { +- fn nanos_mod_sec(&self) -> c_long { ++ fn nanos_mod_sec(&self) -> timespec_tv_nsec_t { + if self.tv_sec() < 0 && self.tv_nsec() > 0 { +- self.tv_nsec() - NANOS_PER_SEC as c_long ++ self.tv_nsec() - NANOS_PER_SEC as timespec_tv_nsec_t + } else { + self.tv_nsec() + } + } + ++ #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 + pub fn tv_sec(&self) -> time_t { + self.0.tv_sec + } + +- pub fn tv_nsec(&self) -> c_long { ++ pub fn tv_nsec(&self) -> timespec_tv_nsec_t { + self.0.tv_nsec + } + } +@@ -191,7 +230,7 @@ impl ops::Mul<i32> for TimeSpec { + type Output = TimeSpec; + + fn mul(self, rhs: i32) -> TimeSpec { +- let usec = self.num_nanoseconds().checked_mul(rhs as i64) ++ let usec = self.num_nanoseconds().checked_mul(i64::from(rhs)) + .expect("TimeSpec multiply out of bounds"); + + TimeSpec::nanoseconds(usec) +@@ -202,7 +241,7 @@ impl ops::Div<i32> for TimeSpec { + type Output = TimeSpec; + + fn div(self, rhs: i32) -> TimeSpec { +- let usec = self.num_nanoseconds() / rhs as i64; ++ let usec = self.num_nanoseconds() / i64::from(rhs); + TimeSpec::nanoseconds(usec) + } + } +@@ -239,7 +278,7 @@ impl fmt::Display for TimeSpec { + + + +-#[repr(C)] ++#[repr(transparent)] + #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] + pub struct TimeVal(timeval); + +@@ -259,6 +298,12 @@ impl AsRef<timeval> for TimeVal { + } + } + ++impl AsMut<timeval> for TimeVal { ++ fn as_mut(&mut self) -> &mut timeval { ++ &mut self.0 ++ } ++} ++ + impl Ord for TimeVal { + // The implementation of cmp is simplified by assuming that the struct is + // normalized. That is, tv_usec must always be within [0, 1_000_000) +@@ -282,6 +327,7 @@ impl TimeValLike for TimeVal { + fn seconds(seconds: i64) -> TimeVal { + assert!(seconds >= TV_MIN_SECONDS && seconds <= TV_MAX_SECONDS, + "TimeVal out of bounds; seconds={}", seconds); ++ #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 + TimeVal(timeval {tv_sec: seconds as time_t, tv_usec: 0 }) + } + +@@ -299,6 +345,7 @@ impl TimeValLike for TimeVal { + let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC); + assert!(secs >= TV_MIN_SECONDS && secs <= TV_MAX_SECONDS, + "TimeVal out of bounds"); ++ #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 + TimeVal(timeval {tv_sec: secs as time_t, + tv_usec: micros as suseconds_t }) + } +@@ -311,6 +358,7 @@ impl TimeValLike for TimeVal { + let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC); + assert!(secs >= TV_MIN_SECONDS && secs <= TV_MAX_SECONDS, + "TimeVal out of bounds"); ++ #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 + TimeVal(timeval {tv_sec: secs as time_t, + tv_usec: micros as suseconds_t }) + } +@@ -347,6 +395,7 @@ impl TimeVal { + } + } + ++ #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 + pub fn tv_sec(&self) -> time_t { + self.0.tv_sec + } +@@ -386,7 +435,7 @@ impl ops::Mul<i32> for TimeVal { + type Output = TimeVal; + + fn mul(self, rhs: i32) -> TimeVal { +- let usec = self.num_microseconds().checked_mul(rhs as i64) ++ let usec = self.num_microseconds().checked_mul(i64::from(rhs)) + .expect("TimeVal multiply out of bounds"); + + TimeVal::microseconds(usec) +@@ -397,7 +446,7 @@ impl ops::Div<i32> for TimeVal { + type Output = TimeVal; + + fn div(self, rhs: i32) -> TimeVal { +- let usec = self.num_microseconds() / rhs as i64; ++ let usec = self.num_microseconds() / i64::from(rhs); + TimeVal::microseconds(usec) + } + } +@@ -467,6 +516,7 @@ fn div_rem_64(this: i64, other: i64) -> (i64, i64) { + #[cfg(test)] + mod test { + use super::{TimeSpec, TimeVal, TimeValLike}; ++ use std::time::Duration; + + #[test] + pub fn test_timespec() { +@@ -477,6 +527,15 @@ mod test { + TimeSpec::seconds(182)); + } + ++ #[test] ++ pub fn test_timespec_from() { ++ let duration = Duration::new(123, 123_456_789); ++ let timespec = TimeSpec::nanoseconds(123_123_456_789); ++ ++ assert_eq!(TimeSpec::from(duration), timespec); ++ assert_eq!(Duration::from(timespec), duration); ++ } ++ + #[test] + pub fn test_timespec_neg() { + let a = TimeSpec::seconds(1) + TimeSpec::nanoseconds(123); +diff --git a/third_party/rust/nix/src/sys/timerfd.rs b/third_party/rust/nix/src/sys/timerfd.rs +new file mode 100644 +index 0000000000000..4a24719498602 +--- /dev/null ++++ b/third_party/rust/nix/src/sys/timerfd.rs +@@ -0,0 +1,285 @@ ++//! Timer API via file descriptors. ++//! ++//! Timer FD is a Linux-only API to create timers and get expiration ++//! notifications through file descriptors. ++//! ++//! For more documentation, please read [timerfd_create(2)](http://man7.org/linux/man-pages/man2/timerfd_create.2.html). ++//! ++//! # Examples ++//! ++//! Create a new one-shot timer that expires after 1 second. ++//! ``` ++//! # use std::os::unix::io::AsRawFd; ++//! # use nix::sys::timerfd::{TimerFd, ClockId, TimerFlags, TimerSetTimeFlags, ++//! # Expiration}; ++//! # use nix::sys::time::{TimeSpec, TimeValLike}; ++//! # use nix::unistd::read; ++//! # ++//! // We create a new monotonic timer. ++//! let timer = TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty()) ++//! .unwrap(); ++//! ++//! // We set a new one-shot timer in 1 seconds. ++//! timer.set( ++//! Expiration::OneShot(TimeSpec::seconds(1)), ++//! TimerSetTimeFlags::empty() ++//! ).unwrap(); ++//! ++//! // We wait for the timer to expire. ++//! timer.wait().unwrap(); ++//! ``` ++use crate::sys::time::TimeSpec; ++use crate::unistd::read; ++use crate::{errno::Errno, Error, Result}; ++use bitflags::bitflags; ++use libc::c_int; ++use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; ++ ++/// A timerfd instance. This is also a file descriptor, you can feed it to ++/// other interfaces consuming file descriptors, epoll for example. ++#[derive(Debug)] ++pub struct TimerFd { ++ fd: RawFd, ++} ++ ++impl AsRawFd for TimerFd { ++ fn as_raw_fd(&self) -> RawFd { ++ self.fd ++ } ++} ++ ++impl FromRawFd for TimerFd { ++ unsafe fn from_raw_fd(fd: RawFd) -> Self { ++ TimerFd { fd } ++ } ++} ++ ++libc_enum! { ++ /// The type of the clock used to mark the progress of the timer. For more ++ /// details on each kind of clock, please refer to [timerfd_create(2)](http://man7.org/linux/man-pages/man2/timerfd_create.2.html). ++ #[repr(i32)] ++ pub enum ClockId { ++ CLOCK_REALTIME, ++ CLOCK_MONOTONIC, ++ CLOCK_BOOTTIME, ++ CLOCK_REALTIME_ALARM, ++ CLOCK_BOOTTIME_ALARM, ++ } ++} ++ ++libc_bitflags! { ++ /// Additional flags to change the behaviour of the file descriptor at the ++ /// time of creation. ++ pub struct TimerFlags: c_int { ++ TFD_NONBLOCK; ++ TFD_CLOEXEC; ++ } ++} ++ ++bitflags! { ++ /// Flags that are used for arming the timer. ++ pub struct TimerSetTimeFlags: libc::c_int { ++ const TFD_TIMER_ABSTIME = libc::TFD_TIMER_ABSTIME; ++ } ++} ++ ++#[derive(Debug, Clone, Copy)] ++struct TimerSpec(libc::itimerspec); ++ ++impl TimerSpec { ++ pub fn none() -> Self { ++ Self(libc::itimerspec { ++ it_interval: libc::timespec { ++ tv_sec: 0, ++ tv_nsec: 0, ++ }, ++ it_value: libc::timespec { ++ tv_sec: 0, ++ tv_nsec: 0, ++ }, ++ }) ++ } ++} ++ ++impl AsRef<libc::itimerspec> for TimerSpec { ++ fn as_ref(&self) -> &libc::itimerspec { ++ &self.0 ++ } ++} ++ ++impl From<Expiration> for TimerSpec { ++ fn from(expiration: Expiration) -> TimerSpec { ++ match expiration { ++ Expiration::OneShot(t) => TimerSpec(libc::itimerspec { ++ it_interval: libc::timespec { ++ tv_sec: 0, ++ tv_nsec: 0, ++ }, ++ it_value: *t.as_ref(), ++ }), ++ Expiration::IntervalDelayed(start, interval) => TimerSpec(libc::itimerspec { ++ it_interval: *interval.as_ref(), ++ it_value: *start.as_ref(), ++ }), ++ Expiration::Interval(t) => TimerSpec(libc::itimerspec { ++ it_interval: *t.as_ref(), ++ it_value: *t.as_ref(), ++ }), ++ } ++ } ++} ++ ++impl From<TimerSpec> for Expiration { ++ fn from(timerspec: TimerSpec) -> Expiration { ++ match timerspec { ++ TimerSpec(libc::itimerspec { ++ it_interval: ++ libc::timespec { ++ tv_sec: 0, ++ tv_nsec: 0, ++ }, ++ it_value: ts, ++ }) => Expiration::OneShot(ts.into()), ++ TimerSpec(libc::itimerspec { ++ it_interval: int_ts, ++ it_value: val_ts, ++ }) => { ++ if (int_ts.tv_sec == val_ts.tv_sec) && (int_ts.tv_nsec == val_ts.tv_nsec) { ++ Expiration::Interval(int_ts.into()) ++ } else { ++ Expiration::IntervalDelayed(val_ts.into(), int_ts.into()) ++ } ++ } ++ } ++ } ++} ++ ++/// An enumeration allowing the definition of the expiration time of an alarm, ++/// recurring or not. ++#[derive(Debug, Clone, Copy, PartialEq)] ++pub enum Expiration { ++ OneShot(TimeSpec), ++ IntervalDelayed(TimeSpec, TimeSpec), ++ Interval(TimeSpec), ++} ++ ++impl TimerFd { ++ /// Creates a new timer based on the clock defined by `clockid`. The ++ /// underlying fd can be assigned specific flags with `flags` (CLOEXEC, ++ /// NONBLOCK). The underlying fd will be closed on drop. ++ pub fn new(clockid: ClockId, flags: TimerFlags) -> Result<Self> { ++ Errno::result(unsafe { libc::timerfd_create(clockid as i32, flags.bits()) }) ++ .map(|fd| Self { fd }) ++ } ++ ++ /// Sets a new alarm on the timer. ++ /// ++ /// # Types of alarm ++ /// ++ /// There are 3 types of alarms you can set: ++ /// ++ /// - one shot: the alarm will trigger once after the specified amount of ++ /// time. ++ /// Example: I want an alarm to go off in 60s and then disables itself. ++ /// ++ /// - interval: the alarm will trigger every specified interval of time. ++ /// Example: I want an alarm to go off every 60s. The alarm will first ++ /// go off 60s after I set it and every 60s after that. The alarm will ++ /// not disable itself. ++ /// ++ /// - interval delayed: the alarm will trigger after a certain amount of ++ /// time and then trigger at a specified interval. ++ /// Example: I want an alarm to go off every 60s but only start in 1h. ++ /// The alarm will first trigger 1h after I set it and then every 60s ++ /// after that. The alarm will not disable itself. ++ /// ++ /// # Relative vs absolute alarm ++ /// ++ /// If you do not set any `TimerSetTimeFlags`, then the `TimeSpec` you pass ++ /// to the `Expiration` you want is relative. If however you want an alarm ++ /// to go off at a certain point in time, you can set `TFD_TIMER_ABSTIME`. ++ /// Then the one shot TimeSpec and the delay TimeSpec of the delayed ++ /// interval are going to be interpreted as absolute. ++ /// ++ /// # Disabling alarms ++ /// ++ /// Note: Only one alarm can be set for any given timer. Setting a new alarm ++ /// actually removes the previous one. ++ /// ++ /// Note: Setting a one shot alarm with a 0s TimeSpec disables the alarm ++ /// altogether. ++ pub fn set(&self, expiration: Expiration, flags: TimerSetTimeFlags) -> Result<()> { ++ let timerspec: TimerSpec = expiration.into(); ++ Errno::result(unsafe { ++ libc::timerfd_settime( ++ self.fd, ++ flags.bits(), ++ timerspec.as_ref(), ++ std::ptr::null_mut(), ++ ) ++ }) ++ .map(drop) ++ } ++ ++ /// Get the parameters for the alarm currently set, if any. ++ pub fn get(&self) -> Result<Option<Expiration>> { ++ let mut timerspec = TimerSpec::none(); ++ let timerspec_ptr: *mut libc::itimerspec = &mut timerspec.0; ++ ++ Errno::result(unsafe { libc::timerfd_gettime(self.fd, timerspec_ptr) }).map(|_| { ++ if timerspec.0.it_interval.tv_sec == 0 ++ && timerspec.0.it_interval.tv_nsec == 0 ++ && timerspec.0.it_value.tv_sec == 0 ++ && timerspec.0.it_value.tv_nsec == 0 ++ { ++ None ++ } else { ++ Some(timerspec.into()) ++ } ++ }) ++ } ++ ++ /// Remove the alarm if any is set. ++ pub fn unset(&self) -> Result<()> { ++ Errno::result(unsafe { ++ libc::timerfd_settime( ++ self.fd, ++ TimerSetTimeFlags::empty().bits(), ++ TimerSpec::none().as_ref(), ++ std::ptr::null_mut(), ++ ) ++ }) ++ .map(drop) ++ } ++ ++ /// Wait for the configured alarm to expire. ++ /// ++ /// Note: If the alarm is unset, then you will wait forever. ++ pub fn wait(&self) -> Result<()> { ++ loop { ++ if let Err(e) = read(self.fd, &mut [0u8; 8]) { ++ match e { ++ Error::Sys(Errno::EINTR) => continue, ++ _ => return Err(e), ++ } ++ } else { ++ break; ++ } ++ } ++ ++ Ok(()) ++ } ++} ++ ++impl Drop for TimerFd { ++ fn drop(&mut self) { ++ if !std::thread::panicking() { ++ let result = Errno::result(unsafe { ++ libc::close(self.fd) ++ }); ++ if let Err(Error::Sys(Errno::EBADF)) = result { ++ panic!("close of TimerFd encountered EBADF"); ++ } ++ } ++ } ++} +diff --git a/third_party/rust/nix/src/sys/uio.rs b/third_party/rust/nix/src/sys/uio.rs +index d089084eed711..65334227b4d1d 100644 +--- a/third_party/rust/nix/src/sys/uio.rs ++++ b/third_party/rust/nix/src/sys/uio.rs +@@ -1,8 +1,8 @@ + // Silence invalid warnings due to rust-lang/rust#16719 + #![allow(improper_ctypes)] + +-use Result; +-use errno::Errno; ++use crate::Result; ++use crate::errno::Errno; + use libc::{self, c_int, c_void, size_t, off_t}; + use std::marker::PhantomData; + use std::os::unix::io::RawFd; +@@ -117,7 +117,11 @@ pub struct RemoteIoVec { + /// [`IoVec`]: struct.IoVec.html + /// [`RemoteIoVec`]: struct.RemoteIoVec.html + #[cfg(target_os = "linux")] +-pub fn process_vm_writev(pid: ::unistd::Pid, local_iov: &[IoVec<&[u8]>], remote_iov: &[RemoteIoVec]) -> Result<usize> { ++pub fn process_vm_writev( ++ pid: crate::unistd::Pid, ++ local_iov: &[IoVec<&[u8]>], ++ remote_iov: &[RemoteIoVec]) -> Result<usize> ++{ + let res = unsafe { + libc::process_vm_writev(pid.into(), + local_iov.as_ptr() as *const libc::iovec, local_iov.len() as libc::c_ulong, +@@ -148,7 +152,11 @@ pub fn process_vm_writev(pid: ::unistd::Pid, local_iov: &[IoVec<&[u8]>], remote_ + /// [`IoVec`]: struct.IoVec.html + /// [`RemoteIoVec`]: struct.RemoteIoVec.html + #[cfg(any(target_os = "linux"))] +-pub fn process_vm_readv(pid: ::unistd::Pid, local_iov: &[IoVec<&mut [u8]>], remote_iov: &[RemoteIoVec]) -> Result<usize> { ++pub fn process_vm_readv( ++ pid: crate::unistd::Pid, ++ local_iov: &[IoVec<&mut [u8]>], ++ remote_iov: &[RemoteIoVec]) -> Result<usize> ++{ + let res = unsafe { + libc::process_vm_readv(pid.into(), + local_iov.as_ptr() as *const libc::iovec, local_iov.len() as libc::c_ulong, +@@ -158,7 +166,7 @@ pub fn process_vm_readv(pid: ::unistd::Pid, local_iov: &[IoVec<&mut [u8]>], remo + Errno::result(res).map(|r| r as usize) + } + +-#[repr(C)] ++#[repr(transparent)] + #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] + pub struct IoVec<T>(libc::iovec, PhantomData<T>); + +diff --git a/third_party/rust/nix/src/sys/utsname.rs b/third_party/rust/nix/src/sys/utsname.rs +index ab09c7d23232a..bf1a814d6d863 100644 +--- a/third_party/rust/nix/src/sys/utsname.rs ++++ b/third_party/rust/nix/src/sys/utsname.rs +@@ -3,8 +3,8 @@ use libc::{self, c_char}; + use std::ffi::CStr; + use std::str::from_utf8_unchecked; + +-#[repr(C)] + #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] ++#[repr(transparent)] + pub struct UtsName(libc::utsname); + + impl UtsName { +@@ -31,9 +31,9 @@ impl UtsName { + + pub fn uname() -> UtsName { + unsafe { +- let mut ret: UtsName = mem::uninitialized(); +- libc::uname(&mut ret.0); +- ret ++ let mut ret = mem::MaybeUninit::uninit(); ++ libc::uname(ret.as_mut_ptr()); ++ UtsName(ret.assume_init()) + } + } + +diff --git a/third_party/rust/nix/src/sys/wait.rs b/third_party/rust/nix/src/sys/wait.rs +index c54f7ec579667..faf8543cb1589 100644 +--- a/third_party/rust/nix/src/sys/wait.rs ++++ b/third_party/rust/nix/src/sys/wait.rs +@@ -1,9 +1,10 @@ ++use crate::errno::Errno; ++use crate::sys::signal::Signal; ++use crate::unistd::Pid; ++use crate::Result; ++use cfg_if::cfg_if; + use libc::{self, c_int}; +-use Result; +-use errno::Errno; +-use unistd::Pid; +- +-use sys::signal::Signal; ++use std::convert::TryFrom; + + libc_bitflags!( + pub struct WaitPidFlag: c_int { +@@ -14,6 +15,7 @@ libc_bitflags!( + target_os = "haiku", + target_os = "ios", + target_os = "linux", ++ target_os = "redox", + target_os = "macos", + target_os = "netbsd"))] + WEXITED; +@@ -23,6 +25,7 @@ libc_bitflags!( + target_os = "haiku", + target_os = "ios", + target_os = "linux", ++ target_os = "redox", + target_os = "macos", + target_os = "netbsd"))] + WSTOPPED; +@@ -32,16 +35,17 @@ libc_bitflags!( + target_os = "haiku", + target_os = "ios", + target_os = "linux", ++ target_os = "redox", + target_os = "macos", + target_os = "netbsd"))] + WNOWAIT; + /// Don't wait on children of other threads in this group +- #[cfg(any(target_os = "android", target_os = "linux"))] ++ #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))] + __WNOTHREAD; + /// Wait on all children, regardless of type +- #[cfg(any(target_os = "android", target_os = "linux"))] ++ #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))] + __WALL; +- #[cfg(any(target_os = "android", target_os = "linux"))] ++ #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))] + __WCLONE; + } + ); +@@ -104,8 +108,7 @@ impl WaitStatus { + pub fn pid(&self) -> Option<Pid> { + use self::WaitStatus::*; + match *self { +- Exited(p, _) | Signaled(p, _, _) | +- Stopped(p, _) | Continued(p) => Some(p), ++ Exited(p, _) | Signaled(p, _, _) | Stopped(p, _) | Continued(p) => Some(p), + StillAlive => None, + #[cfg(any(target_os = "android", target_os = "linux"))] + PtraceEvent(p, _, _) | PtraceSyscall(p) => Some(p), +@@ -114,31 +117,31 @@ impl WaitStatus { + } + + fn exited(status: i32) -> bool { +- unsafe { libc::WIFEXITED(status) } ++ libc::WIFEXITED(status) + } + + fn exit_status(status: i32) -> i32 { +- unsafe { libc::WEXITSTATUS(status) } ++ libc::WEXITSTATUS(status) + } + + fn signaled(status: i32) -> bool { +- unsafe { libc::WIFSIGNALED(status) } ++ libc::WIFSIGNALED(status) + } + + fn term_signal(status: i32) -> Result<Signal> { +- Signal::from_c_int(unsafe { libc::WTERMSIG(status) }) ++ Signal::try_from(libc::WTERMSIG(status)) + } + + fn dumped_core(status: i32) -> bool { +- unsafe { libc::WCOREDUMP(status) } ++ libc::WCOREDUMP(status) + } + + fn stopped(status: i32) -> bool { +- unsafe { libc::WIFSTOPPED(status) } ++ libc::WIFSTOPPED(status) + } + + fn stop_signal(status: i32) -> Result<Signal> { +- Signal::from_c_int(unsafe { libc::WSTOPSIG(status) }) ++ Signal::try_from(libc::WSTOPSIG(status)) + } + + #[cfg(any(target_os = "android", target_os = "linux"))] +@@ -147,7 +150,7 @@ fn syscall_stop(status: i32) -> bool { + // of delivering SIGTRAP | 0x80 as the signal number for syscall + // stops. This allows easily distinguishing syscall stops from + // genuine SIGTRAP signals. +- unsafe { libc::WSTOPSIG(status) == libc::SIGTRAP | 0x80 } ++ libc::WSTOPSIG(status) == libc::SIGTRAP | 0x80 + } + + #[cfg(any(target_os = "android", target_os = "linux"))] +@@ -156,7 +159,7 @@ fn stop_additional(status: i32) -> c_int { + } + + fn continued(status: i32) -> bool { +- unsafe { libc::WIFCONTINUED(status) } ++ libc::WIFCONTINUED(status) + } + + impl WaitStatus { +@@ -222,7 +225,7 @@ pub fn waitpid<P: Into<Option<Pid>>>(pid: P, options: Option<WaitPidFlag>) -> Re + + let res = unsafe { + libc::waitpid( +- pid.into().unwrap_or(Pid::from_raw(-1)).into(), ++ pid.into().unwrap_or_else(|| Pid::from_raw(-1)).into(), + &mut status as *mut c_int, + option_bits, + ) +diff --git a/third_party/rust/nix/src/time.rs b/third_party/rust/nix/src/time.rs +new file mode 100644 +index 0000000000000..e6c3f8ded5a52 +--- /dev/null ++++ b/third_party/rust/nix/src/time.rs +@@ -0,0 +1,260 @@ ++use crate::sys::time::TimeSpec; ++#[cfg(any( ++ target_os = "freebsd", ++ target_os = "dragonfly", ++ target_os = "linux", ++ target_os = "android", ++ target_os = "emscripten", ++))] ++use crate::{unistd::Pid, Error}; ++use crate::{Errno, Result}; ++use libc::{self, clockid_t}; ++use std::mem::MaybeUninit; ++ ++/// Clock identifier ++/// ++/// Newtype pattern around `clockid_t` (which is just alias). It pervents bugs caused by ++/// accidentally passing wrong value. ++#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] ++pub struct ClockId(clockid_t); ++ ++impl ClockId { ++ /// Creates `ClockId` from raw `clockid_t` ++ pub fn from_raw(clk_id: clockid_t) -> Self { ++ ClockId(clk_id) ++ } ++ ++ /// Returns `ClockId` of a `pid` CPU-time clock ++ #[cfg(any( ++ target_os = "freebsd", ++ target_os = "dragonfly", ++ target_os = "linux", ++ target_os = "android", ++ target_os = "emscripten", ++ ))] ++ pub fn pid_cpu_clock_id(pid: Pid) -> Result<Self> { ++ clock_getcpuclockid(pid) ++ } ++ ++ /// Returns resolution of the clock id ++ #[cfg(not(target_os = "redox"))] ++ pub fn res(self) -> Result<TimeSpec> { ++ clock_getres(self) ++ } ++ ++ /// Returns the current time on the clock id ++ pub fn now(self) -> Result<TimeSpec> { ++ clock_gettime(self) ++ } ++ ++ /// Sets time to `timespec` on the clock id ++ #[cfg(not(any( ++ target_os = "macos", ++ target_os = "ios", ++ all( ++ not(any(target_env = "uclibc", target_env = "newlibc")), ++ any(target_os = "redox", target_os = "hermit",), ++ ), ++ )))] ++ pub fn set_time(self, timespec: TimeSpec) -> Result<()> { ++ clock_settime(self, timespec) ++ } ++ ++ /// Gets the raw `clockid_t` wrapped by `self` ++ pub fn as_raw(self) -> clockid_t { ++ self.0 ++ } ++ ++ #[cfg(any( ++ target_os = "fuchsia", ++ all( ++ not(any(target_env = "uclibc", target_env = "newlib")), ++ any(target_os = "linux", target_os = "android", target_os = "emscripten"), ++ ) ++ ))] ++ pub const CLOCK_BOOTTIME: ClockId = ClockId(libc::CLOCK_BOOTTIME); ++ #[cfg(any( ++ target_os = "fuchsia", ++ all( ++ not(any(target_env = "uclibc", target_env = "newlib")), ++ any(target_os = "linux", target_os = "android", target_os = "emscripten") ++ ) ++ ))] ++ pub const CLOCK_BOOTTIME_ALARM: ClockId = ClockId(libc::CLOCK_BOOTTIME_ALARM); ++ pub const CLOCK_MONOTONIC: ClockId = ClockId(libc::CLOCK_MONOTONIC); ++ #[cfg(any( ++ target_os = "fuchsia", ++ all( ++ not(any(target_env = "uclibc", target_env = "newlib")), ++ any(target_os = "linux", target_os = "android", target_os = "emscripten") ++ ) ++ ))] ++ pub const CLOCK_MONOTONIC_COARSE: ClockId = ClockId(libc::CLOCK_MONOTONIC_COARSE); ++ #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] ++ pub const CLOCK_MONOTONIC_FAST: ClockId = ClockId(libc::CLOCK_MONOTONIC_FAST); ++ #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] ++ pub const CLOCK_MONOTONIC_PRECISE: ClockId = ClockId(libc::CLOCK_MONOTONIC_PRECISE); ++ #[cfg(any( ++ target_os = "fuchsia", ++ all( ++ not(any(target_env = "uclibc", target_env = "newlib")), ++ any(target_os = "linux", target_os = "android", target_os = "emscripten") ++ ) ++ ))] ++ pub const CLOCK_MONOTONIC_RAW: ClockId = ClockId(libc::CLOCK_MONOTONIC_RAW); ++ #[cfg(any( ++ target_os = "fuchsia", ++ target_env = "uclibc", ++ target_os = "macos", ++ target_os = "ios", ++ target_os = "freebsd", ++ target_os = "dragonfly", ++ all( ++ not(target_env = "newlib"), ++ any(target_os = "linux", target_os = "android", target_os = "emscripten") ++ ) ++ ))] ++ pub const CLOCK_PROCESS_CPUTIME_ID: ClockId = ClockId(libc::CLOCK_PROCESS_CPUTIME_ID); ++ #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] ++ pub const CLOCK_PROF: ClockId = ClockId(libc::CLOCK_PROF); ++ pub const CLOCK_REALTIME: ClockId = ClockId(libc::CLOCK_REALTIME); ++ #[cfg(any( ++ target_os = "fuchsia", ++ all( ++ not(any(target_env = "uclibc", target_env = "newlib")), ++ any(target_os = "linux", target_os = "android", target_os = "emscripten") ++ ) ++ ))] ++ pub const CLOCK_REALTIME_ALARM: ClockId = ClockId(libc::CLOCK_REALTIME_ALARM); ++ #[cfg(any( ++ target_os = "fuchsia", ++ all( ++ not(any(target_env = "uclibc", target_env = "newlib")), ++ any(target_os = "linux", target_os = "android", target_os = "emscripten") ++ ) ++ ))] ++ pub const CLOCK_REALTIME_COARSE: ClockId = ClockId(libc::CLOCK_REALTIME_COARSE); ++ #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] ++ pub const CLOCK_REALTIME_FAST: ClockId = ClockId(libc::CLOCK_REALTIME_FAST); ++ #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] ++ pub const CLOCK_REALTIME_PRECISE: ClockId = ClockId(libc::CLOCK_REALTIME_PRECISE); ++ #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] ++ pub const CLOCK_SECOND: ClockId = ClockId(libc::CLOCK_SECOND); ++ #[cfg(any( ++ target_os = "fuchsia", ++ all( ++ not(any(target_env = "uclibc", target_env = "newlib")), ++ any( ++ target_os = "emscripten", ++ all(target_os = "linux", target_env = "musl") ++ ) ++ ) ++ ))] ++ pub const CLOCK_SGI_CYCLE: ClockId = ClockId(libc::CLOCK_SGI_CYCLE); ++ #[cfg(any( ++ target_os = "fuchsia", ++ all( ++ not(any(target_env = "uclibc", target_env = "newlib")), ++ any( ++ target_os = "emscripten", ++ all(target_os = "linux", target_env = "musl") ++ ) ++ ) ++ ))] ++ pub const CLOCK_TAI: ClockId = ClockId(libc::CLOCK_TAI); ++ #[cfg(any( ++ target_env = "uclibc", ++ target_os = "fuchsia", ++ target_os = "ios", ++ target_os = "macos", ++ target_os = "freebsd", ++ target_os = "dragonfly", ++ all( ++ not(target_env = "newlib"), ++ any(target_os = "linux", target_os = "android", target_os = "emscripten",), ++ ), ++ ))] ++ pub const CLOCK_THREAD_CPUTIME_ID: ClockId = ClockId(libc::CLOCK_THREAD_CPUTIME_ID); ++ #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] ++ pub const CLOCK_UPTIME: ClockId = ClockId(libc::CLOCK_UPTIME); ++ #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] ++ pub const CLOCK_UPTIME_FAST: ClockId = ClockId(libc::CLOCK_UPTIME_FAST); ++ #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] ++ pub const CLOCK_UPTIME_PRECISE: ClockId = ClockId(libc::CLOCK_UPTIME_PRECISE); ++ #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] ++ pub const CLOCK_VIRTUAL: ClockId = ClockId(libc::CLOCK_VIRTUAL); ++} ++ ++impl Into<clockid_t> for ClockId { ++ fn into(self) -> clockid_t { ++ self.as_raw() ++ } ++} ++ ++impl From<clockid_t> for ClockId { ++ fn from(clk_id: clockid_t) -> Self { ++ ClockId::from_raw(clk_id) ++ } ++} ++ ++impl std::fmt::Display for ClockId { ++ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { ++ std::fmt::Display::fmt(&self.0, f) ++ } ++} ++ ++/// Get the resolution of the specified clock, (see ++/// [clock_getres(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_getres.html)). ++#[cfg(not(target_os = "redox"))] ++pub fn clock_getres(clock_id: ClockId) -> Result<TimeSpec> { ++ let mut c_time: MaybeUninit<libc::timespec> = MaybeUninit::uninit(); ++ let ret = unsafe { libc::clock_getres(clock_id.as_raw(), c_time.as_mut_ptr()) }; ++ Errno::result(ret)?; ++ let res = unsafe { c_time.assume_init() }; ++ Ok(TimeSpec::from(res)) ++} ++ ++/// Get the time of the specified clock, (see ++/// [clock_gettime(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_gettime.html)). ++pub fn clock_gettime(clock_id: ClockId) -> Result<TimeSpec> { ++ let mut c_time: MaybeUninit<libc::timespec> = MaybeUninit::uninit(); ++ let ret = unsafe { libc::clock_gettime(clock_id.as_raw(), c_time.as_mut_ptr()) }; ++ Errno::result(ret)?; ++ let res = unsafe { c_time.assume_init() }; ++ Ok(TimeSpec::from(res)) ++} ++ ++/// Set the time of the specified clock, (see ++/// [clock_settime(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_settime.html)). ++#[cfg(not(any( ++ target_os = "macos", ++ target_os = "ios", ++ all( ++ not(any(target_env = "uclibc", target_env = "newlibc")), ++ any(target_os = "redox", target_os = "hermit",), ++ ), ++)))] ++pub fn clock_settime(clock_id: ClockId, timespec: TimeSpec) -> Result<()> { ++ let ret = unsafe { libc::clock_settime(clock_id.as_raw(), timespec.as_ref()) }; ++ Errno::result(ret).map(drop) ++} ++ ++/// Get the clock id of the specified process id, (see ++/// [clock_getcpuclockid(3)](https://pubs.opengroup.org/onlinepubs/009695399/functions/clock_getcpuclockid.html)). ++#[cfg(any( ++ target_os = "freebsd", ++ target_os = "dragonfly", ++ target_os = "linux", ++ target_os = "android", ++ target_os = "emscripten", ++))] ++pub fn clock_getcpuclockid(pid: Pid) -> Result<ClockId> { ++ let mut clk_id: MaybeUninit<libc::clockid_t> = MaybeUninit::uninit(); ++ let ret = unsafe { libc::clock_getcpuclockid(pid.into(), clk_id.as_mut_ptr()) }; ++ if ret == 0 { ++ let res = unsafe { clk_id.assume_init() }; ++ Ok(ClockId::from(res)) ++ } else { ++ Err(Error::Sys(Errno::from_i32(ret))) ++ } ++} +diff --git a/third_party/rust/nix/src/ucontext.rs b/third_party/rust/nix/src/ucontext.rs +index 5e10e7d1f8934..a5b8cc75cb330 100644 +--- a/third_party/rust/nix/src/ucontext.rs ++++ b/third_party/rust/nix/src/ucontext.rs +@@ -1,10 +1,11 @@ + use libc; + #[cfg(not(target_env = "musl"))] +-use Result; ++use crate::Result; ++#[cfg(not(target_env = "musl"))] ++use crate::errno::Errno; + #[cfg(not(target_env = "musl"))] +-use errno::Errno; + use std::mem; +-use sys::signal::SigSet; ++use crate::sys::signal::SigSet; + + #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] + pub struct UContext { +@@ -14,11 +15,11 @@ pub struct UContext { + impl UContext { + #[cfg(not(target_env = "musl"))] + pub fn get() -> Result<UContext> { +- let mut context: libc::ucontext_t = unsafe { mem::uninitialized() }; +- let res = unsafe { +- libc::getcontext(&mut context as *mut libc::ucontext_t) +- }; +- Errno::result(res).map(|_| UContext { context: context }) ++ let mut context = mem::MaybeUninit::<libc::ucontext_t>::uninit(); ++ let res = unsafe { libc::getcontext(context.as_mut_ptr()) }; ++ Errno::result(res).map(|_| unsafe { ++ UContext { context: context.assume_init()} ++ }) + } + + #[cfg(not(target_env = "musl"))] +@@ -30,10 +31,14 @@ impl UContext { + } + + pub fn sigmask_mut(&mut self) -> &mut SigSet { +- unsafe { mem::transmute(&mut self.context.uc_sigmask) } ++ unsafe { ++ &mut *(&mut self.context.uc_sigmask as *mut libc::sigset_t as *mut SigSet) ++ } + } + + pub fn sigmask(&self) -> &SigSet { +- unsafe { mem::transmute(&self.context.uc_sigmask) } ++ unsafe { ++ &*(&self.context.uc_sigmask as *const libc::sigset_t as *const SigSet) ++ } + } + } +diff --git a/third_party/rust/nix/src/unistd.rs b/third_party/rust/nix/src/unistd.rs +index f422f09198655..59cb1ed8b5901 100644 +--- a/third_party/rust/nix/src/unistd.rs ++++ b/third_party/rust/nix/src/unistd.rs +@@ -1,18 +1,26 @@ + //! Safe wrappers around functions found in libc "unistd.h" header + +-use errno::{self, Errno}; +-use {Error, Result, NixPath}; +-use fcntl::{AtFlags, at_rawfd, fcntl, FdFlag, OFlag}; +-use fcntl::FcntlArg::F_SETFD; ++#[cfg(not(target_os = "redox"))] ++use cfg_if::cfg_if; ++use crate::errno::{self, Errno}; ++use crate::{Error, Result, NixPath}; ++#[cfg(not(target_os = "redox"))] ++use crate::fcntl::{AtFlags, at_rawfd}; ++use crate::fcntl::{FdFlag, OFlag, fcntl}; ++use crate::fcntl::FcntlArg::F_SETFD; + use libc::{self, c_char, c_void, c_int, c_long, c_uint, size_t, pid_t, off_t, +- uid_t, gid_t, mode_t}; ++ uid_t, gid_t, mode_t, PATH_MAX}; + use std::{fmt, mem, ptr}; +-use std::ffi::{CString, CStr, OsString, OsStr}; +-use std::os::unix::ffi::{OsStringExt, OsStrExt}; ++use std::convert::Infallible; ++use std::ffi::{CStr, OsString}; ++#[cfg(not(target_os = "redox"))] ++use std::ffi::{CString, OsStr}; ++use std::os::unix::ffi::OsStringExt; ++#[cfg(not(target_os = "redox"))] ++use std::os::unix::ffi::OsStrExt; + use std::os::unix::io::RawFd; + use std::path::PathBuf; +-use void::Void; +-use sys::stat::Mode; ++use crate::sys::stat::Mode; + + #[cfg(any(target_os = "android", target_os = "linux"))] + pub use self::pivot_root::*; +@@ -45,12 +53,12 @@ impl Uid { + } + + /// Returns true if the `Uid` represents privileged user - root. (If it equals zero.) +- pub fn is_root(&self) -> bool { +- *self == ROOT ++ pub fn is_root(self) -> bool { ++ self == ROOT + } + + /// Get the raw `uid_t` wrapped by `self`. +- pub fn as_raw(&self) -> uid_t { ++ pub fn as_raw(self) -> uid_t { + self.0 + } + } +@@ -88,13 +96,13 @@ impl Gid { + getgid() + } + +- /// Returns effective Gid of calling process. This is practically a more Rusty alias for `getgid`. ++ /// Returns effective Gid of calling process. This is practically a more Rusty alias for `getegid`. + pub fn effective() -> Self { + getegid() + } + + /// Get the raw `gid_t` wrapped by `self`. +- pub fn as_raw(&self) -> gid_t { ++ pub fn as_raw(self) -> gid_t { + self.0 + } + } +@@ -115,7 +123,7 @@ impl fmt::Display for Gid { + /// + /// Newtype pattern around `pid_t` (which is just alias). It prevents bugs caused by accidentally + /// passing wrong value. +-#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] ++#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] + pub struct Pid(pid_t); + + impl Pid { +@@ -135,7 +143,7 @@ impl Pid { + } + + /// Get the raw `pid_t` wrapped by `self`. +- pub fn as_raw(&self) -> pid_t { ++ pub fn as_raw(self) -> pid_t { + self.0 + } + } +@@ -168,8 +176,8 @@ impl ForkResult { + + /// Return `true` if this is the child process of the `fork()` + #[inline] +- pub fn is_child(&self) -> bool { +- match *self { ++ pub fn is_child(self) -> bool { ++ match self { + ForkResult::Child => true, + _ => false + } +@@ -177,7 +185,7 @@ impl ForkResult { + + /// Returns `true` if this is the parent process of the `fork()` + #[inline] +- pub fn is_parent(&self) -> bool { ++ pub fn is_parent(self) -> bool { + !self.is_child() + } + } +@@ -192,7 +200,7 @@ impl ForkResult { + /// ```no_run + /// use nix::unistd::{fork, ForkResult}; + /// +-/// match fork() { ++/// match unsafe{fork()} { + /// Ok(ForkResult::Parent { child, .. }) => { + /// println!("Continuing execution in parent process, new child has pid: {}", child); + /// } +@@ -222,9 +230,9 @@ impl ForkResult { + /// + /// [async-signal-safe]: http://man7.org/linux/man-pages/man7/signal-safety.7.html + #[inline] +-pub fn fork() -> Result<ForkResult> { ++pub unsafe fn fork() -> Result<ForkResult> { + use self::ForkResult::*; +- let res = unsafe { libc::fork() }; ++ let res = libc::fork(); + + Errno::result(res).map(|res| match res { + 0 => Child, +@@ -285,6 +293,7 @@ pub fn setsid() -> Result<Pid> { + /// Obtain the process group ID of the process that is the session leader of the process specified + /// by pid. If pid is zero, it specifies the calling process. + #[inline] ++#[cfg(not(target_os = "redox"))] + pub fn getsid(pid: Option<Pid>) -> Result<Pid> { + let res = unsafe { libc::getsid(pid.unwrap_or(Pid(0)).into()) }; + Errno::result(res).map(Pid) +@@ -417,6 +426,7 @@ pub fn chdir<P: ?Sized + NixPath>(path: &P) -> Result<()> { + /// This function may fail in a number of different scenarios. See the man + /// pages for additional details on possible failure cases. + #[inline] ++#[cfg(not(target_os = "fuchsia"))] + pub fn fchdir(dirfd: RawFd) -> Result<()> { + let res = unsafe { libc::fchdir(dirfd) }; + +@@ -436,9 +446,6 @@ pub fn fchdir(dirfd: RawFd) -> Result<()> { + /// # Example + /// + /// ```rust +-/// extern crate tempfile; +-/// extern crate nix; +-/// + /// use nix::unistd; + /// use nix::sys::stat; + /// use tempfile::tempdir; +@@ -479,9 +486,6 @@ pub fn mkdir<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> { + /// # Example + /// + /// ```rust +-/// extern crate tempfile; +-/// extern crate nix; +-/// + /// use nix::unistd; + /// use nix::sys::stat; + /// use tempfile::tempdir; +@@ -498,6 +502,7 @@ pub fn mkdir<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> { + /// } + /// ``` + #[inline] ++#[cfg(not(target_os = "redox"))] // RedoxFS does not support fifo yet + pub fn mkfifo<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> { + let res = path.with_nix_path(|cstr| { + unsafe { libc::mkfifo(cstr.as_ptr(), mode.bits() as mode_t) } +@@ -506,6 +511,28 @@ pub fn mkfifo<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> { + Errno::result(res).map(drop) + } + ++/// Creates new fifo special file (named pipe) with path `path` and access rights `mode`. ++/// ++/// If `dirfd` has a value, then `path` is relative to directory associated with the file descriptor. ++/// ++/// If `dirfd` is `None`, then `path` is relative to the current working directory. ++/// ++/// # References ++/// ++/// [mkfifoat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mkfifoat.html). ++// mkfifoat is not implemented in OSX or android ++#[inline] ++#[cfg(not(any( ++ target_os = "macos", target_os = "ios", ++ target_os = "android", target_os = "redox")))] ++pub fn mkfifoat<P: ?Sized + NixPath>(dirfd: Option<RawFd>, path: &P, mode: Mode) -> Result<()> { ++ let res = path.with_nix_path(|cstr| unsafe { ++ libc::mkfifoat(at_rawfd(dirfd), cstr.as_ptr(), mode.bits() as mode_t) ++ })?; ++ ++ Errno::result(res).map(drop) ++} ++ + /// Creates a symbolic link at `path2` which points to `path1`. + /// + /// If `dirfd` has a value, then `path2` is relative to directory associated +@@ -515,6 +542,7 @@ pub fn mkfifo<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> { + /// directory. This is identical to `libc::symlink(path1, path2)`. + /// + /// See also [symlinkat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/symlinkat.html). ++#[cfg(not(target_os = "redox"))] + pub fn symlinkat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>( + path1: &P1, + dirfd: Option<RawFd>, +@@ -534,6 +562,21 @@ pub fn symlinkat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>( + Errno::result(res).map(drop) + } + ++// Double the buffer capacity up to limit. In case it already has ++// reached the limit, return Errno::ERANGE. ++fn reserve_double_buffer_size<T>(buf: &mut Vec<T>, limit: usize) -> Result<()> { ++ use std::cmp::min; ++ ++ if buf.capacity() >= limit { ++ return Err(Error::Sys(Errno::ERANGE)) ++ } ++ ++ let capacity = min(buf.capacity() * 2, limit); ++ buf.reserve(capacity); ++ ++ Ok(()) ++} ++ + /// Returns the current directory as a `PathBuf` + /// + /// Err is returned if the current user doesn't have the permission to read or search a component +@@ -542,8 +585,6 @@ pub fn symlinkat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>( + /// # Example + /// + /// ```rust +-/// extern crate nix; +-/// + /// use nix::unistd; + /// + /// fn main() { +@@ -576,11 +617,8 @@ pub fn getcwd() -> Result<PathBuf> { + } + } + +- // Trigger the internal buffer resizing logic of `Vec` by requiring +- // more space than the current capacity. +- let cap = buf.capacity(); +- buf.set_len(cap); +- buf.reserve(1); ++ // Trigger the internal buffer resizing logic. ++ reserve_double_buffer_size(&mut buf, PATH_MAX as usize)?; + } + } + } +@@ -590,8 +628,10 @@ fn chown_raw_ids(owner: Option<Uid>, group: Option<Gid>) -> (libc::uid_t, libc:: + // According to the POSIX specification, -1 is used to indicate that owner and group + // are not to be changed. Since uid_t and gid_t are unsigned types, we have to wrap + // around to get -1. +- let uid = owner.map(Into::into).unwrap_or((0 as uid_t).wrapping_sub(1)); +- let gid = group.map(Into::into).unwrap_or((0 as gid_t).wrapping_sub(1)); ++ let uid = owner.map(Into::into) ++ .unwrap_or_else(|| (0 as uid_t).wrapping_sub(1)); ++ let gid = group.map(Into::into) ++ .unwrap_or_else(|| (0 as gid_t).wrapping_sub(1)); + (uid, gid) + } + +@@ -612,6 +652,20 @@ pub fn chown<P: ?Sized + NixPath>(path: &P, owner: Option<Uid>, group: Option<Gi + Errno::result(res).map(drop) + } + ++/// Change the ownership of the file referred to by the open file descriptor `fd` to be owned by ++/// the specified `owner` (user) and `group` (see ++/// [fchown(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchown.html)). ++/// ++/// The owner/group for the provided file will not be modified if `None` is ++/// provided for that argument. Ownership change will be attempted for the path ++/// only if `Some` owner/group is provided. ++#[inline] ++pub fn fchown(fd: RawFd, owner: Option<Uid>, group: Option<Gid>) -> Result<()> { ++ let (uid, gid) = chown_raw_ids(owner, group); ++ let res = unsafe { libc::fchown(fd, uid, gid) }; ++ Errno::result(res).map(drop) ++} ++ + /// Flags for `fchownat` function. + #[derive(Clone, Copy, Debug)] + pub enum FchownatFlags { +@@ -640,6 +694,7 @@ pub enum FchownatFlags { + /// # References + /// + /// [fchownat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fchownat.html). ++#[cfg(not(target_os = "redox"))] + pub fn fchownat<P: ?Sized + NixPath>( + dirfd: Option<RawFd>, + path: &P, +@@ -661,10 +716,9 @@ pub fn fchownat<P: ?Sized + NixPath>( + Errno::result(res).map(drop) + } + +-fn to_exec_array(args: &[CString]) -> Vec<*const c_char> { +- let mut args_p: Vec<*const c_char> = args.iter().map(|s| s.as_ptr()).collect(); +- args_p.push(ptr::null()); +- args_p ++fn to_exec_array<S: AsRef<CStr>>(args: &[S]) -> Vec<*const c_char> { ++ use std::iter::once; ++ args.iter().map(|s| s.as_ref().as_ptr()).chain(once(ptr::null())).collect() + } + + /// Replace the current process image with a new one (see +@@ -674,7 +728,7 @@ fn to_exec_array(args: &[CString]) -> Vec<*const c_char> { + /// performs the same action but does not allow for customization of the + /// environment for the new process. + #[inline] +-pub fn execv(path: &CString, argv: &[CString]) -> Result<Void> { ++pub fn execv<S: AsRef<CStr>>(path: &CStr, argv: &[S]) -> Result<Infallible> { + let args_p = to_exec_array(argv); + + unsafe { +@@ -698,7 +752,7 @@ pub fn execv(path: &CString, argv: &[CString]) -> Result<Void> { + /// in the `args` list is an argument to the new process. Each element in the + /// `env` list should be a string in the form "key=value". + #[inline] +-pub fn execve(path: &CString, args: &[CString], env: &[CString]) -> Result<Void> { ++pub fn execve<SA: AsRef<CStr>, SE: AsRef<CStr>>(path: &CStr, args: &[SA], env: &[SE]) -> Result<Infallible> { + let args_p = to_exec_array(args); + let env_p = to_exec_array(env); + +@@ -719,7 +773,7 @@ pub fn execve(path: &CString, args: &[CString], env: &[CString]) -> Result<Void> + /// would not work if "bash" was specified for the path argument, but `execvp` + /// would assuming that a bash executable was on the system `PATH`. + #[inline] +-pub fn execvp(filename: &CString, args: &[CString]) -> Result<Void> { ++pub fn execvp<S: AsRef<CStr>>(filename: &CStr, args: &[S]) -> Result<Infallible> { + let args_p = to_exec_array(args); + + unsafe { +@@ -739,7 +793,7 @@ pub fn execvp(filename: &CString, args: &[CString]) -> Result<Void> { + #[cfg(any(target_os = "haiku", + target_os = "linux", + target_os = "openbsd"))] +-pub fn execvpe(filename: &CString, args: &[CString], env: &[CString]) -> Result<Void> { ++pub fn execvpe<SA: AsRef<CStr>, SE: AsRef<CStr>>(filename: &CStr, args: &[SA], env: &[SE]) -> Result<Infallible> { + let args_p = to_exec_array(args); + let env_p = to_exec_array(env); + +@@ -767,7 +821,7 @@ pub fn execvpe(filename: &CString, args: &[CString], env: &[CString]) -> Result< + target_os = "linux", + target_os = "freebsd"))] + #[inline] +-pub fn fexecve(fd: RawFd, args: &[CString], env: &[CString]) -> Result<Void> { ++pub fn fexecve<SA: AsRef<CStr> ,SE: AsRef<CStr>>(fd: RawFd, args: &[SA], env: &[SE]) -> Result<Infallible> { + let args_p = to_exec_array(args); + let env_p = to_exec_array(env); + +@@ -790,8 +844,8 @@ pub fn fexecve(fd: RawFd, args: &[CString], env: &[CString]) -> Result<Void> { + /// is referenced as a file descriptor to the base directory plus a path. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[inline] +-pub fn execveat(dirfd: RawFd, pathname: &CString, args: &[CString], +- env: &[CString], flags: super::fcntl::AtFlags) -> Result<Void> { ++pub fn execveat<SA: AsRef<CStr>,SE: AsRef<CStr>>(dirfd: RawFd, pathname: &CStr, args: &[SA], ++ env: &[SE], flags: super::fcntl::AtFlags) -> Result<Infallible> { + let args_p = to_exec_array(args); + let env_p = to_exec_array(env); + +@@ -828,11 +882,12 @@ pub fn execveat(dirfd: RawFd, pathname: &CString, args: &[CString], + /// descriptors will remain identical after daemonizing. + /// * `noclose = false`: The process' stdin, stdout, and stderr will point to + /// `/dev/null` after daemonizing. +-#[cfg_attr(any(target_os = "macos", target_os = "ios"), deprecated( +- since="0.14.0", +- note="Deprecated in MacOSX 10.5" +-))] +-#[cfg_attr(any(target_os = "macos", target_os = "ios"), allow(deprecated))] ++#[cfg(any(target_os = "android", ++ target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "linux", ++ target_os = "netbsd", ++ target_os = "openbsd"))] + pub fn daemon(nochdir: bool, noclose: bool) -> Result<()> { + let res = unsafe { libc::daemon(nochdir as c_int, noclose as c_int) }; + Errno::result(res).map(drop) +@@ -845,6 +900,7 @@ pub fn daemon(nochdir: bool, noclose: bool) -> Result<()> { + /// On some systems, the host name is limited to as few as 64 bytes. An error + /// will be return if the name is not valid or the current process does not have + /// permissions to update the host name. ++#[cfg(not(target_os = "redox"))] + pub fn sethostname<S: AsRef<OsStr>>(name: S) -> Result<()> { + // Handle some differences in type of the len arg across platforms. + cfg_if! { +@@ -906,9 +962,6 @@ pub fn gethostname(buffer: &mut [u8]) -> Result<&CStr> { + /// # Examples + /// + /// ```no_run +-/// extern crate tempfile; +-/// extern crate nix; +-/// + /// use std::os::unix::io::AsRawFd; + /// use nix::unistd::close; + /// +@@ -919,9 +972,6 @@ pub fn gethostname(buffer: &mut [u8]) -> Result<&CStr> { + /// ``` + /// + /// ```rust +-/// extern crate tempfile; +-/// extern crate nix; +-/// + /// use std::os::unix::io::IntoRawFd; + /// use nix::unistd::close; + /// +@@ -969,20 +1019,14 @@ pub enum Whence { + /// Specify an offset relative to the next location in the file greater than or + /// equal to offset that contains some data. If offset points to + /// some data, then the file offset is set to offset. +- #[cfg(any(target_os = "dragonfly", target_os = "freebsd", +- all(target_os = "linux", not(any(target_env = "musl", +- target_arch = "mips", +- target_arch = "mips64")))))] ++ #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))] + SeekData = libc::SEEK_DATA, + /// Specify an offset relative to the next hole in the file greater than + /// or equal to offset. If offset points into the middle of a hole, then + /// the file offset should be set to offset. If there is no hole past offset, + /// then the file offset should be adjusted to the end of the file (i.e., there + /// is an implicit hole at the end of any file). +- #[cfg(any(target_os = "dragonfly", target_os = "freebsd", +- all(target_os = "linux", not(any(target_env = "musl", +- target_arch = "mips", +- target_arch = "mips64")))))] ++ #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))] + SeekHole = libc::SEEK_HOLE + } + +@@ -1007,13 +1051,13 @@ pub fn lseek64(fd: RawFd, offset: libc::off64_t, whence: Whence) -> Result<libc: + /// See also [pipe(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pipe.html) + pub fn pipe() -> Result<(RawFd, RawFd)> { + unsafe { +- let mut fds: [c_int; 2] = mem::uninitialized(); ++ let mut fds = mem::MaybeUninit::<[c_int; 2]>::uninit(); + +- let res = libc::pipe(fds.as_mut_ptr()); ++ let res = libc::pipe(fds.as_mut_ptr() as *mut c_int); + + Errno::result(res)?; + +- Ok((fds[0], fds[1])) ++ Ok((fds.assume_init()[0], fds.assume_init()[1])) + } + } + +@@ -1022,7 +1066,9 @@ pub fn pipe() -> Result<(RawFd, RawFd)> { + /// The following flags are supported, and will be set atomically as the pipe is + /// created: + /// +-/// `O_CLOEXEC`: Set the close-on-exec flag for the new file descriptors. ++/// `O_CLOEXEC`: Set the close-on-exec flag for the new file descriptors. ++#[cfg_attr(target_os = "linux", doc = "`O_DIRECT`: Create a pipe that performs I/O in \"packet\" mode. ")] ++#[cfg_attr(target_os = "netbsd", doc = "`O_NOSIGPIPE`: Return `EPIPE` instead of raising `SIGPIPE`. ")] + /// `O_NONBLOCK`: Set the non-blocking flag for the ends of the pipe. + /// + /// See also [pipe(2)](http://man7.org/linux/man-pages/man2/pipe.2.html) +@@ -1031,74 +1077,26 @@ pub fn pipe() -> Result<(RawFd, RawFd)> { + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", ++ target_os = "redox", + target_os = "netbsd", + target_os = "openbsd"))] + pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> { +- let mut fds: [c_int; 2] = unsafe { mem::uninitialized() }; +- +- let res = unsafe { libc::pipe2(fds.as_mut_ptr(), flags.bits()) }; +- +- Errno::result(res)?; +- +- Ok((fds[0], fds[1])) +-} ++ let mut fds = mem::MaybeUninit::<[c_int; 2]>::uninit(); + +-/// Like `pipe`, but allows setting certain file descriptor flags. +-/// +-/// The following flags are supported, and will be set after the pipe is +-/// created: +-/// +-/// `O_CLOEXEC`: Set the close-on-exec flag for the new file descriptors. +-/// `O_NONBLOCK`: Set the non-blocking flag for the ends of the pipe. +-#[cfg(any(target_os = "ios", target_os = "macos"))] +-#[deprecated( +- since="0.10.0", +- note="pipe2(2) is not actually atomic on these platforms. Use pipe(2) and fcntl(2) instead" +-)] +-pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> { +- let mut fds: [c_int; 2] = unsafe { mem::uninitialized() }; +- +- let res = unsafe { libc::pipe(fds.as_mut_ptr()) }; ++ let res = unsafe { ++ libc::pipe2(fds.as_mut_ptr() as *mut c_int, flags.bits()) ++ }; + + Errno::result(res)?; + +- pipe2_setflags(fds[0], fds[1], flags)?; +- +- Ok((fds[0], fds[1])) +-} +- +-#[cfg(any(target_os = "ios", target_os = "macos"))] +-fn pipe2_setflags(fd1: RawFd, fd2: RawFd, flags: OFlag) -> Result<()> { +- use fcntl::FcntlArg::F_SETFL; +- +- let mut res = Ok(0); +- +- if flags.contains(OFlag::O_CLOEXEC) { +- res = res +- .and_then(|_| fcntl(fd1, F_SETFD(FdFlag::FD_CLOEXEC))) +- .and_then(|_| fcntl(fd2, F_SETFD(FdFlag::FD_CLOEXEC))); +- } +- +- if flags.contains(OFlag::O_NONBLOCK) { +- res = res +- .and_then(|_| fcntl(fd1, F_SETFL(OFlag::O_NONBLOCK))) +- .and_then(|_| fcntl(fd2, F_SETFL(OFlag::O_NONBLOCK))); +- } +- +- match res { +- Ok(_) => Ok(()), +- Err(e) => { +- let _ = close(fd1); +- let _ = close(fd2); +- Err(e) +- } +- } ++ unsafe { Ok((fds.assume_init()[0], fds.assume_init()[1])) } + } + + /// Truncate a file to a specified length + /// + /// See also + /// [truncate(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/truncate.html) ++#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] + pub fn truncate<P: ?Sized + NixPath>(path: &P, len: off_t) -> Result<()> { + let res = path.with_nix_path(|cstr| { + unsafe { +@@ -1132,6 +1130,59 @@ pub fn isatty(fd: RawFd) -> Result<bool> { + } + } + ++/// Flags for `linkat` function. ++#[derive(Clone, Copy, Debug)] ++pub enum LinkatFlags { ++ SymlinkFollow, ++ NoSymlinkFollow, ++} ++ ++/// Link one file to another file ++/// ++/// Creates a new link (directory entry) at `newpath` for the existing file at `oldpath`. In the ++/// case of a relative `oldpath`, the path is interpreted relative to the directory associated ++/// with file descriptor `olddirfd` instead of the current working directory and similiarly for ++/// `newpath` and file descriptor `newdirfd`. In case `flag` is LinkatFlags::SymlinkFollow and ++/// `oldpath` names a symoblic link, a new link for the target of the symbolic link is created. ++/// If either `olddirfd` or `newdirfd` is `None`, `AT_FDCWD` is used respectively where `oldpath` ++/// and/or `newpath` is then interpreted relative to the current working directory of the calling ++/// process. If either `oldpath` or `newpath` is absolute, then `dirfd` is ignored. ++/// ++/// # References ++/// See also [linkat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/linkat.html) ++#[cfg(not(target_os = "redox"))] // RedoxFS does not support symlinks yet ++pub fn linkat<P: ?Sized + NixPath>( ++ olddirfd: Option<RawFd>, ++ oldpath: &P, ++ newdirfd: Option<RawFd>, ++ newpath: &P, ++ flag: LinkatFlags, ++) -> Result<()> { ++ ++ let atflag = ++ match flag { ++ LinkatFlags::SymlinkFollow => AtFlags::AT_SYMLINK_FOLLOW, ++ LinkatFlags::NoSymlinkFollow => AtFlags::empty(), ++ }; ++ ++ let res = ++ oldpath.with_nix_path(|oldcstr| { ++ newpath.with_nix_path(|newcstr| { ++ unsafe { ++ libc::linkat( ++ at_rawfd(olddirfd), ++ oldcstr.as_ptr(), ++ at_rawfd(newdirfd), ++ newcstr.as_ptr(), ++ atflag.bits() as libc::c_int ++ ) ++ } ++ }) ++ })??; ++ Errno::result(res).map(drop) ++} ++ ++ + /// Remove a directory entry + /// + /// See also [unlink(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/unlink.html) +@@ -1161,6 +1212,7 @@ pub enum UnlinkatFlags { + /// + /// # References + /// See also [unlinkat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/unlinkat.html) ++#[cfg(not(target_os = "redox"))] + pub fn unlinkat<P: ?Sized + NixPath>( + dirfd: Option<RawFd>, + path: &P, +@@ -1181,6 +1233,7 @@ pub fn unlinkat<P: ?Sized + NixPath>( + + + #[inline] ++#[cfg(not(target_os = "fuchsia"))] + pub fn chroot<P: ?Sized + NixPath>(path: &P) -> Result<()> { + let res = path.with_nix_path(|cstr| { + unsafe { libc::chroot(cstr.as_ptr()) } +@@ -1199,7 +1252,7 @@ pub fn chroot<P: ?Sized + NixPath>(path: &P) -> Result<()> { + target_os = "netbsd", + target_os = "openbsd" + ))] +-pub fn sync() -> () { ++pub fn sync() { + unsafe { libc::sync() }; + } + +@@ -1309,6 +1362,28 @@ pub fn setgid(gid: Gid) -> Result<()> { + Errno::result(res).map(drop) + } + ++/// Set the user identity used for filesystem checks per-thread. ++/// On both success and failure, this call returns the previous filesystem user ++/// ID of the caller. ++/// ++/// See also [setfsuid(2)](http://man7.org/linux/man-pages/man2/setfsuid.2.html) ++#[cfg(any(target_os = "linux", target_os = "android"))] ++pub fn setfsuid(uid: Uid) -> Uid { ++ let prev_fsuid = unsafe { libc::setfsuid(uid.into()) }; ++ Uid::from_raw(prev_fsuid as uid_t) ++} ++ ++/// Set the group identity used for filesystem checks per-thread. ++/// On both success and failure, this call returns the previous filesystem group ++/// ID of the caller. ++/// ++/// See also [setfsgid(2)](http://man7.org/linux/man-pages/man2/setfsgid.2.html) ++#[cfg(any(target_os = "linux", target_os = "android"))] ++pub fn setfsgid(gid: Gid) -> Gid { ++ let prev_fsgid = unsafe { libc::setfsgid(gid.into()) }; ++ Gid::from_raw(prev_fsgid as gid_t) ++} ++ + /// Get the list of supplementary group IDs of the calling process. + /// + /// [Further reading](http://pubs.opengroup.org/onlinepubs/009695399/functions/getgroups.html) +@@ -1318,33 +1393,39 @@ pub fn setgid(gid: Gid) -> Result<()> { + /// with the `opendirectoryd` service. + #[cfg(not(any(target_os = "ios", target_os = "macos")))] + pub fn getgroups() -> Result<Vec<Gid>> { +- // First get the number of groups so we can size our Vec +- let ret = unsafe { libc::getgroups(0, ptr::null_mut()) }; ++ // First get the maximum number of groups. The value returned ++ // shall always be greater than or equal to one and less than or ++ // equal to the value of {NGROUPS_MAX} + 1. ++ let ngroups_max = match sysconf(SysconfVar::NGROUPS_MAX) { ++ Ok(Some(n)) => (n + 1) as usize, ++ Ok(None) | Err(_) => <usize>::max_value(), ++ }; ++ ++ // Next, get the number of groups so we can size our Vec ++ let ngroups = unsafe { libc::getgroups(0, ptr::null_mut()) }; + + // Now actually get the groups. We try multiple times in case the number of + // groups has changed since the first call to getgroups() and the buffer is + // now too small. +- let mut groups = Vec::<Gid>::with_capacity(Errno::result(ret)? as usize); ++ let mut groups = Vec::<Gid>::with_capacity(Errno::result(ngroups)? as usize); + loop { + // FIXME: On the platforms we currently support, the `Gid` struct has + // the same representation in memory as a bare `gid_t`. This is not + // necessarily the case on all Rust platforms, though. See RFC 1785. +- let ret = unsafe { ++ let ngroups = unsafe { + libc::getgroups(groups.capacity() as c_int, groups.as_mut_ptr() as *mut gid_t) + }; + +- match Errno::result(ret) { ++ match Errno::result(ngroups) { + Ok(s) => { + unsafe { groups.set_len(s as usize) }; + return Ok(groups); + }, + Err(Error::Sys(Errno::EINVAL)) => { +- // EINVAL indicates that the buffer size was too small. Trigger +- // the internal buffer resizing logic of `Vec` by requiring +- // more space than the current capacity. +- let cap = groups.capacity(); +- unsafe { groups.set_len(cap) }; +- groups.reserve(1); ++ // EINVAL indicates that the buffer size was too ++ // small, resize it up to ngroups_max as limit. ++ reserve_double_buffer_size(&mut groups, ngroups_max) ++ .or(Err(Error::Sys(Errno::EINVAL)))?; + }, + Err(e) => return Err(e) + } +@@ -1380,11 +1461,9 @@ pub fn getgroups() -> Result<Vec<Gid>> { + /// # Ok(()) + /// # } + /// # +-/// # fn main() { +-/// # try_main().unwrap(); +-/// # } ++/// # try_main().unwrap(); + /// ``` +-#[cfg(not(any(target_os = "ios", target_os = "macos")))] ++#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox")))] + pub fn setgroups(groups: &[Gid]) -> Result<()> { + cfg_if! { + if #[cfg(any(target_os = "dragonfly", +@@ -1428,15 +1507,14 @@ pub fn setgroups(groups: &[Gid]) -> Result<()> { + /// and `setgroups()`. Additionally, while some implementations will return a + /// partial list of groups when `NGROUPS_MAX` is exceeded, this implementation + /// will only ever return the complete list or else an error. +-#[cfg(not(any(target_os = "ios", target_os = "macos")))] ++#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox")))] + pub fn getgrouplist(user: &CStr, group: Gid) -> Result<Vec<Gid>> { + let ngroups_max = match sysconf(SysconfVar::NGROUPS_MAX) { + Ok(Some(n)) => n as c_int, + Ok(None) | Err(_) => <c_int>::max_value(), + }; + use std::cmp::min; +- let mut ngroups = min(ngroups_max, 8); +- let mut groups = Vec::<Gid>::with_capacity(ngroups as usize); ++ let mut groups = Vec::<Gid>::with_capacity(min(ngroups_max, 8) as usize); + cfg_if! { + if #[cfg(any(target_os = "ios", target_os = "macos"))] { + type getgrouplist_group_t = c_int; +@@ -1446,6 +1524,7 @@ pub fn getgrouplist(user: &CStr, group: Gid) -> Result<Vec<Gid>> { + } + let gid: gid_t = group.into(); + loop { ++ let mut ngroups = groups.capacity() as i32; + let ret = unsafe { + libc::getgrouplist(user.as_ptr(), + gid as getgrouplist_group_t, +@@ -1462,19 +1541,8 @@ pub fn getgrouplist(user: &CStr, group: Gid) -> Result<Vec<Gid>> { + // BSD systems will still fill the groups buffer with as many + // groups as possible, but Linux manpages do not mention this + // behavior. +- +- let cap = groups.capacity(); +- if cap >= ngroups_max as usize { +- // We already have the largest capacity we can, give up +- return Err(Error::invalid_argument()); +- } +- +- // Reserve space for at least ngroups +- groups.reserve(ngroups as usize); +- +- // Even if the buffer gets resized to bigger than ngroups_max, +- // don't ever ask for more than ngroups_max groups +- ngroups = min(ngroups_max, groups.capacity() as c_int); ++ reserve_double_buffer_size(&mut groups, ngroups_max as usize) ++ .or_else(|_| Err(Error::invalid_argument()))?; + } + } + } +@@ -1515,11 +1583,9 @@ pub fn getgrouplist(user: &CStr, group: Gid) -> Result<Vec<Gid>> { + /// # Ok(()) + /// # } + /// # +-/// # fn main() { +-/// # try_main().unwrap(); +-/// # } ++/// # try_main().unwrap(); + /// ``` +-#[cfg(not(any(target_os = "ios", target_os = "macos")))] ++#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox")))] + pub fn initgroups(user: &CStr, group: Gid) -> Result<()> { + cfg_if! { + if #[cfg(any(target_os = "ios", target_os = "macos"))] { +@@ -1538,6 +1604,7 @@ pub fn initgroups(user: &CStr, group: Gid) -> Result<()> { + /// + /// See also [pause(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pause.html). + #[inline] ++#[cfg(not(target_os = "redox"))] + pub fn pause() { + unsafe { libc::pause() }; + } +@@ -1568,7 +1635,8 @@ pub mod alarm { + //! + //! Scheduling an alarm and waiting for the signal: + //! +- //! ``` ++#![cfg_attr(target_os = "redox", doc = " ```rust,ignore")] ++#![cfg_attr(not(target_os = "redox"), doc = " ```rust")] + //! use std::time::{Duration, Instant}; + //! + //! use nix::unistd::{alarm, pause}; +@@ -1577,14 +1645,23 @@ pub mod alarm { + //! // We need to setup an empty signal handler to catch the alarm signal, + //! // otherwise the program will be terminated once the signal is delivered. + //! extern fn signal_handler(_: nix::libc::c_int) { } +- //! unsafe { sigaction(Signal::SIGALRM, &SigAction::new(SigHandler::Handler(signal_handler), SaFlags::empty(), SigSet::empty())); } ++ //! let sa = SigAction::new( ++ //! SigHandler::Handler(signal_handler), ++ //! SaFlags::empty(), ++ //! SigSet::empty() ++ //! ); ++ //! unsafe { ++ //! sigaction(Signal::SIGALRM, &sa); ++ //! } + //! + //! // Set an alarm for 1 second from now. + //! alarm::set(1); + //! + //! let start = Instant::now(); + //! // Pause the process until the alarm signal is received. +- //! pause(); ++ //! let mut sigset = SigSet::empty(); ++ //! sigset.add(Signal::SIGALRM); ++ //! sigset.wait(); + //! + //! assert!(start.elapsed() >= Duration::from_secs(1)); + //! ``` +@@ -1593,8 +1670,6 @@ pub mod alarm { + //! + //! See also [alarm(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/alarm.html). + +- use libc; +- + /// Schedule an alarm signal. + /// + /// This will cause the system to generate a `SIGALRM` signal for the +@@ -1630,10 +1705,10 @@ pub fn sleep(seconds: c_uint) -> c_uint { + unsafe { libc::sleep(seconds) } + } + ++#[cfg(not(target_os = "redox"))] + pub mod acct { +- use libc; +- use {Result, NixPath}; +- use errno::Errno; ++ use crate::{Result, NixPath}; ++ use crate::errno::Errno; + use std::ptr; + + /// Enable process accounting +@@ -1711,7 +1786,7 @@ pub fn mkstemp<P: ?Sized + NixPath>(template: &P) -> Result<(RawFd, PathBuf)> { + #[repr(i32)] + pub enum PathconfVar { + #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "linux", +- target_os = "netbsd", target_os = "openbsd"))] ++ target_os = "netbsd", target_os = "openbsd", target_os = "redox"))] + /// Minimum number of bits needed to represent, as a signed integer value, + /// the maximum size of a regular file allowed in the specified directory. + FILESIZEBITS = libc::_PC_FILESIZEBITS, +@@ -1735,11 +1810,11 @@ pub enum PathconfVar { + /// a pipe. + PIPE_BUF = libc::_PC_PIPE_BUF, + #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "linux", +- target_os = "netbsd", target_os = "openbsd"))] ++ target_os = "netbsd", target_os = "openbsd", target_os = "redox"))] + /// Symbolic links can be created. + POSIX2_SYMLINKS = libc::_PC_2_SYMLINKS, + #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", +- target_os = "linux", target_os = "openbsd"))] ++ target_os = "linux", target_os = "openbsd", target_os = "redox"))] + /// Minimum number of bytes of storage actually allocated for any portion of + /// a file. + POSIX_ALLOC_SIZE_MIN = libc::_PC_ALLOC_SIZE_MIN, +@@ -1749,19 +1824,20 @@ pub enum PathconfVar { + /// `POSIX_REC_MIN_XFER_SIZE` and `POSIX_REC_MAX_XFER_SIZE` values. + POSIX_REC_INCR_XFER_SIZE = libc::_PC_REC_INCR_XFER_SIZE, + #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", +- target_os = "linux", target_os = "openbsd"))] ++ target_os = "linux", target_os = "openbsd", target_os = "redox"))] + /// Maximum recommended file transfer size. + POSIX_REC_MAX_XFER_SIZE = libc::_PC_REC_MAX_XFER_SIZE, + #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", +- target_os = "linux", target_os = "openbsd"))] ++ target_os = "linux", target_os = "openbsd", target_os = "redox"))] + /// Minimum recommended file transfer size. + POSIX_REC_MIN_XFER_SIZE = libc::_PC_REC_MIN_XFER_SIZE, + #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", +- target_os = "linux", target_os = "openbsd"))] ++ target_os = "linux", target_os = "openbsd", target_os = "redox"))] + /// Recommended file transfer buffer alignment. + POSIX_REC_XFER_ALIGN = libc::_PC_REC_XFER_ALIGN, + #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", +- target_os = "linux", target_os = "netbsd", target_os = "openbsd"))] ++ target_os = "linux", target_os = "netbsd", target_os = "openbsd", ++ target_os = "redox"))] + /// Maximum number of bytes in a symbolic link. + SYMLINK_MAX = libc::_PC_SYMLINK_MAX, + /// The use of `chown` and `fchown` is restricted to a process with +@@ -1775,17 +1851,18 @@ pub enum PathconfVar { + /// disable terminal special character handling. + _POSIX_VDISABLE = libc::_PC_VDISABLE, + #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", +- target_os = "linux", target_os = "openbsd"))] ++ target_os = "linux", target_os = "openbsd", target_os = "redox"))] + /// Asynchronous input or output operations may be performed for the + /// associated file. + _POSIX_ASYNC_IO = libc::_PC_ASYNC_IO, + #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", +- target_os = "linux", target_os = "openbsd"))] ++ target_os = "linux", target_os = "openbsd", target_os = "redox"))] + /// Prioritized input or output operations may be performed for the + /// associated file. + _POSIX_PRIO_IO = libc::_PC_PRIO_IO, + #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", +- target_os = "linux", target_os = "netbsd", target_os = "openbsd"))] ++ target_os = "linux", target_os = "netbsd", target_os = "openbsd", ++ target_os = "redox"))] + /// Synchronized input or output operations may be performed for the + /// associated file. + _POSIX_SYNC_IO = libc::_PC_SYNC_IO, +@@ -1886,9 +1963,11 @@ pub fn pathconf<P: ?Sized + NixPath>(path: &P, var: PathconfVar) -> Result<Optio + pub enum SysconfVar { + /// Maximum number of I/O operations in a single list I/O call supported by + /// the implementation. ++ #[cfg(not(target_os = "redox"))] + AIO_LISTIO_MAX = libc::_SC_AIO_LISTIO_MAX, + /// Maximum number of outstanding asynchronous I/O operations supported by + /// the implementation. ++ #[cfg(not(target_os = "redox"))] + AIO_MAX = libc::_SC_AIO_MAX, + #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", + target_os = "ios", target_os="linux", target_os = "macos", +@@ -1899,25 +1978,34 @@ pub enum SysconfVar { + /// Maximum length of argument to the exec functions including environment data. + ARG_MAX = libc::_SC_ARG_MAX, + /// Maximum number of functions that may be registered with `atexit`. ++ #[cfg(not(target_os = "redox"))] + ATEXIT_MAX = libc::_SC_ATEXIT_MAX, + /// Maximum obase values allowed by the bc utility. ++ #[cfg(not(target_os = "redox"))] + BC_BASE_MAX = libc::_SC_BC_BASE_MAX, + /// Maximum number of elements permitted in an array by the bc utility. ++ #[cfg(not(target_os = "redox"))] + BC_DIM_MAX = libc::_SC_BC_DIM_MAX, + /// Maximum scale value allowed by the bc utility. ++ #[cfg(not(target_os = "redox"))] + BC_SCALE_MAX = libc::_SC_BC_SCALE_MAX, + /// Maximum length of a string constant accepted by the bc utility. ++ #[cfg(not(target_os = "redox"))] + BC_STRING_MAX = libc::_SC_BC_STRING_MAX, + /// Maximum number of simultaneous processes per real user ID. + CHILD_MAX = libc::_SC_CHILD_MAX, +- // _SC_CLK_TCK is obsolete ++ // The number of clock ticks per second. ++ CLK_TCK = libc::_SC_CLK_TCK, + /// Maximum number of weights that can be assigned to an entry of the + /// LC_COLLATE order keyword in the locale definition file ++ #[cfg(not(target_os = "redox"))] + COLL_WEIGHTS_MAX = libc::_SC_COLL_WEIGHTS_MAX, + /// Maximum number of timer expiration overruns. ++ #[cfg(not(target_os = "redox"))] + DELAYTIMER_MAX = libc::_SC_DELAYTIMER_MAX, + /// Maximum number of expressions that can be nested within parentheses by + /// the expr utility. ++ #[cfg(not(target_os = "redox"))] + EXPR_NEST_MAX = libc::_SC_EXPR_NEST_MAX, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="netbsd", +@@ -1927,23 +2015,29 @@ pub enum SysconfVar { + HOST_NAME_MAX = libc::_SC_HOST_NAME_MAX, + /// Maximum number of iovec structures that one process has available for + /// use with `readv` or `writev`. ++ #[cfg(not(target_os = "redox"))] + IOV_MAX = libc::_SC_IOV_MAX, + /// Unless otherwise noted, the maximum length, in bytes, of a utility's + /// input line (either standard input or another file), when the utility is + /// described as processing text files. The length includes room for the + /// trailing <newline>. ++ #[cfg(not(target_os = "redox"))] + LINE_MAX = libc::_SC_LINE_MAX, + /// Maximum length of a login name. + LOGIN_NAME_MAX = libc::_SC_LOGIN_NAME_MAX, + /// Maximum number of simultaneous supplementary group IDs per process. + NGROUPS_MAX = libc::_SC_NGROUPS_MAX, + /// Initial size of `getgrgid_r` and `getgrnam_r` data buffers ++ #[cfg(not(target_os = "redox"))] + GETGR_R_SIZE_MAX = libc::_SC_GETGR_R_SIZE_MAX, + /// Initial size of `getpwuid_r` and `getpwnam_r` data buffers ++ #[cfg(not(target_os = "redox"))] + GETPW_R_SIZE_MAX = libc::_SC_GETPW_R_SIZE_MAX, + /// The maximum number of open message queue descriptors a process may hold. ++ #[cfg(not(target_os = "redox"))] + MQ_OPEN_MAX = libc::_SC_MQ_OPEN_MAX, + /// The maximum number of message priorities supported by the implementation. ++ #[cfg(not(target_os = "redox"))] + MQ_PRIO_MAX = libc::_SC_MQ_PRIO_MAX, + /// A value one greater than the maximum value that the system may assign to + /// a newly-created file descriptor. +@@ -1958,6 +2052,7 @@ pub enum SysconfVar { + /// The implementation supports barriers. + _POSIX_BARRIERS = libc::_SC_BARRIERS, + /// The implementation supports asynchronous input and output. ++ #[cfg(not(target_os = "redox"))] + _POSIX_ASYNCHRONOUS_IO = libc::_SC_ASYNCHRONOUS_IO, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="netbsd", +@@ -1970,24 +2065,32 @@ pub enum SysconfVar { + /// The implementation supports the Process CPU-Time Clocks option. + _POSIX_CPUTIME = libc::_SC_CPUTIME, + /// The implementation supports the File Synchronization option. ++ #[cfg(not(target_os = "redox"))] + _POSIX_FSYNC = libc::_SC_FSYNC, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="openbsd"))] + /// The implementation supports the IPv6 option. + _POSIX_IPV6 = libc::_SC_IPV6, + /// The implementation supports job control. ++ #[cfg(not(target_os = "redox"))] + _POSIX_JOB_CONTROL = libc::_SC_JOB_CONTROL, + /// The implementation supports memory mapped Files. ++ #[cfg(not(target_os = "redox"))] + _POSIX_MAPPED_FILES = libc::_SC_MAPPED_FILES, + /// The implementation supports the Process Memory Locking option. ++ #[cfg(not(target_os = "redox"))] + _POSIX_MEMLOCK = libc::_SC_MEMLOCK, + /// The implementation supports the Range Memory Locking option. ++ #[cfg(not(target_os = "redox"))] + _POSIX_MEMLOCK_RANGE = libc::_SC_MEMLOCK_RANGE, + /// The implementation supports memory protection. ++ #[cfg(not(target_os = "redox"))] + _POSIX_MEMORY_PROTECTION = libc::_SC_MEMORY_PROTECTION, + /// The implementation supports the Message Passing option. ++ #[cfg(not(target_os = "redox"))] + _POSIX_MESSAGE_PASSING = libc::_SC_MESSAGE_PASSING, + /// The implementation supports the Monotonic Clock option. ++ #[cfg(not(target_os = "redox"))] + _POSIX_MONOTONIC_CLOCK = libc::_SC_MONOTONIC_CLOCK, + #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", + target_os = "ios", target_os="linux", target_os = "macos", +@@ -1995,6 +2098,7 @@ pub enum SysconfVar { + /// The implementation supports the Prioritized Input and Output option. + _POSIX_PRIORITIZED_IO = libc::_SC_PRIORITIZED_IO, + /// The implementation supports the Process Scheduling option. ++ #[cfg(not(target_os = "redox"))] + _POSIX_PRIORITY_SCHEDULING = libc::_SC_PRIORITY_SCHEDULING, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="openbsd"))] +@@ -2016,10 +2120,13 @@ pub enum SysconfVar { + /// The implementation supports the Regular Expression Handling option. + _POSIX_REGEXP = libc::_SC_REGEXP, + /// Each process has a saved set-user-ID and a saved set-group-ID. ++ #[cfg(not(target_os = "redox"))] + _POSIX_SAVED_IDS = libc::_SC_SAVED_IDS, + /// The implementation supports semaphores. ++ #[cfg(not(target_os = "redox"))] + _POSIX_SEMAPHORES = libc::_SC_SEMAPHORES, + /// The implementation supports the Shared Memory Objects option. ++ #[cfg(not(target_os = "redox"))] + _POSIX_SHARED_MEMORY_OBJECTS = libc::_SC_SHARED_MEMORY_OBJECTS, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="netbsd", +@@ -2044,10 +2151,13 @@ pub enum SysconfVar { + target_os="openbsd"))] + _POSIX_SS_REPL_MAX = libc::_SC_SS_REPL_MAX, + /// The implementation supports the Synchronized Input and Output option. ++ #[cfg(not(target_os = "redox"))] + _POSIX_SYNCHRONIZED_IO = libc::_SC_SYNCHRONIZED_IO, + /// The implementation supports the Thread Stack Address Attribute option. ++ #[cfg(not(target_os = "redox"))] + _POSIX_THREAD_ATTR_STACKADDR = libc::_SC_THREAD_ATTR_STACKADDR, + /// The implementation supports the Thread Stack Size Attribute option. ++ #[cfg(not(target_os = "redox"))] + _POSIX_THREAD_ATTR_STACKSIZE = libc::_SC_THREAD_ATTR_STACKSIZE, + #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos", + target_os="netbsd", target_os="openbsd"))] +@@ -2055,10 +2165,13 @@ pub enum SysconfVar { + _POSIX_THREAD_CPUTIME = libc::_SC_THREAD_CPUTIME, + /// The implementation supports the Non-Robust Mutex Priority Inheritance + /// option. ++ #[cfg(not(target_os = "redox"))] + _POSIX_THREAD_PRIO_INHERIT = libc::_SC_THREAD_PRIO_INHERIT, + /// The implementation supports the Non-Robust Mutex Priority Protection option. ++ #[cfg(not(target_os = "redox"))] + _POSIX_THREAD_PRIO_PROTECT = libc::_SC_THREAD_PRIO_PROTECT, + /// The implementation supports the Thread Execution Scheduling option. ++ #[cfg(not(target_os = "redox"))] + _POSIX_THREAD_PRIORITY_SCHEDULING = libc::_SC_THREAD_PRIORITY_SCHEDULING, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="netbsd", +@@ -2073,18 +2186,21 @@ pub enum SysconfVar { + /// The implementation supports the Robust Mutex Priority Protection option. + _POSIX_THREAD_ROBUST_PRIO_PROTECT = libc::_SC_THREAD_ROBUST_PRIO_PROTECT, + /// The implementation supports thread-safe functions. ++ #[cfg(not(target_os = "redox"))] + _POSIX_THREAD_SAFE_FUNCTIONS = libc::_SC_THREAD_SAFE_FUNCTIONS, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="openbsd"))] + /// The implementation supports the Thread Sporadic Server option. + _POSIX_THREAD_SPORADIC_SERVER = libc::_SC_THREAD_SPORADIC_SERVER, + /// The implementation supports threads. ++ #[cfg(not(target_os = "redox"))] + _POSIX_THREADS = libc::_SC_THREADS, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="openbsd"))] + /// The implementation supports timeouts. + _POSIX_TIMEOUTS = libc::_SC_TIMEOUTS, + /// The implementation supports timers. ++ #[cfg(not(target_os = "redox"))] + _POSIX_TIMERS = libc::_SC_TIMERS, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="openbsd"))] +@@ -2149,17 +2265,23 @@ pub enum SysconfVar { + /// using at least 64 bits. + _POSIX_V6_LPBIG_OFFBIG = libc::_SC_V6_LPBIG_OFFBIG, + /// The implementation supports the C-Language Binding option. ++ #[cfg(not(target_os = "redox"))] + _POSIX2_C_BIND = libc::_SC_2_C_BIND, + /// The implementation supports the C-Language Development Utilities option. ++ #[cfg(not(target_os = "redox"))] + _POSIX2_C_DEV = libc::_SC_2_C_DEV, + /// The implementation supports the Terminal Characteristics option. ++ #[cfg(not(target_os = "redox"))] + _POSIX2_CHAR_TERM = libc::_SC_2_CHAR_TERM, + /// The implementation supports the FORTRAN Development Utilities option. ++ #[cfg(not(target_os = "redox"))] + _POSIX2_FORT_DEV = libc::_SC_2_FORT_DEV, + /// The implementation supports the FORTRAN Runtime Utilities option. ++ #[cfg(not(target_os = "redox"))] + _POSIX2_FORT_RUN = libc::_SC_2_FORT_RUN, + /// The implementation supports the creation of locales by the localedef + /// utility. ++ #[cfg(not(target_os = "redox"))] + _POSIX2_LOCALEDEF = libc::_SC_2_LOCALEDEF, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="netbsd", +@@ -2193,26 +2315,34 @@ pub enum SysconfVar { + /// The implementation supports the Track Batch Job Request option. + _POSIX2_PBS_TRACK = libc::_SC_2_PBS_TRACK, + /// The implementation supports the Software Development Utilities option. ++ #[cfg(not(target_os = "redox"))] + _POSIX2_SW_DEV = libc::_SC_2_SW_DEV, + /// The implementation supports the User Portability Utilities option. ++ #[cfg(not(target_os = "redox"))] + _POSIX2_UPE = libc::_SC_2_UPE, + /// Integer value indicating version of the Shell and Utilities volume of + /// POSIX.1 to which the implementation conforms. ++ #[cfg(not(target_os = "redox"))] + _POSIX2_VERSION = libc::_SC_2_VERSION, + /// The size of a system page in bytes. + /// + /// POSIX also defines an alias named `PAGESIZE`, but Rust does not allow two + /// enum constants to have the same value, so nix omits `PAGESIZE`. + PAGE_SIZE = libc::_SC_PAGE_SIZE, ++ #[cfg(not(target_os = "redox"))] + PTHREAD_DESTRUCTOR_ITERATIONS = libc::_SC_THREAD_DESTRUCTOR_ITERATIONS, ++ #[cfg(not(target_os = "redox"))] + PTHREAD_KEYS_MAX = libc::_SC_THREAD_KEYS_MAX, ++ #[cfg(not(target_os = "redox"))] + PTHREAD_STACK_MIN = libc::_SC_THREAD_STACK_MIN, ++ #[cfg(not(target_os = "redox"))] + PTHREAD_THREADS_MAX = libc::_SC_THREAD_THREADS_MAX, + RE_DUP_MAX = libc::_SC_RE_DUP_MAX, + #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", + target_os = "ios", target_os="linux", target_os = "macos", + target_os="openbsd"))] + RTSIG_MAX = libc::_SC_RTSIG_MAX, ++ #[cfg(not(target_os = "redox"))] + SEM_NSEMS_MAX = libc::_SC_SEM_NSEMS_MAX, + #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", + target_os = "ios", target_os="linux", target_os = "macos", +@@ -2227,6 +2357,7 @@ pub enum SysconfVar { + target_os="linux", target_os = "macos", target_os="netbsd", + target_os="openbsd"))] + SYMLOOP_MAX = libc::_SC_SYMLOOP_MAX, ++ #[cfg(not(target_os = "redox"))] + TIMER_MAX = libc::_SC_TIMER_MAX, + TTY_NAME_MAX = libc::_SC_TTY_NAME_MAX, + TZNAME_MAX = libc::_SC_TZNAME_MAX, +@@ -2257,6 +2388,7 @@ pub enum SysconfVar { + _XOPEN_REALTIME_THREADS = libc::_SC_XOPEN_REALTIME_THREADS, + /// The implementation supports the Issue 4, Version 2 Shared Memory Option + /// Group. ++ #[cfg(not(target_os = "redox"))] + _XOPEN_SHM = libc::_SC_XOPEN_SHM, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="openbsd"))] +@@ -2309,9 +2441,8 @@ pub fn sysconf(var: SysconfVar) -> Result<Option<c_long>> { + + #[cfg(any(target_os = "android", target_os = "linux"))] + mod pivot_root { +- use libc; +- use {Result, NixPath}; +- use errno::Errno; ++ use crate::{Result, NixPath}; ++ use crate::errno::Errno; + + pub fn pivot_root<P1: ?Sized + NixPath, P2: ?Sized + NixPath>( + new_root: &P1, put_old: &P2) -> Result<()> { +@@ -2330,9 +2461,8 @@ mod pivot_root { + #[cfg(any(target_os = "android", target_os = "freebsd", + target_os = "linux", target_os = "openbsd"))] + mod setres { +- use libc; +- use Result; +- use errno::Errno; ++ use crate::Result; ++ use crate::errno::Errno; + use super::{Uid, Gid}; + + /// Sets the real, effective, and saved uid. +@@ -2392,3 +2522,308 @@ pub fn access<P: ?Sized + NixPath>(path: &P, amode: AccessFlags) -> Result<()> { + })?; + Errno::result(res).map(drop) + } ++ ++/// Representation of a User, based on `libc::passwd` ++/// ++/// The reason some fields in this struct are `String` and others are `CString` is because some ++/// fields are based on the user's locale, which could be non-UTF8, while other fields are ++/// guaranteed to conform to [`NAME_REGEX`](https://serverfault.com/a/73101/407341), which only ++/// contains ASCII. ++#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd ++#[derive(Debug, Clone, PartialEq)] ++pub struct User { ++ /// Username ++ pub name: String, ++ /// User password (probably encrypted) ++ pub passwd: CString, ++ /// User ID ++ pub uid: Uid, ++ /// Group ID ++ pub gid: Gid, ++ /// User information ++ #[cfg(not(target_os = "android"))] ++ pub gecos: CString, ++ /// Home directory ++ pub dir: PathBuf, ++ /// Path to shell ++ pub shell: PathBuf, ++ /// Login class ++ #[cfg(not(any(target_os = "android", target_os = "fuchsia", ++ target_os = "linux")))] ++ pub class: CString, ++ /// Last password change ++ #[cfg(not(any(target_os = "android", target_os = "fuchsia", ++ target_os = "linux")))] ++ pub change: libc::time_t, ++ /// Expiration time of account ++ #[cfg(not(any(target_os = "android", target_os = "fuchsia", ++ target_os = "linux")))] ++ pub expire: libc::time_t ++} ++ ++#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd ++impl From<&libc::passwd> for User { ++ fn from(pw: &libc::passwd) -> User { ++ unsafe { ++ User { ++ name: CStr::from_ptr((*pw).pw_name).to_string_lossy().into_owned(), ++ passwd: CString::new(CStr::from_ptr((*pw).pw_passwd).to_bytes()).unwrap(), ++ #[cfg(not(target_os = "android"))] ++ gecos: CString::new(CStr::from_ptr((*pw).pw_gecos).to_bytes()).unwrap(), ++ dir: PathBuf::from(OsStr::from_bytes(CStr::from_ptr((*pw).pw_dir).to_bytes())), ++ shell: PathBuf::from(OsStr::from_bytes(CStr::from_ptr((*pw).pw_shell).to_bytes())), ++ uid: Uid::from_raw((*pw).pw_uid), ++ gid: Gid::from_raw((*pw).pw_gid), ++ #[cfg(not(any(target_os = "android", target_os = "fuchsia", ++ target_os = "linux")))] ++ class: CString::new(CStr::from_ptr((*pw).pw_class).to_bytes()).unwrap(), ++ #[cfg(not(any(target_os = "android", target_os = "fuchsia", ++ target_os = "linux")))] ++ change: (*pw).pw_change, ++ #[cfg(not(any(target_os = "android", target_os = "fuchsia", ++ target_os = "linux")))] ++ expire: (*pw).pw_expire ++ } ++ } ++ } ++} ++ ++#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd ++impl User { ++ fn from_anything<F>(f: F) -> Result<Option<Self>> ++ where ++ F: Fn(*mut libc::passwd, ++ *mut libc::c_char, ++ libc::size_t, ++ *mut *mut libc::passwd) -> libc::c_int ++ { ++ let buflimit = 16384; ++ let bufsize = match sysconf(SysconfVar::GETPW_R_SIZE_MAX) { ++ Ok(Some(n)) => n as usize, ++ Ok(None) | Err(_) => buflimit as usize, ++ }; ++ ++ let mut cbuf = Vec::with_capacity(bufsize); ++ let mut pwd = mem::MaybeUninit::<libc::passwd>::uninit(); ++ let mut res = ptr::null_mut(); ++ ++ loop { ++ let error = f(pwd.as_mut_ptr(), cbuf.as_mut_ptr(), cbuf.capacity(), &mut res); ++ if error == 0 { ++ if res.is_null() { ++ return Ok(None); ++ } else { ++ let pwd = unsafe { pwd.assume_init() }; ++ return Ok(Some(User::from(&pwd))); ++ } ++ } else if Errno::last() == Errno::ERANGE { ++ // Trigger the internal buffer resizing logic. ++ reserve_double_buffer_size(&mut cbuf, buflimit)?; ++ } else { ++ return Err(Error::Sys(Errno::last())); ++ } ++ } ++ } ++ ++ /// Get a user by UID. ++ /// ++ /// Internally, this function calls ++ /// [getpwuid_r(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html) ++ /// ++ /// # Examples ++ /// ++ /// ``` ++ /// use nix::unistd::{Uid, User}; ++ /// // Returns an Result<Option<User>>, thus the double unwrap. ++ /// let res = User::from_uid(Uid::from_raw(0)).unwrap().unwrap(); ++ /// assert!(res.name == "root"); ++ /// ``` ++ pub fn from_uid(uid: Uid) -> Result<Option<Self>> { ++ User::from_anything(|pwd, cbuf, cap, res| { ++ unsafe { libc::getpwuid_r(uid.0, pwd, cbuf, cap, res) } ++ }) ++ } ++ ++ /// Get a user by name. ++ /// ++ /// Internally, this function calls ++ /// [getpwnam_r(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html) ++ /// ++ /// # Examples ++ /// ++ /// ``` ++ /// use nix::unistd::User; ++ /// // Returns an Result<Option<User>>, thus the double unwrap. ++ /// let res = User::from_name("root").unwrap().unwrap(); ++ /// assert!(res.name == "root"); ++ /// ``` ++ pub fn from_name(name: &str) -> Result<Option<Self>> { ++ let name = CString::new(name).unwrap(); ++ User::from_anything(|pwd, cbuf, cap, res| { ++ unsafe { libc::getpwnam_r(name.as_ptr(), pwd, cbuf, cap, res) } ++ }) ++ } ++} ++ ++/// Representation of a Group, based on `libc::group` ++#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd ++#[derive(Debug, Clone, PartialEq)] ++pub struct Group { ++ /// Group name ++ pub name: String, ++ /// Group password ++ pub passwd: CString, ++ /// Group ID ++ pub gid: Gid, ++ /// List of Group members ++ pub mem: Vec<String> ++} ++ ++#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd ++impl From<&libc::group> for Group { ++ fn from(gr: &libc::group) -> Group { ++ unsafe { ++ Group { ++ name: CStr::from_ptr((*gr).gr_name).to_string_lossy().into_owned(), ++ passwd: CString::new(CStr::from_ptr((*gr).gr_passwd).to_bytes()).unwrap(), ++ gid: Gid::from_raw((*gr).gr_gid), ++ mem: Group::members((*gr).gr_mem) ++ } ++ } ++ } ++} ++ ++#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd ++impl Group { ++ unsafe fn members(mem: *mut *mut c_char) -> Vec<String> { ++ let mut ret = Vec::new(); ++ ++ for i in 0.. { ++ let u = mem.offset(i); ++ if (*u).is_null() { ++ break; ++ } else { ++ let s = CStr::from_ptr(*u).to_string_lossy().into_owned(); ++ ret.push(s); ++ } ++ } ++ ++ ret ++ } ++ ++ fn from_anything<F>(f: F) -> Result<Option<Self>> ++ where ++ F: Fn(*mut libc::group, ++ *mut libc::c_char, ++ libc::size_t, ++ *mut *mut libc::group) -> libc::c_int ++ { ++ let buflimit = 16384; ++ let bufsize = match sysconf(SysconfVar::GETGR_R_SIZE_MAX) { ++ Ok(Some(n)) => n as usize, ++ Ok(None) | Err(_) => buflimit as usize, ++ }; ++ ++ let mut cbuf = Vec::with_capacity(bufsize); ++ let mut grp = mem::MaybeUninit::<libc::group>::uninit(); ++ let mut res = ptr::null_mut(); ++ ++ loop { ++ let error = f(grp.as_mut_ptr(), cbuf.as_mut_ptr(), cbuf.capacity(), &mut res); ++ if error == 0 { ++ if res.is_null() { ++ return Ok(None); ++ } else { ++ let grp = unsafe { grp.assume_init() }; ++ return Ok(Some(Group::from(&grp))); ++ } ++ } else if Errno::last() == Errno::ERANGE { ++ // Trigger the internal buffer resizing logic. ++ reserve_double_buffer_size(&mut cbuf, buflimit)?; ++ } else { ++ return Err(Error::Sys(Errno::last())); ++ } ++ } ++ } ++ ++ /// Get a group by GID. ++ /// ++ /// Internally, this function calls ++ /// [getgrgid_r(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html) ++ /// ++ /// # Examples ++ /// ++ // Disable this test on all OS except Linux as root group may not exist. ++ #[cfg_attr(not(target_os = "linux"), doc = " ```no_run")] ++ #[cfg_attr(target_os = "linux", doc = " ```")] ++ /// use nix::unistd::{Gid, Group}; ++ /// // Returns an Result<Option<Group>>, thus the double unwrap. ++ /// let res = Group::from_gid(Gid::from_raw(0)).unwrap().unwrap(); ++ /// assert!(res.name == "root"); ++ /// ``` ++ pub fn from_gid(gid: Gid) -> Result<Option<Self>> { ++ Group::from_anything(|grp, cbuf, cap, res| { ++ unsafe { libc::getgrgid_r(gid.0, grp, cbuf, cap, res) } ++ }) ++ } ++ ++ /// Get a group by name. ++ /// ++ /// Internally, this function calls ++ /// [getgrnam_r(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html) ++ /// ++ /// # Examples ++ /// ++ // Disable this test on all OS except Linux as root group may not exist. ++ #[cfg_attr(not(target_os = "linux"), doc = " ```no_run")] ++ #[cfg_attr(target_os = "linux", doc = " ```")] ++ /// use nix::unistd::Group; ++ /// // Returns an Result<Option<Group>>, thus the double unwrap. ++ /// let res = Group::from_name("root").unwrap().unwrap(); ++ /// assert!(res.name == "root"); ++ /// ``` ++ pub fn from_name(name: &str) -> Result<Option<Self>> { ++ let name = CString::new(name).unwrap(); ++ Group::from_anything(|grp, cbuf, cap, res| { ++ unsafe { libc::getgrnam_r(name.as_ptr(), grp, cbuf, cap, res) } ++ }) ++ } ++} ++ ++/// Get the name of the terminal device that is open on file descriptor fd ++/// (see [`ttyname(3)`](http://man7.org/linux/man-pages/man3/ttyname.3.html)). ++#[cfg(not(target_os = "fuchsia"))] ++pub fn ttyname(fd: RawFd) -> Result<PathBuf> { ++ const PATH_MAX: usize = libc::PATH_MAX as usize; ++ let mut buf = vec![0_u8; PATH_MAX]; ++ let c_buf = buf.as_mut_ptr() as *mut libc::c_char; ++ ++ let ret = unsafe { libc::ttyname_r(fd, c_buf, buf.len()) }; ++ if ret != 0 { ++ return Err(Error::Sys(Errno::from_i32(ret))); ++ } ++ ++ let nul = buf.iter().position(|c| *c == b'\0').unwrap(); ++ buf.truncate(nul); ++ Ok(OsString::from_vec(buf).into()) ++} ++ ++/// Get the effective user ID and group ID associated with a Unix domain socket. ++/// ++/// See also [getpeereid(3)](https://www.freebsd.org/cgi/man.cgi?query=getpeereid) ++#[cfg(any( ++ target_os = "macos", ++ target_os = "ios", ++ target_os = "freebsd", ++ target_os = "openbsd", ++ target_os = "netbsd", ++ target_os = "dragonfly", ++))] ++pub fn getpeereid(fd: RawFd) -> Result<(Uid, Gid)> { ++ let mut uid = 1; ++ let mut gid = 1; ++ ++ let ret = unsafe { libc::getpeereid(fd, &mut uid, &mut gid) }; ++ ++ Errno::result(ret).map(|_| (Uid(uid), Gid(gid))) ++} +diff --git a/third_party/rust/nix/test/common/mod.rs b/third_party/rust/nix/test/common/mod.rs +new file mode 100644 +index 0000000000000..a871b47041d3e +--- /dev/null ++++ b/third_party/rust/nix/test/common/mod.rs +@@ -0,0 +1,127 @@ ++use cfg_if::cfg_if; ++ ++#[macro_export] macro_rules! skip { ++ ($($reason: expr),+) => { ++ use ::std::io::{self, Write}; ++ ++ let stderr = io::stderr(); ++ let mut handle = stderr.lock(); ++ writeln!(handle, $($reason),+).unwrap(); ++ return; ++ } ++} ++ ++cfg_if! { ++ if #[cfg(any(target_os = "android", target_os = "linux"))] { ++ #[macro_export] macro_rules! require_capability { ++ ($capname:ident) => { ++ use ::caps::{Capability, CapSet, has_cap}; ++ ++ if !has_cap(None, CapSet::Effective, Capability::$capname) ++ .unwrap() ++ { ++ skip!("Insufficient capabilities. Skipping test."); ++ } ++ } ++ } ++ } else if #[cfg(not(target_os = "redox"))] { ++ #[macro_export] macro_rules! require_capability { ++ ($capname:ident) => {} ++ } ++ } ++} ++ ++#[cfg(any(target_os = "linux", target_os= "android"))] ++#[macro_export] macro_rules! skip_if_cirrus { ++ ($reason:expr) => { ++ if std::env::var_os("CIRRUS_CI").is_some() { ++ skip!("{}", $reason); ++ } ++ } ++} ++ ++#[cfg(target_os = "freebsd")] ++#[macro_export] macro_rules! skip_if_jailed { ++ ($name:expr) => { ++ use ::sysctl::CtlValue; ++ ++ if let CtlValue::Int(1) = ::sysctl::value("security.jail.jailed") ++ .unwrap() ++ { ++ skip!("{} cannot run in a jail. Skipping test.", $name); ++ } ++ } ++} ++ ++#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] ++#[macro_export] macro_rules! skip_if_not_root { ++ ($name:expr) => { ++ use nix::unistd::Uid; ++ ++ if !Uid::current().is_root() { ++ skip!("{} requires root privileges. Skipping test.", $name); ++ } ++ }; ++} ++ ++cfg_if! { ++ if #[cfg(any(target_os = "android", target_os = "linux"))] { ++ #[macro_export] macro_rules! skip_if_seccomp { ++ ($name:expr) => { ++ if let Ok(s) = std::fs::read_to_string("/proc/self/status") { ++ for l in s.lines() { ++ let mut fields = l.split_whitespace(); ++ if fields.next() == Some("Seccomp:") && ++ fields.next() != Some("0") ++ { ++ skip!("{} cannot be run in Seccomp mode. Skipping test.", ++ stringify!($name)); ++ } ++ } ++ } ++ } ++ } ++ } else if #[cfg(not(target_os = "redox"))] { ++ #[macro_export] macro_rules! skip_if_seccomp { ++ ($name:expr) => {} ++ } ++ } ++} ++ ++cfg_if! { ++ if #[cfg(target_os = "linux")] { ++ #[macro_export] macro_rules! require_kernel_version { ++ ($name:expr, $version_requirement:expr) => { ++ use semver::{Version, VersionReq}; ++ ++ let version_requirement = VersionReq::parse($version_requirement) ++ .expect("Bad match_version provided"); ++ ++ let uname = nix::sys::utsname::uname(); ++ println!("{}", uname.sysname()); ++ println!("{}", uname.nodename()); ++ println!("{}", uname.release()); ++ println!("{}", uname.version()); ++ println!("{}", uname.machine()); ++ ++ // Fix stuff that the semver parser can't handle ++ let fixed_release = &uname.release().to_string() ++ // Fedora 33 reports version as 4.18.el8_2.x86_64 or ++ // 5.18.200-fc33.x86_64. Remove the underscore. ++ .replace("_", "-") ++ // Cirrus-CI reports version as 4.19.112+ . Remove the + ++ .replace("+", ""); ++ let mut version = Version::parse(fixed_release).unwrap(); ++ ++ //Keep only numeric parts ++ version.pre.clear(); ++ version.build.clear(); ++ ++ if !version_requirement.matches(&version) { ++ skip!("Skip {} because kernel version `{}` doesn't match the requirement `{}`", ++ stringify!($name), version, version_requirement); ++ } ++ } ++ } ++ } ++} +diff --git a/third_party/rust/nix/test/sys/mod.rs b/third_party/rust/nix/test/sys/mod.rs +index 60a58dd106f19..14b03784a0a57 100644 +--- a/third_party/rust/nix/test/sys/mod.rs ++++ b/third_party/rust/nix/test/sys/mod.rs +@@ -13,12 +13,17 @@ mod test_signal; + mod test_aio; + #[cfg(target_os = "linux")] + mod test_signalfd; ++#[cfg(not(target_os = "redox"))] + mod test_socket; ++#[cfg(not(target_os = "redox"))] + mod test_sockopt; ++#[cfg(not(target_os = "redox"))] + mod test_select; + #[cfg(any(target_os = "android", target_os = "linux"))] + mod test_sysinfo; ++#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] + mod test_termios; ++#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] + mod test_ioctl; + mod test_wait; + mod test_uio; +@@ -36,3 +41,5 @@ mod test_pthread; + target_os = "netbsd", + target_os = "openbsd"))] + mod test_ptrace; ++#[cfg(any(target_os = "android", target_os = "linux"))] ++mod test_timerfd; +diff --git a/third_party/rust/nix/test/sys/test_aio.rs b/third_party/rust/nix/test/sys/test_aio.rs +index d4b09b0b81905..3878da94a6ef6 100644 +--- a/third_party/rust/nix/test/sys/test_aio.rs ++++ b/third_party/rust/nix/test/sys/test_aio.rs +@@ -47,7 +47,7 @@ fn test_accessors() { + // our bindings. So it's sufficient to check that AioCb.cancel returned any + // AioCancelStat value. + #[test] +-#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] ++#[cfg_attr(target_env = "musl", ignore)] + fn test_cancel() { + let wbuf: &[u8] = b"CDEF"; + +@@ -72,7 +72,7 @@ fn test_cancel() { + + // Tests using aio_cancel_all for all outstanding IOs. + #[test] +-#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] ++#[cfg_attr(target_env = "musl", ignore)] + fn test_aio_cancel_all() { + let wbuf: &[u8] = b"CDEF"; + +@@ -133,6 +133,13 @@ fn test_fsync_error() { + + #[test] + #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] ++// On Travis, aio_suspend hits an assertion within glibc. This is either a bug ++// in Travis's version of glibc or Linux. Either way, we must skip the test. ++// https://github.com/nix-rust/nix/issues/1099 ++#[cfg_attr(target_os = "linux", ignore)] ++// On Cirrus, aio_suspend is failing with EINVAL ++// https://github.com/nix-rust/nix/issues/1361 ++#[cfg_attr(target_os = "macos", ignore)] + fn test_aio_suspend() { + const INITIAL: &[u8] = b"abcdef123456"; + const WBUF: &[u8] = b"CDEFG"; +@@ -160,7 +167,12 @@ fn test_aio_suspend() { + loop { + { + let cbbuf = [&wcb, &rcb]; +- assert!(aio_suspend(&cbbuf[..], Some(timeout)).is_ok()); ++ let r = aio_suspend(&cbbuf[..], Some(timeout)); ++ match r { ++ Err(Error::Sys(Errno::EINTR)) => continue, ++ Err(e) => panic!("aio_suspend returned {:?}", e), ++ Ok(_) => () ++ }; + } + if rcb.error() != Err(Error::from(Errno::EINPROGRESS)) && + wcb.error() != Err(Error::from(Errno::EINPROGRESS)) { +@@ -168,8 +180,8 @@ fn test_aio_suspend() { + } + } + +- assert!(wcb.aio_return().unwrap() as usize == WBUF.len()); +- assert!(rcb.aio_return().unwrap() as usize == rlen); ++ assert_eq!(wcb.aio_return().unwrap() as usize, WBUF.len()); ++ assert_eq!(rcb.aio_return().unwrap() as usize, rlen); + } + + // Test a simple aio operation with no completion notification. We must poll +@@ -192,11 +204,11 @@ fn test_read() { + aiocb.read().unwrap(); + + let err = poll_aio(&mut aiocb); +- assert!(err == Ok(())); +- assert!(aiocb.aio_return().unwrap() as usize == EXPECT.len()); ++ assert_eq!(err, Ok(())); ++ assert_eq!(aiocb.aio_return().unwrap() as usize, EXPECT.len()); + } + +- assert!(EXPECT == rbuf.deref().deref()); ++ assert_eq!(EXPECT, rbuf.deref().deref()); + } + + /// `AioCb::read` should not modify the `AioCb` object if `libc::aio_read` +@@ -238,11 +250,11 @@ fn test_read_into_mut_slice() { + aiocb.read().unwrap(); + + let err = poll_aio(&mut aiocb); +- assert!(err == Ok(())); +- assert!(aiocb.aio_return().unwrap() as usize == EXPECT.len()); ++ assert_eq!(err, Ok(())); ++ assert_eq!(aiocb.aio_return().unwrap() as usize, EXPECT.len()); + } + +- assert!(rbuf == EXPECT); ++ assert_eq!(rbuf, EXPECT); + } + + // Tests from_ptr +@@ -268,11 +280,11 @@ fn test_read_into_pointer() { + aiocb.read().unwrap(); + + let err = poll_aio(&mut aiocb); +- assert!(err == Ok(())); +- assert!(aiocb.aio_return().unwrap() as usize == EXPECT.len()); ++ assert_eq!(err, Ok(())); ++ assert_eq!(aiocb.aio_return().unwrap() as usize, EXPECT.len()); + } + +- assert!(rbuf == EXPECT); ++ assert_eq!(rbuf, EXPECT); + } + + // Test reading into an immutable buffer. It should fail +@@ -314,13 +326,13 @@ fn test_write() { + aiocb.write().unwrap(); + + let err = poll_aio(&mut aiocb); +- assert!(err == Ok(())); +- assert!(aiocb.aio_return().unwrap() as usize == wbuf.len()); ++ assert_eq!(err, Ok(())); ++ assert_eq!(aiocb.aio_return().unwrap() as usize, wbuf.len()); + + f.seek(SeekFrom::Start(0)).unwrap(); + let len = f.read_to_end(&mut rbuf).unwrap(); +- assert!(len == EXPECT.len()); +- assert!(rbuf == EXPECT); ++ assert_eq!(len, EXPECT.len()); ++ assert_eq!(rbuf, EXPECT); + } + + // Tests `AioCb::from_boxed_slice` with `Bytes` +@@ -344,13 +356,13 @@ fn test_write_bytes() { + aiocb.write().unwrap(); + + let err = poll_aio(&mut aiocb); +- assert!(err == Ok(())); +- assert!(aiocb.aio_return().unwrap() as usize == expected_len); ++ assert_eq!(err, Ok(())); ++ assert_eq!(aiocb.aio_return().unwrap() as usize, expected_len); + + f.seek(SeekFrom::Start(0)).unwrap(); + let len = f.read_to_end(&mut rbuf).unwrap(); +- assert!(len == EXPECT.len()); +- assert!(rbuf == EXPECT); ++ assert_eq!(len, EXPECT.len()); ++ assert_eq!(rbuf, EXPECT); + } + + // Tests `AioCb::from_boxed_mut_slice` with `BytesMut` +@@ -402,13 +414,13 @@ fn test_write_from_pointer() { + aiocb.write().unwrap(); + + let err = poll_aio(&mut aiocb); +- assert!(err == Ok(())); +- assert!(aiocb.aio_return().unwrap() as usize == wbuf.len()); ++ assert_eq!(err, Ok(())); ++ assert_eq!(aiocb.aio_return().unwrap() as usize, wbuf.len()); + + f.seek(SeekFrom::Start(0)).unwrap(); + let len = f.read_to_end(&mut rbuf).unwrap(); +- assert!(len == EXPECT.len()); +- assert!(rbuf == EXPECT); ++ assert_eq!(len, EXPECT.len()); ++ assert_eq!(rbuf, EXPECT); + } + + /// `AioCb::write` should not modify the `AioCb` object if `libc::aio_write` +@@ -441,7 +453,7 @@ extern fn sigfunc(_: c_int) { + #[test] + #[cfg_attr(any(all(target_env = "musl", target_arch = "x86_64"), target_arch = "mips", target_arch = "mips64"), ignore)] + fn test_write_sigev_signal() { +- let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); ++ let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); + let sa = SigAction::new(SigHandler::Handler(sigfunc), + SaFlags::SA_RESETHAND, + SigSet::empty()); +@@ -469,11 +481,11 @@ fn test_write_sigev_signal() { + thread::sleep(time::Duration::from_millis(10)); + } + +- assert!(aiocb.aio_return().unwrap() as usize == WBUF.len()); ++ assert_eq!(aiocb.aio_return().unwrap() as usize, WBUF.len()); + f.seek(SeekFrom::Start(0)).unwrap(); + let len = f.read_to_end(&mut rbuf).unwrap(); +- assert!(len == EXPECT.len()); +- assert!(rbuf == EXPECT); ++ assert_eq!(len, EXPECT.len()); ++ assert_eq!(rbuf, EXPECT); + } + + // Test LioCb::listio with LIO_WAIT, so all AIO ops should be complete by the +@@ -512,15 +524,15 @@ fn test_liocb_listio_wait() { + let err = liocb.listio(LioMode::LIO_WAIT, SigevNotify::SigevNone); + err.expect("lio_listio"); + +- assert!(liocb.aio_return(0).unwrap() as usize == WBUF.len()); +- assert!(liocb.aio_return(1).unwrap() as usize == rlen); ++ assert_eq!(liocb.aio_return(0).unwrap() as usize, WBUF.len()); ++ assert_eq!(liocb.aio_return(1).unwrap() as usize, rlen); + } +- assert!(rbuf.deref().deref() == b"3456"); ++ assert_eq!(rbuf.deref().deref(), b"3456"); + + f.seek(SeekFrom::Start(0)).unwrap(); + let len = f.read_to_end(&mut rbuf2).unwrap(); +- assert!(len == EXPECT.len()); +- assert!(rbuf2 == EXPECT); ++ assert_eq!(len, EXPECT.len()); ++ assert_eq!(rbuf2, EXPECT); + } + + // Test LioCb::listio with LIO_NOWAIT and no SigEvent, so we must use some other +@@ -561,15 +573,15 @@ fn test_liocb_listio_nowait() { + + poll_aio(&mut liocb.aiocbs[0]).unwrap(); + poll_aio(&mut liocb.aiocbs[1]).unwrap(); +- assert!(liocb.aiocbs[0].aio_return().unwrap() as usize == WBUF.len()); +- assert!(liocb.aiocbs[1].aio_return().unwrap() as usize == rlen); ++ assert_eq!(liocb.aiocbs[0].aio_return().unwrap() as usize, WBUF.len()); ++ assert_eq!(liocb.aiocbs[1].aio_return().unwrap() as usize, rlen); + } +- assert!(rbuf.deref().deref() == b"3456"); ++ assert_eq!(rbuf.deref().deref(), b"3456"); + + f.seek(SeekFrom::Start(0)).unwrap(); + let len = f.read_to_end(&mut rbuf2).unwrap(); +- assert!(len == EXPECT.len()); +- assert!(rbuf2 == EXPECT); ++ assert_eq!(len, EXPECT.len()); ++ assert_eq!(rbuf2, EXPECT); + } + + // Test LioCb::listio with LIO_NOWAIT and a SigEvent to indicate when all +@@ -579,7 +591,7 @@ fn test_liocb_listio_nowait() { + #[cfg(not(any(target_os = "ios", target_os = "macos")))] + #[cfg_attr(any(target_arch = "mips", target_arch = "mips64", target_env = "musl"), ignore)] + fn test_liocb_listio_signal() { +- let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); ++ let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); + const INITIAL: &[u8] = b"abcdef123456"; + const WBUF: &[u8] = b"CDEF"; + let mut rbuf = vec![0; 4]; +@@ -620,15 +632,15 @@ fn test_liocb_listio_signal() { + thread::sleep(time::Duration::from_millis(10)); + } + +- assert!(liocb.aiocbs[0].aio_return().unwrap() as usize == WBUF.len()); +- assert!(liocb.aiocbs[1].aio_return().unwrap() as usize == rlen); ++ assert_eq!(liocb.aiocbs[0].aio_return().unwrap() as usize, WBUF.len()); ++ assert_eq!(liocb.aiocbs[1].aio_return().unwrap() as usize, rlen); + } +- assert!(rbuf.deref().deref() == b"3456"); ++ assert_eq!(rbuf.deref().deref(), b"3456"); + + f.seek(SeekFrom::Start(0)).unwrap(); + let len = f.read_to_end(&mut rbuf2).unwrap(); +- assert!(len == EXPECT.len()); +- assert!(rbuf2 == EXPECT); ++ assert_eq!(len, EXPECT.len()); ++ assert_eq!(rbuf2, EXPECT); + } + + // Try to use LioCb::listio to read into an immutable buffer. It should fail +diff --git a/third_party/rust/nix/test/sys/test_aio_drop.rs b/third_party/rust/nix/test/sys/test_aio_drop.rs +index 492da401ef726..784ee3ef6c75e 100644 +--- a/third_party/rust/nix/test/sys/test_aio_drop.rs ++++ b/third_party/rust/nix/test/sys/test_aio_drop.rs +@@ -1,6 +1,3 @@ +-extern crate nix; +-extern crate tempfile; +- + // Test dropping an AioCb that hasn't yet finished. + // This must happen in its own process, because on OSX this test seems to hose + // the AIO subsystem and causes subsequent tests to fail +@@ -12,6 +9,7 @@ extern crate tempfile; + target_os = "macos", + target_os = "freebsd", + target_os = "netbsd")))] ++#[cfg_attr(target_env = "gnu", ignore = "Occasionally fails in Travis; glibc bug suspected")] + fn test_drop() { + use nix::sys::aio::*; + use nix::sys::signal::*; +diff --git a/third_party/rust/nix/test/sys/test_ioctl.rs b/third_party/rust/nix/test/sys/test_ioctl.rs +index 0a439b3346f53..fa4510a69c089 100644 +--- a/third_party/rust/nix/test/sys/test_ioctl.rs ++++ b/third_party/rust/nix/test/sys/test_ioctl.rs +@@ -33,22 +33,22 @@ mod linux { + #[test] + fn test_op_none() { + if cfg!(any(target_arch = "mips", target_arch = "mips64", target_arch="powerpc", target_arch="powerpc64")){ +- assert_eq!(request_code_none!(b'q', 10), 0x2000_710A); +- assert_eq!(request_code_none!(b'a', 255), 0x2000_61FF); ++ assert_eq!(request_code_none!(b'q', 10) as u32, 0x2000_710A); ++ assert_eq!(request_code_none!(b'a', 255) as u32, 0x2000_61FF); + } else { +- assert_eq!(request_code_none!(b'q', 10), 0x0000_710A); +- assert_eq!(request_code_none!(b'a', 255), 0x0000_61FF); ++ assert_eq!(request_code_none!(b'q', 10) as u32, 0x0000_710A); ++ assert_eq!(request_code_none!(b'a', 255) as u32, 0x0000_61FF); + } + } + + #[test] + fn test_op_write() { + if cfg!(any(target_arch = "mips", target_arch = "mips64", target_arch="powerpc", target_arch="powerpc64")){ +- assert_eq!(request_code_write!(b'z', 10, 1), 0x8001_7A0A); +- assert_eq!(request_code_write!(b'z', 10, 512), 0x8200_7A0A); ++ assert_eq!(request_code_write!(b'z', 10, 1) as u32, 0x8001_7A0A); ++ assert_eq!(request_code_write!(b'z', 10, 512) as u32, 0x8200_7A0A); + } else { +- assert_eq!(request_code_write!(b'z', 10, 1), 0x4001_7A0A); +- assert_eq!(request_code_write!(b'z', 10, 512), 0x4200_7A0A); ++ assert_eq!(request_code_write!(b'z', 10, 1) as u32, 0x4001_7A0A); ++ assert_eq!(request_code_write!(b'z', 10, 512) as u32, 0x4200_7A0A); + } + } + +@@ -56,9 +56,11 @@ mod linux { + #[test] + fn test_op_write_64() { + if cfg!(any(target_arch = "mips64", target_arch="powerpc64")){ +- assert_eq!(request_code_write!(b'z', 10, (1 as u64) << 32), 0x8000_7A0A); ++ assert_eq!(request_code_write!(b'z', 10, (1 as u64) << 32) as u32, ++ 0x8000_7A0A); + } else { +- assert_eq!(request_code_write!(b'z', 10, (1 as u64) << 32), 0x4000_7A0A); ++ assert_eq!(request_code_write!(b'z', 10, (1 as u64) << 32) as u32, ++ 0x4000_7A0A); + } + + } +@@ -66,11 +68,11 @@ mod linux { + #[test] + fn test_op_read() { + if cfg!(any(target_arch = "mips", target_arch = "mips64", target_arch="powerpc", target_arch="powerpc64")){ +- assert_eq!(request_code_read!(b'z', 10, 1), 0x4001_7A0A); +- assert_eq!(request_code_read!(b'z', 10, 512), 0x4200_7A0A); ++ assert_eq!(request_code_read!(b'z', 10, 1) as u32, 0x4001_7A0A); ++ assert_eq!(request_code_read!(b'z', 10, 512) as u32, 0x4200_7A0A); + } else { +- assert_eq!(request_code_read!(b'z', 10, 1), 0x8001_7A0A); +- assert_eq!(request_code_read!(b'z', 10, 512), 0x8200_7A0A); ++ assert_eq!(request_code_read!(b'z', 10, 1) as u32, 0x8001_7A0A); ++ assert_eq!(request_code_read!(b'z', 10, 512) as u32, 0x8200_7A0A); + } + } + +@@ -78,22 +80,25 @@ mod linux { + #[test] + fn test_op_read_64() { + if cfg!(any(target_arch = "mips64", target_arch="powerpc64")){ +- assert_eq!(request_code_read!(b'z', 10, (1 as u64) << 32), 0x4000_7A0A); ++ assert_eq!(request_code_read!(b'z', 10, (1 as u64) << 32) as u32, ++ 0x4000_7A0A); + } else { +- assert_eq!(request_code_read!(b'z', 10, (1 as u64) << 32), 0x8000_7A0A); ++ assert_eq!(request_code_read!(b'z', 10, (1 as u64) << 32) as u32, ++ 0x8000_7A0A); + } + } + + #[test] + fn test_op_read_write() { +- assert_eq!(request_code_readwrite!(b'z', 10, 1), 0xC001_7A0A); +- assert_eq!(request_code_readwrite!(b'z', 10, 512), 0xC200_7A0A); ++ assert_eq!(request_code_readwrite!(b'z', 10, 1) as u32, 0xC001_7A0A); ++ assert_eq!(request_code_readwrite!(b'z', 10, 512) as u32, 0xC200_7A0A); + } + + #[cfg(target_pointer_width = "64")] + #[test] + fn test_op_read_write_64() { +- assert_eq!(request_code_readwrite!(b'z', 10, (1 as u64) << 32), 0xC000_7A0A); ++ assert_eq!(request_code_readwrite!(b'z', 10, (1 as u64) << 32) as u32, ++ 0xC000_7A0A); + } + } + +@@ -177,7 +182,7 @@ mod linux_ioctls { + #[test] + fn test_ioctl_read_bad() { + let file = tempfile().unwrap(); +- let mut termios = unsafe { mem::uninitialized() }; ++ let mut termios = unsafe { mem::zeroed() }; + let res = unsafe { tcgets(file.as_raw_fd(), &mut termios) }; + assert_eq!(res, Err(Sys(ENOTTY))); + } +@@ -194,7 +199,7 @@ mod linux_ioctls { + #[test] + fn test_ioctl_write_ptr_bad() { + let file = tempfile().unwrap(); +- let termios: termios = unsafe { mem::uninitialized() }; ++ let termios: termios = unsafe { mem::zeroed() }; + let res = unsafe { tcsets(file.as_raw_fd(), &termios) }; + assert_eq!(res, Err(Sys(ENOTTY))); + } +@@ -245,7 +250,7 @@ mod linux_ioctls { + #[test] + fn test_ioctl_read() { + let file = tempfile().unwrap(); +- let mut data: v4l2_audio = unsafe { mem::uninitialized() }; ++ let mut data: v4l2_audio = unsafe { mem::zeroed() }; + let res = unsafe { g_audio(file.as_raw_fd(), &mut data) }; + assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS))); + } +@@ -255,7 +260,7 @@ mod linux_ioctls { + #[test] + fn test_ioctl_readwrite() { + let file = tempfile().unwrap(); +- let mut data: v4l2_audio = unsafe { mem::uninitialized() }; ++ let mut data: v4l2_audio = unsafe { mem::zeroed() }; + let res = unsafe { enum_audio(file.as_raw_fd(), &mut data) }; + assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS))); + } +@@ -318,7 +323,7 @@ mod freebsd_ioctls { + #[test] + fn test_ioctl_read() { + let file = tempfile().unwrap(); +- let mut termios = unsafe { mem::uninitialized() }; ++ let mut termios = unsafe { mem::zeroed() }; + let res = unsafe { tiocgeta(file.as_raw_fd(), &mut termios) }; + assert_eq!(res, Err(Sys(ENOTTY))); + } +@@ -327,7 +332,7 @@ mod freebsd_ioctls { + #[test] + fn test_ioctl_write_ptr() { + let file = tempfile().unwrap(); +- let termios: termios = unsafe { mem::uninitialized() }; ++ let termios: termios = unsafe { mem::zeroed() }; + let res = unsafe { tiocseta(file.as_raw_fd(), &termios) }; + assert_eq!(res, Err(Sys(ENOTTY))); + } +diff --git a/third_party/rust/nix/test/sys/test_lio_listio_resubmit.rs b/third_party/rust/nix/test/sys/test_lio_listio_resubmit.rs +index 19ee3facf87d7..0795370b8c448 100644 +--- a/third_party/rust/nix/test/sys/test_lio_listio_resubmit.rs ++++ b/third_party/rust/nix/test/sys/test_lio_listio_resubmit.rs +@@ -4,10 +4,6 @@ + // we must disable the test here rather than in Cargo.toml + #![cfg(target_os = "freebsd")] + +-extern crate nix; +-extern crate sysctl; +-extern crate tempfile; +- + use nix::Error; + use nix::errno::*; + use nix::libc::off_t; +diff --git a/third_party/rust/nix/test/sys/test_mman.rs b/third_party/rust/nix/test/sys/test_mman.rs +new file mode 100644 +index 0000000000000..152fff69c24de +--- /dev/null ++++ b/third_party/rust/nix/test/sys/test_mman.rs +@@ -0,0 +1,80 @@ ++use nix::Error; ++use nix::libc::{c_void, size_t}; ++use nix::sys::mman::{mmap, MapFlags, ProtFlags}; ++ ++#[cfg(target_os = "linux")] ++use nix::sys::mman::{mremap, MRemapFlags}; ++ ++#[test] ++fn test_mmap_anonymous() { ++ let ref mut byte = unsafe { ++ let ptr = mmap(std::ptr::null_mut(), 1, ++ ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, ++ MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS, -1, 0) ++ .unwrap(); ++ *(ptr as * mut u8) ++ }; ++ assert_eq !(*byte, 0x00u8); ++ *byte = 0xffu8; ++ assert_eq !(*byte, 0xffu8); ++} ++ ++#[test] ++#[cfg(target_os = "linux")] ++fn test_mremap_grow() { ++ const ONE_K : size_t = 1024; ++ let slice : &mut[u8] = unsafe { ++ let mem = mmap(std::ptr::null_mut(), ONE_K, ++ ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, ++ MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE, -1, 0) ++ .unwrap(); ++ std::slice::from_raw_parts_mut(mem as * mut u8, ONE_K) ++ }; ++ assert_eq !(slice[ONE_K - 1], 0x00); ++ slice[ONE_K - 1] = 0xFF; ++ assert_eq !(slice[ONE_K - 1], 0xFF); ++ ++ let slice : &mut[u8] = unsafe { ++ let mem = mremap(slice.as_mut_ptr() as * mut c_void, ONE_K, 10 * ONE_K, ++ MRemapFlags::MREMAP_MAYMOVE, None) ++ .unwrap(); ++ std::slice::from_raw_parts_mut(mem as * mut u8, 10 * ONE_K) ++ }; ++ ++ // The first KB should still have the old data in it. ++ assert_eq !(slice[ONE_K - 1], 0xFF); ++ ++ // The additional range should be zero-init'd and accessible. ++ assert_eq !(slice[10 * ONE_K - 1], 0x00); ++ slice[10 * ONE_K - 1] = 0xFF; ++ assert_eq !(slice[10 * ONE_K - 1], 0xFF); ++} ++ ++#[test] ++#[cfg(target_os = "linux")] ++fn test_mremap_shrink() { ++ const ONE_K : size_t = 1024; ++ let slice : &mut[u8] = unsafe { ++ let mem = mmap(std::ptr::null_mut(), 10 * ONE_K, ++ ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, ++ MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE, -1, 0) ++ .unwrap(); ++ std::slice::from_raw_parts_mut(mem as * mut u8, ONE_K) ++ }; ++ assert_eq !(slice[ONE_K - 1], 0x00); ++ slice[ONE_K - 1] = 0xFF; ++ assert_eq !(slice[ONE_K - 1], 0xFF); ++ ++ let slice : &mut[u8] = unsafe { ++ let mem = mremap(slice.as_mut_ptr() as * mut c_void, 10 * ONE_K, ONE_K, ++ MRemapFlags::empty(), None) ++ .unwrap(); ++ // Since we didn't supply MREMAP_MAYMOVE, the address should be the ++ // same. ++ assert_eq !(mem, slice.as_mut_ptr() as * mut c_void); ++ std::slice::from_raw_parts_mut(mem as * mut u8, ONE_K) ++ }; ++ ++ // The first KB should still be accessible and have the old data in it. ++ assert_eq !(slice[ONE_K - 1], 0xFF); ++} +diff --git a/third_party/rust/nix/test/sys/test_pthread.rs b/third_party/rust/nix/test/sys/test_pthread.rs +index 8928010087a13..1fc3dd900f382 100644 +--- a/third_party/rust/nix/test/sys/test_pthread.rs ++++ b/third_party/rust/nix/test/sys/test_pthread.rs +@@ -1,13 +1,13 @@ + use nix::sys::pthread::*; + +-#[cfg(target_env = "musl")] ++#[cfg(any(target_env = "musl", target_os = "redox"))] + #[test] + fn test_pthread_self() { + let tid = pthread_self(); + assert!(tid != ::std::ptr::null_mut()); + } + +-#[cfg(not(target_env = "musl"))] ++#[cfg(not(any(target_env = "musl", target_os = "redox")))] + #[test] + fn test_pthread_self() { + let tid = pthread_self(); +diff --git a/third_party/rust/nix/test/sys/test_ptrace.rs b/third_party/rust/nix/test/sys/test_ptrace.rs +index 24d9b522ee4e5..b9793b39c54ae 100644 +--- a/third_party/rust/nix/test/sys/test_ptrace.rs ++++ b/third_party/rust/nix/test/sys/test_ptrace.rs +@@ -8,10 +8,13 @@ use nix::sys::ptrace::Options; + #[cfg(any(target_os = "android", target_os = "linux"))] + use std::mem; + ++use crate::*; ++ + #[test] + fn test_ptrace() { + // Just make sure ptrace can be called at all, for now. + // FIXME: qemu-user doesn't implement ptrace on all arches, so permit ENOSYS ++ require_capability!(CAP_SYS_PTRACE); + let err = ptrace::attach(getpid()).unwrap_err(); + assert!(err == Error::Sys(Errno::EPERM) || err == Error::Sys(Errno::EINVAL) || + err == Error::Sys(Errno::ENOSYS)); +@@ -21,6 +24,7 @@ fn test_ptrace() { + #[test] + #[cfg(any(target_os = "android", target_os = "linux"))] + fn test_ptrace_setoptions() { ++ require_capability!(CAP_SYS_PTRACE); + let err = ptrace::setoptions(getpid(), Options::PTRACE_O_TRACESYSGOOD).unwrap_err(); + assert!(err != Error::UnsupportedOperation); + } +@@ -29,6 +33,7 @@ fn test_ptrace_setoptions() { + #[test] + #[cfg(any(target_os = "android", target_os = "linux"))] + fn test_ptrace_getevent() { ++ require_capability!(CAP_SYS_PTRACE); + let err = ptrace::getevent(getpid()).unwrap_err(); + assert!(err != Error::UnsupportedOperation); + } +@@ -37,6 +42,7 @@ fn test_ptrace_getevent() { + #[test] + #[cfg(any(target_os = "android", target_os = "linux"))] + fn test_ptrace_getsiginfo() { ++ require_capability!(CAP_SYS_PTRACE); + if let Err(Error::UnsupportedOperation) = ptrace::getsiginfo(getpid()) { + panic!("ptrace_getsiginfo returns Error::UnsupportedOperation!"); + } +@@ -46,7 +52,8 @@ fn test_ptrace_getsiginfo() { + #[test] + #[cfg(any(target_os = "android", target_os = "linux"))] + fn test_ptrace_setsiginfo() { +- let siginfo = unsafe { mem::uninitialized() }; ++ require_capability!(CAP_SYS_PTRACE); ++ let siginfo = unsafe { mem::zeroed() }; + if let Err(Error::UnsupportedOperation) = ptrace::setsiginfo(getpid(), &siginfo) { + panic!("ptrace_setsiginfo returns Error::UnsupportedOperation!"); + } +@@ -61,7 +68,9 @@ fn test_ptrace_cont() { + use nix::unistd::fork; + use nix::unistd::ForkResult::*; + +- let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test"); ++ require_capability!(CAP_SYS_PTRACE); ++ ++ let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test"); + + // FIXME: qemu-user doesn't implement ptrace on all architectures + // and retunrs ENOSYS in this case. +@@ -74,7 +83,7 @@ fn test_ptrace_cont() { + return; + } + +- match fork().expect("Error: Fork Failed") { ++ match unsafe{fork()}.expect("Error: Fork Failed") { + Child => { + ptrace::traceme().unwrap(); + // As recommended by ptrace(2), raise SIGTRAP to pause the child +@@ -91,7 +100,7 @@ fn test_ptrace_cont() { + ptrace::cont(child, Some(Signal::SIGKILL)).unwrap(); + match waitpid(child, None) { + Ok(WaitStatus::Signaled(pid, Signal::SIGKILL, _)) if pid == child => { +- // FIXME It's been observed on some systems (apple) the ++ // FIXME It's been observed on some systems (apple) the + // tracee may not be killed but remain as a zombie process + // affecting other wait based tests. Add an extra kill just + // to make sure there are no zombies. +@@ -105,3 +114,65 @@ fn test_ptrace_cont() { + }, + } + } ++ ++// ptrace::{setoptions, getregs} are only available in these platforms ++#[cfg(all(target_os = "linux", ++ any(target_arch = "x86_64", ++ target_arch = "x86"), ++ target_env = "gnu"))] ++#[test] ++fn test_ptrace_syscall() { ++ use nix::sys::signal::kill; ++ use nix::sys::ptrace; ++ use nix::sys::signal::Signal; ++ use nix::sys::wait::{waitpid, WaitStatus}; ++ use nix::unistd::fork; ++ use nix::unistd::getpid; ++ use nix::unistd::ForkResult::*; ++ ++ require_capability!(CAP_SYS_PTRACE); ++ ++ let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test"); ++ ++ match unsafe{fork()}.expect("Error: Fork Failed") { ++ Child => { ++ ptrace::traceme().unwrap(); ++ // first sigstop until parent is ready to continue ++ let pid = getpid(); ++ kill(pid, Signal::SIGSTOP).unwrap(); ++ kill(pid, Signal::SIGTERM).unwrap(); ++ unsafe { ::libc::_exit(0); } ++ }, ++ ++ Parent { child } => { ++ assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGSTOP))); ++ ++ // set this option to recognize syscall-stops ++ ptrace::setoptions(child, ptrace::Options::PTRACE_O_TRACESYSGOOD).unwrap(); ++ ++ #[cfg(target_arch = "x86_64")] ++ let get_syscall_id = || ptrace::getregs(child).unwrap().orig_rax as libc::c_long; ++ ++ #[cfg(target_arch = "x86")] ++ let get_syscall_id = || ptrace::getregs(child).unwrap().orig_eax as libc::c_long; ++ ++ // kill entry ++ ptrace::syscall(child, None).unwrap(); ++ assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child))); ++ assert_eq!(get_syscall_id(), ::libc::SYS_kill); ++ ++ // kill exit ++ ptrace::syscall(child, None).unwrap(); ++ assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child))); ++ assert_eq!(get_syscall_id(), ::libc::SYS_kill); ++ ++ // receive signal ++ ptrace::syscall(child, None).unwrap(); ++ assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGTERM))); ++ ++ // inject signal ++ ptrace::syscall(child, Signal::SIGTERM).unwrap(); ++ assert_eq!(waitpid(child, None), Ok(WaitStatus::Signaled(child, Signal::SIGTERM, false))); ++ }, ++ } ++} +diff --git a/third_party/rust/nix/test/sys/test_select.rs b/third_party/rust/nix/test/sys/test_select.rs +index cf68700c5e16f..37951086c2d8d 100644 +--- a/third_party/rust/nix/test/sys/test_select.rs ++++ b/third_party/rust/nix/test/sys/test_select.rs +@@ -5,7 +5,7 @@ use nix::sys::time::{TimeSpec, TimeValLike}; + + #[test] + pub fn test_pselect() { +- let _mtx = ::SIGNAL_MTX ++ let _mtx = crate::SIGNAL_MTX + .lock() + .expect("Mutex got poisoned by another test"); + +diff --git a/third_party/rust/nix/test/sys/test_signal.rs b/third_party/rust/nix/test/sys/test_signal.rs +index 8780763f773ef..ae22527fde278 100644 +--- a/third_party/rust/nix/test/sys/test_signal.rs ++++ b/third_party/rust/nix/test/sys/test_signal.rs +@@ -1,7 +1,9 @@ + use libc; ++#[cfg(not(target_os = "redox"))] + use nix::Error; + use nix::sys::signal::*; + use nix::unistd::*; ++use std::convert::TryFrom; + use std::sync::atomic::{AtomicBool, Ordering}; + + #[test] +@@ -10,6 +12,7 @@ fn test_kill_none() { + } + + #[test] ++#[cfg(not(target_os = "fuchsia"))] + fn test_killpg_none() { + killpg(getpgrp(), None) + .expect("Should be able to send signal to my process group."); +@@ -17,6 +20,8 @@ fn test_killpg_none() { + + #[test] + fn test_old_sigaction_flags() { ++ let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); ++ + extern "C" fn handler(_: ::libc::c_int) {} + let act = SigAction::new( + SigHandler::Handler(handler), +@@ -37,7 +42,7 @@ fn test_sigprocmask_noop() { + + #[test] + fn test_sigprocmask() { +- let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); ++ let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); + + // This needs to be a signal that rust doesn't use in the test harness. + const SIGNAL: Signal = Signal::SIGCHLD; +@@ -75,16 +80,25 @@ lazy_static! { + } + + extern fn test_sigaction_handler(signal: libc::c_int) { +- let signal = Signal::from_c_int(signal).unwrap(); ++ let signal = Signal::try_from(signal).unwrap(); + SIGNALED.store(signal == Signal::SIGINT, Ordering::Relaxed); + } + +-extern fn test_sigaction_action(_: libc::c_int, _: *mut libc::siginfo_t, _: *mut libc::c_void) { ++#[cfg(not(target_os = "redox"))] ++extern fn test_sigaction_action(_: libc::c_int, _: *mut libc::siginfo_t, _: *mut libc::c_void) {} ++ ++#[test] ++#[cfg(not(target_os = "redox"))] ++fn test_signal_sigaction() { ++ let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); ++ ++ let action_handler = SigHandler::SigAction(test_sigaction_action); ++ assert_eq!(unsafe { signal(Signal::SIGINT, action_handler) }.unwrap_err(), Error::UnsupportedOperation); + } + + #[test] + fn test_signal() { +- let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); ++ let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); + + unsafe { signal(Signal::SIGINT, SigHandler::SigIgn) }.unwrap(); + raise(Signal::SIGINT).unwrap(); +@@ -96,9 +110,6 @@ fn test_signal() { + assert!(SIGNALED.load(Ordering::Relaxed)); + assert_eq!(unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(), handler); + +- let action_handler = SigHandler::SigAction(test_sigaction_action); +- assert_eq!(unsafe { signal(Signal::SIGINT, action_handler) }.unwrap_err(), Error::UnsupportedOperation); +- + // Restore default signal handler + unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(); + } +diff --git a/third_party/rust/nix/test/sys/test_signalfd.rs b/third_party/rust/nix/test/sys/test_signalfd.rs +index a3b6098841f1c..af04c222852d8 100644 +--- a/third_party/rust/nix/test/sys/test_signalfd.rs ++++ b/third_party/rust/nix/test/sys/test_signalfd.rs +@@ -1,10 +1,12 @@ ++use std::convert::TryFrom; ++ + #[test] + fn test_signalfd() { + use nix::sys::signalfd::SignalFd; + use nix::sys::signal::{self, raise, Signal, SigSet}; + + // Grab the mutex for altering signals so we don't interfere with other tests. +- let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); ++ let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); + + // Block the SIGUSR1 signal from automatic processing for this thread + let mut mask = SigSet::empty(); +@@ -20,6 +22,6 @@ fn test_signalfd() { + + // And now catch that same signal. + let res = fd.read_signal().unwrap().unwrap(); +- let signo = Signal::from_c_int(res.ssi_signo as i32).unwrap(); ++ let signo = Signal::try_from(res.ssi_signo as i32).unwrap(); + assert_eq!(signo, signal::SIGUSR1); + } +diff --git a/third_party/rust/nix/test/sys/test_socket.rs b/third_party/rust/nix/test/sys/test_socket.rs +index 7e64d2b77f071..2b89a45336f3e 100644 +--- a/third_party/rust/nix/test/sys/test_socket.rs ++++ b/third_party/rust/nix/test/sys/test_socket.rs +@@ -1,4 +1,3 @@ +-use nix::ifaddrs::InterfaceAddress; + use nix::sys::socket::{AddressFamily, InetAddr, UnixAddr, getsockname}; + use std::collections::hash_map::DefaultHasher; + use std::hash::{Hash, Hasher}; +@@ -9,6 +8,8 @@ use std::slice; + use std::str::FromStr; + use libc::c_char; + use tempfile; ++#[cfg(any(target_os = "linux", target_os= "android"))] ++use crate::*; + + #[test] + pub fn test_inetv4_addr_to_sock_addr() { +@@ -106,7 +107,7 @@ pub fn test_addr_equality_abstract() { + assert_eq!(addr1, addr2); + assert_eq!(calculate_hash(&addr1), calculate_hash(&addr2)); + +- addr2.0.sun_path[18] = 127; ++ addr2.0.sun_path[17] = 127; + assert_ne!(addr1, addr2); + assert_ne!(calculate_hash(&addr1), calculate_hash(&addr2)); + } +@@ -117,16 +118,13 @@ pub fn test_addr_equality_abstract() { + pub fn test_abstract_uds_addr() { + let empty = String::new(); + let addr = UnixAddr::new_abstract(empty.as_bytes()).unwrap(); +- let sun_path = [0u8; 107]; ++ let sun_path: [u8; 0] = []; + assert_eq!(addr.as_abstract(), Some(&sun_path[..])); + + let name = String::from("nix\0abstract\0test"); + let addr = UnixAddr::new_abstract(name.as_bytes()).unwrap(); + let sun_path = [ +- 110u8, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, 116, 101, 115, 116, 0, 0, 0, 0, +- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 110u8, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, 116, 101, 115, 116 + ]; + assert_eq!(addr.as_abstract(), Some(&sun_path[..])); + assert_eq!(addr.path(), None); +@@ -164,6 +162,360 @@ pub fn test_socketpair() { + assert_eq!(&buf[..], b"hello"); + } + ++mod recvfrom { ++ use nix::Result; ++ use nix::sys::socket::*; ++ use std::thread; ++ use super::*; ++ ++ const MSG: &'static [u8] = b"Hello, World!"; ++ ++ fn sendrecv<Fs, Fr>(rsock: RawFd, ssock: RawFd, f_send: Fs, mut f_recv: Fr) -> Option<SockAddr> ++ where ++ Fs: Fn(RawFd, &[u8], MsgFlags) -> Result<usize> + Send + 'static, ++ Fr: FnMut(usize, Option<SockAddr>), ++ { ++ let mut buf: [u8; 13] = [0u8; 13]; ++ let mut l = 0; ++ let mut from = None; ++ ++ let send_thread = thread::spawn(move || { ++ let mut l = 0; ++ while l < std::mem::size_of_val(MSG) { ++ l += f_send(ssock, &MSG[l..], MsgFlags::empty()).unwrap(); ++ } ++ }); ++ ++ while l < std::mem::size_of_val(MSG) { ++ let (len, from_) = recvfrom(rsock, &mut buf[l..]).unwrap(); ++ f_recv(len, from_); ++ from = from_; ++ l += len; ++ } ++ assert_eq!(&buf, MSG); ++ send_thread.join().unwrap(); ++ from ++ } ++ ++ #[test] ++ pub fn stream() { ++ let (fd2, fd1) = socketpair(AddressFamily::Unix, SockType::Stream, ++ None, SockFlag::empty()).unwrap(); ++ // Ignore from for stream sockets ++ let _ = sendrecv(fd1, fd2, |s, m, flags| { ++ send(s, m, flags) ++ }, |_, _| {}); ++ } ++ ++ #[test] ++ pub fn udp() { ++ let std_sa = SocketAddr::from_str("127.0.0.1:6789").unwrap(); ++ let inet_addr = InetAddr::from_std(&std_sa); ++ let sock_addr = SockAddr::new_inet(inet_addr); ++ let rsock = socket(AddressFamily::Inet, ++ SockType::Datagram, ++ SockFlag::empty(), ++ None ++ ).unwrap(); ++ bind(rsock, &sock_addr).unwrap(); ++ let ssock = socket( ++ AddressFamily::Inet, ++ SockType::Datagram, ++ SockFlag::empty(), ++ None, ++ ).expect("send socket failed"); ++ let from = sendrecv(rsock, ssock, move |s, m, flags| { ++ sendto(s, m, &sock_addr, flags) ++ },|_, _| {}); ++ // UDP sockets should set the from address ++ assert_eq!(AddressFamily::Inet, from.unwrap().family()); ++ } ++ ++ #[cfg(target_os = "linux")] ++ mod udp_offload { ++ use super::*; ++ use nix::sys::uio::IoVec; ++ use nix::sys::socket::sockopt::{UdpGroSegment, UdpGsoSegment}; ++ ++ #[test] ++ // Disable the test on emulated platforms because it fails in Cirrus-CI. Lack of QEMU ++ // support is suspected. ++ #[cfg_attr(not(any(target_arch = "x86_64", target_arch="i686")), ignore)] ++ pub fn gso() { ++ require_kernel_version!(udp_offload::gso, ">= 4.18"); ++ ++ // In this test, we send the data and provide a GSO segment size. ++ // Since we are sending the buffer of size 13, six UDP packets ++ // with size 2 and two UDP packet with size 1 will be sent. ++ let segment_size: u16 = 2; ++ ++ let std_sa = SocketAddr::from_str("127.0.0.1:6791").unwrap(); ++ let inet_addr = InetAddr::from_std(&std_sa); ++ let sock_addr = SockAddr::new_inet(inet_addr); ++ let rsock = socket(AddressFamily::Inet, ++ SockType::Datagram, ++ SockFlag::empty(), ++ None ++ ).unwrap(); ++ ++ setsockopt(rsock, UdpGsoSegment, &(segment_size as _)) ++ .expect("setsockopt UDP_SEGMENT failed"); ++ ++ bind(rsock, &sock_addr).unwrap(); ++ let ssock = socket( ++ AddressFamily::Inet, ++ SockType::Datagram, ++ SockFlag::empty(), ++ None, ++ ).expect("send socket failed"); ++ ++ let mut num_packets_received: i32 = 0; ++ ++ sendrecv(rsock, ssock, move |s, m, flags| { ++ let iov = [IoVec::from_slice(m)]; ++ let cmsg = ControlMessage::UdpGsoSegments(&segment_size); ++ sendmsg(s, &iov, &[cmsg], flags, Some(&sock_addr)) ++ }, { ++ let num_packets_received_ref = &mut num_packets_received; ++ ++ move |len, _| { ++ // check that we receive UDP packets with payload size ++ // less or equal to segment size ++ assert!(len <= segment_size as usize); ++ *num_packets_received_ref += 1; ++ } ++ }); ++ ++ // Buffer size is 13, we will receive six packets of size 2, ++ // and one packet of size 1. ++ assert_eq!(7, num_packets_received); ++ } ++ ++ #[test] ++ // Disable the test on emulated platforms because it fails in Cirrus-CI. Lack of QEMU ++ // support is suspected. ++ #[cfg_attr(not(any(target_arch = "x86_64", target_arch="i686")), ignore)] ++ pub fn gro() { ++ require_kernel_version!(udp_offload::gro, ">= 5.3"); ++ ++ // It's hard to guarantee receiving GRO packets. Just checking ++ // that `setsockopt` doesn't fail with error ++ ++ let rsock = socket(AddressFamily::Inet, ++ SockType::Datagram, ++ SockFlag::empty(), ++ None ++ ).unwrap(); ++ ++ setsockopt(rsock, UdpGroSegment, &true) ++ .expect("setsockopt UDP_GRO failed"); ++ } ++ } ++ ++ #[cfg(any( ++ target_os = "linux", ++ target_os = "android", ++ target_os = "freebsd", ++ target_os = "netbsd", ++ ))] ++ #[test] ++ pub fn udp_sendmmsg() { ++ use nix::sys::uio::IoVec; ++ ++ let std_sa = SocketAddr::from_str("127.0.0.1:6793").unwrap(); ++ let std_sa2 = SocketAddr::from_str("127.0.0.1:6794").unwrap(); ++ let inet_addr = InetAddr::from_std(&std_sa); ++ let inet_addr2 = InetAddr::from_std(&std_sa2); ++ let sock_addr = SockAddr::new_inet(inet_addr); ++ let sock_addr2 = SockAddr::new_inet(inet_addr2); ++ ++ let rsock = socket(AddressFamily::Inet, ++ SockType::Datagram, ++ SockFlag::empty(), ++ None ++ ).unwrap(); ++ bind(rsock, &sock_addr).unwrap(); ++ let ssock = socket( ++ AddressFamily::Inet, ++ SockType::Datagram, ++ SockFlag::empty(), ++ None, ++ ).expect("send socket failed"); ++ ++ let from = sendrecv(rsock, ssock, move |s, m, flags| { ++ let iov = [IoVec::from_slice(m)]; ++ let mut msgs = Vec::new(); ++ msgs.push( ++ SendMmsgData { ++ iov: &iov, ++ cmsgs: &[], ++ addr: Some(sock_addr), ++ _lt: Default::default(), ++ }); ++ ++ let batch_size = 15; ++ ++ for _ in 0..batch_size { ++ msgs.push( ++ SendMmsgData { ++ iov: &iov, ++ cmsgs: &[], ++ addr: Some(sock_addr2), ++ _lt: Default::default(), ++ } ++ ); ++ } ++ sendmmsg(s, msgs.iter(), flags) ++ .map(move |sent_bytes| { ++ assert!(sent_bytes.len() >= 1); ++ for sent in &sent_bytes { ++ assert_eq!(*sent, m.len()); ++ } ++ sent_bytes.len() ++ }) ++ }, |_, _ | {}); ++ // UDP sockets should set the from address ++ assert_eq!(AddressFamily::Inet, from.unwrap().family()); ++ } ++ ++ #[cfg(any( ++ target_os = "linux", ++ target_os = "android", ++ target_os = "freebsd", ++ target_os = "netbsd", ++ ))] ++ #[test] ++ pub fn udp_recvmmsg() { ++ use nix::sys::uio::IoVec; ++ use nix::sys::socket::{MsgFlags, recvmmsg}; ++ ++ const NUM_MESSAGES_SENT: usize = 2; ++ const DATA: [u8; 2] = [1,2]; ++ ++ let std_sa = SocketAddr::from_str("127.0.0.1:6798").unwrap(); ++ let inet_addr = InetAddr::from_std(&std_sa); ++ let sock_addr = SockAddr::new_inet(inet_addr); ++ ++ let rsock = socket(AddressFamily::Inet, ++ SockType::Datagram, ++ SockFlag::empty(), ++ None ++ ).unwrap(); ++ bind(rsock, &sock_addr).unwrap(); ++ let ssock = socket( ++ AddressFamily::Inet, ++ SockType::Datagram, ++ SockFlag::empty(), ++ None, ++ ).expect("send socket failed"); ++ ++ let send_thread = thread::spawn(move || { ++ for _ in 0..NUM_MESSAGES_SENT { ++ sendto(ssock, &DATA[..], &sock_addr, MsgFlags::empty()).unwrap(); ++ } ++ }); ++ ++ let mut msgs = std::collections::LinkedList::new(); ++ ++ // Buffers to receive exactly `NUM_MESSAGES_SENT` messages ++ let mut receive_buffers = [[0u8; 32]; NUM_MESSAGES_SENT]; ++ let iovs: Vec<_> = receive_buffers.iter_mut().map(|buf| { ++ [IoVec::from_mut_slice(&mut buf[..])] ++ }).collect(); ++ ++ for iov in &iovs { ++ msgs.push_back(RecvMmsgData { ++ iov: iov, ++ cmsg_buffer: None, ++ }) ++ }; ++ ++ let res = recvmmsg(rsock, &mut msgs, MsgFlags::empty(), None).expect("recvmmsg"); ++ assert_eq!(res.len(), DATA.len()); ++ ++ for RecvMsg { address, bytes, .. } in res.into_iter() { ++ assert_eq!(AddressFamily::Inet, address.unwrap().family()); ++ assert_eq!(DATA.len(), bytes); ++ } ++ ++ for buf in &receive_buffers { ++ assert_eq!(&buf[..DATA.len()], DATA); ++ } ++ ++ send_thread.join().unwrap(); ++ } ++ ++ #[cfg(any( ++ target_os = "linux", ++ target_os = "android", ++ target_os = "freebsd", ++ target_os = "netbsd", ++ ))] ++ #[test] ++ pub fn udp_recvmmsg_dontwait_short_read() { ++ use nix::sys::uio::IoVec; ++ use nix::sys::socket::{MsgFlags, recvmmsg}; ++ ++ const NUM_MESSAGES_SENT: usize = 2; ++ const DATA: [u8; 4] = [1,2,3,4]; ++ ++ let std_sa = SocketAddr::from_str("127.0.0.1:6799").unwrap(); ++ let inet_addr = InetAddr::from_std(&std_sa); ++ let sock_addr = SockAddr::new_inet(inet_addr); ++ ++ let rsock = socket(AddressFamily::Inet, ++ SockType::Datagram, ++ SockFlag::empty(), ++ None ++ ).unwrap(); ++ bind(rsock, &sock_addr).unwrap(); ++ let ssock = socket( ++ AddressFamily::Inet, ++ SockType::Datagram, ++ SockFlag::empty(), ++ None, ++ ).expect("send socket failed"); ++ ++ let send_thread = thread::spawn(move || { ++ for _ in 0..NUM_MESSAGES_SENT { ++ sendto(ssock, &DATA[..], &sock_addr, MsgFlags::empty()).unwrap(); ++ } ++ }); ++ // Ensure we've sent all the messages before continuing so `recvmmsg` ++ // will return right away ++ send_thread.join().unwrap(); ++ ++ let mut msgs = std::collections::LinkedList::new(); ++ ++ // Buffers to receive >`NUM_MESSAGES_SENT` messages to ensure `recvmmsg` ++ // will return when there are fewer than requested messages in the ++ // kernel buffers when using `MSG_DONTWAIT`. ++ let mut receive_buffers = [[0u8; 32]; NUM_MESSAGES_SENT + 2]; ++ let iovs: Vec<_> = receive_buffers.iter_mut().map(|buf| { ++ [IoVec::from_mut_slice(&mut buf[..])] ++ }).collect(); ++ ++ for iov in &iovs { ++ msgs.push_back(RecvMmsgData { ++ iov: iov, ++ cmsg_buffer: None, ++ }) ++ }; ++ ++ let res = recvmmsg(rsock, &mut msgs, MsgFlags::MSG_DONTWAIT, None).expect("recvmmsg"); ++ assert_eq!(res.len(), NUM_MESSAGES_SENT); ++ ++ for RecvMsg { address, bytes, .. } in res.into_iter() { ++ assert_eq!(AddressFamily::Inet, address.unwrap().family()); ++ assert_eq!(DATA.len(), bytes); ++ } ++ ++ for buf in &receive_buffers[..NUM_MESSAGES_SENT] { ++ assert_eq!(&buf[..DATA.len()], DATA); ++ } ++ } ++} ++ + // Test error handling of our recvmsg wrapper + #[test] + pub fn test_recvmsg_ebadf() { +@@ -247,8 +599,13 @@ pub fn test_af_alg_cipher() { + ControlMessage, MsgFlags}; + use nix::sys::socket::sockopt::AlgSetKey; + ++ skip_if_cirrus!("Fails for an unknown reason Cirrus CI. Bug #1352"); ++ // Travis's seccomp profile blocks AF_ALG ++ // https://docs.docker.com/engine/security/seccomp/ ++ skip_if_seccomp!(test_af_alg_cipher); ++ + let alg_type = "skcipher"; +- let alg_name = "ctr(aes)"; ++ let alg_name = "ctr-aes-aesni"; + // 256-bits secret key + let key = vec![0u8; 32]; + // 16-bytes IV +@@ -311,6 +668,11 @@ pub fn test_af_alg_aead() { + ControlMessage, MsgFlags}; + use nix::sys::socket::sockopt::{AlgSetKey, AlgSetAeadAuthSize}; + ++ skip_if_cirrus!("Fails for an unknown reason Cirrus CI. Bug #1352"); ++ // Travis's seccomp profile blocks AF_ALG ++ // https://docs.docker.com/engine/security/seccomp/ ++ skip_if_seccomp!(test_af_alg_aead); ++ + let auth_size = 4usize; + let assoc_size = 16u32; + +@@ -383,6 +745,111 @@ pub fn test_af_alg_aead() { + assert_eq!(decrypted[(assoc_size as usize)..(payload_len + (assoc_size as usize))], payload[(assoc_size as usize)..payload_len + (assoc_size as usize)]); + } + ++// Verify `ControlMessage::Ipv4PacketInfo` for `sendmsg`. ++// This creates a (udp) socket bound to localhost, then sends a message to ++// itself but uses Ipv4PacketInfo to force the source address to be localhost. ++// ++// This would be a more interesting test if we could assume that the test host ++// has more than one IP address (since we could select a different address to ++// test from). ++#[cfg(any(target_os = "linux", ++ target_os = "macos", ++ target_os = "netbsd"))] ++#[test] ++pub fn test_sendmsg_ipv4packetinfo() { ++ use nix::sys::uio::IoVec; ++ use nix::sys::socket::{socket, sendmsg, bind, ++ AddressFamily, SockType, SockFlag, SockAddr, ++ ControlMessage, MsgFlags}; ++ ++ let sock = socket(AddressFamily::Inet, ++ SockType::Datagram, ++ SockFlag::empty(), ++ None) ++ .expect("socket failed"); ++ ++ let std_sa = SocketAddr::from_str("127.0.0.1:4000").unwrap(); ++ let inet_addr = InetAddr::from_std(&std_sa); ++ let sock_addr = SockAddr::new_inet(inet_addr); ++ ++ bind(sock, &sock_addr).expect("bind failed"); ++ ++ let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; ++ let iov = [IoVec::from_slice(&slice)]; ++ ++ if let InetAddr::V4(sin) = inet_addr { ++ let pi = libc::in_pktinfo { ++ ipi_ifindex: 0, /* Unspecified interface */ ++ ipi_addr: libc::in_addr { s_addr: 0 }, ++ ipi_spec_dst: sin.sin_addr, ++ }; ++ ++ let cmsg = [ControlMessage::Ipv4PacketInfo(&pi)]; ++ ++ sendmsg(sock, &iov, &cmsg, MsgFlags::empty(), Some(&sock_addr)) ++ .expect("sendmsg"); ++ } else { ++ panic!("No IPv4 addresses available for testing?"); ++ } ++} ++ ++// Verify `ControlMessage::Ipv6PacketInfo` for `sendmsg`. ++// This creates a (udp) socket bound to ip6-localhost, then sends a message to ++// itself but uses Ipv6PacketInfo to force the source address to be ++// ip6-localhost. ++// ++// This would be a more interesting test if we could assume that the test host ++// has more than one IP address (since we could select a different address to ++// test from). ++#[cfg(any(target_os = "linux", ++ target_os = "macos", ++ target_os = "netbsd", ++ target_os = "freebsd"))] ++#[test] ++pub fn test_sendmsg_ipv6packetinfo() { ++ use nix::Error; ++ use nix::errno::Errno; ++ use nix::sys::uio::IoVec; ++ use nix::sys::socket::{socket, sendmsg, bind, ++ AddressFamily, SockType, SockFlag, SockAddr, ++ ControlMessage, MsgFlags}; ++ ++ let sock = socket(AddressFamily::Inet6, ++ SockType::Datagram, ++ SockFlag::empty(), ++ None) ++ .expect("socket failed"); ++ ++ let std_sa = SocketAddr::from_str("[::1]:6000").unwrap(); ++ let inet_addr = InetAddr::from_std(&std_sa); ++ let sock_addr = SockAddr::new_inet(inet_addr); ++ ++ match bind(sock, &sock_addr) { ++ Err(Error::Sys(Errno::EADDRNOTAVAIL)) => { ++ println!("IPv6 not available, skipping test."); ++ return; ++ }, ++ _ => (), ++ } ++ ++ let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; ++ let iov = [IoVec::from_slice(&slice)]; ++ ++ if let InetAddr::V6(sin) = inet_addr { ++ let pi = libc::in6_pktinfo { ++ ipi6_ifindex: 0, /* Unspecified interface */ ++ ipi6_addr: sin.sin6_addr, ++ }; ++ ++ let cmsg = [ControlMessage::Ipv6PacketInfo(&pi)]; ++ ++ sendmsg(sock, &iov, &cmsg, MsgFlags::empty(), Some(&sock_addr)) ++ .expect("sendmsg"); ++ } else { ++ println!("No IPv6 addresses available for testing: skipping testing Ipv6PacketInfo"); ++ } ++} ++ + /// Tests that passing multiple fds using a single `ControlMessage` works. + // Disable the test on emulated platforms due to a bug in QEMU versions < + // 2.12.0. https://bugs.launchpad.net/qemu/+bug/1701808 +@@ -468,29 +935,36 @@ pub fn test_sendmsg_empty_cmsgs() { + } + } + +-#[cfg(any(target_os = "android", target_os = "linux"))] ++#[cfg(any( ++ target_os = "android", ++ target_os = "linux", ++ target_os = "freebsd", ++ target_os = "dragonfly", ++))] + #[test] + fn test_scm_credentials() { +- use libc; + use nix::sys::uio::IoVec; + use nix::unistd::{close, getpid, getuid, getgid}; +- use nix::sys::socket::{socketpair, sendmsg, recvmsg, setsockopt, ++ use nix::sys::socket::{socketpair, sendmsg, recvmsg, + AddressFamily, SockType, SockFlag, +- ControlMessage, ControlMessageOwned, MsgFlags}; +- use nix::sys::socket::sockopt::PassCred; ++ ControlMessage, ControlMessageOwned, MsgFlags, ++ UnixCredentials}; ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ use nix::sys::socket::{setsockopt, sockopt::PassCred}; + + let (send, recv) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()) + .unwrap(); ++ #[cfg(any(target_os = "android", target_os = "linux"))] + setsockopt(recv, PassCred, &true).unwrap(); + + { + let iov = [IoVec::from_slice(b"hello")]; +- let cred = libc::ucred { +- pid: getpid().as_raw(), +- uid: getuid().as_raw(), +- gid: getgid().as_raw(), +- }; ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ let cred = UnixCredentials::new(); ++ #[cfg(any(target_os = "android", target_os = "linux"))] + let cmsg = ControlMessage::ScmCredentials(&cred); ++ #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] ++ let cmsg = ControlMessage::ScmCreds; + assert_eq!(sendmsg(send, &iov, &[cmsg], MsgFlags::empty(), None).unwrap(), 5); + close(send).unwrap(); + } +@@ -498,20 +972,23 @@ fn test_scm_credentials() { + { + let mut buf = [0u8; 5]; + let iov = [IoVec::from_mut_slice(&mut buf[..])]; +- let mut cmsgspace = cmsg_space!(libc::ucred); ++ let mut cmsgspace = cmsg_space!(UnixCredentials); + let msg = recvmsg(recv, &iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap(); + let mut received_cred = None; + + for cmsg in msg.cmsgs() { +- if let ControlMessageOwned::ScmCredentials(cred) = cmsg { +- assert!(received_cred.is_none()); +- assert_eq!(cred.pid, getpid().as_raw()); +- assert_eq!(cred.uid, getuid().as_raw()); +- assert_eq!(cred.gid, getgid().as_raw()); +- received_cred = Some(cred); +- } else { +- panic!("unexpected cmsg"); +- } ++ let cred = match cmsg { ++ #[cfg(any(target_os = "android", target_os = "linux"))] ++ ControlMessageOwned::ScmCredentials(cred) => cred, ++ #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] ++ ControlMessageOwned::ScmCreds(cred) => cred, ++ other => panic!("unexpected cmsg {:?}", other), ++ }; ++ assert!(received_cred.is_none()); ++ assert_eq!(cred.pid(), getpid().as_raw()); ++ assert_eq!(cred.uid(), getuid().as_raw()); ++ assert_eq!(cred.gid(), getgid().as_raw()); ++ received_cred = Some(cred); + } + received_cred.expect("no creds received"); + assert_eq!(msg.bytes, 5); +@@ -550,7 +1027,7 @@ fn test_too_large_cmsgspace() { + fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) { + use libc::ucred; + use nix::sys::uio::IoVec; +- use nix::unistd::{pipe, read, write, close, getpid, getuid, getgid}; ++ use nix::unistd::{pipe, write, close, getpid, getuid, getgid}; + use nix::sys::socket::{socketpair, sendmsg, recvmsg, setsockopt, + SockType, SockFlag, + ControlMessage, ControlMessageOwned, MsgFlags}; +@@ -569,7 +1046,7 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) { + pid: getpid().as_raw(), + uid: getuid().as_raw(), + gid: getgid().as_raw(), +- }; ++ }.into(); + let fds = [r]; + let cmsgs = [ + ControlMessage::ScmCredentials(&cred), +@@ -597,9 +1074,9 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) { + } + ControlMessageOwned::ScmCredentials(cred) => { + assert!(received_cred.is_none()); +- assert_eq!(cred.pid, getpid().as_raw()); +- assert_eq!(cred.uid, getuid().as_raw()); +- assert_eq!(cred.gid, getgid().as_raw()); ++ assert_eq!(cred.pid(), getpid().as_raw()); ++ assert_eq!(cred.uid(), getuid().as_raw()); ++ assert_eq!(cred.gid(), getgid().as_raw()); + received_cred = Some(cred); + } + _ => panic!("unexpected cmsg"), +@@ -683,7 +1160,7 @@ pub fn test_syscontrol() { + target_os = "netbsd", + target_os = "openbsd", + ))] +-fn loopback_address(family: AddressFamily) -> Option<InterfaceAddress> { ++fn loopback_address(family: AddressFamily) -> Option<nix::ifaddrs::InterfaceAddress> { + use std::io; + use std::io::Write; + use nix::ifaddrs::getifaddrs; +@@ -1013,7 +1490,7 @@ pub fn test_recv_ipv6pktinfo() { + } + } + +-#[cfg(target_os = "linux")] ++#[cfg(any(target_os = "android", target_os = "linux"))] + #[test] + pub fn test_vsock() { + use libc; +@@ -1030,17 +1507,11 @@ pub fn test_vsock() { + SockFlag::empty(), None) + .expect("socket failed"); + +- // VMADDR_CID_HYPERVISOR and VMADDR_CID_RESERVED are reserved, so we expect +- // an EADDRNOTAVAIL error. ++ // VMADDR_CID_HYPERVISOR is reserved, so we expect an EADDRNOTAVAIL error. + let sockaddr = SockAddr::new_vsock(libc::VMADDR_CID_HYPERVISOR, port); + assert_eq!(bind(s1, &sockaddr).err(), + Some(Error::Sys(Errno::EADDRNOTAVAIL))); + +- let sockaddr = SockAddr::new_vsock(libc::VMADDR_CID_RESERVED, port); +- assert_eq!(bind(s1, &sockaddr).err(), +- Some(Error::Sys(Errno::EADDRNOTAVAIL))); +- +- + let sockaddr = SockAddr::new_vsock(libc::VMADDR_CID_ANY, port); + assert_eq!(bind(s1, &sockaddr), Ok(())); + listen(s1, 10).expect("listen failed"); +diff --git a/third_party/rust/nix/test/sys/test_sockopt.rs b/third_party/rust/nix/test/sys/test_sockopt.rs +index c4860c0d61d3d..56065931322ec 100644 +--- a/third_party/rust/nix/test/sys/test_sockopt.rs ++++ b/third_party/rust/nix/test/sys/test_sockopt.rs +@@ -1,5 +1,7 @@ + use rand::{thread_rng, Rng}; + use nix::sys::socket::{socket, sockopt, getsockopt, setsockopt, AddressFamily, SockType, SockFlag, SockProtocol}; ++#[cfg(any(target_os = "android", target_os = "linux"))] ++use crate::*; + + #[cfg(target_os = "linux")] + #[test] +@@ -51,3 +53,44 @@ fn test_tcp_congestion() { + val + ); + } ++ ++#[test] ++#[cfg(any(target_os = "android", target_os = "linux"))] ++fn test_bindtodevice() { ++ skip_if_not_root!("test_bindtodevice"); ++ ++ let fd = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap(); ++ ++ let val = getsockopt(fd, sockopt::BindToDevice).unwrap(); ++ setsockopt(fd, sockopt::BindToDevice, &val).unwrap(); ++ ++ assert_eq!( ++ getsockopt(fd, sockopt::BindToDevice).unwrap(), ++ val ++ ); ++} ++ ++#[test] ++fn test_so_tcp_keepalive() { ++ let fd = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), SockProtocol::Tcp).unwrap(); ++ setsockopt(fd, sockopt::KeepAlive, &true).unwrap(); ++ assert_eq!(getsockopt(fd, sockopt::KeepAlive).unwrap(), true); ++ ++ #[cfg(any(target_os = "android", ++ target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "linux", ++ target_os = "nacl"))] { ++ let x = getsockopt(fd, sockopt::TcpKeepIdle).unwrap(); ++ setsockopt(fd, sockopt::TcpKeepIdle, &(x + 1)).unwrap(); ++ assert_eq!(getsockopt(fd, sockopt::TcpKeepIdle).unwrap(), x + 1); ++ ++ let x = getsockopt(fd, sockopt::TcpKeepCount).unwrap(); ++ setsockopt(fd, sockopt::TcpKeepCount, &(x + 1)).unwrap(); ++ assert_eq!(getsockopt(fd, sockopt::TcpKeepCount).unwrap(), x + 1); ++ ++ let x = getsockopt(fd, sockopt::TcpKeepInterval).unwrap(); ++ setsockopt(fd, sockopt::TcpKeepInterval, &(x + 1)).unwrap(); ++ assert_eq!(getsockopt(fd, sockopt::TcpKeepInterval).unwrap(), x + 1); ++ } ++} +diff --git a/third_party/rust/nix/test/sys/test_termios.rs b/third_party/rust/nix/test/sys/test_termios.rs +index a14b8ce1a23cb..00aeb2fc57f15 100644 +--- a/third_party/rust/nix/test/sys/test_termios.rs ++++ b/third_party/rust/nix/test/sys/test_termios.rs +@@ -4,7 +4,7 @@ use tempfile::tempfile; + use nix::{Error, fcntl}; + use nix::errno::Errno; + use nix::pty::openpty; +-use nix::sys::termios::{self, LocalFlags, OutputFlags, Termios, tcgetattr}; ++use nix::sys::termios::{self, LocalFlags, OutputFlags, tcgetattr}; + use nix::unistd::{read, write, close}; + + /// Helper function analogous to `std::io::Write::write_all`, but for `RawFd`s +@@ -19,10 +19,10 @@ fn write_all(f: RawFd, buf: &[u8]) { + #[test] + fn test_tcgetattr_pty() { + // openpty uses ptname(3) internally +- let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); ++ let _m = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); + + let pty = openpty(None, None).expect("openpty failed"); +- assert!(termios::tcgetattr(pty.master).is_ok()); ++ assert!(termios::tcgetattr(pty.slave).is_ok()); + close(pty.master).expect("closing the master failed"); + close(pty.slave).expect("closing the slave failed"); + } +@@ -46,14 +46,14 @@ fn test_tcgetattr_ebadf() { + #[test] + fn test_output_flags() { + // openpty uses ptname(3) internally +- let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); ++ let _m = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); + + // Open one pty to get attributes for the second one + let mut termios = { + let pty = openpty(None, None).expect("openpty failed"); + assert!(pty.master > 0); + assert!(pty.slave > 0); +- let termios = tcgetattr(pty.master).expect("tcgetattr failed"); ++ let termios = tcgetattr(pty.slave).expect("tcgetattr failed"); + close(pty.master).unwrap(); + close(pty.slave).unwrap(); + termios +@@ -77,7 +77,7 @@ fn test_output_flags() { + + // Read from the slave verifying that the output has been properly transformed + let mut buf = [0u8; 10]; +- ::read_exact(pty.slave, &mut buf); ++ crate::read_exact(pty.slave, &mut buf); + let transformed_string = "foofoofoo\n"; + close(pty.master).unwrap(); + close(pty.slave).unwrap(); +@@ -88,14 +88,14 @@ fn test_output_flags() { + #[test] + fn test_local_flags() { + // openpty uses ptname(3) internally +- let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); ++ let _m = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); + + // Open one pty to get attributes for the second one + let mut termios = { + let pty = openpty(None, None).unwrap(); + assert!(pty.master > 0); + assert!(pty.slave > 0); +- let termios = tcgetattr(pty.master).unwrap(); ++ let termios = tcgetattr(pty.slave).unwrap(); + close(pty.master).unwrap(); + close(pty.slave).unwrap(); + termios +@@ -128,9 +128,3 @@ fn test_local_flags() { + close(pty.slave).unwrap(); + assert_eq!(read, Error::Sys(Errno::EAGAIN)); + } +- +-#[test] +-fn test_cfmakeraw() { +- let mut termios = unsafe { Termios::default_uninit() }; +- termios::cfmakeraw(&mut termios); +-} +diff --git a/third_party/rust/nix/test/sys/test_timerfd.rs b/third_party/rust/nix/test/sys/test_timerfd.rs +new file mode 100644 +index 0000000000000..24fb2ac002e1d +--- /dev/null ++++ b/third_party/rust/nix/test/sys/test_timerfd.rs +@@ -0,0 +1,61 @@ ++use nix::sys::time::{TimeSpec, TimeValLike}; ++use nix::sys::timerfd::{ClockId, Expiration, TimerFd, TimerFlags, TimerSetTimeFlags}; ++use std::time::Instant; ++ ++#[test] ++pub fn test_timerfd_oneshot() { ++ let timer = TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty()).unwrap(); ++ ++ let before = Instant::now(); ++ ++ timer ++ .set( ++ Expiration::OneShot(TimeSpec::seconds(1)), ++ TimerSetTimeFlags::empty(), ++ ) ++ .unwrap(); ++ ++ timer.wait().unwrap(); ++ ++ let millis = before.elapsed().as_millis(); ++ assert!(millis > 900); ++} ++ ++#[test] ++pub fn test_timerfd_interval() { ++ let timer = TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty()).unwrap(); ++ ++ let before = Instant::now(); ++ timer ++ .set( ++ Expiration::IntervalDelayed(TimeSpec::seconds(1), TimeSpec::seconds(2)), ++ TimerSetTimeFlags::empty(), ++ ) ++ .unwrap(); ++ ++ timer.wait().unwrap(); ++ ++ let start_delay = before.elapsed().as_millis(); ++ assert!(start_delay > 900); ++ ++ timer.wait().unwrap(); ++ ++ let interval_delay = before.elapsed().as_millis(); ++ assert!(interval_delay > 2900); ++} ++ ++#[test] ++pub fn test_timerfd_unset() { ++ let timer = TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty()).unwrap(); ++ ++ timer ++ .set( ++ Expiration::OneShot(TimeSpec::seconds(1)), ++ TimerSetTimeFlags::empty(), ++ ) ++ .unwrap(); ++ ++ timer.unset().unwrap(); ++ ++ assert!(timer.get().unwrap() == None); ++} +diff --git a/third_party/rust/nix/test/sys/test_uio.rs b/third_party/rust/nix/test/sys/test_uio.rs +index 3e4fc28ceb0e4..8d22bf1755a2c 100644 +--- a/third_party/rust/nix/test/sys/test_uio.rs ++++ b/third_party/rust/nix/test/sys/test_uio.rs +@@ -6,7 +6,9 @@ use std::{cmp, iter}; + use std::fs::{OpenOptions}; + use std::os::unix::io::AsRawFd; + +-use tempfile::{tempfile, tempdir}; ++#[cfg(not(target_os = "redox"))] ++use tempfile::tempfile; ++use tempfile::tempdir; + + #[test] + fn test_writev() { +@@ -53,6 +55,7 @@ fn test_writev() { + } + + #[test] ++#[cfg(not(target_os = "redox"))] + fn test_readv() { + let s:String = thread_rng().sample_iter(&Alphanumeric).take(128).collect(); + let to_write = s.as_bytes().to_vec(); +@@ -97,6 +100,7 @@ fn test_readv() { + } + + #[test] ++#[cfg(not(target_os = "redox"))] + fn test_pwrite() { + use std::io::Read; + +@@ -199,15 +203,17 @@ fn test_process_vm_readv() { + use nix::unistd::ForkResult::*; + use nix::sys::signal::*; + use nix::sys::wait::*; ++ use crate::*; + +- let _ = ::FORK_MTX.lock().expect("Mutex got poisoned by another test"); ++ require_capability!(CAP_SYS_PTRACE); ++ let _ = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test"); + + // Pre-allocate memory in the child, since allocation isn't safe + // post-fork (~= async-signal-safe) + let mut vector = vec![1u8, 2, 3, 4, 5]; + + let (r, w) = pipe().unwrap(); +- match fork().expect("Error: Fork Failed") { ++ match unsafe{fork()}.expect("Error: Fork Failed") { + Parent { child } => { + close(w).unwrap(); + // wait for child +diff --git a/third_party/rust/nix/test/sys/test_wait.rs b/third_party/rust/nix/test/sys/test_wait.rs +index d07d82f0d9075..5bb298eba4d29 100644 +--- a/third_party/rust/nix/test/sys/test_wait.rs ++++ b/third_party/rust/nix/test/sys/test_wait.rs +@@ -6,11 +6,12 @@ use nix::sys::wait::*; + use libc::_exit; + + #[test] ++#[cfg(not(target_os = "redox"))] + fn test_wait_signal() { +- let _ = ::FORK_MTX.lock().expect("Mutex got poisoned by another test"); ++ let _ = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test"); + + // Safe: The child only calls `pause` and/or `_exit`, which are async-signal-safe. +- match fork().expect("Error: Fork Failed") { ++ match unsafe{fork()}.expect("Error: Fork Failed") { + Child => { + pause(); + unsafe { _exit(123) } +@@ -24,10 +25,10 @@ fn test_wait_signal() { + + #[test] + fn test_wait_exit() { +- let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test"); ++ let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test"); + + // Safe: Child only calls `_exit`, which is async-signal-safe. +- match fork().expect("Error: Fork Failed") { ++ match unsafe{fork()}.expect("Error: Fork Failed") { + Child => unsafe { _exit(12); }, + Parent { child } => { + assert_eq!(waitpid(child, None), Ok(WaitStatus::Exited(child, 12))); +@@ -45,9 +46,9 @@ fn test_waitstatus_from_raw() { + + #[test] + fn test_waitstatus_pid() { +- let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test"); ++ let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test"); + +- match fork().unwrap() { ++ match unsafe{fork()}.unwrap() { + Child => unsafe { _exit(0) }, + Parent { child } => { + let status = waitpid(child, None).unwrap(); +@@ -66,6 +67,7 @@ mod ptrace { + use nix::unistd::*; + use nix::unistd::ForkResult::*; + use libc::_exit; ++ use crate::*; + + fn ptrace_child() -> ! { + ptrace::traceme().unwrap(); +@@ -82,7 +84,7 @@ mod ptrace { + assert!(ptrace::setoptions(child, Options::PTRACE_O_TRACESYSGOOD | Options::PTRACE_O_TRACEEXIT).is_ok()); + + // First, stop on the next system call, which will be exit() +- assert!(ptrace::syscall(child).is_ok()); ++ assert!(ptrace::syscall(child, None).is_ok()); + assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child))); + // Then get the ptrace event for the process exiting + assert!(ptrace::cont(child, None).is_ok()); +@@ -94,9 +96,10 @@ mod ptrace { + + #[test] + fn test_wait_ptrace() { +- let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test"); ++ require_capability!(CAP_SYS_PTRACE); ++ let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test"); + +- match fork().expect("Error: Fork Failed") { ++ match unsafe{fork()}.expect("Error: Fork Failed") { + Child => ptrace_child(), + Parent { child } => ptrace_parent(child), + } +diff --git a/third_party/rust/nix/test/test.rs b/third_party/rust/nix/test/test.rs +index 6a71d261b5712..5a5330b7e4010 100644 +--- a/third_party/rust/nix/test/test.rs ++++ b/third_party/rust/nix/test/test.rs +@@ -1,69 +1,13 @@ +-// XXX Allow deprecated items until release 0.16.0. See issue #1096. +-#![allow(deprecated)] +-extern crate bytes; +-#[cfg(any(target_os = "android", target_os = "linux"))] +-extern crate caps; + #[macro_use] + extern crate cfg_if; +-#[macro_use] ++#[cfg_attr(not(target_os = "redox"), macro_use)] + extern crate nix; + #[macro_use] + extern crate lazy_static; +-extern crate libc; +-extern crate rand; +-#[cfg(target_os = "freebsd")] +-extern crate sysctl; +-extern crate tempfile; +- +-#[cfg(any(target_os = "android", target_os = "linux"))] +-macro_rules! require_capability { +- ($capname:ident) => { +- use ::caps::{Capability, CapSet, has_cap}; +- use ::std::io::{self, Write}; +- +- if !has_cap(None, CapSet::Effective, Capability::$capname).unwrap() { +- let stderr = io::stderr(); +- let mut handle = stderr.lock(); +- writeln!(handle, "Insufficient capabilities. Skipping test.") +- .unwrap(); +- return; +- } +- } +-} +- +-#[cfg(target_os = "freebsd")] +-macro_rules! skip_if_jailed { +- ($name:expr) => { +- use ::sysctl::CtlValue; +- +- if let CtlValue::Int(1) = ::sysctl::value("security.jail.jailed") +- .unwrap() +- { +- use ::std::io::Write; +- let stderr = ::std::io::stderr(); +- let mut handle = stderr.lock(); +- writeln!(handle, "{} cannot run in a jail. Skipping test.", $name) +- .unwrap(); +- return; +- } +- } +-} +- +-macro_rules! skip_if_not_root { +- ($name:expr) => { +- use nix::unistd::Uid; +- +- if !Uid::current().is_root() { +- use ::std::io::Write; +- let stderr = ::std::io::stderr(); +- let mut handle = stderr.lock(); +- writeln!(handle, "{} requires root privileges. Skipping test.", $name).unwrap(); +- return; +- } +- }; +-} + ++mod common; + mod sys; ++#[cfg(not(target_os = "redox"))] + mod test_dir; + mod test_fcntl; + #[cfg(any(target_os = "android", +@@ -75,10 +19,15 @@ mod test_kmod; + target_os = "linux", + target_os = "netbsd"))] + mod test_mq; ++#[cfg(not(target_os = "redox"))] + mod test_net; + mod test_nix_path; + mod test_poll; ++#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] + mod test_pty; ++#[cfg(any(target_os = "android", ++ target_os = "linux"))] ++mod test_sched; + #[cfg(any(target_os = "android", + target_os = "freebsd", + target_os = "ios", +@@ -86,6 +35,7 @@ mod test_pty; + target_os = "macos"))] + mod test_sendfile; + mod test_stat; ++mod test_time; + mod test_unistd; + + use std::os::unix::io::RawFd; +@@ -93,6 +43,7 @@ use std::path::PathBuf; + use std::sync::{Mutex, RwLock, RwLockWriteGuard}; + use nix::unistd::{chdir, getcwd, read}; + ++ + /// Helper function analogous to `std::io::Read::read_exact`, but for `RawFD`s + fn read_exact(f: RawFd, buf: &mut [u8]) { + let mut len = 0; +@@ -130,7 +81,7 @@ struct DirRestore<'a> { + + impl<'a> DirRestore<'a> { + fn new() -> Self { +- let guard = ::CWD_LOCK.write() ++ let guard = crate::CWD_LOCK.write() + .expect("Lock got poisoned by another test"); + DirRestore{ + _g: guard, +diff --git a/third_party/rust/nix/test/test_clearenv.rs b/third_party/rust/nix/test/test_clearenv.rs +new file mode 100644 +index 0000000000000..28a77680498ca +--- /dev/null ++++ b/third_party/rust/nix/test/test_clearenv.rs +@@ -0,0 +1,9 @@ ++use std::env; ++ ++#[test] ++fn clearenv() { ++ env::set_var("FOO", "BAR"); ++ unsafe { nix::env::clearenv() }.unwrap(); ++ assert_eq!(env::var("FOO").unwrap_err(), env::VarError::NotPresent); ++ assert_eq!(env::vars().count(), 0); ++} +diff --git a/third_party/rust/nix/test/test_dir.rs b/third_party/rust/nix/test/test_dir.rs +index c42fbcd18a29d..505277e7143b7 100644 +--- a/third_party/rust/nix/test/test_dir.rs ++++ b/third_party/rust/nix/test/test_dir.rs +@@ -1,11 +1,8 @@ +-extern crate nix; +-extern crate tempfile; +- + use nix::dir::{Dir, Type}; + use nix::fcntl::OFlag; + use nix::sys::stat::Mode; + use std::fs::File; +-use self::tempfile::tempdir; ++use tempfile::tempdir; + + #[test] + fn read() { +@@ -37,7 +34,9 @@ fn rewind() { + Mode::empty()).unwrap(); + let entries1: Vec<_> = dir.iter().map(|e| e.unwrap().file_name().to_owned()).collect(); + let entries2: Vec<_> = dir.iter().map(|e| e.unwrap().file_name().to_owned()).collect(); ++ let entries3: Vec<_> = dir.into_iter().map(|e| e.unwrap().file_name().to_owned()).collect(); + assert_eq!(entries1, entries2); ++ assert_eq!(entries2, entries3); + } + + #[test] +diff --git a/third_party/rust/nix/test/test_fcntl.rs b/third_party/rust/nix/test/test_fcntl.rs +index 6b2bbd679fc31..5d1bafebe195f 100644 +--- a/third_party/rust/nix/test/test_fcntl.rs ++++ b/third_party/rust/nix/test/test_fcntl.rs +@@ -1,14 +1,28 @@ ++#[cfg(not(target_os = "redox"))] + use nix::Error; ++#[cfg(not(target_os = "redox"))] + use nix::errno::*; +-use nix::fcntl::{openat, open, OFlag, readlink, readlinkat, renameat}; ++#[cfg(not(target_os = "redox"))] ++use nix::fcntl::{open, OFlag, readlink}; ++#[cfg(not(target_os = "redox"))] ++use nix::fcntl::{openat, readlinkat, renameat}; ++#[cfg(not(target_os = "redox"))] + use nix::sys::stat::Mode; ++#[cfg(not(target_os = "redox"))] + use nix::unistd::{close, read}; ++#[cfg(not(target_os = "redox"))] + use tempfile::{self, NamedTempFile}; ++#[cfg(not(target_os = "redox"))] + use std::fs::File; ++#[cfg(not(target_os = "redox"))] + use std::io::prelude::*; ++#[cfg(not(target_os = "redox"))] + use std::os::unix::fs; + ++use crate::*; ++ + #[test] ++#[cfg(not(target_os = "redox"))] + fn test_openat() { + const CONTENTS: &[u8] = b"abcd"; + let mut tmp = NamedTempFile::new().unwrap(); +@@ -31,6 +45,7 @@ fn test_openat() { + } + + #[test] ++#[cfg(not(target_os = "redox"))] + fn test_renameat() { + let old_dir = tempfile::tempdir().unwrap(); + let old_dirfd = open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); +@@ -47,6 +62,7 @@ fn test_renameat() { + } + + #[test] ++#[cfg(not(target_os = "redox"))] + fn test_readlink() { + let tempdir = tempfile::tempdir().unwrap(); + let src = tempdir.path().join("a"); +@@ -56,28 +72,31 @@ fn test_readlink() { + let dirfd = open(tempdir.path(), + OFlag::empty(), + Mode::empty()).unwrap(); ++ let expected_dir = src.to_str().unwrap(); ++ ++ assert_eq!(readlink(&dst).unwrap().to_str().unwrap(), expected_dir); ++ assert_eq!(readlinkat(dirfd, "b").unwrap().to_str().unwrap(), expected_dir); + +- let mut buf = vec![0; src.to_str().unwrap().len() + 1]; +- assert_eq!(readlink(&dst, &mut buf).unwrap().to_str().unwrap(), +- src.to_str().unwrap()); +- assert_eq!(readlinkat(dirfd, "b", &mut buf).unwrap().to_str().unwrap(), +- src.to_str().unwrap()); + } + + #[cfg(any(target_os = "linux", target_os = "android"))] + mod linux_android { ++ use std::fs::File; + use std::io::prelude::*; +- use std::io::SeekFrom; ++ use std::io::{BufRead, BufReader, SeekFrom}; + use std::os::unix::prelude::*; + + use libc::loff_t; + + use nix::fcntl::*; ++ use nix::sys::stat::fstat; + use nix::sys::uio::IoVec; + use nix::unistd::{close, pipe, read, write}; + + use tempfile::{tempfile, NamedTempFile}; + ++ use crate::*; ++ + /// This test creates a temporary file containing the contents + /// 'foobarbaz' and uses the `copy_file_range` call to transfer + /// 3 bytes at offset 3 (`bar`) to another empty file at offset 0. The +@@ -198,6 +217,113 @@ mod linux_android { + let mut buf = [0u8; 200]; + assert_eq!(100, read(fd, &mut buf).unwrap()); + } ++ ++ // The tests below are disabled for the listed targets ++ // due to OFD locks not being available in the kernel/libc ++ // versions used in the CI environment, probably because ++ // they run under QEMU. ++ ++ #[test] ++ #[cfg(not(any(target_arch = "aarch64", ++ target_arch = "arm", ++ target_arch = "armv7", ++ target_arch = "x86", ++ target_arch = "mips", ++ target_arch = "mips64", ++ target_arch = "mips64el", ++ target_arch = "powerpc64", ++ target_arch = "powerpc64le", ++ target_env = "musl")))] ++ fn test_ofd_write_lock() { ++ let tmp = NamedTempFile::new().unwrap(); ++ ++ let fd = tmp.as_raw_fd(); ++ let statfs = nix::sys::statfs::fstatfs(&tmp).unwrap(); ++ if statfs.filesystem_type() == nix::sys::statfs::OVERLAYFS_SUPER_MAGIC { ++ // OverlayFS is a union file system. It returns one inode value in ++ // stat(2), but a different one shows up in /proc/locks. So we must ++ // skip the test. ++ skip!("/proc/locks does not work on overlayfs"); ++ } ++ let inode = fstat(fd).expect("fstat failed").st_ino as usize; ++ ++ let mut flock = libc::flock { ++ l_type: libc::F_WRLCK as libc::c_short, ++ l_whence: libc::SEEK_SET as libc::c_short, ++ l_start: 0, ++ l_len: 0, ++ l_pid: 0, ++ }; ++ fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("write lock failed"); ++ assert_eq!( ++ Some(("OFDLCK".to_string(), "WRITE".to_string())), ++ lock_info(inode) ++ ); ++ ++ flock.l_type = libc::F_UNLCK as libc::c_short; ++ fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("write unlock failed"); ++ assert_eq!(None, lock_info(inode)); ++ } ++ ++ #[test] ++ #[cfg(not(any(target_arch = "aarch64", ++ target_arch = "arm", ++ target_arch = "armv7", ++ target_arch = "x86", ++ target_arch = "mips", ++ target_arch = "mips64", ++ target_arch = "mips64el", ++ target_arch = "powerpc64", ++ target_arch = "powerpc64le", ++ target_env = "musl")))] ++ fn test_ofd_read_lock() { ++ let tmp = NamedTempFile::new().unwrap(); ++ ++ let fd = tmp.as_raw_fd(); ++ let statfs = nix::sys::statfs::fstatfs(&tmp).unwrap(); ++ if statfs.filesystem_type() == nix::sys::statfs::OVERLAYFS_SUPER_MAGIC { ++ // OverlayFS is a union file system. It returns one inode value in ++ // stat(2), but a different one shows up in /proc/locks. So we must ++ // skip the test. ++ skip!("/proc/locks does not work on overlayfs"); ++ } ++ let inode = fstat(fd).expect("fstat failed").st_ino as usize; ++ ++ let mut flock = libc::flock { ++ l_type: libc::F_RDLCK as libc::c_short, ++ l_whence: libc::SEEK_SET as libc::c_short, ++ l_start: 0, ++ l_len: 0, ++ l_pid: 0, ++ }; ++ fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("read lock failed"); ++ assert_eq!( ++ Some(("OFDLCK".to_string(), "READ".to_string())), ++ lock_info(inode) ++ ); ++ ++ flock.l_type = libc::F_UNLCK as libc::c_short; ++ fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("read unlock failed"); ++ assert_eq!(None, lock_info(inode)); ++ } ++ ++ fn lock_info(inode: usize) -> Option<(String, String)> { ++ let file = File::open("/proc/locks").expect("open /proc/locks failed"); ++ let buf = BufReader::new(file); ++ ++ for line in buf.lines() { ++ let line = line.unwrap(); ++ let parts: Vec<_> = line.split_whitespace().collect(); ++ let lock_type = parts[1]; ++ let lock_access = parts[3]; ++ let ino_parts: Vec<_> = parts[5].split(':').collect(); ++ let ino: usize = ino_parts[2].parse().unwrap(); ++ if ino == inode { ++ return Some((lock_type.to_string(), lock_access.to_string())); ++ } ++ } ++ None ++ } + } + + #[cfg(any(target_os = "linux", +@@ -206,7 +332,7 @@ mod linux_android { + target_os = "fuchsia", + any(target_os = "wasi", target_env = "wasi"), + target_env = "uclibc", +- target_env = "freebsd"))] ++ target_os = "freebsd"))] + mod test_posix_fadvise { + + use tempfile::NamedTempFile; +@@ -232,3 +358,60 @@ mod test_posix_fadvise { + assert_eq!(errno, Errno::ESPIPE as i32); + } + } ++ ++#[cfg(any(target_os = "linux", ++ target_os = "android", ++ target_os = "emscripten", ++ target_os = "fuchsia", ++ any(target_os = "wasi", target_env = "wasi"), ++ target_os = "freebsd"))] ++mod test_posix_fallocate { ++ ++ use tempfile::NamedTempFile; ++ use std::{io::Read, os::unix::io::{RawFd, AsRawFd}}; ++ use nix::errno::Errno; ++ use nix::fcntl::*; ++ use nix::unistd::pipe; ++ ++ #[test] ++ fn success() { ++ const LEN: usize = 100; ++ let mut tmp = NamedTempFile::new().unwrap(); ++ let fd = tmp.as_raw_fd(); ++ let res = posix_fallocate(fd, 0, LEN as libc::off_t); ++ match res { ++ Ok(_) => { ++ let mut data = [1u8; LEN]; ++ assert_eq!(tmp.read(&mut data).expect("read failure"), LEN); ++ assert_eq!(&data[..], &[0u8; LEN][..]); ++ } ++ Err(nix::Error::Sys(Errno::EINVAL)) => { ++ // POSIX requires posix_fallocate to return EINVAL both for ++ // invalid arguments (i.e. len < 0) and if the operation is not ++ // supported by the file system. ++ // There's no way to tell for sure whether the file system ++ // supports posix_fallocate, so we must pass the test if it ++ // returns EINVAL. ++ } ++ _ => res.unwrap(), ++ } ++ } ++ ++ #[test] ++ fn errno() { ++ let (rd, _wr) = pipe().unwrap(); ++ let err = posix_fallocate(rd as RawFd, 0, 100).unwrap_err(); ++ use nix::Error::Sys; ++ match err { ++ Sys(Errno::EINVAL) ++ | Sys(Errno::ENODEV) ++ | Sys(Errno::ESPIPE) ++ | Sys(Errno::EBADF) => (), ++ errno => ++ panic!( ++ "unexpected errno {}", ++ errno, ++ ), ++ } ++ } ++} +diff --git a/third_party/rust/nix/test/test_kmod/mod.rs b/third_party/rust/nix/test/test_kmod/mod.rs +index ad406357b06d2..fb7260ba9c9d9 100644 +--- a/third_party/rust/nix/test/test_kmod/mod.rs ++++ b/third_party/rust/nix/test/test_kmod/mod.rs +@@ -2,9 +2,10 @@ use std::fs::copy; + use std::path::PathBuf; + use std::process::Command; + use tempfile::{tempdir, TempDir}; ++use crate::*; + + fn compile_kernel_module() -> (PathBuf, String, TempDir) { +- let _m = ::FORK_MTX ++ let _m = crate::FORK_MTX + .lock() + .expect("Mutex got poisoned by another test"); + +@@ -41,8 +42,8 @@ use std::io::Read; + #[test] + fn test_finit_and_delete_module() { + require_capability!(CAP_SYS_MODULE); +- let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); +- let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test"); ++ let _m0 = crate::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); ++ let _m1 = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test"); + + let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module(); + +@@ -59,8 +60,8 @@ fn test_finit_and_delete_module() { + #[test] + fn test_finit_and_delete_modul_with_params() { + require_capability!(CAP_SYS_MODULE); +- let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); +- let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test"); ++ let _m0 = crate::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); ++ let _m1 = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test"); + + let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module(); + +@@ -80,8 +81,8 @@ fn test_finit_and_delete_modul_with_params() { + #[test] + fn test_init_and_delete_module() { + require_capability!(CAP_SYS_MODULE); +- let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); +- let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test"); ++ let _m0 = crate::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); ++ let _m1 = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test"); + + let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module(); + +@@ -100,8 +101,8 @@ fn test_init_and_delete_module() { + #[test] + fn test_init_and_delete_module_with_params() { + require_capability!(CAP_SYS_MODULE); +- let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); +- let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test"); ++ let _m0 = crate::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); ++ let _m1 = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test"); + + let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module(); + +@@ -121,8 +122,8 @@ fn test_init_and_delete_module_with_params() { + #[test] + fn test_finit_module_invalid() { + require_capability!(CAP_SYS_MODULE); +- let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); +- let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test"); ++ let _m0 = crate::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); ++ let _m1 = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test"); + + let kmod_path = "/dev/zero"; + +@@ -135,8 +136,8 @@ fn test_finit_module_invalid() { + #[test] + fn test_finit_module_twice_and_delete_module() { + require_capability!(CAP_SYS_MODULE); +- let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); +- let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test"); ++ let _m0 = crate::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); ++ let _m1 = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test"); + + let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module(); + +@@ -157,8 +158,8 @@ fn test_finit_module_twice_and_delete_module() { + #[test] + fn test_delete_module_not_loaded() { + require_capability!(CAP_SYS_MODULE); +- let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); +- let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test"); ++ let _m0 = crate::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); ++ let _m1 = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test"); + + let result = delete_module(&CString::new("hello").unwrap(), DeleteModuleFlags::empty()); + +diff --git a/third_party/rust/nix/test/test_mount.rs b/third_party/rust/nix/test/test_mount.rs +index d2e08bc42855d..c1b6c8a3bf2d2 100644 +--- a/third_party/rust/nix/test/test_mount.rs ++++ b/third_party/rust/nix/test/test_mount.rs +@@ -1,12 +1,10 @@ ++mod common; ++ + // Impelmentation note: to allow unprivileged users to run it, this test makes + // use of user and mount namespaces. On systems that allow unprivileged user + // namespaces (Linux >= 3.8 compiled with CONFIG_USER_NS), the test should run + // without root. + +-extern crate libc; +-extern crate nix; +-extern crate tempfile; +- + #[cfg(target_os = "linux")] + mod test_mount { + use std::fs::{self, File}; +@@ -226,6 +224,7 @@ fn main() { + use test_mount::{setup_namespaces, test_mount_tmpfs_without_flags_allows_rwx, + test_mount_rdonly_disallows_write, test_mount_noexec_disallows_exec, + test_mount_bind}; ++ skip_if_cirrus!("Fails for an unknown reason Cirrus CI. Bug #1351"); + setup_namespaces(); + + run_tests!(test_mount_tmpfs_without_flags_allows_rwx, +diff --git a/third_party/rust/nix/test/test_mq.rs b/third_party/rust/nix/test/test_mq.rs +index caac4fc261cd6..1667a35b1a04b 100644 +--- a/third_party/rust/nix/test/test_mq.rs ++++ b/third_party/rust/nix/test/test_mq.rs +@@ -1,17 +1,15 @@ +-use libc::c_long; +- + use std::ffi::CString; + use std::str; + + use nix::errno::Errno::*; + use nix::Error::Sys; +-use nix::mqueue::{mq_open, mq_close, mq_send, mq_receive}; ++use nix::mqueue::{mq_open, mq_close, mq_send, mq_receive, mq_attr_member_t}; + use nix::mqueue::{MqAttr, MQ_OFlag}; + use nix::sys::stat::Mode; + + #[test] + fn test_mq_send_and_receive() { +- const MSG_SIZE: c_long = 32; ++ const MSG_SIZE: mq_attr_member_t = 32; + let attr = MqAttr::new(0, 10, MSG_SIZE, 0); + let mq_name= &CString::new(b"/a_nix_test_queue".as_ref()).unwrap(); + +@@ -31,7 +29,7 @@ fn test_mq_send_and_receive() { + let mut buf = [0u8; 32]; + let mut prio = 0u32; + let len = mq_receive(mqd1, &mut buf, &mut prio).unwrap(); +- assert!(prio == 1); ++ assert_eq!(prio, 1); + + mq_close(mqd1).unwrap(); + mq_close(mqd0).unwrap(); +@@ -43,7 +41,7 @@ fn test_mq_send_and_receive() { + #[cfg(not(any(target_os = "netbsd")))] + fn test_mq_getattr() { + use nix::mqueue::mq_getattr; +- const MSG_SIZE: c_long = 32; ++ const MSG_SIZE: mq_attr_member_t = 32; + let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0); + let mq_name = &CString::new(b"/attr_test_get_attr".as_ref()).unwrap(); + let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; +@@ -66,7 +64,7 @@ fn test_mq_getattr() { + #[cfg_attr(any(target_arch = "mips", target_arch = "mips64"), ignore)] + fn test_mq_setattr() { + use nix::mqueue::{mq_getattr, mq_setattr}; +- const MSG_SIZE: c_long = 32; ++ const MSG_SIZE: mq_attr_member_t = 32; + let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0); + let mq_name = &CString::new(b"/attr_test_get_attr".as_ref()).unwrap(); + let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; +@@ -87,7 +85,7 @@ fn test_mq_setattr() { + // O_NONBLOCK can be set (see tests below) + assert_ne!(new_attr_get, new_attr); + +- let new_attr_non_blocking = MqAttr::new(MQ_OFlag::O_NONBLOCK.bits() as c_long, 10, MSG_SIZE, 0); ++ let new_attr_non_blocking = MqAttr::new(MQ_OFlag::O_NONBLOCK.bits() as mq_attr_member_t, 10, MSG_SIZE, 0); + mq_setattr(mqd, &new_attr_non_blocking).unwrap(); + let new_attr_get = mq_getattr(mqd).unwrap(); + +@@ -103,7 +101,7 @@ fn test_mq_setattr() { + #[cfg_attr(any(target_arch = "mips", target_arch = "mips64"), ignore)] + fn test_mq_set_nonblocking() { + use nix::mqueue::{mq_getattr, mq_set_nonblock, mq_remove_nonblock}; +- const MSG_SIZE: c_long = 32; ++ const MSG_SIZE: mq_attr_member_t = 32; + let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0); + let mq_name = &CString::new(b"/attr_test_get_attr".as_ref()).unwrap(); + let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; +@@ -116,10 +114,10 @@ fn test_mq_set_nonblocking() { + let mqd = r.unwrap(); + mq_set_nonblock(mqd).unwrap(); + let new_attr = mq_getattr(mqd); +- assert!(new_attr.unwrap().flags() == MQ_OFlag::O_NONBLOCK.bits() as c_long); ++ assert_eq!(new_attr.unwrap().flags(), MQ_OFlag::O_NONBLOCK.bits() as mq_attr_member_t); + mq_remove_nonblock(mqd).unwrap(); + let new_attr = mq_getattr(mqd); +- assert!(new_attr.unwrap().flags() == 0); ++ assert_eq!(new_attr.unwrap().flags(), 0); + mq_close(mqd).unwrap(); + } + +@@ -127,7 +125,7 @@ fn test_mq_set_nonblocking() { + #[cfg(not(any(target_os = "netbsd")))] + fn test_mq_unlink() { + use nix::mqueue::mq_unlink; +- const MSG_SIZE: c_long = 32; ++ const MSG_SIZE: mq_attr_member_t = 32; + let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0); + let mq_name_opened = &CString::new(b"/mq_unlink_test".as_ref()).unwrap(); + let mq_name_not_opened = &CString::new(b"/mq_unlink_test".as_ref()).unwrap(); +@@ -141,12 +139,12 @@ fn test_mq_unlink() { + let mqd = r.unwrap(); + + let res_unlink = mq_unlink(mq_name_opened); +- assert!(res_unlink == Ok(()) ); ++ assert_eq!(res_unlink, Ok(()) ); + + let res_unlink_not_opened = mq_unlink(mq_name_not_opened); +- assert!(res_unlink_not_opened == Err(Sys(ENOENT)) ); ++ assert_eq!(res_unlink_not_opened, Err(Sys(ENOENT)) ); + + mq_close(mqd).unwrap(); + let res_unlink_after_close = mq_unlink(mq_name_opened); +- assert!(res_unlink_after_close == Err(Sys(ENOENT)) ); ++ assert_eq!(res_unlink_after_close, Err(Sys(ENOENT)) ); + } +diff --git a/third_party/rust/nix/test/test_poll.rs b/third_party/rust/nix/test/test_poll.rs +index aef40e4792b5a..acfaad8bea6c0 100644 +--- a/third_party/rust/nix/test/test_poll.rs ++++ b/third_party/rust/nix/test/test_poll.rs +@@ -1,5 +1,21 @@ +-use nix::poll::{PollFlags, poll, PollFd}; +-use nix::unistd::{write, pipe}; ++use nix::{ ++ Error, ++ errno::Errno, ++ poll::{PollFlags, poll, PollFd}, ++ unistd::{write, pipe} ++}; ++ ++macro_rules! loop_while_eintr { ++ ($poll_expr: expr) => { ++ loop { ++ match $poll_expr { ++ Ok(nfds) => break nfds, ++ Err(Error::Sys(Errno::EINTR)) => (), ++ Err(e) => panic!("{}", e) ++ } ++ } ++ } ++} + + #[test] + fn test_poll() { +@@ -7,7 +23,7 @@ fn test_poll() { + let mut fds = [PollFd::new(r, PollFlags::POLLIN)]; + + // Poll an idle pipe. Should timeout +- let nfds = poll(&mut fds, 100).unwrap(); ++ let nfds = loop_while_eintr!(poll(&mut fds, 100)); + assert_eq!(nfds, 0); + assert!(!fds[0].revents().unwrap().contains(PollFlags::POLLIN)); + +@@ -37,14 +53,15 @@ fn test_ppoll() { + let mut fds = [PollFd::new(r, PollFlags::POLLIN)]; + + // Poll an idle pipe. Should timeout +- let nfds = ppoll(&mut fds, timeout, SigSet::empty()).unwrap(); ++ let sigset = SigSet::empty(); ++ let nfds = loop_while_eintr!(ppoll(&mut fds, Some(timeout), sigset)); + assert_eq!(nfds, 0); + assert!(!fds[0].revents().unwrap().contains(PollFlags::POLLIN)); + + write(w, b".").unwrap(); + + // Poll a readable pipe. Should return an event. +- let nfds = ppoll(&mut fds, timeout, SigSet::empty()).unwrap(); ++ let nfds = ppoll(&mut fds, Some(timeout), SigSet::empty()).unwrap(); + assert_eq!(nfds, 1); + assert!(fds[0].revents().unwrap().contains(PollFlags::POLLIN)); + } +diff --git a/third_party/rust/nix/test/test_pty.rs b/third_party/rust/nix/test/test_pty.rs +index 476b15c10128c..ab347bb040f5f 100644 +--- a/third_party/rust/nix/test/test_pty.rs ++++ b/third_party/rust/nix/test/test_pty.rs +@@ -1,4 +1,5 @@ +-use std::io::Write; ++use std::fs::File; ++use std::io::{Read, Write}; + use std::path::Path; + use std::os::unix::prelude::*; + use tempfile::tempfile; +@@ -28,7 +29,7 @@ fn test_explicit_close() { + #[test] + #[cfg(any(target_os = "android", target_os = "linux"))] + fn test_ptsname_equivalence() { +- let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); ++ let _m = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); + + // Open a new PTTY master + let master_fd = posix_openpt(OFlag::O_RDWR).unwrap(); +@@ -45,7 +46,7 @@ fn test_ptsname_equivalence() { + #[test] + #[cfg(any(target_os = "android", target_os = "linux"))] + fn test_ptsname_copy() { +- let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); ++ let _m = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); + + // Open a new PTTY master + let master_fd = posix_openpt(OFlag::O_RDWR).unwrap(); +@@ -54,7 +55,7 @@ fn test_ptsname_copy() { + // Get the name of the slave + let slave_name1 = unsafe { ptsname(&master_fd) }.unwrap(); + let slave_name2 = unsafe { ptsname(&master_fd) }.unwrap(); +- assert!(slave_name1 == slave_name2); ++ assert_eq!(slave_name1, slave_name2); + // Also make sure that the string was actually copied and they point to different parts of + // memory. + assert!(slave_name1.as_ptr() != slave_name2.as_ptr()); +@@ -71,7 +72,7 @@ fn test_ptsname_r_copy() { + // Get the name of the slave + let slave_name1 = ptsname_r(&master_fd).unwrap(); + let slave_name2 = ptsname_r(&master_fd).unwrap(); +- assert!(slave_name1 == slave_name2); ++ assert_eq!(slave_name1, slave_name2); + assert!(slave_name1.as_ptr() != slave_name2.as_ptr()); + } + +@@ -79,7 +80,7 @@ fn test_ptsname_r_copy() { + #[test] + #[cfg(any(target_os = "android", target_os = "linux"))] + fn test_ptsname_unique() { +- let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); ++ let _m = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); + + // Open a new PTTY master + let master1_fd = posix_openpt(OFlag::O_RDWR).unwrap(); +@@ -95,35 +96,74 @@ fn test_ptsname_unique() { + assert!(slave_name1 != slave_name2); + } + +-/// Test opening a master/slave PTTY pair +-/// +-/// This is a single larger test because much of these functions aren't useful by themselves. So for +-/// this test we perform the basic act of getting a file handle for a connect master/slave PTTY +-/// pair. +-#[test] +-fn test_open_ptty_pair() { +- let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); ++/// Common setup for testing PTTY pairs ++fn open_ptty_pair() -> (PtyMaster, File) { ++ let _m = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); + + // Open a new PTTY master +- let master_fd = posix_openpt(OFlag::O_RDWR).expect("posix_openpt failed"); +- assert!(master_fd.as_raw_fd() > 0); ++ let master = posix_openpt(OFlag::O_RDWR).expect("posix_openpt failed"); + + // Allow a slave to be generated for it +- grantpt(&master_fd).expect("grantpt failed"); +- unlockpt(&master_fd).expect("unlockpt failed"); ++ grantpt(&master).expect("grantpt failed"); ++ unlockpt(&master).expect("unlockpt failed"); + + // Get the name of the slave +- let slave_name = unsafe { ptsname(&master_fd) }.expect("ptsname failed"); ++ let slave_name = unsafe { ptsname(&master) }.expect("ptsname failed"); + + // Open the slave device + let slave_fd = open(Path::new(&slave_name), OFlag::O_RDWR, stat::Mode::empty()).unwrap(); +- assert!(slave_fd > 0); ++ let slave = unsafe { File::from_raw_fd(slave_fd) }; ++ ++ (master, slave) ++} ++ ++/// Test opening a master/slave PTTY pair ++/// ++/// This uses a common `open_ptty_pair` because much of these functions aren't useful by ++/// themselves. So for this test we perform the basic act of getting a file handle for a ++/// master/slave PTTY pair, then just sanity-check the raw values. ++#[test] ++fn test_open_ptty_pair() { ++ let (master, slave) = open_ptty_pair(); ++ assert!(master.as_raw_fd() > 0); ++ assert!(slave.as_raw_fd() > 0); ++} ++ ++/// Put the terminal in raw mode. ++fn make_raw(fd: RawFd) { ++ let mut termios = tcgetattr(fd).unwrap(); ++ cfmakeraw(&mut termios); ++ tcsetattr(fd, SetArg::TCSANOW, &termios).unwrap(); ++} ++ ++/// Test `io::Read` on the PTTY master ++#[test] ++fn test_read_ptty_pair() { ++ let (mut master, mut slave) = open_ptty_pair(); ++ make_raw(slave.as_raw_fd()); ++ ++ let mut buf = [0u8; 5]; ++ slave.write_all(b"hello").unwrap(); ++ master.read_exact(&mut buf).unwrap(); ++ assert_eq!(&buf, b"hello"); ++} ++ ++/// Test `io::Write` on the PTTY master ++#[test] ++fn test_write_ptty_pair() { ++ let (mut master, mut slave) = open_ptty_pair(); ++ make_raw(slave.as_raw_fd()); ++ ++ let mut buf = [0u8; 5]; ++ master.write_all(b"adios").unwrap(); ++ slave.read_exact(&mut buf).unwrap(); ++ assert_eq!(&buf, b"adios"); + } + + #[test] + fn test_openpty() { + // openpty uses ptname(3) internally +- let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); ++ let _m = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); + + let pty = openpty(None, None).unwrap(); + assert!(pty.master > 0); +@@ -133,21 +173,21 @@ fn test_openpty() { + let string = "foofoofoo\n"; + let mut buf = [0u8; 10]; + write(pty.master, string.as_bytes()).unwrap(); +- ::read_exact(pty.slave, &mut buf); ++ crate::read_exact(pty.slave, &mut buf); + + assert_eq!(&buf, string.as_bytes()); + + // Read the echo as well + let echoed_string = "foofoofoo\r\n"; + let mut buf = [0u8; 11]; +- ::read_exact(pty.master, &mut buf); ++ crate::read_exact(pty.master, &mut buf); + assert_eq!(&buf, echoed_string.as_bytes()); + + let string2 = "barbarbarbar\n"; + let echoed_string2 = "barbarbarbar\r\n"; + let mut buf = [0u8; 14]; + write(pty.slave, string2.as_bytes()).unwrap(); +- ::read_exact(pty.master, &mut buf); ++ crate::read_exact(pty.master, &mut buf); + + assert_eq!(&buf, echoed_string2.as_bytes()); + +@@ -158,14 +198,14 @@ fn test_openpty() { + #[test] + fn test_openpty_with_termios() { + // openpty uses ptname(3) internally +- let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); ++ let _m = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); + + // Open one pty to get attributes for the second one + let mut termios = { + let pty = openpty(None, None).unwrap(); + assert!(pty.master > 0); + assert!(pty.slave > 0); +- let termios = tcgetattr(pty.master).unwrap(); ++ let termios = tcgetattr(pty.slave).unwrap(); + close(pty.master).unwrap(); + close(pty.slave).unwrap(); + termios +@@ -182,20 +222,20 @@ fn test_openpty_with_termios() { + let string = "foofoofoo\n"; + let mut buf = [0u8; 10]; + write(pty.master, string.as_bytes()).unwrap(); +- ::read_exact(pty.slave, &mut buf); ++ crate::read_exact(pty.slave, &mut buf); + + assert_eq!(&buf, string.as_bytes()); + + // read the echo as well + let echoed_string = "foofoofoo\n"; +- ::read_exact(pty.master, &mut buf); ++ crate::read_exact(pty.master, &mut buf); + assert_eq!(&buf, echoed_string.as_bytes()); + + let string2 = "barbarbarbar\n"; + let echoed_string2 = "barbarbarbar\n"; + let mut buf = [0u8; 13]; + write(pty.slave, string2.as_bytes()).unwrap(); +- ::read_exact(pty.master, &mut buf); ++ crate::read_exact(pty.master, &mut buf); + + assert_eq!(&buf, echoed_string2.as_bytes()); + +@@ -209,9 +249,9 @@ fn test_forkpty() { + use nix::sys::signal::*; + use nix::sys::wait::wait; + // forkpty calls openpty which uses ptname(3) internally. +- let _m0 = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); ++ let _m0 = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); + // forkpty spawns a child process +- let _m1 = ::FORK_MTX.lock().expect("Mutex got poisoned by another test"); ++ let _m1 = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test"); + + let string = "naninani\n"; + let echoed_string = "naninani\r\n"; +@@ -225,7 +265,7 @@ fn test_forkpty() { + Parent { child } => { + let mut buf = [0u8; 10]; + assert!(child.as_raw() > 0); +- ::read_exact(pty.master, &mut buf); ++ crate::read_exact(pty.master, &mut buf); + kill(child, SIGTERM).unwrap(); + wait().unwrap(); // keep other tests using generic wait from getting our child + assert_eq!(&buf, echoed_string.as_bytes()); +diff --git a/third_party/rust/nix/test/test_ptymaster_drop.rs b/third_party/rust/nix/test/test_ptymaster_drop.rs +index 9b59d66435ed0..ff939b9c63e76 100644 +--- a/third_party/rust/nix/test/test_ptymaster_drop.rs ++++ b/third_party/rust/nix/test/test_ptymaster_drop.rs +@@ -1,21 +1,24 @@ +-extern crate nix; ++#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] ++mod t { ++ use nix::fcntl::OFlag; ++ use nix::pty::*; ++ use nix::unistd::close; ++ use std::os::unix::io::AsRawFd; + +-use nix::fcntl::OFlag; +-use nix::pty::*; +-use nix::unistd::close; +-use std::os::unix::io::AsRawFd; +- +-/// Regression test for Issue #659 +-/// `PtyMaster` should panic rather than double close the file descriptor +-/// This must run in its own test process because it deliberately creates a race +-/// condition. +-#[test] +-#[should_panic(expected = "Closing an invalid file descriptor!")] +-// In Travis on i686-unknown-linux-musl, this test gets SIGABRT. I don't know +-// why. It doesn't happen on any other target, and it doesn't happen on my PC. +-#[cfg_attr(all(target_env = "musl", target_arch = "x86"), ignore)] +-fn test_double_close() { +- let m = posix_openpt(OFlag::O_RDWR).unwrap(); +- close(m.as_raw_fd()).unwrap(); +- drop(m); // should panic here ++ /// Regression test for Issue #659 ++ /// ++ /// `PtyMaster` should panic rather than double close the file descriptor ++ /// This must run in its own test process because it deliberately creates a ++ /// race condition. ++ #[test] ++ #[should_panic(expected = "Closing an invalid file descriptor!")] ++ // In Travis on i686-unknown-linux-musl, this test gets SIGABRT. I don't ++ // know why. It doesn't happen on any other target, and it doesn't happen ++ // on my PC. ++ #[cfg_attr(all(target_env = "musl", target_arch = "x86"), ignore)] ++ fn test_double_close() { ++ let m = posix_openpt(OFlag::O_RDWR).unwrap(); ++ close(m.as_raw_fd()).unwrap(); ++ drop(m); // should panic here ++ } + } +diff --git a/third_party/rust/nix/test/test_sched.rs b/third_party/rust/nix/test/test_sched.rs +new file mode 100644 +index 0000000000000..922196a3dba73 +--- /dev/null ++++ b/third_party/rust/nix/test/test_sched.rs +@@ -0,0 +1,32 @@ ++use nix::sched::{sched_getaffinity, sched_setaffinity, CpuSet}; ++use nix::unistd::Pid; ++ ++#[test] ++fn test_sched_affinity() { ++ // If pid is zero, then the mask of the calling process is returned. ++ let initial_affinity = sched_getaffinity(Pid::from_raw(0)).unwrap(); ++ let mut at_least_one_cpu = false; ++ let mut last_valid_cpu = 0; ++ for field in 0..CpuSet::count() { ++ if initial_affinity.is_set(field).unwrap() { ++ at_least_one_cpu = true; ++ last_valid_cpu = field; ++ } ++ } ++ assert!(at_least_one_cpu); ++ ++ // Now restrict the running CPU ++ let mut new_affinity = CpuSet::new(); ++ new_affinity.set(last_valid_cpu).unwrap(); ++ sched_setaffinity(Pid::from_raw(0), &new_affinity).unwrap(); ++ ++ // And now re-check the affinity which should be only the one we set. ++ let updated_affinity = sched_getaffinity(Pid::from_raw(0)).unwrap(); ++ for field in 0..CpuSet::count() { ++ // Should be set only for the CPU we set previously ++ assert_eq!(updated_affinity.is_set(field).unwrap(), field==last_valid_cpu) ++ } ++ ++ // Finally, reset the initial CPU set ++ sched_setaffinity(Pid::from_raw(0), &initial_affinity).unwrap(); ++} +diff --git a/third_party/rust/nix/test/test_stat.rs b/third_party/rust/nix/test/test_stat.rs +index 1173455fae8db..0b9466685607b 100644 +--- a/third_party/rust/nix/test/test_stat.rs ++++ b/third_party/rust/nix/test/test_stat.rs +@@ -1,15 +1,26 @@ +-use std::fs::{self, File}; ++#[cfg(not(target_os = "redox"))] ++use std::fs; ++use std::fs::File; ++#[cfg(not(target_os = "redox"))] + use std::os::unix::fs::{symlink, PermissionsExt}; + use std::os::unix::prelude::AsRawFd; ++#[cfg(not(target_os = "redox"))] + use std::time::{Duration, UNIX_EPOCH}; ++#[cfg(not(target_os = "redox"))] + use std::path::Path; + +-#[cfg(not(any(target_os = "netbsd")))] ++#[cfg(not(any(target_os = "netbsd", target_os = "redox")))] + use libc::{S_IFMT, S_IFLNK, mode_t}; + ++#[cfg(not(target_os = "redox"))] + use nix::{fcntl, Error}; +-use nix::errno::{Errno}; +-use nix::sys::stat::{self, fchmod, fchmodat, futimens, stat, utimes, utimensat, mkdirat}; ++#[cfg(not(target_os = "redox"))] ++use nix::errno::Errno; ++#[cfg(not(target_os = "redox"))] ++use nix::sys::stat::{self, futimens, utimes}; ++use nix::sys::stat::{fchmod, stat}; ++#[cfg(not(target_os = "redox"))] ++use nix::sys::stat::{fchmodat, utimensat, mkdirat}; + #[cfg(any(target_os = "linux", + target_os = "haiku", + target_os = "ios", +@@ -17,15 +28,19 @@ use nix::sys::stat::{self, fchmod, fchmodat, futimens, stat, utimes, utimensat, + target_os = "freebsd", + target_os = "netbsd"))] + use nix::sys::stat::lutimes; +-use nix::sys::stat::{Mode, FchmodatFlags, UtimensatFlags}; ++#[cfg(not(target_os = "redox"))] ++use nix::sys::stat::{FchmodatFlags, UtimensatFlags}; ++use nix::sys::stat::Mode; + +-#[cfg(not(any(target_os = "netbsd")))] ++#[cfg(not(any(target_os = "netbsd", target_os = "redox")))] + use nix::sys::stat::FileStat; + ++#[cfg(not(target_os = "redox"))] + use nix::sys::time::{TimeSpec, TimeVal, TimeValLike}; ++#[cfg(not(target_os = "redox"))] + use nix::unistd::chdir; + +-#[cfg(not(any(target_os = "netbsd")))] ++#[cfg(not(any(target_os = "netbsd", target_os = "redox")))] + use nix::Result; + use tempfile; + +@@ -33,27 +48,27 @@ use tempfile; + // uid and gid are signed on Windows, but not on other platforms. This function + // allows warning free compiles on all platforms, and can be removed when + // expression-level #[allow] is available. +-#[cfg(not(any(target_os = "netbsd")))] ++#[cfg(not(any(target_os = "netbsd", target_os = "redox")))] + fn valid_uid_gid(stat: FileStat) -> bool { + // uid could be 0 for the `root` user. This quite possible when + // the tests are being run on a rooted Android device. + stat.st_uid >= 0 && stat.st_gid >= 0 + } + +-#[cfg(not(any(target_os = "netbsd")))] ++#[cfg(not(any(target_os = "netbsd", target_os = "redox")))] + fn assert_stat_results(stat_result: Result<FileStat>) { + let stats = stat_result.expect("stat call failed"); + assert!(stats.st_dev > 0); // must be positive integer, exact number machine dependent + assert!(stats.st_ino > 0); // inode is positive integer, exact number machine dependent + assert!(stats.st_mode > 0); // must be positive integer +- assert!(stats.st_nlink == 1); // there links created, must be 1 ++ assert_eq!(stats.st_nlink, 1); // there links created, must be 1 + assert!(valid_uid_gid(stats)); // must be positive integers +- assert!(stats.st_size == 0); // size is 0 because we did not write anything to the file ++ assert_eq!(stats.st_size, 0); // size is 0 because we did not write anything to the file + assert!(stats.st_blksize > 0); // must be positive integer, exact number machine dependent + assert!(stats.st_blocks <= 16); // Up to 16 blocks can be allocated for a blank file + } + +-#[cfg(not(any(target_os = "netbsd")))] ++#[cfg(not(any(target_os = "netbsd", target_os = "redox")))] + fn assert_lstat_results(stat_result: Result<FileStat>) { + let stats = stat_result.expect("stat call failed"); + assert!(stats.st_dev > 0); // must be positive integer, exact number machine dependent +@@ -63,8 +78,8 @@ fn assert_lstat_results(stat_result: Result<FileStat>) { + // st_mode is c_uint (u32 on Android) while S_IFMT is mode_t + // (u16 on Android), and that will be a compile error. + // On other platforms they are the same (either both are u16 or u32). +- assert!((stats.st_mode as usize) & (S_IFMT as usize) == S_IFLNK as usize); // should be a link +- assert!(stats.st_nlink == 1); // there links created, must be 1 ++ assert_eq!((stats.st_mode as usize) & (S_IFMT as usize), S_IFLNK as usize); // should be a link ++ assert_eq!(stats.st_nlink, 1); // there links created, must be 1 + assert!(valid_uid_gid(stats)); // must be positive integers + assert!(stats.st_size > 0); // size is > 0 because it points to another file + assert!(stats.st_blksize > 0); // must be positive integer, exact number machine dependent +@@ -76,7 +91,7 @@ fn assert_lstat_results(stat_result: Result<FileStat>) { + } + + #[test] +-#[cfg(not(any(target_os = "netbsd")))] ++#[cfg(not(any(target_os = "netbsd", target_os = "redox")))] + fn test_stat_and_fstat() { + use nix::sys::stat::fstat; + +@@ -92,7 +107,7 @@ fn test_stat_and_fstat() { + } + + #[test] +-#[cfg(not(any(target_os = "netbsd")))] ++#[cfg(not(any(target_os = "netbsd", target_os = "redox")))] + fn test_fstatat() { + let tempdir = tempfile::tempdir().unwrap(); + let filename = tempdir.path().join("foo.txt"); +@@ -108,7 +123,7 @@ fn test_fstatat() { + } + + #[test] +-#[cfg(not(any(target_os = "netbsd")))] ++#[cfg(not(any(target_os = "netbsd", target_os = "redox")))] + fn test_stat_fstat_lstat() { + use nix::sys::stat::{fstat, lstat}; + +@@ -155,8 +170,9 @@ fn test_fchmod() { + } + + #[test] ++#[cfg(not(target_os = "redox"))] + fn test_fchmodat() { +- let _dr = ::DirRestore::new(); ++ let _dr = crate::DirRestore::new(); + let tempdir = tempfile::tempdir().unwrap(); + let filename = "foo.txt"; + let fullpath = tempdir.path().join(filename); +@@ -186,6 +202,7 @@ fn test_fchmodat() { + /// + /// The atime and mtime are expressed with a resolution of seconds because some file systems + /// (like macOS's HFS+) do not have higher granularity. ++#[cfg(not(target_os = "redox"))] + fn assert_times_eq(exp_atime_sec: u64, exp_mtime_sec: u64, attr: &fs::Metadata) { + assert_eq!( + Duration::new(exp_atime_sec, 0), +@@ -196,6 +213,7 @@ fn assert_times_eq(exp_atime_sec: u64, exp_mtime_sec: u64, attr: &fs::Metadata) + } + + #[test] ++#[cfg(not(target_os = "redox"))] + fn test_utimes() { + let tempdir = tempfile::tempdir().unwrap(); + let fullpath = tempdir.path().join("file"); +@@ -231,6 +249,7 @@ fn test_lutimes() { + } + + #[test] ++#[cfg(not(target_os = "redox"))] + fn test_futimens() { + let tempdir = tempfile::tempdir().unwrap(); + let fullpath = tempdir.path().join("file"); +@@ -243,8 +262,9 @@ fn test_futimens() { + } + + #[test] ++#[cfg(not(target_os = "redox"))] + fn test_utimensat() { +- let _dr = ::DirRestore::new(); ++ let _dr = crate::DirRestore::new(); + let tempdir = tempfile::tempdir().unwrap(); + let filename = "foo.txt"; + let fullpath = tempdir.path().join(filename); +@@ -264,6 +284,7 @@ fn test_utimensat() { + } + + #[test] ++#[cfg(not(target_os = "redox"))] + fn test_mkdirat_success_path() { + let tempdir = tempfile::tempdir().unwrap(); + let filename = "example_subdir"; +@@ -273,6 +294,7 @@ fn test_mkdirat_success_path() { + } + + #[test] ++#[cfg(not(target_os = "redox"))] + fn test_mkdirat_success_mode() { + let expected_bits = stat::SFlag::S_IFDIR.bits() | stat::Mode::S_IRWXU.bits(); + let tempdir = tempfile::tempdir().unwrap(); +@@ -285,6 +307,7 @@ fn test_mkdirat_success_mode() { + } + + #[test] ++#[cfg(not(target_os = "redox"))] + fn test_mkdirat_fail() { + let tempdir = tempfile::tempdir().unwrap(); + let not_dir_filename= "example_not_dir"; +diff --git a/third_party/rust/nix/test/test_time.rs b/third_party/rust/nix/test/test_time.rs +new file mode 100644 +index 0000000000000..c321352d79c16 +--- /dev/null ++++ b/third_party/rust/nix/test/test_time.rs +@@ -0,0 +1,56 @@ ++#[cfg(any( ++ target_os = "freebsd", ++ target_os = "dragonfly", ++ target_os = "linux", ++ target_os = "android", ++ target_os = "emscripten", ++))] ++use nix::time::clock_getcpuclockid; ++use nix::time::{clock_getres, clock_gettime, ClockId}; ++ ++#[test] ++pub fn test_clock_getres() { ++ assert!(clock_getres(ClockId::CLOCK_REALTIME).is_ok()); ++} ++ ++#[test] ++pub fn test_clock_gettime() { ++ assert!(clock_gettime(ClockId::CLOCK_REALTIME).is_ok()); ++} ++ ++#[cfg(any( ++ target_os = "freebsd", ++ target_os = "dragonfly", ++ target_os = "linux", ++ target_os = "android", ++ target_os = "emscripten", ++))] ++#[test] ++pub fn test_clock_getcpuclockid() { ++ let clock_id = clock_getcpuclockid(nix::unistd::Pid::this()).unwrap(); ++ assert!(clock_gettime(clock_id).is_ok()); ++} ++ ++#[test] ++pub fn test_clock_id_res() { ++ assert!(ClockId::CLOCK_REALTIME.res().is_ok()); ++} ++ ++#[test] ++pub fn test_clock_id_now() { ++ assert!(ClockId::CLOCK_REALTIME.now().is_ok()); ++} ++ ++#[cfg(any( ++ target_os = "freebsd", ++ target_os = "dragonfly", ++ target_os = "linux", ++ target_os = "android", ++ target_os = "emscripten", ++))] ++#[test] ++pub fn test_clock_id_pid_cpu_clock_id() { ++ assert!(ClockId::pid_cpu_clock_id(nix::unistd::Pid::this()) ++ .map(ClockId::now) ++ .is_ok()); ++} +diff --git a/third_party/rust/nix/test/test_unistd.rs b/third_party/rust/nix/test/test_unistd.rs +index 46196dec7ccce..16a8a05dd6d08 100644 +--- a/third_party/rust/nix/test/test_unistd.rs ++++ b/third_party/rust/nix/test/test_unistd.rs +@@ -1,26 +1,39 @@ +-use nix::fcntl::{self, fcntl, FcntlArg, FdFlag, open, OFlag, readlink}; ++#[cfg(not(target_os = "redox"))] ++use nix::fcntl::{self, open, readlink}; ++use nix::fcntl::{fcntl, FcntlArg, FdFlag, OFlag}; + use nix::unistd::*; + use nix::unistd::ForkResult::*; ++#[cfg(not(target_os = "redox"))] + use nix::sys::signal::{SaFlags, SigAction, SigHandler, SigSet, Signal, sigaction}; + use nix::sys::wait::*; + use nix::sys::stat::{self, Mode, SFlag}; ++#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] ++use nix::pty::{posix_openpt, grantpt, unlockpt, ptsname}; + use nix::errno::Errno; ++#[cfg(not(target_os = "redox"))] + use nix::Error; + use std::{env, iter}; ++#[cfg(not(target_os = "redox"))] + use std::ffi::CString; +-use std::fs::{self, DirBuilder, File}; ++#[cfg(not(target_os = "redox"))] ++use std::fs::DirBuilder; ++use std::fs::{self, File}; + use std::io::Write; + use std::os::unix::prelude::*; +-use tempfile::{self, tempfile}; +-use libc::{self, _exit, off_t}; ++#[cfg(not(target_os = "redox"))] ++use std::path::Path; ++use tempfile::{tempdir, tempfile}; ++use libc::{_exit, off_t}; ++ ++use crate::*; + + #[test] + #[cfg(not(any(target_os = "netbsd")))] + fn test_fork_and_waitpid() { +- let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test"); ++ let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test"); + + // Safe: Child only calls `_exit`, which is signal-safe +- match fork().expect("Error: Fork Failed") { ++ match unsafe{fork()}.expect("Error: Fork Failed") { + Child => unsafe { _exit(0) }, + Parent { child } => { + // assert that child was created and pid > 0 +@@ -29,7 +42,7 @@ fn test_fork_and_waitpid() { + let wait_status = waitpid(child, None); + match wait_status { + // assert that waitpid returned correct status and the pid is the one of the child +- Ok(WaitStatus::Exited(pid_t, _)) => assert!(pid_t == child), ++ Ok(WaitStatus::Exited(pid_t, _)) => assert_eq!(pid_t, child), + + // panic, must never happen + s @ Ok(_) => panic!("Child exited {:?}, should never happen", s), +@@ -45,10 +58,10 @@ fn test_fork_and_waitpid() { + #[test] + fn test_wait() { + // Grab FORK_MTX so wait doesn't reap a different test's child process +- let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test"); ++ let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test"); + + // Safe: Child only calls `_exit`, which is signal-safe +- match fork().expect("Error: Fork Failed") { ++ match unsafe{fork()}.expect("Error: Fork Failed") { + Child => unsafe { _exit(0) }, + Parent { child } => { + let wait_status = wait(); +@@ -81,8 +94,9 @@ fn test_mkstemp_directory() { + } + + #[test] ++#[cfg(not(target_os = "redox"))] + fn test_mkfifo() { +- let tempdir = tempfile::tempdir().unwrap(); ++ let tempdir = tempdir().unwrap(); + let mkfifo_fifo = tempdir.path().join("mkfifo_fifo"); + + mkfifo(&mkfifo_fifo, Mode::S_IRUSR).unwrap(); +@@ -93,11 +107,70 @@ fn test_mkfifo() { + } + + #[test] ++#[cfg(not(target_os = "redox"))] + fn test_mkfifo_directory() { + // mkfifo should fail if a directory is given + assert!(mkfifo(&env::temp_dir(), Mode::S_IRUSR).is_err()); + } + ++#[test] ++#[cfg(not(any( ++ target_os = "macos", target_os = "ios", ++ target_os = "android", target_os = "redox")))] ++fn test_mkfifoat_none() { ++ let _m = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test"); ++ ++ let tempdir = tempdir().unwrap(); ++ let mkfifoat_fifo = tempdir.path().join("mkfifoat_fifo"); ++ ++ mkfifoat(None, &mkfifoat_fifo, Mode::S_IRUSR).unwrap(); ++ ++ let stats = stat::stat(&mkfifoat_fifo).unwrap(); ++ let typ = stat::SFlag::from_bits_truncate(stats.st_mode); ++ assert_eq!(typ, SFlag::S_IFIFO); ++} ++ ++#[test] ++#[cfg(not(any( ++ target_os = "macos", target_os = "ios", ++ target_os = "android", target_os = "redox")))] ++fn test_mkfifoat() { ++ let tempdir = tempdir().unwrap(); ++ let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); ++ let mkfifoat_name = "mkfifoat_name"; ++ ++ mkfifoat(Some(dirfd), mkfifoat_name, Mode::S_IRUSR).unwrap(); ++ ++ let stats = stat::fstatat(dirfd, mkfifoat_name, fcntl::AtFlags::empty()).unwrap(); ++ let typ = stat::SFlag::from_bits_truncate(stats.st_mode); ++ assert_eq!(typ, SFlag::S_IFIFO); ++} ++ ++#[test] ++#[cfg(not(any( ++ target_os = "macos", target_os = "ios", ++ target_os = "android", target_os = "redox")))] ++fn test_mkfifoat_directory_none() { ++ let _m = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test"); ++ ++ // mkfifoat should fail if a directory is given ++ assert!(!mkfifoat(None, &env::temp_dir(), Mode::S_IRUSR).is_ok()); ++} ++ ++#[test] ++#[cfg(not(any( ++ target_os = "macos", target_os = "ios", ++ target_os = "android", target_os = "redox")))] ++fn test_mkfifoat_directory() { ++ // mkfifoat should fail if a directory is given ++ let tempdir = tempdir().unwrap(); ++ let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); ++ let mkfifoat_dir = "mkfifoat_dir"; ++ stat::mkdirat(dirfd, mkfifoat_dir, Mode::S_IRUSR).unwrap(); ++ ++ assert!(!mkfifoat(Some(dirfd), mkfifoat_dir, Mode::S_IRUSR).is_ok()); ++} ++ + #[test] + fn test_getpid() { + let pid: ::libc::pid_t = getpid().into(); +@@ -107,11 +180,12 @@ fn test_getpid() { + } + + #[test] ++#[cfg(not(target_os = "redox"))] + fn test_getsid() { + let none_sid: ::libc::pid_t = getsid(None).unwrap().into(); + let pid_sid: ::libc::pid_t = getsid(Some(getpid())).unwrap().into(); + assert!(none_sid > 0); +- assert!(none_sid == pid_sid); ++ assert_eq!(none_sid, pid_sid); + } + + #[cfg(any(target_os = "linux", target_os = "android"))] +@@ -127,12 +201,12 @@ mod linux_android { + + #[test] + // `getgroups()` and `setgroups()` do not behave as expected on Apple platforms +-#[cfg(not(any(target_os = "ios", target_os = "macos")))] ++#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox", target_os = "fuchsia")))] + fn test_setgroups() { + // Skip this test when not run as root as `setgroups()` requires root. + skip_if_not_root!("test_setgroups"); + +- let _m = ::GROUPS_MTX.lock().expect("Mutex got poisoned by another test"); ++ let _m = crate::GROUPS_MTX.lock().expect("Mutex got poisoned by another test"); + + // Save the existing groups + let old_groups = getgroups().unwrap(); +@@ -150,13 +224,13 @@ fn test_setgroups() { + + #[test] + // `getgroups()` and `setgroups()` do not behave as expected on Apple platforms +-#[cfg(not(any(target_os = "ios", target_os = "macos")))] ++#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox", target_os = "fuchsia")))] + fn test_initgroups() { + // Skip this test when not run as root as `initgroups()` and `setgroups()` + // require root. + skip_if_not_root!("test_initgroups"); + +- let _m = ::GROUPS_MTX.lock().expect("Mutex got poisoned by another test"); ++ let _m = crate::GROUPS_MTX.lock().expect("Mutex got poisoned by another test"); + + // Save the existing groups + let old_groups = getgroups().unwrap(); +@@ -180,11 +254,53 @@ fn test_initgroups() { + setgroups(&old_groups).unwrap(); + } + ++#[cfg(not(target_os = "redox"))] + macro_rules! execve_test_factory( + ($test_name:ident, $syscall:ident, $exe: expr $(, $pathname:expr, $flags:expr)*) => ( +- #[test] +- fn $test_name() { +- let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test"); ++ ++ #[cfg(test)] ++ mod $test_name { ++ use std::ffi::CStr; ++ use super::*; ++ ++ const EMPTY: &'static [u8] = b"\0"; ++ const DASH_C: &'static [u8] = b"-c\0"; ++ const BIGARG: &'static [u8] = b"echo nix!!! && echo foo=$foo && echo baz=$baz\0"; ++ const FOO: &'static [u8] = b"foo=bar\0"; ++ const BAZ: &'static [u8] = b"baz=quux\0"; ++ ++ fn syscall_cstr_ref() -> Result<std::convert::Infallible, nix::Error> { ++ $syscall( ++ $exe, ++ $(CString::new($pathname).unwrap().as_c_str(), )* ++ &[CStr::from_bytes_with_nul(EMPTY).unwrap(), ++ CStr::from_bytes_with_nul(DASH_C).unwrap(), ++ CStr::from_bytes_with_nul(BIGARG).unwrap()], ++ &[CStr::from_bytes_with_nul(FOO).unwrap(), ++ CStr::from_bytes_with_nul(BAZ).unwrap()] ++ $(, $flags)*) ++ } ++ ++ fn syscall_cstring() -> Result<std::convert::Infallible, nix::Error> { ++ $syscall( ++ $exe, ++ $(CString::new($pathname).unwrap().as_c_str(), )* ++ &[CString::from(CStr::from_bytes_with_nul(EMPTY).unwrap()), ++ CString::from(CStr::from_bytes_with_nul(DASH_C).unwrap()), ++ CString::from(CStr::from_bytes_with_nul(BIGARG).unwrap())], ++ &[CString::from(CStr::from_bytes_with_nul(FOO).unwrap()), ++ CString::from(CStr::from_bytes_with_nul(BAZ).unwrap())] ++ $(, $flags)*) ++ } ++ ++ fn common_test(syscall: fn() -> Result<std::convert::Infallible, nix::Error>) { ++ if "execveat" == stringify!($syscall) { ++ // Though undocumented, Docker's default seccomp profile seems to ++ // block this syscall. https://github.com/nix-rust/nix/issues/1122 ++ skip_if_seccomp!($test_name); ++ } ++ ++ let m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test"); + // The `exec`d process will write to `writer`, and we'll read that + // data from `reader`. + let (reader, writer) = pipe().unwrap(); +@@ -192,27 +308,21 @@ macro_rules! execve_test_factory( + // Safe: Child calls `exit`, `dup`, `close` and the provided `exec*` family function. + // NOTE: Technically, this makes the macro unsafe to use because you could pass anything. + // The tests make sure not to do that, though. +- match fork().unwrap() { ++ match unsafe{fork()}.unwrap() { + Child => { +- // Close stdout. +- close(1).unwrap(); + // Make `writer` be the stdout of the new process. +- dup(writer).unwrap(); +- // exec! +- $syscall( +- $exe, +- $(&CString::new($pathname).unwrap(), )* +- &[CString::new(b"".as_ref()).unwrap(), +- CString::new(b"-c".as_ref()).unwrap(), +- CString::new(b"echo nix!!! && echo foo=$foo && echo baz=$baz" +- .as_ref()).unwrap()], +- &[CString::new(b"foo=bar".as_ref()).unwrap(), +- CString::new(b"baz=quux".as_ref()).unwrap()] +- $(, $flags)*).unwrap(); ++ dup2(writer, 1).unwrap(); ++ let r = syscall(); ++ let _ = std::io::stderr() ++ .write_all(format!("{:?}", r).as_bytes()); ++ // Should only get here in event of error ++ unsafe{ _exit(1) }; + }, + Parent { child } => { + // Wait for the child to exit. +- waitpid(child, None).unwrap(); ++ let ws = waitpid(child, None); ++ drop(m); ++ assert_eq!(ws, Ok(WaitStatus::Exited(child, 0))); + // Read 1024 bytes. + let mut buf = [0u8; 1024]; + read(reader, &mut buf).unwrap(); +@@ -224,23 +334,43 @@ macro_rules! execve_test_factory( + } + } + } ++ ++ // These tests frequently fail on musl, probably due to ++ // https://github.com/nix-rust/nix/issues/555 ++ #[cfg_attr(target_env = "musl", ignore)] ++ #[test] ++ fn test_cstr_ref() { ++ common_test(syscall_cstr_ref); ++ } ++ ++ // These tests frequently fail on musl, probably due to ++ // https://github.com/nix-rust/nix/issues/555 ++ #[cfg_attr(target_env = "musl", ignore)] ++ #[test] ++ fn test_cstring() { ++ common_test(syscall_cstring); ++ } ++ } ++ + ) + ); + + cfg_if!{ + if #[cfg(target_os = "android")] { +- execve_test_factory!(test_execve, execve, &CString::new("/system/bin/sh").unwrap()); ++ execve_test_factory!(test_execve, execve, CString::new("/system/bin/sh").unwrap().as_c_str()); + execve_test_factory!(test_fexecve, fexecve, File::open("/system/bin/sh").unwrap().into_raw_fd()); + } else if #[cfg(any(target_os = "freebsd", + target_os = "linux"))] { +- execve_test_factory!(test_execve, execve, &CString::new("/bin/sh").unwrap()); ++ // These tests frequently fail on musl, probably due to ++ // https://github.com/nix-rust/nix/issues/555 ++ execve_test_factory!(test_execve, execve, CString::new("/bin/sh").unwrap().as_c_str()); + execve_test_factory!(test_fexecve, fexecve, File::open("/bin/sh").unwrap().into_raw_fd()); + } else if #[cfg(any(target_os = "dragonfly", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd"))] { +- execve_test_factory!(test_execve, execve, &CString::new("/bin/sh").unwrap()); ++ execve_test_factory!(test_execve, execve, CString::new("/bin/sh").unwrap().as_c_str()); + // No fexecve() on DragonFly, ios, macos, NetBSD, OpenBSD. + // + // Note for NetBSD and OpenBSD: although rust-lang/libc includes it +@@ -255,13 +385,16 @@ execve_test_factory!(test_execvpe, execvpe, &CString::new("sh").unwrap()); + cfg_if!{ + if #[cfg(target_os = "android")] { + use nix::fcntl::AtFlags; +- execve_test_factory!(test_execveat_empty, execveat, File::open("/system/bin/sh").unwrap().into_raw_fd(), ++ execve_test_factory!(test_execveat_empty, execveat, ++ File::open("/system/bin/sh").unwrap().into_raw_fd(), + "", AtFlags::AT_EMPTY_PATH); +- execve_test_factory!(test_execveat_relative, execveat, File::open("/system/bin/").unwrap().into_raw_fd(), ++ execve_test_factory!(test_execveat_relative, execveat, ++ File::open("/system/bin/").unwrap().into_raw_fd(), + "./sh", AtFlags::empty()); +- execve_test_factory!(test_execveat_absolute, execveat, File::open("/").unwrap().into_raw_fd(), ++ execve_test_factory!(test_execveat_absolute, execveat, ++ File::open("/").unwrap().into_raw_fd(), + "/system/bin/sh", AtFlags::empty()); +- } else if #[cfg(all(target_os = "linux"), any(target_arch ="x86_64", target_arch ="x86"))] { ++ } else if #[cfg(all(target_os = "linux", any(target_arch ="x86_64", target_arch ="x86")))] { + use nix::fcntl::AtFlags; + execve_test_factory!(test_execveat_empty, execveat, File::open("/bin/sh").unwrap().into_raw_fd(), + "", AtFlags::AT_EMPTY_PATH); +@@ -273,11 +406,12 @@ cfg_if!{ + } + + #[test] ++#[cfg(not(target_os = "fuchsia"))] + fn test_fchdir() { + // fchdir changes the process's cwd +- let _dr = ::DirRestore::new(); ++ let _dr = crate::DirRestore::new(); + +- let tmpdir = tempfile::tempdir().unwrap(); ++ let tmpdir = tempdir().unwrap(); + let tmpdir_path = tmpdir.path().canonicalize().unwrap(); + let tmpdir_fd = File::open(&tmpdir_path).unwrap().into_raw_fd(); + +@@ -290,9 +424,9 @@ fn test_fchdir() { + #[test] + fn test_getcwd() { + // chdir changes the process's cwd +- let _dr = ::DirRestore::new(); ++ let _dr = crate::DirRestore::new(); + +- let tmpdir = tempfile::tempdir().unwrap(); ++ let tmpdir = tempdir().unwrap(); + let tmpdir_path = tmpdir.path().canonicalize().unwrap(); + assert!(chdir(&tmpdir_path).is_ok()); + assert_eq!(getcwd().unwrap(), tmpdir_path); +@@ -317,7 +451,7 @@ fn test_chown() { + let uid = Some(getuid()); + let gid = Some(getgid()); + +- let tempdir = tempfile::tempdir().unwrap(); ++ let tempdir = tempdir().unwrap(); + let path = tempdir.path().join("file"); + { + File::create(&path).unwrap(); +@@ -332,13 +466,29 @@ fn test_chown() { + } + + #[test] ++fn test_fchown() { ++ // Testing for anything other than our own UID/GID is hard. ++ let uid = Some(getuid()); ++ let gid = Some(getgid()); ++ ++ let path = tempfile().unwrap(); ++ let fd = path.as_raw_fd(); ++ ++ fchown(fd, uid, gid).unwrap(); ++ fchown(fd, uid, None).unwrap(); ++ fchown(fd, None, gid).unwrap(); ++ fchown(999999999, uid, gid).unwrap_err(); ++} ++ ++#[test] ++#[cfg(not(target_os = "redox"))] + fn test_fchownat() { +- let _dr = ::DirRestore::new(); ++ let _dr = crate::DirRestore::new(); + // Testing for anything other than our own UID/GID is hard. + let uid = Some(getuid()); + let gid = Some(getgid()); + +- let tempdir = tempfile::tempdir().unwrap(); ++ let tempdir = tempdir().unwrap(); + let path = tempdir.path().join("file"); + { + File::create(&path).unwrap(); +@@ -366,7 +516,7 @@ fn test_lseek() { + lseek(tmpfd, offset, Whence::SeekSet).unwrap(); + + let mut buf = [0u8; 7]; +- ::read_exact(tmpfd, &mut buf); ++ crate::read_exact(tmpfd, &mut buf); + assert_eq!(b"f123456", &buf); + + close(tmpfd).unwrap(); +@@ -383,7 +533,7 @@ fn test_lseek64() { + lseek64(tmpfd, 5, Whence::SeekSet).unwrap(); + + let mut buf = [0u8; 7]; +- ::read_exact(tmpfd, &mut buf); ++ crate::read_exact(tmpfd, &mut buf); + assert_eq!(b"f123456", &buf); + + close(tmpfd).unwrap(); +@@ -403,7 +553,7 @@ cfg_if!{ + skip_if_jailed!("test_acct"); + } + } +- } else { ++ } else if #[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] { + macro_rules! require_acct{ + () => { + skip_if_not_root!("test_acct"); +@@ -413,12 +563,13 @@ cfg_if!{ + } + + #[test] ++#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] + fn test_acct() { + use tempfile::NamedTempFile; + use std::process::Command; + use std::{thread, time}; + +- let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test"); ++ let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test"); + require_acct!(); + + let file = NamedTempFile::new().unwrap(); +@@ -481,6 +632,14 @@ fn test_pipe() { + + // pipe2(2) is the same as pipe(2), except it allows setting some flags. Check + // that we can set a flag. ++#[cfg(any(target_os = "android", ++ target_os = "dragonfly", ++ target_os = "emscripten", ++ target_os = "freebsd", ++ target_os = "linux", ++ target_os = "netbsd", ++ target_os = "openbsd", ++ target_os = "redox"))] + #[test] + fn test_pipe2() { + let (fd0, fd1) = pipe2(OFlag::O_CLOEXEC).unwrap(); +@@ -491,8 +650,9 @@ fn test_pipe2() { + } + + #[test] ++#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] + fn test_truncate() { +- let tempdir = tempfile::tempdir().unwrap(); ++ let tempdir = tempdir().unwrap(); + let path = tempdir.path().join("file"); + + { +@@ -509,7 +669,7 @@ fn test_truncate() { + + #[test] + fn test_ftruncate() { +- let tempdir = tempfile::tempdir().unwrap(); ++ let tempdir = tempdir().unwrap(); + let path = tempdir.path().join("file"); + + let tmpfd = { +@@ -527,17 +687,26 @@ fn test_ftruncate() { + } + + // Used in `test_alarm`. ++#[cfg(not(target_os = "redox"))] + static mut ALARM_CALLED: bool = false; + + // Used in `test_alarm`. ++#[cfg(not(target_os = "redox"))] + pub extern fn alarm_signal_handler(raw_signal: libc::c_int) { + assert_eq!(raw_signal, libc::SIGALRM, "unexpected signal: {}", raw_signal); + unsafe { ALARM_CALLED = true }; + } + + #[test] ++#[cfg(not(target_os = "redox"))] + fn test_alarm() { +- let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); ++ use std::{ ++ time::{Duration, Instant,}, ++ thread ++ }; ++ ++ // Maybe other tests that fork interfere with this one? ++ let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); + + let handler = SigHandler::Handler(alarm_signal_handler); + let signal_action = SigAction::new(handler, SaFlags::SA_RESTART, SigSet::empty()); +@@ -554,8 +723,16 @@ fn test_alarm() { + + // We should be woken up after 1 second by the alarm, so we'll sleep for 2 + // seconds to be sure. +- sleep(2); +- assert_eq!(unsafe { ALARM_CALLED }, true, "expected our alarm signal handler to be called"); ++ let starttime = Instant::now(); ++ loop { ++ thread::sleep(Duration::from_millis(100)); ++ if unsafe { ALARM_CALLED} { ++ break; ++ } ++ if starttime.elapsed() > Duration::from_secs(3) { ++ panic!("Timeout waiting for SIGALRM"); ++ } ++ } + + // Reset the signal. + unsafe { +@@ -565,8 +742,9 @@ fn test_alarm() { + } + + #[test] ++#[cfg(not(target_os = "redox"))] + fn test_canceling_alarm() { +- let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); ++ let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); + + assert_eq!(alarm::cancel(), None); + +@@ -575,15 +753,17 @@ fn test_canceling_alarm() { + } + + #[test] ++#[cfg(not(target_os = "redox"))] + fn test_symlinkat() { +- let mut buf = [0; 1024]; +- let tempdir = tempfile::tempdir().unwrap(); ++ let _m = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test"); ++ ++ let tempdir = tempdir().unwrap(); + + let target = tempdir.path().join("a"); + let linkpath = tempdir.path().join("b"); + symlinkat(&target, None, &linkpath).unwrap(); + assert_eq!( +- readlink(&linkpath, &mut buf).unwrap().to_str().unwrap(), ++ readlink(&linkpath).unwrap().to_str().unwrap(), + target.to_str().unwrap() + ); + +@@ -592,7 +772,7 @@ fn test_symlinkat() { + let linkpath = "d"; + symlinkat(target, Some(dirfd), linkpath).unwrap(); + assert_eq!( +- readlink(&tempdir.path().join(linkpath), &mut buf) ++ readlink(&tempdir.path().join(linkpath)) + .unwrap() + .to_str() + .unwrap(), +@@ -600,10 +780,154 @@ fn test_symlinkat() { + ); + } + ++#[test] ++#[cfg(not(target_os = "redox"))] ++fn test_linkat_file() { ++ let tempdir = tempdir().unwrap(); ++ let oldfilename = "foo.txt"; ++ let oldfilepath = tempdir.path().join(oldfilename); ++ ++ let newfilename = "bar.txt"; ++ let newfilepath = tempdir.path().join(newfilename); ++ ++ // Create file ++ File::create(&oldfilepath).unwrap(); ++ ++ // Get file descriptor for base directory ++ let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap(); ++ ++ // Attempt hard link file at relative path ++ linkat(Some(dirfd), oldfilename, Some(dirfd), newfilename, LinkatFlags::SymlinkFollow).unwrap(); ++ assert!(newfilepath.exists()); ++} ++ ++#[test] ++#[cfg(not(target_os = "redox"))] ++fn test_linkat_olddirfd_none() { ++ let _dr = crate::DirRestore::new(); ++ ++ let tempdir_oldfile = tempdir().unwrap(); ++ let oldfilename = "foo.txt"; ++ let oldfilepath = tempdir_oldfile.path().join(oldfilename); ++ ++ let tempdir_newfile = tempdir().unwrap(); ++ let newfilename = "bar.txt"; ++ let newfilepath = tempdir_newfile.path().join(newfilename); ++ ++ // Create file ++ File::create(&oldfilepath).unwrap(); ++ ++ // Get file descriptor for base directory of new file ++ let dirfd = fcntl::open(tempdir_newfile.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap(); ++ ++ // Attempt hard link file using curent working directory as relative path for old file path ++ chdir(tempdir_oldfile.path()).unwrap(); ++ linkat(None, oldfilename, Some(dirfd), newfilename, LinkatFlags::SymlinkFollow).unwrap(); ++ assert!(newfilepath.exists()); ++} ++ ++#[test] ++#[cfg(not(target_os = "redox"))] ++fn test_linkat_newdirfd_none() { ++ let _dr = crate::DirRestore::new(); ++ ++ let tempdir_oldfile = tempdir().unwrap(); ++ let oldfilename = "foo.txt"; ++ let oldfilepath = tempdir_oldfile.path().join(oldfilename); ++ ++ let tempdir_newfile = tempdir().unwrap(); ++ let newfilename = "bar.txt"; ++ let newfilepath = tempdir_newfile.path().join(newfilename); ++ ++ // Create file ++ File::create(&oldfilepath).unwrap(); ++ ++ // Get file descriptor for base directory of old file ++ let dirfd = fcntl::open(tempdir_oldfile.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap(); ++ ++ // Attempt hard link file using current working directory as relative path for new file path ++ chdir(tempdir_newfile.path()).unwrap(); ++ linkat(Some(dirfd), oldfilename, None, newfilename, LinkatFlags::SymlinkFollow).unwrap(); ++ assert!(newfilepath.exists()); ++} ++ ++#[test] ++#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox")))] ++fn test_linkat_no_follow_symlink() { ++ let _m = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test"); ++ ++ let tempdir = tempdir().unwrap(); ++ let oldfilename = "foo.txt"; ++ let oldfilepath = tempdir.path().join(oldfilename); ++ ++ let symoldfilename = "symfoo.txt"; ++ let symoldfilepath = tempdir.path().join(symoldfilename); ++ ++ let newfilename = "nofollowsymbar.txt"; ++ let newfilepath = tempdir.path().join(newfilename); ++ ++ // Create file ++ File::create(&oldfilepath).unwrap(); ++ ++ // Create symlink to file ++ symlinkat(&oldfilepath, None, &symoldfilepath).unwrap(); ++ ++ // Get file descriptor for base directory ++ let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap(); ++ ++ // Attempt link symlink of file at relative path ++ linkat(Some(dirfd), symoldfilename, Some(dirfd), newfilename, LinkatFlags::NoSymlinkFollow).unwrap(); ++ ++ // Assert newfile is actually a symlink to oldfile. ++ assert_eq!( ++ readlink(&newfilepath) ++ .unwrap() ++ .to_str() ++ .unwrap(), ++ oldfilepath.to_str().unwrap() ++ ); ++} ++ ++#[test] ++#[cfg(not(target_os = "redox"))] ++fn test_linkat_follow_symlink() { ++ let _m = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test"); ++ ++ let tempdir = tempdir().unwrap(); ++ let oldfilename = "foo.txt"; ++ let oldfilepath = tempdir.path().join(oldfilename); ++ ++ let symoldfilename = "symfoo.txt"; ++ let symoldfilepath = tempdir.path().join(symoldfilename); ++ ++ let newfilename = "nofollowsymbar.txt"; ++ let newfilepath = tempdir.path().join(newfilename); ++ ++ // Create file ++ File::create(&oldfilepath).unwrap(); ++ ++ // Create symlink to file ++ symlinkat(&oldfilepath, None, &symoldfilepath).unwrap(); ++ ++ // Get file descriptor for base directory ++ let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap(); ++ ++ // Attempt link target of symlink of file at relative path ++ linkat(Some(dirfd), symoldfilename, Some(dirfd), newfilename, LinkatFlags::SymlinkFollow).unwrap(); ++ ++ let newfilestat = stat::stat(&newfilepath).unwrap(); ++ ++ // Check the file type of the new link ++ assert!((stat::SFlag::from_bits_truncate(newfilestat.st_mode) & SFlag::S_IFMT) == SFlag::S_IFREG); ++ ++ // Check the number of hard links to the original file ++ assert_eq!(newfilestat.st_nlink, 2); ++} + + #[test] ++#[cfg(not(target_os = "redox"))] + fn test_unlinkat_dir_noremovedir() { +- let tempdir = tempfile::tempdir().unwrap(); ++ let tempdir = tempdir().unwrap(); + let dirname = "foo_dir"; + let dirpath = tempdir.path().join(dirname); + +@@ -619,8 +943,9 @@ fn test_unlinkat_dir_noremovedir() { + } + + #[test] ++#[cfg(not(target_os = "redox"))] + fn test_unlinkat_dir_removedir() { +- let tempdir = tempfile::tempdir().unwrap(); ++ let tempdir = tempdir().unwrap(); + let dirname = "foo_dir"; + let dirpath = tempdir.path().join(dirname); + +@@ -636,8 +961,9 @@ fn test_unlinkat_dir_removedir() { + } + + #[test] ++#[cfg(not(target_os = "redox"))] + fn test_unlinkat_file() { +- let tempdir = tempfile::tempdir().unwrap(); ++ let tempdir = tempdir().unwrap(); + let filename = "foo.txt"; + let filepath = tempdir.path().join(filename); + +@@ -654,7 +980,7 @@ fn test_unlinkat_file() { + + #[test] + fn test_access_not_existing() { +- let tempdir = tempfile::tempdir().unwrap(); ++ let tempdir = tempdir().unwrap(); + let dir = tempdir.path().join("does_not_exist.txt"); + assert_eq!(access(&dir, AccessFlags::F_OK).err().unwrap().as_errno().unwrap(), + Errno::ENOENT); +@@ -662,8 +988,123 @@ fn test_access_not_existing() { + + #[test] + fn test_access_file_exists() { +- let tempdir = tempfile::tempdir().unwrap(); ++ let tempdir = tempdir().unwrap(); + let path = tempdir.path().join("does_exist.txt"); + let _file = File::create(path.clone()).unwrap(); + assert!(access(&path, AccessFlags::R_OK | AccessFlags::W_OK).is_ok()); + } ++ ++/// Tests setting the filesystem UID with `setfsuid`. ++#[cfg(any(target_os = "linux", target_os = "android"))] ++#[test] ++fn test_setfsuid() { ++ use std::os::unix::fs::PermissionsExt; ++ use std::{fs, io, thread}; ++ require_capability!(CAP_SETUID); ++ ++ // get the UID of the "nobody" user ++ let nobody = User::from_name("nobody").unwrap().unwrap(); ++ ++ // create a temporary file with permissions '-rw-r-----' ++ let file = tempfile::NamedTempFile::new_in("/var/tmp").unwrap(); ++ let temp_path = file.into_temp_path(); ++ dbg!(&temp_path); ++ let temp_path_2 = (&temp_path).to_path_buf(); ++ let mut permissions = fs::metadata(&temp_path).unwrap().permissions(); ++ permissions.set_mode(640); ++ ++ // spawn a new thread where to test setfsuid ++ thread::spawn(move || { ++ // set filesystem UID ++ let fuid = setfsuid(nobody.uid); ++ // trying to open the temporary file should fail with EACCES ++ let res = fs::File::open(&temp_path); ++ assert!(res.is_err()); ++ assert_eq!(res.err().unwrap().kind(), io::ErrorKind::PermissionDenied); ++ ++ // assert fuid actually changes ++ let prev_fuid = setfsuid(Uid::from_raw(-1i32 as u32)); ++ assert_ne!(prev_fuid, fuid); ++ }) ++ .join() ++ .unwrap(); ++ ++ // open the temporary file with the current thread filesystem UID ++ fs::File::open(temp_path_2).unwrap(); ++} ++ ++#[test] ++#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] ++fn test_ttyname() { ++ let fd = posix_openpt(OFlag::O_RDWR).expect("posix_openpt failed"); ++ assert!(fd.as_raw_fd() > 0); ++ ++ // on linux, we can just call ttyname on the pty master directly, but ++ // apparently osx requires that ttyname is called on a slave pty (can't ++ // find this documented anywhere, but it seems to empirically be the case) ++ grantpt(&fd).expect("grantpt failed"); ++ unlockpt(&fd).expect("unlockpt failed"); ++ let sname = unsafe { ptsname(&fd) }.expect("ptsname failed"); ++ let fds = open( ++ Path::new(&sname), ++ OFlag::O_RDWR, ++ stat::Mode::empty(), ++ ).expect("open failed"); ++ assert!(fds > 0); ++ ++ let name = ttyname(fds).expect("ttyname failed"); ++ assert!(name.starts_with("/dev")); ++} ++ ++#[test] ++#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] ++fn test_ttyname_not_pty() { ++ let fd = File::open("/dev/zero").unwrap(); ++ assert!(fd.as_raw_fd() > 0); ++ assert_eq!(ttyname(fd.as_raw_fd()), Err(Error::Sys(Errno::ENOTTY))); ++} ++ ++#[test] ++#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] ++fn test_ttyname_invalid_fd() { ++ assert_eq!(ttyname(-1), Err(Error::Sys(Errno::EBADF))); ++} ++ ++#[test] ++#[cfg(any( ++ target_os = "macos", ++ target_os = "ios", ++ target_os = "freebsd", ++ target_os = "openbsd", ++ target_os = "netbsd", ++ target_os = "dragonfly", ++))] ++fn test_getpeereid() { ++ use std::os::unix::net::UnixStream; ++ let (sock_a, sock_b) = UnixStream::pair().unwrap(); ++ ++ let (uid_a, gid_a) = getpeereid(sock_a.as_raw_fd()).unwrap(); ++ let (uid_b, gid_b) = getpeereid(sock_b.as_raw_fd()).unwrap(); ++ ++ let uid = geteuid(); ++ let gid = getegid(); ++ ++ assert_eq!(uid, uid_a); ++ assert_eq!(gid, gid_a); ++ assert_eq!(uid_a, uid_b); ++ assert_eq!(gid_a, gid_b); ++} ++ ++#[test] ++#[cfg(any( ++ target_os = "macos", ++ target_os = "ios", ++ target_os = "freebsd", ++ target_os = "openbsd", ++ target_os = "netbsd", ++ target_os = "dragonfly", ++))] ++fn test_getpeereid_invalid_fd() { ++ // getpeereid is not POSIX, so error codes are inconsistent between different Unices. ++ assert!(getpeereid(-1).is_err()); ++} diff --git a/www-client/firefox/firefox-98.0.2.ebuild b/www-client/firefox/firefox-98.0.2.ebuild index 4b45248..7eee8fb 100644 --- a/www-client/firefox/firefox-98.0.2.ebuild +++ b/www-client/firefox/firefox-98.0.2.ebuild @@ -51,6 +51,8 @@ PATCH_URIS=( https://dev.gentoo.org/~{juippis,polynomial-c,whissi,slashbeast}/mozilla/patchsets/${FIREFOX_PATCHSET} ) +PATCHES=${FILESDIR}/makotokato-riscv64-support-and-zenithal-backported.patch + SRC_URI="${MOZ_SRC_BASE_URI}/source/${MOZ_P}.source.tar.xz -> ${MOZ_P_DISTFILES}.source.tar.xz ${PATCH_URIS[@]}" @@ -725,7 +727,7 @@ src_configure() { # For future keywording: This is currently (97.0) only supported on: # amd64, arm, arm64 & x86. # Might want to flip the logic around if Firefox is to support more arches. - if use ppc64; then + if use ppc64 || use riscv; then mozconfig_add_options_ac '' --disable-sandbox else mozconfig_add_options_ac '' --enable-sandbox |