Browse Source

WIP env support

jD91mZM2 6 năm trước cách đây
mục cha
commit
019011f029

+ 30 - 0
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));
 }
 

+ 9 - 3
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;
 

+ 68 - 6
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]

+ 1 - 4
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]

+ 21 - 20
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
-stdlib/strtol
-stdlib/strtoul
+stdio/fwrite
 stdlib/a64l
+stdlib/bsearch
+stdlib/mktemp
 stdlib/rand
-string/strncmp
-string/strcspn
+stdlib/strtol
+stdlib/strtoul
 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

+ 1 - 0
tests/Makefile

@@ -8,6 +8,7 @@ EXPECT_BINS=\
 	create \
 	ctype \
 	dup \
+	env \
 	error \
 	exec \
 	fchdir \

+ 11 - 0
tests/env.c

@@ -0,0 +1,11 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+int main() {
+    puts(getenv("SHELL"));
+    puts(getenv("CC"));
+
+    putenv("KEK=lol");
+
+    puts(getenv("KEK"));
+}

+ 0 - 0
tests/expected/env.stderr


+ 3 - 0
tests/expected/env.stdout

@@ -0,0 +1,3 @@
+/nix/store/zqh3l3lyw32q1ayb15bnvg9f24j5v2p0-bash-4.4-p12/bin/bash
+gcc
+lol

+ 7 - 0
tests/pipe.c

@@ -1,4 +1,5 @@
 //http://www2.cs.uregina.ca/~hamilton/courses/330/notes/unix/pipes/pipes.html
+#include <stdio.h>
 #include <string.h>
 #include <unistd.h>
 
@@ -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]);
     }