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