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