about summary refs log tree commit diff
path: root/library/std/src/sys/pal/unix/os.rs
diff options
context:
space:
mode:
authorThalia Archibald <thalia@archibald.dev>2025-04-21 20:56:43 -0700
committerThalia Archibald <thalia@archibald.dev>2025-04-21 20:56:43 -0700
commit90fe2805df75b9d46b985346f0dff2690c285330 (patch)
tree314e83705721dbd25abe01f5fa35885ca6c9b12a /library/std/src/sys/pal/unix/os.rs
parentd6c1e454aa8af5e7e59fbf5c4e7d3128d2f99582 (diff)
downloadrust-90fe2805df75b9d46b985346f0dff2690c285330.tar.gz
rust-90fe2805df75b9d46b985346f0dff2690c285330.zip
Move `sys::pal::os::Env` into `sys::env`
Although `Env` (as `Vars`), `Args`, path functions, and OS constants are
publicly exposed via `std::env`, their implementations are each
self-contained. Keep them separate in `std::sys` and make a new module,
`sys::env`, for `Env`.
Diffstat (limited to 'library/std/src/sys/pal/unix/os.rs')
-rw-r--r--library/std/src/sys/pal/unix/os.rs173
1 files changed, 4 insertions, 169 deletions
diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs
index f47421c6705..4883303b88e 100644
--- a/library/std/src/sys/pal/unix/os.rs
+++ b/library/std/src/sys/pal/unix/os.rs
@@ -5,20 +5,15 @@
 #[cfg(test)]
 mod tests;
 
-use core::slice::memchr;
-
 use libc::{c_char, c_int, c_void};
 
 use crate::error::Error as StdError;
-use crate::ffi::{CStr, CString, OsStr, OsString};
+use crate::ffi::{CStr, OsStr, OsString};
 use crate::os::unix::prelude::*;
 use crate::path::{self, PathBuf};
-use crate::sync::{PoisonError, RwLock};
-use crate::sys::common::small_c_string::{run_path_with_cstr, run_with_cstr};
-#[cfg(all(target_env = "gnu", not(target_os = "vxworks")))]
-use crate::sys::weak::weak;
-use crate::sys::{cvt, fd};
-use crate::{fmt, io, iter, mem, ptr, slice, str, vec};
+use crate::sys::common::small_c_string::run_path_with_cstr;
+use crate::sys::cvt;
+use crate::{fmt, io, iter, mem, ptr, slice, str};
 
 const TMPBUF_SZ: usize = 128;
 
@@ -552,166 +547,6 @@ pub fn current_exe() -> io::Result<PathBuf> {
     if !path.is_absolute() { getcwd().map(|cwd| cwd.join(path)) } else { Ok(path) }
 }
 
