2018-11-15 20:49:42 +04:00
|
|
|
//! Kernel shell
|
|
|
|
|
|
|
|
use alloc::string::String;
|
2019-02-28 11:50:58 +04:00
|
|
|
use alloc::vec::Vec;
|
2018-11-19 13:21:06 +04:00
|
|
|
use crate::fs::{ROOT_INODE, INodeExt};
|
|
|
|
use crate::process::*;
|
2019-01-24 15:03:45 +04:00
|
|
|
use crate::thread;
|
2018-11-15 20:49:42 +04:00
|
|
|
|
2018-11-15 21:22:47 +04:00
|
|
|
pub fn run_user_shell() {
|
2019-02-26 16:46:51 +04:00
|
|
|
use crate::net::server;
|
|
|
|
processor().manager().add(Thread::new_kernel(server, 0), 0);
|
2018-11-28 21:22:44 +04:00
|
|
|
if let Ok(inode) = ROOT_INODE.lookup("sh") {
|
2018-12-15 16:17:02 +04:00
|
|
|
println!("Going to user mode shell.");
|
|
|
|
println!("Use 'ls' to list available programs.");
|
2018-11-28 21:22:44 +04:00
|
|
|
let data = inode.read_as_vec().unwrap();
|
2019-01-25 18:58:49 +04:00
|
|
|
processor().manager().add(Thread::new_user(data.as_slice(), "sh".split(' ')), 0);
|
2018-11-28 21:22:44 +04:00
|
|
|
} else {
|
2019-01-25 18:58:49 +04:00
|
|
|
processor().manager().add(Thread::new_kernel(shell, 0), 0);
|
2018-11-28 21:22:44 +04:00
|
|
|
}
|
2018-11-15 21:22:47 +04:00
|
|
|
}
|
2018-11-15 20:49:42 +04:00
|
|
|
|
2018-11-28 21:22:44 +04:00
|
|
|
pub extern fn shell(_arg: usize) -> ! {
|
2018-11-15 20:49:42 +04:00
|
|
|
let files = ROOT_INODE.list().unwrap();
|
|
|
|
println!("Available programs: {:?}", files);
|
2019-02-28 11:50:58 +04:00
|
|
|
let mut history = Vec::new();
|
2018-11-15 20:49:42 +04:00
|
|
|
|
|
|
|
loop {
|
|
|
|
print!(">> ");
|
2019-02-28 11:50:58 +04:00
|
|
|
let cmd = get_line(&mut history);
|
2018-11-15 20:49:42 +04:00
|
|
|
if cmd == "" {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
let name = cmd.split(' ').next().unwrap();
|
|
|
|
if let Ok(file) = ROOT_INODE.lookup(name) {
|
2018-11-15 21:22:47 +04:00
|
|
|
let data = file.read_as_vec().unwrap();
|
2019-01-25 18:58:49 +04:00
|
|
|
let pid = processor().manager().add(Thread::new_user(data.as_slice(), cmd.split(' ')), thread::current().id());
|
2018-11-15 21:22:47 +04:00
|
|
|
unsafe { thread::JoinHandle::<()>::_of(pid) }.join().unwrap();
|
2018-11-15 20:49:42 +04:00
|
|
|
} else {
|
|
|
|
println!("Program not exist");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-28 11:50:58 +04:00
|
|
|
const BEL: u8 = 0x07u8;
|
|
|
|
const BS: u8 = 0x08u8;
|
|
|
|
const LF: u8 = 0x0au8;
|
|
|
|
const CR: u8 = 0x0du8;
|
|
|
|
const ESC: u8 = 0x1bu8;
|
|
|
|
const DEL: u8 = 0x7fu8;
|
|
|
|
|
|
|
|
fn get_line(history: &mut Vec<Vec<u8>>) -> String {
|
|
|
|
let mut cursor = 0;
|
|
|
|
let mut line_vec = Vec::with_capacity(512);
|
|
|
|
let mut history_index = history.len();
|
2018-11-15 20:49:42 +04:00
|
|
|
loop {
|
2019-02-28 11:50:58 +04:00
|
|
|
match get_char() {
|
|
|
|
BS | DEL => {
|
|
|
|
// Backspace
|
|
|
|
if cursor > 0 {
|
|
|
|
cursor -= 1;
|
|
|
|
line_vec.remove(cursor);
|
|
|
|
|
|
|
|
put_char(BS);
|
|
|
|
for byte in &line_vec[cursor..] {
|
|
|
|
put_char(*byte);
|
|
|
|
}
|
|
|
|
put_char(b' ');
|
|
|
|
for _i in cursor..line_vec.len() {
|
|
|
|
put_char(ESC);
|
|
|
|
put_char(b'[');
|
|
|
|
put_char(b'D');
|
|
|
|
}
|
|
|
|
put_char(ESC);
|
|
|
|
put_char(b'[');
|
|
|
|
put_char(b'D');
|
|
|
|
} else {
|
|
|
|
put_char(BEL);
|
2018-11-15 20:49:42 +04:00
|
|
|
}
|
|
|
|
}
|
2019-02-28 11:50:58 +04:00
|
|
|
CR | LF => {
|
|
|
|
// Return
|
|
|
|
put_char(CR);
|
|
|
|
put_char(LF);
|
|
|
|
break;
|
2018-11-15 20:49:42 +04:00
|
|
|
}
|
2019-02-28 11:50:58 +04:00
|
|
|
ESC => {
|
|
|
|
match get_char() {
|
|
|
|
b'[' => {
|
|
|
|
match get_char() {
|
|
|
|
b'D' => {
|
|
|
|
// Left arrow
|
|
|
|
if cursor > 0 {
|
|
|
|
cursor -= 1;
|
|
|
|
put_char(ESC);
|
|
|
|
put_char(b'[');
|
|
|
|
put_char(b'D');
|
|
|
|
} else {
|
|
|
|
put_char(BEL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
b'C' => {
|
|
|
|
// Right arrow
|
|
|
|
if cursor < line_vec.len() {
|
|
|
|
cursor += 1;
|
|
|
|
put_char(ESC);
|
|
|
|
put_char(b'[');
|
|
|
|
put_char(b'C');
|
|
|
|
} else {
|
|
|
|
put_char(BEL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
direction @ b'A' | direction @ b'B' => {
|
|
|
|
if direction == b'A' && history_index > 0 {
|
|
|
|
// Up arrow
|
|
|
|
history_index -= 1;
|
|
|
|
} else if direction == b'B' && history.len() > 0 // usize underflow
|
|
|
|
&& history_index < history.len() - 1
|
|
|
|
{
|
|
|
|
// Down arrow
|
|
|
|
history_index += 1;
|
|
|
|
} else {
|
|
|
|
put_char(BEL);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
for _ in 0..line_vec.len() {
|
|
|
|
put_char(ESC);
|
|
|
|
put_char(b'[');
|
|
|
|
put_char(b'D');
|
|
|
|
}
|
|
|
|
for _ in 0..line_vec.len() {
|
|
|
|
put_char(b' ');
|
|
|
|
}
|
|
|
|
for _ in 0..line_vec.len() {
|
|
|
|
put_char(ESC);
|
|
|
|
put_char(b'[');
|
|
|
|
put_char(b'D');
|
|
|
|
}
|
|
|
|
line_vec = history[history_index].clone();
|
|
|
|
cursor = line_vec.len();
|
|
|
|
for byte in &line_vec {
|
|
|
|
put_char(*byte);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
put_char(BEL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
put_char(BEL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
byte if byte.is_ascii_graphic() || byte == b' ' => {
|
|
|
|
line_vec.insert(cursor, byte);
|
|
|
|
for byte in &line_vec[cursor..] {
|
|
|
|
put_char(*byte);
|
|
|
|
}
|
|
|
|
cursor += 1;
|
|
|
|
for _i in cursor..line_vec.len() {
|
2019-02-28 11:53:41 +04:00
|
|
|
put_char(ESC);
|
|
|
|
put_char(b'[');
|
|
|
|
put_char(b'D');
|
2019-02-28 11:50:58 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
// unrecognized characters
|
|
|
|
put_char(BEL);
|
2018-11-15 20:49:42 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-02-28 11:50:58 +04:00
|
|
|
|
|
|
|
history.push(line_vec.clone());
|
|
|
|
String::from_utf8(line_vec).unwrap_or_default()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_char() -> u8 {
|
|
|
|
crate::fs::STDIN.pop() as u8
|
2018-11-15 20:49:42 +04:00
|
|
|
}
|
|
|
|
|
2019-02-28 11:50:58 +04:00
|
|
|
fn put_char(ch: u8) {
|
|
|
|
print!("{}", ch as char);
|
2018-11-15 20:49:42 +04:00
|
|
|
}
|