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