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