1use std::ffi::{CStr, CString};
2use std::io;
3use std::os::raw::*;
4use std::ptr;
5
6pub struct Group {
8 pub name: String,
10 pub password: Option<String>,
12 pub gid: c_uint,
14
15 pub members: Vec<String>,
17}
18
19#[repr(C)]
21struct Raw {
22 gr_name: *const c_char,
23 gr_passwd: *const c_char,
24 gr_gid: c_uint,
25
26 gr_mem: *const *const c_char,
27}
28extern "C" {
29 fn getgrnam(name: *const c_char) -> *const Raw;
30 fn getgrgid(gid: c_uint) -> *const Raw;
31}
32
33impl Group {
34 unsafe fn convert(s: *const Raw) -> io::Result<Self> {
35 if s == ptr::null() {
36 return Err(io::Error::last_os_error());
37 }
38
39 let name = match CStr::from_ptr((*s).gr_name).to_str() {
40 Err(_) => return Err(io::Error::from(io::ErrorKind::InvalidData)),
41 Ok(o) => o.to_string(),
42 };
43 let passwd = match CStr::from_ptr((*s).gr_passwd).to_str() {
44 Err(_) => None,
45 Ok(o) => Some(o.to_string()),
46 };
47 let gid = (*s).gr_gid;
48
49 let mut members = Vec::new();
50 if (*s).gr_mem != ptr::null() {
51 for i in 0.. {
52 let memeber_ptr = *(*s).gr_mem.offset(i);
53 if memeber_ptr != ptr::null() {
54 match CStr::from_ptr(memeber_ptr).to_str() {
55 Ok(o) => members.push(o.to_string()),
56 Err(_) => continue,
57 }
58 } else {
59 break;
60 }
61 }
62 }
63
64 Ok(Self {
65 name,
66 password: passwd,
67 gid,
68 members,
69 })
70 }
71
72 pub fn new_from_groupname(username: &str) -> io::Result<Self> {
74 unsafe {
75 let raw = match CString::new(username) {
76 Err(_) => return Err(io::Error::from(io::ErrorKind::InvalidData)),
77 Ok(o) => o,
78 };
79
80 Self::convert(getgrnam(raw.as_ptr()))
81 }
82 }
83
84 pub fn new_from_gid(gid: c_uint) -> io::Result<Self> {
86 unsafe { Self::convert(getgrgid(gid)) }
87 }
88
89 pub fn display_members(&self) -> String {
91 let mut m = String::new();
92 for member in &self.members {
93 m.push_str(format!("{} ", member).as_str());
94 }
95
96 m
97 }
98}