1 //! Implementation of `std::os` functionality for unix systems
3 #![allow(unused_imports)] // lots of cfg code here
7 use crate::os::unix::prelude::*;
9 use crate::error::Error as StdError;
10 use crate::ffi::{CStr, CString, OsStr, OsString};
12 use crate::io::{self, Read, Write};
14 use crate::marker::PhantomData;
17 use crate::path::{self, PathBuf};
21 use crate::sys_common::mutex::Mutex;
22 use crate::sys::{cvt, cvt_libc, fd, syscall};
26 #[link_name = "__errno_location"]
27 fn errno_location() -> *mut i32;
30 /// Returns the platform-specific value of errno
31 pub fn errno() -> i32 {
37 /// Gets a detailed string description for the given error number.
38 pub fn error_string(errno: i32) -> String {
39 if let Some(string) = syscall::STR_ERROR.get(errno as usize) {
42 "unknown error".to_string()
46 pub fn getcwd() -> io::Result<PathBuf> {
47 let mut buf = [0; 4096];
48 let count = cvt(syscall::getcwd(&mut buf))?;
49 Ok(PathBuf::from(OsString::from_vec(buf[.. count].to_vec())))
52 pub fn chdir(p: &path::Path) -> io::Result<()> {
53 cvt(syscall::chdir(p.to_str().unwrap())).and(Ok(()))
56 pub struct SplitPaths<'a> {
57 iter: iter::Map<slice::Split<'a, u8, fn(&u8) -> bool>,
58 fn(&'a [u8]) -> PathBuf>,
61 pub fn split_paths(unparsed: &OsStr) -> SplitPaths {
62 fn bytes_to_path(b: &[u8]) -> PathBuf {
63 PathBuf::from(<OsStr as OsStrExt>::from_bytes(b))
65 fn is_semicolon(b: &u8) -> bool { *b == b';' }
66 let unparsed = unparsed.as_bytes();
68 iter: unparsed.split(is_semicolon as fn(&u8) -> bool)
69 .map(bytes_to_path as fn(&[u8]) -> PathBuf)
73 impl<'a> Iterator for SplitPaths<'a> {
75 fn next(&mut self) -> Option<PathBuf> { self.iter.next() }
76 fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
80 pub struct JoinPathsError;
82 pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
83 where I: Iterator<Item=T>, T: AsRef<OsStr>
85 let mut joined = Vec::new();
88 for (i, path) in paths.enumerate() {
89 let path = path.as_ref().as_bytes();
90 if i > 0 { joined.push(sep) }
91 if path.contains(&sep) {
92 return Err(JoinPathsError)
94 joined.extend_from_slice(path);
96 Ok(OsStringExt::from_vec(joined))
99 impl fmt::Display for JoinPathsError {
100 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
101 "path segment contains separator `:`".fmt(f)
105 impl StdError for JoinPathsError {
106 fn description(&self) -> &str { "failed to join paths" }
109 pub fn current_exe() -> io::Result<PathBuf> {
112 let mut file = File::open("sys:exe")?;
114 let mut path = String::new();
115 file.read_to_string(&mut path)?;
117 if path.ends_with('\n') {
121 Ok(PathBuf::from(path))
124 pub static ENV_LOCK: Mutex = Mutex::new();
127 iter: vec::IntoIter<(OsString, OsString)>,
128 _dont_send_or_sync_me: PhantomData<*mut ()>,
131 impl Iterator for Env {
132 type Item = (OsString, OsString);
133 fn next(&mut self) -> Option<(OsString, OsString)> { self.iter.next() }
134 fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
137 pub unsafe fn environ() -> *mut *const *const c_char {
138 extern { static mut environ: *const *const c_char; }
142 /// Returns a vector of (variable, value) byte-vector pairs for all the
143 /// environment variables of the current process.
144 pub fn env() -> Env {
146 let _guard = ENV_LOCK.lock();
147 let mut environ = *environ();
148 if environ == ptr::null() {
149 panic!("os::env() failure getting env string from OS: {}",
150 io::Error::last_os_error());
152 let mut result = Vec::new();
153 while *environ != ptr::null() {
154 if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) {
155 result.push(key_value);
157 environ = environ.offset(1);
160 iter: result.into_iter(),
161 _dont_send_or_sync_me: PhantomData,
165 fn parse(input: &[u8]) -> Option<(OsString, OsString)> {
166 // Strategy (copied from glibc): Variable name and value are separated
167 // by an ASCII equals sign '='. Since a variable name must not be
168 // empty, allow variable names starting with an equals sign. Skip all
170 if input.is_empty() {
173 let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1);
175 OsStringExt::from_vec(input[..p].to_vec()),
176 OsStringExt::from_vec(input[p+1..].to_vec()),
181 pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
182 // environment variables with a nul byte can't be set, so their value is
183 // always None as well
184 let k = CString::new(k.as_bytes())?;
186 let _guard = ENV_LOCK.lock();
187 let s = libc::getenv(k.as_ptr()) as *const libc::c_char;
188 let ret = if s.is_null() {
191 Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec()))
197 pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
198 let k = CString::new(k.as_bytes())?;
199 let v = CString::new(v.as_bytes())?;
202 let _guard = ENV_LOCK.lock();
203 cvt_libc(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(|_| ())
207 pub fn unsetenv(n: &OsStr) -> io::Result<()> {
208 let nbuf = CString::new(n.as_bytes())?;
211 let _guard = ENV_LOCK.lock();
212 cvt_libc(libc::unsetenv(nbuf.as_ptr())).map(|_| ())
216 pub fn page_size() -> usize {
220 pub fn temp_dir() -> PathBuf {
221 crate::env::var_os("TMPDIR").map(PathBuf::from).unwrap_or_else(|| {
222 PathBuf::from("/tmp")
226 pub fn home_dir() -> Option<PathBuf> {
227 return crate::env::var_os("HOME").map(PathBuf::from);
230 pub fn exit(code: i32) -> ! {
231 let _ = syscall::exit(code as usize);
235 pub fn getpid() -> u32 {
236 syscall::getpid().unwrap() as u32
239 pub fn getppid() -> u32 {
240 syscall::getppid().unwrap() as u32