xref: /DragonReach/src/parse/mod.rs (revision b58bd5a17ff5d5ea5385adc176e215cd2b9a485c)
1 use crate::error::ParseErrorType;
2 use crate::unit::{BaseUnit, Unit};
3 use crate::{
4     error::ParseError,
5     unit::{service::ServiceUnitAttr, BaseUnitAttr, InstallUnitAttr, UnitType},
6 };
7 
8 #[cfg(target_os = "dragonos")]
9 use drstd as std;
10 
11 use hashbrown::HashMap;
12 use lazy_static::lazy_static;
13 use std::format;
14 use std::fs::File;
15 use std::io::{self, BufRead};
16 use std::rc::Rc;
17 use std::string::String;
18 use std::vec::Vec;
19 use std::string::ToString;
20 
21 pub mod parse_target;
22 pub mod parse_service;
23 pub mod parse_util;
24 
25 //对应Unit段类型
26 #[derive(PartialEq, Clone, Copy)]
27 pub enum Segment {
28     None,
29     Unit,
30     Install,
31     Service,
32 }
33 
34 lazy_static! {
35     pub static ref UNIT_SUFFIX: HashMap<&'static str, UnitType> = {
36         let mut table = HashMap::new();
37         table.insert("automount", UnitType::Automount);
38         table.insert("device", UnitType::Device);
39         table.insert("mount", UnitType::Mount);
40         table.insert("path", UnitType::Path);
41         table.insert("scope", UnitType::Scope);
42         table.insert("service", UnitType::Service);
43         table.insert("slice", UnitType::Automount);
44         table.insert("automount", UnitType::Slice);
45         table.insert("socket", UnitType::Socket);
46         table.insert("swap", UnitType::Swap);
47         table.insert("target", UnitType::Target);
48         table.insert("timer", UnitType::Timer);
49         table
50     };
51     pub static ref SEGMENT_TABLE: HashMap<&'static str, Segment> = {
52         let mut table = HashMap::new();
53         table.insert("[Unit]", Segment::Unit);
54         table.insert("[Install]", Segment::Install);
55         table.insert("[Service]", Segment::Service);
56         table
57     };
58     pub static ref INSTALL_UNIT_ATTR_TABLE: HashMap<&'static str, InstallUnitAttr> = {
59         let mut unit_attr_table = HashMap::new();
60         unit_attr_table.insert("WantedBy", InstallUnitAttr::WantedBy);
61         unit_attr_table.insert("RequiredBy", InstallUnitAttr::RequiredBy);
62         unit_attr_table.insert("Also", InstallUnitAttr::Also);
63         unit_attr_table.insert("Alias", InstallUnitAttr::Alias);
64         unit_attr_table
65     };
66     pub static ref SERVICE_UNIT_ATTR_TABLE: HashMap<&'static str, ServiceUnitAttr> = {
67         let mut unit_attr_table = HashMap::new();
68         unit_attr_table.insert("Type", ServiceUnitAttr::Type);
69         unit_attr_table.insert("RemainAfterExit", ServiceUnitAttr::RemainAfterExit);
70         unit_attr_table.insert("ExecStart", ServiceUnitAttr::ExecStart);
71         unit_attr_table.insert("ExecStartPre", ServiceUnitAttr::ExecStartPre);
72         unit_attr_table.insert("ExecStartPos", ServiceUnitAttr::ExecStartPos);
73         unit_attr_table.insert("ExecReload", ServiceUnitAttr::ExecReload);
74         unit_attr_table.insert("ExecStop", ServiceUnitAttr::ExecStop);
75         unit_attr_table.insert("ExecStopPost", ServiceUnitAttr::ExecStopPost);
76         unit_attr_table.insert("RestartSec", ServiceUnitAttr::RestartSec);
77         unit_attr_table.insert("Restart", ServiceUnitAttr::Restart);
78         unit_attr_table.insert("TimeoutStartSec", ServiceUnitAttr::TimeoutStartSec);
79         unit_attr_table.insert("TimeoutStopSec", ServiceUnitAttr::TimeoutStopSec);
80         unit_attr_table.insert("Environment", ServiceUnitAttr::Environment);
81         unit_attr_table.insert("EnvironmentFile", ServiceUnitAttr::EnvironmentFile);
82         unit_attr_table.insert("Nice", ServiceUnitAttr::Nice);
83         unit_attr_table.insert("WorkingDirectory", ServiceUnitAttr::WorkingDirectory);
84         unit_attr_table.insert("RootDirectory", ServiceUnitAttr::RootDirectory);
85         unit_attr_table.insert("User", ServiceUnitAttr::User);
86         unit_attr_table.insert("Group", ServiceUnitAttr::Group);
87         unit_attr_table.insert("MountFlags", ServiceUnitAttr::MountFlags);
88         unit_attr_table
89     };
90     pub static ref BASE_UNIT_ATTR_TABLE: HashMap<&'static str, BaseUnitAttr> = {
91         let mut unit_attr_table = HashMap::new();
92         unit_attr_table.insert("Description", BaseUnitAttr::Description);
93         unit_attr_table.insert("Documentation", BaseUnitAttr::Documentation);
94         unit_attr_table.insert("Requires", BaseUnitAttr::Requires);
95         unit_attr_table.insert("Wants", BaseUnitAttr::Wants);
96         unit_attr_table.insert("After", BaseUnitAttr::After);
97         unit_attr_table.insert("Before", BaseUnitAttr::Before);
98         unit_attr_table.insert("Binds To", BaseUnitAttr::BindsTo);
99         unit_attr_table.insert("Part Of", BaseUnitAttr::PartOf);
100         unit_attr_table.insert("OnFailure", BaseUnitAttr::OnFailure);
101         unit_attr_table.insert("Conflicts", BaseUnitAttr::Conflicts);
102         unit_attr_table
103     };
104     pub static ref BASE_IEC: HashMap<&'static str, u64> = {
105         let mut table = HashMap::new();
106         table.insert(
107             "E",
108             1024u64 * 1024u64 * 1024u64 * 1024u64 * 1024u64 * 1024u64,
109         );
110         table.insert("P", 1024u64 * 1024u64 * 1024u64 * 1024u64 * 1024u64);
111         table.insert("T", 1024u64 * 1024u64 * 1024u64 * 1024u64);
112         table.insert("G", 1024u64 * 1024u64 * 1024u64);
113         table.insert("M", 1024u64 * 1024u64);
114         table.insert("K", 1024u64);
115         table.insert("B", 1u64);
116         table.insert("", 1u64);
117         table
118     };
119     pub static ref BASE_SI: HashMap<&'static str, u64> = {
120         let mut table = HashMap::new();
121         table.insert(
122             "E",
123             1000u64 * 1000u64 * 1000u64 * 1000u64 * 1000u64 * 1000u64,
124         );
125         table.insert("P", 1000u64 * 1000u64 * 1000u64 * 1000u64 * 1000u64);
126         table.insert("T", 1000u64 * 1000u64 * 1000u64 * 1000u64);
127         table.insert("G", 1000u64 * 1000u64 * 1000u64);
128         table.insert("M", 1000u64 * 1000u64);
129         table.insert("K", 1000u64);
130         table.insert("B", 1u64);
131         table.insert("", 1u64);
132         table
133     };
134     pub static ref SEC_UNIT_TABLE: HashMap<&'static str, u64> = {
135         let mut table = HashMap::new();
136         table.insert("h", 60 * 60 * 1000 * 1000 * 1000);
137         table.insert("min", 60 * 1000 * 1000 * 1000);
138         table.insert("m", 60 * 1000 * 1000 * 1000);
139         table.insert("s", 1000 * 1000 * 1000);
140         table.insert("", 1000 * 1000 * 1000);
141         table.insert("ms", 1000 * 1000);
142         table.insert("us", 1000);
143         table.insert("ns", 1);
144         table
145     };
146 }
147 
148 //用于解析Unit共有段的方法
149 pub struct UnitParser;
150 
151 impl UnitParser {
152     /// @brief 从path获取到BufReader,此方法将会检验文件类型
153     ///
154     /// 从path获取到BufReader,此方法将会检验文件类型
155     ///
156     /// @param path 需解析的文件路径
157     ///
158     /// @param unit_type 指定Unit类型
159     ///
160     /// @return 成功则返回对应BufReader,否则返回Err
161     fn get_unit_reader(path: &str, unit_type: UnitType) -> Result<io::BufReader<File>, ParseError> {
162         let suffix = match path.rfind('.') {
163             Some(idx) => &path[idx + 1..],
164             None => {
165                 return Err(ParseError::new(ParseErrorType::EFILE, path.to_string(),0));
166             }
167         };
168         let u_type = UNIT_SUFFIX.get(suffix);
169         if u_type.is_none() {
170             return Err(ParseError::new(ParseErrorType::EFILE, path.to_string(),0));
171         }
172         if *(u_type.unwrap()) != unit_type {
173             return Err(ParseError::new(ParseErrorType::EFILE, path.to_string(),0));
174         }
175 
176         let file = match File::open(path) {
177             Ok(file) => file,
178             Err(_) => {
179                 return Err(ParseError::new(ParseErrorType::EFILE, path.to_string(),0));
180             }
181         };
182         return Ok(io::BufReader::new(file));
183     }
184 
185     /// @brief 将path路径的文件解析为unit_type类型的Unit
186     ///
187     /// 该方法解析每个Unit共有的段(Unit,Install),其余独有的段属性将会交付T类型的Unit去解析
188     ///
189     /// @param path 需解析的文件路径
190     ///
191     /// @param unit_type 指定Unit类型
192     ///
193     /// @return 解析成功则返回Ok(Rc<T>),否则返回Err
194     pub fn parse<T: Unit + Default>(path: &str, unit_type: UnitType) -> Result<Rc<T>, ParseError> {
195         let mut unit: T = T::default();
196         let mut unit_base = BaseUnit::default();
197         //设置unit类型标记
198         unit_base.set_unit_type(unit_type);
199 
200         let reader = UnitParser::get_unit_reader(path, unit_type)?;
201 
202         //用于记录当前段的类型
203         let mut segment = Segment::None;
204         //用于处理多行对应一个属性的情况
205         let mut last_attr = ServiceUnitAttr::None;
206 
207         //一行一行向下解析
208         let lines = reader
209             .lines()
210             .map(|line| line.unwrap())
211             .collect::<Vec<String>>();
212         let mut i = 0;
213         while i < lines.len() {
214             let line = &lines[i];
215             //空行跳过
216             if line.chars().all(char::is_whitespace) {
217                 i += 1;
218                 continue;
219             }
220             //注释跳过
221             if line.starts_with('#') {
222                 i += 1;
223                 continue;
224             }
225             let mut line = line.trim();
226             let segment_flag = SEGMENT_TABLE.get(&line);
227             if !segment_flag.is_none() {
228                 //如果当前行匹配到的为段名,则切换段类型继续匹配下一行
229                 segment = *segment_flag.unwrap();
230                 i += 1;
231                 continue;
232             }
233             if segment == Segment::None {
234                 //未找到段名则不能继续匹配
235                 return Err(ParseError::new(ParseErrorType::ESyntaxError, path.to_string(),i + 1));
236             }
237 
238             //下面进行属性匹配
239             //合并多行为一个属性的情况
240             //最后一个字符为\,代表换行,将多行转换为一行统一解析
241             if lines[i].ends_with('\\') {
242                 let mut templine = String::new();
243                 while lines[i].ends_with('\\') {
244                     let temp = &lines[i][..lines[i].len() - 1];
245                     templine = format!("{} {}", templine, temp);
246                     i += 1;
247                 }
248                 templine = format!("{} {}", templine, lines[i]);
249                 line = templine.as_str();
250                 i += 1;
251                 break;
252             }
253             //=号分割后第一个元素为属性,后面的均为值,若一行出现两个等号则是语法错误
254             let (attr_str,val_str) = match line.find('=') {
255                 Some(idx) => {
256                     (line[..idx].trim(), line[idx+1..].trim())
257                 }
258                 None => {
259                     return Err(ParseError::new(ParseErrorType::ESyntaxError, path.to_string(),i + 1));
260                 }
261             };
262             //首先匹配所有unit文件都有的unit段和install段
263             if BASE_UNIT_ATTR_TABLE.get(attr_str).is_some() {
264                 if segment != Segment::Unit {
265                     return Err(ParseError::new(ParseErrorType::EINVAL, path.to_string(),i + 1));
266                 }
267                 if let Err(e) = unit_base.set_unit_part_attr(
268                     BASE_UNIT_ATTR_TABLE.get(attr_str).unwrap(),
269                     val_str,
270                 ){
271                     let mut e = e.clone();
272                     e.set_file(path);
273                     e.set_linenum(i + 1);
274                     return Err(e);
275                 }
276             } else if INSTALL_UNIT_ATTR_TABLE.get(attr_str).is_some() {
277                 if segment != Segment::Install {
278                     return Err(ParseError::new(ParseErrorType::EINVAL, path.to_string(),i + 1));
279                 }
280                 if let Err(e) = unit_base.set_install_part_attr(
281                     INSTALL_UNIT_ATTR_TABLE.get(attr_str).unwrap(),
282                     val_str,
283                 ){
284                     let mut e = e.clone();
285                     e.set_file(path);
286                     e.set_linenum(i + 1);
287                     return Err(e);
288                 }
289             } else {
290                 if let Err(e) = unit.set_attr(segment, attr_str, val_str){
291                     let mut e = e.clone();
292                     e.set_file(path);
293                     e.set_linenum(i + 1);
294                     return Err(e);
295                 }
296             }
297             i += 1;
298         }
299         unit.set_unit_base(unit_base);
300         return Ok(Rc::new(unit));
301     }
302 }
303