Read command line args from userspace programs (#351)

* Read command line args from userspace programs

* Use Stop syscall to debug pointers from userpace

* Fix address translation system

* Update binaries

* Move print to bin

* Add hardcoded alias system

* Strip debug from binaries

* Build userspace binaries before running tests

* Save all the args in args including the command invocation name

* Move sleep command to /bin

* Rebuild binaries
This commit is contained in:
Vincent Ollivier 2022-06-14 22:43:33 +02:00 committed by GitHub
parent 6e3f3afcb0
commit dd5899a74d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 184 additions and 89 deletions

View File

@ -17,4 +17,5 @@ jobs:
- run: sudo apt-get -qqy update - run: sudo apt-get -qqy update
- run: sudo apt-get -qqy install qemu-system-x86 - run: sudo apt-get -qqy install qemu-system-x86
- run: make - run: make
- run: make user-rust
- run: make test - run: make test

View File

@ -28,6 +28,7 @@ user-rust:
-C relocation-model=static -C relocation-model=static
basename -s .rs src/bin/*.rs | xargs -I {} \ basename -s .rs src/bin/*.rs | xargs -I {} \
cp target/x86_64-moros/release/{} dsk/bin/{} cp target/x86_64-moros/release/{} dsk/bin/{}
strip dsk/bin/*
bin = target/x86_64-moros/release/bootimage-moros.bin bin = target/x86_64-moros/release/bootimage-moros.bin
img = disk.img img = disk.img

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
dsk/bin/print Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,8 +1,8 @@
use crate::api::syscall; use crate::api::syscall;
pub fn spawn(path: &str) -> Result<(), ()> { pub fn spawn(path: &str, args: &[&str]) -> Result<(), ()> {
if syscall::info(path).is_some() { if syscall::info(path).is_some() {
return syscall::spawn(path); return syscall::spawn(path, args);
} }
Err(()) Err(())
} }

View File

@ -80,10 +80,12 @@ pub fn close(handle: usize) {
unsafe { syscall!(CLOSE, handle as usize) }; unsafe { syscall!(CLOSE, handle as usize) };
} }
pub fn spawn(path: &str) -> Result<(), ()> { pub fn spawn(path: &str, args: &[&str]) -> Result<(), ()> {
let ptr = path.as_ptr() as usize; let path_ptr = path.as_ptr() as usize;
let len = path.len() as usize; let path_len = path.len() as usize;
let res = unsafe { syscall!(SPAWN, ptr, len) } as isize; let args_ptr = args.as_ptr() as usize;
let args_len = args.len() as usize;
let res = unsafe { syscall!(SPAWN, path_ptr, path_len, args_ptr, args_len) } as isize;
if res.is_negative() { if res.is_negative() {
Err(()) Err(())
} else { } else {
@ -91,12 +93,16 @@ pub fn spawn(path: &str) -> Result<(), ()> {
} }
} }
pub fn stop(code: usize) {
unsafe { syscall!(STOP, code) };
}
pub fn reboot() { pub fn reboot() {
unsafe { syscall!(STOP, 0xcafe) }; stop(0xcafe);
} }
pub fn halt() { pub fn halt() {
unsafe { syscall!(STOP, 0xdead) }; stop(0xdead);
} }
#[test_case] #[test_case]

30
src/bin/print.rs Normal file
View File

@ -0,0 +1,30 @@
#![no_std]
#![no_main]
use moros::api::syscall;
use core::panic::PanicInfo;
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
syscall::write(1, b"An exception occured!\n");
loop {}
}
#[no_mangle]
pub unsafe extern "sysv64" fn _start(args_ptr: u64, args_len: usize) {
let args = core::slice::from_raw_parts(args_ptr as *const _, args_len);
let code = main(args);
syscall::exit(code);
}
fn main(args: &[&str]) -> usize {
let n = args.len();
for i in 1..n {
syscall::write(1, args[i].as_bytes());
if i < n - 1 {
syscall::write(1, b" ");
}
}
syscall::write(1, b"\n");
0
}

28
src/bin/sleep.rs Normal file
View File

@ -0,0 +1,28 @@
#![no_std]
#![no_main]
use moros::api::syscall;
use core::panic::PanicInfo;
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
syscall::write(1, b"An exception occured!\n");
loop {}
}
#[no_mangle]
pub unsafe extern "sysv64" fn _start(args_ptr: u64, args_len: usize) {
let args = core::slice::from_raw_parts(args_ptr as *const _, args_len);
let code = main(args);
syscall::exit(code);
}
fn main(args: &[&str]) -> usize {
if args.len() == 2 {
if let Ok(duration) = args[1].parse::<f64>() {
syscall::sleep(duration);
return 0
}
}
1
}

View File

@ -44,16 +44,18 @@ pub fn init_heap(mapper: &mut impl Mapper<Size4KiB>, frame_allocator: &mut impl
Ok(()) Ok(())
} }
pub fn alloc_pages(addr: u64, size: u64) { pub fn alloc_pages(addr: u64, size: usize) {
//debug!("Alloc pages (addr={:#x}, size={})", addr, size);
let mut mapper = unsafe { sys::mem::mapper(VirtAddr::new(sys::mem::PHYS_MEM_OFFSET)) }; let mut mapper = unsafe { sys::mem::mapper(VirtAddr::new(sys::mem::PHYS_MEM_OFFSET)) };
let mut frame_allocator = unsafe { sys::mem::BootInfoFrameAllocator::init(sys::mem::MEMORY_MAP.unwrap()) }; let mut frame_allocator = unsafe { sys::mem::BootInfoFrameAllocator::init(sys::mem::MEMORY_MAP.unwrap()) };
let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::USER_ACCESSIBLE; let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::USER_ACCESSIBLE;
let pages = { let pages = {
let start_page = Page::containing_address(VirtAddr::new(addr)); let start_page = Page::containing_address(VirtAddr::new(addr));
let end_page = Page::containing_address(VirtAddr::new(addr + size - 1)); let end_page = Page::containing_address(VirtAddr::new(addr + (size as u64) - 1));
Page::range_inclusive(start_page, end_page) Page::range_inclusive(start_page, end_page)
}; };
for page in pages { for page in pages {
//debug!("Alloc page {:?}", page);
if let Some(frame) = frame_allocator.allocate_frame() { if let Some(frame) = frame_allocator.allocate_frame() {
unsafe { unsafe {
if let Ok(mapping) = mapper.map_to(page, frame, flags, &mut frame_allocator) { if let Ok(mapping) = mapper.map_to(page, frame, flags, &mut frame_allocator) {
@ -71,11 +73,11 @@ pub fn alloc_pages(addr: u64, size: u64) {
use x86_64::structures::paging::page::PageRangeInclusive; use x86_64::structures::paging::page::PageRangeInclusive;
// TODO: Replace `free` by `dealloc` // TODO: Replace `free` by `dealloc`
pub fn free_pages(addr: u64, size: u64) { pub fn free_pages(addr: u64, size: usize) {
let mut mapper = unsafe { sys::mem::mapper(VirtAddr::new(sys::mem::PHYS_MEM_OFFSET)) }; let mut mapper = unsafe { sys::mem::mapper(VirtAddr::new(sys::mem::PHYS_MEM_OFFSET)) };
let pages: PageRangeInclusive<Size4KiB> = { let pages: PageRangeInclusive<Size4KiB> = {
let start_page = Page::containing_address(VirtAddr::new(addr)); let start_page = Page::containing_address(VirtAddr::new(addr));
let end_page = Page::containing_address(VirtAddr::new(addr + size - 1)); let end_page = Page::containing_address(VirtAddr::new(addr + (size as u64) - 1));
Page::range_inclusive(start_page, end_page) Page::range_inclusive(start_page, end_page)
}; };
for page in pages { for page in pages {

View File

@ -180,13 +180,14 @@ extern "sysv64" fn syscall_handler(stack_frame: &mut InterruptStackFrame, regs:
let arg1 = regs.rdi; let arg1 = regs.rdi;
let arg2 = regs.rsi; let arg2 = regs.rsi;
let arg3 = regs.rdx; let arg3 = regs.rdx;
let arg4 = regs.r8;
if n == sys::syscall::number::SPAWN { // Backup CPU context if n == sys::syscall::number::SPAWN { // Backup CPU context
sys::process::set_stack_frame(**stack_frame); sys::process::set_stack_frame(**stack_frame);
sys::process::set_registers(*regs); sys::process::set_registers(*regs);
} }
let res = sys::syscall::dispatcher(n, arg1, arg2, arg3); let res = sys::syscall::dispatcher(n, arg1, arg2, arg3, arg4);
if n == sys::syscall::number::EXIT { // Restore CPU context if n == sys::syscall::number::EXIT { // Restore CPU context
let sf = sys::process::stack_frame(); let sf = sys::process::stack_frame();

View File

@ -14,6 +14,7 @@ use x86_64::structures::idt::InterruptStackFrameValue;
const MAX_FILE_HANDLES: usize = 64; const MAX_FILE_HANDLES: usize = 64;
const MAX_PROCS: usize = 2; // TODO: Update this when more than one process can run at once const MAX_PROCS: usize = 2; // TODO: Update this when more than one process can run at once
const MAX_PROC_SIZE: usize = 1 << 20; // 1 MB
lazy_static! { lazy_static! {
pub static ref PID: AtomicUsize = AtomicUsize::new(0); pub static ref PID: AtomicUsize = AtomicUsize::new(0);
@ -145,7 +146,12 @@ pub fn set_code_addr(addr: u64) {
} }
pub fn ptr_from_addr(addr: u64) -> *mut u8 { pub fn ptr_from_addr(addr: u64) -> *mut u8 {
(code_addr() + addr) as *mut u8 let base = code_addr();
if addr < base {
(base + addr) as *mut u8
} else {
addr as *mut u8
}
} }
pub fn registers() -> Registers { pub fn registers() -> Registers {
@ -175,7 +181,7 @@ pub fn set_stack_frame(stack_frame: InterruptStackFrameValue) {
pub fn exit() { pub fn exit() {
let table = PROCESS_TABLE.read(); let table = PROCESS_TABLE.read();
let proc = &table[id()]; let proc = &table[id()];
sys::allocator::free_pages(proc.code_addr, proc.code_size); sys::allocator::free_pages(proc.code_addr, MAX_PROC_SIZE);
MAX_PID.fetch_sub(1, Ordering::SeqCst); MAX_PID.fetch_sub(1, Ordering::SeqCst);
set_id(0); // FIXME: No process manager so we switch back to process 0 set_id(0); // FIXME: No process manager so we switch back to process 0
} }
@ -193,7 +199,6 @@ use core::sync::atomic::AtomicU64;
use x86_64::VirtAddr; use x86_64::VirtAddr;
static CODE_ADDR: AtomicU64 = AtomicU64::new((sys::allocator::HEAP_START as u64) + (16 << 20)); static CODE_ADDR: AtomicU64 = AtomicU64::new((sys::allocator::HEAP_START as u64) + (16 << 20));
const PAGE_SIZE: u64 = 4 * 1024;
#[repr(align(8), C)] #[repr(align(8), C)]
#[derive(Debug, Clone, Copy, Default)] #[derive(Debug, Clone, Copy, Default)]
@ -216,7 +221,7 @@ const BIN_MAGIC: [u8; 4] = [0x7F, b'B', b'I', b'N'];
pub struct Process { pub struct Process {
id: usize, id: usize,
code_addr: u64, code_addr: u64,
code_size: u64, stack_addr: u64,
entry_point: u64, entry_point: u64,
stack_frame: InterruptStackFrameValue, stack_frame: InterruptStackFrameValue,
registers: Registers, registers: Registers,
@ -235,7 +240,7 @@ impl Process {
Self { Self {
id, id,
code_addr: 0, code_addr: 0,
code_size: 0, stack_addr: 0,
entry_point: 0, entry_point: 0,
stack_frame: isf, stack_frame: isf,
registers: Registers::default(), registers: Registers::default(),
@ -243,13 +248,13 @@ impl Process {
} }
} }
pub fn spawn(bin: &[u8]) -> Result<(), ()> { pub fn spawn(bin: &[u8], args_ptr: usize, args_len: usize) -> Result<(), ()> {
if let Ok(pid) = Self::create(bin) { if let Ok(pid) = Self::create(bin) {
let proc = { let proc = {
let table = PROCESS_TABLE.read(); let table = PROCESS_TABLE.read();
table[pid].clone() table[pid].clone()
}; };
proc.exec(); proc.exec(args_ptr, args_len);
Ok(()) Ok(())
} else { } else {
Err(()) Err(())
@ -257,35 +262,29 @@ impl Process {
} }
fn create(bin: &[u8]) -> Result<usize, ()> { fn create(bin: &[u8]) -> Result<usize, ()> {
// Allocate some memory for the code and the stack of the program let proc_size = MAX_PROC_SIZE as u64;
let code_size = 1 * PAGE_SIZE; let code_addr = CODE_ADDR.fetch_add(proc_size, Ordering::SeqCst);
let code_addr = CODE_ADDR.fetch_add(code_size, Ordering::SeqCst); let stack_addr = code_addr + proc_size;
let mut entry_point = 0; let mut entry_point = 0;
let code_ptr = code_addr as *mut u8; let code_ptr = code_addr as *mut u8;
if bin[0..4] == ELF_MAGIC { // ELF binary if bin[0..4] == ELF_MAGIC { // ELF binary
if let Ok(obj) = object::File::parse(bin) { if let Ok(obj) = object::File::parse(bin) {
sys::allocator::alloc_pages(code_addr, code_size); //sys::allocator::alloc_pages(code_addr, code_size);
entry_point = obj.entry(); entry_point = obj.entry();
for segment in obj.segments() { for segment in obj.segments() {
let addr = segment.address() as usize; let addr = segment.address() as usize;
if let Ok(data) = segment.data() { if let Ok(data) = segment.data() {
for (i, op) in data.iter().enumerate() { for (i, b) in data.iter().enumerate() {
unsafe { unsafe { core::ptr::write(code_ptr.add(addr + i), *b) };
let ptr = code_ptr.add(addr + i);
core::ptr::write(ptr, *op);
}
} }
} }
} }
} }
} else if bin[0..4] == BIN_MAGIC { // Flat binary } else if bin[0..4] == BIN_MAGIC { // Flat binary
sys::allocator::alloc_pages(code_addr, code_size); //sys::allocator::alloc_pages(code_addr, code_size);
for (i, op) in bin.iter().skip(4).enumerate() { for (i, b) in bin.iter().skip(4).enumerate() {
unsafe { unsafe { core::ptr::write(code_ptr.add(i), *b) };
let ptr = code_ptr.add(i);
core::ptr::write(ptr, *op);
}
} }
} else { } else {
return Err(()); return Err(());
@ -299,28 +298,58 @@ impl Process {
let stack_frame = parent.stack_frame; let stack_frame = parent.stack_frame;
let id = MAX_PID.fetch_add(1, Ordering::SeqCst); let id = MAX_PID.fetch_add(1, Ordering::SeqCst);
let proc = Process { id, code_addr, code_size, entry_point, data, stack_frame, registers }; let proc = Process { id, code_addr, stack_addr, entry_point, data, stack_frame, registers };
table[id] = Box::new(proc); table[id] = Box::new(proc);
Ok(id) Ok(id)
} }
// Switch to user mode and execute the program // Switch to user mode and execute the program
fn exec(&self) { fn exec(&self, args_ptr: usize, args_len: usize) {
let args_ptr = ptr_from_addr(args_ptr as u64) as usize;
let args: &[&str] = unsafe { core::slice::from_raw_parts(args_ptr as *const &str, args_len) };
let heap_addr = self.code_addr + (self.stack_addr - self.code_addr) / 2;
let mut ptr = heap_addr;
let vec: Vec<&str> = args.iter().map(|arg| {
let src_len = arg.len();
let src_ptr = arg.as_ptr();
let dst_ptr = ptr as *mut u8;
//let dst_ptr_translated = ((dst_ptr as u64) - self.code_addr) as *const u8; // Userspace address
ptr = ((dst_ptr as usize) + src_len) as u64;
unsafe {
core::ptr::copy_nonoverlapping(src_ptr, dst_ptr, src_len);
//core::str::from_utf8_unchecked(core::slice::from_raw_parts(dst_ptr_translated, src_len))
core::str::from_utf8_unchecked(core::slice::from_raw_parts(dst_ptr, src_len))
}
}).collect();
let args = vec.as_slice();
let src_len = args.len();
let src_ptr = args.as_ptr();
let dst_ptr = ptr as *mut &str;
let args: &[&str] = unsafe {
core::ptr::copy_nonoverlapping(src_ptr, dst_ptr, src_len);
core::slice::from_raw_parts(dst_ptr, src_len)
};
//let args_ptr = (args.as_ptr() as u64) - self.code_addr; // userspace address
let args_ptr = args.as_ptr() as u64;
set_id(self.id); // Change PID set_id(self.id); // Change PID
unsafe { unsafe {
asm!( asm!(
"cli", // Disable interrupts "cli", // Disable interrupts
"push rax", // Stack segment (SS) "push {:r}", // Stack segment (SS)
"push rsi", // Stack pointer (RSP) "push {:r}", // Stack pointer (RSP)
"push 0x200", // RFLAGS with interrupts enabled "push 0x200", // RFLAGS with interrupts enabled
"push rdx", // Code segment (CS) "push {:r}", // Code segment (CS)
"push rdi", // Instruction pointer (RIP) "push {:r}", // Instruction pointer (RIP)
"iretq", "iretq",
in("rax") GDT.1.user_data.0, in(reg) GDT.1.user_data.0,
in("rsi") self.code_addr + self.code_size, in(reg) self.stack_addr,
in("rdx") GDT.1.user_code.0, in(reg) GDT.1.user_code.0,
in("rdi") self.code_addr + self.entry_point, in(reg) self.code_addr + self.entry_point,
in("rdi") args_ptr,
in("rsi") args_len,
); );
} }
} }

View File

@ -10,7 +10,7 @@ use core::arch::asm;
* Dispatching system calls * Dispatching system calls
*/ */
pub fn dispatcher(n: usize, arg1: usize, arg2: usize, arg3: usize) -> usize { pub fn dispatcher(n: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize) -> usize {
match n { match n {
number::EXIT => { number::EXIT => {
service::exit(arg1) service::exit(arg1)
@ -50,7 +50,7 @@ pub fn dispatcher(n: usize, arg1: usize, arg2: usize, arg3: usize) -> usize {
let handle = arg1; let handle = arg1;
let ptr = sys::process::ptr_from_addr(arg2 as u64); let ptr = sys::process::ptr_from_addr(arg2 as u64);
let len = arg3; let len = arg3;
let buf = unsafe { core::slice::from_raw_parts_mut(ptr, len) }; let buf = unsafe { core::slice::from_raw_parts_mut(ptr, len) }; // TODO: Remove mut
service::write(handle, buf) as usize service::write(handle, buf) as usize
} }
number::CLOSE => { number::CLOSE => {
@ -64,10 +64,14 @@ pub fn dispatcher(n: usize, arg1: usize, arg2: usize, arg3: usize) -> usize {
service::dup(old_handle, new_handle) as usize service::dup(old_handle, new_handle) as usize
} }
number::SPAWN => { number::SPAWN => {
let ptr = sys::process::ptr_from_addr(arg1 as u64); let path_ptr = sys::process::ptr_from_addr(arg1 as u64);
let len = arg2; let path_len = arg2;
let path = unsafe { core::str::from_utf8_unchecked(core::slice::from_raw_parts(ptr, len)) }; let path = unsafe { core::str::from_utf8_unchecked(core::slice::from_raw_parts(path_ptr, path_len)) };
service::spawn(path) as usize
let args_ptr = arg3;
let args_len = arg4;
service::spawn(path, args_ptr, args_len) as usize
} }
number::STOP => { number::STOP => {
service::stop(arg1) service::stop(arg1)
@ -125,6 +129,17 @@ pub unsafe fn syscall3(n: usize, arg1: usize, arg2: usize, arg3: usize) -> usize
res res
} }
#[doc(hidden)]
pub unsafe fn syscall4(n: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize) -> usize {
let res: usize;
asm!(
"int 0x80", in("rax") n,
in("rdi") arg1, in("rsi") arg2, in("rdx") arg3, in("r8") arg4,
lateout("rax") res
);
res
}
#[macro_export] #[macro_export]
macro_rules! syscall { macro_rules! syscall {
($n:expr) => ( ($n:expr) => (
@ -139,4 +154,7 @@ macro_rules! syscall {
($n:expr, $a1:expr, $a2:expr, $a3:expr) => ( ($n:expr, $a1:expr, $a2:expr, $a3:expr) => (
$crate::sys::syscall::syscall3( $crate::sys::syscall::syscall3(
$n as usize, $a1 as usize, $a2 as usize, $a3 as usize)); $n as usize, $a1 as usize, $a2 as usize, $a3 as usize));
($n:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr) => (
$crate::sys::syscall::syscall4(
$n as usize, $a1 as usize, $a2 as usize, $a3 as usize, $a4 as usize));
} }

View File

@ -80,7 +80,7 @@ pub fn close(handle: usize) {
sys::process::delete_file_handle(handle); sys::process::delete_file_handle(handle);
} }
pub fn spawn(path: &str) -> isize { pub fn spawn(path: &str, args_ptr: usize, args_len: usize) -> isize {
let path = match sys::fs::canonicalize(path) { let path = match sys::fs::canonicalize(path) {
Ok(path) => path, Ok(path) => path,
Err(_) => return -1, Err(_) => return -1,
@ -89,7 +89,7 @@ pub fn spawn(path: &str) -> isize {
let mut buf = vec![0; file.size()]; let mut buf = vec![0; file.size()];
if let Ok(bytes) = file.read(&mut buf) { if let Ok(bytes) = file.read(&mut buf) {
buf.resize(bytes, 0); buf.resize(bytes, 0);
if Process::spawn(&buf).is_ok() { if Process::spawn(&buf, args_ptr, args_len).is_ok() {
return 0; return 0;
} }
} }
@ -110,7 +110,9 @@ pub fn stop(code: usize) -> usize {
0xdead => { // Halt 0xdead => { // Halt
sys::acpi::shutdown(); sys::acpi::shutdown();
} }
_ => {} _ => {
debug!("STOP SYSCALL: Invalid code '{:#x}' received", code);
}
} }
0 0
} }

View File

@ -20,7 +20,9 @@ pub fn copy_files(verbose: bool) {
copy_file("/bin/clear", include_bytes!("../../dsk/bin/clear"), verbose); copy_file("/bin/clear", include_bytes!("../../dsk/bin/clear"), verbose);
copy_file("/bin/halt", include_bytes!("../../dsk/bin/halt"), verbose); copy_file("/bin/halt", include_bytes!("../../dsk/bin/halt"), verbose);
copy_file("/bin/hello", include_bytes!("../../dsk/bin/hello"), verbose); copy_file("/bin/hello", include_bytes!("../../dsk/bin/hello"), verbose);
copy_file("/bin/print", include_bytes!("../../dsk/bin/print"), verbose);
copy_file("/bin/reboot", include_bytes!("../../dsk/bin/reboot"), verbose); copy_file("/bin/reboot", include_bytes!("../../dsk/bin/reboot"), verbose);
copy_file("/bin/sleep", include_bytes!("../../dsk/bin/sleep"), verbose);
create_dir("/dev/clk", verbose); // Clocks create_dir("/dev/clk", verbose); // Clocks
create_dev("/dev/clk/uptime", DeviceType::Uptime, verbose); create_dev("/dev/clk/uptime", DeviceType::Uptime, verbose);

View File

@ -26,11 +26,9 @@ pub mod memory;
pub mod net; pub mod net;
pub mod pci; pub mod pci;
pub mod pow; pub mod pow;
pub mod print;
pub mod r#move; pub mod r#move;
pub mod read; pub mod read;
pub mod shell; pub mod shell;
pub mod sleep;
pub mod socket; pub mod socket;
pub mod tcp; pub mod tcp;
pub mod time; pub mod time;

View File

@ -1,13 +0,0 @@
use crate::usr;
pub fn main(args: &[&str]) -> usr::shell::ExitCode {
let n = args.len();
for i in 1..n {
print!("{}", args[i]);
if i < n - 1 {
print!(" ");
}
}
println!();
usr::shell::ExitCode::CommandSuccessful
}

View File

@ -12,11 +12,11 @@ use alloc::vec::Vec;
use alloc::string::{String, ToString}; use alloc::string::{String, ToString};
// TODO: Scan /bin // TODO: Scan /bin
const AUTOCOMPLETE_COMMANDS: [&str; 37] = [ const AUTOCOMPLETE_COMMANDS: [&str; 35] = [
"2048", "base64", "calc", "colors", "copy", "date", "delete", "dhcp", "disk", "edit", "2048", "base64", "calc", "colors", "copy", "date", "delete", "dhcp", "disk", "edit",
"env", "exit", "geotime", "goto", "help", "hex", "host", "http", "httpd", "install", "env", "exit", "geotime", "goto", "help", "hex", "host", "http", "httpd", "install",
"keyboard", "lisp", "list", "memory", "move", "net", "pci", "print", "read", "keyboard", "lisp", "list", "memory", "move", "net", "pci", "read",
"shell", "sleep", "socket", "tcp", "time", "user", "vga", "write" "shell", "socket", "tcp", "time", "user", "vga", "write"
]; ];
#[repr(u8)] #[repr(u8)]
@ -276,7 +276,6 @@ pub fn exec(cmd: &str, env: &mut BTreeMap<String, String>) -> ExitCode {
"m" | "move" => usr::r#move::main(&args), "m" | "move" => usr::r#move::main(&args),
"n" => ExitCode::CommandUnknown, "n" => ExitCode::CommandUnknown,
"o" => ExitCode::CommandUnknown, "o" => ExitCode::CommandUnknown,
"p" | "print" => usr::print::main(&args),
"q" | "quit" | "exit" => ExitCode::ShellExit, "q" | "quit" | "exit" => ExitCode::ShellExit,
"r" | "read" => usr::read::main(&args), "r" | "read" => usr::read::main(&args),
"s" => ExitCode::CommandUnknown, "s" => ExitCode::CommandUnknown,
@ -289,7 +288,6 @@ pub fn exec(cmd: &str, env: &mut BTreeMap<String, String>) -> ExitCode {
"z" => ExitCode::CommandUnknown, "z" => ExitCode::CommandUnknown,
"vga" => usr::vga::main(&args), "vga" => usr::vga::main(&args),
"sh" | "shell" => usr::shell::main(&args), "sh" | "shell" => usr::shell::main(&args),
"sleep" => usr::sleep::main(&args),
"calc" => usr::calc::main(&args), "calc" => usr::calc::main(&args),
"base64" => usr::base64::main(&args), "base64" => usr::base64::main(&args),
"date" => usr::date::main(&args), "date" => usr::date::main(&args),
@ -328,7 +326,7 @@ pub fn exec(cmd: &str, env: &mut BTreeMap<String, String>) -> ExitCode {
ExitCode::CommandSuccessful ExitCode::CommandSuccessful
} }
Some(FileType::File) => { Some(FileType::File) => {
if api::process::spawn(&path).is_ok() { if api::process::spawn(&path, &args[1..]).is_ok() {
// TODO: get exit code // TODO: get exit code
ExitCode::CommandSuccessful ExitCode::CommandSuccessful
} else { } else {
@ -337,8 +335,12 @@ pub fn exec(cmd: &str, env: &mut BTreeMap<String, String>) -> ExitCode {
} }
} }
_ => { _ => {
// TODO: add aliases // TODO: add aliases command instead of hardcoding them
if api::process::spawn(&format!("/bin/{}", args[0])).is_ok() { let name = match args[0] {
"p" => "print",
arg => arg,
};
if api::process::spawn(&format!("/bin/{}", name), &args).is_ok() {
ExitCode::CommandSuccessful ExitCode::CommandSuccessful
} else { } else {
error!("Could not execute '{}'", cmd); error!("Could not execute '{}'", cmd);

View File

@ -1,12 +0,0 @@
use crate::usr;
use crate::api::syscall;
pub fn main(args: &[&str]) -> usr::shell::ExitCode {
if args.len() == 2 {
if let Ok(duration) = args[1].parse::<f64>() {
syscall::sleep(duration);
return usr::shell::ExitCode::CommandSuccessful;
}
}
usr::shell::ExitCode::CommandError
}