From df78820f01e7ff80d1dab1447585f76e2474584f Mon Sep 17 00:00:00 2001 From: R Aadarsh Date: Tue, 12 May 2026 21:03:10 +0530 Subject: [PATCH 01/29] Add `posix_spawn_file_actions_t` and `posix_spawnattr_t` and tests --- src/header/mod.rs | 2 +- src/header/spawn/cbindgen.toml | 10 ++ src/header/spawn/file_actions.rs | 200 ++++++++++++++++++++++++ src/header/spawn/mod.rs | 25 +++ src/header/spawn/spawn_attr.rs | 254 +++++++++++++++++++++++++++++++ tests/Makefile.tests.mk | 1 + tests/spawn.c | 92 +++++++++++ 7 files changed, 583 insertions(+), 1 deletion(-) create mode 100644 src/header/spawn/cbindgen.toml create mode 100644 src/header/spawn/file_actions.rs create mode 100644 src/header/spawn/mod.rs create mode 100644 src/header/spawn/spawn_attr.rs create mode 100644 tests/spawn.c diff --git a/src/header/mod.rs b/src/header/mod.rs index 006f5a6a87..7d70798519 100644 --- a/src/header/mod.rs +++ b/src/header/mod.rs @@ -124,7 +124,7 @@ pub mod setjmp; pub mod sgtty; pub mod shadow; pub mod signal; -// TODO: spawn.h +pub mod spawn; // TODO: stdalign.h (likely C implementation) // stdarg.h implemented in C // stdatomic.h implemented in C diff --git a/src/header/spawn/cbindgen.toml b/src/header/spawn/cbindgen.toml new file mode 100644 index 0000000000..0ebe663c2b --- /dev/null +++ b/src/header/spawn/cbindgen.toml @@ -0,0 +1,10 @@ +sys_includes = ["sched.h", "bits/sigset-t.h"] +include_guard = "_RELIBC_SPAWN_H" +language = "C" +cpp_compat = true + +[enum] +prefix_with_name = true + +[export.rename] +"sched_param" = "struct sched_param" \ No newline at end of file diff --git a/src/header/spawn/file_actions.rs b/src/header/spawn/file_actions.rs new file mode 100644 index 0000000000..3602b08daf --- /dev/null +++ b/src/header/spawn/file_actions.rs @@ -0,0 +1,200 @@ +use core::{ + ffi::{c_char, c_int}, + ptr::null, +}; + +use crate::{ + error::{Errno, Result}, + header::{ + errno::{EBADF, EINVAL, ENOMEM}, + stdlib::{free, malloc}, + string::memcpy, + }, + platform::types::{c_void, mode_t}, +}; + +const OPEN: c_char = 1; +const CLOSE: c_char = 2; +const CHDIR: c_char = 3; +const FCHDIR: c_char = 4; +const DUP2: c_char = 5; + +#[repr(C)] +enum Operation { + Open { + fd: c_int, + path: *const c_char, + flag: c_int, + mode: mode_t, + }, + Close(c_int), + Chdir(*const c_char), + FChdir(c_int), + Dup2(c_int, c_int), +} + +#[repr(C)] +pub struct posix_spawn_file_actions_t { + size: usize, + operation: *const Operation, +} + +fn copy_op(file_actions: *mut posix_spawn_file_actions_t, op: Operation) -> Result<()> { + if file_actions.is_null() { + return Err(Errno(EINVAL)); + } + + let new = unsafe { malloc((*file_actions).size + size_of::()) }; + + if new == -1isize as *mut c_void { + return Err(Errno(ENOMEM)); + } + + unsafe { + if (*file_actions).size >= size_of::() { + memcpy( + new, + (*file_actions).operation as *const c_void, + (*file_actions).size / size_of::(), + ); + + free((*file_actions).operation as *mut c_void); + } + + (*file_actions).operation = new as *const Operation; + + let new = new as *mut Operation; + + (*new.add((*file_actions).size)) = op; + (*file_actions).size += size_of::() + } + + Ok(()) +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn posix_spawn_file_actions_init( + file_actions: *mut posix_spawn_file_actions_t, +) -> c_int { + if file_actions.is_null() { + return EINVAL; + } + + unsafe { + (*file_actions).operation = null(); + (*file_actions).size = 0; + } + + 0 +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn posix_spawn_file_actions_destroy( + file_actions: *mut posix_spawn_file_actions_t, +) -> c_int { + if file_actions.is_null() { + return EINVAL; + } + + unsafe { + free((*file_actions).operation as *mut c_void); + (*file_actions).operation = null(); + (*file_actions).size = 0; + } + + 0 +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn posix_spawn_file_actions_addopen( + file_actions: *mut posix_spawn_file_actions_t, + fd: c_int, + path: *const c_char, + oflag: c_int, + mode: mode_t, +) -> c_int { + if fd < 0 { + return EBADF; + } + + let open_op = Operation::Open { + fd, + path, + flag: oflag, + mode, + }; + + if let Err(e) = copy_op(file_actions, open_op) { + return e.0; + } + + 0 +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn posix_spawn_file_actions_addclose( + file_actions: *mut posix_spawn_file_actions_t, + fd: c_int, +) -> c_int { + if fd < 0 { + return EBADF; + } + + let close_op = Operation::Close(fd); + + if let Err(e) = copy_op(file_actions, close_op) { + return e.0; + } + 0 +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn posix_spawn_file_actions_addchdir( + file_actions: *mut posix_spawn_file_actions_t, + path: *const c_char, +) -> c_int { + let chdir_op = Operation::Chdir(path); + + if let Err(e) = copy_op(file_actions, chdir_op) { + return e.0; + } + + 0 +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn posix_spawn_file_actions_addfchdir( + file_actions: *mut posix_spawn_file_actions_t, + fd: c_int, +) -> c_int { + if fd < 0 { + return EBADF; + } + + let fchdir_op = Operation::FChdir(fd); + + if let Err(e) = copy_op(file_actions, fchdir_op) { + return e.0; + } + + 0 +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn posix_spawn_file_actions_adddup2( + file_actions: *mut posix_spawn_file_actions_t, + fd: c_int, + new: c_int, +) -> c_int { + if fd < 0 || new < 0 { + return EBADF; + } + + let dup2_op = Operation::Dup2(fd, new); + + if let Err(e) = copy_op(file_actions, dup2_op) { + return e.0; + } + + 0 +} diff --git a/src/header/spawn/mod.rs b/src/header/spawn/mod.rs new file mode 100644 index 0000000000..76d237fb93 --- /dev/null +++ b/src/header/spawn/mod.rs @@ -0,0 +1,25 @@ +//! `spawn.h` implementation +//! +//! See . + +mod file_actions; +mod spawn_attr; + +use core::ffi::c_char; + +use crate::{ + header::spawn::{file_actions::posix_spawn_file_actions_t, spawn_attr::posix_spawnattr_t}, + platform::types::{c_int, pid_t}, +}; + +#[unsafe(no_mangle)] +pub fn posix_spawn( + pid: *const pid_t, + path: *const c_char, + file_actions: *const posix_spawn_file_actions_t, + spawn_attr: *const posix_spawnattr_t, + argv: *const *const c_char, + envp: *const *const c_char, +) -> c_int { + todo!() +} diff --git a/src/header/spawn/spawn_attr.rs b/src/header/spawn/spawn_attr.rs new file mode 100644 index 0000000000..397cbe1f08 --- /dev/null +++ b/src/header/spawn/spawn_attr.rs @@ -0,0 +1,254 @@ +use core::{ + ffi::{c_int, c_short}, + mem::zeroed, +}; + +use bitflags; + +use crate::header::{ + bits_sigset_t::sigset_t, + errno::EINVAL, + sched::{SCHED_FIFO, SCHED_OTHER, SCHED_RR, sched_param}, + sys_types_internal::pid_t, +}; + +bitflags::bitflags! { + struct Flags: c_short + { + const POSIX_SPAWN_RESETIDS = 1; + const POSIX_SPAWN_SETPGROUP = 2; + const POSIX_SPAWN_SETSIGDEF = 3; + const POSIX_SPAWN_SETSIGMASK = 4; + const POSIX_SPAWN_SETSCHEDPARAM = 5; + const POSIX_SPAWN_SETSCHEDULER = 6; + } +} + +pub const POSIX_SPAWN_RESETIDS: c_short = 1; +pub const POSIX_SPAWN_SETPGROUP: c_short = 2; +pub const POSIX_SPAWN_SETSIGDEF: c_short = 3; +pub const POSIX_SPAWN_SETSIGMASK: c_short = 4; +pub const POSIX_SPAWN_SETSCHEDPARAM: c_short = 5; +pub const POSIX_SPAWN_SETSCHEDULER: c_short = 6; + +#[repr(C)] +pub struct posix_spawnattr_t { + pub(crate) param: sched_param, + flags: c_short, + pgroup: c_int, + policy: c_int, + sigdefault: sigset_t, + sigmask: sigset_t, +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn posix_spawnattr_init(attr: *mut posix_spawnattr_t) -> c_int { + if attr.is_null() { + return EINVAL; + } + + unsafe { + *attr = zeroed(); + } + 0 +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn posix_spawnattr_destroy(attr: *mut posix_spawnattr_t) -> c_int { + if attr.is_null() { + return EINVAL; + } + + 0 +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn posix_spawnattr_setschedparam( + attr: *mut posix_spawnattr_t, + schedparam: *const sched_param, +) -> c_int { + if attr.is_null() || schedparam.is_null() { + return EINVAL; + } + + unsafe { + (*attr).param = *schedparam; + } + + 0 +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn posix_spawnattr_getschedparam( + attr: *const posix_spawnattr_t, + schedparam: *mut sched_param, +) -> c_int { + if attr.is_null() || schedparam.is_null() { + return EINVAL; + } + + unsafe { + *schedparam = (*attr).param; + } + + 0 +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn posix_spawnattr_setschedpolicy( + attr: *mut posix_spawnattr_t, + schedpolicy: c_int, +) -> c_int { + if attr.is_null() { + return EINVAL; + } + + match schedpolicy { + SCHED_FIFO | SCHED_RR | SCHED_OTHER => unsafe { + (*attr).policy = schedpolicy; + }, + _ => return EINVAL, + } + + 0 +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn posix_spawnattr_getschedpolicy( + attr: *const posix_spawnattr_t, + schedpolicy: *mut c_int, +) -> c_int { + if attr.is_null() || schedpolicy.is_null() { + return EINVAL; + } + + unsafe { + *schedpolicy = (*attr).policy; + } + 0 +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn posix_spawnattr_setsigdefault( + attr: *mut posix_spawnattr_t, + sigdefault: *const sigset_t, +) -> c_int { + if attr.is_null() || sigdefault.is_null() { + return EINVAL; + } + + unsafe { + (*attr).sigdefault = *sigdefault; + } + 0 +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn posix_spawnattr_getsigdefault( + attr: *const posix_spawnattr_t, + sigdefault: *mut sigset_t, +) -> c_int { + if attr.is_null() || sigdefault.is_null() { + return EINVAL; + } + + unsafe { + *sigdefault = (*attr).sigdefault; + } + 0 +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn posix_spawnattr_setsigmask( + attr: *mut posix_spawnattr_t, + sigmask: *const sigset_t, +) -> c_int { + if attr.is_null() || sigmask.is_null() { + return EINVAL; + } + + unsafe { + (*attr).sigmask = *sigmask; + } + 0 +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn posix_spawnattr_getsigmask( + attr: *const posix_spawnattr_t, + sigmask: *mut sigset_t, +) -> c_int { + if attr.is_null() || sigmask.is_null() { + return EINVAL; + } + + unsafe { + *sigmask = (*attr).sigmask; + } + 0 +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn posix_spawnattr_setflags( + attr: *mut posix_spawnattr_t, + flags: c_short, +) -> c_int { + if attr.is_null() { + return EINVAL; + } + + unsafe { + match Flags::from_bits(flags) { + Some(v) => (*attr).flags = v.bits(), + None => { + return EINVAL; + } + } + } + 0 +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn posix_spawnattr_getflags( + attr: *const posix_spawnattr_t, + flags: *mut c_short, +) -> c_int { + if attr.is_null() || flags.is_null() { + return EINVAL; + } + + unsafe { + *flags = (*attr).flags; + } + 0 +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn posix_spawnattr_setpgroup( + attr: *mut posix_spawnattr_t, + pgroup: pid_t, +) -> c_int { + if attr.is_null() { + return EINVAL; + } + + unsafe { + (*attr).pgroup = pgroup; + } + 0 +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn posix_spawnattr_getpgroup( + attr: *const posix_spawnattr_t, + pgroup: *mut pid_t, +) -> c_int { + if attr.is_null() || pgroup.is_null() { + return EINVAL; + } + + unsafe { + *pgroup = (*attr).pgroup; + } + 0 +} diff --git a/tests/Makefile.tests.mk b/tests/Makefile.tests.mk index e82236799e..dddebeed2d 100644 --- a/tests/Makefile.tests.mk +++ b/tests/Makefile.tests.mk @@ -77,6 +77,7 @@ EXPECT_NAMES=\ sigaltstack \ signal \ sigsetjmp \ + spawn \ stdio/all \ stdio/buffer \ stdio/dprintf \ diff --git a/tests/spawn.c b/tests/spawn.c new file mode 100644 index 0000000000..b55f1d4286 --- /dev/null +++ b/tests/spawn.c @@ -0,0 +1,92 @@ +#include +#include +#include +#include +#include + +#include "test_helpers.h" + +#define CHECK(cond, msg) \ + if (!cond) \ + { \ + fprintf(stderr, "Error in spawn.h: %s\n", msg); \ + _exit(EXIT_FAILURE); \ + } + +#define CHECK_WHEN_NULL(call, name) \ + if (!(call)) \ + { \ + fprintf(stderr, "Error in spawn.h: %s expected to fail when passing NULL\n", name); \ + _exit(EXIT_FAILURE); \ + } + +int main() +{ + posix_spawn_file_actions_t fa_t; + CHECK((posix_spawn_file_actions_init(&fa_t) == 0), "posix_spawn_file_actions_init failed") + CHECK_WHEN_NULL(posix_spawn_file_actions_init(NULL), "posix_spawn_file_actions_init") + CHECK((posix_spawn_file_actions_addopen(&fa_t, 1, ".", O_RDONLY, 1) == 0), "Error while adding open action") + CHECK((posix_spawn_file_actions_addclose(&fa_t, 1) == 0), "Error while adding close action") + CHECK((posix_spawn_file_actions_adddup2(&fa_t, -1, 3) == EBADF), "Adding dup2 with negative fd must fail") + CHECK((fa_t.size == 64), "Size remains unchanged") + CHECK_WHEN_NULL(posix_spawn_file_actions_destroy(NULL), "posix_spawn_file_actions_destroy") + CHECK_WHEN_NULL(posix_spawn_file_actions_addclose(NULL, 1), "posix_spawn_file_actions_addclose") + CHECK((posix_spawn_file_actions_destroy(&fa_t) == 0), "posix_spawn_file_actions_destroy failed") + CHECK((fa_t.size == 0), "Expected 0 size in posix_spawn_file_actions_t after destruction") + + posix_spawnattr_t sa; + CHECK((posix_spawnattr_init(&sa) == 0), "posix_spawnattr_init failed") + CHECK((sa.param.sched_priority == 0 && sa.flags == 0 && sa.pgroup == 0 && sa.policy == 0 && sa.sigdefault == 0 && sa.sigmask == 0), "All fields expected to be zero after init in posix_spawnattr_t") + CHECK_WHEN_NULL(posix_spawnattr_init(NULL), "posix_spawnattr_init") + CHECK_WHEN_NULL(posix_spawnattr_destroy(NULL), "posix_spawnattr_destroy") + + struct sched_param sp1; + sp1.sched_priority = 2; + struct sched_param sp2; + sp2.sched_priority = 0; + CHECK_WHEN_NULL(posix_spawnattr_setschedparam(NULL, &sp1), "posix_spawnattr_setschedparam") + CHECK_WHEN_NULL(posix_spawnattr_setschedparam(&sa, NULL), "posix_spawnattr_setschedparam") + CHECK((posix_spawnattr_setschedparam(&sa, &sp1) == 0), "posix_spawnattr_setschedparam failed") + CHECK_WHEN_NULL(posix_spawnattr_getschedparam(NULL, &sp2), "posix_spawnattr_getschedparam") + CHECK_WHEN_NULL(posix_spawnattr_getschedparam(&sa, NULL), "posix_spawnattr_getschedparam") + CHECK((posix_spawnattr_getschedparam(&sa, &sp2) == 0 && sp2.sched_priority == 2), "posix_spawnattr_getschedparam failed") + + CHECK_WHEN_NULL(posix_spawnattr_setschedpolicy(NULL, 0), "posix_spawnattr_setschedpolicy") + CHECK((posix_spawnattr_setschedpolicy(&sa, 1) == 0), "posix_spawnattr_setschedpolicy failed") + int pol = 0; + CHECK_WHEN_NULL(posix_spawnattr_getschedpolicy(NULL, &pol), "posix_spawnattr_getschedpolicy") + CHECK_WHEN_NULL(posix_spawnattr_getschedpolicy(&sa, NULL), "posix_spawnattr_getschedpolicy") + CHECK((posix_spawnattr_getschedpolicy(&sa, &pol) == 0 && pol == 1), "posix_spawnattr_getschedpolicy failed") + + sigset_t sst = 1; + sigset_t sst2 = 0; + CHECK_WHEN_NULL(posix_spawnattr_setsigdefault(NULL, &sst), "posix_spawnattr_setsigdefault") + CHECK_WHEN_NULL(posix_spawnattr_setsigdefault(&sa, NULL), "posix_spawnattr_setsigdefault") + CHECK((posix_spawnattr_setsigdefault(&sa, &sst) == 0), "posix_spawnattr_setsigdefault failed") + CHECK((posix_spawnattr_getsigdefault(&sa, &sst2) == 0 && sst2 == 1), "posix_spawnattr_getsigdefault failed") + CHECK_WHEN_NULL(posix_spawnattr_getsigdefault(NULL, &sst2), "posix_spawnattr_getsigdefault") + CHECK_WHEN_NULL(posix_spawnattr_getsigdefault(&sa, NULL), "posix_spawnattr_getsigdefault") + + sst = 3; + CHECK_WHEN_NULL(posix_spawnattr_setsigmask(NULL, &sst), "posix_spawnattr_setsigmask") + CHECK_WHEN_NULL(posix_spawnattr_setsigmask(&sa, NULL), "posix_spawnattr_setsigmask") + CHECK((posix_spawnattr_setsigmask(&sa, &sst) == 0), "posix_spawnattr_setsigmask failed") + CHECK_WHEN_NULL(posix_spawnattr_getsigmask(NULL, &sst2), "posix_spawnattr_getsigmask") + CHECK_WHEN_NULL(posix_spawnattr_getsigmask(&sa, NULL), "posix_spawnattr_getsigmask") + CHECK((posix_spawnattr_getsigmask(&sa, &sst2) == 0 && sst2 == 3), "posix_spawnattr_getsigmask failed") + + CHECK_WHEN_NULL(posix_spawnattr_setflags(NULL, 0), "posix_spawnattr_setflags") + CHECK((posix_spawnattr_setflags(&sa, 1) == 0), "posix_spawnattr_setflags failed") + short int pf = 0; + CHECK_WHEN_NULL(posix_spawnattr_getflags(NULL, &pf), "posix_spawnattr_getflags") + CHECK_WHEN_NULL(posix_spawnattr_getflags(&sa, NULL), "posix_spawnattr_getflags") + CHECK((posix_spawnattr_getflags(&sa, &pf) == 0 && pf == 1), "posix_spawnattr_getflags failed") + CHECK((posix_spawnattr_setflags(&sa, 7565) == EINVAL), "posix_spawnattr_setflags expected to fail when passing invalid bits") + + pid_t id = 0; + CHECK_WHEN_NULL(posix_spawnattr_setpgroup(NULL, 3), "posix_spawnattr_setpgroup") + CHECK((posix_spawnattr_setpgroup(&sa, 3) == 0), "posix_spawnattr_setpgroup failed") + CHECK_WHEN_NULL(posix_spawnattr_getpgroup(NULL, &id), "posix_spawnattr_getpgroup") + CHECK_WHEN_NULL(posix_spawnattr_getpgroup(&sa, NULL), "posix_spawnattr_getpgroup") + CHECK((posix_spawnattr_getpgroup(&sa, &id) == 0 && id == 3), "posix_spawnattr_getpgroup failed") +} From 1bc472e7e1dcc5aa3c20b06750b2514577f538d2 Mon Sep 17 00:00:00 2001 From: R Aadarsh Date: Thu, 14 May 2026 18:47:42 +0530 Subject: [PATCH 02/29] Add `posix_spawn` and `posix_spawnp` for RedoxOS --- redox-rt/src/proc.rs | 6 +- src/header/spawn/file_actions.rs | 29 ++++----- src/header/spawn/mod.rs | 100 ++++++++++++++++++++++++++++--- src/header/spawn/spawn_attr.rs | 12 ++-- src/platform/pal/mod.rs | 9 +++ src/platform/redox/mod.rs | 69 ++++++++++++++++++++- 6 files changed, 190 insertions(+), 35 deletions(-) diff --git a/redox-rt/src/proc.rs b/redox-rt/src/proc.rs index c79d475d75..2682e2443b 100644 --- a/redox-rt/src/proc.rs +++ b/redox-rt/src/proc.rs @@ -1086,10 +1086,10 @@ pub fn fork_inner(initial_rsp: *mut usize, args: &ForkArgs) -> Result { } pub struct NewChildProc { - proc_fd: Option, + pub proc_fd: Option, - thr_fd: FdGuardUpper, - pid: usize, + pub thr_fd: FdGuardUpper, + pub pid: usize, } pub fn new_child_process(args: &ForkArgs<'_>) -> Result { diff --git a/src/header/spawn/file_actions.rs b/src/header/spawn/file_actions.rs index 3602b08daf..2d1bcb05ac 100644 --- a/src/header/spawn/file_actions.rs +++ b/src/header/spawn/file_actions.rs @@ -20,7 +20,7 @@ const FCHDIR: c_char = 4; const DUP2: c_char = 5; #[repr(C)] -enum Operation { +pub enum Operation { Open { fd: c_int, path: *const c_char, @@ -76,14 +76,13 @@ fn copy_op(file_actions: *mut posix_spawn_file_actions_t, op: Operation) -> Resu pub unsafe extern "C" fn posix_spawn_file_actions_init( file_actions: *mut posix_spawn_file_actions_t, ) -> c_int { - if file_actions.is_null() { - return EINVAL; - } + let file_actions = match unsafe { file_actions.as_mut().ok_or(Errno(EINVAL)) } { + Ok(v) => v, + Err(_) => return EINVAL, + }; - unsafe { - (*file_actions).operation = null(); - (*file_actions).size = 0; - } + (*file_actions).operation = null(); + (*file_actions).size = 0; 0 } @@ -92,15 +91,13 @@ pub unsafe extern "C" fn posix_spawn_file_actions_init( pub unsafe extern "C" fn posix_spawn_file_actions_destroy( file_actions: *mut posix_spawn_file_actions_t, ) -> c_int { - if file_actions.is_null() { - return EINVAL; - } + let file_actions = match unsafe { file_actions.as_mut().ok_or(Errno(EINVAL)) } { + Ok(v) => v, + Err(_) => return EINVAL, + }; - unsafe { - free((*file_actions).operation as *mut c_void); - (*file_actions).operation = null(); - (*file_actions).size = 0; - } + (*file_actions).operation = null(); + (*file_actions).size = 0; 0 } diff --git a/src/header/spawn/mod.rs b/src/header/spawn/mod.rs index 76d237fb93..2d079f128a 100644 --- a/src/header/spawn/mod.rs +++ b/src/header/spawn/mod.rs @@ -5,21 +5,105 @@ mod file_actions; mod spawn_attr; -use core::ffi::c_char; +pub use file_actions::{Operation, posix_spawn_file_actions_t}; +pub use spawn_attr::{Flags, posix_spawnattr_t}; use crate::{ - header::spawn::{file_actions::posix_spawn_file_actions_t, spawn_attr::posix_spawnattr_t}, - platform::types::{c_int, pid_t}, + c_str::CStr, + error::{Errno, Result}, + header::{errno::ENOENT, stdlib::getenv}, + platform::{ + self, Pal, + types::{c_char, c_int, pid_t}, + }, }; +fn spawn( + mut program: &str, + file_actions: Option<&posix_spawn_file_actions_t>, + spawn_attr: Option<&posix_spawnattr_t>, + argv: *const *mut c_char, + envp: *const *mut c_char, + use_path: bool, +) -> Result { + if use_path { + let path_env = unsafe { + CStr::from_ptr(getenv("PATH".as_ptr() as *const c_char)) + .to_str() + .unwrap() + }; + let path_elements = path_env.split(':'); + let program_name = program.split("/").last().unwrap(); + let mut flag = false; + + for element in path_elements { + if element.split("/").last().unwrap() == program_name { + flag = true; + program = element; + break; + } + if !flag { + return Err(Errno(ENOENT)); + } + } + } + + unsafe { + platform::Sys::spawn( + CStr::from_bytes_with_nul_unchecked(program.as_bytes()), + file_actions, + spawn_attr, + argv, + envp, + use_path, + ) + } +} + #[unsafe(no_mangle)] -pub fn posix_spawn( +pub extern "C" fn posix_spawn( pid: *const pid_t, - path: *const c_char, + program: *const c_char, file_actions: *const posix_spawn_file_actions_t, spawn_attr: *const posix_spawnattr_t, - argv: *const *const c_char, - envp: *const *const c_char, + argv: *const *mut c_char, + envp: *const *mut c_char, ) -> c_int { - todo!() + let program = unsafe { CStr::from_ptr(program).to_str().unwrap() }; + + match spawn( + program, + unsafe { file_actions.as_ref() }, + unsafe { spawn_attr.as_ref() }, + argv, + envp, + false, + ) { + Ok(v) => v, + Err(e) => e.0, + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn posix_spawnp( + pid: *const pid_t, + program: *const c_char, + file_actions: *const posix_spawn_file_actions_t, + spawn_attr: *const posix_spawnattr_t, + argv: *const *mut c_char, + envp: *const *mut c_char, +) -> c_int { + let program = unsafe { CStr::from_ptr(program).to_str().unwrap() }; + + match spawn( + program, + unsafe { file_actions.as_ref() }, + unsafe { spawn_attr.as_ref() }, + argv, + envp, + true, + ) { + Ok(v) => v, + Err(e) => e.0, + } } diff --git a/src/header/spawn/spawn_attr.rs b/src/header/spawn/spawn_attr.rs index 397cbe1f08..c109c4f261 100644 --- a/src/header/spawn/spawn_attr.rs +++ b/src/header/spawn/spawn_attr.rs @@ -13,7 +13,7 @@ use crate::header::{ }; bitflags::bitflags! { - struct Flags: c_short + pub struct Flags: c_short { const POSIX_SPAWN_RESETIDS = 1; const POSIX_SPAWN_SETPGROUP = 2; @@ -34,11 +34,11 @@ pub const POSIX_SPAWN_SETSCHEDULER: c_short = 6; #[repr(C)] pub struct posix_spawnattr_t { pub(crate) param: sched_param, - flags: c_short, - pgroup: c_int, + pub(crate) flags: c_short, + pub(crate) pgroup: c_int, policy: c_int, sigdefault: sigset_t, - sigmask: sigset_t, + pub(crate) sigmask: sigset_t, } #[unsafe(no_mangle)] @@ -217,9 +217,7 @@ pub unsafe extern "C" fn posix_spawnattr_getflags( return EINVAL; } - unsafe { - *flags = (*attr).flags; - } + unsafe { *flags = (*attr).flags } 0 } diff --git a/src/platform/pal/mod.rs b/src/platform/pal/mod.rs index f3ed9595b3..a6c7be22dc 100644 --- a/src/platform/pal/mod.rs +++ b/src/platform/pal/mod.rs @@ -433,6 +433,15 @@ pub trait Pal { /// Platform implementation of [`setsid()`](crate::header::unistd::setsid) from [`unistd.h`](crate::header::unistd). fn setsid() -> Result; + unsafe fn spawn( + program: CStr, + fac: Option<&crate::header::spawn::posix_spawn_file_actions_t>, + fat: Option<&crate::header::spawn::posix_spawnattr_t>, + argv: *const *mut c_char, + envp: *const *mut c_char, + use_path: bool, + ) -> Result; + /// Platform implementation of [`symlink()`](crate::header::unistd::symlink) from [`unistd.h`](crate::header::unistd). fn symlink(path1: CStr, path2: CStr) -> Result<()> { Self::symlinkat(path1, AT_FDCWD, path2) diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index 54967ade95..549891c9d2 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -39,6 +39,7 @@ use crate::{ signal::{NSIG, SIGEV_NONE, SIGEV_SIGNAL, SIGEV_THREAD, SIGRTMIN, sigevent}, stdio::RENAME_NOREPLACE, stdlib::posix_memalign, + string::strlen, sys_file, sys_mman::{MAP_ANONYMOUS, PROT_READ, PROT_WRITE}, sys_random, @@ -67,7 +68,7 @@ pub use redox_rt::proc::FdGuard; mod epoll; mod event; -mod exec; +pub(crate) mod exec; mod extra; mod libcscheme; mod libredox; @@ -1192,6 +1193,72 @@ impl Pal for Sys { Ok(()) } + unsafe fn spawn( + program: CStr, + fac: Option<&crate::header::spawn::posix_spawn_file_actions_t>, + fat: Option<&crate::header::spawn::posix_spawnattr_t>, + mut argv: *const *mut c_char, + mut envp: *const *mut c_char, + use_path: bool, + ) -> Result { + let child = redox_rt::proc::new_child_process(&redox_rt::proc::ForkArgs::Managed)?; + let executable = File::open(program, fcntl::O_RDONLY)?; + let cwd = path::clone_cwd().unwrap(); + let proc_fd = child.proc_fd.unwrap(); + + let extra_info = redox_rt::proc::ExtraInfo { + cwd: Some(cwd.as_bytes()), + sigignmask: redox_rt::signal::get_sigignmask_to_inherit(), + sigprocmask: if let Some(fat) = fat + && crate::header::spawn::Flags::from_bits(fat.flags) + .unwrap() + .contains(crate::header::spawn::Flags::POSIX_SPAWN_SETSIGMASK) + { + fat.sigmask + } else { + redox_rt::signal::get_sigmask().unwrap() + }, + umask: redox_rt::sys::get_umask(), + thr_fd: child.thr_fd.as_raw_fd(), + proc_fd: proc_fd.as_raw_fd(), + ns_fd: redox_rt::current_namespace_fd().ok(), + cwd_fd: path::current_dir() + .ok() + .map(|fd| fd.as_ref().unwrap().fd.as_raw_fd()), + }; + + let mut args = Vec::new(); + let mut envs = Vec::new(); + + while unsafe { !(*argv).is_null() } { + let arg = unsafe { *argv }; + let len = unsafe { strlen(arg) }; + args.push(unsafe { slice::from_raw_parts(arg as *const u8, len) }); + argv = unsafe { argv.add(1) }; + } + + while unsafe { !(*envp).is_null() } { + let env = unsafe { *envp }; + let len = unsafe { strlen(env) }; + envs.push(unsafe { slice::from_raw_parts(env as *const u8, len) }); + envp = unsafe { envp.add(1) }; + } + + redox_rt::proc::fexec_impl( + FdGuard::new(executable.fd as usize).to_upper().unwrap(), + &child.thr_fd, + &proc_fd, + program.to_bytes(), + args.as_slice(), + envs.as_slice(), + &extra_info, + None, + ) + .map_err(|_| syscall::error::Error::new(syscall::error::ENOEXEC))?; + + Ok(i32::try_from(child.pid).unwrap()) + } + fn symlinkat(path1: CStr, fd: c_int, path2: CStr) -> Result<()> { let mut file = File::createat( fd, From 119f078216feb866427b5e27f7c229776557aa19 Mon Sep 17 00:00:00 2001 From: R Aadarsh Date: Fri, 15 May 2026 16:11:36 +0530 Subject: [PATCH 03/29] * Fix bug that caused pid of the child process to be returned instead of 0 or errorno * Add `same_process` field to not change the address space when `fexec_impl` is called on a different process --- redox-rt/src/proc.rs | 14 ++++++++++---- src/header/spawn/mod.rs | 26 +++++++++++++++++--------- src/platform/redox/exec.rs | 4 +++- src/platform/redox/mod.rs | 32 ++++++++++++++++++++++++++++---- 4 files changed, 58 insertions(+), 18 deletions(-) diff --git a/redox-rt/src/proc.rs b/redox-rt/src/proc.rs index 2682e2443b..0c067af24d 100644 --- a/redox-rt/src/proc.rs +++ b/redox-rt/src/proc.rs @@ -63,6 +63,8 @@ pub struct ExtraInfo<'a> { pub ns_fd: Option, /// CWD handle pub cwd_fd: Option, + /// If the process for which the image is to be loaded the same as the currently running process + pub same_process: bool, } pub fn fexec_impl( @@ -74,7 +76,7 @@ pub fn fexec_impl( envs: &[&[u8]], extrainfo: &ExtraInfo, interp_override: Option, -) -> Result { +) -> Result> { // Here, we do the minimum part of loading an application, which is what the kernel used to do. // We load the executable into memory (albeit at different offsets in this executable), fix // some misalignments, and then switch address space. @@ -235,7 +237,7 @@ pub fn fexec_impl( } if let Some(interpreter_path) = interpreter { - return Ok(FexecResult::Interp { + return Ok(Some(FexecResult::Interp { path: interpreter_path, interp_override: InterpOverride { at_entry: base_addr + header.e_entry as usize, @@ -246,7 +248,7 @@ pub fn fexec_impl( min_mmap_addr, grants_fd: grants_fd.take(), }, - }); + })); } mmap_anon_remote( @@ -495,7 +497,11 @@ pub fn fexec_impl( // Dropping this FD will cause the address space switch. drop(addrspace_selection_fd); - unreachable!(); + if extrainfo.same_process { + unreachable!(); + } else { + Ok(None) + } } fn write_usizes(fd: &FdGuardUpper, usizes: [usize; N]) -> Result { fd.write(unsafe { plain::as_bytes(&usizes) }) diff --git a/src/header/spawn/mod.rs b/src/header/spawn/mod.rs index 2d079f128a..0e66fe9d6a 100644 --- a/src/header/spawn/mod.rs +++ b/src/header/spawn/mod.rs @@ -19,13 +19,14 @@ use crate::{ }; fn spawn( + pid: Option<&mut pid_t>, mut program: &str, file_actions: Option<&posix_spawn_file_actions_t>, spawn_attr: Option<&posix_spawnattr_t>, argv: *const *mut c_char, envp: *const *mut c_char, use_path: bool, -) -> Result { +) -> Result<()> { if use_path { let path_env = unsafe { CStr::from_ptr(getenv("PATH".as_ptr() as *const c_char)) @@ -57,12 +58,17 @@ fn spawn( envp, use_path, ) + .map(|v| { + if let Some(pid) = pid { + *pid = v; + } + }) } } #[unsafe(no_mangle)] pub extern "C" fn posix_spawn( - pid: *const pid_t, + pid: *mut pid_t, program: *const c_char, file_actions: *const posix_spawn_file_actions_t, spawn_attr: *const posix_spawnattr_t, @@ -71,7 +77,8 @@ pub extern "C" fn posix_spawn( ) -> c_int { let program = unsafe { CStr::from_ptr(program).to_str().unwrap() }; - match spawn( + if let Err(e) = spawn( + unsafe { pid.as_mut() }, program, unsafe { file_actions.as_ref() }, unsafe { spawn_attr.as_ref() }, @@ -79,14 +86,14 @@ pub extern "C" fn posix_spawn( envp, false, ) { - Ok(v) => v, - Err(e) => e.0, + return e.0; } + 0 } #[unsafe(no_mangle)] pub extern "C" fn posix_spawnp( - pid: *const pid_t, + pid: *mut pid_t, program: *const c_char, file_actions: *const posix_spawn_file_actions_t, spawn_attr: *const posix_spawnattr_t, @@ -95,7 +102,8 @@ pub extern "C" fn posix_spawnp( ) -> c_int { let program = unsafe { CStr::from_ptr(program).to_str().unwrap() }; - match spawn( + if let Err(e) = spawn( + unsafe { pid.as_mut() }, program, unsafe { file_actions.as_ref() }, unsafe { spawn_attr.as_ref() }, @@ -103,7 +111,7 @@ pub extern "C" fn posix_spawnp( envp, true, ) { - Ok(v) => v, - Err(e) => e.0, + return e.0; } + 0 } diff --git a/src/platform/redox/exec.rs b/src/platform/redox/exec.rs index f269f59234..5235549f90 100644 --- a/src/platform/redox/exec.rs +++ b/src/platform/redox/exec.rs @@ -38,7 +38,8 @@ fn fexec_impl( envs, extrainfo, interp_override, - )?; + )? + .unwrap(); // According to elf(5), PT_INTERP requires that the interpreter path be // null-terminated. Violating this should therefore give the "format error" ENOEXEC. @@ -238,6 +239,7 @@ pub fn execve( cwd_fd: super::path::current_dir() .ok() .map(|fd| fd.as_ref().unwrap().fd.as_raw_fd()), + same_process: true, }; fexec_impl( diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index 549891c9d2..55a0551a56 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -61,7 +61,11 @@ use crate::{ free, sys::timer::{TIMERS, timer_routine, timer_update_wake_time}, }, - sync::rwlock::RwLock, + sync::{ + self, Mutex, + rwlock::RwLock, + sys::timer::{timer_routine, timer_update_wake_time}, + }, }; pub use redox_rt::proc::FdGuard; @@ -1225,6 +1229,7 @@ impl Pal for Sys { cwd_fd: path::current_dir() .ok() .map(|fd| fd.as_ref().unwrap().fd.as_raw_fd()), + same_process: false, }; let mut args = Vec::new(); @@ -1244,7 +1249,10 @@ impl Pal for Sys { envp = unsafe { envp.add(1) }; } - redox_rt::proc::fexec_impl( + if let Some(redox_rt::proc::FexecResult::Interp { + path: interp_path, + interp_override, + }) = redox_rt::proc::fexec_impl( FdGuard::new(executable.fd as usize).to_upper().unwrap(), &child.thr_fd, &proc_fd, @@ -1253,8 +1261,24 @@ impl Pal for Sys { envs.as_slice(), &extra_info, None, - ) - .map_err(|_| syscall::error::Error::new(syscall::error::ENOEXEC))?; + )? { + let interp_path = CStr::from_bytes_with_nul(&interp_path) + .map_err(|_| platform::Errno(syscall::error::ENOEXEC))?; + + let interpreter = File::open(interp_path, fcntl::O_RDONLY | fcntl::O_CLOEXEC) + .map_err(|_| platform::Errno(syscall::error::ENOEXEC))?; + + redox_rt::proc::fexec_impl( + FdGuard::new(interpreter.fd as usize).to_upper().unwrap(), + &child.thr_fd, + &proc_fd, + program.to_bytes(), + args.as_slice(), + envs.as_slice(), + &extra_info, + Some(interp_override), + )?; + } Ok(i32::try_from(child.pid).unwrap()) } From 88185cbd8d49d1ef0500c04c7192d11d919fb2eb Mon Sep 17 00:00:00 2001 From: R Aadarsh Date: Sat, 16 May 2026 08:54:00 +0530 Subject: [PATCH 04/29] Make `posix_spawnp` work --- src/header/spawn/mod.rs | 53 +++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/src/header/spawn/mod.rs b/src/header/spawn/mod.rs index 0e66fe9d6a..2ba437220a 100644 --- a/src/header/spawn/mod.rs +++ b/src/header/spawn/mod.rs @@ -5,13 +5,18 @@ mod file_actions; mod spawn_attr; +use alloc::string::{String, ToString}; pub use file_actions::{Operation, posix_spawn_file_actions_t}; pub use spawn_attr::{Flags, posix_spawnattr_t}; use crate::{ c_str::CStr, error::{Errno, Result}, - header::{errno::ENOENT, stdlib::getenv}, + header::{ + dirent::{opendir, readdir}, + errno::ENOENT, + stdlib::getenv, + }, platform::{ self, Pal, types::{c_char, c_int, pid_t}, @@ -20,7 +25,7 @@ use crate::{ fn spawn( pid: Option<&mut pid_t>, - mut program: &str, + mut program: String, file_actions: Option<&posix_spawn_file_actions_t>, spawn_attr: Option<&posix_spawnattr_t>, argv: *const *mut c_char, @@ -28,25 +33,37 @@ fn spawn( use_path: bool, ) -> Result<()> { if use_path { - let path_env = unsafe { - CStr::from_ptr(getenv("PATH".as_ptr() as *const c_char)) - .to_str() - .unwrap() - }; + let path = unsafe { getenv(c"PATH".as_ptr()) }; + let path_env = unsafe { CStr::from_nullable_ptr(path).unwrap().to_str().unwrap() }; let path_elements = path_env.split(':'); - let program_name = program.split("/").last().unwrap(); let mut flag = false; - for element in path_elements { - if element.split("/").last().unwrap() == program_name { - flag = true; - program = element; - break; - } - if !flag { - return Err(Errno(ENOENT)); + for path_element in path_elements { + let dir = if let Some(dir) = + unsafe { opendir(path_element.as_bytes().as_ptr() as *const c_char).as_mut() } + { + dir + } else { + continue; + }; + + while let Some(dir_ent) = unsafe { readdir(dir).as_ref() } { + let dir_ent_name = unsafe { + CStr::from_ptr(dir_ent.d_name.as_ptr() as *const c_char) + .to_str() + .unwrap() + }; + if dir_ent_name == program { + flag = true; + program = format!("{}/{}", path_element, program); + break; + } } } + + if !flag { + return Err(Errno(ENOENT)); + } } unsafe { @@ -75,7 +92,7 @@ pub extern "C" fn posix_spawn( argv: *const *mut c_char, envp: *const *mut c_char, ) -> c_int { - let program = unsafe { CStr::from_ptr(program).to_str().unwrap() }; + let program = unsafe { CStr::from_ptr(program).to_str().unwrap().to_string() }; if let Err(e) = spawn( unsafe { pid.as_mut() }, @@ -100,7 +117,7 @@ pub extern "C" fn posix_spawnp( argv: *const *mut c_char, envp: *const *mut c_char, ) -> c_int { - let program = unsafe { CStr::from_ptr(program).to_str().unwrap() }; + let program = unsafe { CStr::from_ptr(program).to_str().unwrap().to_string() }; if let Err(e) = spawn( unsafe { pid.as_mut() }, From ad832272258cc60ff33a1395b1cf5b06a924d2a7 Mon Sep 17 00:00:00 2001 From: R Aadarsh Date: Sat, 16 May 2026 10:42:49 +0530 Subject: [PATCH 05/29] Change the `posix_spawn_file_actions_t` struct to use a linked list instead of an array --- src/header/spawn/file_actions.rs | 94 ++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 41 deletions(-) diff --git a/src/header/spawn/file_actions.rs b/src/header/spawn/file_actions.rs index 2d1bcb05ac..69369b4a08 100644 --- a/src/header/spawn/file_actions.rs +++ b/src/header/spawn/file_actions.rs @@ -1,6 +1,6 @@ use core::{ ffi::{c_char, c_int}, - ptr::null, + ptr::{null, null_mut}, }; use crate::{ @@ -8,7 +8,6 @@ use crate::{ header::{ errno::{EBADF, EINVAL, ENOMEM}, stdlib::{free, malloc}, - string::memcpy, }, platform::types::{c_void, mode_t}, }; @@ -33,40 +32,35 @@ pub enum Operation { Dup2(c_int, c_int), } -#[repr(C)] -pub struct posix_spawn_file_actions_t { - size: usize, - operation: *const Operation, +pub struct OperationNode { + operation: Operation, + next: *const OperationNode, } -fn copy_op(file_actions: *mut posix_spawn_file_actions_t, op: Operation) -> Result<()> { - if file_actions.is_null() { - return Err(Errno(EINVAL)); - } +#[repr(C)] +pub struct posix_spawn_file_actions_t { + len: usize, + head: *const OperationNode, + tail: *mut OperationNode, +} - let new = unsafe { malloc((*file_actions).size + size_of::()) }; +fn copy_op(file_actions: &mut posix_spawn_file_actions_t, op: Operation) -> Result<()> { + let new = unsafe { malloc(size_of::()) }; + let new_ref = unsafe { + (new as *const OperationNode) + .as_ref() + .ok_or(Errno(ENOMEM))? + }; - if new == -1isize as *mut c_void { - return Err(Errno(ENOMEM)); - } - - unsafe { - if (*file_actions).size >= size_of::() { - memcpy( - new, - (*file_actions).operation as *const c_void, - (*file_actions).size / size_of::(), - ); - - free((*file_actions).operation as *mut c_void); - } - - (*file_actions).operation = new as *const Operation; - - let new = new as *mut Operation; - - (*new.add((*file_actions).size)) = op; - (*file_actions).size += size_of::() + if (*file_actions).head.is_null() && (*file_actions).tail.is_null() { + (*file_actions).head = new as *const OperationNode; + (*file_actions).tail = new as *mut OperationNode; + (*file_actions).len += 1; + } else { + let tail = unsafe { (*file_actions).tail.as_mut().unwrap() }; + (*tail).next = new as *mut OperationNode; + (*file_actions).tail = new as *mut OperationNode; + (*file_actions).len += 1; } Ok(()) @@ -81,8 +75,9 @@ pub unsafe extern "C" fn posix_spawn_file_actions_init( Err(_) => return EINVAL, }; - (*file_actions).operation = null(); - (*file_actions).size = 0; + (*file_actions).head = null(); + (*file_actions).tail = null_mut(); + (*file_actions).len = 0; 0 } @@ -96,15 +91,32 @@ pub unsafe extern "C" fn posix_spawn_file_actions_destroy( Err(_) => return EINVAL, }; - (*file_actions).operation = null(); - (*file_actions).size = 0; + if (*file_actions).head.is_null() { + assert!((*file_actions).tail.is_null() && (*file_actions).len == 0); + return 0; + } + + let node = unsafe { (*file_actions).head.as_ref().unwrap() }; + + while !(*file_actions).head.is_null() { + let head = (*file_actions).head; + let next = unsafe { (*head).next }; + (*file_actions).head = next; + + unsafe { + free(head as *mut c_void); + } + } + + (*file_actions).tail = null_mut(); + (*file_actions).len = 0; 0 } #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawn_file_actions_addopen( - file_actions: *mut posix_spawn_file_actions_t, + file_actions: &mut posix_spawn_file_actions_t, fd: c_int, path: *const c_char, oflag: c_int, @@ -130,7 +142,7 @@ pub unsafe extern "C" fn posix_spawn_file_actions_addopen( #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawn_file_actions_addclose( - file_actions: *mut posix_spawn_file_actions_t, + file_actions: &mut posix_spawn_file_actions_t, fd: c_int, ) -> c_int { if fd < 0 { @@ -147,7 +159,7 @@ pub unsafe extern "C" fn posix_spawn_file_actions_addclose( #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawn_file_actions_addchdir( - file_actions: *mut posix_spawn_file_actions_t, + file_actions: &mut posix_spawn_file_actions_t, path: *const c_char, ) -> c_int { let chdir_op = Operation::Chdir(path); @@ -161,7 +173,7 @@ pub unsafe extern "C" fn posix_spawn_file_actions_addchdir( #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawn_file_actions_addfchdir( - file_actions: *mut posix_spawn_file_actions_t, + file_actions: &mut posix_spawn_file_actions_t, fd: c_int, ) -> c_int { if fd < 0 { @@ -179,7 +191,7 @@ pub unsafe extern "C" fn posix_spawn_file_actions_addfchdir( #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawn_file_actions_adddup2( - file_actions: *mut posix_spawn_file_actions_t, + file_actions: &mut posix_spawn_file_actions_t, fd: c_int, new: c_int, ) -> c_int { From e3d2257f64bcf058ead7f8d76b91113f086faab9 Mon Sep 17 00:00:00 2001 From: R Aadarsh Date: Sat, 16 May 2026 15:12:34 +0530 Subject: [PATCH 06/29] * Make `posix_spawn_file_actions_t` an iterator * Fix bug that caused the spawned process to not start * Make the spawned process inherit the parent's file descriptos --- redox-rt/src/proc.rs | 2 +- src/header/spawn/file_actions.rs | 28 +++++++++++++++++++++++++++- src/header/spawn/mod.rs | 4 +++- src/platform/redox/mod.rs | 14 +++++++++++++- 4 files changed, 44 insertions(+), 4 deletions(-) diff --git a/redox-rt/src/proc.rs b/redox-rt/src/proc.rs index 0c067af24d..7ae7c7502a 100644 --- a/redox-rt/src/proc.rs +++ b/redox-rt/src/proc.rs @@ -495,9 +495,9 @@ pub fn fexec_impl( } // Dropping this FD will cause the address space switch. - drop(addrspace_selection_fd); if extrainfo.same_process { + drop(addrspace_selection_fd); unreachable!(); } else { Ok(None) diff --git a/src/header/spawn/file_actions.rs b/src/header/spawn/file_actions.rs index 69369b4a08..f8a3add872 100644 --- a/src/header/spawn/file_actions.rs +++ b/src/header/spawn/file_actions.rs @@ -33,7 +33,7 @@ pub enum Operation { } pub struct OperationNode { - operation: Operation, + pub operation: Operation, next: *const OperationNode, } @@ -44,6 +44,32 @@ pub struct posix_spawn_file_actions_t { tail: *mut OperationNode, } +pub struct FileActionsIter<'a> { + curr: Option<&'a OperationNode>, +} + +impl<'a> Iterator for FileActionsIter<'a> { + type Item = &'a OperationNode; + + fn next(&mut self) -> Option { + let curr = self.curr?; + self.curr = unsafe { curr.next.as_ref() }; + Some(curr) + } +} + +impl<'a> IntoIterator for &'a posix_spawn_file_actions_t { + type Item = &'a OperationNode; + + type IntoIter = FileActionsIter<'a>; + + fn into_iter(self) -> Self::IntoIter { + FileActionsIter { + curr: unsafe { self.head.as_ref() }, + } + } +} + fn copy_op(file_actions: &mut posix_spawn_file_actions_t, op: Operation) -> Result<()> { let new = unsafe { malloc(size_of::()) }; let new_ref = unsafe { diff --git a/src/header/spawn/mod.rs b/src/header/spawn/mod.rs index 2ba437220a..ad55f00908 100644 --- a/src/header/spawn/mod.rs +++ b/src/header/spawn/mod.rs @@ -79,8 +79,10 @@ fn spawn( if let Some(pid) = pid { *pid = v; } - }) + })?; } + + Ok(()) } #[unsafe(no_mangle)] diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index 55a0551a56..fb36b17447 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -1209,6 +1209,15 @@ impl Pal for Sys { let executable = File::open(program, fcntl::O_RDONLY)?; let cwd = path::clone_cwd().unwrap(); let proc_fd = child.proc_fd.unwrap(); + let curr_proc_fd = redox_rt::current_proc_fd(); + let file_table = RtTcb::current() + .thread_fd() + .dup(b"filetable")? + .dup(b"copy")?; + + let new_file_table = child.thr_fd.dup(b"current-filetable")?; + + new_file_table.write(&file_table.as_raw_fd().to_ne_bytes())?; let extra_info = redox_rt::proc::ExtraInfo { cwd: Some(cwd.as_bytes()), @@ -1280,7 +1289,10 @@ impl Pal for Sys { )?; } - Ok(i32::try_from(child.pid).unwrap()) + let start_fd = child.thr_fd.dup(b"start")?; + start_fd.write(&[0])?; + + Ok(pid_t::try_from(child.pid).unwrap()) } fn symlinkat(path1: CStr, fd: c_int, path2: CStr) -> Result<()> { From 0e5210cb4dca298ba4bea5bf7308551506f34ac6 Mon Sep 17 00:00:00 2001 From: R Aadarsh Date: Sun, 24 May 2026 14:19:13 +0530 Subject: [PATCH 07/29] Make close operation work --- Cargo.lock | 110 ++++++++++++------------------- Cargo.toml | 3 +- redox-ioctl/Cargo.toml | 3 + src/header/spawn/cbindgen.toml | 4 +- src/header/spawn/file_actions.rs | 33 ++++------ src/platform/redox/mod.rs | 32 ++++++++- 6 files changed, 92 insertions(+), 93 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index aa6e71ad98..a9ce26fefa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16,15 +16,15 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] name = "base64ct" -version = "1.8.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] name = "bcrypt-pbkdf" @@ -39,9 +39,9 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.10.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" [[package]] name = "blake2" @@ -102,9 +102,9 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "chrono" -version = "0.4.42" +version = "0.4.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" dependencies = [ "num-traits", ] @@ -181,9 +181,9 @@ dependencies = [ [[package]] name = "drm-sys" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bafb66c8dbc944d69e15cfcc661df7e703beffbaec8bd63151368b06c5f9858c" +checksum = "ecc8e1361066d91f5ffccff060a3c3be9c3ecde15be2959c1937595f7a82a9f8" dependencies = [ "libc", "linux-raw-sys", @@ -244,15 +244,15 @@ version = "0.1.0" [[package]] name = "libc" -version = "0.2.177" +version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]] name = "libm" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" @@ -268,9 +268,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.6.5" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a385b1be4e5c3e362ad2ffa73c392e53f031eaa5b7d648e64cd87f27f6063d7" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" [[package]] name = "lock_api" @@ -299,9 +299,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.6" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "num-traits" @@ -374,29 +374,29 @@ checksum = "66df580334caab2f744839ab1be85493d7ec731a92d6cf928008ab0b212bf3bc" [[package]] name = "proc-macro2" -version = "1.0.103" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.42" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] [[package]] name = "rand" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8" +checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" dependencies = [ - "rand_core 0.10.0", + "rand_core 0.10.1", ] [[package]] @@ -407,19 +407,19 @@ checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" [[package]] name = "rand_core" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" [[package]] name = "rand_jitter" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a02dd27aa28665e46e60168c8f355240c73b8a344d2557a92318849441ffda33" +checksum = "3fdcd80e68f0a8f9ca5ec7cfd02fd5fbb8fbe6ef4e9b90ea2f48bb929b74f88e" dependencies = [ "libc", - "rand_core 0.10.0", - "winapi", + "rand_core 0.10.1", + "windows-sys", ] [[package]] @@ -428,7 +428,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60aa6af80be32871323012e02e6e65f8a7cc7890931ae421d217ad8fe0df2ccf" dependencies = [ - "rand_core 0.10.0", + "rand_core 0.10.1", ] [[package]] @@ -461,9 +461,8 @@ dependencies = [ [[package]] name = "redox_event" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c07d0d6d291e3a951bd847b1cd4af32fc6243d64116cf7702838c02797688b7" +version = "0.4.6" +source = "git+https://gitlab.redox-os.org/EuclidDivisionLemma/event?branch=spawn#17c4e4c5f0aaf83a2a8057b78ad75364e1f2242a" dependencies = [ "bitflags", "libredox", @@ -473,8 +472,7 @@ dependencies = [ [[package]] name = "redox_syscall" version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c7591fa2c6b601dfcfe5f043f65a1c39fcdf50efefcd7f1572e538c1f4b398d" +source = "git+https://gitlab.redox-os.org/EuclidDivisionLemma/syscall/?branch=spawn#5ae449893d6bc3731ad122d8320372cfbe83c245" dependencies = [ "bitflags", ] @@ -602,9 +600,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "siphasher" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" +checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" [[package]] name = "spin" @@ -623,9 +621,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.110" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -634,15 +632,15 @@ dependencies = [ [[package]] name = "typenum" -version = "1.19.0" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" [[package]] name = "unicode-ident" -version = "1.0.22" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-width" @@ -656,28 +654,6 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - [[package]] name = "windows-sys" version = "0.59.0" diff --git a/Cargo.toml b/Cargo.toml index 24dbc8c66b..8c7a9595d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -121,7 +121,7 @@ sc = "0.2.7" redox_syscall.workspace = true redox-rt = { path = "redox-rt" } redox-path.workspace = true -redox_event = { version = "0.4.7", default-features = false, features = [ +redox_event = { git = "https://gitlab.redox-os.org/EuclidDivisionLemma/event", branch = "spawn", default-features = false, features = [ "redox_syscall", ] } ioslice.workspace = true @@ -145,3 +145,4 @@ panic = "abort" [patch.crates-io] cc-11 = { git = "https://github.com/tea/cc-rs", branch = "riscv-abi-arch-fix", package = "cc" } +redox_syscall = {git = "https://gitlab.redox-os.org/EuclidDivisionLemma/syscall/", branch = "spawn"} diff --git a/redox-ioctl/Cargo.toml b/redox-ioctl/Cargo.toml index 0bf8029cab..8a9c484bad 100644 --- a/redox-ioctl/Cargo.toml +++ b/redox-ioctl/Cargo.toml @@ -10,4 +10,7 @@ description = "Ioctl definitions and (de)serialization for Redox" drm-sys = "0.8.0" redox_syscall = "0.8" +[patch.crates-io] +redox_syscall = {git = "https://gitlab.redox-os.org/EuclidDivisionLemma/syscall/", branch = "spawn"} + [features] diff --git a/src/header/spawn/cbindgen.toml b/src/header/spawn/cbindgen.toml index 0ebe663c2b..fdf8013426 100644 --- a/src/header/spawn/cbindgen.toml +++ b/src/header/spawn/cbindgen.toml @@ -1,4 +1,4 @@ -sys_includes = ["sched.h", "bits/sigset-t.h"] +sys_includes = ["sched.h", "bits/sigset-t.h", "bits/mode-t.h"] include_guard = "_RELIBC_SPAWN_H" language = "C" cpp_compat = true @@ -7,4 +7,4 @@ cpp_compat = true prefix_with_name = true [export.rename] -"sched_param" = "struct sched_param" \ No newline at end of file +"sched_param" = "struct sched_param" diff --git a/src/header/spawn/file_actions.rs b/src/header/spawn/file_actions.rs index f8a3add872..ca2b7322ad 100644 --- a/src/header/spawn/file_actions.rs +++ b/src/header/spawn/file_actions.rs @@ -6,7 +6,7 @@ use core::{ use crate::{ error::{Errno, Result}, header::{ - errno::{EBADF, EINVAL, ENOMEM}, + errno::{EBADF, ENOMEM}, stdlib::{free, malloc}, }, platform::types::{c_void, mode_t}, @@ -19,6 +19,7 @@ const FCHDIR: c_char = 4; const DUP2: c_char = 5; #[repr(C)] +#[derive(Debug, Clone, Copy)] pub enum Operation { Open { fd: c_int, @@ -32,16 +33,18 @@ pub enum Operation { Dup2(c_int, c_int), } +#[derive(Debug, Clone, Copy)] pub struct OperationNode { pub operation: Operation, next: *const OperationNode, } #[repr(C)] +#[derive(Debug)] pub struct posix_spawn_file_actions_t { len: usize, - head: *const OperationNode, - tail: *mut OperationNode, + pub head: *const OperationNode, + pub tail: *mut OperationNode, } pub struct FileActionsIter<'a> { @@ -72,11 +75,11 @@ impl<'a> IntoIterator for &'a posix_spawn_file_actions_t { fn copy_op(file_actions: &mut posix_spawn_file_actions_t, op: Operation) -> Result<()> { let new = unsafe { malloc(size_of::()) }; - let new_ref = unsafe { - (new as *const OperationNode) - .as_ref() - .ok_or(Errno(ENOMEM))? - }; + + let new_ref = unsafe { (new as *mut OperationNode).as_mut().ok_or(Errno(ENOMEM))? }; + + (*new_ref).next = null(); + (*new_ref).operation = op; if (*file_actions).head.is_null() && (*file_actions).tail.is_null() { (*file_actions).head = new as *const OperationNode; @@ -94,13 +97,8 @@ fn copy_op(file_actions: &mut posix_spawn_file_actions_t, op: Operation) -> Resu #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawn_file_actions_init( - file_actions: *mut posix_spawn_file_actions_t, + file_actions: &mut posix_spawn_file_actions_t, ) -> c_int { - let file_actions = match unsafe { file_actions.as_mut().ok_or(Errno(EINVAL)) } { - Ok(v) => v, - Err(_) => return EINVAL, - }; - (*file_actions).head = null(); (*file_actions).tail = null_mut(); (*file_actions).len = 0; @@ -110,13 +108,8 @@ pub unsafe extern "C" fn posix_spawn_file_actions_init( #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawn_file_actions_destroy( - file_actions: *mut posix_spawn_file_actions_t, + file_actions: &mut posix_spawn_file_actions_t, ) -> c_int { - let file_actions = match unsafe { file_actions.as_mut().ok_or(Errno(EINVAL)) } { - Ok(v) => v, - Err(_) => return EINVAL, - }; - if (*file_actions).head.is_null() { assert!((*file_actions).tail.is_null() && (*file_actions).len == 0); return 0; diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index fb36b17447..084fa231e9 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -1215,9 +1215,10 @@ impl Pal for Sys { .dup(b"filetable")? .dup(b"copy")?; - let new_file_table = child.thr_fd.dup(b"current-filetable")?; - - new_file_table.write(&file_table.as_raw_fd().to_ne_bytes())?; + { + let new_file_table = child.thr_fd.dup(b"current-filetable")?; + new_file_table.write(&file_table.as_raw_fd().to_ne_bytes())?; + } let extra_info = redox_rt::proc::ExtraInfo { cwd: Some(cwd.as_bytes()), @@ -1258,6 +1259,31 @@ impl Pal for Sys { envp = unsafe { envp.add(1) }; } + let new_file_table = child.thr_fd.dup(b"filetable")?; + + if let Some(fac) = fac { + for action in fac { + match action.operation { + crate::header::spawn::Operation::Open { + fd, + path, + flag, + mode, + } => todo!(), + crate::header::spawn::Operation::Close(fd) => { + new_file_table.call_wo( + &(fd as usize).to_ne_bytes(), + syscall::CallFlags::empty(), + &[syscall::flag::FileTableVerb::Close as u64], + )?; + } + crate::header::spawn::Operation::Chdir(_) => todo!(), + crate::header::spawn::Operation::FChdir(_) => todo!(), + crate::header::spawn::Operation::Dup2(_, _) => todo!(), + } + } + } + if let Some(redox_rt::proc::FexecResult::Interp { path: interp_path, interp_override, From 0810991d7d022ca0f4d26af6762b78d850828a04 Mon Sep 17 00:00:00 2001 From: R Aadarsh Date: Mon, 25 May 2026 19:58:22 +0530 Subject: [PATCH 08/29] Do the requested sigmask changes and u/g id changes --- redox-rt/src/sys.rs | 13 ++- src/header/spawn/spawn_attr.rs | 162 +++++++++------------------------ src/platform/redox/mod.rs | 123 ++++++++++++++++++------- 3 files changed, 144 insertions(+), 154 deletions(-) diff --git a/redox-rt/src/sys.rs b/redox-rt/src/sys.rs index 190610b5de..1728f1ea62 100644 --- a/redox-rt/src/sys.rs +++ b/redox-rt/src/sys.rs @@ -340,7 +340,7 @@ pub struct Resugid { } /// Sets [res][ug]id, fields that are None will be unchanged. -pub fn posix_setresugid(ids: &Resugid>) -> Result<()> { +pub fn posix_setresugid(ids: &Resugid>, pid: Option) -> Result<()> { // TODO: not sure how "tmp" an IPC call is? let _sig_guard = tmp_disable_signals(); let mut guard = DYNAMIC_PROC_INFO.lock(); @@ -357,7 +357,16 @@ pub fn posix_setresugid(ids: &Resugid>) -> Result<()> { ids.sgid.unwrap_or(u32::MAX), ]); - this_proc_call(&mut buf, CallFlags::empty(), &[ProcCall::SetResugid as u64])?; + if let Some(pid) = pid { + proc_call( + pid, + &mut buf, + CallFlags::empty(), + &[ProcCall::SetResugid as u64], + )?; + } else { + this_proc_call(&mut buf, CallFlags::empty(), &[ProcCall::SetResugid as u64])?; + } if let Some(ruid) = ids.ruid { guard.ruid = ruid; diff --git a/src/header/spawn/spawn_attr.rs b/src/header/spawn/spawn_attr.rs index c109c4f261..ba1cd73546 100644 --- a/src/header/spawn/spawn_attr.rs +++ b/src/header/spawn/spawn_attr.rs @@ -42,71 +42,42 @@ pub struct posix_spawnattr_t { } #[unsafe(no_mangle)] -pub unsafe extern "C" fn posix_spawnattr_init(attr: *mut posix_spawnattr_t) -> c_int { - if attr.is_null() { - return EINVAL; - } - - unsafe { - *attr = zeroed(); - } +pub extern "C" fn posix_spawnattr_init(attr: &mut posix_spawnattr_t) -> c_int { + *attr = unsafe { zeroed() }; 0 } #[unsafe(no_mangle)] -pub unsafe extern "C" fn posix_spawnattr_destroy(attr: *mut posix_spawnattr_t) -> c_int { - if attr.is_null() { - return EINVAL; - } - +pub extern "C" fn posix_spawnattr_destroy(attr: &mut posix_spawnattr_t) -> c_int { + *attr = unsafe { zeroed() }; 0 } #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawnattr_setschedparam( - attr: *mut posix_spawnattr_t, - schedparam: *const sched_param, + attr: &mut posix_spawnattr_t, + schedparam: &sched_param, ) -> c_int { - if attr.is_null() || schedparam.is_null() { - return EINVAL; - } - - unsafe { - (*attr).param = *schedparam; - } - + (*attr).param = *schedparam; 0 } #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawnattr_getschedparam( - attr: *const posix_spawnattr_t, - schedparam: *mut sched_param, + attr: &posix_spawnattr_t, + schedparam: &mut sched_param, ) -> c_int { - if attr.is_null() || schedparam.is_null() { - return EINVAL; - } - - unsafe { - *schedparam = (*attr).param; - } - + *schedparam = (*attr).param; 0 } #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawnattr_setschedpolicy( - attr: *mut posix_spawnattr_t, + attr: &mut posix_spawnattr_t, schedpolicy: c_int, ) -> c_int { - if attr.is_null() { - return EINVAL; - } - match schedpolicy { - SCHED_FIFO | SCHED_RR | SCHED_OTHER => unsafe { - (*attr).policy = schedpolicy; - }, + SCHED_FIFO | SCHED_RR | SCHED_OTHER => (*attr).policy = schedpolicy, _ => return EINVAL, } @@ -115,138 +86,87 @@ pub unsafe extern "C" fn posix_spawnattr_setschedpolicy( #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawnattr_getschedpolicy( - attr: *const posix_spawnattr_t, - schedpolicy: *mut c_int, + attr: &posix_spawnattr_t, + schedpolicy: &mut c_int, ) -> c_int { - if attr.is_null() || schedpolicy.is_null() { - return EINVAL; - } - - unsafe { - *schedpolicy = (*attr).policy; - } + *schedpolicy = (*attr).policy; 0 } #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawnattr_setsigdefault( - attr: *mut posix_spawnattr_t, - sigdefault: *const sigset_t, + attr: &mut posix_spawnattr_t, + sigdefault: &sigset_t, ) -> c_int { - if attr.is_null() || sigdefault.is_null() { - return EINVAL; - } - - unsafe { - (*attr).sigdefault = *sigdefault; - } + (*attr).sigdefault = *sigdefault; 0 } #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawnattr_getsigdefault( - attr: *const posix_spawnattr_t, - sigdefault: *mut sigset_t, + attr: &posix_spawnattr_t, + sigdefault: &mut sigset_t, ) -> c_int { - if attr.is_null() || sigdefault.is_null() { - return EINVAL; - } - - unsafe { - *sigdefault = (*attr).sigdefault; - } + *sigdefault = (*attr).sigdefault; 0 } #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawnattr_setsigmask( - attr: *mut posix_spawnattr_t, - sigmask: *const sigset_t, + attr: &mut posix_spawnattr_t, + sigmask: &sigset_t, ) -> c_int { - if attr.is_null() || sigmask.is_null() { - return EINVAL; - } - - unsafe { - (*attr).sigmask = *sigmask; - } + (*attr).sigmask = *sigmask; 0 } #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawnattr_getsigmask( - attr: *const posix_spawnattr_t, - sigmask: *mut sigset_t, + attr: &posix_spawnattr_t, + sigmask: &mut sigset_t, ) -> c_int { - if attr.is_null() || sigmask.is_null() { - return EINVAL; - } - - unsafe { - *sigmask = (*attr).sigmask; - } + *sigmask = (*attr).sigmask; 0 } #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawnattr_setflags( - attr: *mut posix_spawnattr_t, + attr: &mut posix_spawnattr_t, flags: c_short, ) -> c_int { - if attr.is_null() { - return EINVAL; - } - - unsafe { - match Flags::from_bits(flags) { - Some(v) => (*attr).flags = v.bits(), - None => { - return EINVAL; - } + match Flags::from_bits(flags) { + Some(v) => (*attr).flags = v.bits(), + None => { + return EINVAL; } } + 0 } #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawnattr_getflags( - attr: *const posix_spawnattr_t, - flags: *mut c_short, + attr: &posix_spawnattr_t, + flags: &mut c_short, ) -> c_int { - if attr.is_null() || flags.is_null() { - return EINVAL; - } - - unsafe { *flags = (*attr).flags } + *flags = (*attr).flags; 0 } #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawnattr_setpgroup( - attr: *mut posix_spawnattr_t, + attr: &mut posix_spawnattr_t, pgroup: pid_t, ) -> c_int { - if attr.is_null() { - return EINVAL; - } - - unsafe { - (*attr).pgroup = pgroup; - } + (*attr).pgroup = pgroup; 0 } #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawnattr_getpgroup( - attr: *const posix_spawnattr_t, - pgroup: *mut pid_t, + attr: &posix_spawnattr_t, + pgroup: &mut pid_t, ) -> c_int { - if attr.is_null() || pgroup.is_null() { - return EINVAL; - } - - unsafe { - *pgroup = (*attr).pgroup; - } + *pgroup = (*attr).pgroup; 0 } diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index 084fa231e9..f3368ecb37 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -27,8 +27,8 @@ use crate::{ fs::File, header::{ errno::{ - EBADF, EBADFD, EEXIST, EFAULT, EFBIG, EINTR, EINVAL, EIO, ENAMETOOLONG, ENOENT, ENOMEM, - ENOSYS, EOPNOTSUPP, EPERM, + EBADF, EBADFD, EEXIST, EFAULT, EFBIG, EINTR, EINVAL, EIO, ENAMETOOLONG, ENOENT, + ENOEXEC, ENOMEM, ENOSYS, EOPNOTSUPP, EPERM, }, fcntl::{ self, AT_EACCESS, AT_EMPTY_PATH, AT_FDCWD, AT_REMOVEDIR, AT_SYMLINK_FOLLOW, F_GETLK, @@ -61,11 +61,7 @@ use crate::{ free, sys::timer::{TIMERS, timer_routine, timer_update_wake_time}, }, - sync::{ - self, Mutex, - rwlock::RwLock, - sys::timer::{timer_routine, timer_update_wake_time}, - }, + sync::rwlock::RwLock, }; pub use redox_rt::proc::FdGuard; @@ -1174,26 +1170,32 @@ impl Pal for Sys { } fn setresgid(rgid: gid_t, egid: gid_t, sgid: gid_t) -> Result<()> { - redox_rt::sys::posix_setresugid(&Resugid { - ruid: None, - euid: None, - suid: None, - rgid: cvt_uid(rgid)?, - egid: cvt_uid(egid)?, - sgid: cvt_uid(sgid)?, - })?; + redox_rt::sys::posix_setresugid( + &Resugid { + ruid: None, + euid: None, + suid: None, + rgid: cvt_uid(rgid)?, + egid: cvt_uid(egid)?, + sgid: cvt_uid(sgid)?, + }, + None, + )?; Ok(()) } fn setresuid(ruid: uid_t, euid: uid_t, suid: uid_t) -> Result<()> { - redox_rt::sys::posix_setresugid(&Resugid { - ruid: cvt_uid(ruid)?, - euid: cvt_uid(euid)?, - suid: cvt_uid(suid)?, - rgid: None, - egid: None, - sgid: None, - })?; + redox_rt::sys::posix_setresugid( + &Resugid { + ruid: cvt_uid(ruid)?, + euid: cvt_uid(euid)?, + suid: cvt_uid(suid)?, + rgid: None, + egid: None, + sgid: None, + }, + None, + )?; Ok(()) } @@ -1205,6 +1207,8 @@ impl Pal for Sys { mut envp: *const *mut c_char, use_path: bool, ) -> Result { + use crate::header::spawn::Flags; + let child = redox_rt::proc::new_child_process(&redox_rt::proc::ForkArgs::Managed)?; let executable = File::open(program, fcntl::O_RDONLY)?; let cwd = path::clone_cwd().unwrap(); @@ -1220,13 +1224,13 @@ impl Pal for Sys { new_file_table.write(&file_table.as_raw_fd().to_ne_bytes())?; } - let extra_info = redox_rt::proc::ExtraInfo { + let mut extra_info = redox_rt::proc::ExtraInfo { cwd: Some(cwd.as_bytes()), sigignmask: redox_rt::signal::get_sigignmask_to_inherit(), sigprocmask: if let Some(fat) = fat - && crate::header::spawn::Flags::from_bits(fat.flags) + && Flags::from_bits(fat.flags) .unwrap() - .contains(crate::header::spawn::Flags::POSIX_SPAWN_SETSIGMASK) + .contains(Flags::POSIX_SPAWN_SETSIGMASK) { fat.sigmask } else { @@ -1279,11 +1283,67 @@ impl Pal for Sys { } crate::header::spawn::Operation::Chdir(_) => todo!(), crate::header::spawn::Operation::FChdir(_) => todo!(), - crate::header::spawn::Operation::Dup2(_, _) => todo!(), + crate::header::spawn::Operation::Dup2(old, new) => { + new_file_table.call_wo( + [(old as usize).to_ne_bytes(), (new as usize).to_ne_bytes()] + .into_iter() + .flatten() + .collect::>() + .as_slice(), + syscall::CallFlags::empty(), + &[syscall::flag::FileTableVerb::Dup2 as u64], + )?; + } } } } + if let Some(attr) = fat { + let flags = Flags::from_bits(attr.flags).ok_or(Errno(EINVAL))?; + + if flags.contains(Flags::POSIX_SPAWN_SETPGROUP) { + if attr.pgroup != 0 { + redox_rt::sys::posix_setpgid( + proc_fd.as_raw_fd(), + usize::try_from(attr.pgroup).map_err(|_| Errno(EINVAL))?, + )?; + } else { + redox_rt::sys::posix_setpgid(proc_fd.as_raw_fd(), proc_fd.as_raw_fd())?; + } + } + + if flags.contains(Flags::POSIX_SPAWN_SETSCHEDPARAM) { + todo!() + } + + if flags.contains(Flags::POSIX_SPAWN_RESETIDS) { + let parent_resugid = redox_rt::sys::posix_getresugid(); + + redox_rt::sys::posix_setresugid( + &Resugid { + ruid: None, + euid: Some(parent_resugid.ruid), + suid: None, + rgid: None, + egid: Some(parent_resugid.rgid), + sgid: None, + }, + Some(proc_fd.as_raw_fd()), + )?; + } + + // todo: if set-uid bit is set, euid must be owner id + // todo: if set-gid bit is set, egid is file's gid + + if flags.contains(Flags::POSIX_SPAWN_SETSIGMASK) { + extra_info.sigprocmask = attr.sigmask; + } + + if flags.contains(Flags::POSIX_SPAWN_SETSIGDEF) { + todo!() + } + } + if let Some(redox_rt::proc::FexecResult::Interp { path: interp_path, interp_override, @@ -1297,11 +1357,11 @@ impl Pal for Sys { &extra_info, None, )? { - let interp_path = CStr::from_bytes_with_nul(&interp_path) - .map_err(|_| platform::Errno(syscall::error::ENOEXEC))?; + let interp_path = + CStr::from_bytes_with_nul(&interp_path).map_err(|_| Errno(ENOEXEC))?; let interpreter = File::open(interp_path, fcntl::O_RDONLY | fcntl::O_CLOEXEC) - .map_err(|_| platform::Errno(syscall::error::ENOEXEC))?; + .map_err(|_| Errno(ENOENT))?; redox_rt::proc::fexec_impl( FdGuard::new(interpreter.fd as usize).to_upper().unwrap(), @@ -1312,7 +1372,8 @@ impl Pal for Sys { envs.as_slice(), &extra_info, Some(interp_override), - )?; + ) + .unwrap(); } let start_fd = child.thr_fd.dup(b"start")?; From 4df38b6f0d4fc2c04a472db4d21052957bc19a7a Mon Sep 17 00:00:00 2001 From: R Aadarsh Date: Wed, 27 May 2026 20:22:16 +0530 Subject: [PATCH 09/29] * Implement open operation * Comment out the code for dup2 --- Cargo.lock | 33 +++++++++++++++++++++------------ Cargo.toml | 2 +- redox-ioctl/Cargo.toml | 2 +- src/platform/redox/mod.rs | 29 +++++++++++++++++++---------- 4 files changed, 42 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a9ce26fefa..02f8606189 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -205,9 +205,9 @@ version = "0.1.0" [[package]] name = "goblin" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "983a6aafb3b12d4c41ea78d39e189af4298ce747353945ff5105b54a056e5cd9" +checksum = "0d494b2004fbc8cf419a6d2115488df4e11140f6f4abd877519de1bbd90c5370" dependencies = [ "log", "plain", @@ -263,7 +263,7 @@ dependencies = [ "bitflags", "libc", "plain", - "redox_syscall", + "redox_syscall 0.8.0", ] [[package]] @@ -283,9 +283,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.29" +version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +checksum = "616ec5685824bcc94416c6d4a7a446eea774a31efd7062c8480ba6fd06d7a6e5" [[package]] name = "md-5" @@ -299,9 +299,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.8.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8" [[package]] name = "num-traits" @@ -436,7 +436,7 @@ name = "redox-ioctl" version = "0.1.0" dependencies = [ "drm-sys", - "redox_syscall", + "redox_syscall 0.9.0", ] [[package]] @@ -456,7 +456,7 @@ dependencies = [ "libredox", "plain", "redox-path", - "redox_syscall", + "redox_syscall 0.9.0", ] [[package]] @@ -466,13 +466,22 @@ source = "git+https://gitlab.redox-os.org/EuclidDivisionLemma/event?branch=spawn dependencies = [ "bitflags", "libredox", - "redox_syscall", + "redox_syscall 0.8.0", ] [[package]] name = "redox_syscall" version = "0.8.0" -source = "git+https://gitlab.redox-os.org/EuclidDivisionLemma/syscall/?branch=spawn#5ae449893d6bc3731ad122d8320372cfbe83c245" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c7591fa2c6b601dfcfe5f043f65a1c39fcdf50efefcd7f1572e538c1f4b398d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_syscall" +version = "0.9.0" +source = "git+https://gitlab.redox-os.org/EuclidDivisionLemma/syscall/?branch=spawn#4a768587a071f8c87e915c6b0836d272bed1d56c" dependencies = [ "bitflags", ] @@ -509,7 +518,7 @@ dependencies = [ "redox-path", "redox-rt", "redox_event", - "redox_syscall", + "redox_syscall 0.9.0", "sc", "scrypt", "sha-crypt", diff --git a/Cargo.toml b/Cargo.toml index 8c7a9595d2..2e17acc3d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,7 +69,7 @@ ioslice = { version = "0.6", default-features = false } plain = "0.2" redox-path = "0.3" redox_protocols = { package = "libredox", version = "0.1.17", default-features = false, features = ["protocol"] } -redox_syscall = "0.8.0" +redox_syscall = "0.9.0" [build-dependencies] cc = "1" diff --git a/redox-ioctl/Cargo.toml b/redox-ioctl/Cargo.toml index 8a9c484bad..ec1707f5dc 100644 --- a/redox-ioctl/Cargo.toml +++ b/redox-ioctl/Cargo.toml @@ -8,7 +8,7 @@ description = "Ioctl definitions and (de)serialization for Redox" [dependencies] drm-sys = "0.8.0" -redox_syscall = "0.8" +redox_syscall = "0.9" [patch.crates-io] redox_syscall = {git = "https://gitlab.redox-os.org/EuclidDivisionLemma/syscall/", branch = "spawn"} diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index f3368ecb37..715e1df2f7 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -1273,7 +1273,16 @@ impl Pal for Sys { path, flag, mode, - } => todo!(), + } => { + let src_fd = + Sys::open(unsafe { CStr::from_ptr(path) }, flag, mode)? as usize; + syscall::sendfd( + new_file_table.as_raw_fd(), + src_fd, + 0, + u64::try_from(fd).map_err(|_| Errno(EBADFD))?, + )?; + } crate::header::spawn::Operation::Close(fd) => { new_file_table.call_wo( &(fd as usize).to_ne_bytes(), @@ -1284,15 +1293,15 @@ impl Pal for Sys { crate::header::spawn::Operation::Chdir(_) => todo!(), crate::header::spawn::Operation::FChdir(_) => todo!(), crate::header::spawn::Operation::Dup2(old, new) => { - new_file_table.call_wo( - [(old as usize).to_ne_bytes(), (new as usize).to_ne_bytes()] - .into_iter() - .flatten() - .collect::>() - .as_slice(), - syscall::CallFlags::empty(), - &[syscall::flag::FileTableVerb::Dup2 as u64], - )?; + // new_file_table.call_wo( + // [(old as usize).to_ne_bytes(), (new as usize).to_ne_bytes()] + // .into_iter() + // .flatten() + // .collect::>() + // .as_slice(), + // syscall::CallFlags::empty(), + // &[syscall::flag::FileTableVerb::Dup2 as u64], + // )?; } } } From a6e1b269afc82de429ac17043e31babccb6cb94a Mon Sep 17 00:00:00 2001 From: R Aadarsh Date: Thu, 28 May 2026 12:51:05 +0530 Subject: [PATCH 10/29] * Make dup2 work * Use `CloseCloExec` for closing O_CLOEXEC files --- Cargo.lock | 8 ++++---- redox-rt/src/proc.rs | 2 +- src/platform/redox/mod.rs | 25 ++++++++++++++++--------- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 02f8606189..abedbb6342 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -461,12 +461,12 @@ dependencies = [ [[package]] name = "redox_event" -version = "0.4.6" -source = "git+https://gitlab.redox-os.org/EuclidDivisionLemma/event?branch=spawn#17c4e4c5f0aaf83a2a8057b78ad75364e1f2242a" +version = "0.4.7" +source = "git+https://gitlab.redox-os.org/EuclidDivisionLemma/event?branch=spawn#48847ea51f9d06c8e2fc7ba3441343d12944e482" dependencies = [ "bitflags", "libredox", - "redox_syscall 0.8.0", + "redox_syscall 0.9.0", ] [[package]] @@ -481,7 +481,7 @@ dependencies = [ [[package]] name = "redox_syscall" version = "0.9.0" -source = "git+https://gitlab.redox-os.org/EuclidDivisionLemma/syscall/?branch=spawn#4a768587a071f8c87e915c6b0836d272bed1d56c" +source = "git+https://gitlab.redox-os.org/EuclidDivisionLemma/syscall/?branch=spawn#d28cf36f5a6684fcbf8be449af55e12d0024d503" dependencies = [ "bitflags", ] diff --git a/redox-rt/src/proc.rs b/redox-rt/src/proc.rs index 7ae7c7502a..f11cf5a4c1 100644 --- a/redox-rt/src/proc.rs +++ b/redox-rt/src/proc.rs @@ -464,7 +464,7 @@ pub fn fexec_impl( )); // Close all O_CLOEXEC file descriptors. TODO: close_range? - { + if extrainfo.same_process { // NOTE: This approach of implementing O_CLOEXEC will not work in multithreaded // scenarios. While execve() is undefined according to POSIX if there exist sibling // threads, it could still be allowed by keeping certain file descriptors and instead diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index 715e1df2f7..09b84dd611 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -1282,6 +1282,7 @@ impl Pal for Sys { 0, u64::try_from(fd).map_err(|_| Errno(EBADFD))?, )?; + Sys::close(src_fd as i32)?; } crate::header::spawn::Operation::Close(fd) => { new_file_table.call_wo( @@ -1293,18 +1294,24 @@ impl Pal for Sys { crate::header::spawn::Operation::Chdir(_) => todo!(), crate::header::spawn::Operation::FChdir(_) => todo!(), crate::header::spawn::Operation::Dup2(old, new) => { - // new_file_table.call_wo( - // [(old as usize).to_ne_bytes(), (new as usize).to_ne_bytes()] - // .into_iter() - // .flatten() - // .collect::>() - // .as_slice(), - // syscall::CallFlags::empty(), - // &[syscall::flag::FileTableVerb::Dup2 as u64], - // )?; + new_file_table.call_wo( + [(old as usize).to_ne_bytes(), (new as usize).to_ne_bytes()] + .into_iter() + .flatten() + .collect::>() + .as_slice(), + syscall::CallFlags::empty(), + &[syscall::flag::FileTableVerb::Dup2 as u64], + )?; } } } + + new_file_table.call_wo( + &[], + syscall::CallFlags::empty(), + &[syscall::flag::FileTableVerb::CloseCloExec as u64], + )?; } if let Some(attr) = fat { From db5eeb7c204931f8b2da55ca070eeadb24bfb4d8 Mon Sep 17 00:00:00 2001 From: R Aadarsh Date: Thu, 28 May 2026 14:12:53 +0530 Subject: [PATCH 11/29] Remove call to `close`, instead make the kernel remove the file --- src/platform/redox/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index 09b84dd611..92614ac0e7 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -1282,7 +1282,7 @@ impl Pal for Sys { 0, u64::try_from(fd).map_err(|_| Errno(EBADFD))?, )?; - Sys::close(src_fd as i32)?; + core::mem::forget(src_fd); } crate::header::spawn::Operation::Close(fd) => { new_file_table.call_wo( From 38af072426060287d784cf9bdfa807b87191e5aa Mon Sep 17 00:00:00 2001 From: R Aadarsh Date: Thu, 28 May 2026 17:10:54 +0530 Subject: [PATCH 12/29] Implement chdir and fchdir operations --- src/platform/redox/mod.rs | 75 ++++++++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 29 deletions(-) diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index 92614ac0e7..890cbddec5 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -22,19 +22,20 @@ use self::{ }; use super::{Pal, Read, types::*}; use crate::{ + alloc::string::ToString, c_str::{CStr, CString}, error::{Errno, Result}, fs::File, header::{ errno::{ EBADF, EBADFD, EEXIST, EFAULT, EFBIG, EINTR, EINVAL, EIO, ENAMETOOLONG, ENOENT, - ENOEXEC, ENOMEM, ENOSYS, EOPNOTSUPP, EPERM, + ENOEXEC, ENOMEM, ENOSYS, ENOTDIR, EOPNOTSUPP, EPERM, }, fcntl::{ self, AT_EACCESS, AT_EMPTY_PATH, AT_FDCWD, AT_REMOVEDIR, AT_SYMLINK_FOLLOW, F_GETLK, F_OFD_GETLK, F_OFD_SETLK, F_RDLCK, F_SETLK, F_SETLKW, F_UNLCK, F_WRLCK, flock, }, - limits, + limits::{self, NAME_MAX}, pthread::{pthread_cancel, pthread_create}, signal::{NSIG, SIGEV_NONE, SIGEV_SIGNAL, SIGEV_THREAD, SIGRTMIN, sigevent}, stdio::RENAME_NOREPLACE, @@ -45,7 +46,7 @@ use crate::{ sys_random, sys_resource::{RLIM_INFINITY, rlimit, rusage}, sys_select::timeval, - sys_stat::{S_ISVTX, stat}, + sys_stat::{self, S_ISVTX, stat}, sys_statvfs::statvfs, sys_time::timezone, sys_utsname::{UTSLENGTH, utsname}, @@ -1211,7 +1212,9 @@ impl Pal for Sys { let child = redox_rt::proc::new_child_process(&redox_rt::proc::ForkArgs::Managed)?; let executable = File::open(program, fcntl::O_RDONLY)?; - let cwd = path::clone_cwd().unwrap(); + let original_cwd = path::clone_cwd().unwrap().to_string(); + let mut cwd = original_cwd.clone(); + cwd.reserve_exact(NAME_MAX - cwd.len()); let proc_fd = child.proc_fd.unwrap(); let curr_proc_fd = redox_rt::current_proc_fd(); let file_table = RtTcb::current() @@ -1224,28 +1227,6 @@ impl Pal for Sys { new_file_table.write(&file_table.as_raw_fd().to_ne_bytes())?; } - let mut extra_info = redox_rt::proc::ExtraInfo { - cwd: Some(cwd.as_bytes()), - sigignmask: redox_rt::signal::get_sigignmask_to_inherit(), - sigprocmask: if let Some(fat) = fat - && Flags::from_bits(fat.flags) - .unwrap() - .contains(Flags::POSIX_SPAWN_SETSIGMASK) - { - fat.sigmask - } else { - redox_rt::signal::get_sigmask().unwrap() - }, - umask: redox_rt::sys::get_umask(), - thr_fd: child.thr_fd.as_raw_fd(), - proc_fd: proc_fd.as_raw_fd(), - ns_fd: redox_rt::current_namespace_fd().ok(), - cwd_fd: path::current_dir() - .ok() - .map(|fd| fd.as_ref().unwrap().fd.as_raw_fd()), - same_process: false, - }; - let mut args = Vec::new(); let mut envs = Vec::new(); @@ -1282,7 +1263,6 @@ impl Pal for Sys { 0, u64::try_from(fd).map_err(|_| Errno(EBADFD))?, )?; - core::mem::forget(src_fd); } crate::header::spawn::Operation::Close(fd) => { new_file_table.call_wo( @@ -1291,8 +1271,21 @@ impl Pal for Sys { &[syscall::flag::FileTableVerb::Close as u64], )?; } - crate::header::spawn::Operation::Chdir(_) => todo!(), - crate::header::spawn::Operation::FChdir(_) => todo!(), + crate::header::spawn::Operation::Chdir(path) => { + let path = unsafe { CStr::from_ptr(path) }; + let mut stat = sys_stat::stat::default(); + let fd = Sys::stat(path, Out::from_mut(&mut stat))?; + + if sys_stat::S_IFDIR & sys_stat::S_IFMT != sys_stat::S_IFDIR { + return Err(Errno(ENOTDIR)); + } + cwd = path.to_str().unwrap().to_string(); + path::chdir(cwd.as_str())?; + } + crate::header::spawn::Operation::FChdir(fd) => { + path::fchdir(fd)?; + path::getcwd(Out::from_mut(unsafe { cwd.as_bytes_mut() }))?; + } crate::header::spawn::Operation::Dup2(old, new) => { new_file_table.call_wo( [(old as usize).to_ne_bytes(), (new as usize).to_ne_bytes()] @@ -1314,6 +1307,28 @@ impl Pal for Sys { )?; } + let mut extra_info = redox_rt::proc::ExtraInfo { + cwd: Some(cwd.as_bytes()), + sigignmask: redox_rt::signal::get_sigignmask_to_inherit(), + sigprocmask: if let Some(fat) = fat + && Flags::from_bits(fat.flags) + .unwrap() + .contains(Flags::POSIX_SPAWN_SETSIGMASK) + { + fat.sigmask + } else { + redox_rt::signal::get_sigmask().unwrap() + }, + umask: redox_rt::sys::get_umask(), + thr_fd: child.thr_fd.as_raw_fd(), + proc_fd: proc_fd.as_raw_fd(), + ns_fd: redox_rt::current_namespace_fd().ok(), + cwd_fd: path::current_dir() + .ok() + .map(|fd| fd.as_ref().unwrap().fd.as_raw_fd()), + same_process: false, + }; + if let Some(attr) = fat { let flags = Flags::from_bits(attr.flags).ok_or(Errno(EINVAL))?; @@ -1392,6 +1407,8 @@ impl Pal for Sys { .unwrap(); } + path::chdir(original_cwd.as_str())?; + let start_fd = child.thr_fd.dup(b"start")?; start_fd.write(&[0])?; From 2df7484e6c5e4cef94d9d674ab5509c8c8cb4a03 Mon Sep 17 00:00:00 2001 From: R Aadarsh Date: Thu, 28 May 2026 17:17:57 +0530 Subject: [PATCH 13/29] * Make `posix_spawnp` consider the `program` argument as a path if it contains a slash * Remove existence and file type check * Make envp optional * Ensure that the CWD of the calling process is same before and after spawning --- Cargo.lock | 41 +++++++++++++------------------- Cargo.toml | 2 +- redox-ioctl/Cargo.toml | 2 +- src/header/spawn/mod.rs | 33 ++++++++++++++++---------- src/platform/pal/mod.rs | 2 +- src/platform/redox/mod.rs | 50 ++++++++++++++++++++++----------------- 6 files changed, 67 insertions(+), 63 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index abedbb6342..7808523537 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -39,9 +39,9 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.11.1" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" +checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" [[package]] name = "blake2" @@ -102,9 +102,9 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "chrono" -version = "0.4.44" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" dependencies = [ "num-traits", ] @@ -205,9 +205,9 @@ version = "0.1.0" [[package]] name = "goblin" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d494b2004fbc8cf419a6d2115488df4e11140f6f4abd877519de1bbd90c5370" +checksum = "17582616a7718cca54cec18e534a76c7c4aec11a8b9a85695712f262fd15a4c8" dependencies = [ "log", "plain", @@ -263,7 +263,7 @@ dependencies = [ "bitflags", "libc", "plain", - "redox_syscall 0.8.0", + "redox_syscall", ] [[package]] @@ -283,9 +283,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.30" +version = "0.4.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616ec5685824bcc94416c6d4a7a446eea774a31efd7062c8480ba6fd06d7a6e5" +checksum = "953f07c43838f8e6f9758cab68bf5bed85465e7587ebe0b823f1bcd81978ad3a" [[package]] name = "md-5" @@ -436,7 +436,7 @@ name = "redox-ioctl" version = "0.1.0" dependencies = [ "drm-sys", - "redox_syscall 0.9.0", + "redox_syscall", ] [[package]] @@ -456,32 +456,23 @@ dependencies = [ "libredox", "plain", "redox-path", - "redox_syscall 0.9.0", + "redox_syscall", ] [[package]] name = "redox_event" version = "0.4.7" -source = "git+https://gitlab.redox-os.org/EuclidDivisionLemma/event?branch=spawn#48847ea51f9d06c8e2fc7ba3441343d12944e482" +source = "git+https://gitlab.redox-os.org/EuclidDivisionLemma/event?branch=spawn#9126b9b1166e4633877feacf109720481e814e2e" dependencies = [ "bitflags", "libredox", - "redox_syscall 0.9.0", + "redox_syscall", ] [[package]] name = "redox_syscall" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c7591fa2c6b601dfcfe5f043f65a1c39fcdf50efefcd7f1572e538c1f4b398d" -dependencies = [ - "bitflags", -] - -[[package]] -name = "redox_syscall" -version = "0.9.0" -source = "git+https://gitlab.redox-os.org/EuclidDivisionLemma/syscall/?branch=spawn#d28cf36f5a6684fcbf8be449af55e12d0024d503" +version = "0.8.1" +source = "git+https://gitlab.redox-os.org/EuclidDivisionLemma/syscall/?branch=spawn#2708fc84ac7347d16408e8b73f62ec7656f0bc25" dependencies = [ "bitflags", ] @@ -518,7 +509,7 @@ dependencies = [ "redox-path", "redox-rt", "redox_event", - "redox_syscall 0.9.0", + "redox_syscall", "sc", "scrypt", "sha-crypt", diff --git a/Cargo.toml b/Cargo.toml index 2e17acc3d9..07fc1f68aa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,7 +69,7 @@ ioslice = { version = "0.6", default-features = false } plain = "0.2" redox-path = "0.3" redox_protocols = { package = "libredox", version = "0.1.17", default-features = false, features = ["protocol"] } -redox_syscall = "0.9.0" +redox_syscall = "0.8.1" [build-dependencies] cc = "1" diff --git a/redox-ioctl/Cargo.toml b/redox-ioctl/Cargo.toml index ec1707f5dc..88778d300c 100644 --- a/redox-ioctl/Cargo.toml +++ b/redox-ioctl/Cargo.toml @@ -8,7 +8,7 @@ description = "Ioctl definitions and (de)serialization for Redox" [dependencies] drm-sys = "0.8.0" -redox_syscall = "0.9" +redox_syscall = "0.8.1" [patch.crates-io] redox_syscall = {git = "https://gitlab.redox-os.org/EuclidDivisionLemma/syscall/", branch = "spawn"} diff --git a/src/header/spawn/mod.rs b/src/header/spawn/mod.rs index ad55f00908..c22bbf9c19 100644 --- a/src/header/spawn/mod.rs +++ b/src/header/spawn/mod.rs @@ -19,6 +19,7 @@ use crate::{ }, platform::{ self, Pal, + sys::path, types::{c_char, c_int, pid_t}, }, }; @@ -29,9 +30,11 @@ fn spawn( file_actions: Option<&posix_spawn_file_actions_t>, spawn_attr: Option<&posix_spawnattr_t>, argv: *const *mut c_char, - envp: *const *mut c_char, + envp: Option<*const *mut c_char>, use_path: bool, ) -> Result<()> { + let original_cwd = path::clone_cwd().unwrap().to_string(); + if use_path { let path = unsafe { getenv(c"PATH".as_ptr()) }; let path_env = unsafe { CStr::from_nullable_ptr(path).unwrap().to_str().unwrap() }; @@ -79,6 +82,10 @@ fn spawn( if let Some(pid) = pid { *pid = v; } + }) + .map_err(|e| { + path::chdir(original_cwd.as_str()).unwrap(); + e })?; } @@ -88,21 +95,21 @@ fn spawn( #[unsafe(no_mangle)] pub extern "C" fn posix_spawn( pid: *mut pid_t, - program: *const c_char, + path: *const c_char, file_actions: *const posix_spawn_file_actions_t, - spawn_attr: *const posix_spawnattr_t, + attrp: *const posix_spawnattr_t, argv: *const *mut c_char, envp: *const *mut c_char, ) -> c_int { - let program = unsafe { CStr::from_ptr(program).to_str().unwrap().to_string() }; + let program = unsafe { CStr::from_ptr(path).to_str().unwrap().to_string() }; if let Err(e) = spawn( unsafe { pid.as_mut() }, program, unsafe { file_actions.as_ref() }, - unsafe { spawn_attr.as_ref() }, + unsafe { attrp.as_ref() }, argv, - envp, + if envp.is_null() { None } else { Some(envp) }, false, ) { return e.0; @@ -113,22 +120,22 @@ pub extern "C" fn posix_spawn( #[unsafe(no_mangle)] pub extern "C" fn posix_spawnp( pid: *mut pid_t, - program: *const c_char, + path: *const c_char, file_actions: *const posix_spawn_file_actions_t, - spawn_attr: *const posix_spawnattr_t, + attrp: *const posix_spawnattr_t, argv: *const *mut c_char, envp: *const *mut c_char, ) -> c_int { - let program = unsafe { CStr::from_ptr(program).to_str().unwrap().to_string() }; + let program = unsafe { CStr::from_ptr(path).to_str().unwrap().to_string() }; if let Err(e) = spawn( unsafe { pid.as_mut() }, - program, + program.clone(), unsafe { file_actions.as_ref() }, - unsafe { spawn_attr.as_ref() }, + unsafe { attrp.as_ref() }, argv, - envp, - true, + if envp.is_null() { None } else { Some(envp) }, + if program.contains('/') { false } else { true }, ) { return e.0; } diff --git a/src/platform/pal/mod.rs b/src/platform/pal/mod.rs index a6c7be22dc..83e380610e 100644 --- a/src/platform/pal/mod.rs +++ b/src/platform/pal/mod.rs @@ -438,7 +438,7 @@ pub trait Pal { fac: Option<&crate::header::spawn::posix_spawn_file_actions_t>, fat: Option<&crate::header::spawn::posix_spawnattr_t>, argv: *const *mut c_char, - envp: *const *mut c_char, + envp: Option<*const *mut c_char>, use_path: bool, ) -> Result; diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index 890cbddec5..42fa6d690b 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -1,3 +1,4 @@ +use alloc::string::String; use core::{ convert::TryFrom, mem::{self, size_of}, @@ -29,13 +30,13 @@ use crate::{ header::{ errno::{ EBADF, EBADFD, EEXIST, EFAULT, EFBIG, EINTR, EINVAL, EIO, ENAMETOOLONG, ENOENT, - ENOEXEC, ENOMEM, ENOSYS, ENOTDIR, EOPNOTSUPP, EPERM, + ENOEXEC, ENOMEM, ENOSYS, EOPNOTSUPP, EPERM, }, fcntl::{ self, AT_EACCESS, AT_EMPTY_PATH, AT_FDCWD, AT_REMOVEDIR, AT_SYMLINK_FOLLOW, F_GETLK, F_OFD_GETLK, F_OFD_SETLK, F_RDLCK, F_SETLK, F_SETLKW, F_UNLCK, F_WRLCK, flock, }, - limits::{self, NAME_MAX}, + limits::{self}, pthread::{pthread_cancel, pthread_create}, signal::{NSIG, SIGEV_NONE, SIGEV_SIGNAL, SIGEV_THREAD, SIGRTMIN, sigevent}, stdio::RENAME_NOREPLACE, @@ -46,7 +47,7 @@ use crate::{ sys_random, sys_resource::{RLIM_INFINITY, rlimit, rusage}, sys_select::timeval, - sys_stat::{self, S_ISVTX, stat}, + sys_stat::{S_ISVTX, stat}, sys_statvfs::statvfs, sys_time::timezone, sys_utsname::{UTSLENGTH, utsname}, @@ -1205,7 +1206,7 @@ impl Pal for Sys { fac: Option<&crate::header::spawn::posix_spawn_file_actions_t>, fat: Option<&crate::header::spawn::posix_spawnattr_t>, mut argv: *const *mut c_char, - mut envp: *const *mut c_char, + envp: Option<*const *mut c_char>, use_path: bool, ) -> Result { use crate::header::spawn::Flags; @@ -1214,7 +1215,6 @@ impl Pal for Sys { let executable = File::open(program, fcntl::O_RDONLY)?; let original_cwd = path::clone_cwd().unwrap().to_string(); let mut cwd = original_cwd.clone(); - cwd.reserve_exact(NAME_MAX - cwd.len()); let proc_fd = child.proc_fd.unwrap(); let curr_proc_fd = redox_rt::current_proc_fd(); let file_table = RtTcb::current() @@ -1230,6 +1230,15 @@ impl Pal for Sys { let mut args = Vec::new(); let mut envs = Vec::new(); + let len = unsafe { strlen(*argv) }; + let program_name = + str::from_utf8(unsafe { slice::from_raw_parts(*argv as *const u8, len) }).unwrap(); + let program_name: String = + redox_path::canonicalize_using_cwd(Some(original_cwd.as_str()), program_name) + .ok_or(Errno(ENOENT))?; + argv = unsafe { argv.add(1) }; + args.push(program_name.as_bytes()); + while unsafe { !(*argv).is_null() } { let arg = unsafe { *argv }; let len = unsafe { strlen(arg) }; @@ -1237,11 +1246,13 @@ impl Pal for Sys { argv = unsafe { argv.add(1) }; } - while unsafe { !(*envp).is_null() } { - let env = unsafe { *envp }; - let len = unsafe { strlen(env) }; - envs.push(unsafe { slice::from_raw_parts(env as *const u8, len) }); - envp = unsafe { envp.add(1) }; + if let Some(mut envp) = envp { + while unsafe { !(*envp).is_null() } { + let env = unsafe { *envp }; + let len = unsafe { strlen(env) }; + envs.push(unsafe { slice::from_raw_parts(env as *const u8, len) }); + envp = unsafe { envp.add(1) }; + } } let new_file_table = child.thr_fd.dup(b"filetable")?; @@ -1273,13 +1284,8 @@ impl Pal for Sys { } crate::header::spawn::Operation::Chdir(path) => { let path = unsafe { CStr::from_ptr(path) }; - let mut stat = sys_stat::stat::default(); - let fd = Sys::stat(path, Out::from_mut(&mut stat))?; - - if sys_stat::S_IFDIR & sys_stat::S_IFMT != sys_stat::S_IFDIR { - return Err(Errno(ENOTDIR)); - } cwd = path.to_str().unwrap().to_string(); + path::chdir(cwd.as_str())?; } crate::header::spawn::Operation::FChdir(fd) => { @@ -1299,14 +1305,14 @@ impl Pal for Sys { } } } - - new_file_table.call_wo( - &[], - syscall::CallFlags::empty(), - &[syscall::flag::FileTableVerb::CloseCloExec as u64], - )?; } + new_file_table.call_wo( + &[], + syscall::CallFlags::empty(), + &[syscall::flag::FileTableVerb::CloseCloExec as u64], + )?; + let mut extra_info = redox_rt::proc::ExtraInfo { cwd: Some(cwd.as_bytes()), sigignmask: redox_rt::signal::get_sigignmask_to_inherit(), From 91933b41652187321d49cf1e7762a3a86a41f122 Mon Sep 17 00:00:00 2001 From: R Aadarsh Date: Tue, 2 Jun 2026 18:22:36 +0530 Subject: [PATCH 14/29] * Change `Operation` to `Action` * Change the linked list to a `Vec` * Make functions unsafe --- src/header/spawn/file_actions.rs | 165 +++++++++++-------------------- src/header/spawn/mod.rs | 48 ++++----- src/platform/redox/mod.rs | 12 +-- 3 files changed, 88 insertions(+), 137 deletions(-) diff --git a/src/header/spawn/file_actions.rs b/src/header/spawn/file_actions.rs index ca2b7322ad..0c8ecaec8d 100644 --- a/src/header/spawn/file_actions.rs +++ b/src/header/spawn/file_actions.rs @@ -1,16 +1,12 @@ use core::{ ffi::{c_char, c_int}, - ptr::{null, null_mut}, + mem::ManuallyDrop, + ptr::null_mut, }; -use crate::{ - error::{Errno, Result}, - header::{ - errno::{EBADF, ENOMEM}, - stdlib::{free, malloc}, - }, - platform::types::{c_void, mode_t}, -}; +use alloc::vec::Vec; + +use crate::{header::errno::EBADF, platform::types::mode_t}; const OPEN: c_char = 1; const CLOSE: c_char = 2; @@ -20,7 +16,7 @@ const DUP2: c_char = 5; #[repr(C)] #[derive(Debug, Clone, Copy)] -pub enum Operation { +pub enum Action { Open { fd: c_int, path: *const c_char, @@ -33,76 +29,64 @@ pub enum Operation { Dup2(c_int, c_int), } -#[derive(Debug, Clone, Copy)] -pub struct OperationNode { - pub operation: Operation, - next: *const OperationNode, -} - #[repr(C)] -#[derive(Debug)] +#[derive(Debug, Clone, Copy)] pub struct posix_spawn_file_actions_t { - len: usize, - pub head: *const OperationNode, - pub tail: *mut OperationNode, + file_actions: *mut Action, + length: usize, + capacity: usize, } -pub struct FileActionsIter<'a> { - curr: Option<&'a OperationNode>, +impl posix_spawn_file_actions_t { + pub fn add_action(&mut self, action: Action) { + let v = unsafe { &mut Vec::from_raw_parts(self.file_actions, self.length, self.capacity) }; + v.push(action); + } } -impl<'a> Iterator for FileActionsIter<'a> { - type Item = &'a OperationNode; +pub struct FileActionsIter { + actions: posix_spawn_file_actions_t, + curr: usize, +} + +impl Iterator for FileActionsIter { + type Item = Action; fn next(&mut self) -> Option { - let curr = self.curr?; - self.curr = unsafe { curr.next.as_ref() }; - Some(curr) + let actions = unsafe { + &Vec::from_raw_parts( + self.actions.file_actions, + self.actions.length, + self.actions.capacity, + ) + }; + let e = actions.get(self.curr)?; + self.curr += 1; + Some(*e) } } impl<'a> IntoIterator for &'a posix_spawn_file_actions_t { - type Item = &'a OperationNode; + type Item = Action; - type IntoIter = FileActionsIter<'a>; + type IntoIter = FileActionsIter; fn into_iter(self) -> Self::IntoIter { FileActionsIter { - curr: unsafe { self.head.as_ref() }, + actions: *self, + curr: 0, } } } -fn copy_op(file_actions: &mut posix_spawn_file_actions_t, op: Operation) -> Result<()> { - let new = unsafe { malloc(size_of::()) }; - - let new_ref = unsafe { (new as *mut OperationNode).as_mut().ok_or(Errno(ENOMEM))? }; - - (*new_ref).next = null(); - (*new_ref).operation = op; - - if (*file_actions).head.is_null() && (*file_actions).tail.is_null() { - (*file_actions).head = new as *const OperationNode; - (*file_actions).tail = new as *mut OperationNode; - (*file_actions).len += 1; - } else { - let tail = unsafe { (*file_actions).tail.as_mut().unwrap() }; - (*tail).next = new as *mut OperationNode; - (*file_actions).tail = new as *mut OperationNode; - (*file_actions).len += 1; - } - - Ok(()) -} - #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawn_file_actions_init( file_actions: &mut posix_spawn_file_actions_t, ) -> c_int { - (*file_actions).head = null(); - (*file_actions).tail = null_mut(); - (*file_actions).len = 0; - + let mut v = ManuallyDrop::new(Vec::new()); + file_actions.file_actions = v.as_mut_ptr(); + file_actions.capacity = v.capacity(); + file_actions.length = 0; 0 } @@ -110,25 +94,16 @@ pub unsafe extern "C" fn posix_spawn_file_actions_init( pub unsafe extern "C" fn posix_spawn_file_actions_destroy( file_actions: &mut posix_spawn_file_actions_t, ) -> c_int { - if (*file_actions).head.is_null() { - assert!((*file_actions).tail.is_null() && (*file_actions).len == 0); - return 0; - } - - let node = unsafe { (*file_actions).head.as_ref().unwrap() }; - - while !(*file_actions).head.is_null() { - let head = (*file_actions).head; - let next = unsafe { (*head).next }; - (*file_actions).head = next; - - unsafe { - free(head as *mut c_void); - } - } - - (*file_actions).tail = null_mut(); - (*file_actions).len = 0; + let v = unsafe { + &Vec::from_raw_parts( + file_actions.file_actions, + file_actions.length, + file_actions.capacity, + ) + }; + file_actions.capacity = 0; + file_actions.length = 0; + file_actions.file_actions = null_mut(); 0 } @@ -144,18 +119,12 @@ pub unsafe extern "C" fn posix_spawn_file_actions_addopen( if fd < 0 { return EBADF; } - - let open_op = Operation::Open { + file_actions.add_action(Action::Open { fd, path, flag: oflag, mode, - }; - - if let Err(e) = copy_op(file_actions, open_op) { - return e.0; - } - + }); 0 } @@ -167,12 +136,7 @@ pub unsafe extern "C" fn posix_spawn_file_actions_addclose( if fd < 0 { return EBADF; } - - let close_op = Operation::Close(fd); - - if let Err(e) = copy_op(file_actions, close_op) { - return e.0; - } + file_actions.add_action(Action::Close(fd)); 0 } @@ -181,12 +145,7 @@ pub unsafe extern "C" fn posix_spawn_file_actions_addchdir( file_actions: &mut posix_spawn_file_actions_t, path: *const c_char, ) -> c_int { - let chdir_op = Operation::Chdir(path); - - if let Err(e) = copy_op(file_actions, chdir_op) { - return e.0; - } - + file_actions.add_action(Action::Chdir(path)); 0 } @@ -198,13 +157,7 @@ pub unsafe extern "C" fn posix_spawn_file_actions_addfchdir( if fd < 0 { return EBADF; } - - let fchdir_op = Operation::FChdir(fd); - - if let Err(e) = copy_op(file_actions, fchdir_op) { - return e.0; - } - + file_actions.add_action(Action::FChdir(fd)); 0 } @@ -217,12 +170,6 @@ pub unsafe extern "C" fn posix_spawn_file_actions_adddup2( if fd < 0 || new < 0 { return EBADF; } - - let dup2_op = Operation::Dup2(fd, new); - - if let Err(e) = copy_op(file_actions, dup2_op) { - return e.0; - } - + file_actions.add_action(Action::Dup2(fd, new)); 0 } diff --git a/src/header/spawn/mod.rs b/src/header/spawn/mod.rs index c22bbf9c19..83d6674efb 100644 --- a/src/header/spawn/mod.rs +++ b/src/header/spawn/mod.rs @@ -6,7 +6,7 @@ mod file_actions; mod spawn_attr; use alloc::string::{String, ToString}; -pub use file_actions::{Operation, posix_spawn_file_actions_t}; +pub use file_actions::{Action, posix_spawn_file_actions_t}; pub use spawn_attr::{Flags, posix_spawnattr_t}; use crate::{ @@ -24,7 +24,7 @@ use crate::{ }, }; -fn spawn( +unsafe fn spawn( pid: Option<&mut pid_t>, mut program: String, file_actions: Option<&posix_spawn_file_actions_t>, @@ -93,7 +93,7 @@ fn spawn( } #[unsafe(no_mangle)] -pub extern "C" fn posix_spawn( +pub unsafe extern "C" fn posix_spawn( pid: *mut pid_t, path: *const c_char, file_actions: *const posix_spawn_file_actions_t, @@ -103,22 +103,24 @@ pub extern "C" fn posix_spawn( ) -> c_int { let program = unsafe { CStr::from_ptr(path).to_str().unwrap().to_string() }; - if let Err(e) = spawn( - unsafe { pid.as_mut() }, - program, - unsafe { file_actions.as_ref() }, - unsafe { attrp.as_ref() }, - argv, - if envp.is_null() { None } else { Some(envp) }, - false, - ) { + if let Err(e) = unsafe { + spawn( + pid.as_mut(), + program, + file_actions.as_ref(), + attrp.as_ref(), + argv, + if envp.is_null() { None } else { Some(envp) }, + false, + ) + } { return e.0; } 0 } #[unsafe(no_mangle)] -pub extern "C" fn posix_spawnp( +pub unsafe extern "C" fn posix_spawnp( pid: *mut pid_t, path: *const c_char, file_actions: *const posix_spawn_file_actions_t, @@ -128,15 +130,17 @@ pub extern "C" fn posix_spawnp( ) -> c_int { let program = unsafe { CStr::from_ptr(path).to_str().unwrap().to_string() }; - if let Err(e) = spawn( - unsafe { pid.as_mut() }, - program.clone(), - unsafe { file_actions.as_ref() }, - unsafe { attrp.as_ref() }, - argv, - if envp.is_null() { None } else { Some(envp) }, - if program.contains('/') { false } else { true }, - ) { + if let Err(e) = unsafe { + spawn( + pid.as_mut(), + program.clone(), + file_actions.as_ref(), + attrp.as_ref(), + argv, + if envp.is_null() { None } else { Some(envp) }, + if program.contains('/') { false } else { true }, + ) + } { return e.0; } 0 diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index 42fa6d690b..4fb69c5461 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -1259,8 +1259,8 @@ impl Pal for Sys { if let Some(fac) = fac { for action in fac { - match action.operation { - crate::header::spawn::Operation::Open { + match action { + crate::header::spawn::Action::Open { fd, path, flag, @@ -1275,24 +1275,24 @@ impl Pal for Sys { u64::try_from(fd).map_err(|_| Errno(EBADFD))?, )?; } - crate::header::spawn::Operation::Close(fd) => { + crate::header::spawn::Action::Close(fd) => { new_file_table.call_wo( &(fd as usize).to_ne_bytes(), syscall::CallFlags::empty(), &[syscall::flag::FileTableVerb::Close as u64], )?; } - crate::header::spawn::Operation::Chdir(path) => { + crate::header::spawn::Action::Chdir(path) => { let path = unsafe { CStr::from_ptr(path) }; cwd = path.to_str().unwrap().to_string(); path::chdir(cwd.as_str())?; } - crate::header::spawn::Operation::FChdir(fd) => { + crate::header::spawn::Action::FChdir(fd) => { path::fchdir(fd)?; path::getcwd(Out::from_mut(unsafe { cwd.as_bytes_mut() }))?; } - crate::header::spawn::Operation::Dup2(old, new) => { + crate::header::spawn::Action::Dup2(old, new) => { new_file_table.call_wo( [(old as usize).to_ne_bytes(), (new as usize).to_ne_bytes()] .into_iter() From 8c65ed481a45952a56baa6c159961d03a23df300 Mon Sep 17 00:00:00 2001 From: R Aadarsh Date: Tue, 2 Jun 2026 18:46:50 +0530 Subject: [PATCH 15/29] Make path to be owned --- src/header/spawn/file_actions.rs | 39 ++++++++++++++++++++------------ src/platform/mod.rs | 2 +- src/platform/redox/mod.rs | 13 +++++++---- 3 files changed, 33 insertions(+), 21 deletions(-) diff --git a/src/header/spawn/file_actions.rs b/src/header/spawn/file_actions.rs index 0c8ecaec8d..a501086b83 100644 --- a/src/header/spawn/file_actions.rs +++ b/src/header/spawn/file_actions.rs @@ -1,13 +1,12 @@ -use core::{ - ffi::{c_char, c_int}, - mem::ManuallyDrop, - ptr::null_mut, +use core::{mem::ManuallyDrop, ptr::null_mut}; + +use alloc::{ffi::CString, vec::Vec}; + +use crate::{ + header::errno::EBADF, + platform::types::{c_char, c_int, mode_t}, }; -use alloc::vec::Vec; - -use crate::{header::errno::EBADF, platform::types::mode_t}; - const OPEN: c_char = 1; const CLOSE: c_char = 2; const CHDIR: c_char = 3; @@ -15,16 +14,16 @@ const FCHDIR: c_char = 4; const DUP2: c_char = 5; #[repr(C)] -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone)] pub enum Action { Open { fd: c_int, - path: *const c_char, + path: CString, flag: c_int, mode: mode_t, }, Close(c_int), - Chdir(*const c_char), + Chdir(CString), FChdir(c_int), Dup2(c_int, c_int), } @@ -62,7 +61,7 @@ impl Iterator for FileActionsIter { }; let e = actions.get(self.curr)?; self.curr += 1; - Some(*e) + Some((*e).clone()) } } @@ -73,7 +72,7 @@ impl<'a> IntoIterator for &'a posix_spawn_file_actions_t { fn into_iter(self) -> Self::IntoIter { FileActionsIter { - actions: *self, + actions: (*self).clone(), curr: 0, } } @@ -121,7 +120,11 @@ pub unsafe extern "C" fn posix_spawn_file_actions_addopen( } file_actions.add_action(Action::Open { fd, - path, + path: if path.is_null() { + CString::new("").unwrap() + } else { + unsafe { CString::from_raw(path as *mut c_char) } + }, flag: oflag, mode, }); @@ -145,7 +148,13 @@ pub unsafe extern "C" fn posix_spawn_file_actions_addchdir( file_actions: &mut posix_spawn_file_actions_t, path: *const c_char, ) -> c_int { - file_actions.add_action(Action::Chdir(path)); + file_actions.add_action(Action::Chdir(unsafe { + if path.is_null() { + CString::new("").unwrap() + } else { + CString::from_raw(path as *mut c_char) + } + })); 0 } diff --git a/src/platform/mod.rs b/src/platform/mod.rs index d9ec7cfee6..36cf5c01b6 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -24,7 +24,7 @@ pub use self::sys::Sys; #[path = "linux/mod.rs"] pub(crate) mod sys; -#[cfg(target_os = "redox")] +// #[cfg(target_os = "redox")] #[path = "redox/mod.rs"] pub(crate) mod sys; diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index 4fb69c5461..9672ec6141 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -1266,8 +1266,11 @@ impl Pal for Sys { flag, mode, } => { - let src_fd = - Sys::open(unsafe { CStr::from_ptr(path) }, flag, mode)? as usize; + let src_fd = Sys::open( + CStr::from_bytes_with_nul(path.as_bytes_with_nul()).unwrap(), + flag, + mode, + )? as usize; syscall::sendfd( new_file_table.as_raw_fd(), src_fd, @@ -1283,10 +1286,10 @@ impl Pal for Sys { )?; } crate::header::spawn::Action::Chdir(path) => { - let path = unsafe { CStr::from_ptr(path) }; - cwd = path.to_str().unwrap().to_string(); + let path = path.to_str().unwrap(); + cwd = path.to_string(); - path::chdir(cwd.as_str())?; + path::chdir(path)?; } crate::header::spawn::Action::FChdir(fd) => { path::fchdir(fd)?; From fefea0f0a9aa942f6f4389ece4977e88769553ba Mon Sep 17 00:00:00 2001 From: R Aadarsh Date: Wed, 3 Jun 2026 20:09:31 +0530 Subject: [PATCH 16/29] Make code safer by disallowing NULL argv, empty argv and NULL values for pointer arguments to functions --- src/header/spawn/file_actions.rs | 53 ++++++++++++++++++++------------ src/header/spawn/mod.rs | 45 +++++++++++++++++++++++---- src/iter.rs | 6 ++++ src/platform/pal/mod.rs | 5 +-- src/platform/redox/mod.rs | 45 ++++++++++++--------------- 5 files changed, 101 insertions(+), 53 deletions(-) diff --git a/src/header/spawn/file_actions.rs b/src/header/spawn/file_actions.rs index a501086b83..fcf4cde770 100644 --- a/src/header/spawn/file_actions.rs +++ b/src/header/spawn/file_actions.rs @@ -1,4 +1,4 @@ -use core::{mem::ManuallyDrop, ptr::null_mut}; +use core::{mem::ManuallyDrop, slice}; use alloc::{ffi::CString, vec::Vec}; @@ -13,7 +13,6 @@ const CHDIR: c_char = 3; const FCHDIR: c_char = 4; const DUP2: c_char = 5; -#[repr(C)] #[derive(Debug, Clone)] pub enum Action { Open { @@ -31,15 +30,19 @@ pub enum Action { #[repr(C)] #[derive(Debug, Clone, Copy)] pub struct posix_spawn_file_actions_t { - file_actions: *mut Action, + file_actions: usize, length: usize, capacity: usize, } impl posix_spawn_file_actions_t { pub fn add_action(&mut self, action: Action) { - let v = unsafe { &mut Vec::from_raw_parts(self.file_actions, self.length, self.capacity) }; + let mut v = unsafe { + Vec::from_raw_parts(self.file_actions as *mut Action, self.length, self.capacity) + }; v.push(action); + let raw = v.into_raw_parts(); + (self.file_actions, self.length, self.capacity) = (raw.0.addr(), raw.1, raw.2); } } @@ -53,10 +56,9 @@ impl Iterator for FileActionsIter { fn next(&mut self) -> Option { let actions = unsafe { - &Vec::from_raw_parts( - self.actions.file_actions, + slice::from_raw_parts( + self.actions.file_actions as *const Action, self.actions.length, - self.actions.capacity, ) }; let e = actions.get(self.curr)?; @@ -80,10 +82,11 @@ impl<'a> IntoIterator for &'a posix_spawn_file_actions_t { #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawn_file_actions_init( - file_actions: &mut posix_spawn_file_actions_t, + file_actions: *mut posix_spawn_file_actions_t, ) -> c_int { - let mut v = ManuallyDrop::new(Vec::new()); - file_actions.file_actions = v.as_mut_ptr(); + let file_actions = unsafe { file_actions.as_mut().expect("file_actions cannot be NULL") }; + let mut v = ManuallyDrop::new(Vec::::new()); + file_actions.file_actions = v.as_mut_ptr().addr(); file_actions.capacity = v.capacity(); file_actions.length = 0; 0 @@ -91,30 +94,35 @@ pub unsafe extern "C" fn posix_spawn_file_actions_init( #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawn_file_actions_destroy( - file_actions: &mut posix_spawn_file_actions_t, + file_actions: *mut posix_spawn_file_actions_t, ) -> c_int { + let file_actions = unsafe { file_actions.as_mut().expect("file_actions cannot be NULL") }; let v = unsafe { - &Vec::from_raw_parts( - file_actions.file_actions, + Vec::from_raw_parts( + file_actions.file_actions as *mut Action, file_actions.length, file_actions.capacity, ) }; file_actions.capacity = 0; file_actions.length = 0; - file_actions.file_actions = null_mut(); + file_actions.file_actions = 0; 0 } #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawn_file_actions_addopen( - file_actions: &mut posix_spawn_file_actions_t, + file_actions: *mut posix_spawn_file_actions_t, fd: c_int, path: *const c_char, oflag: c_int, mode: mode_t, ) -> c_int { + let file_actions = unsafe { file_actions.as_mut().expect("file_actions cannot be NULL") }; + if path.is_null() { + panic!("path cannot be NULL"); + } if fd < 0 { return EBADF; } @@ -133,9 +141,10 @@ pub unsafe extern "C" fn posix_spawn_file_actions_addopen( #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawn_file_actions_addclose( - file_actions: &mut posix_spawn_file_actions_t, + file_actions: *mut posix_spawn_file_actions_t, fd: c_int, ) -> c_int { + let file_actions = unsafe { file_actions.as_mut().expect("file_actions cannot be NULL") }; if fd < 0 { return EBADF; } @@ -145,9 +154,13 @@ pub unsafe extern "C" fn posix_spawn_file_actions_addclose( #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawn_file_actions_addchdir( - file_actions: &mut posix_spawn_file_actions_t, + file_actions: *mut posix_spawn_file_actions_t, path: *const c_char, ) -> c_int { + let file_actions = unsafe { file_actions.as_mut().expect("file_actions cannot be NULL") }; + if path.is_null() { + panic!("path cannot be NULL"); + } file_actions.add_action(Action::Chdir(unsafe { if path.is_null() { CString::new("").unwrap() @@ -160,9 +173,10 @@ pub unsafe extern "C" fn posix_spawn_file_actions_addchdir( #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawn_file_actions_addfchdir( - file_actions: &mut posix_spawn_file_actions_t, + file_actions: *mut posix_spawn_file_actions_t, fd: c_int, ) -> c_int { + let file_actions = unsafe { file_actions.as_mut().expect("file_actions cannot be NULL") }; if fd < 0 { return EBADF; } @@ -172,10 +186,11 @@ pub unsafe extern "C" fn posix_spawn_file_actions_addfchdir( #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawn_file_actions_adddup2( - file_actions: &mut posix_spawn_file_actions_t, + file_actions: *mut posix_spawn_file_actions_t, fd: c_int, new: c_int, ) -> c_int { + let file_actions = unsafe { file_actions.as_mut().expect("file_actions cannot be NULL") }; if fd < 0 || new < 0 { return EBADF; } diff --git a/src/header/spawn/mod.rs b/src/header/spawn/mod.rs index 83d6674efb..79c4e305dc 100644 --- a/src/header/spawn/mod.rs +++ b/src/header/spawn/mod.rs @@ -17,6 +17,7 @@ use crate::{ errno::ENOENT, stdlib::getenv, }, + iter::NulTerminated, platform::{ self, Pal, sys::path, @@ -29,8 +30,8 @@ unsafe fn spawn( mut program: String, file_actions: Option<&posix_spawn_file_actions_t>, spawn_attr: Option<&posix_spawnattr_t>, - argv: *const *mut c_char, - envp: Option<*const *mut c_char>, + argv: NulTerminated<*mut c_char>, + envp: Option>, use_path: bool, ) -> Result<()> { let original_cwd = path::clone_cwd().unwrap().to_string(); @@ -101,7 +102,23 @@ pub unsafe extern "C" fn posix_spawn( argv: *const *mut c_char, envp: *const *mut c_char, ) -> c_int { - let program = unsafe { CStr::from_ptr(path).to_str().unwrap().to_string() }; + let argv = { + if argv.is_null() { + panic!("argv cannot be NULL") + } else { + if unsafe { (*argv).is_null() } { + panic!("argv must contain the program name"); + } + unsafe { NulTerminated::new(argv).unwrap() } + } + }; + let envp = unsafe { NulTerminated::new(envp) }; + let program = unsafe { + CStr::from_ptr(path) + .to_str() + .expect("path cannot be NULL") + .to_string() + }; if let Err(e) = unsafe { spawn( @@ -110,7 +127,7 @@ pub unsafe extern "C" fn posix_spawn( file_actions.as_ref(), attrp.as_ref(), argv, - if envp.is_null() { None } else { Some(envp) }, + envp, false, ) } { @@ -128,7 +145,23 @@ pub unsafe extern "C" fn posix_spawnp( argv: *const *mut c_char, envp: *const *mut c_char, ) -> c_int { - let program = unsafe { CStr::from_ptr(path).to_str().unwrap().to_string() }; + let argv = { + if argv.is_null() { + panic!("argv cannot be NULL") + } else { + if unsafe { (*argv).is_null() } { + panic!("argv must contain the program name"); + } + unsafe { NulTerminated::new(argv).unwrap() } + } + }; + let envp = unsafe { NulTerminated::new(envp) }; + let program = unsafe { + CStr::from_ptr(path) + .to_str() + .expect("path cannot be NULL") + .to_string() + }; if let Err(e) = unsafe { spawn( @@ -137,7 +170,7 @@ pub unsafe extern "C" fn posix_spawnp( file_actions.as_ref(), attrp.as_ref(), argv, - if envp.is_null() { None } else { Some(envp) }, + envp, if program.contains('/') { false } else { true }, ) } { diff --git a/src/iter.rs b/src/iter.rs index 369d2dadc8..4b3cc6c872 100644 --- a/src/iter.rs +++ b/src/iter.rs @@ -30,6 +30,12 @@ unsafe impl Zero for wchar_t { } } +unsafe impl Zero for *mut c_char { + fn is_zero(&self) -> bool { + self.is_null() + } +} + /// An iterator over a nul-terminated buffer. /// /// This is intended to allow safe, ergonomic iteration over C-style byte and diff --git a/src/platform/pal/mod.rs b/src/platform/pal/mod.rs index 83e380610e..194535eb17 100644 --- a/src/platform/pal/mod.rs +++ b/src/platform/pal/mod.rs @@ -15,6 +15,7 @@ use crate::{ sys_utsname::utsname, time::{itimerspec, timespec}, }, + iter::NulTerminated, ld_so::tcb::OsSpecific, out::Out, pthread, @@ -437,8 +438,8 @@ pub trait Pal { program: CStr, fac: Option<&crate::header::spawn::posix_spawn_file_actions_t>, fat: Option<&crate::header::spawn::posix_spawnattr_t>, - argv: *const *mut c_char, - envp: Option<*const *mut c_char>, + argv: NulTerminated<*mut c_char>, + envp: Option>, use_path: bool, ) -> Result; diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index 9672ec6141..50346fce4c 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -41,7 +41,6 @@ use crate::{ signal::{NSIG, SIGEV_NONE, SIGEV_SIGNAL, SIGEV_THREAD, SIGRTMIN, sigevent}, stdio::RENAME_NOREPLACE, stdlib::posix_memalign, - string::strlen, sys_file, sys_mman::{MAP_ANONYMOUS, PROT_READ, PROT_WRITE}, sys_random, @@ -57,6 +56,7 @@ use crate::{ unistd::{F_OK, R_OK, SEEK_CUR, SEEK_SET, W_OK, X_OK}, }, io::{self, BufReader, prelude::*}, + iter::NulTerminated, ld_so::tcb::OsSpecific, out::Out, platform::{ @@ -1205,8 +1205,8 @@ impl Pal for Sys { program: CStr, fac: Option<&crate::header::spawn::posix_spawn_file_actions_t>, fat: Option<&crate::header::spawn::posix_spawnattr_t>, - mut argv: *const *mut c_char, - envp: Option<*const *mut c_char>, + argv: NulTerminated<*mut c_char>, + envp: Option>, use_path: bool, ) -> Result { use crate::header::spawn::Flags; @@ -1230,31 +1230,25 @@ impl Pal for Sys { let mut args = Vec::new(); let mut envs = Vec::new(); - let len = unsafe { strlen(*argv) }; - let program_name = - str::from_utf8(unsafe { slice::from_raw_parts(*argv as *const u8, len) }).unwrap(); - let program_name: String = - redox_path::canonicalize_using_cwd(Some(original_cwd.as_str()), program_name) - .ok_or(Errno(ENOENT))?; - argv = unsafe { argv.add(1) }; - args.push(program_name.as_bytes()); - - while unsafe { !(*argv).is_null() } { - let arg = unsafe { *argv }; - let len = unsafe { strlen(arg) }; - args.push(unsafe { slice::from_raw_parts(arg as *const u8, len) }); - argv = unsafe { argv.add(1) }; + for arg in argv { + args.push(unsafe { CStr::from_ptr(*arg).to_chars() }); } - if let Some(mut envp) = envp { - while unsafe { !(*envp).is_null() } { - let env = unsafe { *envp }; - let len = unsafe { strlen(env) }; - envs.push(unsafe { slice::from_raw_parts(env as *const u8, len) }); - envp = unsafe { envp.add(1) }; + if let Some(envp) = envp { + for env in envp { + envs.push(unsafe { CStr::from_ptr(*env).to_chars() }); } } + let mut program_name = String::new(); + + program_name = redox_path::canonicalize_using_cwd( + Some(original_cwd.as_str()), + str::from_utf8(args[0]).unwrap(), + ) + .ok_or(Errno(ENOENT))?; + args[0] = program_name.as_bytes(); + let new_file_table = child.thr_fd.dup(b"filetable")?; if let Some(fac) = fac { @@ -1286,10 +1280,9 @@ impl Pal for Sys { )?; } crate::header::spawn::Action::Chdir(path) => { - let path = path.to_str().unwrap(); - cwd = path.to_string(); + cwd = path.to_str().unwrap().to_string(); - path::chdir(path)?; + path::chdir(path.to_str().unwrap())?; } crate::header::spawn::Action::FChdir(fd) => { path::fchdir(fd)?; From a941458ba0568f0939e427b180ba09543e002bd8 Mon Sep 17 00:00:00 2001 From: R Aadarsh Date: Thu, 4 Jun 2026 08:50:12 +0530 Subject: [PATCH 17/29] Remove the use of `platform::redox::path` --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- src/header/spawn/mod.rs | 8 +++++--- src/platform/linux/mod.rs | 11 +++++++++++ src/platform/mod.rs | 2 +- 5 files changed, 21 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7808523537..402d28e3ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -472,7 +472,7 @@ dependencies = [ [[package]] name = "redox_syscall" version = "0.8.1" -source = "git+https://gitlab.redox-os.org/EuclidDivisionLemma/syscall/?branch=spawn#2708fc84ac7347d16408e8b73f62ec7656f0bc25" +source = "git+https://gitlab.redox-os.org/redox-os/syscall/#79cb6d9057642be31623677458a93aa88145864f" dependencies = [ "bitflags", ] @@ -632,9 +632,9 @@ dependencies = [ [[package]] name = "typenum" -version = "1.20.0" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" [[package]] name = "unicode-ident" diff --git a/Cargo.toml b/Cargo.toml index 07fc1f68aa..1b5f3d4312 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -145,4 +145,4 @@ panic = "abort" [patch.crates-io] cc-11 = { git = "https://github.com/tea/cc-rs", branch = "riscv-abi-arch-fix", package = "cc" } -redox_syscall = {git = "https://gitlab.redox-os.org/EuclidDivisionLemma/syscall/", branch = "spawn"} +redox_syscall = {git = "https://gitlab.redox-os.org/redox-os/syscall/"} diff --git a/src/header/spawn/mod.rs b/src/header/spawn/mod.rs index 79c4e305dc..8497668227 100644 --- a/src/header/spawn/mod.rs +++ b/src/header/spawn/mod.rs @@ -15,12 +15,13 @@ use crate::{ header::{ dirent::{opendir, readdir}, errno::ENOENT, + limits::PATH_MAX, stdlib::getenv, + unistd::{chdir, getcwd}, }, iter::NulTerminated, platform::{ self, Pal, - sys::path, types::{c_char, c_int, pid_t}, }, }; @@ -34,7 +35,8 @@ unsafe fn spawn( envp: Option>, use_path: bool, ) -> Result<()> { - let original_cwd = path::clone_cwd().unwrap().to_string(); + let mut original_cwd = [0u8; PATH_MAX]; + assert!(unsafe { !getcwd(original_cwd.as_mut_ptr() as *mut c_char, PATH_MAX).is_null() }); if use_path { let path = unsafe { getenv(c"PATH".as_ptr()) }; @@ -85,7 +87,7 @@ unsafe fn spawn( } }) .map_err(|e| { - path::chdir(original_cwd.as_str()).unwrap(); + chdir(original_cwd.as_ptr() as *const c_char); e })?; } diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs index 1b002995c9..856e5128ad 100644 --- a/src/platform/linux/mod.rs +++ b/src/platform/linux/mod.rs @@ -793,4 +793,15 @@ impl Pal for Sys { // GETPID on Linux is 39, which does not exist on Redox e_raw(unsafe { sc::syscall5(sc::nr::GETPID, !0, !0, !0, !0, !0) }).is_ok() } + + unsafe fn spawn( + program: CStr, + fac: Option<&crate::header::spawn::posix_spawn_file_actions_t>, + fat: Option<&crate::header::spawn::posix_spawnattr_t>, + argv: crate::iter::NulTerminated<*mut c_char>, + envp: Option>, + use_path: bool, + ) -> Result { + todo!() + } } diff --git a/src/platform/mod.rs b/src/platform/mod.rs index 36cf5c01b6..d9ec7cfee6 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -24,7 +24,7 @@ pub use self::sys::Sys; #[path = "linux/mod.rs"] pub(crate) mod sys; -// #[cfg(target_os = "redox")] +#[cfg(target_os = "redox")] #[path = "redox/mod.rs"] pub(crate) mod sys; From 632c8302a4c1e6ab49066f3b8360ec97448e67d3 Mon Sep 17 00:00:00 2001 From: R Aadarsh Date: Thu, 4 Jun 2026 08:59:19 +0530 Subject: [PATCH 18/29] Change assertions and panics to display ERRNO --- src/header/spawn/mod.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/header/spawn/mod.rs b/src/header/spawn/mod.rs index 8497668227..ac046b5452 100644 --- a/src/header/spawn/mod.rs +++ b/src/header/spawn/mod.rs @@ -21,7 +21,7 @@ use crate::{ }, iter::NulTerminated, platform::{ - self, Pal, + self, ERRNO, Pal, types::{c_char, c_int, pid_t}, }, }; @@ -35,8 +35,12 @@ unsafe fn spawn( envp: Option>, use_path: bool, ) -> Result<()> { - let mut original_cwd = [0u8; PATH_MAX]; - assert!(unsafe { !getcwd(original_cwd.as_mut_ptr() as *mut c_char, PATH_MAX).is_null() }); + let mut original_cwd = [0 as c_char; PATH_MAX]; + assert!( + unsafe { !getcwd(original_cwd.as_mut_ptr() as *mut c_char, PATH_MAX).is_null() }, + "Error getting cwd: {}", + ERRNO.get() + ); if use_path { let path = unsafe { getenv(c"PATH".as_ptr()) }; @@ -87,7 +91,10 @@ unsafe fn spawn( } }) .map_err(|e| { - chdir(original_cwd.as_ptr() as *const c_char); + let status = chdir(original_cwd.as_ptr() as *const c_char); + if status != 0 { + panic!("Error switching back to original cwd: {}", ERRNO.get()); + } e })?; } From 72ee48df3fe9031e5742bf0a8b77d69d95359f5a Mon Sep 17 00:00:00 2001 From: R Aadarsh Date: Sat, 6 Jun 2026 14:57:42 +0530 Subject: [PATCH 19/29] Change file_actions implementation to mirror other pthread --- src/header/spawn/file_actions.rs | 63 +++++++++++++++----------------- 1 file changed, 29 insertions(+), 34 deletions(-) diff --git a/src/header/spawn/file_actions.rs b/src/header/spawn/file_actions.rs index fcf4cde770..d804828fd2 100644 --- a/src/header/spawn/file_actions.rs +++ b/src/header/spawn/file_actions.rs @@ -1,10 +1,9 @@ -use core::{mem::ManuallyDrop, slice}; - use alloc::{ffi::CString, vec::Vec}; +use core::ptr; use crate::{ header::errno::EBADF, - platform::types::{c_char, c_int, mode_t}, + platform::types::{c_char, c_int, mode_t, size_t}, }; const OPEN: c_char = 1; @@ -27,22 +26,21 @@ pub enum Action { Dup2(c_int, c_int), } +struct FileActions(Vec); + #[repr(C)] #[derive(Debug, Clone, Copy)] pub struct posix_spawn_file_actions_t { - file_actions: usize, - length: usize, - capacity: usize, + __relibc_internal_size: [u8; 24], + __relibc_internal_align: size_t, } impl posix_spawn_file_actions_t { pub fn add_action(&mut self, action: Action) { - let mut v = unsafe { - Vec::from_raw_parts(self.file_actions as *mut Action, self.length, self.capacity) - }; - v.push(action); - let raw = v.into_raw_parts(); - (self.file_actions, self.length, self.capacity) = (raw.0.addr(), raw.1, raw.2); + let v = ptr::from_mut(self).cast::(); + unsafe { + (*v).0.push(action); + } } } @@ -56,12 +54,12 @@ impl Iterator for FileActionsIter { fn next(&mut self) -> Option { let actions = unsafe { - slice::from_raw_parts( - self.actions.file_actions as *const Action, - self.actions.length, - ) + ptr::from_mut(&mut self.actions) + .cast::() + .as_ref() + .unwrap() }; - let e = actions.get(self.curr)?; + let e = actions.0.get(self.curr)?; self.curr += 1; Some((*e).clone()) } @@ -84,11 +82,14 @@ impl<'a> IntoIterator for &'a posix_spawn_file_actions_t { pub unsafe extern "C" fn posix_spawn_file_actions_init( file_actions: *mut posix_spawn_file_actions_t, ) -> c_int { - let file_actions = unsafe { file_actions.as_mut().expect("file_actions cannot be NULL") }; - let mut v = ManuallyDrop::new(Vec::::new()); - file_actions.file_actions = v.as_mut_ptr().addr(); - file_actions.capacity = v.capacity(); - file_actions.length = 0; + if file_actions.is_null() { + panic!("file_actions cannot be NULL"); + } + let v = Vec::new(); + let actions = FileActions(v); + unsafe { + ptr::write(file_actions.cast::(), actions); + } 0 } @@ -96,18 +97,12 @@ pub unsafe extern "C" fn posix_spawn_file_actions_init( pub unsafe extern "C" fn posix_spawn_file_actions_destroy( file_actions: *mut posix_spawn_file_actions_t, ) -> c_int { - let file_actions = unsafe { file_actions.as_mut().expect("file_actions cannot be NULL") }; - let v = unsafe { - Vec::from_raw_parts( - file_actions.file_actions as *mut Action, - file_actions.length, - file_actions.capacity, - ) - }; - file_actions.capacity = 0; - file_actions.length = 0; - file_actions.file_actions = 0; - + if file_actions.is_null() { + panic!("file_actions cannot be NULL"); + } + unsafe { + let _ = *(file_actions.cast::()); + } 0 } From 4ea8f329b6725dde474922383958b973c01c104d Mon Sep 17 00:00:00 2001 From: R Aadarsh Date: Sat, 6 Jun 2026 14:59:03 +0530 Subject: [PATCH 20/29] Remove unused constants --- src/header/spawn/file_actions.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/header/spawn/file_actions.rs b/src/header/spawn/file_actions.rs index d804828fd2..9dd01f6e40 100644 --- a/src/header/spawn/file_actions.rs +++ b/src/header/spawn/file_actions.rs @@ -6,12 +6,6 @@ use crate::{ platform::types::{c_char, c_int, mode_t, size_t}, }; -const OPEN: c_char = 1; -const CLOSE: c_char = 2; -const CHDIR: c_char = 3; -const FCHDIR: c_char = 4; -const DUP2: c_char = 5; - #[derive(Debug, Clone)] pub enum Action { Open { From f59e29274446a4947cf054152389e9846137adf4 Mon Sep 17 00:00:00 2001 From: R Aadarsh Date: Sat, 6 Jun 2026 18:21:48 +0530 Subject: [PATCH 21/29] Change `spawn` to use `CString`. String not-being null-terminated prevented files on PATH from being opened. --- src/header/spawn/mod.rs | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/header/spawn/mod.rs b/src/header/spawn/mod.rs index ac046b5452..7290714e08 100644 --- a/src/header/spawn/mod.rs +++ b/src/header/spawn/mod.rs @@ -5,7 +5,12 @@ mod file_actions; mod spawn_attr; -use alloc::string::{String, ToString}; +use core::str::FromStr; + +use alloc::{ + ffi::CString, + string::{String, ToString}, +}; pub use file_actions::{Action, posix_spawn_file_actions_t}; pub use spawn_attr::{Flags, posix_spawnattr_t}; @@ -14,7 +19,7 @@ use crate::{ error::{Errno, Result}, header::{ dirent::{opendir, readdir}, - errno::ENOENT, + errno::{ENOENT, ENOTDIR}, limits::PATH_MAX, stdlib::getenv, unistd::{chdir, getcwd}, @@ -48,13 +53,16 @@ unsafe fn spawn( let path_elements = path_env.split(':'); let mut flag = false; - for path_element in path_elements { + 'a: for path_element in path_elements { + let pe = CString::from_str(path_element).unwrap(); let dir = if let Some(dir) = - unsafe { opendir(path_element.as_bytes().as_ptr() as *const c_char).as_mut() } + unsafe { opendir(pe.as_bytes_with_nul().as_ptr() as *const c_char).as_mut() } { dir - } else { + } else if ERRNO.get() == 0 || ERRNO.get() == ENOTDIR || ERRNO.get() == ENOENT { continue; + } else { + return Err(Errno(ERRNO.get())); }; while let Some(dir_ent) = unsafe { readdir(dir).as_ref() } { @@ -66,7 +74,7 @@ unsafe fn spawn( if dir_ent_name == program { flag = true; program = format!("{}/{}", path_element, program); - break; + break 'a; } } } @@ -76,9 +84,11 @@ unsafe fn spawn( } } + let program = CString::from_str(program.as_str()).unwrap(); + unsafe { platform::Sys::spawn( - CStr::from_bytes_with_nul_unchecked(program.as_bytes()), + CStr::from_bytes_with_nul(program.as_bytes_with_nul()).unwrap(), file_actions, spawn_attr, argv, From ad151e0de82caf8307092a9da5e1798cc6b344ba Mon Sep 17 00:00:00 2001 From: R Aadarsh Date: Sun, 7 Jun 2026 10:10:02 +0530 Subject: [PATCH 22/29] * Correctly determine `argv[0]` - If the function called is `posix_spawnp`, and the passed program name **does not** contain a slash, the path is used unmodified, and the path to the directory containing the program on $PATH is prepended to the program's path and assigned to `argv[0]. If the program name **does** contain a slash, the path is absolutised relative to CWD, and assigned to argv[0] - If the function called is `posix_spawn`, the behaviour is as described above in the case where path contains a slash * Add initial tests --- src/header/spawn/mod.rs | 5 +- src/platform/linux/mod.rs | 4 +- src/platform/mod.rs | 2 +- src/platform/pal/mod.rs | 4 +- src/platform/redox/mod.rs | 21 ++++-- tests/Makefile.tests.mk | 5 +- tests/expected/spawn/file_actions.stdout | 1 + tests/expected/spawn/spawn_attr.stdout | 0 tests/spawn.c | 92 ------------------------ tests/spawn/file_actions.c | 75 +++++++++++++++++++ tests/spawn/spawn_attr.c | 1 + 11 files changed, 106 insertions(+), 104 deletions(-) create mode 100644 tests/expected/spawn/file_actions.stdout create mode 100644 tests/expected/spawn/spawn_attr.stdout delete mode 100644 tests/spawn.c create mode 100644 tests/spawn/file_actions.c create mode 100644 tests/spawn/spawn_attr.c diff --git a/src/header/spawn/mod.rs b/src/header/spawn/mod.rs index 7290714e08..f7b6feca2f 100644 --- a/src/header/spawn/mod.rs +++ b/src/header/spawn/mod.rs @@ -47,6 +47,7 @@ unsafe fn spawn( ERRNO.get() ); + let mut path_path = None; if use_path { let path = unsafe { getenv(c"PATH".as_ptr()) }; let path_env = unsafe { CStr::from_nullable_ptr(path).unwrap().to_str().unwrap() }; @@ -70,10 +71,12 @@ unsafe fn spawn( CStr::from_ptr(dir_ent.d_name.as_ptr() as *const c_char) .to_str() .unwrap() + .to_string() }; if dir_ent_name == program { flag = true; program = format!("{}/{}", path_element, program); + path_path = Some(path_element.to_string()); break 'a; } } @@ -93,7 +96,7 @@ unsafe fn spawn( spawn_attr, argv, envp, - use_path, + path_path, ) .map(|v| { if let Some(pid) = pid { diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs index 856e5128ad..bc3cb308ab 100644 --- a/src/platform/linux/mod.rs +++ b/src/platform/linux/mod.rs @@ -1,6 +1,8 @@ #[cfg(target_arch = "x86_64")] use core::arch::asm; +use alloc::string::String; + use super::{Pal, types::*}; use crate::{ c_str::CStr, @@ -800,7 +802,7 @@ impl Pal for Sys { fat: Option<&crate::header::spawn::posix_spawnattr_t>, argv: crate::iter::NulTerminated<*mut c_char>, envp: Option>, - use_path: bool, + dir_ent_name: Option, ) -> Result { todo!() } diff --git a/src/platform/mod.rs b/src/platform/mod.rs index d9ec7cfee6..36cf5c01b6 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -24,7 +24,7 @@ pub use self::sys::Sys; #[path = "linux/mod.rs"] pub(crate) mod sys; -#[cfg(target_os = "redox")] +// #[cfg(target_os = "redox")] #[path = "redox/mod.rs"] pub(crate) mod sys; diff --git a/src/platform/pal/mod.rs b/src/platform/pal/mod.rs index 194535eb17..75a706605d 100644 --- a/src/platform/pal/mod.rs +++ b/src/platform/pal/mod.rs @@ -1,5 +1,7 @@ use core::num::NonZeroU64; +use alloc::string::String; + use super::types::*; use crate::{ c_str::CStr, @@ -440,7 +442,7 @@ pub trait Pal { fat: Option<&crate::header::spawn::posix_spawnattr_t>, argv: NulTerminated<*mut c_char>, envp: Option>, - use_path: bool, + dir_ent_name: Option, ) -> Result; /// Platform implementation of [`symlink()`](crate::header::unistd::symlink) from [`unistd.h`](crate::header::unistd). diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index 50346fce4c..f496b4d2ab 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -1207,7 +1207,7 @@ impl Pal for Sys { fat: Option<&crate::header::spawn::posix_spawnattr_t>, argv: NulTerminated<*mut c_char>, envp: Option>, - use_path: bool, + dir_ent_name: Option, ) -> Result { use crate::header::spawn::Flags; @@ -1242,11 +1242,20 @@ impl Pal for Sys { let mut program_name = String::new(); - program_name = redox_path::canonicalize_using_cwd( - Some(original_cwd.as_str()), - str::from_utf8(args[0]).unwrap(), - ) - .ok_or(Errno(ENOENT))?; + if let Some(ent) = dir_ent_name { + let mut binary = str::from_utf8(args[0]).unwrap().to_string(); + binary.insert_str(0, "./"); + + program_name = redox_path::canonicalize_using_cwd(Some(ent.as_str()), binary.as_str()) + .ok_or(Errno(ENOENT))?; + } else { + program_name = redox_path::canonicalize_using_cwd( + Some(original_cwd.as_str()), + str::from_utf8(args[0]).unwrap(), + ) + .ok_or(Errno(ENOENT))?; + } + args[0] = program_name.as_bytes(); let new_file_table = child.thr_fd.dup(b"filetable")?; diff --git a/tests/Makefile.tests.mk b/tests/Makefile.tests.mk index dddebeed2d..5f62e1f8cc 100644 --- a/tests/Makefile.tests.mk +++ b/tests/Makefile.tests.mk @@ -11,7 +11,7 @@ FAILING_TESTS += malloc/usable_size FAILING_TESTS += mkfifo # Waitpid had EINTR FAILING_TESTS += sigchld -# not triggering ERANGE +# not triggering ERANGE FAILING_TESTS += stdlib/ptsname # Hang FAILING_TESTS += sys_epoll/epollet @@ -77,7 +77,8 @@ EXPECT_NAMES=\ sigaltstack \ signal \ sigsetjmp \ - spawn \ + spawn/file_actions \ + spawn/spawn_attr \ stdio/all \ stdio/buffer \ stdio/dprintf \ diff --git a/tests/expected/spawn/file_actions.stdout b/tests/expected/spawn/file_actions.stdout new file mode 100644 index 0000000000..f0ad0dec66 --- /dev/null +++ b/tests/expected/spawn/file_actions.stdout @@ -0,0 +1 @@ +hello.txt diff --git a/tests/expected/spawn/spawn_attr.stdout b/tests/expected/spawn/spawn_attr.stdout new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/spawn.c b/tests/spawn.c deleted file mode 100644 index b55f1d4286..0000000000 --- a/tests/spawn.c +++ /dev/null @@ -1,92 +0,0 @@ -#include -#include -#include -#include -#include - -#include "test_helpers.h" - -#define CHECK(cond, msg) \ - if (!cond) \ - { \ - fprintf(stderr, "Error in spawn.h: %s\n", msg); \ - _exit(EXIT_FAILURE); \ - } - -#define CHECK_WHEN_NULL(call, name) \ - if (!(call)) \ - { \ - fprintf(stderr, "Error in spawn.h: %s expected to fail when passing NULL\n", name); \ - _exit(EXIT_FAILURE); \ - } - -int main() -{ - posix_spawn_file_actions_t fa_t; - CHECK((posix_spawn_file_actions_init(&fa_t) == 0), "posix_spawn_file_actions_init failed") - CHECK_WHEN_NULL(posix_spawn_file_actions_init(NULL), "posix_spawn_file_actions_init") - CHECK((posix_spawn_file_actions_addopen(&fa_t, 1, ".", O_RDONLY, 1) == 0), "Error while adding open action") - CHECK((posix_spawn_file_actions_addclose(&fa_t, 1) == 0), "Error while adding close action") - CHECK((posix_spawn_file_actions_adddup2(&fa_t, -1, 3) == EBADF), "Adding dup2 with negative fd must fail") - CHECK((fa_t.size == 64), "Size remains unchanged") - CHECK_WHEN_NULL(posix_spawn_file_actions_destroy(NULL), "posix_spawn_file_actions_destroy") - CHECK_WHEN_NULL(posix_spawn_file_actions_addclose(NULL, 1), "posix_spawn_file_actions_addclose") - CHECK((posix_spawn_file_actions_destroy(&fa_t) == 0), "posix_spawn_file_actions_destroy failed") - CHECK((fa_t.size == 0), "Expected 0 size in posix_spawn_file_actions_t after destruction") - - posix_spawnattr_t sa; - CHECK((posix_spawnattr_init(&sa) == 0), "posix_spawnattr_init failed") - CHECK((sa.param.sched_priority == 0 && sa.flags == 0 && sa.pgroup == 0 && sa.policy == 0 && sa.sigdefault == 0 && sa.sigmask == 0), "All fields expected to be zero after init in posix_spawnattr_t") - CHECK_WHEN_NULL(posix_spawnattr_init(NULL), "posix_spawnattr_init") - CHECK_WHEN_NULL(posix_spawnattr_destroy(NULL), "posix_spawnattr_destroy") - - struct sched_param sp1; - sp1.sched_priority = 2; - struct sched_param sp2; - sp2.sched_priority = 0; - CHECK_WHEN_NULL(posix_spawnattr_setschedparam(NULL, &sp1), "posix_spawnattr_setschedparam") - CHECK_WHEN_NULL(posix_spawnattr_setschedparam(&sa, NULL), "posix_spawnattr_setschedparam") - CHECK((posix_spawnattr_setschedparam(&sa, &sp1) == 0), "posix_spawnattr_setschedparam failed") - CHECK_WHEN_NULL(posix_spawnattr_getschedparam(NULL, &sp2), "posix_spawnattr_getschedparam") - CHECK_WHEN_NULL(posix_spawnattr_getschedparam(&sa, NULL), "posix_spawnattr_getschedparam") - CHECK((posix_spawnattr_getschedparam(&sa, &sp2) == 0 && sp2.sched_priority == 2), "posix_spawnattr_getschedparam failed") - - CHECK_WHEN_NULL(posix_spawnattr_setschedpolicy(NULL, 0), "posix_spawnattr_setschedpolicy") - CHECK((posix_spawnattr_setschedpolicy(&sa, 1) == 0), "posix_spawnattr_setschedpolicy failed") - int pol = 0; - CHECK_WHEN_NULL(posix_spawnattr_getschedpolicy(NULL, &pol), "posix_spawnattr_getschedpolicy") - CHECK_WHEN_NULL(posix_spawnattr_getschedpolicy(&sa, NULL), "posix_spawnattr_getschedpolicy") - CHECK((posix_spawnattr_getschedpolicy(&sa, &pol) == 0 && pol == 1), "posix_spawnattr_getschedpolicy failed") - - sigset_t sst = 1; - sigset_t sst2 = 0; - CHECK_WHEN_NULL(posix_spawnattr_setsigdefault(NULL, &sst), "posix_spawnattr_setsigdefault") - CHECK_WHEN_NULL(posix_spawnattr_setsigdefault(&sa, NULL), "posix_spawnattr_setsigdefault") - CHECK((posix_spawnattr_setsigdefault(&sa, &sst) == 0), "posix_spawnattr_setsigdefault failed") - CHECK((posix_spawnattr_getsigdefault(&sa, &sst2) == 0 && sst2 == 1), "posix_spawnattr_getsigdefault failed") - CHECK_WHEN_NULL(posix_spawnattr_getsigdefault(NULL, &sst2), "posix_spawnattr_getsigdefault") - CHECK_WHEN_NULL(posix_spawnattr_getsigdefault(&sa, NULL), "posix_spawnattr_getsigdefault") - - sst = 3; - CHECK_WHEN_NULL(posix_spawnattr_setsigmask(NULL, &sst), "posix_spawnattr_setsigmask") - CHECK_WHEN_NULL(posix_spawnattr_setsigmask(&sa, NULL), "posix_spawnattr_setsigmask") - CHECK((posix_spawnattr_setsigmask(&sa, &sst) == 0), "posix_spawnattr_setsigmask failed") - CHECK_WHEN_NULL(posix_spawnattr_getsigmask(NULL, &sst2), "posix_spawnattr_getsigmask") - CHECK_WHEN_NULL(posix_spawnattr_getsigmask(&sa, NULL), "posix_spawnattr_getsigmask") - CHECK((posix_spawnattr_getsigmask(&sa, &sst2) == 0 && sst2 == 3), "posix_spawnattr_getsigmask failed") - - CHECK_WHEN_NULL(posix_spawnattr_setflags(NULL, 0), "posix_spawnattr_setflags") - CHECK((posix_spawnattr_setflags(&sa, 1) == 0), "posix_spawnattr_setflags failed") - short int pf = 0; - CHECK_WHEN_NULL(posix_spawnattr_getflags(NULL, &pf), "posix_spawnattr_getflags") - CHECK_WHEN_NULL(posix_spawnattr_getflags(&sa, NULL), "posix_spawnattr_getflags") - CHECK((posix_spawnattr_getflags(&sa, &pf) == 0 && pf == 1), "posix_spawnattr_getflags failed") - CHECK((posix_spawnattr_setflags(&sa, 7565) == EINVAL), "posix_spawnattr_setflags expected to fail when passing invalid bits") - - pid_t id = 0; - CHECK_WHEN_NULL(posix_spawnattr_setpgroup(NULL, 3), "posix_spawnattr_setpgroup") - CHECK((posix_spawnattr_setpgroup(&sa, 3) == 0), "posix_spawnattr_setpgroup failed") - CHECK_WHEN_NULL(posix_spawnattr_getpgroup(NULL, &id), "posix_spawnattr_getpgroup") - CHECK_WHEN_NULL(posix_spawnattr_getpgroup(&sa, NULL), "posix_spawnattr_getpgroup") - CHECK((posix_spawnattr_getpgroup(&sa, &id) == 0 && id == 3), "posix_spawnattr_getpgroup failed") -} diff --git a/tests/spawn/file_actions.c b/tests/spawn/file_actions.c new file mode 100644 index 0000000000..d22ef9bfdc --- /dev/null +++ b/tests/spawn/file_actions.c @@ -0,0 +1,75 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ERROR_IF(func, status, condition) \ + do { \ + if (status condition) { \ + fprintf(stderr, "%s:%s:%d: '%s' failed: %s (%d)\n", __FILE__, __func__, \ + __LINE__, #func, strerror(errno), errno); \ + _exit(EXIT_FAILURE); \ + } \ + } while (0) + +#define OPTIONALLY_ERROR(function, args, cond) \ + { \ + int x = function args; \ + if (!(x cond)) { \ + printf("%s failed with error: %s\n", #function, strerror(x)); \ + exit(EXIT_FAILURE); \ + } \ + } + +extern char **environ; + +int main() { + pid_t pid = 0; + char cwd[PATH_MAX]; + int status = 0; + char *__cwd = getcwd(cwd, PATH_MAX); + ERROR_IF(getcwd, __cwd, == NULL); + char target[PATH_MAX]; + strcpy(target, cwd); + strcat(target, "/hello"); + + // TEST: chdir and open + char *argv1[] = {"ls", target, NULL}; + posix_spawn_file_actions_t fa; + posix_spawn_file_actions_init(&fa); + status = mkdir("./hello", S_IRUSR | S_IWUSR); + ERROR_IF(mkdir, status, != 0); + OPTIONALLY_ERROR(posix_spawn_file_actions_addchdir, (&fa, "./hello"), == 0); + OPTIONALLY_ERROR(posix_spawn_file_actions_addopen, + (&fa, 2, "./hello.txt", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR), + == 0); + OPTIONALLY_ERROR(posix_spawnp, (&pid, "ls", &fa, NULL, argv1, environ), == 0); + assert(pid != 0); + waitpid(pid, NULL, 0); + OPTIONALLY_ERROR(posix_spawn_file_actions_destroy, (&fa), == 0); + + pid = 0; + + // TEST: close + argv1[0] = "/usr/bin/ls"; + OPTIONALLY_ERROR(posix_spawn_file_actions_init, (&fa), == 0); + OPTIONALLY_ERROR(posix_spawn_file_actions_addclose, (&fa, 1), == 0); + OPTIONALLY_ERROR(posix_spawn, + (&pid, "/usr/bin/ls", &fa, NULL, argv1, environ), == 0); + assert(pid != 0); + waitpid(pid, NULL, 0); + OPTIONALLY_ERROR(posix_spawn_file_actions_destroy, (&fa), == 0); + status = unlink("./hello/hello.txt"); + ERROR_IF(unlink, status, != 0); + status = rmdir("./hello"); + ERROR_IF(rmdir, status, != 0); +} diff --git a/tests/spawn/spawn_attr.c b/tests/spawn/spawn_attr.c new file mode 100644 index 0000000000..237c8ce181 --- /dev/null +++ b/tests/spawn/spawn_attr.c @@ -0,0 +1 @@ +int main() {} From 0d127d3652de622550911fc3d2776183349f36c7 Mon Sep 17 00:00:00 2001 From: R Aadarsh Date: Sun, 7 Jun 2026 12:49:39 +0530 Subject: [PATCH 23/29] Add more tests --- tests/expected/spawn/file_actions.stdout | 1 + tests/spawn/file_actions.c | 39 ++++++++++++++++++------ 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/tests/expected/spawn/file_actions.stdout b/tests/expected/spawn/file_actions.stdout index f0ad0dec66..83e53f3f62 100644 --- a/tests/expected/spawn/file_actions.stdout +++ b/tests/expected/spawn/file_actions.stdout @@ -1 +1,2 @@ hello.txt +HELLO REDOX diff --git a/tests/spawn/file_actions.c b/tests/spawn/file_actions.c index d22ef9bfdc..a3b670f5a9 100644 --- a/tests/spawn/file_actions.c +++ b/tests/spawn/file_actions.c @@ -1,8 +1,8 @@ +#include "../test_helpers.h" #include #include -#include #include -#include +#include #include #include #include @@ -12,14 +12,8 @@ #include #include -#define ERROR_IF(func, status, condition) \ - do { \ - if (status condition) { \ - fprintf(stderr, "%s:%s:%d: '%s' failed: %s (%d)\n", __FILE__, __func__, \ - __LINE__, #func, strerror(errno), errno); \ - _exit(EXIT_FAILURE); \ - } \ - } while (0) +static const char buf[] = "#include \nint main()\n{\nwrite(900, " + "\"HELLO REDOX\\n\", 12);\n}"; #define OPTIONALLY_ERROR(function, args, cond) \ { \ @@ -72,4 +66,29 @@ int main() { ERROR_IF(unlink, status, != 0); status = rmdir("./hello"); ERROR_IF(rmdir, status, != 0); + + // TEST: dup2 + pid = 0; + posix_spawn_file_actions_init(&fa); + posix_spawn_file_actions_adddup2(&fa, 1, 900); + + FILE *f = fopen("./dup2_check.c", "w"); + if (!f) { + printf("Failed to create dup2_check.c\n"); + exit(EXIT_FAILURE); + } + OPTIONALLY_ERROR(fwrite, (buf, sizeof(char), 67, f), == 67); + fclose(f); + char *argv2[] = {"gcc", "./dup2_check.c", "-o", "d.out", NULL}; + OPTIONALLY_ERROR(posix_spawnp, (&pid, "gcc", NULL, NULL, argv2, environ), + == 0); + waitpid(pid, NULL, 0); + assert(pid != 0); + pid = 0; + char *argv3[] = {"./d.out", NULL}; + OPTIONALLY_ERROR(posix_spawnp, (&pid, "./d.out", &fa, NULL, argv3, environ), + == 0); + assert(pid != 0); + waitpid(pid, NULL, 0); + posix_spawn_file_actions_destroy(&fa); } From 6d14437f34180e60921b93893f3c1d8825faaa19 Mon Sep 17 00:00:00 2001 From: R Aadarsh Date: Tue, 9 Jun 2026 07:59:13 +0530 Subject: [PATCH 24/29] Implement u/g id change based on executable's s(u/g)id mode bit --- src/header/spawn/spawn_attr.rs | 10 +++---- src/platform/mod.rs | 2 +- src/platform/redox/mod.rs | 52 +++++++++++++++++++--------------- 3 files changed, 35 insertions(+), 29 deletions(-) diff --git a/src/header/spawn/spawn_attr.rs b/src/header/spawn/spawn_attr.rs index ba1cd73546..6d46a54f12 100644 --- a/src/header/spawn/spawn_attr.rs +++ b/src/header/spawn/spawn_attr.rs @@ -33,12 +33,12 @@ pub const POSIX_SPAWN_SETSCHEDULER: c_short = 6; #[repr(C)] pub struct posix_spawnattr_t { - pub(crate) param: sched_param, - pub(crate) flags: c_short, - pub(crate) pgroup: c_int, + pub param: sched_param, + pub flags: c_short, + pub pgroup: c_int, policy: c_int, - sigdefault: sigset_t, - pub(crate) sigmask: sigset_t, + pub sigdefault: sigset_t, + pub sigmask: sigset_t, } #[unsafe(no_mangle)] diff --git a/src/platform/mod.rs b/src/platform/mod.rs index 36cf5c01b6..d9ec7cfee6 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -24,7 +24,7 @@ pub use self::sys::Sys; #[path = "linux/mod.rs"] pub(crate) mod sys; -// #[cfg(target_os = "redox")] +#[cfg(target_os = "redox")] #[path = "redox/mod.rs"] pub(crate) mod sys; diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index f496b4d2ab..14bfd7ea63 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -46,7 +46,7 @@ use crate::{ sys_random, sys_resource::{RLIM_INFINITY, rlimit, rusage}, sys_select::timeval, - sys_stat::{S_ISVTX, stat}, + sys_stat::{S_ISGID, S_ISUID, S_ISVTX, stat}, sys_statvfs::statvfs, sys_time::timezone, sys_utsname::{UTSLENGTH, utsname}, @@ -1212,7 +1212,11 @@ impl Pal for Sys { use crate::header::spawn::Flags; let child = redox_rt::proc::new_child_process(&redox_rt::proc::ForkArgs::Managed)?; - let executable = File::open(program, fcntl::O_RDONLY)?; + let executable = FdGuard::new(File::open(program, fcntl::O_RDONLY)?.fd as usize) + .to_upper() + .unwrap(); + let mut executable_stat = syscall::Stat::default(); + executable.fstat(&mut executable_stat)?; let original_cwd = path::clone_cwd().unwrap().to_string(); let mut cwd = original_cwd.clone(); let proc_fd = child.proc_fd.unwrap(); @@ -1222,10 +1226,8 @@ impl Pal for Sys { .dup(b"filetable")? .dup(b"copy")?; - { - let new_file_table = child.thr_fd.dup(b"current-filetable")?; - new_file_table.write(&file_table.as_raw_fd().to_ne_bytes())?; - } + let new_file_table = child.thr_fd.dup(b"current-filetable")?; + new_file_table.write(&file_table.as_raw_fd().to_ne_bytes())?; let mut args = Vec::new(); let mut envs = Vec::new(); @@ -1240,21 +1242,19 @@ impl Pal for Sys { } } - let mut program_name = String::new(); - - if let Some(ent) = dir_ent_name { + let program_name: String = if let Some(ent) = dir_ent_name { let mut binary = str::from_utf8(args[0]).unwrap().to_string(); binary.insert_str(0, "./"); - program_name = redox_path::canonicalize_using_cwd(Some(ent.as_str()), binary.as_str()) - .ok_or(Errno(ENOENT))?; + redox_path::canonicalize_using_cwd(Some(ent.as_str()), binary.as_str()) + .ok_or(Errno(ENOENT))? } else { - program_name = redox_path::canonicalize_using_cwd( + redox_path::canonicalize_using_cwd( Some(original_cwd.as_str()), str::from_utf8(args[0]).unwrap(), ) - .ok_or(Errno(ENOENT))?; - } + .ok_or(Errno(ENOENT))? + }; args[0] = program_name.as_bytes(); @@ -1320,6 +1320,8 @@ impl Pal for Sys { let mut extra_info = redox_rt::proc::ExtraInfo { cwd: Some(cwd.as_bytes()), + // Signals set to be ignored by the calling process + // must also be ignored by the child process sigignmask: redox_rt::signal::get_sigignmask_to_inherit(), sigprocmask: if let Some(fat) = fat && Flags::from_bits(fat.flags) @@ -1364,33 +1366,37 @@ impl Pal for Sys { redox_rt::sys::posix_setresugid( &Resugid { ruid: None, - euid: Some(parent_resugid.ruid), + euid: Some(if executable_stat.st_mode as mode_t & S_ISUID == S_ISUID { + executable_stat.st_uid + } else { + parent_resugid.ruid + }), suid: None, rgid: None, - egid: Some(parent_resugid.rgid), + egid: Some(if executable_stat.st_mode as mode_t & S_ISGID == S_ISGID { + executable_stat.st_gid + } else { + parent_resugid.rgid + }), sgid: None, }, Some(proc_fd.as_raw_fd()), )?; } - // todo: if set-uid bit is set, euid must be owner id - // todo: if set-gid bit is set, egid is file's gid - if flags.contains(Flags::POSIX_SPAWN_SETSIGMASK) { extra_info.sigprocmask = attr.sigmask; } - if flags.contains(Flags::POSIX_SPAWN_SETSIGDEF) { - todo!() - } + // if POSIX_SPAWN_SETSIGDEF flag is set, the signals specified in + // sigdefault must have default actions } if let Some(redox_rt::proc::FexecResult::Interp { path: interp_path, interp_override, }) = redox_rt::proc::fexec_impl( - FdGuard::new(executable.fd as usize).to_upper().unwrap(), + executable, &child.thr_fd, &proc_fd, program.to_bytes(), From 484fe42c0ef555e8decdac56df57868329083c3f Mon Sep 17 00:00:00 2001 From: R Aadarsh Date: Wed, 10 Jun 2026 16:03:16 +0530 Subject: [PATCH 25/29] * Add docs * Change safety signatures * Change tests * Correctly set u/g id --- src/header/spawn/file_actions.rs | 41 ++++- src/header/spawn/mod.rs | 16 ++ src/header/spawn/spawn_attr.rs | 159 +++++++++++++++--- src/platform/redox/mod.rs | 22 ++- tests/Makefile.tests.mk | 3 +- .../file_actions.stdout => spawn.stdout} | 0 tests/expected/spawn/spawn_attr.stdout | 0 tests/{spawn/file_actions.c => spawn.c} | 16 +- tests/spawn/spawn_attr.c | 1 - 9 files changed, 215 insertions(+), 43 deletions(-) rename tests/expected/{spawn/file_actions.stdout => spawn.stdout} (100%) delete mode 100644 tests/expected/spawn/spawn_attr.stdout rename tests/{spawn/file_actions.c => spawn.c} (88%) delete mode 100644 tests/spawn/spawn_attr.c diff --git a/src/header/spawn/file_actions.rs b/src/header/spawn/file_actions.rs index 9dd01f6e40..c9c34f9579 100644 --- a/src/header/spawn/file_actions.rs +++ b/src/header/spawn/file_actions.rs @@ -72,8 +72,11 @@ impl<'a> IntoIterator for &'a posix_spawn_file_actions_t { } } +/// See +/// +/// Panics if `file_actions` is `NULL`. #[unsafe(no_mangle)] -pub unsafe extern "C" fn posix_spawn_file_actions_init( +pub extern "C" fn posix_spawn_file_actions_init( file_actions: *mut posix_spawn_file_actions_t, ) -> c_int { if file_actions.is_null() { @@ -87,6 +90,12 @@ pub unsafe extern "C" fn posix_spawn_file_actions_init( 0 } +/// See +/// +/// Panics if `file_actions` is `NULL`. +/// +/// # Safety: +/// If `file_actions` is not `NULL`, then it must be a pointer to a `file_actions` object that was initialised by calling `posix_spawn_file_actions_init`. #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawn_file_actions_destroy( file_actions: *mut posix_spawn_file_actions_t, @@ -100,6 +109,12 @@ pub unsafe extern "C" fn posix_spawn_file_actions_destroy( 0 } +/// See +/// +/// Panics if `file_actions` is `NULL`. +/// +/// # Safety: +/// `path` must be a valid null-terminated C string. #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawn_file_actions_addopen( file_actions: *mut posix_spawn_file_actions_t, @@ -128,6 +143,12 @@ pub unsafe extern "C" fn posix_spawn_file_actions_addopen( 0 } +/// See +/// +/// Panics if `file_actions` is `NULL`. +/// +/// # Safety: +/// `file_actions` must be initialised. #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawn_file_actions_addclose( file_actions: *mut posix_spawn_file_actions_t, @@ -141,6 +162,12 @@ pub unsafe extern "C" fn posix_spawn_file_actions_addclose( 0 } +/// See +/// +/// Panics if `file_actions` is `NULL`. +/// +/// # Safety: +/// `file_actions` must be initialised and `path` must be a valid null-terminated C string. #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawn_file_actions_addchdir( file_actions: *mut posix_spawn_file_actions_t, @@ -160,6 +187,12 @@ pub unsafe extern "C" fn posix_spawn_file_actions_addchdir( 0 } +/// See +/// +/// Panics if `file_actions` is `NULL`. +/// +/// # Safety: +/// `file_actions` must be initialised. #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawn_file_actions_addfchdir( file_actions: *mut posix_spawn_file_actions_t, @@ -173,6 +206,12 @@ pub unsafe extern "C" fn posix_spawn_file_actions_addfchdir( 0 } +/// See +/// +/// Panics if `file_actions` is `NULL`. +/// +/// # Safety: +/// `file_actions` must be initialised. #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawn_file_actions_adddup2( file_actions: *mut posix_spawn_file_actions_t, diff --git a/src/header/spawn/mod.rs b/src/header/spawn/mod.rs index f7b6feca2f..6f5ac703c9 100644 --- a/src/header/spawn/mod.rs +++ b/src/header/spawn/mod.rs @@ -115,6 +115,14 @@ unsafe fn spawn( Ok(()) } +/// See +/// +/// `argv` must **not** be `NULL` and must contain atleast the program name. `path` must also be **not** `NULL`. Failure to ensure any of this will result in a panic. +/// +/// # Safety: +/// `file_actions` and `attrp` must either be `NULL` or be pointers to properly initialised objects. Doing otherwise is undefined behaviour. +/// +/// `path` and the elements in `argv` must be a pointers to valid null-terminated character arrays. Failure to ensure any of this will result in undefined behaviour. #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawn( pid: *mut pid_t, @@ -158,6 +166,14 @@ pub unsafe extern "C" fn posix_spawn( 0 } +/// See +/// +/// `argv` must **not** be `NULL` and must contain atleast the program name. `path` must also be **not** `NULL`. Failure to ensure any of this will result in a panic. +/// +/// # Safety: +/// `file_actions` and `attrp` must either be `NULL` or be pointers to properly initialised objects. Doing otherwise is undefined behaviour. +/// +/// `path` and the elements in `argv` must be a pointers to valid null-terminated character arrays. Failure to ensure any of this will result in undefined behaviour. #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawnp( pid: *mut pid_t, diff --git a/src/header/spawn/spawn_attr.rs b/src/header/spawn/spawn_attr.rs index 6d46a54f12..f2f7176023 100644 --- a/src/header/spawn/spawn_attr.rs +++ b/src/header/spawn/spawn_attr.rs @@ -41,41 +41,79 @@ pub struct posix_spawnattr_t { pub sigmask: sigset_t, } +/// See +/// +/// Panics is `attr` is `NULL`. #[unsafe(no_mangle)] -pub extern "C" fn posix_spawnattr_init(attr: &mut posix_spawnattr_t) -> c_int { - *attr = unsafe { zeroed() }; +pub extern "C" fn posix_spawnattr_init(attr: *mut posix_spawnattr_t) -> c_int { + unsafe { + let attr = attr.as_mut().expect("posix_spawnattr_t cannot be NULL"); + *attr = zeroed(); + } 0 } +/// See +/// +/// Panics is `attr` is `NULL`. +/// +/// # Safety: +/// `attr` must be a pointer to `posix_spawnattr_t` and must at least be initialised. #[unsafe(no_mangle)] -pub extern "C" fn posix_spawnattr_destroy(attr: &mut posix_spawnattr_t) -> c_int { - *attr = unsafe { zeroed() }; +pub unsafe extern "C" fn posix_spawnattr_destroy(attr: *mut posix_spawnattr_t) -> c_int { + unsafe { + let attr = attr.as_mut().expect("posix_spawnattr_t cannot be NULL"); + *attr = zeroed(); + } 0 } +/// See +/// +/// Panics if `attr` or `schedparam` is `NULL`. +/// +/// # Safety: +/// `attr` must be initialised. #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawnattr_setschedparam( - attr: &mut posix_spawnattr_t, - schedparam: &sched_param, + attr: *mut posix_spawnattr_t, + schedparam: *const sched_param, ) -> c_int { + let attr = unsafe { attr.as_mut().expect("posix_spawnattr_t cannot be NULL") }; + let schedparam = unsafe { schedparam.as_ref().expect("schedparam cannot be NULL") }; (*attr).param = *schedparam; 0 } +/// See +/// +/// Panics if `attr` or `schedparam` is `NULL`. +/// +/// # Safety: +/// `attr` must be initialised. #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawnattr_getschedparam( - attr: &posix_spawnattr_t, - schedparam: &mut sched_param, + attr: *const posix_spawnattr_t, + schedparam: *mut sched_param, ) -> c_int { + let attr = unsafe { attr.as_ref().expect("posix_spawnattr_t cannot be NULL") }; + let schedparam = unsafe { schedparam.as_mut().expect("schedparam cannot be NULL") }; *schedparam = (*attr).param; 0 } +/// See +/// +/// Panics if `attr` is `NULL`. +/// +/// # Safety: +/// `attr` must be initialised. #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawnattr_setschedpolicy( - attr: &mut posix_spawnattr_t, + attr: *mut posix_spawnattr_t, schedpolicy: c_int, ) -> c_int { + let attr = unsafe { attr.as_mut().expect("posix_spawnattr_t cannot be NULL") }; match schedpolicy { SCHED_FIFO | SCHED_RR | SCHED_OTHER => (*attr).policy = schedpolicy, _ => return EINVAL, @@ -84,56 +122,103 @@ pub unsafe extern "C" fn posix_spawnattr_setschedpolicy( 0 } +/// See +/// +/// Panics if `attr` or `schedpolicy` is `NULL`. +/// +/// # Safety: +/// `attr` must be initialised. #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawnattr_getschedpolicy( - attr: &posix_spawnattr_t, - schedpolicy: &mut c_int, + attr: *const posix_spawnattr_t, + schedpolicy: *mut c_int, ) -> c_int { + let attr = unsafe { attr.as_ref().expect("posix_spawnattr_t cannot be NULL") }; + let schedpolicy = unsafe { schedpolicy.as_mut().expect("schedpolicy cannot be NULL") }; *schedpolicy = (*attr).policy; 0 } +/// See +/// +/// Panics if `attr` or `sigdefault` is `NULL`. +/// +/// # Safety: +/// `attr` must be initialised. #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawnattr_setsigdefault( - attr: &mut posix_spawnattr_t, - sigdefault: &sigset_t, + attr: *mut posix_spawnattr_t, + sigdefault: *const sigset_t, ) -> c_int { + let attr = unsafe { attr.as_mut().expect("posix_spawnattr_t cannot be NULL") }; + let sigdefault = unsafe { sigdefault.as_ref().expect("sigdefault cannot be NULL") }; (*attr).sigdefault = *sigdefault; 0 } +/// See +/// +/// Panics if `attr` or `sigdefault` is `NULL`. +/// +/// # Safety: +/// `attr` must be initialised. #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawnattr_getsigdefault( - attr: &posix_spawnattr_t, - sigdefault: &mut sigset_t, + attr: *const posix_spawnattr_t, + sigdefault: *mut sigset_t, ) -> c_int { + let attr = unsafe { attr.as_ref().expect("posix_spawnattr_t cannot be NULL") }; + let sigdefault = unsafe { sigdefault.as_mut().expect("sigdefault cannot be NULL") }; *sigdefault = (*attr).sigdefault; 0 } +/// See +/// +/// Panics if `attr` or `sigmask` is `NULL`. +/// +/// # Safety: +/// `attr` must be initialised. #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawnattr_setsigmask( - attr: &mut posix_spawnattr_t, - sigmask: &sigset_t, + attr: *mut posix_spawnattr_t, + sigmask: *const sigset_t, ) -> c_int { + let attr = unsafe { attr.as_mut().expect("posix_spawnattr_t cannot be NULL") }; + let sigmask = unsafe { sigmask.as_ref().expect("sigmask cannot be NULL") }; (*attr).sigmask = *sigmask; 0 } +/// See +/// +/// Panics if `attr` or `sigmask` is `NULL`. +/// +/// # Safety: +/// `attr` must be initialised. #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawnattr_getsigmask( - attr: &posix_spawnattr_t, - sigmask: &mut sigset_t, + attr: *const posix_spawnattr_t, + sigmask: *mut sigset_t, ) -> c_int { + let attr = unsafe { attr.as_ref().expect("posix_spawnattr_t cannot be NULL") }; + let sigmask = unsafe { sigmask.as_mut().expect("sigmask cannot be NULL") }; *sigmask = (*attr).sigmask; 0 } +/// See +/// +/// Panics if `attr` is `NULL`. +/// +/// # Safety: +/// `attr` must be initialised. #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawnattr_setflags( - attr: &mut posix_spawnattr_t, + attr: *mut posix_spawnattr_t, flags: c_short, ) -> c_int { + let attr = unsafe { attr.as_mut().expect("posix_spawnattr_t cannot be NULL") }; match Flags::from_bits(flags) { Some(v) => (*attr).flags = v.bits(), None => { @@ -144,29 +229,53 @@ pub unsafe extern "C" fn posix_spawnattr_setflags( 0 } +/// See +/// +/// Panics if `attr` or `flags` is `NULL`. +/// +/// # Safety: +/// `attr` must be initialised. #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawnattr_getflags( - attr: &posix_spawnattr_t, - flags: &mut c_short, + attr: *const posix_spawnattr_t, + flags: *mut c_short, ) -> c_int { + let attr = unsafe { attr.as_ref().expect("posix_spawnattr_t cannot be NULL") }; + let flags = unsafe { flags.as_mut().expect("flags cannot be NULL") }; + *flags = (*attr).flags; 0 } +/// See +/// +/// Panics if `attr` is `NULL`. +/// +/// # Safety: +/// `attr` must be initialised. #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawnattr_setpgroup( - attr: &mut posix_spawnattr_t, + attr: *mut posix_spawnattr_t, pgroup: pid_t, ) -> c_int { + let attr = unsafe { attr.as_mut().expect("posix_spawnattr_t cannot be NULL") }; (*attr).pgroup = pgroup; 0 } +/// See +/// +/// Panics if `attr` or `pgroup` is `NULL`. +/// +/// # Safety: +/// `attr` must be initialised. #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawnattr_getpgroup( - attr: &posix_spawnattr_t, - pgroup: &mut pid_t, + attr: *const posix_spawnattr_t, + pgroup: *mut pid_t, ) -> c_int { + let attr = unsafe { attr.as_ref().expect("posix_spawnattr_t cannot be NULL") }; + let pgroup = unsafe { pgroup.as_mut().expect("pgroup cannot be NULL") }; *pgroup = (*attr).pgroup; 0 } diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index 14bfd7ea63..72fa26d513 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -1226,8 +1226,10 @@ impl Pal for Sys { .dup(b"filetable")? .dup(b"copy")?; - let new_file_table = child.thr_fd.dup(b"current-filetable")?; - new_file_table.write(&file_table.as_raw_fd().to_ne_bytes())?; + { + let new_file_table = child.thr_fd.dup(b"current-filetable")?; + new_file_table.write(&file_table.as_raw_fd().to_ne_bytes())?; + } let mut args = Vec::new(); let mut envs = Vec::new(); @@ -1360,7 +1362,7 @@ impl Pal for Sys { todo!() } - if flags.contains(Flags::POSIX_SPAWN_RESETIDS) { + let set_resugid = || -> Result<()> { let parent_resugid = redox_rt::sys::posix_getresugid(); redox_rt::sys::posix_setresugid( @@ -1368,21 +1370,29 @@ impl Pal for Sys { ruid: None, euid: Some(if executable_stat.st_mode as mode_t & S_ISUID == S_ISUID { executable_stat.st_uid - } else { + } else if flags.contains(Flags::POSIX_SPAWN_RESETIDS) { parent_resugid.ruid + } else { + return Ok(()); }), suid: None, rgid: None, egid: Some(if executable_stat.st_mode as mode_t & S_ISGID == S_ISGID { executable_stat.st_gid - } else { + } else if flags.contains(Flags::POSIX_SPAWN_RESETIDS) { parent_resugid.rgid + } else { + return Ok(()); }), sgid: None, }, Some(proc_fd.as_raw_fd()), )?; - } + + Ok(()) + }; + + set_resugid()?; if flags.contains(Flags::POSIX_SPAWN_SETSIGMASK) { extra_info.sigprocmask = attr.sigmask; diff --git a/tests/Makefile.tests.mk b/tests/Makefile.tests.mk index 5f62e1f8cc..ae0cd18e80 100644 --- a/tests/Makefile.tests.mk +++ b/tests/Makefile.tests.mk @@ -77,8 +77,6 @@ EXPECT_NAMES=\ sigaltstack \ signal \ sigsetjmp \ - spawn/file_actions \ - spawn/spawn_attr \ stdio/all \ stdio/buffer \ stdio/dprintf \ @@ -288,6 +286,7 @@ VARIED_NAMES=\ signals/sigset-4 \ signals/sigset-5 \ signals/sigset-9 \ + spawn \ stdio/ctermid \ stdio/tempnam \ stdio/tmpnam \ diff --git a/tests/expected/spawn/file_actions.stdout b/tests/expected/spawn.stdout similarity index 100% rename from tests/expected/spawn/file_actions.stdout rename to tests/expected/spawn.stdout diff --git a/tests/expected/spawn/spawn_attr.stdout b/tests/expected/spawn/spawn_attr.stdout deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/spawn/file_actions.c b/tests/spawn.c similarity index 88% rename from tests/spawn/file_actions.c rename to tests/spawn.c index a3b670f5a9..53338de813 100644 --- a/tests/spawn/file_actions.c +++ b/tests/spawn.c @@ -1,4 +1,4 @@ -#include "../test_helpers.h" +#include "./test_helpers.h" #include #include #include @@ -13,7 +13,7 @@ #include static const char buf[] = "#include \nint main()\n{\nwrite(900, " - "\"HELLO REDOX\\n\", 12);\n}"; + "\"hello_spawn REDOX\\n\", 12);\n}"; #define OPTIONALLY_ERROR(function, args, cond) \ { \ @@ -34,17 +34,17 @@ int main() { ERROR_IF(getcwd, __cwd, == NULL); char target[PATH_MAX]; strcpy(target, cwd); - strcat(target, "/hello"); + strcat(target, "/hello_spawn"); // TEST: chdir and open char *argv1[] = {"ls", target, NULL}; posix_spawn_file_actions_t fa; posix_spawn_file_actions_init(&fa); - status = mkdir("./hello", S_IRUSR | S_IWUSR); + status = mkdir("./hello_spawn", S_IRUSR | S_IWUSR); ERROR_IF(mkdir, status, != 0); - OPTIONALLY_ERROR(posix_spawn_file_actions_addchdir, (&fa, "./hello"), == 0); + OPTIONALLY_ERROR(posix_spawn_file_actions_addchdir, (&fa, "./hello_spawn"), == 0); OPTIONALLY_ERROR(posix_spawn_file_actions_addopen, - (&fa, 2, "./hello.txt", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR), + (&fa, 2, "./hello_spawn.txt", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR), == 0); OPTIONALLY_ERROR(posix_spawnp, (&pid, "ls", &fa, NULL, argv1, environ), == 0); assert(pid != 0); @@ -62,9 +62,9 @@ int main() { assert(pid != 0); waitpid(pid, NULL, 0); OPTIONALLY_ERROR(posix_spawn_file_actions_destroy, (&fa), == 0); - status = unlink("./hello/hello.txt"); + status = unlink("./hello_spawn/hello_spawn.txt"); ERROR_IF(unlink, status, != 0); - status = rmdir("./hello"); + status = rmdir("./hello_spawn"); ERROR_IF(rmdir, status, != 0); // TEST: dup2 diff --git a/tests/spawn/spawn_attr.c b/tests/spawn/spawn_attr.c deleted file mode 100644 index 237c8ce181..0000000000 --- a/tests/spawn/spawn_attr.c +++ /dev/null @@ -1 +0,0 @@ -int main() {} From 58fefac9f5691fa5f46339d89d66b296df2313f7 Mon Sep 17 00:00:00 2001 From: R Aadarsh Date: Wed, 10 Jun 2026 21:18:13 +0530 Subject: [PATCH 26/29] Enable sched params change --- Cargo.lock | 6 ++++-- Cargo.toml | 5 +---- redox-ioctl/Cargo.toml | 3 --- src/header/spawn/cbindgen.toml | 2 +- src/header/spawn/file_actions.rs | 10 ++-------- src/platform/redox/mod.rs | 27 +++++++++++++++++++++++---- 6 files changed, 31 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 402d28e3ac..47568e432f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -462,7 +462,8 @@ dependencies = [ [[package]] name = "redox_event" version = "0.4.7" -source = "git+https://gitlab.redox-os.org/EuclidDivisionLemma/event?branch=spawn#9126b9b1166e4633877feacf109720481e814e2e" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c07d0d6d291e3a951bd847b1cd4af32fc6243d64116cf7702838c02797688b7" dependencies = [ "bitflags", "libredox", @@ -472,7 +473,8 @@ dependencies = [ [[package]] name = "redox_syscall" version = "0.8.1" -source = "git+https://gitlab.redox-os.org/redox-os/syscall/#79cb6d9057642be31623677458a93aa88145864f" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b44b894f2a6e36457d665d1e08c3866add6ed5e70050c1b4ba8a8ddedb02ce7" dependencies = [ "bitflags", ] diff --git a/Cargo.toml b/Cargo.toml index 1b5f3d4312..7a7682e825 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -121,9 +121,7 @@ sc = "0.2.7" redox_syscall.workspace = true redox-rt = { path = "redox-rt" } redox-path.workspace = true -redox_event = { git = "https://gitlab.redox-os.org/EuclidDivisionLemma/event", branch = "spawn", default-features = false, features = [ - "redox_syscall", -] } +redox_event = { version = "0.4.7", default-features = false, features = ["redox_syscall"] } ioslice.workspace = true redox-ioctl = { path = "redox-ioctl" } redox_protocols.workspace = true @@ -145,4 +143,3 @@ panic = "abort" [patch.crates-io] cc-11 = { git = "https://github.com/tea/cc-rs", branch = "riscv-abi-arch-fix", package = "cc" } -redox_syscall = {git = "https://gitlab.redox-os.org/redox-os/syscall/"} diff --git a/redox-ioctl/Cargo.toml b/redox-ioctl/Cargo.toml index 88778d300c..5c89dfd6b6 100644 --- a/redox-ioctl/Cargo.toml +++ b/redox-ioctl/Cargo.toml @@ -10,7 +10,4 @@ description = "Ioctl definitions and (de)serialization for Redox" drm-sys = "0.8.0" redox_syscall = "0.8.1" -[patch.crates-io] -redox_syscall = {git = "https://gitlab.redox-os.org/EuclidDivisionLemma/syscall/", branch = "spawn"} - [features] diff --git a/src/header/spawn/cbindgen.toml b/src/header/spawn/cbindgen.toml index fdf8013426..baba99bf2f 100644 --- a/src/header/spawn/cbindgen.toml +++ b/src/header/spawn/cbindgen.toml @@ -1,4 +1,4 @@ -sys_includes = ["sched.h", "bits/sigset-t.h", "bits/mode-t.h"] +sys_includes = ["sched.h", "bits/sigset-t.h", "bits/mode-t.h", "bits/size-t.h"] include_guard = "_RELIBC_SPAWN_H" language = "C" cpp_compat = true diff --git a/src/header/spawn/file_actions.rs b/src/header/spawn/file_actions.rs index c9c34f9579..74b84e5509 100644 --- a/src/header/spawn/file_actions.rs +++ b/src/header/spawn/file_actions.rs @@ -3,7 +3,7 @@ use core::ptr; use crate::{ header::errno::EBADF, - platform::types::{c_char, c_int, mode_t, size_t}, + platform::types::{c_char, c_int, c_uchar, mode_t, size_t}, }; #[derive(Debug, Clone)] @@ -25,7 +25,7 @@ struct FileActions(Vec); #[repr(C)] #[derive(Debug, Clone, Copy)] pub struct posix_spawn_file_actions_t { - __relibc_internal_size: [u8; 24], + __relibc_internal_size: [c_uchar; 24], __relibc_internal_align: size_t, } @@ -124,9 +124,6 @@ pub unsafe extern "C" fn posix_spawn_file_actions_addopen( mode: mode_t, ) -> c_int { let file_actions = unsafe { file_actions.as_mut().expect("file_actions cannot be NULL") }; - if path.is_null() { - panic!("path cannot be NULL"); - } if fd < 0 { return EBADF; } @@ -174,9 +171,6 @@ pub unsafe extern "C" fn posix_spawn_file_actions_addchdir( path: *const c_char, ) -> c_int { let file_actions = unsafe { file_actions.as_mut().expect("file_actions cannot be NULL") }; - if path.is_null() { - panic!("path cannot be NULL"); - } file_actions.add_action(Action::Chdir(unsafe { if path.is_null() { CString::new("").unwrap() diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index 72fa26d513..6cdb71f37d 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -44,7 +44,7 @@ use crate::{ sys_file, sys_mman::{MAP_ANONYMOUS, PROT_READ, PROT_WRITE}, sys_random, - sys_resource::{RLIM_INFINITY, rlimit, rusage}, + sys_resource::{PRIO_PROCESS, RLIM_INFINITY, rlimit, rusage, setpriority}, sys_select::timeval, sys_stat::{S_ISGID, S_ISUID, S_ISVTX, stat}, sys_statvfs::statvfs, @@ -60,7 +60,7 @@ use crate::{ ld_so::tcb::OsSpecific, out::Out, platform::{ - free, + ERRNO, free, sys::timer::{TIMERS, timer_routine, timer_update_wake_time}, }, sync::rwlock::RwLock, @@ -1358,8 +1358,27 @@ impl Pal for Sys { } } - if flags.contains(Flags::POSIX_SPAWN_SETSCHEDPARAM) { - todo!() + let set_schedparam = || -> Result<()> { + if setpriority( + PRIO_PROCESS, + proc_fd.as_raw_fd() as id_t, + attr.param.sched_priority, + ) as usize + != 0 + { + Err(Errno(ERRNO.get())) + } else { + Ok(()) + } + }; + let set_scheduler = || -> Result<()> { todo!() }; + + // scheduling paramters must be set regardless of whether the flag POSIX_SPAWN_SETSCHEDPARAM is set + if flags.contains(Flags::POSIX_SPAWN_SETSCHEDULER) { + set_schedparam()?; + set_scheduler()?; + } else if flags.contains(Flags::POSIX_SPAWN_SETSCHEDPARAM) { + set_schedparam()?; } let set_resugid = || -> Result<()> { From 5891ae023e6964dafe38f1f635f334df75ed92b6 Mon Sep 17 00:00:00 2001 From: R Aadarsh Date: Mon, 15 Jun 2026 10:51:49 +0530 Subject: [PATCH 27/29] Change number of characters --- tests/spawn.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/spawn.c b/tests/spawn.c index 53338de813..26cd6220fc 100644 --- a/tests/spawn.c +++ b/tests/spawn.c @@ -13,7 +13,7 @@ #include static const char buf[] = "#include \nint main()\n{\nwrite(900, " - "\"hello_spawn REDOX\\n\", 12);\n}"; + "\"hello_spawn REDOX\\n\", 18);\n}"; #define OPTIONALLY_ERROR(function, args, cond) \ { \ @@ -42,10 +42,11 @@ int main() { posix_spawn_file_actions_init(&fa); status = mkdir("./hello_spawn", S_IRUSR | S_IWUSR); ERROR_IF(mkdir, status, != 0); - OPTIONALLY_ERROR(posix_spawn_file_actions_addchdir, (&fa, "./hello_spawn"), == 0); - OPTIONALLY_ERROR(posix_spawn_file_actions_addopen, - (&fa, 2, "./hello_spawn.txt", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR), + OPTIONALLY_ERROR(posix_spawn_file_actions_addchdir, (&fa, "./hello_spawn"), == 0); + OPTIONALLY_ERROR( + posix_spawn_file_actions_addopen, + (&fa, 2, "./hello_spawn.txt", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR), == 0); OPTIONALLY_ERROR(posix_spawnp, (&pid, "ls", &fa, NULL, argv1, environ), == 0); assert(pid != 0); waitpid(pid, NULL, 0); @@ -77,7 +78,7 @@ int main() { printf("Failed to create dup2_check.c\n"); exit(EXIT_FAILURE); } - OPTIONALLY_ERROR(fwrite, (buf, sizeof(char), 67, f), == 67); + OPTIONALLY_ERROR(fwrite, (buf, sizeof(char), 74, f), == 74); fclose(f); char *argv2[] = {"gcc", "./dup2_check.c", "-o", "d.out", NULL}; OPTIONALLY_ERROR(posix_spawnp, (&pid, "gcc", NULL, NULL, argv2, environ), From 1ff7d7bba08808f59c697da7c623b555ee81d9b7 Mon Sep 17 00:00:00 2001 From: R Aadarsh Date: Mon, 15 Jun 2026 11:15:18 +0530 Subject: [PATCH 28/29] * Fix pgroup inheritance * Remove unnecessary nesting * Make the child process explicitly inherit parent's u/g id --- src/platform/redox/mod.rs | 79 +++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 44 deletions(-) diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index 6cdb71f37d..0595b74bfd 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -1320,7 +1320,7 @@ impl Pal for Sys { &[syscall::flag::FileTableVerb::CloseCloExec as u64], )?; - let mut extra_info = redox_rt::proc::ExtraInfo { + let extra_info = redox_rt::proc::ExtraInfo { cwd: Some(cwd.as_bytes()), // Signals set to be ignored by the calling process // must also be ignored by the child process @@ -1347,15 +1347,16 @@ impl Pal for Sys { if let Some(attr) = fat { let flags = Flags::from_bits(attr.flags).ok_or(Errno(EINVAL))?; - if flags.contains(Flags::POSIX_SPAWN_SETPGROUP) { - if attr.pgroup != 0 { - redox_rt::sys::posix_setpgid( - proc_fd.as_raw_fd(), - usize::try_from(attr.pgroup).map_err(|_| Errno(EINVAL))?, - )?; - } else { - redox_rt::sys::posix_setpgid(proc_fd.as_raw_fd(), proc_fd.as_raw_fd())?; - } + if flags.contains(Flags::POSIX_SPAWN_SETPGROUP) && attr.pgroup != 0 { + redox_rt::sys::posix_setpgid( + proc_fd.as_raw_fd(), + usize::try_from(attr.pgroup).map_err(|_| Errno(EINVAL))?, + )?; + } else { + redox_rt::sys::posix_setpgid( + proc_fd.as_raw_fd(), + redox_rt::sys::posix_getpgid(proc_fd.as_raw_fd())?, + )?; } let set_schedparam = || -> Result<()> { @@ -1381,41 +1382,31 @@ impl Pal for Sys { set_schedparam()?; } - let set_resugid = || -> Result<()> { - let parent_resugid = redox_rt::sys::posix_getresugid(); + let parent_resugid = redox_rt::sys::posix_getresugid(); - redox_rt::sys::posix_setresugid( - &Resugid { - ruid: None, - euid: Some(if executable_stat.st_mode as mode_t & S_ISUID == S_ISUID { - executable_stat.st_uid - } else if flags.contains(Flags::POSIX_SPAWN_RESETIDS) { - parent_resugid.ruid - } else { - return Ok(()); - }), - suid: None, - rgid: None, - egid: Some(if executable_stat.st_mode as mode_t & S_ISGID == S_ISGID { - executable_stat.st_gid - } else if flags.contains(Flags::POSIX_SPAWN_RESETIDS) { - parent_resugid.rgid - } else { - return Ok(()); - }), - sgid: None, - }, - Some(proc_fd.as_raw_fd()), - )?; - - Ok(()) - }; - - set_resugid()?; - - if flags.contains(Flags::POSIX_SPAWN_SETSIGMASK) { - extra_info.sigprocmask = attr.sigmask; - } + redox_rt::sys::posix_setresugid( + &Resugid { + ruid: None, + euid: Some(if executable_stat.st_mode as mode_t & S_ISUID == S_ISUID { + executable_stat.st_uid + } else if flags.contains(Flags::POSIX_SPAWN_RESETIDS) { + parent_resugid.ruid + } else { + parent_resugid.euid + }), + suid: None, + rgid: None, + egid: Some(if executable_stat.st_mode as mode_t & S_ISGID == S_ISGID { + executable_stat.st_gid + } else if flags.contains(Flags::POSIX_SPAWN_RESETIDS) { + parent_resugid.rgid + } else { + parent_resugid.egid + }), + sgid: None, + }, + Some(proc_fd.as_raw_fd()), + )?; // if POSIX_SPAWN_SETSIGDEF flag is set, the signals specified in // sigdefault must have default actions From 789be35518ad7a4dd4576eed898ea4abb61329be Mon Sep 17 00:00:00 2001 From: R Aadarsh Date: Mon, 15 Jun 2026 12:15:31 +0530 Subject: [PATCH 29/29] Add comments to `cbindgen.toml` --- src/header/spawn/cbindgen.toml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/header/spawn/cbindgen.toml b/src/header/spawn/cbindgen.toml index baba99bf2f..0a66991526 100644 --- a/src/header/spawn/cbindgen.toml +++ b/src/header/spawn/cbindgen.toml @@ -1,3 +1,13 @@ +# POSIX header spec: https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/spawn.h.html +# +# Spec quotations relating to includes: +# - "The header shall define the mode_t and pid_t types as described in ." +# - "The header shall define the sigset_t type as described in ." +# - "The tag sched_param shall be declared as naming an incomplete structure type, the contents of which are described in the header." +# - "Inclusion of the header may make visible symbols defined in the and headers." +# +# shed.h brings in pid_t +# size_t would have been brought in by signal.h so we can include it here directly sys_includes = ["sched.h", "bits/sigset-t.h", "bits/mode-t.h", "bits/size-t.h"] include_guard = "_RELIBC_SPAWN_H" language = "C"