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