1 use super::unsupported; 2 use crate::std::error::Error as StdError; 3 use crate::std::ffi::{CStr, OsStr, OsString}; 4 use crate::std::fmt; 5 use crate::std::io; 6 use crate::std::os::{ 7 raw::{c_char, c_int}, 8 solid::ffi::{OsStrExt, OsStringExt}, 9 }; 10 use crate::std::path::{self, PathBuf}; 11 use crate::std::sync::{PoisonError, RwLock}; 12 use crate::std::sys::common::small_c_string::run_with_cstr; 13 use crate::std::vec; 14 use dlibc; 15 16 use super::{error, itron, memchr}; 17 18 // `solid` directly maps `errno`s to μITRON error codes. 19 impl itron::error::ItronError { 20 #[inline] 21 pub(crate) fn as_io_error(self) -> crate::std::io::Error { 22 crate::std::io::Error::from_raw_os_error(self.as_raw()) 23 } 24 } 25 26 pub fn errno() -> i32 { 27 0 28 } 29 30 pub fn error_string(errno: i32) -> String { 31 if let Some(name) = error::error_name(errno) { 32 name.to_owned() 33 } else { 34 format!("{errno}") 35 } 36 } 37 38 pub fn getcwd() -> io::Result<PathBuf> { 39 unsupported() 40 } 41 42 pub fn chdir(_: &path::Path) -> io::Result<()> { 43 unsupported() 44 } 45 46 pub struct SplitPaths<'a>(&'a !); 47 48 pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> { 49 panic!("unsupported") 50 } 51 52 impl<'a> Iterator for SplitPaths<'a> { 53 type Item = PathBuf; 54 fn next(&mut self) -> Option<PathBuf> { 55 *self.0 56 } 57 } 58 59 #[derive(Debug)] 60 pub struct JoinPathsError; 61 62 pub fn join_paths<I, T>(_paths: I) -> Result<OsString, JoinPathsError> 63 where 64 I: Iterator<Item = T>, 65 T: AsRef<OsStr>, 66 { 67 Err(JoinPathsError) 68 } 69 70 impl fmt::Display for JoinPathsError { 71 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 72 "not supported on this platform yet".fmt(f) 73 } 74 } 75 76 impl StdError for JoinPathsError { 77 #[allow(deprecated)] 78 fn description(&self) -> &str { 79 "not supported on this platform yet" 80 } 81 } 82 83 pub fn current_exe() -> io::Result<PathBuf> { 84 unsupported() 85 } 86 87 static ENV_LOCK: RwLock<()> = RwLock::new(()); 88 89 pub fn env_read_lock() -> impl Drop { 90 ENV_LOCK.read().unwrap_or_else(PoisonError::into_inner) 91 } 92 93 pub struct Env { 94 iter: vec::IntoIter<(OsString, OsString)>, 95 } 96 97 // FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt. 98 pub struct EnvStrDebug<'a> { 99 slice: &'a [(OsString, OsString)], 100 } 101 102 impl fmt::Debug for EnvStrDebug<'_> { 103 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 104 let Self { slice } = self; 105 f.debug_list() 106 .entries( 107 slice 108 .iter() 109 .map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap())), 110 ) 111 .finish() 112 } 113 } 114 115 impl Env { 116 pub fn str_debug(&self) -> impl fmt::Debug + '_ { 117 let Self { iter } = self; 118 EnvStrDebug { 119 slice: iter.as_slice(), 120 } 121 } 122 } 123 124 impl fmt::Debug for Env { 125 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 126 let Self { iter } = self; 127 f.debug_list().entries(iter.as_slice()).finish() 128 } 129 } 130 131 impl !Send for Env {} 132 impl !Sync for Env {} 133 134 impl Iterator for Env { 135 type Item = (OsString, OsString); 136 fn next(&mut self) -> Option<(OsString, OsString)> { 137 self.iter.next() 138 } 139 fn size_hint(&self) -> (usize, Option<usize>) { 140 self.iter.size_hint() 141 } 142 } 143 144 /// Returns a vector of (variable, value) byte-vector pairs for all the 145 /// environment variables of the current process. 146 pub fn env() -> Env { 147 extern "C" { 148 static mut environ: *const *const c_char; 149 } 150 151 unsafe { 152 let _guard = env_read_lock(); 153 let mut result = Vec::new(); 154 if !environ.is_null() { 155 while !(*environ).is_null() { 156 if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) { 157 result.push(key_value); 158 } 159 environ = environ.add(1); 160 } 161 } 162 return Env { 163 iter: result.into_iter(), 164 }; 165 } 166 167 fn parse(input: &[u8]) -> Option<(OsString, OsString)> { 168 // Strategy (copied from glibc): Variable name and value are separated 169 // by an ASCII equals sign '='. Since a variable name must not be 170 // empty, allow variable names starting with an equals sign. Skip all 171 // malformed lines. 172 if input.is_empty() { 173 return None; 174 } 175 let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1); 176 pos.map(|p| { 177 ( 178 OsStringExt::from_vec(input[..p].to_vec()), 179 OsStringExt::from_vec(input[p + 1..].to_vec()), 180 ) 181 }) 182 } 183 } 184 185 pub fn getenv(k: &OsStr) -> Option<OsString> { 186 // environment variables with a nul byte can't be set, so their value is 187 // always None as well 188 run_with_cstr(k.as_bytes(), |k| { 189 let _guard = env_read_lock(); 190 let v = unsafe { dlibc::getenv(k.as_ptr()) } as *const dlibc::c_char; 191 192 if v.is_null() { 193 Ok(None) 194 } else { 195 // SAFETY: `v` cannot be mutated while executing this line since we've a read lock 196 let bytes = unsafe { CStr::from_ptr(v) }.to_bytes().to_vec(); 197 198 Ok(Some(OsStringExt::from_vec(bytes))) 199 } 200 }) 201 .ok() 202 .flatten() 203 } 204 205 pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { 206 run_with_cstr(k.as_bytes(), |k| { 207 run_with_cstr(v.as_bytes(), |v| { 208 let _guard = ENV_LOCK.write(); 209 cvt_env(unsafe { dlibc::setenv(k.as_ptr(), v.as_ptr(), 1) }).map(drop) 210 }) 211 }) 212 } 213 214 pub fn unsetenv(n: &OsStr) -> io::Result<()> { 215 run_with_cstr(n.as_bytes(), |nbuf| { 216 let _guard = ENV_LOCK.write(); 217 cvt_env(unsafe { dlibc::unsetenv(nbuf.as_ptr()) }).map(drop) 218 }) 219 } 220 221 /// In kmclib, `setenv` and `unsetenv` don't always set `errno`, so this 222 /// function just returns a generic error. 223 fn cvt_env(t: c_int) -> io::Result<c_int> { 224 if t == -1 { 225 Err(io::const_io_error!(io::ErrorKind::Uncategorized, "failure")) 226 } else { 227 Ok(t) 228 } 229 } 230 231 pub fn temp_dir() -> PathBuf { 232 panic!("no standard temporary directory on this platform") 233 } 234 235 pub fn home_dir() -> Option<PathBuf> { 236 None 237 } 238 239 pub fn exit(code: i32) -> ! { 240 rtabort!("exit({}) called", code); 241 } 242 243 pub fn getpid() -> u32 { 244 panic!("no pids on this platform") 245 } 246