Add arrayvec and split PATH env logic

This commit is contained in:
Wildan M
2026-06-20 06:38:50 +07:00
parent dd8394865d
commit fdcc92cd3b
4 changed files with 60 additions and 16 deletions
Generated
+7
View File
@@ -14,6 +14,12 @@ dependencies = [
"password-hash",
]
[[package]]
name = "arrayvec"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
[[package]]
name = "autocfg"
version = "1.5.1"
@@ -484,6 +490,7 @@ name = "relibc"
version = "0.2.5"
dependencies = [
"argon2",
"arrayvec",
"base64ct",
"bcrypt-pbkdf",
"bitflags",
+1
View File
@@ -76,6 +76,7 @@ cc = "1"
[dependencies]
bitflags.workspace = true
arrayvec = { version = "0.7.6", default-features = false }
cbitset = "0.2"
posix-regex = { version = "0.1.4", features = ["no_std"] }
+8 -16
View File
@@ -25,7 +25,7 @@ use crate::{
sys_select::timeval,
sys_time, sys_utsname, termios,
time::timespec,
unistd::alarm::alarm_timespec,
unistd::{alarm::alarm_timespec, path::PathSearchIter},
},
out::Out,
platform::{
@@ -57,6 +57,7 @@ mod alarm;
mod brk;
mod getopt;
mod getpass;
pub mod path;
mod pathconf;
#[cfg(target_os = "linux")]
pub mod syscall;
@@ -369,16 +370,13 @@ pub unsafe extern "C" fn fexecve(
.or_minus_one_errno()
}
const PATH_SEPARATOR: u8 = b':';
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/exec.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn execvp(file: *const c_char, argv: *const *mut c_char) -> c_int {
let file = unsafe { CStr::from_ptr(file) };
let file_bytes = file.to_bytes();
if file.to_bytes().contains(&b'/')
|| (cfg!(target_os = "redox") && file.to_bytes().contains(&b':'))
{
if file_bytes.contains(&b'/') || (cfg!(target_os = "redox") && file_bytes.contains(&b':')) {
unsafe { execv(file.as_ptr(), argv) }
} else {
let mut error = errno::ENOENT;
@@ -386,16 +384,10 @@ pub unsafe extern "C" fn execvp(file: *const c_char, argv: *const *mut c_char) -
let path_env = unsafe { getenv(c"PATH".as_ptr()) };
if !path_env.is_null() {
let path_env = unsafe { CStr::from_ptr(path_env) };
for path in path_env.to_bytes().split(|&b| b == PATH_SEPARATOR) {
let file = file.to_bytes();
let length = file.len() + path.len() + 2;
let mut program = alloc::vec::Vec::with_capacity(length);
program.extend_from_slice(path);
program.push(b'/');
program.extend_from_slice(file);
program.push(b'\0');
let program_c = CStr::from_bytes_with_nul(&program).unwrap();
for program_buf in PathSearchIter::new(&file.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()) };
unsafe { execv(program_c.as_ptr(), argv) };
match platform::ERRNO.get() {
+44
View File
@@ -0,0 +1,44 @@
use core::slice::Split;
use arrayvec::ArrayVec;
use crate::{c_str::CStr, header::limits::PATH_MAX};
pub struct PathSearchIter<'a> {
file_bytes: &'a [u8],
path_splits: Split<'a, u8, fn(&u8) -> bool>,
}
const PATH_SEPARATOR: u8 = b':';
impl<'a> PathSearchIter<'a> {
/// Construct a new PATH parser.
/// Safety: file must have no slashes
pub fn new(file_bytes: &'a [u8], path_env: &'a CStr) -> Self {
Self {
file_bytes,
path_splits: path_env.to_bytes().split(|&b| b == PATH_SEPARATOR),
}
}
}
impl<'a> Iterator for PathSearchIter<'a> {
type Item = ArrayVec<u8, PATH_MAX>;
fn next(&mut self) -> Option<Self::Item> {
for path in &mut self.path_splits {
let len = path.len() + self.file_bytes.len() + 2;
if len > PATH_MAX {
continue;
}
let mut program: ArrayVec<u8, PATH_MAX> = ArrayVec::new();
program.try_extend_from_slice(path).unwrap();
program.push(b'/');
program.try_extend_from_slice(self.file_bytes).unwrap();
program.push(b'\0');
return Some(program);
}
None
}
}