diff --git a/src/crt0/src/lib.rs b/src/crt0/src/lib.rs index 6cf3220ddd..5a18f98adb 100644 --- a/src/crt0/src/lib.rs +++ b/src/crt0/src/lib.rs @@ -1,14 +1,18 @@ //! crt0 #![no_std] +#![feature(alloc)] #![feature(asm)] #![feature(linkage)] #![feature(naked_functions)] #![feature(panic_implementation)] #![feature(lang_items)] +extern crate alloc; extern crate platform; +use alloc::Vec; +use core::ptr; use platform::types::*; #[no_mangle] @@ -47,6 +51,10 @@ impl Stack { fn argv(&self) -> *const *const u8 { &self.argv0 as *const *const u8 } + + fn envp(&self) -> *const *const u8 { + unsafe { self.argv().offset(self.argc() + 1) } + } } #[inline(never)] @@ -59,6 +67,28 @@ pub unsafe extern "C" fn _start_rust(sp: &'static Stack) -> ! { let argc = sp.argc(); let argv = sp.argv(); + let envp = sp.envp(); + let mut len = 0; + while *envp.offset(len) != ptr::null() { + len += 1; + } + platform::inner_environ = Vec::with_capacity(len as usize + 1); + for i in 0..len { + let mut item = *envp.offset(i); + let mut len = 0; + while *item.offset(len) != 0 { + len += 1; + } + + let buf = platform::alloc(len as usize + 1) as *mut c_char; + for i in 0..=len { + *buf.offset(i) = *item.offset(i) as c_char; + } + platform::inner_environ.push(buf); + } + platform::inner_environ.push(ptr::null_mut()); + platform::environ = platform::inner_environ.as_mut_ptr(); + platform::exit(main(argc, argv)); } diff --git a/src/platform/src/lib.rs b/src/platform/src/lib.rs index b0891fd25a..452671bc53 100644 --- a/src/platform/src/lib.rs +++ b/src/platform/src/lib.rs @@ -1,7 +1,6 @@ #![no_std] #![allow(non_camel_case_types)] -#![feature(alloc)] -#![feature(allocator_api)] +#![feature(alloc, allocator_api, const_vec_new)] //TODO #![feature(thread_local)] #[cfg_attr(target_os = "redox", macro_use)] @@ -36,7 +35,8 @@ mod sys; pub mod types; -use core::fmt; +use alloc::Vec; +use core::{fmt, ptr}; use types::*; @@ -64,6 +64,12 @@ pub struct sockaddr { #[no_mangle] pub static mut errno: c_int = 0; +#[allow(non_upper_case_globals)] +#[no_mangle] +pub static mut environ: *mut *mut c_char = ptr::null_mut(); +#[allow(non_upper_case_globals)] +pub static mut inner_environ: Vec<*mut c_char> = Vec::new(); + pub unsafe fn c_str_mut<'a>(s: *mut c_char) -> &'a mut [u8] { use core::usize; diff --git a/src/stdlib/src/lib.rs b/src/stdlib/src/lib.rs index 6d0a921baf..e6445119aa 100644 --- a/src/stdlib/src/lib.rs +++ b/src/stdlib/src/lib.rs @@ -260,9 +260,38 @@ pub extern "C" fn gcvt(value: c_double, ndigit: c_int, buf: *mut c_char) -> *mut unimplemented!(); } -// #[no_mangle] -pub extern "C" fn getenv(name: *const c_char) -> *mut c_char { - unimplemented!(); +unsafe fn find_env(name: *const c_char) -> Option<(usize, *mut c_char)> { + for (i, item) in platform::inner_environ.iter().enumerate() { + let mut item = *item; + if item == ptr::null_mut() { + assert_eq!(i, platform::inner_environ.len() - 1, "an early null pointer in environ vector"); + break; + } + let mut name = name; + loop { + let end_of_name = *name == 0 || *name == b'=' as c_char; + if *item == 0 || *item == b'=' as c_char || end_of_name { + if *item == b'=' as c_char || end_of_name { + return Some((i, item.offset(1))); + } else { + break; + } + } + + if *item != *name { + break; + } + + item = item.offset(1); + name = name.offset(1); + } + } + None +} + +#[no_mangle] +pub unsafe extern "C" fn getenv(name: *const c_char) -> *mut c_char { + find_env(name).map(|val| val.1).unwrap_or(ptr::null_mut()) } // #[no_mangle] @@ -443,9 +472,42 @@ pub extern "C" fn ptsname(fildes: c_int) -> *mut c_char { unimplemented!(); } -// #[no_mangle] -pub extern "C" fn putenv(s: *mut c_char) -> c_int { - unimplemented!(); +#[no_mangle] +pub unsafe extern "C" fn putenv(s: *mut c_char) -> c_int { + let mut s_len = 0; + while *s.offset(s_len) != 0 { + s_len += 1; + } + + let ptr; + + if let Some((i, _)) = find_env(s) { + let mut item = platform::inner_environ[i]; + let mut item_len = 0; + while *item.offset(item_len) != 0 { + item_len += 1; + } + + if item_len > s_len { + ptr = item; + } else { + platform::free(item as *mut c_void); + ptr = platform::alloc(s_len as usize + 1) as *mut c_char; + platform::inner_environ[i] = ptr; + } + } else { + ptr = platform::alloc(s_len as usize + 1) as *mut c_char; + let i = platform::inner_environ.len() - 1; + assert_eq!(platform::inner_environ[i], ptr::null_mut(), "last element in environ vector was not null"); + platform::inner_environ[i] = ptr; + platform::inner_environ.push(ptr::null_mut()); + + platform::environ = platform::inner_environ.as_mut_ptr(); + } + for i in 0..=s_len { + *ptr.offset(i) = *s.offset(i); + } + 0 } #[no_mangle] diff --git a/src/unistd/src/lib.rs b/src/unistd/src/lib.rs index 3d911ff6eb..408143a7bb 100644 --- a/src/unistd/src/lib.rs +++ b/src/unistd/src/lib.rs @@ -41,9 +41,6 @@ pub const STDIN_FILENO: c_int = 0; pub const STDOUT_FILENO: c_int = 1; pub const STDERR_FILENO: c_int = 2; -#[no_mangle] -pub static mut environ: *mut *mut c_char = ptr::null_mut(); - #[no_mangle] pub extern "C" fn _exit(status: c_int) { platform::exit(status) @@ -125,7 +122,7 @@ pub extern "C" fn encrypt(block: [c_char; 64], edflag: c_int) { #[no_mangle] pub unsafe extern "C" fn execv(path: *const c_char, argv: *const *mut c_char) -> c_int { - execve(path, argv, environ) + execve(path, argv, platform::environ) } #[no_mangle] diff --git a/tests/.gitignore b/tests/.gitignore index 6b46660daf..37fb9ac0fc 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -1,14 +1,18 @@ # Automatically generated by 'make ignore' /*.out /gen/ +alloc +args +asctime assert atof atoi brk -args +chdir create ctype dup +env error exec fchdir @@ -16,6 +20,10 @@ fcntl fsync ftruncate getc_unget +gethostname +getid +gmtime +link locale localtime math @@ -26,43 +34,36 @@ printf rename rmdir scanf +setid setjmp sleep sprintf -strings -stdio/fwrite stdio/all stdio/freopen +stdio/fwrite +stdlib/a64l +stdlib/bsearch +stdlib/mktemp +stdlib/rand stdlib/strtol stdlib/strtoul -stdlib/a64l -stdlib/rand -string/strncmp -string/strcspn string/strchr +string/strcspn +string/strncmp +string/strpbrk string/strrchr string/strspn string/strstr -string/strpbrk string/strtok string/strtok_r +strings system +time unistd/getopt +unlink waitpid wchar/mbrtowc wchar/mbsrtowcs wchar/putwchar wchar/wcrtomb write -time -gmtime -asctime -alloc -chdir -gethostname -getid -link -setid -stdlib/bsearch -stdlib/mktemp -unlink diff --git a/tests/Makefile b/tests/Makefile index 0f348118b8..2f7d9fbb98 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -8,6 +8,7 @@ EXPECT_BINS=\ create \ ctype \ dup \ + env \ error \ exec \ fchdir \ diff --git a/tests/env.c b/tests/env.c new file mode 100644 index 0000000000..73b39154ad --- /dev/null +++ b/tests/env.c @@ -0,0 +1,11 @@ +#include +#include + +int main() { + puts(getenv("SHELL")); + puts(getenv("CC")); + + putenv("KEK=lol"); + + puts(getenv("KEK")); +} diff --git a/tests/expected/env.stderr b/tests/expected/env.stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/env.stdout b/tests/expected/env.stdout new file mode 100644 index 0000000000..d0ec8ca5bb --- /dev/null +++ b/tests/expected/env.stdout @@ -0,0 +1,3 @@ +/nix/store/zqh3l3lyw32q1ayb15bnvg9f24j5v2p0-bash-4.4-p12/bin/bash +gcc +lol diff --git a/tests/pipe.c b/tests/pipe.c index 703073cc35..fbbc72ea9f 100644 --- a/tests/pipe.c +++ b/tests/pipe.c @@ -1,4 +1,5 @@ //http://www2.cs.uregina.ca/~hamilton/courses/330/notes/unix/pipes/pipes.html +#include #include #include @@ -14,19 +15,25 @@ int main() pid = fork(); if (pid == 0) /* child : sends message to parent*/ { + puts("Child: Close Read"); /* close read end */ close(pip[0]); + puts("Child: Write"); /* send 7 characters in the string, including end-of-string */ write(pip[1], outstring, strlen(outstring)); + puts("Child: Close Write"); /* close write end */ close(pip[1]); } else /* parent : receives message from child */ { + puts("Parent: Close Write"); /* close write end */ close(pip[1]); + puts("Parent: Read"); /* read from the pipe */ read(pip[0], instring, 7); + puts("Parent: Close Read"); /* close read end */ close(pip[0]); }