libc: setenv/putenv/unsetenv/getenv
This commit is contained in:
parent
e2ef677b4a
commit
c65b06fadb
129
test.c
129
test.c
@ -4,75 +4,70 @@
|
|||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
static void test1(void) {
|
|
||||||
#define N 128
|
|
||||||
void *array[N] = {NULL};
|
|
||||||
|
|
||||||
for (size_t i = 0; i < N; ++i) {
|
|
||||||
array[i] = malloc(i * 2 + 1);
|
|
||||||
memset(array[i], 0xA3, i * 2 + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < N; i += 2) {
|
|
||||||
free(array[i]);
|
|
||||||
array[i] = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 1; i < N; i += 2) {
|
|
||||||
for (size_t j = 0; j < i * 2 + 1; ++j) {
|
|
||||||
assert(((const unsigned char *) array[i])[j] == 0xA3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < N; i += 2) {
|
|
||||||
array[i] = malloc(i * 3 + 3);
|
|
||||||
memset(array[i], 0x7D, i * 3 + 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 1; i < N; i += 2) {
|
|
||||||
for (size_t j = 0; j < i * 2 + 1; ++j) {
|
|
||||||
assert(((const unsigned char *) array[i])[j] == 0xA3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (size_t i = 0; i < N; i += 2) {
|
|
||||||
for (size_t j = 0; j < i * 3 + 3; ++j) {
|
|
||||||
assert(((const unsigned char *) array[i])[j] == 0x7D);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < N; ++i) {
|
|
||||||
free(array[i]);
|
|
||||||
}
|
|
||||||
#undef N
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test2(void) {
|
|
||||||
#define N 64
|
|
||||||
void *ptr0 = NULL;
|
|
||||||
void *ptr1 = NULL;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < N; ++i) {
|
|
||||||
printf("Round #%zu\n", i);
|
|
||||||
// 2, 4, 6, ...
|
|
||||||
ptr0 = realloc(ptr0, (i + 1) * 2);
|
|
||||||
for (size_t j = 0; j < i * 2; ++j) {
|
|
||||||
assert(((const unsigned char *) ptr0)[j] == 0x12);
|
|
||||||
}
|
|
||||||
memset(ptr0, 0x12, (i + 1) * 2);
|
|
||||||
// 3, 6, 9, ...
|
|
||||||
ptr1 = realloc(ptr1, (i + 1) * 3);
|
|
||||||
for (size_t j = 0; j < i * 3; ++j) {
|
|
||||||
assert(((const unsigned char *) ptr1)[j] == 0x34);
|
|
||||||
}
|
|
||||||
memset(ptr1, 0x34, (i + 1) * 3);
|
|
||||||
}
|
|
||||||
#undef N
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, const char **argv) {
|
int main(int argc, const char **argv) {
|
||||||
test1();
|
char *val;
|
||||||
test2();
|
|
||||||
|
assert(environ != NULL);
|
||||||
|
assert(*environ == NULL);
|
||||||
|
|
||||||
|
setenv("key1", "value1", 0);
|
||||||
|
assert(environ != NULL);
|
||||||
|
assert(!strcmp(*environ, "key1=value1"));
|
||||||
|
assert(*(environ + 1) == NULL);
|
||||||
|
|
||||||
|
setenv("key1", "value2", 0);
|
||||||
|
assert(environ != NULL);
|
||||||
|
assert(!strcmp(*environ, "key1=value1"));
|
||||||
|
assert(*(environ + 1) == NULL);
|
||||||
|
|
||||||
|
setenv("key1", "value3", 1);
|
||||||
|
assert(environ != NULL);
|
||||||
|
assert(!strcmp(*environ, "key1=value3"));
|
||||||
|
assert(*(environ + 1) == NULL);
|
||||||
|
|
||||||
|
setenv("key1", "longer-value", 1);
|
||||||
|
assert(environ != NULL);
|
||||||
|
assert(!strcmp(*environ, "key1=longer-value"));
|
||||||
|
assert(*(environ + 1) == NULL);
|
||||||
|
|
||||||
|
setenv("key2", "other-value", 0);
|
||||||
|
assert(environ != NULL);
|
||||||
|
assert(!strcmp(environ[0], "key1=longer-value"));
|
||||||
|
assert(!strcmp(environ[1], "key2=other-value"));
|
||||||
|
assert(environ[2] == NULL);
|
||||||
|
|
||||||
|
assert(!strcmp(getenv("key1"), "longer-value"));
|
||||||
|
assert(!strcmp(getenv("key2"), "other-value"));
|
||||||
|
assert(getenv("key3") == NULL);
|
||||||
|
|
||||||
|
unsetenv("key2");
|
||||||
|
|
||||||
|
assert(!strcmp(getenv("key1"), "longer-value"));
|
||||||
|
assert(getenv("key2") == NULL);
|
||||||
|
assert(getenv("key3") == NULL);
|
||||||
|
|
||||||
|
environ[0] = strdup("key2=???");
|
||||||
|
|
||||||
|
assert(!strcmp(getenv("key2"), "???"));
|
||||||
|
|
||||||
|
char *value = strdup("key4=!!!");
|
||||||
|
putenv(value);
|
||||||
|
|
||||||
|
assert(!strcmp(getenv("key2"), "???"));
|
||||||
|
assert(!strcmp(getenv("key4"), "!!!"));
|
||||||
|
|
||||||
|
value[6] = '@';
|
||||||
|
|
||||||
|
assert(!strcmp(getenv("key2"), "???"));
|
||||||
|
assert(!strcmp(getenv("key4"), "!@!"));
|
||||||
|
|
||||||
|
unsetenv("key4");
|
||||||
|
unsetenv("key2");
|
||||||
|
|
||||||
|
assert(environ != NULL);
|
||||||
|
assert(*environ == NULL);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -5,4 +5,6 @@ int execl(const char *path, const char *arg, ...);
|
|||||||
int execlp(const char *file, const char *arg, ...);
|
int execlp(const char *file, const char *arg, ...);
|
||||||
int execle(const char *path, const char *arg, ...);
|
int execle(const char *path, const char *arg, ...);
|
||||||
|
|
||||||
|
extern char **environ;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
use alloc::{ffi::CString, vec::Vec};
|
|
||||||
use yggdrasil_rt::process::ProgramArgumentInner;
|
|
||||||
|
|
||||||
use crate::util::PointerExt;
|
|
||||||
|
|
||||||
pub fn handle_kernel_argument(arg: usize) -> (Vec<CString>, Vec<CString>) {
|
|
||||||
let arg_ptr: *const ProgramArgumentInner = core::ptr::with_exposed_provenance(arg);
|
|
||||||
let arg = unsafe { arg_ptr.ensure() };
|
|
||||||
|
|
||||||
let mut args = Vec::new();
|
|
||||||
let mut envs = Vec::new();
|
|
||||||
|
|
||||||
for &arg in arg.args {
|
|
||||||
let c_arg = CString::new(arg).unwrap();
|
|
||||||
args.push(c_arg);
|
|
||||||
}
|
|
||||||
for &env in arg.env {
|
|
||||||
let c_env = CString::new(env).unwrap();
|
|
||||||
envs.push(c_env);
|
|
||||||
}
|
|
||||||
|
|
||||||
(args, envs)
|
|
||||||
}
|
|
230
userspace/lib/ygglibc/src/env.rs
Normal file
230
userspace/lib/ygglibc/src/env.rs
Normal file
@ -0,0 +1,230 @@
|
|||||||
|
#![allow(non_upper_case_globals)]
|
||||||
|
|
||||||
|
use core::{
|
||||||
|
ffi::{c_char, CStr},
|
||||||
|
ptr::{null_mut, NonNull},
|
||||||
|
slice::memchr,
|
||||||
|
};
|
||||||
|
|
||||||
|
use alloc::{ffi::CString, vec::Vec};
|
||||||
|
use yggdrasil_rt::process::ProgramArgumentInner;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
allocator::{c_alloc, c_free},
|
||||||
|
error::EResult,
|
||||||
|
headers::{
|
||||||
|
errno,
|
||||||
|
string::{
|
||||||
|
mem::memcpy,
|
||||||
|
str::{strcpy, strlen},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
util::PointerExt,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub static mut environ: *mut *mut c_char = null_mut();
|
||||||
|
static mut shadow: Vec<*mut c_char> = Vec::new();
|
||||||
|
|
||||||
|
unsafe fn get_key(var: NonNull<c_char>) -> Option<&'static [u8]> {
|
||||||
|
let cstr = CStr::from_ptr(var.as_ptr()).to_bytes();
|
||||||
|
let eq_pos = memchr::memchr(b'=', cstr)?;
|
||||||
|
Some(&cstr[..eq_pos])
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn entry_from_key_value(key: &[u8], value: &[u8]) -> EResult<NonNull<c_char>> {
|
||||||
|
let entry = c_alloc(key.len() + value.len() + 2, 1, false)?.cast::<c_char>();
|
||||||
|
memcpy(entry.as_ptr().cast(), key.as_ptr().cast(), key.len());
|
||||||
|
memcpy(
|
||||||
|
entry.add(key.len() + 1).as_ptr().cast(),
|
||||||
|
value.as_ptr().cast(),
|
||||||
|
value.len(),
|
||||||
|
);
|
||||||
|
entry.add(key.len()).write(b'=' as _);
|
||||||
|
entry.add(key.len() + value.len() + 1).write(0);
|
||||||
|
EResult::Ok(entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn entry_from_raw(raw: &[u8]) -> EResult<NonNull<c_char>> {
|
||||||
|
let entry = c_alloc(raw.len() + 1, 1, false)?.cast::<c_char>();
|
||||||
|
memcpy(entry.as_ptr().cast(), raw.as_ptr().cast(), raw.len());
|
||||||
|
entry.add(raw.len()).write(0);
|
||||||
|
EResult::Ok(entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn reclaim_env() -> EResult<()> {
|
||||||
|
if environ == shadow.as_mut_ptr() {
|
||||||
|
// environ already points to ygglibc-owned list
|
||||||
|
return EResult::Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn push_env(str: NonNull<c_char>) -> EResult<()> {
|
||||||
|
reclaim_env();
|
||||||
|
|
||||||
|
if shadow.try_reserve(1).is_err() {
|
||||||
|
return EResult::Err(errno::ENOMEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
let entry = shadow.last_mut().unwrap();
|
||||||
|
assert!(entry.is_null());
|
||||||
|
*entry = str.as_ptr();
|
||||||
|
|
||||||
|
// Won't fail
|
||||||
|
shadow.push(null_mut());
|
||||||
|
|
||||||
|
// Fixup the pointer, shadow might've got reallocated
|
||||||
|
environ = shadow.as_mut_ptr();
|
||||||
|
|
||||||
|
EResult::Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn setup_env(envs: impl IntoIterator<Item = &'static &'static str>) {
|
||||||
|
for &env in envs {
|
||||||
|
// Make a malloc()ed, NULL-terminated string
|
||||||
|
let entry = entry_from_raw(env.as_bytes()).expect("Couldn't allocate env variable");
|
||||||
|
shadow.push(entry.as_ptr());
|
||||||
|
}
|
||||||
|
shadow.push(null_mut());
|
||||||
|
environ = shadow.as_mut_ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn get_env(name: &[u8]) -> EResult<Option<NonNull<c_char>>> {
|
||||||
|
if name.is_empty() || name.contains(&b'=') {
|
||||||
|
return EResult::Err(errno::EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(mut iter) = NonNull::new(environ) else {
|
||||||
|
// User set environ to NULL
|
||||||
|
return EResult::Ok(None);
|
||||||
|
};
|
||||||
|
|
||||||
|
while let Some(entry) = NonNull::new(iter.read()) {
|
||||||
|
let Some(key) = get_key(entry) else { continue };
|
||||||
|
|
||||||
|
if key == name {
|
||||||
|
// Safe: key != None means there is at least a '=' after whatever "key" points at
|
||||||
|
let value = entry.add(key.len() + 1);
|
||||||
|
return EResult::Ok(Some(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
iter = iter.add(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
EResult::Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn set_env(name: &[u8], value: NonNull<c_char>, overwrite: bool) -> EResult<()> {
|
||||||
|
if name.is_empty() || name.contains(&b'=') {
|
||||||
|
return EResult::Err(errno::EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
let value = CStr::from_ptr(value.as_ptr()).to_bytes();
|
||||||
|
|
||||||
|
if let Some(mut iter) = NonNull::new(environ) {
|
||||||
|
// Try to locate the key=value pair in the existing env
|
||||||
|
while let Some(entry) = NonNull::new(iter.read()) {
|
||||||
|
let Some(key) = get_key(entry) else { continue };
|
||||||
|
|
||||||
|
if key == name {
|
||||||
|
if !overwrite {
|
||||||
|
return EResult::Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Safe: key != None means there is at least a '=' after whatever "key" points at
|
||||||
|
let old_value = entry.add(key.len() + 1);
|
||||||
|
|
||||||
|
if strlen(old_value.as_ptr()) >= value.len() {
|
||||||
|
// Old allocation can contain `value`
|
||||||
|
memcpy(
|
||||||
|
old_value.as_ptr().cast(),
|
||||||
|
value.as_ptr().cast(),
|
||||||
|
value.len(),
|
||||||
|
);
|
||||||
|
old_value.add(value.len()).write(0);
|
||||||
|
} else {
|
||||||
|
// Need to allocate a new entry
|
||||||
|
let new_entry = entry_from_key_value(name, value)?;
|
||||||
|
c_free(entry.cast());
|
||||||
|
iter.write(new_entry.as_ptr());
|
||||||
|
}
|
||||||
|
|
||||||
|
return EResult::Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
iter = iter.add(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Key not found or environ == NULL, need to push a new entry
|
||||||
|
let entry = entry_from_key_value(name, value)?;
|
||||||
|
push_env(entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn remove_env(name: &[u8]) -> EResult<bool> {
|
||||||
|
if name.is_empty() || name.contains(&b'=') {
|
||||||
|
return EResult::Err(errno::EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
reclaim_env();
|
||||||
|
for i in 0..shadow.len() {
|
||||||
|
let Some(entry) = NonNull::new(shadow[i]) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let Some(key) = get_key(entry) else { continue };
|
||||||
|
|
||||||
|
if key == name {
|
||||||
|
// Pop entry at [i]
|
||||||
|
shadow.remove(i);
|
||||||
|
environ = shadow.as_mut_ptr();
|
||||||
|
c_free(entry.cast());
|
||||||
|
return EResult::Ok(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EResult::Ok(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn put_env(str: NonNull<c_char>) -> EResult<()> {
|
||||||
|
let bytes = CStr::from_ptr(str.as_ptr()).to_bytes();
|
||||||
|
if bytes.is_empty() || !bytes.contains(&b'=') {
|
||||||
|
return EResult::Err(errno::EINVAL);
|
||||||
|
}
|
||||||
|
let name = get_key(str).unwrap();
|
||||||
|
|
||||||
|
if let Some(mut iter) = NonNull::new(environ) {
|
||||||
|
while let Some(entry) = NonNull::new(iter.read()) {
|
||||||
|
let Some(key) = get_key(entry) else { continue };
|
||||||
|
|
||||||
|
if key == name {
|
||||||
|
// Replace the entry
|
||||||
|
iter.write(str.as_ptr());
|
||||||
|
c_free(entry.cast());
|
||||||
|
return EResult::Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
iter = iter.add(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push a new entry
|
||||||
|
push_env(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_kernel_argument(arg: usize) -> Vec<CString> {
|
||||||
|
let arg_ptr: *const ProgramArgumentInner = core::ptr::with_exposed_provenance(arg);
|
||||||
|
let arg = unsafe { arg_ptr.ensure() };
|
||||||
|
|
||||||
|
let mut args = Vec::new();
|
||||||
|
|
||||||
|
for &arg in arg.args {
|
||||||
|
let c_arg = CString::new(arg).unwrap();
|
||||||
|
args.push(c_arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe { setup_env(arg.env) };
|
||||||
|
|
||||||
|
args
|
||||||
|
}
|
@ -2,6 +2,8 @@ use core::ffi::{c_char, c_int, c_long, c_void};
|
|||||||
|
|
||||||
use yggdrasil_rt::process::Signal;
|
use yggdrasil_rt::process::Signal;
|
||||||
|
|
||||||
|
use crate::{error::CIntZeroResult, util::PointerExt};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
sys_time::__ygg_timespec_t,
|
sys_time::__ygg_timespec_t,
|
||||||
sys_types::{pid_t, uid_t},
|
sys_types::{pid_t, uid_t},
|
||||||
@ -170,11 +172,12 @@ unsafe extern "C" fn raise(_signum: c_int) -> c_int {
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
unsafe extern "C" fn sigaction(
|
unsafe extern "C" fn sigaction(
|
||||||
_signum: c_int,
|
signum: c_int,
|
||||||
_new: *const sigaction,
|
_new: *const sigaction,
|
||||||
_old: *mut sigaction,
|
_old: *mut sigaction,
|
||||||
) -> c_int {
|
) -> CIntZeroResult {
|
||||||
todo!()
|
yggdrasil_rt::debug_trace!("TODO: sigaction({})", signum);
|
||||||
|
CIntZeroResult::SUCCESS
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@ -194,8 +197,10 @@ unsafe extern "C" fn sigdelset(_mask: *mut sigset_t, _signum: c_int) -> c_int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
unsafe extern "C" fn sigemptyset(_mask: *mut sigset_t) -> c_int {
|
unsafe extern "C" fn sigemptyset(mask: *mut sigset_t) -> CIntZeroResult {
|
||||||
todo!()
|
let mask = mask.ensure_mut();
|
||||||
|
*mask = 0;
|
||||||
|
CIntZeroResult::SUCCESS
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
use core::ffi::{c_char, c_int};
|
use core::{ffi::{c_char, c_int}, ptr::NonNull};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::{CIntZeroResult, CPtrResult},
|
env, error::{CIntZeroResult, CPtrResult, CResult, OptionExt}, headers::errno, process, util::{PointerExt, PointerStrExt}
|
||||||
process,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@ -26,22 +25,34 @@ unsafe extern "C" fn exit(status: c_int) -> ! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
unsafe extern "C" fn getenv(_name: *const c_char) -> CPtrResult<c_char> {
|
unsafe extern "C" fn getenv(name: *const c_char) -> CPtrResult<c_char> {
|
||||||
todo!()
|
let name = name.ensure_cstr().to_bytes();
|
||||||
|
|
||||||
|
if let Some(value) = env::get_env(name)? {
|
||||||
|
CPtrResult::success(value)
|
||||||
|
} else {
|
||||||
|
CPtrResult::ERROR
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
unsafe extern "C" fn putenv(_value: *const c_char) -> CPtrResult<c_char> {
|
unsafe extern "C" fn putenv(value: *mut c_char) -> CIntZeroResult {
|
||||||
todo!()
|
let value = NonNull::new(value).e_ok_or(errno::EINVAL)?;
|
||||||
|
env::put_env(value)?;
|
||||||
|
CIntZeroResult::SUCCESS
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
unsafe extern "C" fn setenv(
|
unsafe extern "C" fn setenv(
|
||||||
_name: *const c_char,
|
name: *const c_char,
|
||||||
_value: *const c_char,
|
value: *const c_char,
|
||||||
_overwrite: c_int,
|
overwrite: c_int,
|
||||||
) -> CIntZeroResult {
|
) -> CIntZeroResult {
|
||||||
todo!()
|
let name = name.ensure_cstr().to_bytes();
|
||||||
|
let value = NonNull::new(value.cast_mut()).e_ok_or(errno::EINVAL)?;
|
||||||
|
let overwrite = overwrite != 0;
|
||||||
|
env::set_env(name, value, overwrite)?;
|
||||||
|
CIntZeroResult::SUCCESS
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deprecated
|
// Deprecated
|
||||||
@ -56,6 +67,8 @@ unsafe extern "C" fn system(_command: *const c_char) -> CIntZeroResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
unsafe extern "C" fn unsetenv(_name: *const c_char) -> c_int {
|
unsafe extern "C" fn unsetenv(name: *const c_char) -> CIntZeroResult {
|
||||||
todo!()
|
let name = name.ensure_cstr().to_bytes();
|
||||||
|
env::remove_env(name)?;
|
||||||
|
CIntZeroResult::SUCCESS
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ unsafe extern "C" fn strcmp(a: *const c_char, b: *const c_char) -> c_int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
unsafe extern "C" fn strcpy(dst: *mut c_char, src: *const c_char) -> *mut c_char {
|
pub unsafe extern "C" fn strcpy(dst: *mut c_char, src: *const c_char) -> *mut c_char {
|
||||||
stpcpy(dst, src);
|
stpcpy(dst, src);
|
||||||
dst
|
dst
|
||||||
}
|
}
|
||||||
@ -121,7 +121,7 @@ unsafe extern "C" fn strerror_r(e: c_int, buf: *mut c_char, n: usize) -> *mut c_
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
unsafe extern "C" fn strlen(s: *const c_char) -> usize {
|
pub unsafe extern "C" fn strlen(s: *const c_char) -> usize {
|
||||||
compiler_builtins::mem::strlen(s.cast())
|
compiler_builtins::mem::strlen(s.cast())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ unsafe extern "C" fn fsync(fd: c_int) -> CIntZeroResult {
|
|||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
unsafe extern "C" fn isatty(fd: c_int) -> c_int {
|
unsafe extern "C" fn isatty(fd: c_int) -> c_int {
|
||||||
debug_trace!("TODO: isatty()");
|
debug_trace!("TODO: isatty()");
|
||||||
0
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
#![allow(internal_features)]
|
#![allow(internal_features)]
|
||||||
#![cfg_attr(not(test), no_std)]
|
#![cfg_attr(not(test), no_std)]
|
||||||
|
|
||||||
|
use env::environ;
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
extern crate compiler_builtins;
|
extern crate compiler_builtins;
|
||||||
@ -22,15 +24,15 @@ extern crate compiler_builtins;
|
|||||||
extern crate std;
|
extern crate std;
|
||||||
|
|
||||||
mod allocator;
|
mod allocator;
|
||||||
mod args;
|
mod env;
|
||||||
mod error;
|
mod error;
|
||||||
mod io;
|
mod io;
|
||||||
mod panic;
|
mod panic;
|
||||||
mod process;
|
mod process;
|
||||||
|
mod ssp;
|
||||||
mod sync;
|
mod sync;
|
||||||
mod types;
|
mod types;
|
||||||
mod util;
|
mod util;
|
||||||
mod ssp;
|
|
||||||
|
|
||||||
pub mod headers;
|
pub mod headers;
|
||||||
|
|
||||||
@ -51,23 +53,18 @@ unsafe extern "C" fn __ygglibc_entry(arg: usize) {
|
|||||||
io::init();
|
io::init();
|
||||||
|
|
||||||
// Setup args
|
// Setup args
|
||||||
let (args, envs) = args::handle_kernel_argument(arg);
|
let args = env::handle_kernel_argument(arg);
|
||||||
let mut c_args = Vec::new();
|
let mut c_args = Vec::new();
|
||||||
let mut c_envs = Vec::new();
|
|
||||||
|
|
||||||
for arg in args.iter() {
|
for arg in args.iter() {
|
||||||
c_args.push(arg.as_ptr());
|
c_args.push(arg.as_ptr());
|
||||||
}
|
}
|
||||||
for env in envs.iter() {
|
|
||||||
c_envs.push(env.as_ptr());
|
|
||||||
}
|
|
||||||
c_args.push(null());
|
c_args.push(null());
|
||||||
c_envs.push(null());
|
|
||||||
|
|
||||||
let status = main(
|
let status = main(
|
||||||
args.len().try_into().unwrap(),
|
args.len().try_into().unwrap(),
|
||||||
c_args.as_ptr(),
|
c_args.as_ptr(),
|
||||||
c_envs.as_ptr(),
|
environ.cast(),
|
||||||
);
|
);
|
||||||
|
|
||||||
process::c_exit(status)
|
process::c_exit(status)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user