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