sc_sysinfo/
sysinfo_linux.rs1use regex::Regex;
20use sc_telemetry::SysInfo;
21use std::collections::HashSet;
22
23fn read_file(path: &str) -> Option<String> {
24 match std::fs::read_to_string(path) {
25 Ok(data) => Some(data),
26 Err(error) => {
27 log::warn!("Failed to read '{}': {}", path, error);
28 None
29 },
30 }
31}
32
33fn extract<T>(data: &str, regex: &str) -> Option<T>
34where
35 T: std::str::FromStr,
36{
37 Regex::new(regex)
38 .expect("regex is correct; qed")
39 .captures(&data)?
40 .get(1)?
41 .as_str()
42 .parse()
43 .ok()
44}
45
46const LINUX_REGEX_CPU: &str = r#"(?m)^model name\s*:\s*([^\n]+)"#;
47const LINUX_REGEX_PHYSICAL_ID: &str = r#"(?m)^physical id\s*:\s*(\d+)"#;
48const LINUX_REGEX_CORE_ID: &str = r#"(?m)^core id\s*:\s*(\d+)"#;
49const LINUX_REGEX_HYPERVISOR: &str = r#"(?m)^flags\s*:.+?\bhypervisor\b"#;
50const LINUX_REGEX_MEMORY: &str = r#"(?m)^MemTotal:\s*(\d+) kB"#;
51const LINUX_REGEX_DISTRO: &str = r#"(?m)^PRETTY_NAME\s*=\s*"?(.+?)"?$"#;
52
53pub fn gather_linux_sysinfo(sysinfo: &mut SysInfo) {
54 if let Some(data) = read_file("/proc/cpuinfo") {
55 sysinfo.cpu = extract(&data, LINUX_REGEX_CPU);
56 sysinfo.is_virtual_machine =
57 Some(Regex::new(LINUX_REGEX_HYPERVISOR).unwrap().is_match(&data));
58
59 let mut set: HashSet<(u32, u32)> = HashSet::new();
64 for chunk in data.split("\n\n") {
65 let pid = extract(chunk, LINUX_REGEX_PHYSICAL_ID);
66 let cid = extract(chunk, LINUX_REGEX_CORE_ID);
67 if let (Some(pid), Some(cid)) = (pid, cid) {
68 set.insert((pid, cid));
69 }
70 }
71
72 if !set.is_empty() {
73 sysinfo.core_count = Some(set.len() as u32);
74 }
75 }
76
77 if let Some(data) = read_file("/proc/meminfo") {
78 sysinfo.memory = extract(&data, LINUX_REGEX_MEMORY).map(|memory: u64| memory * 1024);
79 }
80
81 if let Some(data) = read_file("/etc/os-release") {
82 sysinfo.linux_distro = extract(&data, LINUX_REGEX_DISTRO);
83 }
84
85 unsafe {
88 let mut uname: libc::utsname = std::mem::zeroed();
90 if libc::uname(&mut uname) < 0 {
91 log::warn!("uname failed: {}", std::io::Error::last_os_error());
92 } else {
93 let length =
94 uname.release.iter().position(|&byte| byte == 0).unwrap_or(uname.release.len());
95 let release = std::slice::from_raw_parts(uname.release.as_ptr().cast(), length);
96 if let Ok(release) = std::str::from_utf8(release) {
97 sysinfo.linux_kernel = Some(release.into());
98 }
99 }
100 }
101}