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