c_scape/
lib.rs

1#![doc = include_str!("../README.md")]
2// c-scape does not use std; features that depend on std are in c-gull instead.
3#![no_std]
4// Nightly Rust features that we depend on.
5#![feature(thread_local)] // for `pthread_getspecific` etc.
6#![feature(c_variadic)] // for `printf`, `ioctl`, etc.
7#![feature(sync_unsafe_cell)] // for lots of libc static variables
8#![feature(linkage)] // for `malloc` etc.
9// Disable some common warnings.
10#![allow(unexpected_cfgs)]
11// Don't warn if `try_into()` is fallible on some targets.
12#![allow(unreachable_patterns)]
13// Don't warn if `try_into()` is fallible on some targets.
14#![allow(irrefutable_let_patterns)]
15
16// Check that our features were used as we intend.
17#[cfg(all(feature = "coexist-with-libc", feature = "take-charge"))]
18compile_error!("Enable only one of \"coexist-with-libc\" and \"take-charge\".");
19#[cfg(all(not(feature = "coexist-with-libc"), not(feature = "take-charge")))]
20compile_error!("Enable one \"coexist-with-libc\" and \"take-charge\".");
21
22extern crate alloc;
23
24// Re-export the libc crate's API. This allows users to depend on the c-scape
25// crate in place of libc.
26pub use libc::*;
27
28#[macro_use]
29mod use_libc;
30
31#[cfg(not(target_os = "wasi"))]
32mod at_fork;
33mod error_str;
34mod sync_ptr;
35
36// Selected libc-compatible interfaces.
37//
38// The goal here isn't necessarily to build a complete libc; it's primarily
39// to provide things that `std` and possibly popular crates are currently
40// using.
41//
42// This effectively undoes the work that `rustix` does: it calls `rustix` and
43// translates it back into a C-like ABI. Ideally, Rust code should just call
44// the `rustix` APIs directly, which are safer, more ergonomic, and skip this
45// whole layer.
46
47#[cfg(feature = "take-charge")]
48use core::ptr::addr_of;
49use errno::{set_errno, Errno};
50
51mod arpa_inet;
52mod atoi;
53mod base64;
54mod brk;
55mod ctype;
56mod env;
57mod errno_;
58mod error;
59mod exec;
60#[cfg(feature = "take-charge")]
61mod exit;
62mod fs;
63mod glibc_versioning;
64mod int;
65mod io;
66mod jmp;
67mod locale;
68#[cfg(feature = "take-charge")]
69mod malloc;
70mod math;
71mod mem;
72mod mkostemps;
73#[cfg(not(target_os = "wasi"))]
74mod mm;
75mod net;
76mod nss;
77mod path;
78mod pause;
79mod posix_spawn;
80#[cfg(not(target_os = "wasi"))]
81mod process;
82mod process_;
83mod pty;
84mod rand;
85mod rand48;
86mod rand_;
87mod regex;
88mod shm;
89#[cfg(not(target_os = "wasi"))]
90#[cfg(feature = "take-charge")]
91mod signal;
92mod sort;
93#[cfg(feature = "take-charge")]
94mod stdio;
95mod strtod;
96mod strtol;
97mod syscall;
98mod system;
99mod termios_;
100#[cfg(feature = "thread")]
101#[cfg(feature = "take-charge")]
102mod thread;
103mod time;
104
105#[cfg(feature = "deprecated-and-unimplemented")]
106mod deprecated;
107#[cfg(feature = "todo")]
108mod todo;
109
110/// An ABI-conforming `__dso_handle`.
111#[cfg(feature = "take-charge")]
112#[no_mangle]
113static __dso_handle: UnsafeSendSyncVoidStar =
114    UnsafeSendSyncVoidStar(addr_of!(__dso_handle) as *const _);
115
116/// A type for `__dso_handle`.
117///
118/// `*const c_void` isn't `Send` or `Sync` because a raw pointer could point to
119/// arbitrary data which isn't thread-safe, however `__dso_handle` is used as
120/// an opaque cookie value, and it always points to itself.
121///
122/// Note that in C, `__dso_handle`'s type is usually `void *` which would
123/// correspond to `*mut c_void`, however we can assume the pointee is never
124/// actually mutated.
125#[repr(transparent)]
126#[cfg(feature = "take-charge")]
127struct UnsafeSendSyncVoidStar(*const core::ffi::c_void);
128#[cfg(feature = "take-charge")]
129unsafe impl Send for UnsafeSendSyncVoidStar {}
130#[cfg(feature = "take-charge")]
131unsafe impl Sync for UnsafeSendSyncVoidStar {}
132
133/// This function is called by Origin.
134///
135/// SAFETY: `argc`, `argv`, and `envp` describe incoming program
136/// command-line arguments and environment variables.
137#[cfg(feature = "take-charge")]
138#[cfg(feature = "call-main")]
139#[no_mangle]
140unsafe fn origin_main(argc: usize, argv: *mut *mut u8, envp: *mut *mut u8) -> i32 {
141    extern "C" {
142        fn main(argc: i32, argv: *const *const u8, envp: *const *const u8) -> i32;
143    }
144    main(argc as _, argv as _, envp as _)
145}
146
147// utilities
148
149/// Convert a rustix `Result` into an `Option` with the error stored
150/// in `errno`.
151fn convert_res<T>(result: Result<T, rustix::io::Errno>) -> Option<T> {
152    result
153        .map_err(|err| set_errno(Errno(err.raw_os_error())))
154        .ok()
155}
156
157/// A type that implements `lock_api::GetThreadId` for use with
158/// `lock_api::RawReentrantMutex`.
159#[cfg(feature = "thread")]
160#[cfg(feature = "take-charge")]
161pub(crate) struct GetThreadId;
162
163#[cfg(feature = "thread")]
164#[cfg(feature = "take-charge")]
165unsafe impl rustix_futex_sync::lock_api::GetThreadId for GetThreadId {
166    const INIT: Self = Self;
167
168    #[inline]
169    fn nonzero_thread_id(&self) -> core::num::NonZeroUsize {
170        // Use the current thread "raw" value, which origin guarantees uniquely
171        // identifies a thread. `thread::current_id` would also work, but would
172        // be slightly slower on some architectures.
173        origin::thread::current().to_raw_non_null().addr()
174    }
175}
176
177/// If requested, define the global allocator.
178#[cfg(feature = "global-allocator")]
179#[global_allocator]
180static GLOBAL_ALLOCATOR: rustix_dlmalloc::GlobalDlmalloc = rustix_dlmalloc::GlobalDlmalloc;
181
182/// Convert a `KernelSigSet` into a `libc::sigset_t`.
183#[cfg(feature = "take-charge")]
184pub(crate) fn expand_sigset(set: rustix::runtime::KernelSigSet) -> libc::sigset_t {
185    let mut lc = core::mem::MaybeUninit::<libc::sigset_t>::uninit();
186    unsafe {
187        // First create an empty `sigset_t`.
188        let r = libc::sigemptyset(lc.as_mut_ptr());
189        assert_eq!(r, 0);
190        // Then write a `KernelSigSet` into the beginning of it. It's
191        // guaranteed to have a subset of the layout.
192        lc.as_mut_ptr()
193            .cast::<rustix::runtime::KernelSigSet>()
194            .write(set);
195        lc.assume_init()
196    }
197}