use crate::utils::command::new_command;
use once_cell::sync::Lazy;
use std::io::{self, Write};
use std::sync::Mutex;
use sysinfo::{ProcessRefreshKind, ProcessesToUpdate, System, UpdateKind};
static GLOBAL_SYSTEM: Lazy<Mutex<System>> = Lazy::new(|| {
let system = System::new();
Mutex::new(system)
});
static CACHED_HOSTNAME: Lazy<String> =
Lazy::new(|| System::host_name().unwrap_or_else(|| "unknown".to_string()));
pub fn get_hostname() -> String {
CACHED_HOSTNAME.clone()
}
pub fn with_global_system<F, R>(f: F) -> R
where
F: FnOnce(&mut System) -> R,
{
let mut system = GLOBAL_SYSTEM.lock().unwrap();
f(&mut system)
}
#[allow(dead_code)]
pub fn refresh_global_processes() {
let mut system = GLOBAL_SYSTEM.lock().unwrap();
system.refresh_processes_specifics(
ProcessesToUpdate::All,
true,
ProcessRefreshKind::everything().with_user(UpdateKind::Always),
);
system.refresh_memory();
}
pub fn has_sudo_privileges() -> bool {
new_command("sudo")
.arg("-n") .arg("-v") .output()
.map(|output| output.status.success())
.unwrap_or(false)
}
#[allow(dead_code)] pub fn calculate_adaptive_interval(node_count: usize) -> u64 {
match node_count {
0..=10 => 2,
11..=50 => 3,
51..=100 => 4,
101..=200 => 5,
_ => 6,
}
}
#[allow(dead_code)] pub fn ensure_sudo_permissions() {
if cfg!(target_os = "macos") {
} else if cfg!(target_os = "linux") {
#[cfg(all(target_os = "linux", not(target_env = "musl")))]
{
use crate::device::platform_detection::has_amd;
if has_amd() {
if unsafe { libc::geteuid() } != 0 {
request_sudo_with_explanation(SudoPlatform::Linux, false);
}
}
}
} else {
eprintln!("Note: This platform may not require sudo for hardware monitoring.");
}
}
pub fn ensure_sudo_permissions_for_api() -> bool {
#[cfg(target_os = "windows")]
{
println!("✅ Running on Windows, no sudo required.");
true
}
#[cfg(unix)]
{
#[cfg(target_os = "macos")]
{
true
}
#[cfg(not(target_os = "macos"))]
{
if std::env::var("USER").unwrap_or_default() == "root"
|| unsafe { libc::geteuid() } == 0
{
println!("✅ Running as root, no sudo required.");
return true;
}
if has_sudo_privileges() {
println!("✅ Sudo privileges already available.");
return true;
}
println!("⚠️ Warning: Running without sudo privileges.");
println!(" Some hardware metrics may not be available.");
println!(" For full functionality, run with: sudo all-smi api --port <port>");
false
}
}
#[cfg(not(any(target_os = "windows", unix)))]
{
println!("✅ Running on unsupported platform, no sudo required.");
true
}
}
#[allow(dead_code)] pub fn ensure_sudo_permissions_with_fallback() -> bool {
if cfg!(target_os = "macos") {
true
} else if cfg!(target_os = "linux") {
#[cfg(all(target_os = "linux", not(target_env = "musl")))]
{
use crate::device::platform_detection::has_amd;
if has_amd() {
if unsafe { libc::geteuid() } != 0 {
request_sudo_with_explanation(SudoPlatform::Linux, false);
}
return true;
}
}
true
} else {
true
}
}
#[derive(Copy, Clone)]
#[allow(dead_code)] enum SudoPlatform {
Linux,
}
#[allow(dead_code)] fn get_sudo_messages(
_platform: SudoPlatform,
) -> (
&'static str,
&'static str,
&'static str,
Option<&'static str>,
Option<&'static str>,
) {
(
" • Access to AMD GPU devices requires read/write permissions on /dev/dri\n • These devices are typically only accessible by root or video/render group\n • This includes GPU utilization, memory usage, temperature, and power data",
" • all-smi only reads GPU metrics - it does not modify your system\n • The sudo access is used exclusively for accessing AMD GPU devices\n • No data is transmitted externally without your explicit configuration",
" • AMD GPU: Utilization, VRAM usage, temperature, power, clock speeds\n • CPU: Core utilization and performance metrics\n • Memory: System RAM usage and allocation\n • Storage: Disk usage and performance",
Some(
"💡 Alternative: Add your user to the 'video' and 'render' groups:\n sudo usermod -a -G video,render $USER\n (requires logout/login to take effect)",
),
Some(
" Alternative: Add your user to video/render groups:\n → sudo usermod -a -G video,render $USER",
),
)
}
#[allow(dead_code)] fn request_sudo_with_explanation(platform: SudoPlatform, return_bool: bool) -> bool {
if has_sudo_privileges() {
#[cfg(target_os = "linux")]
{
if matches!(platform, SudoPlatform::Linux) && unsafe { libc::geteuid() } != 0 {
println!();
println!("⚠️ Sudo timestamp is valid, but the process is not running as root.");
println!();
println!("AMD GPU monitoring requires the program itself to run with sudo:");
println!(" → sudo all-smi");
println!();
println!("(Unlike macOS, Linux requires root privileges for /dev/dri access)");
println!();
std::process::exit(1);
}
}
println!();
println!("✅ Administrator privileges already available.");
println!(" Starting system monitoring...");
println!();
if !return_bool {
std::thread::sleep(std::time::Duration::from_millis(300));
}
return true; }
let (required_reasons, security_info, monitored_items, alternative, additional_troubleshooting) =
get_sudo_messages(platform);
println!();
println!("🔧 all-smi: System Monitoring Interface");
println!("============================================");
println!();
println!("This application monitors GPU, CPU, and memory usage on your system.");
println!();
println!("🔒 Administrator privileges are required because:");
println!("{required_reasons}");
println!();
println!("🛡️ Security Information:");
println!("{security_info}");
println!();
println!("📋 What will be monitored:");
println!("{monitored_items}");
println!();
if let Some(alt) = alternative {
println!("{alt}");
println!();
}
print!("To proceed, you need to enter your sudo password.");
println!();
println!("🔑 Requesting administrator privileges...");
println!(" (You may be prompted for your password)");
println!();
io::stdout().flush().unwrap();
let status = new_command("sudo")
.arg("-v")
.status()
.expect("Failed to execute sudo command");
if !status.success() {
println!("❌ Failed to acquire administrator privileges.");
println!();
println!("💡 Troubleshooting:");
println!(" • Make sure you entered the correct password");
println!(" • Ensure your user account has sudo privileges");
println!(" • Try running 'sudo -v' manually to test sudo access");
println!();
if let Some(additional) = additional_troubleshooting {
println!("{additional}");
println!();
}
println!(" For remote monitoring without sudo, use:");
println!(" → all-smi view --hosts <url1> <url2>");
println!();
std::process::exit(1);
}
println!("✅ Administrator privileges granted successfully.");
println!(" Starting system monitoring...");
println!();
true }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_calculate_adaptive_interval() {
assert_eq!(calculate_adaptive_interval(0), 2);
assert_eq!(calculate_adaptive_interval(1), 2);
assert_eq!(calculate_adaptive_interval(5), 2);
assert_eq!(calculate_adaptive_interval(10), 2);
assert_eq!(calculate_adaptive_interval(11), 3);
assert_eq!(calculate_adaptive_interval(25), 3);
assert_eq!(calculate_adaptive_interval(50), 3);
assert_eq!(calculate_adaptive_interval(51), 4);
assert_eq!(calculate_adaptive_interval(75), 4);
assert_eq!(calculate_adaptive_interval(100), 4);
assert_eq!(calculate_adaptive_interval(101), 5);
assert_eq!(calculate_adaptive_interval(150), 5);
assert_eq!(calculate_adaptive_interval(200), 5);
assert_eq!(calculate_adaptive_interval(201), 6);
assert_eq!(calculate_adaptive_interval(500), 6);
assert_eq!(calculate_adaptive_interval(1000), 6);
}
#[test]
fn test_get_hostname() {
let hostname = get_hostname();
assert!(!hostname.is_empty(), "Hostname should not be empty");
assert!(
!hostname.contains('\n'),
"Hostname should not contain newlines"
);
assert!(
!hostname.contains('\r'),
"Hostname should not contain carriage returns"
);
}
#[cfg(target_os = "macos")]
#[test]
#[ignore] fn test_ensure_sudo_permissions_macos() {
ensure_sudo_permissions();
}
#[cfg(not(target_os = "macos"))]
#[test]
fn test_ensure_sudo_permissions_non_macos() {
ensure_sudo_permissions();
}
#[test]
#[cfg_attr(target_os = "macos", ignore)] fn test_ensure_sudo_permissions_with_fallback_returns_bool() {
let _result = ensure_sudo_permissions_with_fallback();
}
#[test]
#[cfg(target_os = "macos")]
fn test_has_sudo_privileges_on_macos() {
let _result = has_sudo_privileges();
}
#[test]
#[cfg(not(target_os = "macos"))]
fn test_has_sudo_privileges_on_non_macos() {
let result = has_sudo_privileges();
let _ = result;
}
}