Skip to main content

retch_sysinfo/
bios.rs

1// SPDX-FileCopyrightText: 2026 Ken Tobias
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4//! BIOS / firmware version detection.
5
6pub(crate) fn detect_bios() -> Option<String> {
7    #[cfg(target_os = "macos")]
8    {
9        crate::macos_ffi::get_firmware_version()
10    }
11
12    #[cfg(target_os = "windows")]
13    {
14        use crate::win_reg;
15        let manufacturer = win_reg::get_reg_string(
16            win_reg::HKEY_LOCAL_MACHINE,
17            "HARDWARE\\DESCRIPTION\\System\\BIOS",
18            "BIOSVendor",
19        )
20        .unwrap_or_default();
21        let version = win_reg::get_reg_string(
22            win_reg::HKEY_LOCAL_MACHINE,
23            "HARDWARE\\DESCRIPTION\\System\\BIOS",
24            "BIOSVersion",
25        )
26        .unwrap_or_default();
27        let raw_date = win_reg::get_reg_string(
28            win_reg::HKEY_LOCAL_MACHINE,
29            "HARDWARE\\DESCRIPTION\\System\\BIOS",
30            "BIOSReleaseDate",
31        )
32        .unwrap_or_default();
33
34        let manufacturer = manufacturer.trim();
35        let version = version.trim();
36        let raw_date = raw_date.trim();
37
38        let date = if raw_date.len() >= 8 {
39            let year = &raw_date[0..4];
40            let month = &raw_date[4..6];
41            let day = &raw_date[6..8];
42            format!("{}/{}/{}", month, day, year)
43        } else {
44            raw_date.to_string()
45        };
46
47        let mut parts = Vec::new();
48        if !manufacturer.is_empty() {
49            parts.push(manufacturer.to_string());
50        }
51        if !version.is_empty() {
52            parts.push(version.to_string());
53        }
54        let mut res = parts.join(" ");
55        if !date.is_empty() {
56            if res.is_empty() {
57                res = date;
58            } else {
59                res = format!("{} ({})", res, date);
60            }
61        }
62        if !res.is_empty() {
63            return Some(res);
64        }
65        None
66    }
67
68    #[cfg(not(any(target_os = "macos", target_os = "windows")))]
69    {
70        let vendor = std::fs::read_to_string("/sys/class/dmi/id/bios_vendor")
71            .map(|s| s.trim().to_string())
72            .ok();
73        let version = std::fs::read_to_string("/sys/class/dmi/id/bios_version")
74            .map(|s| s.trim().to_string())
75            .ok();
76        let date = std::fs::read_to_string("/sys/class/dmi/id/bios_date")
77            .map(|s| s.trim().to_string())
78            .ok();
79
80        let mut parts = Vec::new();
81        if let Some(v) = vendor {
82            if !v.is_empty() {
83                parts.push(v);
84            }
85        }
86        if let Some(ver) = version {
87            let mut ver_cleaned = ver;
88            while ver_cleaned.contains(" )") {
89                ver_cleaned = ver_cleaned.replace(" )", ")");
90            }
91            let ver_cleaned = ver_cleaned.trim().to_string();
92            if !ver_cleaned.is_empty() {
93                parts.push(ver_cleaned);
94            }
95        }
96        let mut res = parts.join(" ");
97        if let Some(d) = date {
98            if !d.is_empty() {
99                if res.is_empty() {
100                    res = d;
101                } else {
102                    res = format!("{} ({})", res, d);
103                }
104            }
105        }
106        if !res.is_empty() {
107            Some(res)
108        } else {
109            None
110        }
111    }
112}