use crate::arch::drivers::sysinfo::master; use crate::filesystem::FILE_SYSTEM; use crate::time::fetch_time; use crate::wasm_jumploader::interp; use crate::ALLOCATOR; use crate::{ arch::{shutdown, sloop}, systeminfo::{KERNEL_VERSION, RELEASE_TYPE}, KERNEL_STATE, }; use genfs::{Fs, OpenOptions}; use rhai::Engine; use spin::Lazy; use x86_64::instructions::interrupts::{disable, enable}; pub const RHAISHELL_VERSION: &str = "0.1.0"; pub static KEYBUFF: spin::Mutex> = spin::Mutex::new(Vec::new()); pub static CURRENT_DIR: Lazy> = Lazy::new(|| spin::Mutex::new("/".to_string())); #[cfg(target_arch = "riscv64")] pub fn shell() {} #[cfg(target_arch = "x86_64")] pub fn shell() { let _current_dir = "/".to_string(); let engine = engine_construction(); let mut scope = rhai::Scope::new(); println!("Rhaishell v{}", RHAISHELL_VERSION); let mut buf = String::new(); print!("> "); loop { match x86_64::instructions::interrupts::without_interrupts(|| KEYBUFF.lock().pop()) { Some('\n') => { if buf == "quit" { println!("Bye!"); break; } match engine.eval_with_scope::(&mut scope, &buf) { Ok(o) => println!("{o}"), Err(e) => println!("Eval error: {e}"), }; buf.clear(); print!("> "); } Some('\u{0008}') => { buf.pop(); } Some('\u{0009}') => { buf.push(' '); buf.push(' '); buf.push(' '); buf.push(' '); } Some(chr) => buf.push(chr), None => (), } } } pub fn afetch() { let kstate = KERNEL_STATE.lock(); let tick_time = fetch_time(); disable(); let allocator = ALLOCATOR.lock(); let size = allocator.size(); let used = allocator.used(); enable(); println!( include_str!("balloon.txt"), kstate.hostname, RELEASE_TYPE, KERNEL_VERSION, tick_time, master().unwrap().brand_string().unwrap(), // "", // mem used, size ); drop(kstate); } pub fn set_hostname(name: String) { let mut kstate = KERNEL_STATE.lock(); kstate.hostname = name; } /// Examine a memory pointer pub fn peek_memory(ptr: i64) -> i64 { unsafe { *(ptr as *const u8) as _ } } pub fn poke_memory(ptr: i64, val: i64) { match val.try_into() { Ok(val) => unsafe { *(ptr as *mut u8) = val }, Err(_) => error!("{val} cannot be converted into u8"), } } pub fn ls() { let current_dir = CURRENT_DIR.lock(); let fs = &*FILE_SYSTEM.lock(); let file = fs .open(current_dir.as_bytes(), OpenOptions::new().read(true)) .unwrap(); let mut files = file.directory().unwrap(); println!("current dir: {}", *current_dir); while let Some(Ok(entry)) = files.next() { let inode_name = entry.name; let s = String::from_utf8_lossy(&inode_name); println!("{}", s); } } pub fn log_dump() { use crate::network::socket::SimpleSock; use crate::relib::network::socket::Socket; let log_socket_id = SimpleSock::grab_socket("Logger".to_string()); match log_socket_id { Some(mut log_socket_id) => { let log = log_socket_id.peek(); match log { crate::network::socket::SocketReturns::ReadOk(ok) => { for x in ok.iter() { print!("{}", *x as char); } } crate::network::socket::SocketReturns::ReadIndexOutOfBounds => todo!(), crate::network::socket::SocketReturns::WriteOk => todo!(), } } None => warn!("No socket found for Logger"), } } pub fn echo_file(path: String) { let mut current_dir = CURRENT_DIR.lock(); let fs = &*FILE_SYSTEM.lock(); current_dir.push_str(&path); let file = fs .open(current_dir.as_bytes(), OpenOptions::new().read(true)) .unwrap(); if file.is_dir() { println!("{} is a directory", path); } else { let mut file_contents = Vec::new(); let _ret = file.read_to_end(&mut file_contents).unwrap(); let file_contents_str = String::from_utf8_lossy(&file_contents); println!("{}", file_contents_str); } } pub fn change_directory(path: String) { let mut current_dir = CURRENT_DIR.lock(); let _fs = &*FILE_SYSTEM.lock(); if path == "." || path == ".." { let mut split_dir = current_dir.split('/').collect::>(); let mut new_dir = String::new(); split_dir.remove(split_dir.len() - 1); println!("{:?}", split_dir); if split_dir.is_empty() { new_dir = "/".to_string(); } else { for x in split_dir { new_dir.push_str(x); new_dir.push('/'); } } *current_dir = new_dir; } else { if !current_dir.ends_with('/') { current_dir.push('/'); } current_dir.push_str(&path); } } fn engine_construction() -> Engine { let mut engine = rhai::Engine::new(); engine.on_print(|x| println!("{}", x)); engine.on_debug(|x, src, pos| { let src = src.unwrap_or("unknown"); println!("DEBUG: {} at {:?}: {}", src, pos, x); debug!("{} at {:?}: {}", src, pos, x); }); engine.register_fn("afetch", afetch); engine.register_fn("set_hostname", set_hostname); engine.register_fn("shutdown", shutdown); engine.register_fn("peek", peek_memory); engine.register_fn("poke", poke_memory); engine.register_fn("sloop", sloop); engine.register_fn("log_dump", log_dump); engine }