use crate::utils::passwd::{EtcPasswd, EtcPasswdError};
use thiserror::Error;
use std::{io, os::unix::fs::MetadataExt, path::Path};
const ETC_PASSWD_PATH: &str = "/etc/passwd";
#[derive(Debug, Error)]
pub enum SystemError {
#[error("failed to access the {name} environment variable: {source}")]
EnvironmentVariable {
name: &'static str,
#[source]
source: std::env::VarError,
},
#[error("failed to read the host passwd database: {0}")]
Passwd(#[from] EtcPasswdError),
#[error("user '{username}' not found in {ETC_PASSWD_PATH}")]
UserNotFound { username: String },
#[error("mount host path '{path}' is not accessible: {source}")]
PathMetadata {
path: String,
#[source]
source: io::Error,
},
}
pub fn current_user_uid() -> Result<u32, SystemError> {
let username = std::env::var("USER").map_err(|source| SystemError::EnvironmentVariable {
name: "USER",
source,
})?;
let etc_passwd = EtcPasswd::new(ETC_PASSWD_PATH)?;
etc_passwd
.iter()
.find(|user| user.name == username)
.map(|user| user.id)
.ok_or(SystemError::UserNotFound { username })
}
pub fn is_path_owned_by_user(path: &Path, expected_uid: u32) -> Result<bool, SystemError> {
let metadata = std::fs::metadata(path).map_err(|source| SystemError::PathMetadata {
path: path.display().to_string(),
source,
})?;
let owner_uid = metadata.uid();
Ok(owner_uid == expected_uid)
}