use std::ffi::CStr;
#[cfg(target_os = "linux")]
use std::ffi::CString;
use crate::who;
#[cfg(target_os = "linux")]
unsafe extern "C" {
fn utmpxname(file: *const libc::c_char) -> libc::c_int;
}
pub fn get_users() -> Vec<String> {
get_users_from(None)
}
pub fn get_users_from(file: Option<&str>) -> Vec<String> {
if let Some(_path) = file {
let mut users = Vec::new();
unsafe {
#[cfg(target_os = "linux")]
{
if let Ok(cpath) = CString::new(_path) {
utmpxname(cpath.as_ptr());
}
}
libc::setutxent();
loop {
let entry = libc::getutxent();
if entry.is_null() {
break;
}
let entry = &*entry;
if entry.ut_type == libc::USER_PROCESS {
let name = CStr::from_ptr(entry.ut_user.as_ptr())
.to_string_lossy()
.to_string();
if !name.is_empty() {
users.push(name);
}
}
}
libc::endutxent();
#[cfg(target_os = "linux")]
{
if let Ok(cpath) = CString::new("/var/run/utmp") {
utmpxname(cpath.as_ptr());
}
}
}
users.sort();
users
} else {
let entries = who::read_utmpx_with_systemd_fallback();
let mut users: Vec<String> = entries
.iter()
.filter(|e| e.ut_type == 7) .map(|e| e.ut_user.clone())
.filter(|name| !name.is_empty())
.collect();
users.sort();
users
}
}
pub fn format_users(users: &[String]) -> String {
users.join(" ")
}