diff --git a/Makefile b/Makefile index e399257..e268819 100644 --- a/Makefile +++ b/Makefile @@ -70,6 +70,9 @@ ifeq ($(arch), $(filter $(arch), x86_64 aarch64)) @mv tmp/bin/busybox $(busybox) @rm -rf tmp && rm busybox.tar.xz endif +ifeq ($(arch), riscv64) + @wget https://github.com/rcore-os/busybox-riscv-prebuilts/raw/master/busybox-1.30.1-riscv64/busybox -O $(busybox) +endif busybox: $(busybox) diff --git a/rust/src/bin/sh.rs b/rust/src/bin/sh.rs index 5a80bbe..c7932d4 100644 --- a/rust/src/bin/sh.rs +++ b/rust/src/bin/sh.rs @@ -10,7 +10,7 @@ use alloc::vec::Vec; use core::ptr; use rcore_user::io::get_line; -use rcore_user::syscall::{sys_exec, sys_vfork, sys_wait}; +use rcore_user::syscall::{sys_exec, sys_vfork, sys_wait, sys_getcwd, sys_chdir, sys_access}; // IMPORTANT: Must define main() like this #[no_mangle] @@ -19,10 +19,12 @@ pub fn main() -> i32 { let mut history = Vec::new(); loop { - print!(">> "); + print!("{}> ", sys_getcwd()); let cmd = get_line(&mut history); // split cmd, make argc & argv + // to-do: handle quotes let cmd = cmd.replace(' ', "\0") + "\0"; + let cmds: Vec<&str> = cmd.split('\0').collect(); let mut ptrs: Vec = cmd .split('\0') .filter(|s| !s.is_empty()) @@ -31,20 +33,33 @@ pub fn main() -> i32 { if ptrs.is_empty() { continue; } - ptrs.push(0); // indicate the end of argv - - let pid = sys_vfork(); - assert!(pid >= 0); - if pid == 0 { - return sys_exec( - ptrs[0] as *const u8, - ptrs.as_ptr() as *const *const u8, - ptr::null(), - ); + + if cmds.len() == 3 { + // handle cd + if cmds[0] == "cd" { + sys_chdir(cmds[1]); + continue; + } + } + + if sys_access(cmds[0]) == 0 { + ptrs.push(0); // indicate the end of argv + + let pid = sys_vfork(); + assert!(pid >= 0); + if pid == 0 { + return sys_exec( + ptrs[0] as *const u8, + ptrs.as_ptr() as *const *const u8, + ptr::null(), + ); + } else { + let mut code: i32 = 0; + sys_wait(pid as usize, &mut code); + println!("\n[Process exited with code {}]", code); + } } else { - let mut code: i32 = 0; - sys_wait(pid as usize, &mut code); - println!("\n[Process exited with code {}]", code); + println!("\n[Command {} not found]", cmds[0]); } } } diff --git a/rust/src/syscall.rs b/rust/src/syscall.rs index d368199..76bf121 100644 --- a/rust/src/syscall.rs +++ b/rust/src/syscall.rs @@ -1,4 +1,5 @@ use crate::ALLOCATOR; +use alloc::string::String; #[inline(always)] fn sys_call(syscall_id: SyscallId, arg0: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) -> i32 { @@ -111,6 +112,25 @@ pub fn sys_getpid() -> i32 { sys_call(SyscallId::GetPid, 0, 0, 0, 0, 0, 0) } +/// Get the current working directory +pub fn sys_getcwd() -> String { + let buffer = [0u8; 256]; + sys_call(SyscallId::GetCwd, buffer.as_ptr() as usize, 256, 0, 0, 0, 0); + String::from_utf8(buffer.to_vec()).unwrap() +} + +/// Change the current working directory +pub fn sys_chdir(path: &str) { + let path = String::from(path) + "\0"; + sys_call(SyscallId::Chdir, path.as_bytes().as_ptr() as usize, 0, 0, 0, 0, 0); +} + +/// Check file accessibility +pub fn sys_access(path: &str) -> i32 { + let path = String::from(path) + "\0"; + sys_call(SyscallId::FAccessAt, -100isize as usize, path.as_bytes().as_ptr() as usize, 0, 0, 0, 0) +} + #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct TimeSpec { @@ -171,11 +191,13 @@ enum SyscallId { Kill = 62, Fsync = 74, GetCwd = 79, + Chdir = 80, GetTime = 96, SetPriority = 141, ArchPrctl = 158, GetDirEntry64 = 217, Openat = 257, + FAccessAt = 269, Dup3 = 292, // custom MapPciDevice = 999, @@ -187,14 +209,12 @@ enum SyscallId { enum SyscallId { Read = 63, Write = 64, - Openat = 56, Close = 57, Fstat = 80, Seek = 62, Mmap = 222, Munmap = 215, Yield = 124, - Dup3 = 24, Sleep = 101, GetPid = 172, Clone = 220, @@ -203,11 +223,15 @@ enum SyscallId { Wait = 260, Kill = 129, Fsync = 82, - GetDirEntry64 = 61, GetCwd = 17, + Chdir = 49, GetTime = 169, SetPriority = 140, ArchPrctl = -4, + GetDirEntry64 = 61, + Openat = 56, + Dup3 = 24, + FAccessAt = 269, // custom MapPciDevice = 999, GetPaddr = 998,