use std::ffi::OsString;
#[cfg(windows)]
use std::os::windows::ffi::OsStringExt;
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct BackgroundInfo {
pub pid: u32,
pub tid: String,
pub username: String,
pub hostname: String,
}
impl BackgroundInfo {
pub fn new() -> Self {
Self {
pid: get_pid(),
tid: get_tid(),
username: get_username(),
hostname: get_hostname(),
}
}
pub fn pid(&self) -> u32 {
self.pid
}
pub fn tid(&self) -> &str {
&self.tid
}
pub fn username(&self) -> &str {
&self.username
}
pub fn hostname(&self) -> &str {
&self.hostname
}
}
pub fn get_pid() -> u32 {
std::process::id()
}
pub fn get_tid() -> String {
#[cfg(windows)]
{
unsafe {
let tid = winapi::um::processthreadsapi::GetCurrentThreadId();
tid.to_string()
}
}
#[cfg(unix)]
{
unsafe {
let tid = libc::syscall(libc::SYS_gettid);
tid.to_string()
}
}
#[cfg(not(any(windows, unix)))]
{
use std::thread;
format!("{:?}", thread::current().id())
}
}
pub fn get_username() -> String {
#[cfg(windows)]
{
get_username_windows().unwrap_or_else(|| "unknown".to_string())
}
#[cfg(unix)]
{
get_username_unix().unwrap_or_else(|| "unknown".to_string())
}
#[cfg(not(any(windows, unix)))]
{
"unknown".to_string()
}
}
pub fn get_hostname() -> String {
hostname::get()
.map(|name| name.to_string_lossy().into_owned())
.ok()
.unwrap_or_else(|| "unknown".to_string())
}
#[cfg(windows)]
fn get_username_windows() -> Option<String> {
use winapi::shared::minwindef::DWORD;
use winapi::um::winbase::GetUserNameW;
let mut buffer = vec![0u16; 256];
let mut size = buffer.len() as DWORD;
unsafe {
if GetUserNameW(buffer.as_mut_ptr(), &mut size) != 0 {
buffer.truncate((size - 1) as usize); let os_string = OsString::from_wide(&buffer);
os_string.into_string().ok()
} else {
None
}
}
}
#[cfg(unix)]
fn get_username_unix() -> Option<String> {
use std::env;
if let Ok(user) = env::var("USER") {
return Some(user);
}
if let Ok(user) = env::var("USERNAME") {
return Some(user);
}
unsafe {
let uid = libc::getuid();
let passwd = libc::getpwuid(uid);
if !passwd.is_null() {
let name_ptr = (*passwd).pw_name;
if !name_ptr.is_null() {
let c_str = std::ffi::CStr::from_ptr(name_ptr);
return c_str.to_string_lossy().into_owned().into();
}
}
}
None
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_get_pid() {
let pid = get_pid();
assert!(pid > 0);
}
#[test]
fn test_get_tid() {
let tid = get_tid();
assert!(!tid.is_empty());
}
#[test]
fn test_get_username() {
let username = get_username();
assert!(!username.is_empty());
assert_ne!(username, "unknown");
}
#[test]
fn test_get_hostname() {
let hostname = get_hostname();
assert!(!hostname.is_empty());
assert_ne!(hostname, "unknown");
}
#[test]
fn test_multiple_calls_consistency() {
let pid1 = get_pid();
let pid2 = get_pid();
assert_eq!(pid1, pid2);
let username1 = get_username();
let username2 = get_username();
assert_eq!(username1, username2);
let hostname1 = get_hostname();
let hostname2 = get_hostname();
assert_eq!(hostname1, hostname2);
}
}