pub(crate) use grp::make_module; #[pymodule] mod grp { use crate::vm::{ builtins::{PyIntRef, PyListRef, PyStrRef}, convert::{IntoPyException, ToPyObject}, exceptions, types::PyStructSequence, PyObjectRef, PyResult, VirtualMachine, }; use nix::unistd; use std::ptr::NonNull; #[pyattr] #[pyclass(module = "grp", name = "struct_group", traverse)] #[derive(PyStructSequence)] struct Group { #[pytraverse(skip)] gr_name: String, #[pytraverse(skip)] gr_passwd: String, #[pytraverse(skip)] gr_gid: u32, gr_mem: PyListRef, } #[pyclass(with(PyStructSequence))] impl Group { fn from_unistd_group(group: unistd::Group, vm: &VirtualMachine) -> Self { let cstr_lossy = |s: std::ffi::CString| { s.into_string() .unwrap_or_else(|e| e.into_cstring().to_string_lossy().into_owned()) }; Group { gr_name: group.name, gr_passwd: cstr_lossy(group.passwd), gr_gid: group.gid.as_raw(), gr_mem: vm .ctx .new_list(group.mem.iter().map(|s| s.to_pyobject(vm)).collect()), } } } #[pyfunction] fn getgrgid(gid: PyIntRef, vm: &VirtualMachine) -> PyResult { let gr_gid = gid.as_bigint(); let gid = libc::gid_t::try_from(gr_gid) .map(unistd::Gid::from_raw) .ok(); let group = gid .map(unistd::Group::from_gid) .transpose() .map_err(|err| err.into_pyexception(vm))? .flatten(); let group = group.ok_or_else(|| { vm.new_key_error( vm.ctx .new_str(format!("getgrgid: group id {gr_gid} not found")) .into(), ) })?; Ok(Group::from_unistd_group(group, vm)) } #[pyfunction] fn getgrnam(name: PyStrRef, vm: &VirtualMachine) -> PyResult { let gr_name = name.as_str(); if gr_name.contains('\0') { return Err(exceptions::cstring_error(vm)); } let group = unistd::Group::from_name(gr_name).map_err(|err| err.into_pyexception(vm))?; let group = group.ok_or_else(|| { vm.new_key_error( vm.ctx .new_str(format!("getgrnam: group name {gr_name} not found")) .into(), ) })?; Ok(Group::from_unistd_group(group, vm)) } #[pyfunction] fn getgrall(vm: &VirtualMachine) -> PyResult> { // setgrent, getgrent, etc are not thread safe. Could use fgetgrent_r, but this is easier static GETGRALL: parking_lot::Mutex<()> = parking_lot::const_mutex(()); let _guard = GETGRALL.lock(); let mut list = Vec::new(); unsafe { libc::setgrent() }; while let Some(ptr) = NonNull::new(unsafe { libc::getgrent() }) { let group = unistd::Group::from(unsafe { ptr.as_ref() }); let group = Group::from_unistd_group(group, vm).to_pyobject(vm); list.push(group); } unsafe { libc::endgrent() }; Ok(list) } }