1 use help::Helper; 2 use std::collections::HashMap; 3 use std::sync::{Arc, Mutex}; 4 use std::{fs::File, io::Read, print}; 5 6 use crate::env::{EnvManager, ROOT_PATH}; 7 use crate::parser::ExecuteErrorType; 8 9 mod help; 10 11 macro_rules! build { 12 ($cmd:expr,$func:expr) => { 13 ( 14 $cmd.to_string(), 15 $func as fn(&Vec<String>) -> Result<(), ExecuteErrorType>, 16 ) 17 }; 18 } 19 20 type CommandMap = HashMap<String, fn(&Vec<String>) -> Result<(), ExecuteErrorType>>; 21 22 static mut BUILD_IN_CMD: Option<Arc<Mutex<CommandMap>>> = None; 23 #[derive(Debug)] 24 pub struct BuildInCmd; 25 26 impl BuildInCmd { 27 // pub const BUILD_IN_CMD: &'static [BuildInCmd] = &[ 28 // BuildInCmd("cd"), 29 // BuildInCmd("exec"), 30 // BuildInCmd("reboot"), 31 // BuildInCmd("free"), 32 // BuildInCmd("help"), 33 // BuildInCmd("export"), 34 // BuildInCmd("compgen"), 35 // BuildInCmd("complete"), 36 // ]; 37 38 pub fn map() -> Option<Arc<Mutex<CommandMap>>> { 39 unsafe { BUILD_IN_CMD.clone() } 40 } 41 42 pub unsafe fn init() { 43 BUILD_IN_CMD = Some(Arc::new(Mutex::new(CommandMap::new()))); 44 let mut map = BUILD_IN_CMD.as_ref().unwrap().lock().unwrap(); 45 let mut insert = |tuple: (String, fn(&Vec<String>) -> Result<(), ExecuteErrorType>)| { 46 map.insert(tuple.0, tuple.1) 47 }; 48 49 insert(build!("cd", Self::shell_cmd_cd)); 50 insert(build!("exec", Self::shell_cmd_exec)); 51 insert(build!("reboot", Self::shell_cmd_reboot)); 52 insert(build!("help", Self::shell_cmd_help)); 53 insert(build!("free", Self::shell_cmd_free)); 54 insert(build!("export", Self::shell_cmd_export)); 55 } 56 57 pub fn shell_cmd_cd(args: &Vec<String>) -> Result<(), ExecuteErrorType> { 58 let path = match args.len() { 59 0 => String::from(ROOT_PATH), 60 1 => match std::fs::canonicalize(args.get(0).unwrap()) { 61 Ok(path) => { 62 if !path.is_dir() { 63 return Err(ExecuteErrorType::NotDir(path.to_str().unwrap().to_string())); 64 } 65 path.to_str().unwrap().to_string() 66 } 67 Err(_) => return Err(ExecuteErrorType::FileNotFound(args.get(0).unwrap().clone())), 68 }, 69 _ => return Err(ExecuteErrorType::TooManyArguments), 70 }; 71 if let Err(_) = std::env::set_current_dir(&path) { 72 return Err(ExecuteErrorType::ExecuteFailed); 73 } 74 Ok(()) 75 } 76 77 pub fn shell_cmd_exec(args: &Vec<String>) -> Result<(), ExecuteErrorType> { 78 if let Some((name, args)) = args.split_first() { 79 let real_path = if name.contains('/') { 80 // 为路径,获取规范的绝对路径 81 if let Ok(path) = std::fs::canonicalize(name) { 82 if path.is_file() { 83 Ok(path) 84 } else { 85 // 路径不为文件,返回错误 86 Err(ExecuteErrorType::NotFile(name.clone())) 87 } 88 } else { 89 Err(ExecuteErrorType::CommandNotFound) 90 } 91 } else { 92 // 不为路径,从环境变量中查找命令 93 which::which(name).map_err(|_| ExecuteErrorType::CommandNotFound) 94 }?; 95 96 let mut err: Option<ExecuteErrorType> = None; 97 98 match std::process::Command::new(real_path) 99 .args(args) 100 .current_dir(EnvManager::current_dir()) 101 .spawn() 102 { 103 Ok(mut child) => match child.wait() { 104 Ok(exit_status) => match exit_status.code() { 105 Some(exit_code) => { 106 if exit_code != 0 { 107 err = Some(ExecuteErrorType::ExitWithCode(exit_code)); 108 } 109 } 110 None => err = Some(ExecuteErrorType::ProcessTerminated), 111 }, 112 Err(_) => err = Some(ExecuteErrorType::ExecuteFailed), 113 }, 114 Err(_) => todo!(), 115 }; 116 return if let Some(err) = err { 117 Err(err) 118 } else { 119 Ok(()) 120 }; 121 } else { 122 return Err(ExecuteErrorType::TooFewArguments); 123 } 124 } 125 126 fn shell_cmd_reboot(args: &Vec<String>) -> Result<(), ExecuteErrorType> { 127 if args.len() == 0 { 128 unsafe { libc::syscall(libc::SYS_reboot, 0, 0, 0, 0, 0, 0) }; 129 return Ok(()); 130 } else { 131 return Err(ExecuteErrorType::TooManyArguments); 132 } 133 } 134 135 fn shell_cmd_free(args: &Vec<String>) -> Result<(), ExecuteErrorType> { 136 if args.len() == 1 && args.get(0).unwrap() != "-m" { 137 return Err(ExecuteErrorType::InvalidArgument( 138 args.get(0).unwrap().to_string(), 139 )); 140 } 141 142 struct Mstat { 143 total: u64, // 计算机的总内存数量大小 144 used: u64, // 已使用的内存大小 145 free: u64, // 空闲物理页所占的内存大小 146 shared: u64, // 共享的内存大小 147 cache_used: u64, // 位于slab缓冲区中的已使用的内存大小 148 cache_free: u64, // 位于slab缓冲区中的空闲的内存大小 149 available: u64, // 系统总空闲内存大小(包括kmalloc缓冲区) 150 } 151 152 let mut mst = Mstat { 153 total: 0, 154 used: 0, 155 free: 0, 156 shared: 0, 157 cache_used: 0, 158 cache_free: 0, 159 available: 0, 160 }; 161 162 let mut info_file = File::open("/proc/meminfo").unwrap(); 163 let mut buf: Vec<u8> = Vec::new(); 164 info_file.read_to_end(&mut buf).unwrap(); 165 let str = String::from_utf8(buf).unwrap(); 166 let info = str 167 .split(&['\n', '\t', ' ']) 168 .filter_map(|str| str.parse::<u64>().ok()) 169 .collect::<Vec<u64>>(); 170 mst.total = *info.get(0).unwrap(); 171 mst.free = *info.get(1).unwrap(); 172 mst.used = mst.total - mst.free; 173 174 print!("\ttotal\t\tused\t\tfree\t\tshared\t\tcache_used\tcache_free\tavailable\n"); 175 print!("Mem:\t"); 176 177 if args.len() == 0 { 178 print!( 179 "{}\t\t{}\t\t{}\t\t{}\t\t{}\t\t{}\t\t{}\n", 180 mst.total, 181 mst.used, 182 mst.free, 183 mst.shared, 184 mst.cache_used, 185 mst.cache_free, 186 mst.available 187 ); 188 } else { 189 print!( 190 "{}\t\t{}\t\t{}\t\t{}\t\t{}\t\t{}\n", 191 mst.total >> 10, 192 mst.used >> 10, 193 mst.free >> 10, 194 mst.shared >> 10, 195 mst.cache_used >> 10, 196 mst.available >> 10 197 ); 198 } 199 Ok(()) 200 } 201 202 fn shell_cmd_help(args: &Vec<String>) -> Result<(), ExecuteErrorType> { 203 if args.len() == 0 { 204 unsafe { Helper::help() }; 205 return Ok(()); 206 } 207 return Err(ExecuteErrorType::TooManyArguments); 208 } 209 210 fn shell_cmd_export(args: &Vec<String>) -> Result<(), ExecuteErrorType> { 211 if args.len() == 1 { 212 let pair = args.get(0).unwrap().split('=').collect::<Vec<&str>>(); 213 214 if pair.len() == 2 && !pair.contains(&"") { 215 let name = pair.get(0).unwrap().to_string(); 216 let value = pair.get(1).unwrap().to_string(); 217 std::env::set_var(name, value); 218 return Ok(()); 219 } else { 220 return Err(ExecuteErrorType::InvalidArgument( 221 args.get(0).unwrap().clone(), 222 )); 223 } 224 } 225 return Err(ExecuteErrorType::TooManyArguments); 226 } 227 } 228