1use std::ffi::{CStr, CString};
2use std::io;
3use std::os::raw::*;
4
5pub struct User {
7 pub name: String,
9 pub fullname: String,
11 pub homedir: String,
13 pub shell: String,
15 pub passwd: Option<String>,
17
18 pub uid: c_uint,
20 pub gid: c_uint,
22}
23
24#[repr(C)]
26struct Raw {
27 pw_name: *const c_char,
28 pw_passwd: *const c_char,
29 pw_uid: c_uint,
30 pw_gid: c_uint,
31 pw_gecos: *const c_char,
32 pw_dir: *const c_char,
33 pw_shell: *const c_char,
34}
35extern "C" {
36 fn getpwnam(name: *const c_char) -> *const Raw;
37 fn getpwuid(uid: c_uint) -> *const Raw;
38}
39unsafe fn unref(ptr: *const c_char) -> String {
40 CStr::from_ptr(ptr).to_str().unwrap_or("").to_string()
41}
42
43impl User {
44 unsafe fn convert(raw: *const Raw) -> io::Result<Self> {
45 if raw == std::ptr::null() {
46 return Err(io::Error::last_os_error());
47 }
48
49 let name = unref((*raw).pw_name);
50 let passwd = {
51 let p = unref((*raw).pw_passwd);
52 let ret;
53 if p.eq("") {
54 ret = None
55 } else {
56 ret = Some(p);
57 }
58 ret
59 };
60 let uid = (*raw).pw_uid;
61 let gid = (*raw).pw_gid;
62 let fullname = unref((*raw).pw_gecos);
63 let homedir = unref((*raw).pw_dir);
64 let shell = unref((*raw).pw_shell);
65
66 Ok(Self {
67 name,
68 fullname,
69 homedir,
70 shell,
71 passwd,
72 uid,
73 gid,
74 })
75 }
76
77 pub fn new_from_uid(uid: c_uint) -> io::Result<Self> {
79 unsafe { Self::convert(getpwuid(uid)) }
80 }
81
82 pub fn new_from_name(name: &str) -> io::Result<Self> {
84 unsafe {
85 let cstr = match CString::new(name) {
86 Ok(o) => o,
87 Err(_) => return Err(io::Error::from(io::ErrorKind::InvalidData)),
88 };
89
90 Self::convert(getpwnam(cstr.as_ptr()))
91 }
92 }
93
94 pub fn current_user() -> io::Result<Self> {
96 unsafe {
97 let uid = crate::getuid();
98
99 Self::convert(getpwuid(uid))
100 }
101 }
102}