• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Environment variables
2 use cfg_if::cfg_if;
3 use std::fmt;
4 
5 /// Indicates that [`clearenv`] failed for some unknown reason
6 #[derive(Clone, Copy, Debug)]
7 pub struct ClearEnvError;
8 
9 impl fmt::Display for ClearEnvError {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result10     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
11         write!(f, "clearenv failed")
12     }
13 }
14 
15 impl std::error::Error for ClearEnvError {}
16 
17 /// Clear the environment of all name-value pairs.
18 ///
19 /// On platforms where libc provides `clearenv()`, it will be used. libc's
20 /// `clearenv()` is documented to return an error code but not set errno; if the
21 /// return value indicates a failure, this function will return
22 /// [`ClearEnvError`].
23 ///
24 /// On platforms where libc does not provide `clearenv()`, a fallback
25 /// implementation will be used that iterates over all environment variables and
26 /// removes them one-by-one.
27 ///
28 /// # Safety
29 ///
30 /// This function is not threadsafe and can cause undefined behavior in
31 /// combination with `std::env` or other program components that access the
32 /// environment. See, for example, the discussion on `std::env::remove_var`; this
33 /// function is a case of an "inherently unsafe non-threadsafe API" dealing with
34 /// the environment.
35 ///
36 ///  The caller must ensure no other threads access the process environment while
37 ///  this function executes and that no raw pointers to an element of libc's
38 ///  `environ` is currently held. The latter is not an issue if the only other
39 ///  environment access in the program is via `std::env`, but the requirement on
40 ///  thread safety must still be upheld.
clearenv() -> std::result::Result<(), ClearEnvError>41 pub unsafe fn clearenv() -> std::result::Result<(), ClearEnvError> {
42     cfg_if! {
43         if #[cfg(any(target_os = "fuchsia",
44                      target_os = "wasi",
45                      target_env = "uclibc",
46                      target_os = "linux",
47                      target_os = "android",
48                      target_os = "emscripten"))] {
49             let ret = libc::clearenv();
50         } else {
51             use std::env;
52             for (name, _) in env::vars_os() {
53                 env::remove_var(name);
54             }
55             let ret = 0;
56         }
57     }
58 
59     if ret == 0 {
60         Ok(())
61     } else {
62         Err(ClearEnvError)
63     }
64 }
65