Skip to content

Commit 90fe280

Browse files
committed
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`.
1 parent d6c1e45 commit 90fe280

File tree

27 files changed

+1228
-1198
lines changed

27 files changed

+1228
-1198
lines changed

library/std/src/env.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
use crate::error::Error;
1414
use crate::ffi::{OsStr, OsString};
1515
use crate::path::{Path, PathBuf};
16-
use crate::sys::os as os_imp;
16+
use crate::sys::{env as env_imp, os as os_imp};
1717
use crate::{fmt, io, sys};
1818

1919
/// Returns the current working directory as a [`PathBuf`].
@@ -96,7 +96,7 @@ pub struct Vars {
9696
/// [`env::vars_os()`]: vars_os
9797
#[stable(feature = "env", since = "1.0.0")]
9898
pub struct VarsOs {
99-
inner: os_imp::Env,
99+
inner: env_imp::Env,
100100
}
101101

102102
/// Returns an iterator of (variable, value) pairs of strings, for all the
@@ -150,7 +150,7 @@ pub fn vars() -> Vars {
150150
#[must_use]
151151
#[stable(feature = "env", since = "1.0.0")]
152152
pub fn vars_os() -> VarsOs {
153-
VarsOs { inner: os_imp::env() }
153+
VarsOs { inner: env_imp::env() }
154154
}
155155

156156
#[stable(feature = "env", since = "1.0.0")]
@@ -259,7 +259,7 @@ pub fn var_os<K: AsRef<OsStr>>(key: K) -> Option<OsString> {
259259
}
260260

261261
fn _var_os(key: &OsStr) -> Option<OsString> {
262-
os_imp::getenv(key)
262+
env_imp::getenv(key)
263263
}
264264

265265
/// The error type for operations interacting with environment variables.
@@ -363,7 +363,7 @@ impl Error for VarError {
363363
#[stable(feature = "env", since = "1.0.0")]
364364
pub unsafe fn set_var<K: AsRef<OsStr>, V: AsRef<OsStr>>(key: K, value: V) {
365365
let (key, value) = (key.as_ref(), value.as_ref());
366-
unsafe { os_imp::setenv(key, value) }.unwrap_or_else(|e| {
366+
unsafe { env_imp::setenv(key, value) }.unwrap_or_else(|e| {
367367
panic!("failed to set environment variable `{key:?}` to `{value:?}`: {e}")
368368
})
369369
}
@@ -434,7 +434,7 @@ pub unsafe fn set_var<K: AsRef<OsStr>, V: AsRef<OsStr>>(key: K, value: V) {
434434
#[stable(feature = "env", since = "1.0.0")]
435435
pub unsafe fn remove_var<K: AsRef<OsStr>>(key: K) {
436436
let key = key.as_ref();
437-
unsafe { os_imp::unsetenv(key) }
437+
unsafe { env_imp::unsetenv(key) }
438438
.unwrap_or_else(|e| panic!("failed to remove environment variable `{key:?}`: {e}"))
439439
}
440440

library/std/src/sys/env/hermit.rs

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
use core::slice::memchr;
2+
3+
use crate::collections::HashMap;
4+
use crate::ffi::{CStr, OsStr, OsString, c_char};
5+
use crate::os::hermit::ffi::OsStringExt;
6+
use crate::sync::Mutex;
7+
use crate::{fmt, io, vec};
8+
9+
static ENV: Mutex<Option<HashMap<OsString, OsString>>> = Mutex::new(None);
10+
11+
pub fn init(env: *const *const c_char) {
12+
let mut guard = ENV.lock().unwrap();
13+
let map = guard.insert(HashMap::new());
14+
15+
if env.is_null() {
16+
return;
17+
}
18+
19+
unsafe {
20+
let mut environ = env;
21+
while !(*environ).is_null() {
22+
if let Some((key, value)) = parse(CStr::from_ptr(*environ).to_bytes()) {
23+
map.insert(key, value);
24+
}
25+
environ = environ.add(1);
26+
}
27+
}
28+
29+
fn parse(input: &[u8]) -> Option<(OsString, OsString)> {
30+
// Strategy (copied from glibc): Variable name and value are separated
31+
// by an ASCII equals sign '='. Since a variable name must not be
32+
// empty, allow variable names starting with an equals sign. Skip all
33+
// malformed lines.
34+
if input.is_empty() {
35+
return None;
36+
}
37+
let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1);
38+
pos.map(|p| {
39+
(
40+
OsStringExt::from_vec(input[..p].to_vec()),
41+
OsStringExt::from_vec(input[p + 1..].to_vec()),
42+
)
43+
})
44+
}
45+
}
46+
47+
pub struct Env {
48+
iter: vec::IntoIter<(OsString, OsString)>,
49+
}
50+
51+
// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt.
52+
pub struct EnvStrDebug<'a> {
53+
slice: &'a [(OsString, OsString)],
54+
}
55+
56+
impl fmt::Debug for EnvStrDebug<'_> {
57+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58+
let Self { slice } = self;
59+
f.debug_list()
60+
.entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap())))
61+
.finish()
62+
}
63+
}
64+
65+
impl Env {
66+
pub fn str_debug(&self) -> impl fmt::Debug + '_ {
67+
let Self { iter } = self;
68+
EnvStrDebug { slice: iter.as_slice() }
69+
}
70+
}
71+
72+
impl fmt::Debug for Env {
73+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74+
let Self { iter } = self;
75+
f.debug_list().entries(iter.as_slice()).finish()
76+
}
77+
}
78+
79+
impl !Send for Env {}
80+
impl !Sync for Env {}
81+
82+
impl Iterator for Env {
83+
type Item = (OsString, OsString);
84+
fn next(&mut self) -> Option<(OsString, OsString)> {
85+
self.iter.next()
86+
}
87+
fn size_hint(&self) -> (usize, Option<usize>) {
88+
self.iter.size_hint()
89+
}
90+
}
91+
92+
/// Returns a vector of (variable, value) byte-vector pairs for all the
93+
/// environment variables of the current process.
94+
pub fn env() -> Env {
95+
let guard = ENV.lock().unwrap();
96+
let env = guard.as_ref().unwrap();
97+
98+
let result = env.iter().map(|(key, value)| (key.clone(), value.clone())).collect::<Vec<_>>();
99+
100+
Env { iter: result.into_iter() }
101+
}
102+
103+
pub fn getenv(k: &OsStr) -> Option<OsString> {
104+
ENV.lock().unwrap().as_ref().unwrap().get(k).cloned()
105+
}
106+
107+
pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
108+
let (k, v) = (k.to_owned(), v.to_owned());
109+
ENV.lock().unwrap().as_mut().unwrap().insert(k, v);
110+
Ok(())
111+
}
112+
113+
pub unsafe fn unsetenv(k: &OsStr) -> io::Result<()> {
114+
ENV.lock().unwrap().as_mut().unwrap().remove(k);
115+
Ok(())
116+
}

library/std/src/sys/env/mod.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//! Platform-dependent environment variables abstraction.
2+
3+
#![deny(unsafe_op_in_unsafe_fn)]
4+
5+
cfg_if::cfg_if! {
6+
if #[cfg(target_family = "unix")] {
7+
mod unix;
8+
pub use unix::*;
9+
} else if #[cfg(target_family = "windows")] {
10+
mod windows;
11+
pub use windows::*;
12+
} else if #[cfg(target_os = "hermit")] {
13+
mod hermit;
14+
pub use hermit::*;
15+
} else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
16+
mod sgx;
17+
pub use sgx::*;
18+
} else if #[cfg(target_os = "solid_asp3")] {
19+
mod solid;
20+
pub use solid::*;
21+
} else if #[cfg(target_os = "uefi")] {
22+
mod uefi;
23+
pub use uefi::*;
24+
} else if #[cfg(target_os = "wasi")] {
25+
mod wasi;
26+
pub use wasi::*;
27+
} else if #[cfg(target_os = "xous")] {
28+
mod xous;
29+
pub use xous::*;
30+
} else if #[cfg(target_os = "zkvm")] {
31+
mod zkvm;
32+
pub use zkvm::*;
33+
} else {
34+
mod unsupported;
35+
pub use unsupported::*;
36+
}
37+
}

library/std/src/sys/env/sgx.rs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
#![allow(fuzzy_provenance_casts)] // FIXME: this module systematically confuses pointers and integers
2+
3+
use crate::collections::HashMap;
4+
use crate::ffi::{OsStr, OsString};
5+
use crate::sync::atomic::{AtomicUsize, Ordering};
6+
use crate::sync::{Mutex, Once};
7+
use crate::{fmt, io, vec};
8+
9+
// Specifying linkage/symbol name is solely to ensure a single instance between this crate and its unit tests
10+
#[cfg_attr(test, linkage = "available_externally")]
11+
#[unsafe(export_name = "_ZN16__rust_internals3std3sys3pal3sgx2os3ENVE")]
12+
static ENV: AtomicUsize = AtomicUsize::new(0);
13+
// Specifying linkage/symbol name is solely to ensure a single instance between this crate and its unit tests
14+
#[cfg_attr(test, linkage = "available_externally")]
15+
#[unsafe(export_name = "_ZN16__rust_internals3std3sys3pal3sgx2os8ENV_INITE")]
16+
static ENV_INIT: Once = Once::new();
17+
type EnvStore = Mutex<HashMap<OsString, OsString>>;
18+
19+
fn get_env_store() -> Option<&'static EnvStore> {
20+
unsafe { (ENV.load(Ordering::Relaxed) as *const EnvStore).as_ref() }
21+
}
22+
23+
fn create_env_store() -> &'static EnvStore {
24+
ENV_INIT.call_once(|| {
25+
ENV.store(Box::into_raw(Box::new(EnvStore::default())) as _, Ordering::Relaxed)
26+
});
27+
unsafe { &*(ENV.load(Ordering::Relaxed) as *const EnvStore) }
28+
}
29+
30+
pub struct Env {
31+
iter: vec::IntoIter<(OsString, OsString)>,
32+
}
33+
34+
// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt.
35+
pub struct EnvStrDebug<'a> {
36+
slice: &'a [(OsString, OsString)],
37+
}
38+
39+
impl fmt::Debug for EnvStrDebug<'_> {
40+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41+
let Self { slice } = self;
42+
f.debug_list()
43+
.entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap())))
44+
.finish()
45+
}
46+
}
47+
48+
impl Env {
49+
pub fn str_debug(&self) -> impl fmt::Debug + '_ {
50+
let Self { iter } = self;
51+
EnvStrDebug { slice: iter.as_slice() }
52+
}
53+
}
54+
55+
impl fmt::Debug for Env {
56+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57+
let Self { iter } = self;
58+
f.debug_list().entries(iter.as_slice()).finish()
59+
}
60+
}
61+
62+
impl !Send for Env {}
63+
impl !Sync for Env {}
64+
65+
impl Iterator for Env {
66+
type Item = (OsString, OsString);
67+
fn next(&mut self) -> Option<(OsString, OsString)> {
68+
self.iter.next()
69+
}
70+
fn size_hint(&self) -> (usize, Option<usize>) {
71+
self.iter.size_hint()
72+
}
73+
}
74+
75+
pub fn env() -> Env {
76+
let clone_to_vec = |map: &HashMap<OsString, OsString>| -> Vec<_> {
77+
map.iter().map(|(k, v)| (k.clone(), v.clone())).collect()
78+
};
79+
80+
let iter = get_env_store()
81+
.map(|env| clone_to_vec(&env.lock().unwrap()))
82+
.unwrap_or_default()
83+
.into_iter();
84+
Env { iter }
85+
}
86+
87+
pub fn getenv(k: &OsStr) -> Option<OsString> {
88+
get_env_store().and_then(|s| s.lock().unwrap().get(k).cloned())
89+
}
90+
91+
pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
92+
let (k, v) = (k.to_owned(), v.to_owned());
93+
create_env_store().lock().unwrap().insert(k, v);
94+
Ok(())
95+
}
96+
97+
pub unsafe fn unsetenv(k: &OsStr) -> io::Result<()> {
98+
if let Some(env) = get_env_store() {
99+
env.lock().unwrap().remove(k);
100+
}
101+
Ok(())
102+
}

0 commit comments

Comments
 (0)