From 57f5699664eb47c985f671e9c07dc0b644e4f235 Mon Sep 17 00:00:00 2001
From: Jeremy Soller <jackpot51@gmail.com>
Date: Sat, 17 Sep 2016 19:01:34 -0600
Subject: [PATCH] Update libstd. Add CWD and associated syscalls. Remove
 debugging

---
 .gitmodules               |  3 +++
 Makefile                  | 13 ++++++++++---
 ion                       |  1 +
 kernel/context/context.rs | 38 ++++++++++++++++++++++++++++++++++++++
 kernel/lib.rs             |  2 ++
 kernel/scheme/initfs.rs   |  3 ++-
 kernel/syscall/call.rs    |  9 ++++++++-
 kernel/syscall/fs.rs      | 22 ++++++++++++++++++++++
 kernel/syscall/mod.rs     |  4 +++-
 kernel/syscall/process.rs | 23 ++++++++++++++++++-----
 libstd                    |  2 +-
 syscall/src/lib.rs        |  5 +++++
 12 files changed, 113 insertions(+), 12 deletions(-)
 create mode 160000 ion

diff --git a/.gitmodules b/.gitmodules
index e033dc27d..fe424c001 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -7,3 +7,6 @@
 [submodule "ralloc"]
 	path = ralloc
 	url = https://github.com/redox-os/ralloc
+[submodule "ion"]
+	path = ion
+	url = https://github.com/redox-os/ion.git
diff --git a/Makefile b/Makefile
index 9d394c83b..3c9c5e06c 100644
--- a/Makefile
+++ b/Makefile
@@ -12,9 +12,9 @@ KCARGOFLAGS=--target $(KTARGET).json -- -C soft-float
 TARGET=$(ARCH)-unknown-redox
 BUILD=build/userspace
 RUSTC=./rustc.sh
-RUSTCFLAGS=--target $(TARGET).json -O -C soft-float --cfg redox
+RUSTCFLAGS=--target $(TARGET).json -C soft-float --cfg redox
 CARGO=RUSTC="$(RUSTC)" cargo
-CARGOFLAGS=--target $(TARGET).json -- -O -C soft-float --cfg redox
+CARGOFLAGS=--target $(TARGET).json -- -C soft-float --cfg redox
 
 # Default targets
 .PHONY: all clean qemu bochs FORCE
@@ -25,6 +25,7 @@ clean:
 	cargo clean
 	cargo clean --manifest-path libstd/Cargo.toml
 	cargo clean --manifest-path init/Cargo.toml
+	cargo clean --manifest-path ion/Cargo.toml
 	cargo clean --manifest-path drivers/pcid/Cargo.toml
 	rm -rf build
 
@@ -93,7 +94,7 @@ $(KBUILD)/librustc_unicode.rlib: rust/src/librustc_unicode/lib.rs $(KBUILD)/libc
 $(KBUILD)/libcollections.rlib: rust/src/libcollections/lib.rs $(KBUILD)/libcore.rlib $(KBUILD)/liballoc.rlib $(KBUILD)/librustc_unicode.rlib
 	$(KRUSTC) $(KRUSTCFLAGS) -o $@ $<
 
