]> git.lizzy.rs Git - rust.git/blob - src/libstd/sys/redox/os.rs
Rollup merge of #58802 - nnethercote:inline-record_layout, r=oli-obk
[rust.git] / src / libstd / sys / redox / os.rs
1 //! Implementation of `std::os` functionality for unix systems
2
3 #![allow(unused_imports)] // lots of cfg code here
4
5 use libc::c_char;
6
7 use crate::os::unix::prelude::*;
8
9 use crate::error::Error as StdError;
10 use crate::ffi::{CStr, CString, OsStr, OsString};
11 use crate::fmt;
12 use crate::io::{self, Read, Write};
13 use crate::iter;
14 use crate::marker::PhantomData;
15 use crate::mem;
16 use crate::memchr;
17 use crate::path::{self, PathBuf};
18 use crate::ptr;
19 use crate::slice;
20 use crate::str;
21 use crate::sys_common::mutex::Mutex;
22 use crate::sys::{cvt, cvt_libc, fd, syscall};
23 use crate::vec;
24
25 extern {
26     #[link_name = "__errno_location"]
27     fn errno_location() -> *mut i32;
28 }
29
30 /// Returns the platform-specific value of errno
31 pub fn errno() -> i32 {
32     unsafe {
33         (*errno_location())
34     }
35 }
36
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) {
40         string.to_string()
41     } else {
42         "unknown error".to_string()
43     }
44 }
45
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())))
50 }
51
52 pub fn chdir(p: &path::Path) -> io::Result<()> {
53     cvt(syscall::chdir(p.to_str().unwrap())).and(Ok(()))
54 }
55
56 pub struct SplitPaths<'a> {
57     iter: iter::Map<slice::Split<'a, u8, fn(&u8) -> bool>,
58                     fn(&'a [u8]) -> PathBuf>,
59 }
60
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))
64     }
65     fn is_semicolon(b: &u8) -> bool { *b == b';' }
66     let unparsed = unparsed.as_bytes();
67     SplitPaths {
68         iter: unparsed.split(is_semicolon as fn(&u8) -> bool)
69                       .map(bytes_to_path as fn(&[u8]) -> PathBuf)
70     }
71 }
72
73 impl<'a> Iterator for SplitPaths<'a> {
74     type Item = PathBuf;
75     fn next(&mut self) -> Option<PathBuf> { self.iter.next() }
76     fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
77 }
78
79 #[derive(Debug)]
80 pub struct JoinPathsError;
81
82 pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
83     where I: Iterator<Item=T>, T: AsRef<OsStr>
84 {
85     let mut joined = Vec::new();
86     let sep = b';';
87
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)
93         }
94         joined.extend_from_slice(path);
95     }
96     Ok(OsStringExt::from_vec(joined))
97 }
98
99 impl fmt::Display for JoinPathsError {
100     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
101         "path segment contains separator `:`".fmt(f)
102     }
103 }
104
105 impl StdError for JoinPathsError {
106     fn description(&self) -> &str { "failed to join paths" }
107 }
108
109 pub fn current_exe() -> io::Result<PathBuf> {
110     use crate::fs::File;
111
112     let mut file = File::open("sys:exe")?;
113
114     let mut path = String::new();
115     file.read_to_string(&mut path)?;
116
117     if path.ends_with('\n') {
118         path.pop();
119     }
120
121     Ok(PathBuf::from(path))
122 }
123
124 pub static ENV_LOCK: Mutex = Mutex::new();
125
126 pub struct Env {
127     iter: vec::IntoIter<(OsString, OsString)>,
128     _dont_send_or_sync_me: PhantomData<*mut ()>,
129 }
130
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() }
135 }
136
137 pub unsafe fn environ() -> *mut *const *const c_char {
138     extern { static mut environ: *const *const c_char; }
139     &mut environ
140 }
141
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 {
145     unsafe {
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());
151         }
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);
156             }
157             environ = environ.offset(1);
158         }
159         return Env {
160             iter: result.into_iter(),
161             _dont_send_or_sync_me: PhantomData,
162         }
163     }
164
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
169         // malformed lines.
170         if input.is_empty() {
171             return None;
172         }
173         let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1);
174         pos.map(|p| (
175             OsStringExt::from_vec(input[..p].to_vec()),
176             OsStringExt::from_vec(input[p+1..].to_vec()),
177         ))
178     }
179 }
180
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())?;
185     unsafe {
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() {
189             None
190         } else {
191             Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec()))
192         };
193         Ok(ret)
194     }
195 }
196
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())?;
200
201     unsafe {
202         let _guard = ENV_LOCK.lock();
203         cvt_libc(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(|_| ())
204     }
205 }
206
207 pub fn unsetenv(n: &OsStr) -> io::Result<()> {
208     let nbuf = CString::new(n.as_bytes())?;
209
210     unsafe {
211         let _guard = ENV_LOCK.lock();
212         cvt_libc(libc::unsetenv(nbuf.as_ptr())).map(|_| ())
213     }
214 }
215
216 pub fn page_size() -> usize {
217     4096
218 }
219
220 pub fn temp_dir() -> PathBuf {
221     crate::env::var_os("TMPDIR").map(PathBuf::from).unwrap_or_else(|| {
222         PathBuf::from("/tmp")
223     })
224 }
225
226 pub fn home_dir() -> Option<PathBuf> {
227     return crate::env::var_os("HOME").map(PathBuf::from);
228 }
229
230 pub fn exit(code: i32) -> ! {
231     let _ = syscall::exit(code as usize);
232     unreachable!();
233 }
234
235 pub fn getpid() -> u32 {
236     syscall::getpid().unwrap() as u32
237 }
238
239 pub fn getppid() -> u32 {
240     syscall::getppid().unwrap() as u32
241 }