xref: /NovaShell/src/shell/command/mod.rs (revision cb835e03e4e256c633660e88ed6ed9d7b342ae0d)
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