-$(KBUILD)/libkernel.a: kernel/** $(KBUILD)/libcore.rlib $(KBUILD)/liballoc.rlib $(KBUILD)/libcollections.rlib $(BUILD)/init $(BUILD)/pcid FORCE
+$(KBUILD)/libkernel.a: kernel/** $(KBUILD)/libcore.rlib $(KBUILD)/liballoc.rlib $(KBUILD)/libcollections.rlib $(BUILD)/initfs.rs FORCE
 	$(KCARGO) rustc $(KCARGOFLAGS) -o $@
 
 $(KBUILD)/kernel: $(KBUILD)/libkernel.a
@@ -124,6 +125,12 @@ $(BUILD)/init: init/Cargo.toml init/src/*.rs $(BUILD)/libstd.rlib
 	$(CARGO) rustc --manifest-path $< $(CARGOFLAGS) -o $@
 	strip $@
 
+$(BUILD)/ion: ion/Cargo.toml ion/src/*.rs $(BUILD)/libstd.rlib
+	$(CARGO) rustc --manifest-path $< $(CARGOFLAGS) -o $@
+	strip $@
+
 $(BUILD)/pcid: drivers/pcid/Cargo.toml drivers/pcid/src/** $(BUILD)/libstd.rlib
 	$(CARGO) rustc --manifest-path $< $(CARGOFLAGS) -o $@
 	strip $@
+
+$(BUILD)/initfs.rs: $(BUILD)/init $(BUILD)/ion $(BUILD)/pcid
diff --git a/ion b/ion
new file mode 160000
index 000000000..cbb3c3003
--- /dev/null
+++ b/ion
@@ -0,0 +1 @@
+Subproject commit cbb3c3003f654d09cd3b3cf1a179469bb1b558b3
diff --git a/kernel/context/context.rs b/kernel/context/context.rs
index 6b4f7c7cf..43bdc61c4 100644
--- a/kernel/context/context.rs
+++ b/kernel/context/context.rs
@@ -33,6 +33,8 @@ pub struct Context {
     pub heap: Option<SharedMemory>,
     /// User stack
     pub stack: Option<Memory>,
+    /// The current working directory
+    pub cwd: Arc<Mutex<Vec<u8>>>,
     /// The open files in the scheme
     pub files: Arc<Mutex<Vec<Option<File>>>>
 }
@@ -49,10 +51,46 @@ impl Context {
             image: Vec::new(),
             heap: None,
             stack: None,
+            cwd: Arc::new(Mutex::new(Vec::new())),
             files: Arc::new(Mutex::new(Vec::new()))
         }
     }
 
+    pub fn canonicalize(&self, path: &[u8]) -> Vec<u8> {
+        if path.iter().position(|&b| b == b':').is_none() {
+            let cwd = self.cwd.lock();
+            if path == b"." {
+                cwd.clone()
+            } else if path == b".." {
+                cwd[..cwd[..cwd.len() - 1]
+                                   .iter().rposition(|&b| b == b'/')
+                                   .map_or(cwd.len(), |i| i + 1)]
+                   .to_vec()
+            } else if path.starts_with(b"./") {
+                let mut canon = cwd.clone();
+                canon.extend_from_slice(&path[2..]);
+                canon
+            } else if path.starts_with(b"../") {
+                let mut canon = cwd[..cwd[..cwd.len() - 1]
+                                   .iter().rposition(|&b| b == b'/')
+                                   .map_or(cwd.len(), |i| i + 1)]
+                   .to_vec();
+                canon.extend_from_slice(&path[3..]);
+                canon
+            } else if path.starts_with(b"/") {
+                let mut canon = cwd[..cwd.iter().position(|&b| b == b':').map_or(1, |i| i + 1)].to_vec();
+                canon.extend_from_slice(&path);
+                canon
+            } else {
+                let mut canon = cwd.clone();
+                canon.extend_from_slice(&path);
+                canon
+            }
+        } else {
+            path.to_vec()
+        }
+    }
+
     /// Add a file to the lowest available slot.
     /// Return the file descriptor number or None if no slot was found
     pub fn add_file(&mut self, file: File) -> Option<usize> {
diff --git a/kernel/lib.rs b/kernel/lib.rs
index dce4bce38..e9eec634a 100644
--- a/kernel/lib.rs
+++ b/kernel/lib.rs
@@ -128,6 +128,8 @@ pub fn cpu_id() -> usize {
 }
 
 pub extern fn userspace_init() {
+    assert_eq!(syscall::chdir(b"initfs:"), Ok(0));
+
     assert_eq!(syscall::open(b"debug:", 0), Ok(0));
     assert_eq!(syscall::open(b"debug:", 0), Ok(1));
     assert_eq!(syscall::open(b"debug:", 0), Ok(2));
diff --git a/kernel/scheme/initfs.rs b/kernel/scheme/initfs.rs
index d947b5ab5..82e5f3581 100644
--- a/kernel/scheme/initfs.rs
+++ b/kernel/scheme/initfs.rs
@@ -19,8 +19,9 @@ impl InitFsScheme {
         let mut files: BTreeMap<&'static [u8], &'static [u8]> = BTreeMap::new();
 
         files.insert(b"bin/init", include_bytes!("../../build/userspace/init"));
+        files.insert(b"bin/ion", include_bytes!("../../build/userspace/ion"));
         files.insert(b"bin/pcid", include_bytes!("../../build/userspace/pcid"));
-        files.insert(b"etc/init.rc", b"echo testing\ninitfs:bin/pcid\n");
+        files.insert(b"etc/init.rc", b"echo testing\ninitfs:bin/pcid\ninitfs:bin/ion");
 
         InitFsScheme {
             next_id: 0,
diff --git a/kernel/syscall/call.rs b/kernel/syscall/call.rs
index e62b27d84..e4a7e9263 100644
--- a/kernel/syscall/call.rs
+++ b/kernel/syscall/call.rs
@@ -19,6 +19,8 @@ pub enum Call {
     WaitPid = 7,
     /// Execute syscall
     Exec = 11,
+    /// Change working directory
+    ChDir = 12,
     /// Get process ID
     GetPid = 20,
     /// Duplicate file descriptor
@@ -30,12 +32,15 @@ pub enum Call {
     /// Clone process
     Clone = 120,
     /// Yield to scheduler
-    SchedYield = 158
+    SchedYield = 158,
+    /// Get process working directory
+    GetCwd = 183
 }
 
 /// Convert numbers to calls
 /// See http://syscalls.kernelgrok.com/
 impl Call {
+    //TODO: Return Option<Call>
     pub fn from(number: usize) -> Result<Call> {
         match number {
             1 => Ok(Call::Exit),
@@ -45,12 +50,14 @@ impl Call {
             6 => Ok(Call::Close),
             7 => Ok(Call::WaitPid),
             11 => Ok(Call::Exec),
+            12 => Ok(Call::ChDir),
             20 => Ok(Call::GetPid),
             41 => Ok(Call::Dup),
             45 => Ok(Call::Brk),
             110 => Ok(Call::Iopl),
             120 => Ok(Call::Clone),
             158 => Ok(Call::SchedYield),
+            183 => Ok(Call::GetCwd),
             _ => Err(Error::NoCall)
         }
     }
diff --git a/kernel/syscall/fs.rs b/kernel/syscall/fs.rs
index ddb4f8afc..acf457e29 100644
--- a/kernel/syscall/fs.rs
+++ b/kernel/syscall/fs.rs
@@ -5,6 +5,28 @@ use scheme;
 
 use super::{Error, Result};
 
+pub fn chdir(path: &[u8]) -> Result<usize> {
+    let contexts = context::contexts();
+    let context_lock = contexts.current().ok_or(Error::NoProcess)?;
+    let context = context_lock.read();
+    let canonical = context.canonicalize(path);
+    *context.cwd.lock() = canonical;
+    Ok(0)
+}
+
+pub fn getcwd(buf: &mut [u8]) -> Result<usize> {
+    let contexts = context::contexts();
+    let context_lock = contexts.current().ok_or(Error::NoProcess)?;
+    let context = context_lock.read();
+    let cwd = context.cwd.lock();
+    let mut i = 0;
+    while i < buf.len() && i < cwd.len() {
+        buf[i] = cwd[i];
+        i += 1;
+    }
+    Ok(i)
+}
+
 /// Read syscall
 pub fn read(fd: usize, buf: &mut [u8]) -> Result<usize> {
     let file = {
diff --git a/kernel/syscall/mod.rs b/kernel/syscall/mod.rs
index f27d00908..c6ab11dfa 100644
--- a/kernel/syscall/mod.rs
+++ b/kernel/syscall/mod.rs
@@ -34,12 +34,14 @@ pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize
                 Call::Close => close(b),
                 Call::WaitPid => waitpid(b, c, d),
                 Call::Exec => exec(validate_slice(b as *const u8, c)?, validate_slice(d as *const [usize; 2], e)?),
+                Call::ChDir => chdir(validate_slice(b as *const u8, c)?),
                 Call::GetPid => getpid(),
                 Call::Dup => dup(b),
                 Call::Brk => brk(b),
                 Call::Iopl => iopl(b),
                 Call::Clone => clone(b, stack),
-                Call::SchedYield => sched_yield()
+                Call::SchedYield => sched_yield(),
+                Call::GetCwd => getcwd(validate_slice_mut(b as *mut u8, c)?)
             },
             Err(err) => {
                 println!("Unknown syscall {}", a);
diff --git a/kernel/syscall/process.rs b/kernel/syscall/process.rs
index fb21a7097..182c5f972 100644
--- a/kernel/syscall/process.rs
+++ b/kernel/syscall/process.rs
@@ -1,6 +1,7 @@
 ///! Process syscalls
 
 use alloc::arc::Arc;
+use collections::Vec;
 use core::mem;
 use core::str;
 use spin::Mutex;
@@ -53,7 +54,9 @@ pub const CLONE_FILES: usize = 0x400;
 pub const CLONE_VFORK: usize = 0x4000;
 pub fn clone(flags: usize, stack_base: usize) -> Result<usize> {
     //TODO: Copy on write?
-    println!("Clone {:X}: {:X}", flags, stack_base);
+
+    // vfork not supported
+    assert!(flags & CLONE_VFORK == 0);
 
     let ppid;
     let pid;
@@ -64,7 +67,8 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<usize> {
         let mut image = vec![];
         let mut heap_option = None;
         let mut stack_option = None;
-        let mut files = Arc::new(Mutex::new(vec![]));
+        let cwd;
+        let files;
 
         // Copy from old process
         {
@@ -159,9 +163,16 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<usize> {
                 stack_option = Some(new_stack);
             }
 
+            if flags & CLONE_FS == CLONE_FS {
+                cwd = context.cwd.clone();
+            } else {
+                cwd = Arc::new(Mutex::new(context.cwd.lock().clone()));
+            }
+
             if flags & CLONE_FILES == CLONE_FILES {
                 files = context.files.clone();
             } else {
+                let mut files_vec = Vec::new();
                 for (fd, file_option) in context.files.lock().iter().enumerate() {
                     if let Some(file) = *file_option {
                         let result = {
@@ -172,16 +183,17 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<usize> {
                         };
                         match result {
                             Ok(new_number) => {
-                                files.lock().push(Some(context::file::File { scheme: file.scheme, number: new_number }));
+                                files_vec.push(Some(context::file::File { scheme: file.scheme, number: new_number }));
                             },
                             Err(err) => {
                                 println!("clone: failed to dup {}: {:?}", fd, err);
                             }
                         }
                     } else {
-                        files.lock().push(None);
+                        files_vec.push(None);
                     }
                 }
+                files = Arc::new(Mutex::new(files_vec));
             }
         }
 
@@ -289,6 +301,8 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<usize> {
                 context.stack = Some(stack);
             }
 
+            context.cwd = cwd;
+
             context.files = files;
 
             context.arch.set_page_table(unsafe { new_table.address() });
@@ -322,7 +336,6 @@ pub fn exec(path: &[u8], _args: &[[usize; 2]]) -> Result<usize> {
     //TODO: Use args
     //TODO: Unmap previous mappings
     //TODO: Drop data vec
-    println!("Exec {}", unsafe { str::from_utf8_unchecked(path) });
 
     let file = syscall::open(path, 0)?;
     let mut data = vec![];
diff --git a/libstd b/libstd
index 009209752..3483097e4 160000
--- a/libstd
+++ b/libstd
@@ -1 +1 @@
-Subproject commit 00920975234a9bc774ad6e33efd57a56a40c0ee8
+Subproject commit 3483097e4f5172fe8b4cbe0dee868d18201c12f8
diff --git a/syscall/src/lib.rs b/syscall/src/lib.rs
index 98fd080d7..ebfbc0aea 100644
--- a/syscall/src/lib.rs
+++ b/syscall/src/lib.rs
@@ -48,6 +48,7 @@ pub const SYS_FUTEX: usize = 240;
     pub const FUTEX_WAIT: usize = 0;
     pub const FUTEX_WAKE: usize = 1;
     pub const FUTEX_REQUEUE: usize = 2;
+pub const SYS_GETCWD: usize = 183;
 pub const SYS_GETPID: usize = 20;
 pub const SYS_IOPL: usize = 110;
 pub const SYS_LINK: usize = 9;
@@ -153,6 +154,10 @@ pub unsafe fn futex(addr: *mut i32, op: usize, val: i32, val2: usize, addr2: *mu
     syscall5(SYS_FUTEX, addr as usize, op, (val as isize) as usize, val2, addr2 as usize)
 }
 
+pub fn getcwd(buf: &mut [u8]) -> Result<usize> {
+    unsafe { syscall2(SYS_GETCWD, buf.as_mut_ptr() as usize, buf.len()) }
+}
+
 pub fn getpid() -> Result<usize> {
     unsafe { syscall0(SYS_GETPID) }
 }
-- 
GitLab