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