1use std::fs::File;
6use std::io::{BufRead, BufReader};
7use std::str::FromStr;
8
9use crate::error::{Error, ErrorKind};
10
11#[derive(Debug, Default, Clone)]
12pub struct Group {
13 pub name: String,
15
16 pub passwd: String,
18
19 pub gid: nc::gid_t,
21
22 pub mem: Vec<String>,
24}
25
26impl FromStr for Group {
27 type Err = Error;
28
29 fn from_str(s: &str) -> Result<Self, Self::Err> {
30 let parts: Vec<&str> = s.split(':').collect();
31 if parts.len() != 4 {
32 return Err(Error::from_string(
33 ErrorKind::PwdGroupError,
34 format!("Invalid group entry: {}", s),
35 ));
36 }
37
38 let gid = parts[2].parse()?;
39 let mem = parts[3]
40 .split(",")
41 .map(|name| name.trim().to_string())
42 .collect();
43 Ok(Self {
44 name: parts[0].to_string(),
45 passwd: parts[1].to_string(),
46 gid,
47 mem,
48 })
49 }
50}
51
52#[derive(Debug)]
53pub struct GroupIter {
54 reader: BufReader<File>,
55}
56
57pub fn getgrent() -> Result<GroupIter, Error> {
58 let fd = File::open("/etc/group")?;
59 let reader = BufReader::new(fd);
60 Ok(GroupIter { reader })
61}
62
63impl Iterator for GroupIter {
64 type Item = Group;
65
66 fn next(&mut self) -> Option<Self::Item> {
67 let mut line = String::new();
68 let len = self.reader.read_line(&mut line);
69 if len.is_err() {
70 return None;
71 }
72
73 match Group::from_str(&line.trim()) {
74 Ok(p) => Some(p),
75 Err(err) => {
76 log::error!("{:?}", err);
77 None
78 }
79 }
80 }
81}
82
83pub fn getgrgid(gid: nc::gid_t) -> Result<Option<Group>, Error> {
84 let iter = getgrent()?;
85 for g in iter {
86 if g.gid == gid {
87 return Ok(Some(g));
88 }
89 }
90 Ok(None)
91}
92
93pub fn getgrname(name: &str) -> Result<Option<Group>, Error> {
94 let iter = getgrent()?;
95 for g in iter {
96 if g.name == name {
97 return Ok(Some(g));
98 }
99 }
100 Ok(None)
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106
107 #[test]
108 fn test_group_iter() {
109 let iter = getgrent();
110 assert!(iter.is_ok());
111 let mut iter = iter.unwrap();
112 let g0 = iter.next();
113 println!("g0: {:#?}", g0);
114 assert!(g0.is_some());
115 }
116
117 #[test]
118 fn test_getgrgid() {
119 let mail_gid = 8;
120 let g = getgrgid(mail_gid);
121 assert!(g.is_ok());
122 let g = g.unwrap();
123 assert!(g.is_some());
124 let g = g.unwrap();
125 assert_eq!(g.gid, mail_gid);
126 }
127
128 #[test]
129 fn test_getgrname() {
130 let mail_name = "mail";
131 let g = getgrname(mail_name);
132 assert!(g.is_ok());
133 let g = g.unwrap();
134 assert!(g.is_some());
135 let g = g.unwrap();
136 assert_eq!(g.name, mail_name);
137 }
138}