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