Skip to main content

relibc/platform/
mod.rs

1//! Platform abstractions and environment.
2
3use crate::{
4    error::{Errno, ResultExt},
5    io::{self, Read, Write},
6    raw_cell::RawCell,
7};
8use alloc::{boxed::Box, vec::Vec};
9use core::{cell::Cell, fmt, ptr};
10
11pub use self::allocator::*;
12
13mod allocator;
14
15pub mod logger;
16
17pub use self::pal::{Pal, PalEpoll, PalPtrace, PalSignal, PalSocket};
18
19mod pal;
20
21pub use self::sys::Sys;
22
23#[cfg(target_os = "linux")]
24#[path = "linux/mod.rs"]
25pub(crate) mod sys;
26
27#[cfg(target_os = "redox")]
28#[path = "redox/mod.rs"]
29pub(crate) mod sys;
30
31pub use self::rlb::{Line, RawLineBuffer};
32pub mod rlb;
33
34#[cfg(target_os = "linux")]
35pub mod auxv_defs;
36
37#[cfg(target_os = "redox")]
38pub use redox_rt::auxv_defs;
39
40use self::types::*;
41pub mod types;
42
43/// The global `errno` variable used internally in relibc.
44#[thread_local]
45pub static ERRNO: Cell<c_int> = Cell::new(0);
46
47/// The `argv` argument available to a program's `main` function.
48#[allow(non_upper_case_globals)]
49pub static mut argv: *mut *mut c_char = ptr::null_mut();
50#[allow(non_upper_case_globals)]
51pub static inner_argv: RawCell<Vec<*mut c_char>> = RawCell::new(Vec::new());
52#[allow(non_upper_case_globals)]
53pub static mut program_invocation_name: *mut c_char = ptr::null_mut();
54#[allow(non_upper_case_globals)]
55pub static mut program_invocation_short_name: *mut c_char = ptr::null_mut();
56
57#[allow(non_upper_case_globals)]
58#[unsafe(no_mangle)]
59pub static mut environ: *mut *mut c_char = ptr::null_mut();
60
61pub static OUR_ENVIRON: RawCell<Vec<*mut c_char>> = RawCell::new(Vec::new());
62
63pub fn environ_iter() -> impl Iterator<Item = *mut c_char> + 'static {
64    unsafe {
65        let mut ptrs = environ;
66
67        core::iter::from_fn(move || {
68            if ptrs.is_null() {
69                None
70            } else {
71                let ptr = ptrs.read();
72                if ptr.is_null() {
73                    None
74                } else {
75                    ptrs = ptrs.add(1);
76                    Some(ptr)
77                }
78            }
79        })
80    }
81}
82
83pub trait WriteByte: fmt::Write {
84    fn write_u8(&mut self, byte: u8) -> fmt::Result;
85}
86
87impl<W: WriteByte> WriteByte for &mut W {
88    fn write_u8(&mut self, byte: u8) -> fmt::Result {
89        (**self).write_u8(byte)
90    }
91}
92
93/// An implementation of [`core::fmt::Write`] for a file descriptor.
94pub struct FileWriter(pub c_int, Option<Errno>);
95
96impl FileWriter {
97    pub fn new(fd: c_int) -> Self {
98        Self(fd, None)
99    }
100
101    pub fn write(&mut self, buf: &[u8]) -> fmt::Result {
102        let _ = Sys::write(self.0, buf).map_err(|err| {
103            self.1 = Some(err);
104            fmt::Error
105        })?;
106        Ok(())
107    }
108}
109
110impl fmt::Write for FileWriter {
111    fn write_str(&mut self, s: &str) -> fmt::Result {
112        if let Ok(()) = self.write(s.as_bytes()) {}; // TODO handle error
113        Ok(())
114    }
115}
116
117impl WriteByte for FileWriter {
118    fn write_u8(&mut self, byte: u8) -> fmt::Result {
119        if let Ok(()) = self.write(&[byte]) {}; // TODO handle error
120        Ok(())
121    }
122}
123
124/// An implementation of [`Read`] for a file descriptor.
125pub struct FileReader(pub c_int);
126
127impl FileReader {
128    // TODO: This is a bad interface. Rustify
129    pub fn read(&mut self, buf: &mut [u8]) -> isize {
130        Sys::read(self.0, buf)
131            .map(|u| u as isize)
132            .or_minus_one_errno()
133    }
134}
135
136impl Read for FileReader {
137    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
138        let i = Sys::read(self.0, buf)
139            .map(|u| u as isize)
140            .or_minus_one_errno(); // TODO
141        if i >= 0 {
142            Ok(i as usize)
143        } else {
144            Err(io::Error::from_raw_os_error(-i as i32))
145        }
146    }
147}
148
149/// An implementation of [`Write`]/[`core::fmt::Write`] for a byte array.
150pub struct StringWriter(pub *mut c_char, pub usize);
151impl Write for StringWriter {
152    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
153        if self.1 > 1 {
154            let copy_size = buf.len().min(self.1 - 1);
155            unsafe {
156                ptr::copy_nonoverlapping(buf.as_ptr().cast(), self.0, copy_size);
157                self.1 -= copy_size;
158
159                self.0 = self.0.add(copy_size);
160                *self.0 = 0;
161            }
162        }
163
164        // Pretend the entire slice was written. This is because many functions
165        // (like snprintf) expects a return value that reflects how many bytes
166        // *would have* been written. So keeping track of this information is
167        // good, and then if we want the *actual* written size we can just go
168        // `cmp::min(written, maxlen)`.
169        Ok(buf.len())
170    }
171    fn flush(&mut self) -> io::Result<()> {
172        Ok(())
173    }
174}
175impl fmt::Write for StringWriter {
176    fn write_str(&mut self, s: &str) -> fmt::Result {
177        // can't fail
178        self.write(s.as_bytes()).unwrap();
179        Ok(())
180    }
181}
182impl WriteByte for StringWriter {
183    fn write_u8(&mut self, byte: u8) -> fmt::Result {
184        // can't fail
185        self.write(&[byte]).unwrap();
186        Ok(())
187    }
188}
189
190/// An implementation of [`Write`]/[`core::fmt::Write`] for a byte array,
191/// without buffer overflow protection.
192pub struct UnsafeStringWriter(pub *mut u8);
193impl Write for UnsafeStringWriter {
194    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
195        unsafe {
196            ptr::copy_nonoverlapping(buf.as_ptr(), self.0, buf.len());
197            self.0 = self.0.add(buf.len());
198            *self.0 = b'\0';
199        }
200        Ok(buf.len())
201    }
202    fn flush(&mut self) -> io::Result<()> {
203        Ok(())
204    }
205}
206impl fmt::Write for UnsafeStringWriter {
207    fn write_str(&mut self, s: &str) -> fmt::Result {
208        // can't fail
209        self.write(s.as_bytes()).unwrap();
210        Ok(())
211    }
212}
213impl WriteByte for UnsafeStringWriter {
214    fn write_u8(&mut self, byte: u8) -> fmt::Result {
215        // can't fail
216        self.write(&[byte]).unwrap();
217        Ok(())
218    }
219}
220
221/// An implementation of [`Read`] for a byte array, without buffer over-read
222/// protection.
223pub struct UnsafeStringReader(pub *const u8);
224impl Read for UnsafeStringReader {
225    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
226        unsafe {
227            for (i, inner) in buf.iter_mut().enumerate() {
228                if *self.0 == 0 {
229                    return Ok(i);
230                }
231
232                *inner = *self.0;
233                self.0 = self.0.offset(1);
234            }
235            Ok(buf.len())
236        }
237    }
238}
239
240/// A wrapper that keeps track of the number of bytes written with the
241/// underlying writer `T`.
242pub struct CountingWriter<T> {
243    pub inner: T,
244    pub written: usize,
245}
246impl<T> CountingWriter<T> {
247    pub fn new(writer: T) -> Self {
248        Self {
249            inner: writer,
250            written: 0,
251        }
252    }
253}
254impl<T: fmt::Write> fmt::Write for CountingWriter<T> {
255    fn write_str(&mut self, s: &str) -> fmt::Result {
256        self.written += s.len();
257        self.inner.write_str(s)
258    }
259}
260impl<T: WriteByte> WriteByte for CountingWriter<T> {
261    fn write_u8(&mut self, byte: u8) -> fmt::Result {
262        self.written += 1;
263        self.inner.write_u8(byte)
264    }
265}
266impl<T: Write> Write for CountingWriter<T> {
267    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
268        let res = self.inner.write(buf);
269        if let Ok(written) = res {
270            self.written += written;
271        }
272        res
273    }
274    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
275        match self.inner.write_all(buf) {
276            Ok(()) => (),
277            Err(ref err) if err.kind() == io::ErrorKind::WriteZero => (),
278            Err(err) => return Err(err),
279        }
280        self.written += buf.len();
281        Ok(())
282    }
283    fn flush(&mut self) -> io::Result<()> {
284        self.inner.flush()
285    }
286}
287
288// TODO: Set a global variable once get_auxvs is called, and then implement getauxval based on
289// get_auxv.
290
291#[cold]
292pub unsafe fn auxv_iter<'a>(ptr: *const usize) -> impl Iterator<Item = [usize; 2]> + 'a {
293    struct St(*const usize);
294    impl Iterator for St {
295        type Item = [usize; 2];
296
297        fn next(&mut self) -> Option<Self::Item> {
298            unsafe {
299                if *self.0 == self::auxv_defs::AT_NULL {
300                    return None;
301                }
302                let kind = *self.0;
303                let value = *self.0.add(1);
304                self.0 = self.0.add(2);
305
306                Some([kind, value])
307            }
308        }
309    }
310    St(ptr)
311}
312
313#[cold]
314pub unsafe fn get_auxvs(ptr: *const usize) -> Box<[[usize; 2]]> {
315    //traverse the stack and collect argument environment variables
316    let mut auxvs = unsafe { auxv_iter(ptr) }.collect::<Vec<_>>();
317
318    auxvs.sort_unstable_by_key(|[kind, _]| *kind);
319    auxvs.into_boxed_slice()
320}
321// TODO: Find an auxv replacement for Redox's execv protocol
322#[cold]
323pub unsafe fn get_auxv_raw(ptr: *const usize, requested_kind: usize) -> Option<usize> {
324    unsafe { auxv_iter(ptr) }
325        .find_map(|[kind, value]| Some(value).filter(|_| kind == requested_kind))
326}
327pub fn get_auxv(auxvs: &[[usize; 2]], key: usize) -> Option<usize> {
328    auxvs
329        .binary_search_by_key(&key, |[entry_key, _]| *entry_key)
330        .ok()
331        .map(|idx| auxvs[idx][1])
332}
333
334#[cold]
335#[cfg(target_os = "redox")]
336// SAFETY: Must only be called when only one thread exists.
337pub unsafe fn init(auxvs: Box<[[usize; 2]]>) {
338    use self::auxv_defs::*;
339    use redox_rt::proc::FdGuard;
340
341    let Some(proc_fd) = get_auxv(&auxvs, AT_REDOX_PROC_FD) else {
342        panic!("Missing proc and thread fd!");
343    };
344    let Some(ns_fd) = get_auxv(&auxvs, AT_REDOX_NS_FD) else {
345        panic!("Missing namespace fd!");
346    };
347    unsafe {
348        redox_rt::initialize(
349            FdGuard::new(proc_fd).to_upper().unwrap(),
350            if ns_fd == usize::MAX {
351                None
352            } else {
353                Some(FdGuard::new(ns_fd).to_upper().unwrap())
354            },
355        );
356        init_inner(auxvs)
357    }
358}
359#[cold]
360#[cfg(target_os = "redox")]
361pub unsafe fn init_inner(auxvs: Box<[[usize; 2]]>) {
362    use self::auxv_defs::*;
363    use crate::header::sys_stat::S_ISVTX;
364    use redox_rt::proc::FdGuard;
365    use syscall::MODE_PERM;
366
367    // TODO: Is it safe to assume setup_sighandler has been called at this point?
368    redox_rt::sys::this_proc_call(
369        &mut [],
370        syscall::CallFlags::empty(),
371        &[redox_protocols::protocol::ProcCall::SyncSigPctl as u64],
372    )
373    .expect("failed to sync signal pctl");
374
375    if let (Some(cwd_ptr), Some(cwd_len), Some(cwd_fd)) = (
376        get_auxv(&auxvs, AT_REDOX_INITIAL_CWD_PTR),
377        get_auxv(&auxvs, AT_REDOX_INITIAL_CWD_LEN),
378        get_auxv(&auxvs, AT_REDOX_CWD_FD),
379    ) {
380        let cwd_bytes: &'static [u8] =
381            unsafe { core::slice::from_raw_parts(cwd_ptr as *const u8, cwd_len) };
382        if let (Ok(Ok(cwd_path)), Some(cwd_fd)) = (
383            core::str::from_utf8(cwd_bytes).map(self::sys::path::CwdPath::from),
384            (cwd_fd != usize::MAX).then(|| {
385                FdGuard::new(cwd_fd)
386                    .to_upper()
387                    .expect("failed to move cwd fd to upper table")
388            }),
389        ) {
390            self::sys::path::set_cwd_manual(cwd_path, cwd_fd);
391        }
392    }
393
394    let mut inherited_sigignmask = 0_u64;
395    if let Some(mask) = get_auxv(&auxvs, AT_REDOX_INHERITED_SIGIGNMASK) {
396        inherited_sigignmask |= mask as u64;
397    }
398    #[cfg(target_pointer_width = "32")]
399    if let Some(mask) = get_auxv(&auxvs, AT_REDOX_INHERITED_SIGIGNMASK_HI) {
400        inherited_sigignmask |= (mask as u64) << 32;
401    }
402    redox_rt::signal::apply_inherited_sigignmask(inherited_sigignmask);
403
404    let mut inherited_sigprocmask = 0_u64;
405
406    if let Some(mask) = get_auxv(&auxvs, AT_REDOX_INHERITED_SIGPROCMASK) {
407        inherited_sigprocmask |= mask as u64;
408    }
409    #[cfg(target_pointer_width = "32")]
410    if let Some(mask) = get_auxv(&auxvs, AT_REDOX_INHERITED_SIGPROCMASK_HI) {
411        inherited_sigprocmask |= (mask as u64) << 32;
412    }
413    redox_rt::signal::set_sigmask(Some(inherited_sigprocmask), None).unwrap();
414
415    if let Some(umask) = get_auxv(&auxvs, AT_REDOX_UMASK) {
416        let _ =
417            redox_rt::sys::swap_umask((umask as u32) & u32::from(MODE_PERM) & !(S_ISVTX as u32));
418    }
419}
420#[expect(clippy::boxed_local)]
421#[cfg(not(target_os = "redox"))]
422pub unsafe fn init(auxvs: Box<[[usize; 2]]>) {}