summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md4
-rw-r--r--Cargo.toml6
-rw-r--r--src/env.rs52
-rw-r--r--src/lib.rs1
-rw-r--r--test/test_clearenv.rs11
5 files changed, 73 insertions, 1 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index def99c18..8e7a7930 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,10 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased] - ReleaseDate
### Added
+- 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))
### Changed
### Fixed
### Removed
diff --git a/Cargo.toml b/Cargo.toml
index f7e0194b..7327987b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -18,7 +18,7 @@ exclude = [
[dependencies]
libc = { version = "0.2.60", features = [ "extra_traits" ] }
bitflags = "1.1"
-cfg-if = "0.1.2"
+cfg-if = "0.1.10"
void = "1.0.2"
[target.'cfg(target_os = "dragonfly")'.build-dependencies]
@@ -45,6 +45,10 @@ 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"
diff --git a/src/env.rs b/src/env.rs
new file mode 100644
index 00000000..0d815be9
--- /dev/null
+++ b/src/env.rs
@@ -0,0 +1,52 @@
+use {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/src/lib.rs b/src/lib.rs
index 410db186..0ba7ace8 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -30,6 +30,7 @@ pub extern crate libc;
// Public crates
pub mod dir;
+pub mod env;
pub mod errno;
#[deny(missing_docs)]
pub mod features;
diff --git a/test/test_clearenv.rs b/test/test_clearenv.rs
new file mode 100644
index 00000000..f122f7c6
--- /dev/null
+++ b/test/test_clearenv.rs
@@ -0,0 +1,11 @@
+extern crate nix;
+
+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);
+}