src/world/bin/su/src/lib.rs

101 lines
2.5 KiB
Rust

use std::{error, ffi::{self, CStr}, fmt, io, num::TryFromIntError, str};
#[derive(Debug)]
pub enum Error {
Io(io::Error),
IncorrectPassword,
InvalidPassword,
IntCast,
PermissionDenied,
Nul(ffi::NulError),
Utf8(str::Utf8Error),
Other(String),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Io(e) => write!(f, "{e}"),
Self::IncorrectPassword => write!(f, "incorrect password"),
Self::InvalidPassword => write!(f, "invalid password"),
Self::IntCast => write!(f, "integer cast error"),
Self::PermissionDenied => write!(f, "permission denied"),
Self::Nul(e) => write!(f, "{e}"),
Self::Utf8(e) => write!(f, "{e}"),
Self::Other(e) => write!(f, "{e}"),
}
}
}
impl error::Error for Error {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match self {
Self::Io(e) => Some(e),
Self::Nul(e) => Some(e),
Self::Utf8(e) => Some(e),
_ => None,
}
}
}
impl From<TryFromIntError> for Error {
fn from(_value: TryFromIntError) -> Self {
Self::IntCast
}
}
impl From<io::Error> for Error {
fn from(value: io::Error) -> Self {
Self::Io(value)
}
}
impl From<ffi::NulError> for Error {
fn from(value: ffi::NulError) -> Self {
Self::Nul(value)
}
}
impl From<str::Utf8Error> for Error {
fn from(value: str::Utf8Error) -> Self {
Self::Utf8(value)
}
}
impl From<&str> for Error {
fn from(value: &str) -> Self {
Self::Other(value.to_string())
}
}
impl From<String> for Error {
fn from(value: String) -> Self {
Self::Other(value)
}
}
pub fn get_group_names() -> Result<Vec<String>, Error> {
let mut gids: Vec<libc::gid_t> = vec![0; 1];
unsafe {
let num = libc::getgroups(0, gids.as_mut_ptr());
gids = vec![0; num.try_into()?];
libc::getgroups(num, gids.as_mut_ptr());
}
let mut names = vec![];
for id in gids {
let name = unsafe {
let gr = libc::getgrgid(id);
if gr.is_null() {
id.to_string()
} else {
let name = (*gr).gr_name;
// if we don't take ownership here the OS can (and will)
// reuse the memory
CStr::from_ptr(name).to_str()?.to_string()
}
};
names.push(name);
}
Ok(names)
}