|
1 |
| -use pwd::Passwd; |
2 |
| - |
| 1 | +use super::os::convert_nix_error; |
| 2 | +use crate::obj::objint::PyIntRef; |
3 | 3 | use crate::obj::objstr::PyStringRef;
|
4 |
| -use crate::obj::objtype::PyClassRef; |
5 |
| -use crate::pyobject::{PyObjectRef, PyRef, PyResult, PyValue}; |
| 4 | +use crate::pyobject::{PyClassImpl, PyObjectRef, PyResult}; |
6 | 5 | use crate::vm::VirtualMachine;
|
| 6 | +use std::convert::TryFrom; |
| 7 | +use std::ptr::NonNull; |
7 | 8 |
|
8 |
| -impl PyValue for Passwd { |
9 |
| - fn class(vm: &VirtualMachine) -> PyClassRef { |
10 |
| - vm.class("pwd", "struct_passwd") |
11 |
| - } |
12 |
| -} |
13 |
| - |
14 |
| -type PasswdRef = PyRef<Passwd>; |
15 |
| - |
16 |
| -impl PasswdRef { |
17 |
| - fn pw_name(self) -> String { |
18 |
| - self.name.clone() |
19 |
| - } |
20 |
| - |
21 |
| - fn pw_passwd(self) -> Option<String> { |
22 |
| - self.passwd.clone() |
23 |
| - } |
24 |
| - |
25 |
| - fn pw_uid(self) -> u32 { |
26 |
| - self.uid |
27 |
| - } |
28 |
| - |
29 |
| - fn pw_gid(self) -> u32 { |
30 |
| - self.gid |
31 |
| - } |
| 9 | +use nix::unistd::{self, User}; |
32 | 10 |
|
33 |
| - fn pw_gecos(self) -> Option<String> { |
34 |
| - self.gecos.clone() |
35 |
| - } |
36 |
| - |
37 |
| - fn pw_dir(self) -> String { |
38 |
| - self.dir.clone() |
39 |
| - } |
| 11 | +#[pystruct_sequence(name = "pwd.struct_passwd")] |
| 12 | +struct Passwd { |
| 13 | + pw_name: String, |
| 14 | + pw_passwd: String, |
| 15 | + pw_uid: u32, |
| 16 | + pw_gid: u32, |
| 17 | + pw_gecos: String, |
| 18 | + pw_dir: String, |
| 19 | + pw_shell: String, |
| 20 | +} |
40 | 21 |
|
41 |
| - fn pw_shell(self) -> String { |
42 |
| - self.shell.clone() |
| 22 | +impl From<User> for Passwd { |
| 23 | + fn from(user: User) -> Self { |
| 24 | + // this is just a pain... |
| 25 | + let cstr_lossy = |s: std::ffi::CString| { |
| 26 | + s.into_string() |
| 27 | + .unwrap_or_else(|e| e.into_cstring().to_string_lossy().into_owned()) |
| 28 | + }; |
| 29 | + let pathbuf_lossy = |p: std::path::PathBuf| { |
| 30 | + p.into_os_string() |
| 31 | + .into_string() |
| 32 | + .unwrap_or_else(|s| s.to_string_lossy().into_owned()) |
| 33 | + }; |
| 34 | + Passwd { |
| 35 | + pw_name: user.name, |
| 36 | + pw_passwd: cstr_lossy(user.passwd), |
| 37 | + pw_uid: user.uid.as_raw(), |
| 38 | + pw_gid: user.gid.as_raw(), |
| 39 | + pw_gecos: cstr_lossy(user.gecos), |
| 40 | + pw_dir: pathbuf_lossy(user.dir), |
| 41 | + pw_shell: pathbuf_lossy(user.shell), |
| 42 | + } |
43 | 43 | }
|
44 | 44 | }
|
45 | 45 |
|
46 |
| -fn pwd_getpwnam(name: PyStringRef, vm: &VirtualMachine) -> PyResult<Passwd> { |
47 |
| - match Passwd::from_name(name.as_str()) { |
48 |
| - Ok(Some(passwd)) => Ok(passwd), |
49 |
| - _ => { |
| 46 | +fn pwd_getpwnam(name: PyStringRef, vm: &VirtualMachine) -> PyResult { |
| 47 | + match User::from_name(name.as_str()).map_err(|e| convert_nix_error(vm, e))? { |
| 48 | + Some(user) => Ok(Passwd::from(user) |
| 49 | + .into_struct_sequence(vm, vm.try_class("pwd", "struct_passwd")?)? |
| 50 | + .into_object()), |
| 51 | + None => { |
50 | 52 | let name_repr = vm.to_repr(name.as_object())?;
|
51 | 53 | let message = vm.new_str(format!("getpwnam(): name not found: {}", name_repr));
|
52 | 54 | Err(vm.new_key_error(message))
|
53 | 55 | }
|
54 | 56 | }
|
55 | 57 | }
|
56 | 58 |
|
57 |
| -fn pwd_getpwuid(uid: u32, vm: &VirtualMachine) -> PyResult<Passwd> { |
58 |
| - match Passwd::from_uid(uid) { |
59 |
| - Some(passwd) => Ok(passwd), |
60 |
| - _ => { |
61 |
| - let message = vm.new_str(format!("getpwuid(): uid not found: {}", uid)); |
| 59 | +fn pwd_getpwuid(uid: PyIntRef, vm: &VirtualMachine) -> PyResult { |
| 60 | + let uid_t = libc::uid_t::try_from(uid.as_bigint()).map(unistd::Uid::from_raw); |
| 61 | + let user = match uid_t { |
| 62 | + Ok(uid) => User::from_uid(uid).map_err(|e| convert_nix_error(vm, e))?, |
| 63 | + Err(_) => None, |
| 64 | + }; |
| 65 | + match user { |
| 66 | + Some(user) => Ok(Passwd::from(user) |
| 67 | + .into_struct_sequence(vm, vm.try_class("pwd", "struct_passwd")?)? |
| 68 | + .into_object()), |
| 69 | + None => { |
| 70 | + let message = vm.new_str(format!("getpwuid(): uid not found: {}", uid.as_bigint())); |
62 | 71 | Err(vm.new_key_error(message))
|
63 | 72 | }
|
64 | 73 | }
|
65 | 74 | }
|
66 | 75 |
|
| 76 | +// TODO: maybe merge this functionality into nix? |
| 77 | +fn pwd_getpwall(vm: &VirtualMachine) -> PyResult { |
| 78 | + // setpwent, getpwent, etc are not thread safe. Could use fgetpwent_r, but this is easier |
| 79 | + static GETPWALL: parking_lot::Mutex<()> = parking_lot::const_mutex(()); |
| 80 | + let _guard = GETPWALL.lock(); |
| 81 | + let mut list = Vec::new(); |
| 82 | + let cls = vm.try_class("pwd", "struct_passwd")?; |
| 83 | + |
| 84 | + unsafe { libc::setpwent() }; |
| 85 | + while let Some(ptr) = NonNull::new(unsafe { libc::getpwent() }) { |
| 86 | + let user = User::from(unsafe { ptr.as_ref() }); |
| 87 | + let passwd = Passwd::from(user) |
| 88 | + .into_struct_sequence(vm, cls.clone())? |
| 89 | + .into_object(); |
| 90 | + list.push(passwd); |
| 91 | + } |
| 92 | + unsafe { libc::endpwent() }; |
| 93 | + |
| 94 | + Ok(vm.ctx.new_list(list)) |
| 95 | +} |
| 96 | + |
67 | 97 | pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
|
68 | 98 | let ctx = &vm.ctx;
|
69 | 99 |
|
70 |
| - let passwd_type = py_class!(ctx, "struct_passwd", ctx.object(), { |
71 |
| - "pw_name" => ctx.new_readonly_getset("pw_name", PasswdRef::pw_name), |
72 |
| - "pw_passwd" => ctx.new_readonly_getset("pw_passwd", PasswdRef::pw_passwd), |
73 |
| - "pw_uid" => ctx.new_readonly_getset("pw_uid", PasswdRef::pw_uid), |
74 |
| - "pw_gid" => ctx.new_readonly_getset("pw_gid", PasswdRef::pw_gid), |
75 |
| - "pw_gecos" => ctx.new_readonly_getset("pw_gecos", PasswdRef::pw_gecos), |
76 |
| - "pw_dir" => ctx.new_readonly_getset("pw_dir", PasswdRef::pw_dir), |
77 |
| - "pw_shell" => ctx.new_readonly_getset("pw_shell", PasswdRef::pw_shell), |
78 |
| - }); |
79 |
| - |
80 | 100 | py_module!(vm, "pwd", {
|
81 |
| - "struct_passwd" => passwd_type, |
82 |
| - "getpwnam" => ctx.new_function(pwd_getpwnam), |
83 |
| - "getpwuid" => ctx.new_function(pwd_getpwuid), |
| 101 | + "struct_passwd" => Passwd::make_class(ctx), |
| 102 | + "getpwnam" => named_function!(ctx, pwd, getpwnam), |
| 103 | + "getpwuid" => named_function!(ctx, pwd, getpwuid), |
| 104 | + "getpwall" => named_function!(ctx, pwd, getpwall), |
84 | 105 | })
|
85 | 106 | }
|
0 commit comments