1use std::sync::LazyLock;
2
3use regex::Regex;
4
5#[derive(Debug)]
6pub enum LinuxVersionSignature {
7 Ubuntu(UbuntuVersionSignature),
8}
9
10#[derive(Debug)]
11pub struct UbuntuVersionSignature {
12 pub release: String,
13 pub revision: String,
14 pub kernel_flavour: String,
15 pub mainline_kernel_version: String,
16}
17
18#[derive(Debug)]
20pub struct LinuxBanner {
21 pub uts_release: String,
22 pub linux_compile_by: String,
23 pub linux_compile_host: String,
24 pub linux_compiler: String,
25 pub uts_version: String,
26 pub version_signature: Option<LinuxVersionSignature>,
27}
28
29impl LinuxBanner {
32 pub fn parse(banner: &str) -> Option<Self> {
33 static LINUX_VERSION_REGEX: LazyLock<Regex> = LazyLock::new(|| {
41 Regex::new(concat!(
42 r"Linux version (?<UTS_RELEASE>[0-9]+\.[0-9]+\.[0-9]+[^ ]*) ",
43 r"\((?<LINUX_COMPILE_BY>[^@]*)@(?<LINUX_COMPILE_HOST>[^)]*)\) ",
44 r"\((?<LINUX_COMPILER>.*)\) ",
45 r"#(?<UTS_VERSION>.*)"
46 ))
47 .unwrap()
48 });
49
50 let captures = LINUX_VERSION_REGEX.captures(banner)?;
51 let version_signature = try_parse_ubuntu_signature(&captures["UTS_VERSION"]);
52
53 Some(Self {
54 uts_release: captures["UTS_RELEASE"].to_string(),
55 linux_compile_by: captures["LINUX_COMPILE_BY"].to_string(),
56 linux_compile_host: captures["LINUX_COMPILE_HOST"].to_string(),
57 linux_compiler: captures["LINUX_COMPILER"].to_string(),
58 uts_version: captures["UTS_VERSION"].to_string(),
59 version_signature,
60 })
61 }
62}
63
64fn try_parse_ubuntu_signature(uts_version: &str) -> Option<LinuxVersionSignature> {
65 static UBUNTU_VERSION_REGEX: LazyLock<Regex> = LazyLock::new(|| {
70 Regex::new(concat!(
71 r"\(Ubuntu ",
72 r"(?<UBUNTU_RELEASE>.*)-(?<UBUNTU_REVISION>.*)-(?<UBUNTU_KERNEL_FLAVOUR>.*) ",
73 r"(?<UBUNTU_MAINLINE_KERNEL_VERSION>.*)\)"
74 ))
75 .unwrap()
76 });
77
78 let captures = UBUNTU_VERSION_REGEX.captures(uts_version)?;
79
80 Some(LinuxVersionSignature::Ubuntu(UbuntuVersionSignature {
81 release: captures["UBUNTU_RELEASE"].into(),
82 revision: captures["UBUNTU_REVISION"].into(),
83 kernel_flavour: captures["UBUNTU_KERNEL_FLAVOUR"].into(),
84 mainline_kernel_version: captures["UBUNTU_MAINLINE_KERNEL_VERSION"].into(),
85 }))
86}