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