Files
RedBear-OS/src/header/spawn/mod.rs
T
2026-06-20 12:31:32 +07:00

140 lines
4.6 KiB
Rust

//! `spawn.h` implementation
//!
//! See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/spawn.h.html>.
mod file_actions;
mod spawn_attr;
pub use file_actions::{Action, posix_spawn_file_actions_t};
pub use spawn_attr::{Flags, posix_spawnattr_t};
use crate::{
c_str::CStr,
header::{
errno,
stdlib::getenv,
unistd::{F_OK, path::PathSearchIter},
},
iter::NulTerminated,
platform::{
self, Pal, Sys,
types::{c_char, c_int, pid_t},
},
};
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_spawn.html>.
///
/// Creates a new process (child process) from the specified process image. The
/// `path` argument is a pathname that identifies the new process image file to
/// execute.
///
/// Returns the process ID of the child process to the parent process, in the
/// variable pointed to by a non-null `pid` argument, and shall return `0` as
/// the function return value. Upon error, an error number shall be returned
/// as the function return value.
///
/// # Panics
/// `argv` must **not** be `NULL` and must contain atleast the program name.
/// `path` must also **not** be `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,
path: *const c_char,
file_actions: *const posix_spawn_file_actions_t,
attrp: *const posix_spawnattr_t,
argv: *const *mut c_char,
envp: *const *mut c_char,
) -> c_int {
let argv = {
if argv.is_null() || unsafe { (*argv).is_null() } {
return errno::EINVAL;
}
unsafe { NulTerminated::new(argv).unwrap() }
};
let envp = unsafe { NulTerminated::new(envp) };
let program = unsafe { CStr::from_ptr(path) };
match unsafe {
platform::Sys::spawn(program, file_actions.as_ref(), attrp.as_ref(), argv, envp)
} {
Ok(v) => {
if let Some(pid) = unsafe { pid.as_mut() } {
*pid = v;
}
0
}
Err(e) => e.0,
}
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_spawnp.html>.
///
/// Creates a new process (child process) from the specified process image. The
/// `file` argument is used to construct a pathname that identifies the new
/// process image file.
///
/// Returns the process ID of the child process to the parent process, in the
/// variable pointed to by a non-null `pid` argument, and shall return `0` as
/// the function return value. Upon error, an error number shall be returned
/// as the function return value.
///
/// # Panics
/// `argv` must **not** be `NULL` and must contain atleast the program name.
/// `file` must also **not** be `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.
///
/// `file` 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,
file: *const c_char,
file_actions: *const posix_spawn_file_actions_t,
attrp: *const posix_spawnattr_t,
argv: *const *mut c_char,
envp: *const *mut c_char,
) -> c_int {
let program = unsafe { CStr::from_ptr(file) };
if program.contains(b'/') {
return unsafe { posix_spawn(pid, file, file_actions, attrp, argv, envp) };
}
let path_env = unsafe { getenv(c"PATH".as_ptr()) };
if path_env.is_null() {
return errno::ENOENT;
}
let path_env = unsafe { CStr::from_ptr(path_env) };
for program_buf in PathSearchIter::new(&program.to_bytes(), &path_env) {
// SAFETY: CStr::from_ptr().to_bytes() always stop at null, no need to check again
let program_c = unsafe { CStr::from_bytes_with_nul_unchecked(program_buf.as_slice()) };
if Sys::access(program_c, F_OK).is_err() {
continue;
}
return unsafe {
posix_spawn(
pid,
program_buf.as_ptr() as *mut _,
file_actions,
attrp,
argv,
envp,
)
};
}
errno::ENOENT
}