rustpython_vm/stdlib/
pwd.rs1pub(crate) use pwd::make_module;
2
3#[pymodule]
4mod pwd {
5 use crate::{
6 builtins::{PyIntRef, PyStrRef},
7 convert::{IntoPyException, ToPyObject},
8 exceptions,
9 types::PyStructSequence,
10 PyObjectRef, PyResult, VirtualMachine,
11 };
12 use nix::unistd::{self, User};
13 use std::ptr::NonNull;
14
15 #[pyattr]
16 #[pyclass(module = "pwd", name = "struct_passwd")]
17 #[derive(PyStructSequence)]
18 struct Passwd {
19 pw_name: String,
20 pw_passwd: String,
21 pw_uid: u32,
22 pw_gid: u32,
23 pw_gecos: String,
24 pw_dir: String,
25 pw_shell: String,
26 }
27 #[pyclass(with(PyStructSequence))]
28 impl Passwd {}
29
30 impl From<User> for Passwd {
31 fn from(user: User) -> Self {
32 let cstr_lossy = |s: std::ffi::CString| {
34 s.into_string()
35 .unwrap_or_else(|e| e.into_cstring().to_string_lossy().into_owned())
36 };
37 let pathbuf_lossy = |p: std::path::PathBuf| {
38 p.into_os_string()
39 .into_string()
40 .unwrap_or_else(|s| s.to_string_lossy().into_owned())
41 };
42 Passwd {
43 pw_name: user.name,
44 pw_passwd: cstr_lossy(user.passwd),
45 pw_uid: user.uid.as_raw(),
46 pw_gid: user.gid.as_raw(),
47 pw_gecos: cstr_lossy(user.gecos),
48 pw_dir: pathbuf_lossy(user.dir),
49 pw_shell: pathbuf_lossy(user.shell),
50 }
51 }
52 }
53
54 #[pyfunction]
55 fn getpwnam(name: PyStrRef, vm: &VirtualMachine) -> PyResult<Passwd> {
56 let pw_name = name.as_str();
57 if pw_name.contains('\0') {
58 return Err(exceptions::cstring_error(vm));
59 }
60 let user = User::from_name(name.as_str()).map_err(|err| err.into_pyexception(vm))?;
61 let user = user.ok_or_else(|| {
62 vm.new_key_error(
63 vm.ctx
64 .new_str(format!("getpwnam(): name not found: {pw_name}"))
65 .into(),
66 )
67 })?;
68 Ok(Passwd::from(user))
69 }
70
71 #[pyfunction]
72 fn getpwuid(uid: PyIntRef, vm: &VirtualMachine) -> PyResult<Passwd> {
73 let uid_t = libc::uid_t::try_from(uid.as_bigint())
74 .map(unistd::Uid::from_raw)
75 .ok();
76 let user = uid_t
77 .map(User::from_uid)
78 .transpose()
79 .map_err(|err| err.into_pyexception(vm))?
80 .flatten();
81 let user = user.ok_or_else(|| {
82 vm.new_key_error(
83 vm.ctx
84 .new_str(format!("getpwuid(): uid not found: {}", uid.as_bigint()))
85 .into(),
86 )
87 })?;
88 Ok(Passwd::from(user))
89 }
90
91 #[pyfunction]
93 fn getpwall(vm: &VirtualMachine) -> PyResult<Vec<PyObjectRef>> {
94 static GETPWALL: parking_lot::Mutex<()> = parking_lot::const_mutex(());
96 let _guard = GETPWALL.lock();
97 let mut list = Vec::new();
98
99 unsafe { libc::setpwent() };
100 while let Some(ptr) = NonNull::new(unsafe { libc::getpwent() }) {
101 let user = User::from(unsafe { ptr.as_ref() });
102 let passwd = Passwd::from(user).to_pyobject(vm);
103 list.push(passwd);
104 }
105 unsafe { libc::endpwent() };
106
107 Ok(list)
108 }
109}