Skip to main content

batuta_common/
sys.rs

1//! System information utilities.
2//!
3//! Provides cross-platform detection for cgroups, CPU info, and other
4//! system-level queries used across the Batuta stack.
5
6/// Check if cgroup v1 or v2 CPU controllers are available.
7///
8/// Returns `true` on Linux when either `/sys/fs/cgroup/cpu` (v1) or
9/// `/sys/fs/cgroup/unified` (v2) exists. Always returns `false` on non-Linux.
10///
11/// # Examples
12/// ```
13/// use batuta_common::sys::is_cgroup_available;
14/// // Returns true on Linux with cgroup support
15/// let _available = is_cgroup_available();
16/// ```
17#[must_use]
18pub fn is_cgroup_available() -> bool {
19    #[cfg(target_os = "linux")]
20    {
21        std::path::Path::new("/sys/fs/cgroup/cpu").exists()
22            || std::path::Path::new("/sys/fs/cgroup/unified").exists()
23    }
24
25    #[cfg(not(target_os = "linux"))]
26    {
27        false
28    }
29}
30
31/// Get CPU model name (best effort).
32///
33/// On Linux, reads `/proc/cpuinfo` for the "model name" field.
34/// Returns `"Unknown CPU"` on other platforms or if parsing fails.
35///
36/// # Examples
37/// ```
38/// use batuta_common::sys::get_cpu_info;
39/// let info = get_cpu_info();
40/// assert!(!info.is_empty());
41/// ```
42#[must_use]
43pub fn get_cpu_info() -> String {
44    #[cfg(target_os = "linux")]
45    {
46        if let Ok(content) = std::fs::read_to_string("/proc/cpuinfo") {
47            for line in content.lines() {
48                if line.starts_with("model name")
49                    && let Some(name) = line.split(':').nth(1)
50                {
51                    return name.trim().to_string();
52                }
53            }
54        }
55    }
56    "Unknown CPU".to_string()
57}
58
59/// Get the number of available CPU cores.
60///
61/// Uses `std::thread::available_parallelism()`, falling back to 1.
62#[must_use]
63pub fn cpu_count() -> usize {
64    std::thread::available_parallelism()
65        .map(std::num::NonZero::get)
66        .unwrap_or(1)
67}
68
69#[cfg(test)]
70mod tests {
71    use super::*;
72
73    #[test]
74    fn test_is_cgroup_available_returns_bool() {
75        // Just verify it doesn't panic
76        let _ = is_cgroup_available();
77    }
78
79    #[test]
80    fn test_get_cpu_info_non_empty() {
81        let info = get_cpu_info();
82        assert!(!info.is_empty());
83    }
84
85    #[test]
86    fn test_cpu_count_positive() {
87        assert!(cpu_count() >= 1);
88    }
89
90    #[cfg(target_os = "linux")]
91    #[test]
92    fn test_cgroup_on_linux() {
93        // On Linux, cgroup should typically be available
94        // but we don't assert true since containers may not have it
95        let _ = is_cgroup_available();
96    }
97}