xref: /DragonReach/src/parse/parse_util/mod.rs (revision b40b6b4d2f72c30a382f9f18740fa73d7fc90721)
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