xref: /DragonOS/user/apps/user-manage/src/check/check.rs (revision 38458c72672b8f53ebe43c4300e3bcd504cb5abc)
1 use super::info::{GAddInfo, GDelInfo, GModInfo, PasswdInfo, UAddInfo, UDelInfo, UModInfo};
2 use crate::{
3     error::error::{ErrorHandler, ExitStatus},
4     parser::cmd::{CmdOption, GroupCommand, PasswdCommand, UserCommand},
5 };
6 use std::{
7     collections::{HashMap, HashSet},
8     fs,
9     io::Write,
10 };
11 
12 /// useradd命令检查器
13 #[derive(Debug)]
14 pub struct UAddCheck;
15 
16 impl UAddCheck {
17     /// **校验解析后的useradd命令**
18     ///
19     /// ## 参数
20     /// - `cmd`: 解析后的useradd命令
21     ///
22     /// ## 返回
23     /// - `UAddInfo`: 校验后的信息
24     pub fn check(cmd: UserCommand) -> UAddInfo {
25         let mut info = UAddInfo::default();
26         info.username = cmd.username;
27 
28         // 填充信息
29         for (option, arg) in cmd.options.iter() {
30             match option {
31                 CmdOption::Shell => {
32                     info.shell = arg.clone();
33                 }
34                 CmdOption::Comment => {
35                     info.comment = arg.clone();
36                 }
37                 CmdOption::Uid => {
38                     info.uid = arg.clone();
39                 }
40                 CmdOption::Group => {
41                     info.group = arg.clone();
42                 }
43                 CmdOption::Gid => {
44                     info.gid = arg.clone();
45                 }
46                 CmdOption::Dir => {
47                     info.home_dir = arg.clone();
48                 }
49                 _ => {
50                     let op: &str = option.clone().into();
51                     ErrorHandler::error_handle(
52                         format!("Unimplemented option: {}", op),
53                         ExitStatus::InvalidCmdSyntax,
54                     );
55                 }
56             }
57         }
58 
59         // 完善用户信息
60         if info.username.is_empty() {
61             ErrorHandler::error_handle("Invalid username".to_string(), ExitStatus::InvalidArg);
62         }
63 
64         if info.uid.is_empty() {
65             ErrorHandler::error_handle("Uid is required".to_string(), ExitStatus::InvalidCmdSyntax);
66         }
67 
68         if info.comment.is_empty() {
69             info.comment = info.username.clone() + ",,,";
70         }
71         if info.home_dir.is_empty() {
72             let home_dir = format!("/home/{}", info.username.clone());
73             info.home_dir = home_dir;
74         }
75         if info.shell.is_empty() {
76             info.shell = "/bin/NovaShell".to_string();
77         }
78 
79         // 校验终端是否有效
80         check_shell(&info.shell);
81 
82         // 校验是否有重复用户名和用户id
83         scan_passwd(
84             PasswdField {
85                 username: Some(info.username.clone()),
86                 uid: Some(info.uid.clone()),
87             },
88             false,
89         );
90 
91         // 判断group和gid是否有效
92         Self::check_group_gid(&mut info);
93 
94         info
95     }
96 
97     /// 检查组名、组id是否有效,如果组名不存在,则创建新的用户组
98     fn check_group_gid(info: &mut UAddInfo) {
99         if info.group.is_empty() && info.gid.is_empty() {
100             ErrorHandler::error_handle(
101                 "user must belong to a group".to_string(),
102                 ExitStatus::InvalidCmdSyntax,
103             );
104         }
105 
106         let r = fs::read_to_string("/etc/group");
107         let mut max_gid: u32 = 0;
108         match r {
109             Ok(content) => {
110                 for line in content.lines() {
111                     let data: Vec<&str> = line.split(":").collect();
112                     let (groupname, gid) = (data[0].to_string(), data[2].to_string());
113                     if !info.group.is_empty() && info.group == groupname {
114                         if !info.gid.is_empty() && info.gid != gid {
115                             ErrorHandler::error_handle(
116                                 format!("The gid of the group [{}] isn't {}", info.group, info.gid),
117                                 ExitStatus::InvalidArg,
118                             )
119                         } else if info.gid.is_empty() || info.gid == gid {
120                             info.gid = gid;
121                             return;
122                         }
123                     }
124 
125                     if !info.gid.is_empty() && info.gid == gid {
126                         if !info.group.is_empty() && info.group != groupname {
127                             ErrorHandler::error_handle(
128                                 format!("The gid of the group [{}] isn't {}", info.group, info.gid),
129                                 ExitStatus::InvalidArg,
130                             )
131                         } else if info.group.is_empty() || info.group == groupname {
132                             info.group = groupname;
133                             return;
134                         }
135                     }
136 
137                     max_gid = max_gid.max(u32::from_str_radix(data[2], 10).unwrap());
138                 }
139             }
140             Err(_) => {
141                 ErrorHandler::error_handle(
142                     "Can't read file: /etc/group".to_string(),
143                     ExitStatus::GroupFile,
144                 );
145             }
146         }
147 
148         // 没有对应的用户组,默认创建新的用户组
149         let mut groupname = info.username.clone();
150         let mut gid = (max_gid + 1).to_string();
151         if !info.group.is_empty() {
152             groupname = info.group.clone();
153         } else {
154             info.group = groupname.clone();
155         }
156 
157         if !info.gid.is_empty() {
158             gid = info.gid.clone();
159         } else {
160             info.gid = gid.clone();
161         }
162         let mut success = true;
163         let r = std::process::Command::new("/bin/groupadd")
164             .arg("-g")
165             .arg(gid.clone())
166             .arg(groupname)
167             .status();
168         if let Ok(exit_status) = r {
169             if exit_status.code() != Some(0) {
170                 success = false;
171             }
172         } else {
173             success = false;
174         }
175 
176         if !success {
177             ErrorHandler::error_handle("groupadd failed".to_string(), ExitStatus::GroupaddFail);
178         }
179     }
180 }
181 
182 /// userdel命令检查器
183 #[derive(Debug)]
184 pub struct UDelCheck;
185 
186 impl UDelCheck {
187     /// **校验userdel命令**
188     ///
189     /// ## 参数
190     /// - `cmd`: userdel命令
191     ///
192     /// ## 返回
193     /// - `UDelInfo`: 校验后的用户信息
194     pub fn check(cmd: UserCommand) -> UDelInfo {
195         let mut info = UDelInfo::default();
196         info.username = cmd.username;
197 
198         // 检查用户是否存在
199         scan_passwd(
200             PasswdField {
201                 username: Some(info.username.clone()),
202                 uid: None,
203             },
204             true,
205         );
206 
207         if let Some(_) = cmd.options.get(&CmdOption::Remove) {
208             info.home = Some(Self::home(&info.username));
209         }
210 
211         info
212     }
213 
214     /// 获取用户家目录
215     fn home(username: &String) -> String {
216         let mut home = String::new();
217         match std::fs::read_to_string("/etc/passwd") {
218             Ok(data) => {
219                 for line in data.lines() {
220                     let data = line.split(':').collect::<Vec<&str>>();
221                     if data[0] == username {
222                         home = data[5].to_string();
223                         break;
224                     }
225                 }
226             }
227             Err(_) => {
228                 ErrorHandler::error_handle(
229                     "Can't read file: /etc/passwd".to_string(),
230                     ExitStatus::PasswdFile,
231                 );
232             }
233         }
234         home
235     }
236 }
237 
238 /// usermod命令检查器
239 #[derive(Debug)]
240 pub struct UModCheck;
241 
242 impl UModCheck {
243     /// **校验usermod命令**
244     ///
245     /// ## 参数
246     /// - `cmd`: usermod命令
247     ///
248     /// ## 返回
249     /// - `UModInfo`: 校验后的用户信息
250     pub fn check(cmd: UserCommand) -> UModInfo {
251         let mut info = Self::parse_options(&cmd.options);
252         info.username = cmd.username;
253 
254         // 校验shell是否有效
255         if let Some(shell) = &info.new_shell {
256             check_shell(shell);
257         }
258 
259         // 校验new_home是否有效
260         if let Some(new_home) = &info.new_home {
261             Self::check_home(new_home);
262         }
263 
264         // 校验用户是否存在
265         scan_passwd(
266             PasswdField {
267                 username: Some(info.username.clone()),
268                 uid: None,
269             },
270             true,
271         );
272 
273         // 校验new_name、new_uid是否有效
274         scan_passwd(
275             PasswdField {
276                 username: info.new_name.clone(),
277                 uid: info.new_uid.clone(),
278             },
279             false,
280         );
281 
282         // 校验groups、new_gid是否有效
283         scan_group(
284             GroupField {
285                 groups: info.groups.clone(),
286                 gid: info.new_gid.clone(),
287             },
288             true,
289         );
290 
291         info
292     }
293 
294     /// **校验home目录是否有效**
295     ///
296     /// ## 参数
297     /// - `home`: home目录路径
298     fn check_home(home: &String) {
299         if fs::File::open(home).is_ok() {
300             ErrorHandler::error_handle(format!("{} already exists", home), ExitStatus::InvalidArg);
301         }
302     }
303 
304     /// **解析options**
305     ///
306     /// ## 参数
307     /// - `options`: 命令选项
308     ///
309     /// ## 返回
310     /// - `UModInfo`: 用户信息
311     fn parse_options(options: &HashMap<CmdOption, String>) -> UModInfo {
312         let mut info = UModInfo::default();
313         for (option, arg) in options {
314             match option {
315                 CmdOption::Append => {
316                     info.groups = Some(arg.split(",").map(|s| s.to_string()).collect());
317                 }
318                 CmdOption::Comment => {
319                     info.new_comment = Some(arg.clone());
320                 }
321                 CmdOption::Dir => {
322                     info.new_home = Some(arg.clone());
323                 }
324                 CmdOption::Gid => {
325                     info.new_gid = Some(arg.clone());
326                 }
327                 CmdOption::Login => {
328                     info.new_name = Some(arg.clone());
329                 }
330                 CmdOption::Shell => {
331                     info.new_shell = Some(arg.clone());
332                 }
333                 CmdOption::Uid => {
334                     info.new_uid = Some(arg.clone());
335                 }
336                 _ => ErrorHandler::error_handle(
337                     "Invalid option".to_string(),
338                     ExitStatus::InvalidCmdSyntax,
339                 ),
340             }
341         }
342         info
343     }
344 }
345 
346 /// passwd命令检查器
347 #[derive(Debug)]
348 pub struct PasswdCheck;
349 
350 impl PasswdCheck {
351     /// **校验passwd命令**
352     ///
353     /// ## 参数
354     /// - `cmd`: passwd命令
355     ///
356     /// ## 返回
357     /// - `PasswdInfo`: 校验后的信息
358     pub fn check(cmd: PasswdCommand) -> PasswdInfo {
359         let uid = unsafe { libc::geteuid().to_string() };
360         let cur_username = Self::cur_username(uid.clone());
361         let mut to_change_username = String::new();
362 
363         if let Some(username) = cmd.username {
364             to_change_username = username.clone();
365 
366             // 不是root用户不能修改别人的密码
367             if uid != "0" && cur_username != username {
368                 ErrorHandler::error_handle(
369                     "You can't change password for other users".to_string(),
370                     ExitStatus::PermissionDenied,
371                 );
372             }
373 
374             // 检验待修改用户是否存在
375             scan_passwd(
376                 PasswdField {
377                     username: Some(username.clone()),
378                     uid: None,
379                 },
380                 true,
381             );
382         }
383 
384         let mut new_password = String::new();
385         match uid.as_str() {
386             "0" => {
387                 if to_change_username.is_empty() {
388                     to_change_username = cur_username;
389                 }
390                 print!("New password: ");
391                 std::io::stdout().flush().unwrap();
392                 std::io::stdin().read_line(&mut new_password).unwrap();
393                 new_password = new_password.trim().to_string();
394                 let mut check_password = String::new();
395                 print!("\nRe-enter new password: ");
396                 std::io::stdout().flush().unwrap();
397                 std::io::stdin().read_line(&mut check_password).unwrap();
398                 check_password = check_password.trim().to_string();
399                 if new_password != check_password {
400                     ErrorHandler::error_handle(
401                         "\nThe two passwords that you entered do not match.".to_string(),
402                         ExitStatus::InvalidArg,
403                     )
404                 }
405             }
406             _ => {
407                 to_change_username = cur_username.clone();
408                 print!("Old password: ");
409                 std::io::stdout().flush().unwrap();
410                 let mut old_password = String::new();
411                 std::io::stdin().read_line(&mut old_password).unwrap();
412                 old_password = old_password.trim().to_string();
413                 Self::check_password(cur_username, old_password);
414                 print!("\nNew password: ");
415                 std::io::stdout().flush().unwrap();
416                 std::io::stdin().read_line(&mut new_password).unwrap();
417                 new_password = new_password.trim().to_string();
418                 print!("\nRe-enter new password: ");
419                 std::io::stdout().flush().unwrap();
420                 let mut check_password = String::new();
421                 std::io::stdin().read_line(&mut check_password).unwrap();
422                 check_password = check_password.trim().to_string();
423                 if new_password != check_password {
424                     println!("{}", new_password);
425                     ErrorHandler::error_handle(
426                         "\nThe two passwords that you entered do not match.".to_string(),
427                         ExitStatus::InvalidArg,
428                     )
429                 }
430             }
431         };
432 
433         PasswdInfo {
434             username: to_change_username,
435             new_password,
436         }
437     }
438 
439     /// **获取uid对应的用户名**
440     ///
441     /// ## 参数
442     /// - `uid`: 用户id
443     ///
444     /// ## 返回
445     /// 用户名
446     fn cur_username(uid: String) -> String {
447         let r = fs::read_to_string("/etc/passwd");
448         let mut cur_username = String::new();
449 
450         match r {
451             Ok(content) => {
452                 for line in content.lines() {
453                     let field = line.split(":").collect::<Vec<&str>>();
454                     if uid == field[2] {
455                         cur_username = field[0].to_string();
456                     }
457                 }
458             }
459             Err(_) => {
460                 ErrorHandler::error_handle(
461                     "Can't read /etc/passwd".to_string(),
462                     ExitStatus::PasswdFile,
463                 );
464             }
465         }
466 
467         cur_username
468     }
469 
470     /// **校验密码**
471     ///
472     /// ## 参数
473     /// - `username`: 用户名
474     /// - `password`: 密码
475     fn check_password(username: String, password: String) {
476         let r = fs::read_to_string("/etc/shadow");
477         match r {
478             Ok(content) => {
479                 for line in content.lines() {
480                     let field = line.split(":").collect::<Vec<&str>>();
481                     if username == field[0] {
482                         if password != field[1] {
483                             ErrorHandler::error_handle(
484                                 "Password error".to_string(),
485                                 ExitStatus::InvalidArg,
486                             );
487                         } else {
488                             return;
489                         }
490                     }
491                 }
492             }
493             Err(_) => {
494                 ErrorHandler::error_handle(
495                     "Can't read /etc/shadow".to_string(),
496                     ExitStatus::ShadowFile,
497                 );
498             }
499         }
500     }
501 }
502 
503 /// groupadd命令检查器
504 #[derive(Debug)]
505 pub struct GAddCheck;
506 
507 impl GAddCheck {
508     /// **校验groupadd命令**
509     ///
510     /// ## 参数
511     /// - `cmd`: groupadd命令
512     ///
513     /// ## 返回
514     /// - `GAddInfo`: 校验后的组信息
515     pub fn check(cmd: GroupCommand) -> GAddInfo {
516         let mut info = GAddInfo {
517             groupname: cmd.groupname.clone(),
518             gid: String::new(),
519             passwd: None,
520         };
521 
522         if info.groupname.is_empty() {
523             ErrorHandler::error_handle("groupname is required".to_string(), ExitStatus::InvalidArg);
524         }
525 
526         if let Some(gid) = cmd.options.get(&CmdOption::Gid) {
527             info.gid = gid.clone();
528         } else {
529             ErrorHandler::error_handle("gid is required".to_string(), ExitStatus::InvalidArg);
530         }
531 
532         if let Some(passwd) = cmd.options.get(&CmdOption::Passwd) {
533             info.passwd = Some(passwd.clone());
534         }
535 
536         // 检查组名或组id是否已存在
537         scan_group(
538             GroupField {
539                 groups: Some(vec![info.groupname.clone()]),
540                 gid: Some(info.gid.clone()),
541             },
542             false,
543         );
544 
545         info
546     }
547 }
548 
549 /// groupdel命令检查器
550 #[derive(Debug)]
551 pub struct GDelCheck;
552 
553 impl GDelCheck {
554     /// **校验groupdel命令**
555     ///
556     /// ## 参数
557     /// - `cmd`: groupdel命令
558     ///
559     /// ## 返回
560     /// - `GDelInfo`: 校验后的组信息
561     pub fn check(cmd: GroupCommand) -> GDelInfo {
562         if let Some(gid) = check_groupname(cmd.groupname.clone()) {
563             // 检查group是不是某个用户的主组,如果是的话则不能删除
564             Self::is_main_group(gid);
565         } else {
566             // 用户组不存在
567             ErrorHandler::error_handle(
568                 format!("group:[{}] doesn't exist", cmd.groupname),
569                 ExitStatus::GroupNotExist,
570             );
571         }
572         GDelInfo {
573             groupname: cmd.groupname,
574         }
575     }
576 
577     /// **检查该组是否为某个用户的主用户组**
578     ///
579     /// ## 参数
580     /// - `gid`: 组id
581     ///
582     /// ## 返回
583     /// Some(gid): 组id
584     /// None
585     fn is_main_group(gid: String) {
586         // 读取/etc/passwd文件
587         let r = fs::read_to_string("/etc/passwd");
588         match r {
589             Ok(content) => {
590                 for line in content.lines() {
591                     let field = line.split(":").collect::<Vec<&str>>();
592                     if field[3] == gid {
593                         ErrorHandler::error_handle(
594                             format!(
595                                 "groupdel failed: group is main group of user:[{}]",
596                                 field[0]
597                             ),
598                             ExitStatus::InvalidArg,
599                         )
600                     }
601                 }
602             }
603             Err(_) => {
604                 ErrorHandler::error_handle(
605                     "Can't read file: /etc/passwd".to_string(),
606                     ExitStatus::PasswdFile,
607                 );
608             }
609         }
610     }
611 }
612 
613 /// groupmod命令检查器
614 #[derive(Debug)]
615 pub struct GModCheck;
616 
617 impl GModCheck {
618     /// **校验groupmod命令**
619     ///
620     /// ## 参数
621     /// - `cmd`: groupmod命令
622     ///
623     /// ## 返回
624     /// - `GModInfo`: 校验后的组信息
625     pub fn check(cmd: GroupCommand) -> GModInfo {
626         let mut info = GModInfo::default();
627         info.groupname = cmd.groupname;
628 
629         if let Some(new_groupname) = cmd.options.get(&CmdOption::NewGroupName) {
630             info.new_groupname = Some(new_groupname.clone());
631         }
632 
633         if let Some(new_gid) = cmd.options.get(&CmdOption::Gid) {
634             info.new_gid = Some(new_gid.clone());
635         }
636 
637         Self::check_group_file(&mut info);
638 
639         info
640     }
641 
642     /// 查看groupname是否存在,同时检测new_gid、new_groupname是否重复
643     fn check_group_file(info: &mut GModInfo) {
644         let mut is_group_exist = false;
645         let r = fs::read_to_string("/etc/group");
646         match r {
647             Ok(content) => {
648                 for line in content.lines() {
649                     let field = line.split(':').collect::<Vec<&str>>();
650                     if field[0] == info.groupname {
651                         is_group_exist = true;
652                         info.gid = field[2].to_string();
653                     }
654 
655                     if let Some(new_gid) = &info.new_gid {
656                         if new_gid == field[2] {
657                             ErrorHandler::error_handle(
658                                 format!("gid:[{}] is already used", new_gid),
659                                 ExitStatus::InvalidArg,
660                             );
661                         }
662                     }
663 
664                     if let Some(new_groupname) = &info.new_groupname {
665                         if new_groupname == field[0] {
666                             ErrorHandler::error_handle(
667                                 format!("groupname:[{}] is already used", new_groupname),
668                                 ExitStatus::InvalidArg,
669                             );
670                         }
671                     }
672                 }
673             }
674             Err(_) => ErrorHandler::error_handle(
675                 "Can't read file: /etc/group".to_string(),
676                 ExitStatus::GroupFile,
677             ),
678         }
679 
680         if !is_group_exist {
681             ErrorHandler::error_handle(
682                 format!("groupname:[{}] doesn't exist", info.groupname),
683                 ExitStatus::GroupNotExist,
684             );
685         }
686     }
687 }
688 
689 /// passwd文件待校验字段
690 pub struct PasswdField {
691     username: Option<String>,
692     uid: Option<String>,
693 }
694 
695 /// group文件待校验字段
696 pub struct GroupField {
697     groups: Option<Vec<String>>,
698     gid: Option<String>,
699 }
700 
701 /// **校验uid**
702 ///
703 /// ## 参数
704 /// - `passwd_field`: passwd文件字段
705 /// - `should_exist`: 是否应该存在
706 fn scan_passwd(passwd_field: PasswdField, should_exist: bool) {
707     let mut username_check = false;
708     let mut uid_check = false;
709     match fs::read_to_string("/etc/passwd") {
710         Ok(content) => {
711             for line in content.lines() {
712                 let field = line.split(':').collect::<Vec<&str>>();
713                 if let Some(uid) = &passwd_field.uid {
714                     // uid必须是有效的数字
715                     let r = uid.parse::<u32>();
716                     if r.is_err() {
717                         ErrorHandler::error_handle(
718                             format!("Uid {} is invalid", uid),
719                             ExitStatus::InvalidArg,
720                         );
721                     }
722                     if field[2] == uid {
723                         uid_check = true;
724                         // username如果不用校验或者被校验过了,才可以return
725                         if should_exist && (passwd_field.username.is_none() || username_check) {
726                             return;
727                         } else {
728                             ErrorHandler::error_handle(
729                                 format!("UID {} already exists", uid),
730                                 ExitStatus::UidInUse,
731                             );
732                         }
733                     }
734                 }
735 
736                 if let Some(username) = &passwd_field.username {
737                     if field[0] == username {
738                         username_check = true;
739                         // uid如果不用校验或者被校验过了,才可以return
740                         if should_exist && (passwd_field.uid.is_none() || uid_check) {
741                             return;
742                         } else {
743                             ErrorHandler::error_handle(
744                                 format!("Username {} already exists", username),
745                                 ExitStatus::UsernameInUse,
746                             );
747                         }
748                     }
749                 }
750             }
751 
752             if should_exist {
753                 if let Some(uid) = &passwd_field.uid {
754                     if !uid_check {
755                         ErrorHandler::error_handle(
756                             format!("UID {} doesn't exist", uid),
757                             ExitStatus::InvalidArg,
758                         );
759                     }
760                 }
761                 if let Some(username) = &passwd_field.username {
762                     if !username_check {
763                         ErrorHandler::error_handle(
764                             format!("User {} doesn't exist", username),
765                             ExitStatus::InvalidArg,
766                         );
767                     }
768                 }
769             }
770         }
771         Err(_) => ErrorHandler::error_handle(
772             "Can't read file: /etc/passwd".to_string(),
773             ExitStatus::PasswdFile,
774         ),
775     }
776 }
777 
778 /// **校验gid**
779 ///
780 /// ## 参数
781 /// - `group_field`: group文件字段
782 /// - `should_exist`: 是否应该存在
783 fn scan_group(group_field: GroupField, should_exist: bool) {
784     let mut gid_check = false;
785     let mut set1 = HashSet::new();
786     let mut set2 = HashSet::new();
787     if let Some(groups) = group_field.groups.clone() {
788         set2.extend(groups.into_iter());
789     }
790     match fs::read_to_string("/etc/group") {
791         Ok(content) => {
792             for line in content.lines() {
793                 let field = line.split(':').collect::<Vec<&str>>();
794                 if let Some(gid) = &group_field.gid {
795                     // gid必须是有效的数字
796                     let r = gid.parse::<u32>();
797                     if r.is_err() {
798                         ErrorHandler::error_handle(
799                             format!("Gid {} is invalid", gid),
800                             ExitStatus::InvalidArg,
801                         );
802                     }
803                     if field[2] == gid {
804                         gid_check = true;
805                         if should_exist && group_field.groups.is_none() {
806                             return;
807                         } else {
808                             ErrorHandler::error_handle(
809                                 format!("GID {} already exists", gid),
810                                 ExitStatus::InvalidArg,
811                             );
812                         }
813                     }
814                 }
815 
816                 // 统计所有组
817                 set1.insert(field[0].to_string());
818             }
819 
820             if should_exist {
821                 if let Some(gid) = &group_field.gid {
822                     if !gid_check {
823                         ErrorHandler::error_handle(
824                             format!("GID {} doesn't exist", gid),
825                             ExitStatus::InvalidArg,
826                         );
827                     }
828                 }
829                 if group_field.groups.is_some() {
830                     let mut non_exist_group = Vec::new();
831                     for group in set2.iter() {
832                         if !set1.contains(group) {
833                             non_exist_group.push(group.clone());
834                         }
835                     }
836 
837                     if non_exist_group.len() > 0 {
838                         ErrorHandler::error_handle(
839                             format!("group: {} doesn't exist", non_exist_group.join(",")),
840                             ExitStatus::GroupNotExist,
841                         );
842                     }
843                 }
844             }
845         }
846 
847         Err(_) => ErrorHandler::error_handle(
848             "Can't read file: /etc/group".to_string(),
849             ExitStatus::GroupFile,
850         ),
851     }
852 }
853 
854 /// **校验shell是否有效**
855 ///
856 /// ## 参数
857 /// - `shell`: shell路径
858 fn check_shell(shell: &String) {
859     if let Ok(file) = fs::File::open(shell.clone()) {
860         if !file.metadata().unwrap().is_file() {
861             ErrorHandler::error_handle(format!("{} is not a file", shell), ExitStatus::InvalidArg);
862         }
863     } else {
864         ErrorHandler::error_handle(format!("{} doesn't exist", shell), ExitStatus::InvalidArg);
865     }
866 }
867 
868 /// **校验组名,判断该用户组是否存在,以及成员是否为空**
869 ///
870 /// ## 参数
871 /// - `groupname`: 组名
872 ///
873 /// ## 返回
874 /// Some(gid): 组id
875 /// None
876 fn check_groupname(groupname: String) -> Option<String> {
877     let r = fs::read_to_string("/etc/group");
878     match r {
879         Ok(content) => {
880             for line in content.lines() {
881                 let field = line.split(":").collect::<Vec<&str>>();
882                 let users = field[3].split(",").collect::<Vec<&str>>();
883                 let filter_users = users
884                     .iter()
885                     .filter(|&x| !x.is_empty())
886                     .collect::<Vec<&&str>>();
887                 if field[0] == groupname {
888                     if filter_users.is_empty() {
889                         return Some(field[2].to_string());
890                     } else {
891                         ErrorHandler::error_handle(
892                             format!("group:[{}] is not empty, unable to delete", groupname),
893                             ExitStatus::InvalidArg,
894                         )
895                     }
896                 }
897             }
898         }
899         Err(_) => {
900             ErrorHandler::error_handle(
901                 "Can't read file: /etc/group".to_string(),
902                 ExitStatus::GroupFile,
903             );
904         }
905     }
906 
907     None
908 }
909