-pub struct Env {
-    iter: vec::IntoIter<(OsString, OsString)>,
-}
-
-// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt.
-pub struct EnvStrDebug<'a> {
-    slice: &'a [(OsString, OsString)],
-}
-
-impl fmt::Debug for EnvStrDebug<'_> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let Self { slice } = self;
-        f.debug_list()
-            .entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap())))
-            .finish()
-    }
-}
-
-impl Env {
-    pub fn str_debug(&self) -> impl fmt::Debug + '_ {
-        let Self { iter } = self;
-        EnvStrDebug { slice: iter.as_slice() }
-    }
-}
-
-impl fmt::Debug for Env {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let Self { iter } = self;
-        f.debug_list().entries(iter.as_slice()).finish()
-    }
-}
-
-impl !Send for Env {}
-impl !Sync for Env {}
-
-impl Iterator for Env {
-    type Item = (OsString, OsString);
-    fn next(&mut self) -> Option<(OsString, OsString)> {
-        self.iter.next()
-    }
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.iter.size_hint()
-    }
-}
-
-// Use `_NSGetEnviron` on Apple platforms.
-//
-// `_NSGetEnviron` is the documented alternative (see `man environ`), and has
-// been available since the first versions of both macOS and iOS.
-//
-// Nowadays, specifically since macOS 10.8, `environ` has been exposed through
-// `libdyld.dylib`, which is linked via. `libSystem.dylib`:
-// <https://github.com/apple-oss-distributions/dyld/blob/dyld-1160.6/libdyld/libdyldGlue.cpp#L913>
-//
-// So in the end, it likely doesn't really matter which option we use, but the
-// performance cost of using `_NSGetEnviron` is extremely miniscule, and it
-// might be ever so slightly more supported, so let's just use that.
-//
-// NOTE: The header where this is defined (`crt_externs.h`) was added to the
-// iOS 13.0 SDK, which has been the source of a great deal of confusion in the
-// past about the availability of this API.
-//
-// NOTE(madsmtm): Neither this nor using `environ` has been verified to not
-// cause App Store rejections; if this is found to be the case, an alternative
-// implementation of this is possible using `[NSProcessInfo environment]`
-// - which internally uses `_NSGetEnviron` and a system-wide lock on the
-// environment variables to protect against `setenv`, so using that might be
-// desirable anyhow? Though it also means that we have to link to Foundation.
-#[cfg(target_vendor = "apple")]
-pub unsafe fn environ() -> *mut *const *const c_char {
-    libc::_NSGetEnviron() as *mut *const *const c_char
-}
-
-// Use the `environ` static which is part of POSIX.
-#[cfg(not(target_vendor = "apple"))]
-pub unsafe fn environ() -> *mut *const *const c_char {
-    unsafe extern "C" {
-        static mut environ: *const *const c_char;
-    }
-    &raw mut environ
-}
-
-static ENV_LOCK: RwLock<()> = RwLock::new(());
-
-pub fn env_read_lock() -> impl Drop {
-    ENV_LOCK.read().unwrap_or_else(PoisonError::into_inner)
-}
-
-/// Returns a vector of (variable, value) byte-vector pairs for all the
-/// environment variables of the current process.
-pub fn env() -> Env {
-    unsafe {
-        let _guard = env_read_lock();
-        let mut environ = *environ();
-        let mut result = Vec::new();
-        if !environ.is_null() {
-            while !(*environ).is_null() {
-                if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) {
-                    result.push(key_value);
-                }
-                environ = environ.add(1);
-            }
-        }
-        return Env { iter: result.into_iter() };
-    }
-
-    fn parse(input: &[u8]) -> Option<(OsString, OsString)> {
-        // Strategy (copied from glibc): Variable name and value are separated
-        // by an ASCII equals sign '='. Since a variable name must not be
-        // empty, allow variable names starting with an equals sign. Skip all
-        // malformed lines.
-        if input.is_empty() {
-            return None;
-        }
-        let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1);
-        pos.map(|p| {
-            (
-                OsStringExt::from_vec(input[..p].to_vec()),
-                OsStringExt::from_vec(input[p + 1..].to_vec()),
-            )
-        })
-    }
-}
-
-pub fn getenv(k: &OsStr) -> Option<OsString> {
-    // environment variables with a nul byte can't be set, so their value is
-    // always None as well
-    run_with_cstr(k.as_bytes(), &|k| {
-        let _guard = env_read_lock();
-        let v = unsafe { libc::getenv(k.as_ptr()) } as *const libc::c_char;
-
-        if v.is_null() {
-            Ok(None)
-        } else {
-            // SAFETY: `v` cannot be mutated while executing this line since we've a read lock
-            let bytes = unsafe { CStr::from_ptr(v) }.to_bytes().to_vec();
-
-            Ok(Some(OsStringExt::from_vec(bytes)))
-        }
-    })
-    .ok()
-    .flatten()
-}
-
-pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
-    run_with_cstr(k.as_bytes(), &|k| {
-        run_with_cstr(v.as_bytes(), &|v| {
-            let _guard = ENV_LOCK.write();
-            cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(drop)
-        })
-    })
-}
-
-pub unsafe fn unsetenv(n: &OsStr) -> io::Result<()> {
-    run_with_cstr(n.as_bytes(), &|nbuf| {
-        let _guard = ENV_LOCK.write();
-        cvt(libc::unsetenv(nbuf.as_ptr())).map(drop)
-    })
-}
-
 #[cfg(not(target_os = "espidf"))]
 pub fn page_size() -> usize {
     unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize }