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 Passwd {
13 pub name: String,
15
16 pub passwd: String,
18
19 pub uid: nc::uid_t,
21
22 pub gid: nc::gid_t,
24
25 pub gecos: String,
27
28 pub home_dir: String,
30
31 pub shell: String,
33}
34
35impl FromStr for Passwd {
36 type Err = Error;
37
38 fn from_str(s: &str) -> Result<Self, Self::Err> {
39 let parts: Vec<&str> = s.split(':').collect();
40 if parts.len() != 7 {
41 return Err(Error::from_string(
42 ErrorKind::PwdError,
43 format!("Invalid passwd entry: {}", s),
44 ));
45 }
46
47 let uid = parts[2].parse()?;
48 let gid = parts[3].parse()?;
49 Ok(Self {
50 name: parts[0].to_string(),
51 passwd: parts[1].to_string(),
52 uid,
53 gid,
54 gecos: parts[4].to_string(),
55 home_dir: parts[5].to_string(),
56 shell: parts[6].to_string(),
57 })
58 }
59}
60
61#[derive(Debug)]
62pub struct PasswdIter {
63 reader: BufReader<File>,
64}
65
66pub fn getpwent() -> Result<PasswdIter, Error> {
67 let fd = File::open("/etc/passwd")?;
68 let reader = BufReader::new(fd);
69 Ok(PasswdIter { reader })
70}
71
72impl Iterator for PasswdIter {
73 type Item = Passwd;
74
75 fn next(&mut self) -> Option<Self::Item> {
76 let mut line = String::new();
77 let len = self.reader.read_line(&mut line);
78 if len.is_err() {
79 return None;
80 }
81
82 match Passwd::from_str(&line.trim()) {
83 Ok(p) => Some(p),
84 Err(err) => {
85 log::error!("{:?}", err);
86 None
87 }
88 }
89 }
90}
91
92pub fn getpwuid(uid: nc::uid_t) -> Result<Option<Passwd>, Error> {
93 let iter = getpwent()?;
94 for p in iter {
95 if p.uid == uid {
96 return Ok(Some(p));
97 }
98 }
99 Ok(None)
100}
101
102pub fn getpwname(name: &str) -> Result<Option<Passwd>, Error> {
103 let iter = getpwent()?;
104 for p in iter {
105 if p.name == name {
106 return Ok(Some(p));
107 }
108 }
109 Ok(None)
110}
111
112#[cfg(test)]
113mod tests {
114 use super::*;
115
116 #[test]
117 fn test_passwd_iter() {
118 let iter = getpwent();
119 assert!(iter.is_ok());
120 let mut iter = iter.unwrap();
121 let p0 = iter.next();
122 println!("p0: {:#?}", p0);
123 assert!(p0.is_some());
124 }
125
126 #[test]
127 fn test_getpwuid() {
128 let mail_uid = 6;
129 let p = getpwuid(mail_uid);
130 assert!(p.is_ok());
131 let p = p.unwrap();
132 assert!(p.is_some());
133 let p = p.unwrap();
134 assert_eq!(p.uid, mail_uid);
135 }
136
137 #[test]
138 fn test_getpwname() {
139 let mail_name = "mail";
140 let p = getpwname(mail_name);
141 assert!(p.is_ok());
142 let p = p.unwrap();
143 assert!(p.is_some());
144 let p = p.unwrap();
145 assert_eq!(p.name, mail_name);
146 }
147}