diff --git a/.gitmodules b/.gitmodules index e033dc2..fe424c0 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 9d394c8..3c9c5e0 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 0000000..cbb3c30 --- /dev/null +++ b/ion @@ -0,0 +1 @@ +Subproject commit cbb3c3003f654d09cd3b3cf1a179469bb1b558b3 diff --git a/kernel/context/context.rs b/kernel/context/context.rs index 6b4f7c7..43bdc61 100644 --- a/kernel/context/context.rs +++ b/kernel/context/context.rs @@ -33,6 +33,8 @@ pub struct Context { pub heap: Option, /// User stack pub stack: Option, + /// The current working directory + pub cwd: Arc>>, /// The open files in the scheme pub files: Arc>>> } @@ -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 { + 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 { diff --git a/kernel/lib.rs b/kernel/lib.rs index dce4bce..e9eec63 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 d947b5a..82e5f35 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 e62b27d..e4a7e92 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 pub fn from(number: usize) -> Result { 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 ddb4f8a..acf457e 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 { + 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 { + 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 { let file = { diff --git a/kernel/syscall/mod.rs b/kernel/syscall/mod.rs index f27d009..c6ab11d 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 fb21a70..182c5f9 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 { //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 { 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 { 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 { }; 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 { 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 { //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 0092097..3483097 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 98fd080..ebfbc0a 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 { + unsafe { syscall2(SYS_GETCWD, buf.as_mut_ptr() as usize, buf.len()) } +} + pub fn getpid() -> Result { unsafe { syscall0(SYS_GETPID) } }