scx_pandemonium/cli/
check.rs1use std::io::Read;
2use std::path::Path;
3use std::process::Command;
4
5use anyhow::Result;
6
7fn check_tool(name: &str) -> bool {
8 Command::new("which")
9 .arg(name)
10 .output()
11 .map(|o| o.status.success())
12 .unwrap_or(false)
13}
14
15fn check_kernel_version() -> bool {
16 let release = std::fs::read_to_string("/proc/sys/kernel/osrelease")
17 .unwrap_or_default()
18 .trim()
19 .to_string();
20 let parts: Vec<&str> = release.split('.').collect();
21 if parts.len() >= 2 {
22 if let (Ok(major), Ok(minor)) = (parts[0].parse::<u32>(), parts[1].parse::<u32>()) {
23 if major > 6 || (major == 6 && minor >= 12) {
24 log_info!("Kernel {} (>= 6.12)", release);
25 return true;
26 }
27 log_error!(
28 "Kernel {}.{} is too old. PANDEMONIUM requires 6.12+.",
29 major,
30 minor
31 );
32 log_error!("sched_ext (CONFIG_SCHED_CLASS_EXT) was merged in Linux 6.12.");
33 return false;
34 }
35 }
36 log_warn!("Cannot parse kernel version from '{}'", release);
37 false
38}
39
40fn check_vmlinux_cache() -> bool {
41 let cache = Path::new("/tmp/pandemonium-vmlinux.h");
42 if cache.exists() && cache.metadata().map(|m| m.len() > 1000).unwrap_or(false) {
43 let size = cache.metadata().map(|m| m.len() / 1024).unwrap_or(0);
44 log_info!("vmlinux.h cached ({size} KB)");
45 return true;
46 }
47 log_warn!("vmlinux.h not cached (will be downloaded on first build)");
48 true
49}
50
51fn check_kernel_config() -> bool {
52 let file = match std::fs::File::open("/proc/config.gz") {
53 Ok(f) => f,
54 Err(_) => {
55 log_warn!("/proc/config.gz not found (skipped)");
56 return true;
57 }
58 };
59 let mut decoder = flate2::read::GzDecoder::new(file);
60 let mut config = String::new();
61 if decoder.read_to_string(&mut config).is_err() {
62 log_warn!("/proc/config.gz unreadable (skipped)");
63 return true;
64 }
65 let found = config.contains("CONFIG_SCHED_CLASS_EXT=y");
66 if found {
67 log_info!("CONFIG_SCHED_CLASS_EXT=y found");
68 } else {
69 log_error!("CONFIG_SCHED_CLASS_EXT not found -- sched_ext may not be available");
70 }
71 found
72}
73
74pub fn run_check() -> Result<()> {
75 log_info!("PANDEMONIUM dependency check");
76
77 let mut ok = true;
78 let tools = ["cargo", "rustc", "clang", "sudo"];
79 for tool in &tools {
80 if check_tool(tool) {
81 log_info!(" {:<24}OK", tool);
82 } else {
83 log_error!(" {:<24}MISSING", tool);
84 ok = false;
85 }
86 }
87
88 log_info!("Kernel version:");
89 if !check_kernel_version() {
90 ok = false;
91 }
92
93 log_info!("Kernel config:");
94 if !check_kernel_config() {
95 ok = false;
96 }
97
98 log_info!("Build cache:");
99 check_vmlinux_cache();
100
101 let scx_path = Path::new("/sys/kernel/sched_ext/root/ops");
102 if scx_path.exists() {
103 let active = std::fs::read_to_string(scx_path).unwrap_or_default();
104 let active = active.trim();
105 if active.is_empty() {
106 log_info!("sched_ext available (no scheduler active)");
107 } else {
108 log_info!("sched_ext active ({})", active);
109 }
110 } else {
111 log_error!("sched_ext not available (sysfs path missing)");
112 ok = false;
113 }
114
115 if ok {
116 log_info!("All checks passed");
117 } else {
118 log_error!("Some checks failed");
119 if !check_tool("cargo") || !check_tool("rustc") {
120 log_info!(" Install Rust: https://rustup.rs");
121 }
122 if !check_tool("clang") {
123 log_info!(" Install clang: pacman -S clang");
124 }
125 std::process::exit(1);
126 }
127
128 Ok(())
129}