use std::fs::File;
use std::io::{BufRead, BufReader};
use std::str::FromStr;
use crate::error::{Error, ErrorKind};
#[derive(Debug, Default, Clone)]
pub struct Passwd {
pub name: String,
pub passwd: String,
pub uid: nc::uid_t,
pub gid: nc::gid_t,
pub gecos: String,
pub home_dir: String,
pub shell: String,
}
impl FromStr for Passwd {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let parts: Vec<&str> = s.split(':').collect();
if parts.len() != 7 {
return Err(Error::from_string(
ErrorKind::PwdError,
format!("Invalid passwd entry: {}", s),
));
}
let uid = parts[2].parse()?;
let gid = parts[3].parse()?;
Ok(Self {
name: parts[0].to_string(),
passwd: parts[1].to_string(),
uid,
gid,
gecos: parts[4].to_string(),
home_dir: parts[5].to_string(),
shell: parts[6].to_string(),
})
}
}
#[derive(Debug)]
pub struct PasswdIter {
reader: BufReader<File>,
}
pub fn getpwent() -> Result<PasswdIter, Error> {
let fd = File::open("/etc/passwd")?;
let reader = BufReader::new(fd);
Ok(PasswdIter { reader })
}
impl Iterator for PasswdIter {
type Item = Passwd;
fn next(&mut self) -> Option<Self::Item> {
let mut line = String::new();
let len = self.reader.read_line(&mut line);
if len.is_err() {
return None;
}
match Passwd::from_str(&line.trim()) {
Ok(p) => Some(p),
Err(err) => {
log::error!("{:?}", err);
None
}
}
}
}
pub fn getpwuid(uid: nc::uid_t) -> Result<Option<Passwd>, Error> {
let iter = getpwent()?;
for p in iter {
if p.uid == uid {
return Ok(Some(p));
}
}
Ok(None)
}
pub fn getpwname(name: &str) -> Result<Option<Passwd>, Error> {
let iter = getpwent()?;
for p in iter {
if p.name == name {
return Ok(Some(p));
}
}
Ok(None)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_passwd_iter() {
let iter = getpwent();
assert!(iter.is_ok());
let mut iter = iter.unwrap();
let p0 = iter.next();
println!("p0: {:#?}", p0);
assert!(p0.is_some());
}
#[test]
fn test_getpwuid() {
let mail_uid = 6;
let p = getpwuid(mail_uid);
assert!(p.is_ok());
let p = p.unwrap();
assert!(p.is_some());
let p = p.unwrap();
assert_eq!(p.uid, mail_uid);
}
#[test]
fn test_getpwname() {
let mail_name = "mail";
let p = getpwname(mail_name);
assert!(p.is_ok());
let p = p.unwrap();
assert!(p.is_some());
let p = p.unwrap();
assert_eq!(p.name, mail_name);
}
}