mirror of https://github.com/vinc/moros.git
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:
parent
6e3f3afcb0
commit
dd5899a74d
|
@ -17,4 +17,5 @@ jobs:
|
|||
- run: sudo apt-get -qqy update
|
||||
- run: sudo apt-get -qqy install qemu-system-x86
|
||||
- run: make
|
||||
- run: make user-rust
|
||||
- run: make test
|
||||
|
|
1
Makefile
1
Makefile
|
@ -28,6 +28,7 @@ user-rust:
|
|||
-C relocation-model=static
|
||||
basename -s .rs src/bin/*.rs | xargs -I {} \
|
||||
cp target/x86_64-moros/release/{} dsk/bin/{}
|
||||
strip dsk/bin/*
|
||||
|
||||
bin = target/x86_64-moros/release/bootimage-moros.bin
|
||||
img = disk.img
|
||||
|
|
BIN
dsk/bin/clear
BIN
dsk/bin/clear
Binary file not shown.
BIN
dsk/bin/halt
BIN
dsk/bin/halt
Binary file not shown.
BIN
dsk/bin/hello
BIN
dsk/bin/hello
Binary file not shown.
Binary file not shown.
BIN
dsk/bin/reboot
BIN
dsk/bin/reboot
Binary file not shown.
BIN
dsk/bin/sleep
BIN
dsk/bin/sleep
Binary file not shown.
|
@ -1,8 +1,8 @@
|
|||
use crate::api::syscall;
|
||||
|
||||
pub fn spawn(path: &str) -> Result<(), ()> {
|
||||
pub fn spawn(path: &str, args: &[&str]) -> Result<(), ()> {
|
||||
if syscall::info(path).is_some() {
|
||||
return syscall::spawn(path);
|
||||
return syscall::spawn(path, args);
|
||||
}
|
||||
Err(())
|
||||
}
|
||||
|
|
|
@ -80,10 +80,12 @@ pub fn close(handle: usize) {
|
|||
unsafe { syscall!(CLOSE, handle as usize) };
|
||||
}
|
||||
|
||||
pub fn spawn(path: &str) -> Result<(), ()> {
|
||||
let ptr = path.as_ptr() as usize;
|
||||
let len = path.len() as usize;
|
||||
let res = unsafe { syscall!(SPAWN, ptr, len) } as isize;
|
||||
pub fn spawn(path: &str, args: &[&str]) -> Result<(), ()> {
|
||||
let path_ptr = path.as_ptr() as usize;
|
||||
let path_len = path.len() as usize;
|
||||
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() {
|
||||
Err(())
|
||||
} else {
|
||||
|
@ -91,12 +93,16 @@ pub fn spawn(path: &str) -> Result<(), ()> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn stop(code: usize) {
|
||||
unsafe { syscall!(STOP, code) };
|
||||
}
|
||||
|
||||
pub fn reboot() {
|
||||
unsafe { syscall!(STOP, 0xcafe) };
|
||||
stop(0xcafe);
|
||||
}
|
||||
|
||||
pub fn halt() {
|
||||
unsafe { syscall!(STOP, 0xdead) };
|
||||
stop(0xdead);
|
||||
}
|
||||
|
||||
#[test_case]
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -44,16 +44,18 @@ pub fn init_heap(mapper: &mut impl Mapper<Size4KiB>, frame_allocator: &mut impl
|
|||
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 frame_allocator = unsafe { sys::mem::BootInfoFrameAllocator::init(sys::mem::MEMORY_MAP.unwrap()) };
|
||||
let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::USER_ACCESSIBLE;
|
||||
let pages = {
|
||||
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)
|
||||
};
|
||||
for page in pages {
|
||||
//debug!("Alloc page {:?}", page);
|
||||
if let Some(frame) = frame_allocator.allocate_frame() {
|
||||
unsafe {
|
||||
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;
|
||||
|
||||
// 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 pages: PageRangeInclusive<Size4KiB> = {
|
||||
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)
|
||||
};
|
||||
for page in pages {
|
||||
|
|
|
@ -180,13 +180,14 @@ extern "sysv64" fn syscall_handler(stack_frame: &mut InterruptStackFrame, regs:
|
|||
let arg1 = regs.rdi;
|
||||
let arg2 = regs.rsi;
|
||||
let arg3 = regs.rdx;
|
||||
let arg4 = regs.r8;
|
||||
|
||||
if n == sys::syscall::number::SPAWN { // Backup CPU context
|
||||
sys::process::set_stack_frame(**stack_frame);
|
||||
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
|
||||
let sf = sys::process::stack_frame();
|
||||
|
|
|
@ -14,6 +14,7 @@ use x86_64::structures::idt::InterruptStackFrameValue;
|
|||
|
||||
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_PROC_SIZE: usize = 1 << 20; // 1 MB
|
||||
|
||||
lazy_static! {
|
||||
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 {
|
||||
(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 {
|
||||
|
@ -175,7 +181,7 @@ pub fn set_stack_frame(stack_frame: InterruptStackFrameValue) {
|
|||
pub fn exit() {
|
||||
let table = PROCESS_TABLE.read();
|
||||
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);
|
||||
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;
|
||||
|
||||
static CODE_ADDR: AtomicU64 = AtomicU64::new((sys::allocator::HEAP_START as u64) + (16 << 20));
|
||||
const PAGE_SIZE: u64 = 4 * 1024;
|
||||
|
||||
#[repr(align(8), C)]
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
|
@ -216,7 +221,7 @@ const BIN_MAGIC: [u8; 4] = [0x7F, b'B', b'I', b'N'];
|
|||
pub struct Process {
|
||||
id: usize,
|
||||
code_addr: u64,
|
||||
code_size: u64,
|
||||
stack_addr: u64,
|
||||
entry_point: u64,
|
||||
stack_frame: InterruptStackFrameValue,
|
||||
registers: Registers,
|
||||
|
@ -235,7 +240,7 @@ impl Process {
|
|||
Self {
|
||||
id,
|
||||
code_addr: 0,
|
||||
code_size: 0,
|
||||
stack_addr: 0,
|
||||
entry_point: 0,
|
||||
stack_frame: isf,
|
||||
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) {
|
||||
let proc = {
|
||||
let table = PROCESS_TABLE.read();
|
||||
table[pid].clone()
|
||||
};
|
||||
proc.exec();
|
||||
proc.exec(args_ptr, args_len);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(())
|
||||
|
@ -257,35 +262,29 @@ impl Process {
|
|||
}
|
||||
|
||||
fn create(bin: &[u8]) -> Result<usize, ()> {
|
||||
// Allocate some memory for the code and the stack of the program
|
||||
let code_size = 1 * PAGE_SIZE;
|
||||
let code_addr = CODE_ADDR.fetch_add(code_size, Ordering::SeqCst);
|
||||
let proc_size = MAX_PROC_SIZE as u64;
|
||||
let code_addr = CODE_ADDR.fetch_add(proc_size, Ordering::SeqCst);
|
||||
let stack_addr = code_addr + proc_size;
|
||||
|
||||
let mut entry_point = 0;
|
||||
let code_ptr = code_addr as *mut u8;
|
||||
if bin[0..4] == ELF_MAGIC { // ELF binary
|
||||
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();
|
||||
for segment in obj.segments() {
|
||||
let addr = segment.address() as usize;
|
||||
if let Ok(data) = segment.data() {
|
||||
for (i, op) in data.iter().enumerate() {
|
||||
unsafe {
|
||||
let ptr = code_ptr.add(addr + i);
|
||||
core::ptr::write(ptr, *op);
|
||||
}
|
||||
for (i, b) in data.iter().enumerate() {
|
||||
unsafe { core::ptr::write(code_ptr.add(addr + i), *b) };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if bin[0..4] == BIN_MAGIC { // Flat binary
|
||||
sys::allocator::alloc_pages(code_addr, code_size);
|
||||
for (i, op) in bin.iter().skip(4).enumerate() {
|
||||
unsafe {
|
||||
let ptr = code_ptr.add(i);
|
||||
core::ptr::write(ptr, *op);
|
||||
}
|
||||
//sys::allocator::alloc_pages(code_addr, code_size);
|
||||
for (i, b) in bin.iter().skip(4).enumerate() {
|
||||
unsafe { core::ptr::write(code_ptr.add(i), *b) };
|
||||
}
|
||||
} else {
|
||||
return Err(());
|
||||
|
@ -299,28 +298,58 @@ impl Process {
|
|||
let stack_frame = parent.stack_frame;
|
||||
|
||||
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);
|
||||
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
// 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
|
||||
unsafe {
|
||||
asm!(
|
||||
"cli", // Disable interrupts
|
||||
"push rax", // Stack segment (SS)
|
||||
"push rsi", // Stack pointer (RSP)
|
||||
"push {:r}", // Stack segment (SS)
|
||||
"push {:r}", // Stack pointer (RSP)
|
||||
"push 0x200", // RFLAGS with interrupts enabled
|
||||
"push rdx", // Code segment (CS)
|
||||
"push rdi", // Instruction pointer (RIP)
|
||||
"push {:r}", // Code segment (CS)
|
||||
"push {:r}", // Instruction pointer (RIP)
|
||||
"iretq",
|
||||
in("rax") GDT.1.user_data.0,
|
||||
in("rsi") self.code_addr + self.code_size,
|
||||
in("rdx") GDT.1.user_code.0,
|
||||
in("rdi") self.code_addr + self.entry_point,
|
||||
in(reg) GDT.1.user_data.0,
|
||||
in(reg) self.stack_addr,
|
||||
in(reg) GDT.1.user_code.0,
|
||||
in(reg) self.code_addr + self.entry_point,
|
||||
in("rdi") args_ptr,
|
||||
in("rsi") args_len,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ use core::arch::asm;
|
|||
* 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 {
|
||||
number::EXIT => {
|
||||
service::exit(arg1)
|
||||
|
@ -50,7 +50,7 @@ pub fn dispatcher(n: usize, arg1: usize, arg2: usize, arg3: usize) -> usize {
|
|||
let handle = arg1;
|
||||
let ptr = sys::process::ptr_from_addr(arg2 as u64);
|
||||
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
|
||||
}
|
||||
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
|
||||
}
|
||||
number::SPAWN => {
|
||||
let ptr = sys::process::ptr_from_addr(arg1 as u64);
|
||||
let len = arg2;
|
||||
let path = unsafe { core::str::from_utf8_unchecked(core::slice::from_raw_parts(ptr, len)) };
|
||||
service::spawn(path) as usize
|
||||
let path_ptr = sys::process::ptr_from_addr(arg1 as u64);
|
||||
let path_len = arg2;
|
||||
let path = unsafe { core::str::from_utf8_unchecked(core::slice::from_raw_parts(path_ptr, path_len)) };
|
||||
|
||||
let args_ptr = arg3;
|
||||
let args_len = arg4;
|
||||
|
||||
service::spawn(path, args_ptr, args_len) as usize
|
||||
}
|
||||
number::STOP => {
|
||||
service::stop(arg1)
|
||||
|
@ -125,6 +129,17 @@ pub unsafe fn syscall3(n: usize, arg1: usize, arg2: usize, arg3: usize) -> usize
|
|||
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_rules! syscall {
|
||||
($n:expr) => (
|
||||
|
@ -139,4 +154,7 @@ macro_rules! syscall {
|
|||
($n:expr, $a1:expr, $a2:expr, $a3:expr) => (
|
||||
$crate::sys::syscall::syscall3(
|
||||
$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));
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ pub fn close(handle: usize) {
|
|||
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) {
|
||||
Ok(path) => path,
|
||||
Err(_) => return -1,
|
||||
|
@ -89,7 +89,7 @@ pub fn spawn(path: &str) -> isize {
|
|||
let mut buf = vec![0; file.size()];
|
||||
if let Ok(bytes) = file.read(&mut buf) {
|
||||
buf.resize(bytes, 0);
|
||||
if Process::spawn(&buf).is_ok() {
|
||||
if Process::spawn(&buf, args_ptr, args_len).is_ok() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -110,7 +110,9 @@ pub fn stop(code: usize) -> usize {
|
|||
0xdead => { // Halt
|
||||
sys::acpi::shutdown();
|
||||
}
|
||||
_ => {}
|
||||
_ => {
|
||||
debug!("STOP SYSCALL: Invalid code '{:#x}' received", code);
|
||||
}
|
||||
}
|
||||
0
|
||||
}
|
||||
|
|
|
@ -20,7 +20,9 @@ pub fn copy_files(verbose: bool) {
|
|||
copy_file("/bin/clear", include_bytes!("../../dsk/bin/clear"), verbose);
|
||||
copy_file("/bin/halt", include_bytes!("../../dsk/bin/halt"), 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/sleep", include_bytes!("../../dsk/bin/sleep"), verbose);
|
||||
|
||||
create_dir("/dev/clk", verbose); // Clocks
|
||||
create_dev("/dev/clk/uptime", DeviceType::Uptime, verbose);
|
||||
|
|
|
@ -26,11 +26,9 @@ pub mod memory;
|
|||
pub mod net;
|
||||
pub mod pci;
|
||||
pub mod pow;
|
||||
pub mod print;
|
||||
pub mod r#move;
|
||||
pub mod read;
|
||||
pub mod shell;
|
||||
pub mod sleep;
|
||||
pub mod socket;
|
||||
pub mod tcp;
|
||||
pub mod time;
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -12,11 +12,11 @@ use alloc::vec::Vec;
|
|||
use alloc::string::{String, ToString};
|
||||
|
||||
// TODO: Scan /bin
|
||||
const AUTOCOMPLETE_COMMANDS: [&str; 37] = [
|
||||
const AUTOCOMPLETE_COMMANDS: [&str; 35] = [
|
||||
"2048", "base64", "calc", "colors", "copy", "date", "delete", "dhcp", "disk", "edit",
|
||||
"env", "exit", "geotime", "goto", "help", "hex", "host", "http", "httpd", "install",
|
||||
"keyboard", "lisp", "list", "memory", "move", "net", "pci", "print", "read",
|
||||
"shell", "sleep", "socket", "tcp", "time", "user", "vga", "write"
|
||||
"keyboard", "lisp", "list", "memory", "move", "net", "pci", "read",
|
||||
"shell", "socket", "tcp", "time", "user", "vga", "write"
|
||||
];
|
||||
|
||||
#[repr(u8)]
|
||||
|
@ -276,7 +276,6 @@ pub fn exec(cmd: &str, env: &mut BTreeMap<String, String>) -> ExitCode {
|
|||
"m" | "move" => usr::r#move::main(&args),
|
||||
"n" => ExitCode::CommandUnknown,
|
||||
"o" => ExitCode::CommandUnknown,
|
||||
"p" | "print" => usr::print::main(&args),
|
||||
"q" | "quit" | "exit" => ExitCode::ShellExit,
|
||||
"r" | "read" => usr::read::main(&args),
|
||||
"s" => ExitCode::CommandUnknown,
|
||||
|
@ -289,7 +288,6 @@ pub fn exec(cmd: &str, env: &mut BTreeMap<String, String>) -> ExitCode {
|
|||
"z" => ExitCode::CommandUnknown,
|
||||
"vga" => usr::vga::main(&args),
|
||||
"sh" | "shell" => usr::shell::main(&args),
|
||||
"sleep" => usr::sleep::main(&args),
|
||||
"calc" => usr::calc::main(&args),
|
||||
"base64" => usr::base64::main(&args),
|
||||
"date" => usr::date::main(&args),
|
||||
|
@ -328,7 +326,7 @@ pub fn exec(cmd: &str, env: &mut BTreeMap<String, String>) -> ExitCode {
|
|||
ExitCode::CommandSuccessful
|
||||
}
|
||||
Some(FileType::File) => {
|
||||
if api::process::spawn(&path).is_ok() {
|
||||
if api::process::spawn(&path, &args[1..]).is_ok() {
|
||||
// TODO: get exit code
|
||||
ExitCode::CommandSuccessful
|
||||
} else {
|
||||
|
@ -337,8 +335,12 @@ pub fn exec(cmd: &str, env: &mut BTreeMap<String, String>) -> ExitCode {
|
|||
}
|
||||
}
|
||||
_ => {
|
||||
// TODO: add aliases
|
||||
if api::process::spawn(&format!("/bin/{}", args[0])).is_ok() {
|
||||
// TODO: add aliases command instead of hardcoding them
|
||||
let name = match args[0] {
|
||||
"p" => "print",
|
||||
arg => arg,
|
||||
};
|
||||
if api::process::spawn(&format!("/bin/{}", name), &args).is_ok() {
|
||||
ExitCode::CommandSuccessful
|
||||
} else {
|
||||
error!("Could not execute '{}'", cmd);
|
||||
|
|
|
@ -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
|
||||
}
|
Loading…
Reference in New Issue