use std::env;
use std::ffi::CString;
use std::fs;
pub fn get_titles(fqdn: bool) -> (String, String) {
let user = get_user();
let host = get_hostname(fqdn);
(user, host)
}
fn get_user() -> String {
if let Some(u) = env::var_os("USER") {
let s = u.to_string_lossy();
if !s.is_empty() {
return s.into();
}
}
let uid = unsafe { libc::getuid() };
if uid > 0 {
if let Some(pw) = get_pwuid(uid) {
return pw;
}
}
if let Ok(home) = env::var("HOME") {
if let Some(name) = home.rsplit('/').find(|s| !s.is_empty()) {
return name.to_string();
}
}
"unknown".into()
}
fn get_pwuid(uid: libc::uid_t) -> Option<String> {
let mut passwd = MaybeUninit::uninit();
let mut buf = vec![0u8; 1024];
let result = unsafe {
let mut pwd_ptr: *mut libc::passwd = std::ptr::null_mut();
libc::getpwuid_r(
uid,
passwd.as_mut_ptr(),
buf.as_mut_ptr() as *mut libc::c_char,
buf.len(),
&mut pwd_ptr,
)
};
if result == 0 && !passwd.as_ptr().is_null() {
let pwd = unsafe { passwd.assume_init() };
if !pwd.pw_name.is_null() {
let name = unsafe { CString::from_raw(pwd.pw_name) };
return Some(name.to_string_lossy().into_owned());
}
}
None
}
fn get_hostname(fqdn: bool) -> String {
let mut buf = [0u8; 256];
let len = unsafe { libc::gethostname(buf.as_mut_ptr() as *mut libc::c_char, buf.len()) };
if len == 0 {
let s = String::from_utf8_lossy(&buf)
.trim_end_matches('\0')
.to_string();
if !s.is_empty() && (s != "localhost" || !fqdn) {
if fqdn {
if let Ok(fqdn_name) = fs::read_to_string("/etc/hostname") {
let trimmed = fqdn_name.trim().to_string();
if !trimmed.is_empty() && trimmed.contains('.') {
return trimmed;
}
}
if let Ok(domain) = fs::read_to_string("/etc/resolv.conf") {
for line in domain.lines() {
if line.starts_with("domain ") {
let domain = line[7..].trim();
if !domain.is_empty() {
return format!("{}.{}", s, domain);
}
}
}
}
}
return s;
}
}
if let Some(h) = env::var_os("HOSTNAME") {
let s = h.to_string_lossy();
if !s.is_empty() {
return s.into();
}
}
if let Ok(hostname) = fs::read_to_string("/etc/hostname") {
let s = hostname.trim().to_string();
if !s.is_empty() {
return s;
}
}
"localhost".into()
}
use std::mem::MaybeUninit;
#[cfg(test)]
mod tests {
use super::*;
use crate::test_utils::EnvLock;
#[test]
fn test_get_user_from_env() {
let env_lock = EnvLock::acquire(&["USER"]);
env_lock.set_var("USER", "testuser");
assert_eq!(get_user(), "testuser");
drop(env_lock);
}
#[test]
fn test_hostname_from_env() {
let env_lock = EnvLock::acquire(&["HOSTNAME"]);
env_lock.set_var("HOSTNAME", "testhost");
assert_eq!(get_hostname(false), "testhost");
drop(env_lock);
}
#[test]
fn test_hostname_command_fallback() {
let env_lock = EnvLock::acquire(&["HOSTNAME"]);
env_lock.remove_var("HOSTNAME");
let result = get_hostname(false);
assert!(!result.is_empty(), "Hostname should not be empty");
drop(env_lock);
}
#[test]
fn test_hostname_final_fallback() {
let result = get_hostname(false);
assert!(!result.is_empty());
}
}