Skip to main content

ferrix_app/
dmi.rs

1/* dmi.rs
2 *
3 * Copyright 2025 Michail Krasnov <mskrasnov07@ya.ru>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 *
18 * SPDX-License-Identifier: GPL-3.0-or-later
19 */
20
21//! DMI Service Provider
22
23use anyhow::Result;
24use async_std::task;
25use ferrix_lib::dmi::{Baseboard, Bios, Chassis, Processor};
26use serde::{Deserialize, Serialize};
27use std::{path::Path, process::Command};
28
29use crate::load_state::{LoadState, ToLoadState};
30
31fn auth_app() -> Option<&'static str> {
32    let apps = ["pkexec", "gksudo"];
33    let bin_dirs = ["/usr/sbin", "/sbin", "/usr/bin", "/bin"];
34
35    for a in apps {
36        for b in bin_dirs {
37            if Path::new(b).join(a).exists() {
38                return Some(a);
39            }
40        }
41    }
42
43    None
44}
45
46pub async fn get_dmi_data() -> LoadState<DMIData> {
47    let auth_app = match auth_app() {
48        Some(auth_app) => auth_app,
49        None => return LoadState::Error("No authentication software found".to_string()),
50    };
51
52    let output = task::spawn_blocking(move || {
53        Command::new(auth_app)
54            .arg("ferrix-polkit")
55            .arg("dmi")
56            .output()
57    })
58    .await;
59
60    if let Err(why) = output {
61        return LoadState::Error(why.to_string());
62    }
63    let output = output.unwrap();
64    if output.status.code().unwrap_or(0) != 0 {
65        return LoadState::Error(format!(
66            "[ferrix-polkit] Non-zero return code:\n{}",
67            String::from_utf8_lossy(&output.stderr)
68        ));
69    }
70
71    let json_str = String::from_utf8_lossy(&output.stdout);
72    let json_data = DMIData::from_json(&json_str);
73
74    match json_data {
75        Ok(data) => LoadState::Loaded(data),
76        Err(why) => LoadState::Error(why.to_string()),
77    }
78}
79
80#[derive(Debug, Serialize, Deserialize, Clone)]
81pub struct DMIData {
82    pub bios: LoadState<Bios>,
83    pub baseboard: LoadState<Baseboard>,
84    pub chassis: LoadState<Chassis>,
85    pub processor: LoadState<Processor>,
86}
87
88impl DMIData {
89    pub fn new() -> Self {
90        Self {
91            bios: Bios::new().to_load_state(),
92            baseboard: Baseboard::new().to_load_state(),
93            chassis: Chassis::new().to_load_state(),
94            processor: Processor::new().to_load_state(),
95        }
96    }
97
98    pub fn to_json(&self) -> Result<String> {
99        let contents = serde_json::to_string(&self)?;
100        Ok(contents)
101    }
102
103    pub fn from_json(json: &str) -> Result<Self> {
104        Ok(serde_json::from_str(json)?)
105    }
106}