mirror of
https://github.com/Noratrieb/libuwuc.git
synced 2026-01-14 19:55:07 +01:00
getenv works
This commit is contained in:
parent
0c69d7db10
commit
9464ea4829
7 changed files with 206 additions and 33 deletions
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
use core::ffi::c_char;
|
use core::ffi::c_char;
|
||||||
|
|
||||||
use libuwuc::println;
|
use libuwuc::{println, utils::SharedThinCstr};
|
||||||
|
|
||||||
extern crate libuwuc;
|
extern crate libuwuc;
|
||||||
|
|
||||||
|
|
@ -23,5 +23,15 @@ fn handler(arg: &core::panic::PanicInfo) -> ! {
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
extern "C" fn main(_argc: i32, _argv: *const *const c_char) -> i32 {
|
extern "C" fn main(_argc: i32, _argv: *const *const c_char) -> i32 {
|
||||||
println!("Hello, world!");
|
println!("Hello, world!");
|
||||||
|
let pwd = libuwuc::env::getenv(SharedThinCstr::from_array(b"PWD\0"));
|
||||||
|
println!("PWD={pwd:?}");
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// libcore seems to require this symbol, even though it's unused.
|
||||||
|
#[no_mangle]
|
||||||
|
fn rust_eh_personality() {
|
||||||
|
unsafe {
|
||||||
|
libuwuc::trap!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
132
src/env.rs
132
src/env.rs
|
|
@ -1,35 +1,38 @@
|
||||||
use core::ffi::CStr;
|
use core::{
|
||||||
|
ffi::{c_char, CStr},
|
||||||
|
iter,
|
||||||
|
ptr::NonNull,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{println, utils::SharedThinCstr};
|
use crate::{println, utils::SharedThinCstr};
|
||||||
|
|
||||||
mod global {
|
mod global {
|
||||||
use core::cell::UnsafeCell;
|
use core::{cell::UnsafeCell, ptr::NonNull};
|
||||||
|
|
||||||
use crate::utils::{SharedThinCstr, SyncUnsafeCell};
|
use crate::utils::{SharedThinCstr, SyncUnsafeCell};
|
||||||
|
|
||||||
use super::EnvP;
|
use super::EnvP;
|
||||||
|
|
||||||
static ENVP: SyncUnsafeCell<EnvP> =
|
static ENVP: SyncUnsafeCell<EnvP> = SyncUnsafeCell(UnsafeCell::new(EnvP(None)));
|
||||||
SyncUnsafeCell(UnsafeCell::new(EnvP(core::ptr::null_mut())));
|
|
||||||
|
|
||||||
pub(super) unsafe fn init(envp: *mut SharedThinCstr) {
|
pub(super) unsafe fn init(envp: *mut Option<SharedThinCstr>) {
|
||||||
assert!((*ENVP.0.get()).0.is_null());
|
assert!((*ENVP.0.get()).0.is_none());
|
||||||
*ENVP.0.get() = EnvP(envp);
|
*ENVP.0.get() = EnvP(Some(NonNull::new(envp).unwrap()));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn get() -> EnvP {
|
pub(super) fn get() -> EnvP {
|
||||||
let ptr = unsafe { *ENVP.0.get() };
|
let ptr = unsafe { *ENVP.0.get() };
|
||||||
assert!(!ptr.0.is_null());
|
assert!(ptr.0.is_some());
|
||||||
ptr
|
ptr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) unsafe fn init(envp: *mut SharedThinCstr) {
|
pub(crate) unsafe fn init(envp: *mut Option<SharedThinCstr>) {
|
||||||
global::init(envp);
|
global::init(envp);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
struct EnvP(*mut SharedThinCstr);
|
struct EnvP(Option<NonNull<Option<SharedThinCstr>>>);
|
||||||
|
|
||||||
unsafe impl Sync for EnvP {}
|
unsafe impl Sync for EnvP {}
|
||||||
|
|
||||||
|
|
@ -38,13 +41,12 @@ impl Iterator for EnvP {
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let value: SharedThinCstr = self.0.read();
|
let value: Option<SharedThinCstr> = self.0.unwrap().as_ptr().read();
|
||||||
if value.0.is_null() {
|
|
||||||
None
|
value.map(|value| {
|
||||||
} else {
|
self.0 = Some(NonNull::new_unchecked(self.0.unwrap().as_ptr().add(1)));
|
||||||
self.0 = self.0.add(1);
|
value
|
||||||
Some(value)
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -57,3 +59,99 @@ pub(crate) fn debug_env() {
|
||||||
});
|
});
|
||||||
println!("end vars");
|
println!("end vars");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn getenv(name: SharedThinCstr) -> Option<SharedThinCstr> {
|
||||||
|
getenv_inner(global::get(), name)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getenv_inner(mut envp: EnvP, name: SharedThinCstr) -> Option<SharedThinCstr> {
|
||||||
|
let mut eq_idx = 0;
|
||||||
|
envp.find(|env| {
|
||||||
|
// Find ENV
|
||||||
|
// EN=x
|
||||||
|
// ENV=x <- this one
|
||||||
|
// ENVNO=x
|
||||||
|
|
||||||
|
let mut name_iter = name.into_iter();
|
||||||
|
let mut env_iter = env.into_iter();
|
||||||
|
eq_idx = 0;
|
||||||
|
loop {
|
||||||
|
let name = name_iter.next().map(|c| c as u8);
|
||||||
|
let env = env_iter.next().map(|c| c as u8);
|
||||||
|
if let (None, Some(b'=')) = (name, env) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if name.is_none() || env == Some(b'=') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
eq_idx += 1;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map(|elem| {
|
||||||
|
let value_idx = eq_idx + 1;
|
||||||
|
unsafe { elem.add(value_idx) }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use core::ptr::NonNull;
|
||||||
|
use std::string::ToString;
|
||||||
|
use std::{ffi::CString, vec::Vec};
|
||||||
|
|
||||||
|
use crate::utils::SharedThinCstr;
|
||||||
|
|
||||||
|
use super::EnvP;
|
||||||
|
|
||||||
|
fn cstr(s: &str) -> SharedThinCstr {
|
||||||
|
assert_eq!(s.as_bytes()[s.len() - 1], 0);
|
||||||
|
unsafe { SharedThinCstr::from_ptr(NonNull::new(s.as_ptr() as _).unwrap()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_envp(env: &[&str], f: impl FnOnce(EnvP)) {
|
||||||
|
let cstrs = env
|
||||||
|
.iter()
|
||||||
|
.map(|s| CString::new(s.to_string()).unwrap())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let mut envs: Vec<Option<SharedThinCstr>> = cstrs
|
||||||
|
.iter()
|
||||||
|
.map(|cstr| unsafe {
|
||||||
|
Some(SharedThinCstr::from_ptr(
|
||||||
|
NonNull::new(cstr.as_ptr() as _).unwrap(),
|
||||||
|
))
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
envs.push(None);
|
||||||
|
|
||||||
|
let envp = EnvP(Some(NonNull::new(envs.as_ptr() as _).unwrap()));
|
||||||
|
f(envp)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn getenv_exact_first() {
|
||||||
|
with_envp(&["UWU=a"], |envp| {
|
||||||
|
assert_eq!(
|
||||||
|
super::getenv_inner(envp, cstr("UWU\0")).unwrap(),
|
||||||
|
cstr("a\0")
|
||||||
|
);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn getenv_previous_mismatches() {
|
||||||
|
with_envp(&["UW=a", "UWUU=b", "UWU=c"], |envp| {
|
||||||
|
assert_eq!(
|
||||||
|
super::getenv_inner(envp, cstr("UWU\0")).unwrap(),
|
||||||
|
cstr("c\0")
|
||||||
|
);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn getenv_name_long() {
|
||||||
|
with_envp(&["U=w"], |envp| {
|
||||||
|
assert_eq!(super::getenv_inner(envp, cstr("LONG_NAME\0")), None);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,16 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![warn(unreachable_pub)]
|
#![warn(unreachable_pub)]
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
extern crate std;
|
||||||
|
|
||||||
mod basic_mem;
|
mod basic_mem;
|
||||||
mod env;
|
pub mod env;
|
||||||
pub mod io;
|
pub mod io;
|
||||||
pub mod start;
|
pub mod start;
|
||||||
mod stubs;
|
mod stubs;
|
||||||
mod sys;
|
mod sys;
|
||||||
mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
pub mod syscall {
|
pub mod syscall {
|
||||||
pub use crate::sys::syscall::*;
|
pub use crate::sys::syscall::*;
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use crate::utils::SharedThinCstr;
|
||||||
/// The entrypoint of the program.
|
/// The entrypoint of the program.
|
||||||
/// This is called by a bit of assembly handling architecture-specific _start.
|
/// This is called by a bit of assembly handling architecture-specific _start.
|
||||||
pub(crate) unsafe extern "C" fn start(argc: u64, argv: *const *const c_char, rsp: u64) -> ! {
|
pub(crate) unsafe extern "C" fn start(argc: u64, argv: *const *const c_char, rsp: u64) -> ! {
|
||||||
let envp = (8 + 8 * argc + rsp + 8) as *mut SharedThinCstr;
|
let envp = (8 + 8 * argc + rsp + 8) as *mut Option<SharedThinCstr>;
|
||||||
|
|
||||||
crate::env::init(envp);
|
crate::env::init(envp);
|
||||||
|
|
||||||
|
|
@ -13,7 +13,7 @@ pub(crate) unsafe extern "C" fn start(argc: u64, argv: *const *const c_char, rsp
|
||||||
fn main(argc: c_int, argv: *const *const c_char) -> c_int;
|
fn main(argc: c_int, argv: *const *const c_char) -> c_int;
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::env::debug_env();
|
// crate::env::debug_env();
|
||||||
|
|
||||||
let result = main(argc as i32, argv);
|
let result = main(argc as i32, argv);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
// libcore seems to require this symbol, even though it's unused.
|
|
||||||
#[no_mangle]
|
|
||||||
fn rust_eh_personality() {
|
|
||||||
unsafe {
|
|
||||||
crate::sys::helpers::trap!();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
#[macro_export]
|
||||||
macro_rules! trap {
|
macro_rules! trap {
|
||||||
() => {
|
() => {
|
||||||
::core::arch::asm!("ud2");
|
::core::arch::asm!("ud2");
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
use core::{
|
use core::{
|
||||||
cell::UnsafeCell,
|
cell::UnsafeCell,
|
||||||
ffi::{c_char, CStr},
|
ffi::{c_char, CStr},
|
||||||
|
fmt::Debug,
|
||||||
|
ptr::NonNull,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
|
|
@ -9,18 +11,84 @@ pub(crate) struct SyncUnsafeCell<T>(pub(crate) UnsafeCell<T>);
|
||||||
|
|
||||||
unsafe impl<T: Sync> Sync for SyncUnsafeCell<T> {}
|
unsafe impl<T: Sync> Sync for SyncUnsafeCell<T> {}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub(crate) struct SharedThinCstr(pub(crate) *const c_char);
|
pub struct SharedThinCstr(pub NonNull<c_char>);
|
||||||
|
|
||||||
|
impl SharedThinCstr {
|
||||||
|
pub unsafe fn from_ptr(ptr: NonNull<c_char>) -> Self {
|
||||||
|
Self(ptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_array<const N: usize>(arr: &[u8; N]) -> Self {
|
||||||
|
assert!(arr[N - 1] == 0);
|
||||||
|
unsafe { Self(NonNull::new_unchecked(arr as *const u8 as *mut c_char)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_ptr(self) -> NonNull<c_char> {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn add(self, amount: usize) -> Self {
|
||||||
|
Self(NonNull::new_unchecked(self.0.as_ptr().add(amount)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoIterator for SharedThinCstr {
|
||||||
|
type Item = c_char;
|
||||||
|
|
||||||
|
type IntoIter = CStrIter;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
CStrIter(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CStrIter(SharedThinCstr);
|
||||||
|
|
||||||
|
impl Iterator for CStrIter {
|
||||||
|
type Item = c_char;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
unsafe {
|
||||||
|
let c = self.0 .0.as_ptr().read();
|
||||||
|
if c == 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.0 = self.0.add(1);
|
||||||
|
Some(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unsafe impl Send for SharedThinCstr {}
|
unsafe impl Send for SharedThinCstr {}
|
||||||
unsafe impl Sync for SharedThinCstr {}
|
unsafe impl Sync for SharedThinCstr {}
|
||||||
|
|
||||||
|
impl Debug for SharedThinCstr {
|
||||||
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
|
let str = <&CStr>::from(*self).to_str();
|
||||||
|
match str {
|
||||||
|
Ok(str) => f.write_str(str),
|
||||||
|
Err(_) => f.write_str("<invalid UTF-8>"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<SharedThinCstr> for &CStr {
|
impl From<SharedThinCstr> for &CStr {
|
||||||
fn from(value: SharedThinCstr) -> Self {
|
fn from(value: SharedThinCstr) -> Self {
|
||||||
unsafe { CStr::from_ptr(value.0) }
|
unsafe { CStr::from_ptr(value.0.as_ptr()) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialEq for SharedThinCstr {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.into_iter().eq(other.into_iter())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for SharedThinCstr {}
|
||||||
|
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub(crate) struct SyncPtr<T>(pub(crate) *mut T);
|
pub(crate) struct SyncPtr<T>(pub(crate) *mut T);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue