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 map() -> Option<Arc<Mutex<CommandMap>>>38 pub fn map() -> Option<Arc<Mutex<CommandMap>>> { 39 unsafe { BUILD_IN_CMD.clone() } 40 } 41 init()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 shell_cmd_cd(args: &Vec<String>) -> Result<(), ExecuteErrorType>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 shell_cmd_exec(args: &Vec<String>) -> Result<(), ExecuteErrorType>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 pgrp = unsafe { libc::tcgetpgrp(libc::STDIN_FILENO) }; 97 98 // 如果当前终端的前台进程等于当前进程,则设置前台进程 99 let run_foreground = if pgrp >= 0 { 100 if pgrp as u32 == std::process::id() { 101 true 102 } else { 103 false 104 } 105 } else { 106 false 107 }; 108 109 let mut err: Option<ExecuteErrorType> = None; 110 111 match std::process::Command::new(real_path) 112 .args(args) 113 .current_dir(EnvManager::current_dir()) 114 .spawn() 115 { 116 Ok(mut child) => { 117 if run_foreground { 118 unsafe { libc::tcsetpgrp(libc::STDIN_FILENO, child.id() as i32) }; 119 } 120 121 match child.wait() { 122 Ok(exit_status) => match exit_status.code() { 123 Some(exit_code) => { 124 if exit_code != 0 { 125 err = Some(ExecuteErrorType::ExitWithCode(exit_code)); 126 } 127 } 128 None => err = Some(ExecuteErrorType::ProcessTerminated), 129 }, 130 Err(_) => err = Some(ExecuteErrorType::ExecuteFailed), 131 } 132 133 if run_foreground { 134 unsafe { libc::tcsetpgrp(libc::STDIN_FILENO, std::process::id() as i32) }; 135 } 136 } 137 Err(_) => todo!(), 138 }; 139 return if let Some(err) = err { 140 Err(err) 141 } else { 142 Ok(()) 143 }; 144 } else { 145 return Err(ExecuteErrorType::TooFewArguments); 146 } 147 } 148 shell_cmd_reboot(args: &Vec<String>) -> Result<(), ExecuteErrorType>149 fn shell_cmd_reboot(args: &Vec<String>) -> Result<(), ExecuteErrorType> { 150 if args.len() == 0 { 151 unsafe { libc::syscall(libc::SYS_reboot, 0, 0, 0, 0, 0, 0) }; 152 return Ok(()); 153 } else { 154 return Err(ExecuteErrorType::TooManyArguments); 155 } 156 } 157 shell_cmd_free(args: &Vec<String>) -> Result<(), ExecuteErrorType>158 fn shell_cmd_free(args: &Vec<String>) -> Result<(), ExecuteErrorType> { 159 if args.len() == 1 && args.get(0).unwrap() != "-m" { 160 return Err(ExecuteErrorType::InvalidArgument( 161 args.get(0).unwrap().to_string(), 162 )); 163 } 164 165 struct Mstat { 166 total: u64, // 计算机的总内存数量大小 167 used: u64, // 已使用的内存大小 168 free: u64, // 空闲物理页所占的内存大小 169 shared: u64, // 共享的内存大小 170 cache_used: u64, // 位于slab缓冲区中的已使用的内存大小 171 cache_free: u64, // 位于slab缓冲区中的空闲的内存大小 172 available: u64, // 系统总空闲内存大小(包括kmalloc缓冲区) 173 } 174 175 let mut mst = Mstat { 176 total: 0, 177 used: 0, 178 free: 0, 179 shared: 0, 180 cache_used: 0, 181 cache_free: 0, 182 available: 0, 183 }; 184 185 let mut info_file = File::open("/proc/meminfo").unwrap(); 186 let mut buf: Vec<u8> = Vec::new(); 187 info_file.read_to_end(&mut buf).unwrap(); 188 let str = String::from_utf8(buf).unwrap(); 189 let info = str 190 .split(&['\n', '\t', ' ']) 191 .filter_map(|str| str.parse::<u64>().ok()) 192 .collect::<Vec<u64>>(); 193 mst.total = *info.get(0).unwrap(); 194 mst.free = *info.get(1).unwrap(); 195 mst.used = mst.total - mst.free; 196 197 print!("\ttotal\t\tused\t\tfree\t\tshared\t\tcache_used\tcache_free\tavailable\n"); 198 print!("Mem:\t"); 199 200 if args.len() == 0 { 201 print!( 202 "{}\t\t{}\t\t{}\t\t{}\t\t{}\t\t{}\t\t{}\n", 203 mst.total, 204 mst.used, 205 mst.free, 206 mst.shared, 207 mst.cache_used, 208 mst.cache_free, 209 mst.available 210 ); 211 } else { 212 print!( 213 "{}\t\t{}\t\t{}\t\t{}\t\t{}\t\t{}\n", 214 mst.total >> 10, 215 mst.used >> 10, 216 mst.free >> 10, 217 mst.shared >> 10, 218 mst.cache_used >> 10, 219 mst.available >> 10 220 ); 221 } 222 Ok(()) 223 } 224 shell_cmd_help(args: &Vec<String>) -> Result<(), ExecuteErrorType>225 fn shell_cmd_help(args: &Vec<String>) -> Result<(), ExecuteErrorType> { 226 if args.len() == 0 { 227 unsafe { Helper::help() }; 228 return Ok(()); 229 } 230 return Err(ExecuteErrorType::TooManyArguments); 231 } 232 shell_cmd_export(args: &Vec<String>) -> Result<(), ExecuteErrorType>233 fn shell_cmd_export(args: &Vec<String>) -> Result<(), ExecuteErrorType> { 234 if args.len() == 1 { 235 let pair = args.get(0).unwrap().split('=').collect::<Vec<&str>>(); 236 237 if pair.len() == 2 && !pair.contains(&"") { 238 let name = pair.get(0).unwrap().to_string(); 239 let value = pair.get(1).unwrap().to_string(); 240 std::env::set_var(name, value); 241 return Ok(()); 242 } else { 243 return Err(ExecuteErrorType::InvalidArgument( 244 args.get(0).unwrap().clone(), 245 )); 246 } 247 } 248 return Err(ExecuteErrorType::TooManyArguments); 249 } 250 } 251