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