Add arrayvec and split PATH env logic
This commit is contained in:
Generated
+7
@@ -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",
|
||||
|
||||
@@ -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"] }
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user