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`: 校验后的信息
check(cmd: UserCommand) -> UAddInfo24 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是否有效,如果组名不存在,则创建新的用户组
check_group_gid(info: &mut UAddInfo)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`: 校验后的用户信息
check(cmd: UserCommand) -> UDelInfo194 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 /// 获取用户家目录
home(username: &String) -> String215 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`: 校验后的用户信息
check(cmd: UserCommand) -> UModInfo250 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目录路径
check_home(home: &String)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`: 用户信息
parse_options(options: &HashMap<CmdOption, String>) -> UModInfo311 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`: 校验后的信息
check(cmd: PasswdCommand) -> PasswdInfo358 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 /// 用户名
cur_username(uid: String) -> String446 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`: 密码
check_password(username: String, password: String)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`: 校验后的组信息
check(cmd: GroupCommand) -> GAddInfo515 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`: 校验后的组信息
check(cmd: GroupCommand) -> GDelInfo561 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
is_main_group(gid: String)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`: 校验后的组信息
check(cmd: GroupCommand) -> GModInfo625 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是否重复
check_group_file(info: &mut GModInfo)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`: 是否应该存在
scan_passwd(passwd_field: PasswdField, should_exist: bool)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`: 是否应该存在
scan_group(group_field: GroupField, should_exist: bool)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路径
check_shell(shell: &String)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
check_groupname(groupname: String) -> Option<String>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