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