annotate src/libpam/environ.rs @ 105:13b4d2a19674

Support Rust v1.75.0. This is the version included in Ubuntu 24.04 LTS and Debian Trixie, so it's old enough to have wide penetration without being too old to get new features (Debian Stable, I love you but v1.63 is just not going to work out).
author Paul Fisher <paul@pfish.zone>
date Thu, 26 Jun 2025 00:48:51 -0400
parents dfcd96a74ac4
children 49d9e2b5c189
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
100
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
1 use crate::constants::{ErrorCode, Result};
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
2 use crate::environ::{EnvironMap, EnvironMapMut};
98
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
3 use crate::libpam::memory::CHeapString;
100
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
4 use crate::libpam::{memory, pam_ffi, LibPamHandle};
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
5 use std::ffi::{c_char, CStr, CString, OsStr, OsString};
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
6 use std::marker::PhantomData;
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
7 use std::os::unix::ffi::{OsStrExt, OsStringExt};
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
8 use std::ptr;
98
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
9 use std::ptr::NonNull;
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
10
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
11 pub struct LibPamEnviron<'a> {
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
12 source: &'a LibPamHandle,
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
13 }
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
14
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
15 pub struct LibPamEnvironMut<'a> {
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
16 source: &'a mut LibPamHandle,
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
17 }
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
18
100
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
19 impl LibPamHandle {
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
20 fn environ_get(&self, key: &OsStr) -> Option<OsString> {
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
21 let key = CString::new(key.as_bytes()).ok()?;
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
22 // SAFETY: We are a valid handle and are calling with a good key.
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
23 unsafe {
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
24 copy_env(pam_ffi::pam_getenv(
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
25 (self as *const LibPamHandle).cast_mut(),
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
26 key.as_ptr(),
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
27 ))
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
28 }
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
29 }
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
30
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
31 fn environ_set(&mut self, key: &OsStr, value: Option<&OsStr>) -> Result<Option<OsString>> {
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
32 let old = self.environ_get(key);
103
dfcd96a74ac4 write a truly prodigious amount of documentation
Paul Fisher <paul@pfish.zone>
parents: 100
diff changeset
33 if old.is_none() && value.is_none() {
dfcd96a74ac4 write a truly prodigious amount of documentation
Paul Fisher <paul@pfish.zone>
parents: 100
diff changeset
34 // pam_putenv returns an error if we try to remove a non-existent
dfcd96a74ac4 write a truly prodigious amount of documentation
Paul Fisher <paul@pfish.zone>
parents: 100
diff changeset
35 // environment variable, so just avoid that entirely.
dfcd96a74ac4 write a truly prodigious amount of documentation
Paul Fisher <paul@pfish.zone>
parents: 100
diff changeset
36 return Ok(None)
dfcd96a74ac4 write a truly prodigious amount of documentation
Paul Fisher <paul@pfish.zone>
parents: 100
diff changeset
37 }
100
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
38 let total_len = key.len() + value.map(OsStr::len).unwrap_or_default() + 2;
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
39 let mut result = Vec::with_capacity(total_len);
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
40 result.extend(key.as_bytes());
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
41 if let Some(value) = value {
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
42 result.push(b'=');
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
43 result.extend(value.as_bytes());
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
44 }
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
45 let put = CString::new(result).map_err(|_| ErrorCode::ConversationError)?;
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
46 // SAFETY: This is a valid handle and a valid environment string.
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
47 ErrorCode::result_from(unsafe { pam_ffi::pam_putenv(self, put.as_ptr()) })?;
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
48 Ok(old)
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
49 }
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
50
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
51 fn environ_iter(&self) -> Result<impl Iterator<Item = (OsString, OsString)>> {
103
dfcd96a74ac4 write a truly prodigious amount of documentation
Paul Fisher <paul@pfish.zone>
parents: 100
diff changeset
52 // SAFETY: This is a valid PAM handle. It will return valid data.
100
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
53 unsafe {
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
54 NonNull::new(pam_ffi::pam_getenvlist(
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
55 (self as *const LibPamHandle).cast_mut(),
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
56 ))
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
57 .map(|ptr| EnvList::from_ptr(ptr.cast()))
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
58 .ok_or(ErrorCode::BufferError)
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
59 }
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
60 }
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
61 }
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
62
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
63 /// Copies the data of the given C string pointer to an OsString,
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
64 /// or None if src is null.
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
65 unsafe fn copy_env(src: *const c_char) -> Option<OsString> {
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
66 let val = match NonNull::new(src.cast_mut()) {
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
67 None => return None,
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
68 Some(ptr) => ptr.as_ptr(),
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
69 };
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
70 // SAFETY: We were just returned this string from PAM.
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
71 // We have to trust it.
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
72 let c_str = unsafe { CStr::from_ptr(val) };
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
73 Some(OsString::from_vec(c_str.to_bytes().to_vec()))
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
74 }
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
75
98
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
76 impl<'a> LibPamEnviron<'a> {
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
77 pub fn new(source: &'a LibPamHandle) -> Self {
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
78 Self { source }
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
79 }
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
80 }
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
81
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
82 impl<'a> LibPamEnvironMut<'a> {
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
83 pub fn new(source: &'a mut LibPamHandle) -> Self {
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
84 Self { source }
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
85 }
100
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
86 }
98
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
87
100
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
88 impl EnvironMap<'_> for LibPamEnviron<'_> {
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
89 fn get(&self, key: impl AsRef<OsStr>) -> Option<OsString> {
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
90 self.source.environ_get(key.as_ref())
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
91 }
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
92
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
93 fn iter(&self) -> Result<impl Iterator<Item = (OsString, OsString)>> {
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
94 self.source.environ_iter()
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
95 }
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
96 }
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
97
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
98 impl EnvironMap<'_> for LibPamEnvironMut<'_> {
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
99 fn get(&self, key: impl AsRef<OsStr>) -> Option<OsString> {
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
100 self.source.environ_get(key.as_ref())
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
101 }
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
102
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
103 fn iter(&self) -> Result<impl Iterator<Item = (OsString, OsString)>> {
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
104 self.source.environ_iter()
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
105 }
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
106 }
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
107
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
108 impl EnvironMapMut<'_> for LibPamEnvironMut<'_> {
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
109 fn insert(
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
110 &mut self,
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
111 key: impl AsRef<OsStr>,
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
112 val: impl AsRef<OsStr>,
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
113 ) -> Result<Option<OsString>> {
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
114 self.source.environ_set(key.as_ref(), Some(val.as_ref()))
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
115 }
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
116
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
117 fn remove(&mut self, key: impl AsRef<OsStr>) -> Result<Option<OsString>> {
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
118 self.source.environ_set(key.as_ref(), None)
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
119 }
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
120 }
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
121
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
122 struct EnvList<'a> {
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
123 /// Pointer to the start of the environment variable list.
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
124 ///
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
125 /// This can't be a `CHeapBox` because it's not just a single
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
126 /// `Option<EnvVar>`.
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
127 start: NonNull<Option<EnvVar>>,
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
128 /// The environment variable we're about to iterate into.
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
129 current: NonNull<Option<EnvVar>>,
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
130 _owner: PhantomData<&'a LibPamHandle>,
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
131 }
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
132
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
133 impl EnvList<'_> {
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
134 unsafe fn from_ptr(ptr: NonNull<*mut c_char>) -> Self {
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
135 Self {
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
136 start: ptr.cast(),
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
137 current: ptr.cast(),
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
138 _owner: Default::default(),
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
139 }
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
140 }
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
141 }
105
13b4d2a19674 Support Rust v1.75.0.
Paul Fisher <paul@pfish.zone>
parents: 103
diff changeset
142
100
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
143 impl Iterator for EnvList<'_> {
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
144 type Item = (OsString, OsString);
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
145
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
146 fn next(&mut self) -> Option<Self::Item> {
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
147 // SAFETY: We were given a pointer to a valid environment list,
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
148 // and we only ever advance it to the exact end of the list.
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
149 match unsafe { self.current.as_mut() } {
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
150 None => None,
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
151 Some(item) => {
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
152 let ret = item.as_kv();
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
153 // SAFETY: We know we're still pointing to a valid pointer,
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
154 // and advancing it one more is allowed.
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
155 unsafe {
105
13b4d2a19674 Support Rust v1.75.0.
Paul Fisher <paul@pfish.zone>
parents: 103
diff changeset
156 self.current = advance(self.current);
100
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
157 ptr::drop_in_place(item as *mut EnvVar);
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
158 }
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
159 Some(ret)
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
160 }
98
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
161 }
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
162 }
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
163 }
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
164
100
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
165 impl Drop for EnvList<'_> {
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
166 fn drop(&mut self) {
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
167 // SAFETY: We own self.start, and we know that self.current points to
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
168 // either an item we haven't used, or to the None end.
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
169 unsafe {
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
170 while let Some(var_ref) = self.current.as_mut() {
105
13b4d2a19674 Support Rust v1.75.0.
Paul Fisher <paul@pfish.zone>
parents: 103
diff changeset
171 self.current = advance(self.current);
100
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
172 ptr::drop_in_place(var_ref as *mut EnvVar);
98
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
173 }
100
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
174 memory::free(self.start.as_ptr())
98
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
175 }
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
176 }
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
177 }
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
178
105
13b4d2a19674 Support Rust v1.75.0.
Paul Fisher <paul@pfish.zone>
parents: 103
diff changeset
179 unsafe fn advance<T>(nn: NonNull<T>) -> NonNull<T> {
13b4d2a19674 Support Rust v1.75.0.
Paul Fisher <paul@pfish.zone>
parents: 103
diff changeset
180 NonNull::new_unchecked(nn.as_ptr().offset(1))
13b4d2a19674 Support Rust v1.75.0.
Paul Fisher <paul@pfish.zone>
parents: 103
diff changeset
181 }
13b4d2a19674 Support Rust v1.75.0.
Paul Fisher <paul@pfish.zone>
parents: 103
diff changeset
182
98
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
183 struct EnvVar(CHeapString);
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
184
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
185 impl EnvVar {
100
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
186 fn as_kv(&self) -> (OsString, OsString) {
98
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
187 let bytes = self.0.to_bytes();
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
188 let mut split = bytes.splitn(2, |&b| b == b'=');
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
189 (
100
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
190 OsString::from_vec(split.next().unwrap_or_default().into()),
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
191 OsString::from_vec(split.next().unwrap_or_default().into()),
98
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
192 )
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
193 }
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
194 }
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
195
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
196 #[cfg(test)]
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
197 mod tests {
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
198 use super::*;
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
199
100
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
200 fn os(text: &str) -> OsString {
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
201 OsString::from_vec(text.into())
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
202 }
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
203
98
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
204 #[test]
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
205 fn test_split_kv() {
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
206 fn test(input: &str, key: &str, value: &str) {
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
207 let data = CHeapString::new(input).unwrap();
100
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
208 let key = os(key);
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
209 let value = os(value);
98
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
210
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
211 assert_eq!(EnvVar(data).as_kv(), (key, value));
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
212 }
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
213 test("THIS=that", "THIS", "that");
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
214 test("THESE=those, no one=knows", "THESE", "those, no one=knows");
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
215 test("HERE=", "HERE", "");
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
216 test("SOME", "SOME", "");
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
217 test("", "", "");
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
218 }
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
219
100
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
220 fn env_list(strings: &[&'static str]) -> EnvList<'static> {
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
221 let ptrs: NonNull<Option<CHeapString>> = memory::calloc(strings.len() + 1).unwrap();
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
222 unsafe {
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
223 for (idx, &text) in strings.iter().enumerate() {
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
224 ptr::write(
105
13b4d2a19674 Support Rust v1.75.0.
Paul Fisher <paul@pfish.zone>
parents: 103
diff changeset
225 ptrs.as_ptr().add(idx),
100
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
226 Some(CHeapString::new(text).unwrap()),
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
227 )
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
228 }
105
13b4d2a19674 Support Rust v1.75.0.
Paul Fisher <paul@pfish.zone>
parents: 103
diff changeset
229 ptr::write(ptrs.as_ptr().add(strings.len()), None);
100
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
230 EnvList::from_ptr(ptrs.cast())
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
231 }
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
232 }
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
233
98
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
234 #[test]
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
235 fn test_iter() {
100
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
236 let envs = env_list(&["ONE=two", "BIRDS=birds=birds", "me", "you="]);
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
237 let result: Vec<_> = envs.collect();
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
238 assert_eq!(
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
239 vec![
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
240 (os("ONE"), os("two")),
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
241 (os("BIRDS"), os("birds=birds")),
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
242 (os("me"), os("")),
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
243 (os("you"), os("")),
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
244 ],
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
245 result
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
246 );
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
247 }
98
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
248
100
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
249 #[test]
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
250 fn test_iter_partial() {
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
251 let mut envs = env_list(&[
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
252 "iterating=this",
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
253 "also=here",
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
254 "but not=this one",
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
255 "or even=the last",
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
256 ]);
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
257
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
258 assert_eq!(Some((os("iterating"), os("this"))), envs.next());
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
259 assert_eq!(Some((os("also"), os("here"))), envs.next());
3f11b8d30f63 Implement environment variable management.
Paul Fisher <paul@pfish.zone>
parents: 98
diff changeset
260 // let envs drop
98
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
261 }
b87100c5eed4 Start on environment variables, and make pointers nicer.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
262 }