Add 8 relibc POSIX compatibility patches for desktop stack
This commit is contained in:
@@ -0,0 +1,43 @@
|
|||||||
|
diff --git a/src/header/time/mod.rs b/src/header/time/mod.rs
|
||||||
|
--- a/src/header/time/mod.rs
|
||||||
|
+++ b/src/header/time/mod.rs
|
||||||
|
@@ -6,8 +6,8 @@
|
||||||
|
c_str::{CStr, CString},
|
||||||
|
error::{Errno, ResultExt},
|
||||||
|
header::{
|
||||||
|
bits_timespec::timespec,
|
||||||
|
- errno::{EFAULT, ENOMEM, EOVERFLOW, ETIMEDOUT},
|
||||||
|
+ errno::{EFAULT, EINVAL, ENOMEM, EOVERFLOW, ETIMEDOUT},
|
||||||
|
signal::sigevent,
|
||||||
|
stdlib::getenv,
|
||||||
|
unistd::readlink,
|
||||||
|
@@ -275,12 +275,28 @@
|
||||||
|
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/clock_nanosleep.html>.
|
||||||
|
// #[unsafe(no_mangle)]
|
||||||
|
pub extern "C" fn clock_nanosleep(
|
||||||
|
clock_id: clockid_t,
|
||||||
|
flags: c_int,
|
||||||
|
rqtp: *const timespec,
|
||||||
|
rmtp: *mut timespec,
|
||||||
|
) -> c_int {
|
||||||
|
- unimplemented!();
|
||||||
|
+ match clock_id {
|
||||||
|
+ CLOCK_REALTIME | CLOCK_MONOTONIC => {
|
||||||
|
+ if flags == TIMER_ABSTIME {
|
||||||
|
+ // Absolute-time sleep requires converting to a relative timeout.
|
||||||
|
+ // For CLOCK_MONOTONIC this is straightforward; for CLOCK_REALTIME
|
||||||
|
+ // we would need clock-delta computation. Return EINVAL until
|
||||||
|
+ // timespec_realtime_to_monotonic integration is validated.
|
||||||
|
+ return EINVAL;
|
||||||
|
+ }
|
||||||
|
+ match unsafe { Sys::nanosleep(rqtp, rmtp) } {
|
||||||
|
+ Ok(()) => 0,
|
||||||
|
+ Err(Errno(ETIMEDOUT)) => ETIMEDOUT,
|
||||||
|
+ Err(Errno(e)) => e,
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ _ => EINVAL,
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/clock_getres.html>.
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
diff --git a/src/header/unistd/mod.rs b/src/header/unistd/mod.rs
|
||||||
|
--- a/src/header/unistd/mod.rs
|
||||||
|
+++ b/src/header/unistd/mod.rs
|
||||||
|
@@ -273,7 +273,20 @@
|
||||||
|
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/dup.html>.
|
||||||
|
// #[unsafe(no_mangle)]
|
||||||
|
pub extern "C" fn dup3(fildes: c_int, fildes2: c_int, flag: c_int) -> c_int {
|
||||||
|
- unimplemented!();
|
||||||
|
+ // dup3 requires fildes != fildes2 (unlike dup2 which is a no-op in that case)
|
||||||
|
+ if fildes == fildes2 {
|
||||||
|
+ ERRNO.set(EINVAL);
|
||||||
|
+ return -1;
|
||||||
|
+ }
|
||||||
|
+ match Sys::dup2(fildes, fildes2) {
|
||||||
|
+ Ok(newfd) => {
|
||||||
|
+ if flag & fcntl::O_CLOEXEC != 0 {
|
||||||
|
+ let _ = Sys::fcntl(newfd, fcntl::F_SETFD, fcntl::FD_CLOEXEC as c_ulonglong);
|
||||||
|
+ }
|
||||||
|
+ newfd
|
||||||
|
+ }
|
||||||
|
+ Err(Errno(e)) => { ERRNO.set(e); -1 }
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/encrypt.html>.
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
diff --git a/src/header/unistd/mod.rs b/src/header/unistd/mod.rs
|
||||||
|
--- a/src/header/unistd/mod.rs
|
||||||
|
+++ b/src/header/unistd/mod.rs
|
||||||
|
@@ -537,8 +537,39 @@
|
||||||
|
|
||||||
|
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/getentropy.html>.
|
||||||
|
// #[unsafe(no_mangle)]
|
||||||
|
-pub extern "C" fn getentropy(buffer: *mut c_void, length: size_t) -> c_int {
|
||||||
|
- unimplemented!();
|
||||||
|
+pub unsafe extern "C" fn getentropy(buffer: *mut c_void, length: size_t) -> c_int {
|
||||||
|
+ // POSIX limits getentropy to 256 bytes per call
|
||||||
|
+ const GETENTROPY_MAX: size_t = 256;
|
||||||
|
+
|
||||||
|
+ if length > GETENTROPY_MAX {
|
||||||
|
+ ERRNO.set(EINVAL);
|
||||||
|
+ return -1;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ let path = unsafe { CStr::from_ptr(c"/scheme/rand".as_ptr().cast()) };
|
||||||
|
+ let fd = match Sys::open(path, fcntl::O_RDONLY, 0) {
|
||||||
|
+ Ok(fd) => fd,
|
||||||
|
+ Err(Errno(e)) => {
|
||||||
|
+ ERRNO.set(e);
|
||||||
|
+ return -1;
|
||||||
|
+ }
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
+ let buf = unsafe { slice::from_raw_parts_mut(buffer.cast::<u8>(), length) };
|
||||||
|
+ let mut filled = 0usize;
|
||||||
|
+ while filled < length {
|
||||||
|
+ match Sys::read(fd, &mut buf[filled..]) {
|
||||||
|
+ Ok(0) => break,
|
||||||
|
+ Ok(n) => filled += n,
|
||||||
|
+ Err(Errno(e)) => {
|
||||||
|
+ let _ = Sys::close(fd);
|
||||||
|
+ ERRNO.set(e);
|
||||||
|
+ return -1;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ let _ = Sys::close(fd);
|
||||||
|
+ if filled < length { ERRNO.set(errno::EIO); -1 } else { 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/geteuid.html>.
|
||||||
@@ -0,0 +1,182 @@
|
|||||||
|
--- a/src/header/semaphore/mod.rs 2026-04-25 17:07:53.742796721 +0100
|
||||||
|
+++ b/src/header/semaphore/mod.rs 2026-04-25 17:08:54.527084219 +0100
|
||||||
|
@@ -2,12 +2,24 @@
|
||||||
|
//!
|
||||||
|
//! See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/semaphore.h.html>.
|
||||||
|
|
||||||
|
+use core::mem::size_of;
|
||||||
|
+
|
||||||
|
use crate::{
|
||||||
|
+ c_str::CStr,
|
||||||
|
header::{
|
||||||
|
bits_timespec::timespec,
|
||||||
|
+ errno::{EEXIST, EINVAL},
|
||||||
|
+ fcntl::{O_CREAT, O_EXCL, O_RDWR},
|
||||||
|
+ sys_mman::{
|
||||||
|
+ mmap, munmap, shm_open, shm_unlink, MAP_SHARED, MAP_FAILED, PROT_READ, PROT_WRITE,
|
||||||
|
+ },
|
||||||
|
time::{CLOCK_MONOTONIC, CLOCK_REALTIME},
|
||||||
|
+ unistd::{close, ftruncate},
|
||||||
|
+ },
|
||||||
|
+ platform::{
|
||||||
|
+ ERRNO,
|
||||||
|
+ types::{c_char, c_int, c_long, c_uint, clockid_t, c_void, mode_t, off_t, size_t},
|
||||||
|
},
|
||||||
|
- platform::types::{c_char, c_int, c_long, c_uint, clockid_t},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/semaphore.h.html>.
|
||||||
|
@@ -18,12 +30,17 @@
|
||||||
|
pub size: [c_char; 4],
|
||||||
|
pub align: c_long,
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+/// Pointer value returned by `sem_open` on failure.
|
||||||
|
+/// cbindgen:ignore
|
||||||
|
+pub const SEM_FAILED: *mut sem_t = usize::MAX as *mut sem_t;
|
||||||
|
+
|
||||||
|
pub type RlctSempahore = crate::sync::Semaphore;
|
||||||
|
|
||||||
|
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sem_close.html>.
|
||||||
|
-// #[unsafe(no_mangle)]
|
||||||
|
+#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn sem_close(sem: *mut sem_t) -> c_int {
|
||||||
|
- todo!("named semaphores")
|
||||||
|
+ unsafe { munmap(sem.cast::<c_void>(), size_of::<sem_t>()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sem_destroy.html>.
|
||||||
|
@@ -50,13 +67,105 @@
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sem_open.html>.
|
||||||
|
-// TODO: va_list
|
||||||
|
-// #[unsafe(no_mangle)]
|
||||||
|
+#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn sem_open(
|
||||||
|
name: *const c_char,
|
||||||
|
- oflag: c_int, /* (va_list) value: c_uint */
|
||||||
|
+ oflag: c_int,
|
||||||
|
+ mut __valist: ...
|
||||||
|
) -> *mut sem_t {
|
||||||
|
- todo!("named semaphores")
|
||||||
|
+ // Validate name: must start with '/', no embedded '/'.
|
||||||
|
+ if name.is_null() {
|
||||||
|
+ ERRNO.set(EINVAL);
|
||||||
|
+ return SEM_FAILED;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ let name_c = unsafe { CStr::from_ptr(name) };
|
||||||
|
+ let name_bytes = name_c.to_bytes();
|
||||||
|
+ if name_bytes.is_empty() || name_bytes[0] != b'/' {
|
||||||
|
+ ERRNO.set(EINVAL);
|
||||||
|
+ return SEM_FAILED;
|
||||||
|
+ }
|
||||||
|
+ if name_bytes[1..].iter().any(|&b| b == b'/') {
|
||||||
|
+ ERRNO.set(EINVAL);
|
||||||
|
+ return SEM_FAILED;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ let creat = oflag & O_CREAT == O_CREAT;
|
||||||
|
+ let excl = oflag & O_EXCL == O_EXCL;
|
||||||
|
+
|
||||||
|
+ let (mode, value): (mode_t, c_uint) = if creat {
|
||||||
|
+ (
|
||||||
|
+ unsafe { __valist.arg::<mode_t>() },
|
||||||
|
+ unsafe { __valist.arg::<c_uint>() },
|
||||||
|
+ )
|
||||||
|
+ } else {
|
||||||
|
+ (0, 0)
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
+ // Open or create the shared memory backing.
|
||||||
|
+ let (fd, created) = if creat && excl {
|
||||||
|
+ // O_CREAT | O_EXCL: must create exclusively.
|
||||||
|
+ let fd = unsafe { shm_open(name, O_CREAT | O_EXCL | O_RDWR, mode) };
|
||||||
|
+ if fd < 0 {
|
||||||
|
+ return SEM_FAILED;
|
||||||
|
+ }
|
||||||
|
+ (fd, true)
|
||||||
|
+ } else if creat {
|
||||||
|
+ // O_CREAT without O_EXCL: try exclusive first, fall back to open.
|
||||||
|
+ let fd = unsafe { shm_open(name, O_CREAT | O_EXCL | O_RDWR, mode) };
|
||||||
|
+ if fd >= 0 {
|
||||||
|
+ (fd, true)
|
||||||
|
+ } else if ERRNO.get() == EEXIST {
|
||||||
|
+ let fd = unsafe { shm_open(name, O_RDWR, 0) };
|
||||||
|
+ if fd < 0 {
|
||||||
|
+ return SEM_FAILED;
|
||||||
|
+ }
|
||||||
|
+ (fd, false)
|
||||||
|
+ } else {
|
||||||
|
+ return SEM_FAILED;
|
||||||
|
+ }
|
||||||
|
+ } else {
|
||||||
|
+ // No O_CREAT: open existing.
|
||||||
|
+ let fd = unsafe { shm_open(name, O_RDWR, 0) };
|
||||||
|
+ if fd < 0 {
|
||||||
|
+ return SEM_FAILED;
|
||||||
|
+ }
|
||||||
|
+ (fd, false)
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
+ // Set size if we created the backing.
|
||||||
|
+ if created {
|
||||||
|
+ if unsafe { ftruncate(fd, size_of::<sem_t>() as off_t) } < 0 {
|
||||||
|
+ let _ = unsafe { close(fd) };
|
||||||
|
+ return SEM_FAILED;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // Map the shared memory.
|
||||||
|
+ let ptr = unsafe {
|
||||||
|
+ mmap(
|
||||||
|
+ core::ptr::null_mut(),
|
||||||
|
+ size_of::<sem_t>(),
|
||||||
|
+ PROT_READ | PROT_WRITE,
|
||||||
|
+ MAP_SHARED,
|
||||||
|
+ fd,
|
||||||
|
+ 0,
|
||||||
|
+ )
|
||||||
|
+ };
|
||||||
|
+ let _ = unsafe { close(fd) };
|
||||||
|
+
|
||||||
|
+ if ptr == MAP_FAILED {
|
||||||
|
+ return SEM_FAILED;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ let sem_ptr = ptr.cast::<sem_t>();
|
||||||
|
+
|
||||||
|
+ // Initialize the semaphore value if we created the backing.
|
||||||
|
+ if created {
|
||||||
|
+ unsafe { sem_ptr.cast::<RlctSempahore>().write(RlctSempahore::new(value)) };
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ sem_ptr
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sem_post.html>.
|
||||||
|
@@ -76,9 +185,9 @@
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sem_unlink.html>.
|
||||||
|
-// #[unsafe(no_mangle)]
|
||||||
|
+#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn sem_unlink(name: *const c_char) -> c_int {
|
||||||
|
- todo!("named semaphores")
|
||||||
|
+ unsafe { shm_unlink(name) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sem_trywait.html>.
|
||||||
|
--- a/src/header/semaphore/cbindgen.toml 2026-04-25 17:07:53.743979154 +0100
|
||||||
|
+++ b/src/header/semaphore/cbindgen.toml 2026-04-25 17:09:18.310792692 +0100
|
||||||
|
@@ -3,6 +3,9 @@
|
||||||
|
after_includes = """
|
||||||
|
#include <bits/timespec.h> // for timespec
|
||||||
|
"""
|
||||||
|
+trailer = """
|
||||||
|
+#define SEM_FAILED ((sem_t *) -1)
|
||||||
|
+"""
|
||||||
|
language = "C"
|
||||||
|
style = "Type"
|
||||||
|
no_includes = true
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
diff --git a/src/header/pthread/mod.rs b/src/header/pthread/mod.rs
|
||||||
|
--- a/src/header/pthread/mod.rs
|
||||||
|
+++ b/src/header/pthread/mod.rs
|
||||||
|
@@ -304,9 +304,17 @@
|
||||||
|
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_setcancelstate.html>.
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn pthread_testcancel() {
|
||||||
|
unsafe { pthread::testcancel() };
|
||||||
|
}
|
||||||
|
|
||||||
|
+/// <https://man7.org/linux/man-pages/man3/pthread_yield.3.html>
|
||||||
|
+///
|
||||||
|
+/// Non-standard GNU extension. Prefer `sched_yield()` instead.
|
||||||
|
+// #[unsafe(no_mangle)]
|
||||||
|
+pub extern "C" fn pthread_yield() {
|
||||||
|
+ let _ = Sys::sched_yield();
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
// Must be the same struct as defined in the pthread_cleanup_push macro.
|
||||||
|
#[repr(C)]
|
||||||
|
pub(crate) struct CleanupLinkedListEntry {
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
diff --git a/src/header/stdlib/mod.rs b/src/header/stdlib/mod.rs
|
||||||
|
--- a/src/header/stdlib/mod.rs
|
||||||
|
+++ b/src/header/stdlib/mod.rs
|
||||||
|
@@ -1233,7 +1233,11 @@
|
||||||
|
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/getenv.html>.
|
||||||
|
// #[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn secure_getenv(name: *const c_char) -> *mut c_char {
|
||||||
|
- unimplemented!();
|
||||||
|
+ // Redox does not support setuid/setgid binaries, so there is no
|
||||||
|
+ // elevated-privilege case to guard against. Always delegate to getenv.
|
||||||
|
+ // If setuid support is ever added, this must check real vs effective
|
||||||
|
+ // uid/gid and return NULL when they differ.
|
||||||
|
+ unsafe { getenv(name) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/drand48.html>.
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
diff --git a/src/header/dl-tls/mod.rs b/src/header/dl-tls/mod.rs
|
||||||
|
--- a/src/header/dl-tls/mod.rs
|
||||||
|
+++ b/src/header/dl-tls/mod.rs
|
||||||
|
@@ -49,8 +49,18 @@ pub unsafe extern "C" fn __tls_get_addr(ti: *mut dl_tls_index) -> *mut c_void {
|
||||||
|
let module_tls = unsafe {
|
||||||
|
// FIXME(andypython): master.align
|
||||||
|
let layout = Layout::from_size_align_unchecked(master.segment_size, 16);
|
||||||
|
let ptr = alloc(layout);
|
||||||
|
|
||||||
|
+ if ptr.is_null() {
|
||||||
|
+ eprintln!(
|
||||||
|
+ "__tls_get_addr: TLS allocation failed for module {:#x} (size {})",
|
||||||
|
+ ti.ti_module, master.segment_size
|
||||||
|
+ );
|
||||||
|
+ return ptr::null_mut();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
ptr::copy_nonoverlapping(master.ptr, ptr, master.image_size);
|
||||||
|
ptr::write_bytes(
|
||||||
|
ptr.add(master.image_size),
|
||||||
|
@@ -68,10 +78,14 @@ pub unsafe extern "C" fn __tls_get_addr(ti: *mut dl_tls_index) -> *mut c_void {
|
||||||
|
let mut ptr = tcb.dtv_mut()[dtv_index];
|
||||||
|
|
||||||
|
if ptr.is_null() {
|
||||||
|
- panic!(
|
||||||
|
- "__tls_get_addr({ti:p}: {:#x}, {:#x})",
|
||||||
|
- ti.ti_module, ti.ti_offset
|
||||||
|
+ eprintln!(
|
||||||
|
+ "__tls_get_addr({:p}: {:#x}, {:#x}): \
|
||||||
|
+ DTV entry is null, module {} TLS not available",
|
||||||
|
+ ti, ti.ti_module, ti.ti_offset, ti.ti_module
|
||||||
|
);
|
||||||
|
+ return ptr::null_mut();
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg!(target_arch = "riscv64") {
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
diff --git a/src/header/unistd/mod.rs b/src/header/unistd/mod.rs
|
||||||
|
--- a/src/header/unistd/mod.rs
|
||||||
|
+++ b/src/header/unistd/mod.rs
|
||||||
|
@@ -1214,12 +1214,20 @@
|
||||||
|
/// See <https://pubs.opengroup.org/onlinepubs/009695399/functions/vfork.html>.
|
||||||
|
///
|
||||||
|
/// # Deprecation
|
||||||
|
/// The `vfork()` function was marked obsolescent in the Open Group Base
|
||||||
|
/// Specifications Issue 6, and removed in Issue 7.
|
||||||
|
#[deprecated]
|
||||||
|
// #[unsafe(no_mangle)]
|
||||||
|
pub extern "C" fn vfork() -> pid_t {
|
||||||
|
- unimplemented!();
|
||||||
|
+ // Simplified implementation: Redox uses copy-on-write fork semantics,
|
||||||
|
+ // which provides the memory-sharing benefits of traditional vfork
|
||||||
|
+ // without the dangerous shared-address-space semantics. This wrapper
|
||||||
|
+ // simply delegates to fork().
|
||||||
|
+ //
|
||||||
|
+ // callers that depend on the parent being suspended until the child
|
||||||
|
+ // calls exec or _exit will still work correctly, just without the
|
||||||
|
+ // scheduling guarantee that vfork traditionally provided.
|
||||||
|
+ unsafe { fork() }
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn with_argv(
|
||||||
Reference in New Issue
Block a user