1 use crate::{ 2 contants::{AF_INET, AF_INET6, IPV4_MIN_MTU, IPV6_MIN_MTU, PRIO_MAX, PRIO_MIN}, 3 error::{parse_error::ParseError, parse_error::ParseErrorType}, 4 task::cmdtask::CmdTask, 5 unit::{service::ServiceUnit, target::TargetUnit, Unit, UnitType, Url}, 6 FileDescriptor, 7 }; 8 9 #[cfg(target_os = "dragonos")] 10 use drstd as std; 11 12 use std::{ 13 fs, io::BufRead, os::unix::prelude::PermissionsExt, path::Path, string::String, 14 string::ToString, vec, vec::Vec, 15 }; 16 17 use super::{UnitParser, BASE_IEC, BASE_SI, SEC_UNIT_TABLE}; 18 19 #[derive(PartialEq)] 20 pub enum SizeBase { 21 IEC, 22 Si, 23 } 24 25 pub struct UnitParseUtil; 26 27 impl UnitParseUtil { 28 /// @brief 解析布尔值 29 /// 30 /// 将传入的字符串解析为布尔值 31 /// "yes","y","1","true","t","on"均可表示true 32 /// "no","n","0","false","f","off"均可表示false 33 /// 34 /// @param s 需解析的字符串 35 /// 36 /// @return 解析成功则返回Ok(解析后的值),否则返回Err 37 pub fn parse_boolean(s: &str) -> Result<bool, ParseError> { 38 let t_table: Vec<&str> = vec!["yes", "y", "1", "true", "t", "on"]; 39 let f_table: Vec<&str> = vec!["no", "n", "0", "false", "f", "off"]; 40 41 if t_table.contains(&s) { 42 return Ok(true); 43 } else if f_table.contains(&s) { 44 return Ok(false); 45 } 46 47 return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0)); 48 } 49 50 /// @brief 解析pid 51 /// 52 /// 将传入的字符串解析为pid 53 /// 54 /// @param s 需解析的字符串 55 /// 56 /// @return 解析成功则返回Ok(解析后的值),否则返回Err 57 pub fn parse_pid(s: &str) -> Result<i32, ParseError> { 58 let s = s.trim(); 59 //先使用u64变换 60 let pid_ul = match s.parse::<u64>() { 61 Ok(val) => val, 62 Err(_) => { 63 return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0)); 64 } 65 }; 66 let pid: i32 = pid_ul as i32; 67 68 if (pid as u64) != pid_ul { 69 //如果在从pid_t转换为u64之后与之前不等,则说明发生了截断,返回错误 70 return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0)); 71 } 72 73 if pid < 0 { 74 //pid小于0不合法 75 return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0)); 76 } 77 78 return Ok(pid); 79 } 80 81 /// @brief 解析pid 82 /// 83 /// 将传入的字符串解析为mode_t 84 /// 85 /// @param s 需解析的字符串 86 /// 87 /// @return 解析成功则返回Ok(解析后的值),否则返回Err 88 pub fn parse_mode(s: &str) -> Result<u32, ParseError> { 89 let s = s.trim(); 90 let m = match u32::from_str_radix(s, 8) { 91 Ok(val) => val, 92 Err(_) => { 93 return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0)); 94 } 95 }; 96 97 //如果模式大于权限的最大值则为非法权限,返回错误 98 if m > 0o7777 { 99 return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0)); 100 } 101 102 return Ok(m); 103 } 104 105 /// @brief 解析网络接口索引 106 /// 107 /// 将传入的字符串解析为网络接口索引具体值 108 /// 109 /// @param s 需解析的字符串 110 /// 111 /// @return 解析成功则返回Ok(解析后的值),否则返回Err 112 pub fn parse_ifindex(s: &str) -> Result<i32, ParseError> { 113 let s = s.trim(); 114 let ret: i32 = match s.parse::<i32>() { 115 Ok(val) => val, 116 Err(_) => { 117 return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0)); 118 } 119 }; 120 121 if ret <= 0 { 122 return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0)); 123 } 124 125 return Ok(ret); 126 } 127 128 /// @brief 解析最大传输单元(MTU) 129 /// 130 /// 将传入的字符串解析为具体值 131 /// 132 /// @param s 需解析的字符串 133 /// 134 /// @param family 网络地址族 135 /// 136 /// @return 解析成功则返回Ok(解析后的值),否则返回Err 137 pub fn parse_mtu(s: &str, family: i32) -> Result<u32, ParseError> { 138 let s = s.trim(); 139 let mtu = match s.parse::<u64>() { 140 Ok(val) => val, 141 Err(_) => { 142 //针对非法字符出错时 143 return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0)); 144 } 145 }; 146 147 //针对数据溢出时的报错 148 if mtu > u32::MAX as u64 { 149 return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0)); 150 } 151 152 let mtu: u32 = mtu as u32; 153 154 let mut min_mtu: u32 = 0; 155 //判断mtu是否合法 156 if family == AF_INET6 { 157 min_mtu = IPV6_MIN_MTU; 158 } else if family == AF_INET { 159 min_mtu = IPV4_MIN_MTU; 160 } else { 161 return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0)); 162 } 163 164 return Ok(mtu); 165 } 166 167 /// @brief 解析Size 168 /// 169 /// 将传入的字符串解析为具体的字节数 170 /// 可支持IEC二进制后缀,也可支持SI十进制后缀 171 /// 172 /// @param s 需解析的字符串 173 /// 174 /// @param base 设置为IEC二进制后缀或者SI十进制后缀 175 /// 176 /// @return 解析成功则返回Ok(解析后的值),否则返回Err 177 pub fn parse_size(s: &str, base: SizeBase) -> Result<u64, ParseError> { 178 let s = s.trim(); 179 //将s分解为数字和后缀部分 180 let (number_str, suffix) = match s.find(|c: char| !c.is_digit(10) && c != '.') { 181 Some(mid) => s.split_at(mid), 182 None => (s, ""), 183 }; 184 185 //获得数字部分的整数和小数部分 186 let (integer, fraction) = match number_str.find(".") { 187 Some(mid) => { 188 let (integer, fraction) = number_str.split_at(mid); 189 let integer = integer.parse::<u64>().unwrap(); 190 let fraction = match fraction[1..].parse::<u64>() { 191 Ok(val) => val, 192 Err(_) => { 193 return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0)); 194 } 195 }; 196 (integer, fraction) 197 } 198 None => (number_str.parse::<u64>().unwrap(), 0), 199 }; 200 201 //从表中查找到后缀所对应的字节倍数 202 let mut factor: u64 = 0; 203 if base == SizeBase::IEC { 204 factor = match BASE_IEC.get(suffix) { 205 Some(val) => *val, 206 None => { 207 return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0)); 208 } 209 } 210 } else if base == SizeBase::Si { 211 factor = match BASE_SI.get(suffix) { 212 Some(val) => *val, 213 None => { 214 return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0)); 215 } 216 } 217 } 218 219 Ok(integer * factor + (fraction * factor) / (10u64.pow(fraction.to_string().len() as u32))) 220 } 221 222 /// @brief 解析扇区大小 223 /// 224 /// 将传入的字符串解析为具体的扇区大小 225 /// 若扇区大小小于512或者大于4096,将会返回错误,若扇区大小不为2的幂,返回错误。 226 /// 227 /// @param s 需解析的字符串 228 /// 229 /// @return 解析成功则返回Ok(解析后的值),否则返回Err 230 pub fn parse_sector_size(s: &str) -> Result<u64, ParseError> { 231 let s = s.trim(); 232 let size: u64 = match s.parse::<u64>() { 233 Ok(val) => val, 234 Err(_) => { 235 return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0)); 236 } 237 }; 238 239 if size < 512 || size > 4096 { 240 return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0)); 241 } 242 243 //判断是否为2的幂,如果不是则报错 244 if (size & (size - 1)) != 0 { 245 return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0)); 246 } 247 248 return Ok(size); 249 } 250 251 /// @brief 解析范围 252 /// 253 /// 将传入的字符串解析为具体的范围 254 /// 255 /// @param s 需解析的字符串 256 /// 257 /// @return 解析成功则返回Ok(解析后的值),否则返回Err 258 pub fn parse_range(s: &str) -> Result<(u32, u32), ParseError> { 259 let mid = match s.find('-') { 260 Some(val) => val, 261 None => { 262 //如果字符串中没有'-'符号,则表示一个值,所以范围两端都为该值 263 let s = s.trim(); 264 let ret = match s.parse::<u32>() { 265 Ok(val) => val, 266 Err(_) => { 267 return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0)); 268 } 269 }; 270 return Ok((ret, ret)); 271 } 272 }; 273 274 //若字符串中存在'-',则分别解析为u32,解析失败则报错 275 let (l, r) = s.split_at(mid); 276 277 let l = l.trim(); 278 let l = match l.parse::<u32>() { 279 Ok(val) => val, 280 Err(_) => { 281 return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0)); 282 } 283 }; 284 let r = r.trim(); 285 let r = match r.parse::<u32>() { 286 Ok(val) => val, 287 Err(_) => { 288 return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0)); 289 } 290 }; 291 292 return Ok((l, r)); 293 } 294 295 /// @brief 解析文件描述符 296 /// 297 /// 将传入的字符串解析为文件描述符fd 298 /// 299 /// @param s 需解析的字符串 300 /// 301 /// @return 解析成功则返回Ok(解析后的值),否则返回Err 302 pub fn parse_fd(s: &str) -> Result<FileDescriptor, ParseError> { 303 let s = s.trim(); 304 let fd = match s.parse::<i32>() { 305 Ok(val) => val, 306 Err(_) => { 307 return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0)); 308 } 309 }; 310 311 if fd < 0 { 312 return Err(ParseError::new(ParseErrorType::EBADF, String::new(), 0)); 313 } 314 315 return Ok(FileDescriptor(fd as usize)); 316 } 317 318 /// @brief 解析nice 319 /// 320 /// 将传入的字符串解析为nice 321 /// 322 /// @param s 需解析的字符串 323 /// 324 /// @return 解析成功则返回Ok(解析后的值),否则返回Err 325 pub fn parse_nice(s: &str) -> Result<i8, ParseError> { 326 let s = s.trim(); 327 let nice = match s.parse::<i8>() { 328 Ok(val) => val, 329 Err(_) => { 330 return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0)); 331 } 332 }; 333 334 if nice > PRIO_MAX || nice < PRIO_MIN { 335 return Err(ParseError::new(ParseErrorType::ERANGE, String::new(), 0)); 336 } 337 338 return Ok(nice); 339 } 340 341 /// @brief 解析端口号 342 /// 343 /// 将传入的字符串解析为端口号 344 /// 345 /// @param s 需解析的字符串 346 /// 347 /// @return 解析成功则返回Ok(解析后的值),否则返回Err 348 pub fn parse_ip_port(s: &str) -> Result<u16, ParseError> { 349 let s = s.trim(); 350 let port = match s.parse::<u16>() { 351 Ok(val) => val, 352 Err(_) => { 353 return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0)); 354 } 355 }; 356 357 if port == 0 { 358 return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0)); 359 } 360 361 return Ok(port); 362 } 363 364 /// @brief 解析端口范围 365 /// 366 /// 将传入的字符串解析为端口范围 367 /// 368 /// @param s 需解析的字符串 369 /// 370 /// @return 解析成功则返回Ok((u16,u16)),否则返回Err 371 pub fn parse_ip_port_range(s: &str) -> Result<(u16, u16), ParseError> { 372 let (l, h) = Self::parse_range(s)?; 373 374 let l = l as u16; 375 let h = h as u16; 376 if l <= 0 || l >= 65535 || h <= 0 || h >= 65535 { 377 return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0)); 378 } 379 380 return Ok((l, h)); 381 } 382 383 /// @brief 解析OOM(Out-of-Memory)分数调整值 384 /// 385 /// 将传入的字符串解析为OOM(Out-of-Memory)分数调整值 386 /// 387 /// @param s 需解析的字符串 388 /// 389 /// @return 解析成功则返回Ok(u32),否则返回Err 390 pub fn parse_ip_prefix_length(s: &str) -> Result<u32, ParseError> { 391 let len = match s.parse::<u32>() { 392 Ok(val) => val, 393 Err(_) => { 394 return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0)); 395 } 396 }; 397 398 if len > 128 { 399 return Err(ParseError::new(ParseErrorType::ERANGE, String::new(), 0)); 400 } 401 402 return Ok(len); 403 } 404 405 /// @brief 目前为简单的分割字符串,并未提供严谨的Url解析 406 /// 407 /// 将传入的字符串解析为Url结构体的Vec,若Url非法则返回错误 408 /// 409 /// @param s 需解析的字符串 410 /// 411 /// @return 解析成功则返回Ok(Url),否则返回Err 412 pub fn parse_url(s: &str) -> Result<Vec<Url>, ParseError> { 413 let _url = Url::default(); 414 let url_strs = s.split_whitespace().collect::<Vec<&str>>(); 415 let mut urls = Vec::new(); 416 for s in url_strs { 417 urls.push(Url { 418 url_string: String::from(s), 419 }) 420 } 421 return Ok(urls); 422 } 423 424 /// @brief 将对应的str解析为对应Unit 425 /// 426 /// 将传入的字符串解析为Unit,解析失败返回错误 427 /// 428 /// @param path 需解析的文件 429 /// 430 /// @return 解析成功则返回Ok(Arc<dyn Unit>),否则返回Err 431 pub fn parse_unit<T: Unit>(path: &str) -> Result<usize, ParseError> { 432 return T::from_path(path); 433 } 434 435 /// @brief 将对应的str解析为Arc<dyn Unit> 436 /// 437 /// 将传入的字符串解析为Arc<dyn Unit>,解析失败返回错误 438 /// 439 /// @param path 需解析的文件 440 /// 441 /// @return 解析成功则返回Ok(Arc<dyn Unit>),否则返回Err 442 pub fn parse_unit_no_type(path: &str) -> Result<usize, ParseError> { 443 let idx = match path.rfind('.') { 444 Some(val) => val, 445 None => { 446 return Err(ParseError::new(ParseErrorType::EFILE, path.to_string(), 0)); 447 } 448 }; 449 450 if idx == path.len() - 1 { 451 //处理非法文件xxxx. 类型 452 return Err(ParseError::new(ParseErrorType::EFILE, path.to_string(), 0)); 453 } 454 455 let suffix = &path[idx + 1..]; 456 457 //通过文件后缀分发给不同类型的Unit解析器解析 458 let unit = match suffix { 459 //TODO: 目前为递归,后续应考虑从DragonReach管理的Unit表中寻找是否有该Unit,并且通过记录消除递归 460 "service" => UnitParser::parse::<ServiceUnit>(path, UnitType::Service)?, 461 "target" => UnitParser::parse::<TargetUnit>(path, UnitType::Target)?, 462 _ => { 463 return Err(ParseError::new(ParseErrorType::EFILE, path.to_string(), 0)); 464 } 465 }; 466 467 return Ok(unit); 468 } 469 470 pub fn parse_env(s: &str) -> Result<(String, String), ParseError> { 471 let s = s.trim().split('=').collect::<Vec<&str>>(); 472 if s.len() != 2 { 473 return Err(ParseError::new(ParseErrorType::EINVAL, "".to_string(), 0)); 474 } 475 476 return Ok((s[0].to_string(), s[1].to_string())); 477 } 478 479 /// @brief 将对应的str解析为对应CmdTask 480 /// 481 /// 将传入的字符串解析为CmdTask组,解析失败返回错误 482 /// 483 /// @param path 需解析的文件 484 /// 485 /// @return 解析成功则返回Ok(Vec<CmdTask>>),否则返回Err 486 pub fn parse_cmd_task(s: &str) -> Result<Vec<CmdTask>, ParseError> { 487 //分拆成单词Vec 488 let cmds = s.split_whitespace().collect::<Vec<&str>>(); 489 let mut tasks = Vec::new(); 490 let mut i = 0; 491 while i < cmds.len() { 492 let mut cmd_task = CmdTask::default(); 493 //匹配到这里时,这个单词肯定是路径,若路径以-开头则设置ignore 494 cmd_task.ignore = cmds[i].starts_with('-'); 495 496 //获取到一个CmdTask的路径部分 497 let mut path = String::new(); 498 if cmd_task.ignore { 499 path = String::from(&cmds[i][1..]); 500 } else { 501 path = String::from(cmds[i]); 502 } 503 504 //得到的非绝对路径则不符合语法要求,报错 505 if !UnitParseUtil::is_valid_exec_path(path.as_str()) { 506 return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0)); 507 } 508 509 cmd_task.path = path; 510 511 //i += 1,继续匹配下一个单词 512 i += 1; 513 let mut cmd_vec = Vec::new(); 514 while i < cmds.len() && !UnitParseUtil::is_valid_exec_path(cmds[i]) { 515 //命令可能会有多个单词,将多个命令整理成一个 516 let cmd = cmds[i]; 517 cmd_vec.push(String::from(cmd)); 518 i += 1; 519 } 520 cmd_task.cmd = cmd_vec; 521 tasks.push(cmd_task); 522 //经过while到这里之后,cmds[i]对应的单词一点是路径,i不需要加一 523 } 524 return Ok(tasks); 525 } 526 527 /// @brief 判断是否为绝对路径,以及指向是否为可执行文件或者sh脚本 528 /// 529 /// 目前该方法仅判断是否为绝对路径 530 /// 531 /// @param path 路径 532 /// 533 /// @return 解析成功则返回true,否则返回false 534 pub fn is_valid_exec_path(path: &str) -> bool { 535 let path = Path::new(path); 536 return path.is_absolute(); 537 538 //TODO: 后续应判断该文件是否为合法文件 539 //let path = Path::new(path); 540 //return Self::is_executable_file(path) || Self::is_shell_script(path); 541 } 542 543 pub fn is_valid_file(path: &str) -> bool { 544 if !path.starts_with("/") { 545 return false; 546 } 547 548 let path = Path::new(path); 549 if let Ok(matadata) = fs::metadata(path) { 550 return matadata.is_file(); 551 } 552 553 return false; 554 } 555 556 fn is_executable_file(path: &Path) -> bool { 557 if let Ok(metadata) = fs::metadata(path) { 558 // 检查文件类型是否是普通文件并且具有可执行权限 559 if metadata.is_file() { 560 let permissions = metadata.permissions().mode(); 561 return permissions & 0o111 != 0; 562 } 563 } 564 false 565 } 566 567 fn is_shell_script(path: &Path) -> bool { 568 if let Some(extension) = path.extension() { 569 if extension == "sh" { 570 return true; 571 } 572 } 573 false 574 } 575 576 /// @brief 将对应的str解析为us(微秒) 577 /// 578 /// 将传入的字符串解析为秒数,解析失败返回错误 579 /// 580 /// @param path 需解析的文件 581 /// 582 /// @return 解析成功则返回Ok(u64),否则返回Err 583 pub fn parse_sec(s: &str) -> Result<u64, ParseError> { 584 //下列参数分别记录整数部分,小数部分以及单位 585 let mut integer: u64 = 0; 586 let mut frac: u64 = 0; 587 let mut unit: &str = ""; 588 589 match s.find('.') { 590 Some(idx) => { 591 //解析整数部分 592 integer = match s[..idx].parse::<u64>() { 593 Ok(val) => val, 594 Err(_) => { 595 return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0)) 596 } 597 }; 598 //获得小数+单位的字符串 599 let frac_and_unit = &s[(idx + 1)..]; 600 match frac_and_unit.find(|c: char| !c.is_digit(10)) { 601 Some(val) => { 602 //匹配小数部分 603 frac = match frac_and_unit[..val].parse::<u64>() { 604 Ok(val) => val, 605 Err(_) => { 606 return Err(ParseError::new( 607 ParseErrorType::EINVAL, 608 String::new(), 609 0, 610 )) 611 } 612 }; 613 //单位部分 614 unit = &frac_and_unit[val..]; 615 } 616 None => { 617 //没有单位的情况,直接匹配小数 618 frac = match frac_and_unit.parse::<u64>() { 619 Ok(val) => val, 620 Err(_) => { 621 return Err(ParseError::new( 622 ParseErrorType::EINVAL, 623 String::new(), 624 0, 625 )) 626 } 627 }; 628 unit = ""; 629 } 630 }; 631 } 632 None => { 633 //没有小数点则直接匹配整数部分和单位部分 634 match s.find(|c: char| !c.is_digit(10)) { 635 Some(idx) => { 636 integer = match s[..idx].parse::<u64>() { 637 Ok(val) => val, 638 Err(_) => { 639 return Err(ParseError::new( 640 ParseErrorType::EINVAL, 641 String::new(), 642 0, 643 )) 644 } 645 }; 646 unit = &s[idx..]; 647 } 648 None => { 649 integer = match s.parse::<u64>() { 650 Ok(val) => val, 651 Err(_) => { 652 return Err(ParseError::new( 653 ParseErrorType::EINVAL, 654 String::new(), 655 0, 656 )) 657 } 658 }; 659 unit = ""; 660 } 661 }; 662 } 663 }; 664 665 //从时间单位转换表中获取到单位转换为ns的倍数 666 let factor = match SEC_UNIT_TABLE.get(unit) { 667 Some(val) => val, 668 None => { 669 return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0)); 670 } 671 }; 672 673 //计算ns 674 return Ok(integer * factor + (frac * factor) / (10u64.pow(frac.to_string().len() as u32))); 675 } 676 /// @brief 判断对应路径是否为目录 677 /// 678 /// @param path 路径 679 /// 680 /// @return true/false 681 pub fn is_dir(path: &str) -> bool { 682 if let Ok(metadata) = fs::metadata(path) { 683 if metadata.is_dir() { 684 return true; 685 } 686 return false; 687 } 688 return false; 689 } 690 691 ///// ## 通过文件名解析该Unit的类型 692 pub fn parse_type(path: &str) -> UnitType { 693 if let Some(index) = path.rfind('.') { 694 let result = &path[index + 1..]; 695 match result { 696 "service" => return UnitType::Service, 697 "target" => return UnitType::Target, 698 //TODO: 添加文件类型 699 _ => return UnitType::Unknown, 700 } 701 } 702 UnitType::Unknown 703 } 704 705 /// ## 将读取环境变量文件解析为环境变量集合 706 pub fn parse_environment_file(env_file: &str) -> Result<Vec<(String, String)>, ParseError> { 707 let mut envs = Vec::new(); 708 if env_file.len() > 0 { 709 let env_reader = UnitParser::get_reader(env_file, UnitType::Unknown)?; 710 for line in env_reader.lines() { 711 if let Ok(line) = line { 712 let x = UnitParseUtil::parse_env(line.as_str())?; 713 envs.push(x); 714 } 715 } 716 } 717 return Ok(envs); 718 } 719 } 720