feat(system/about): display all system information required
This commit is contained in:
parent
0a267c027d
commit
89a251f2ba
6 changed files with 585 additions and 43 deletions
202
pages/system/src/lib.rs
Normal file
202
pages/system/src/lib.rs
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
// Copyright 2023 System76 <info@system76.com>
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use bumpalo::Bump;
|
||||
use std::{ffi::OsStr, io::Read};
|
||||
use sysinfo::{DiskExt, SystemExt};
|
||||
|
||||
use concat_in_place::strcat;
|
||||
use const_format::concatcp;
|
||||
|
||||
const DMI_DIR: &str = "/sys/devices/virtual/dmi/id/";
|
||||
const BOARD_NAME: &str = concatcp!(DMI_DIR, "board_name");
|
||||
const BOARD_VERSION: &str = concatcp!(DMI_DIR, "board_version");
|
||||
const SYS_VENDOR: &str = concatcp!(DMI_DIR, "sys_vendor");
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct Info {
|
||||
pub desktop_environment: String,
|
||||
pub device_name: String,
|
||||
pub disk_capacity: String,
|
||||
pub graphics: Vec<String>,
|
||||
pub hardware_model: String,
|
||||
pub memory: String,
|
||||
pub operating_system: String,
|
||||
pub os_architecture: String,
|
||||
pub processor: String,
|
||||
pub windowing_system: String,
|
||||
}
|
||||
|
||||
impl Info {
|
||||
pub fn load() -> Info {
|
||||
let mut info = Info::default();
|
||||
let mut bump = Bump::with_capacity(8 * 1024);
|
||||
|
||||
architecture(&bump, &mut info.os_architecture);
|
||||
bump.reset();
|
||||
|
||||
hardware_model(&bump, &mut info.hardware_model);
|
||||
bump.reset();
|
||||
|
||||
operating_system(&bump, &mut info.operating_system);
|
||||
bump.reset();
|
||||
|
||||
processor_name(&bump, &mut info.processor);
|
||||
bump.reset();
|
||||
|
||||
let mut sys = sysinfo::System::new();
|
||||
|
||||
sys.refresh_disks_list();
|
||||
sys.refresh_disks();
|
||||
sys.refresh_memory();
|
||||
|
||||
let mut total_capacity = 0;
|
||||
for disk in sys.disks() {
|
||||
total_capacity += disk.total_space();
|
||||
}
|
||||
|
||||
info.disk_capacity = format!("{} GB", (total_capacity / 1_000_000_000));
|
||||
|
||||
if let Some(name) = sys.host_name() {
|
||||
info.device_name = name;
|
||||
}
|
||||
|
||||
info.memory = format!("{} GB", (sys.total_memory() / 1_000_000_000 + 1));
|
||||
|
||||
if let Ok(mut session) = std::env::var("XDG_SESSION_TYPE") {
|
||||
if let Some(first) = session.get_mut(0..1) {
|
||||
first.make_ascii_uppercase();
|
||||
}
|
||||
|
||||
info.windowing_system = session;
|
||||
}
|
||||
|
||||
if let Ok(mut session) = std::env::var("DESKTOP_SESSION") {
|
||||
if let Some(first) = session.get_mut(0..1) {
|
||||
first.make_ascii_uppercase();
|
||||
}
|
||||
|
||||
info.desktop_environment = session;
|
||||
}
|
||||
|
||||
if let Ok(output) = std::process::Command::new("lspci").output() {
|
||||
if let Ok(stdout) = std::str::from_utf8(&output.stdout) {
|
||||
for line in stdout.lines() {
|
||||
if let Some(pos) = memchr::memmem::find(line.as_bytes(), b"VGA") {
|
||||
let line = &line[pos + 3..];
|
||||
if let Some(pos) = memchr::memmem::find(line.as_bytes(), b": ") {
|
||||
info.graphics.push(String::from(&line[pos + 2..]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info
|
||||
}
|
||||
}
|
||||
|
||||
pub fn architecture(bump: &Bump, arch: &mut String) {
|
||||
let buffer = &mut bumpalo::collections::Vec::new_in(bump);
|
||||
if let Some(value) = read_to_string("/proc/sys/kernel/arch", buffer) {
|
||||
arch.push_str(value.trim());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hardware_model(bump: &Bump, hardware_model: &mut String) {
|
||||
let buffer = &mut bumpalo::collections::Vec::new_in(bump);
|
||||
if let Some(mut sys_vendor) = read_to_string(SYS_VENDOR, buffer) {
|
||||
sys_vendor = sys_vendor.trim();
|
||||
|
||||
hardware_model.push_str(sys_vendor);
|
||||
|
||||
let buffer = &mut bumpalo::collections::Vec::new_in(bump);
|
||||
if let Some(mut name) = read_to_string(BOARD_NAME, buffer) {
|
||||
name = name.trim();
|
||||
|
||||
if !name.is_empty() && name != sys_vendor {
|
||||
// Ensure that the name does not contain the vendor.
|
||||
name = match name.strip_prefix(sys_vendor) {
|
||||
Some(stripped) => stripped.trim(),
|
||||
None => name,
|
||||
};
|
||||
|
||||
strcat!(&mut *hardware_model, " " name);
|
||||
}
|
||||
|
||||
let buffer = &mut bumpalo::collections::Vec::new_in(bump);
|
||||
if let Some(mut version) = read_to_string(BOARD_VERSION, buffer) {
|
||||
version = version.trim();
|
||||
|
||||
// These have bogus values for their version.
|
||||
const IGNORE_PRODUCTS: &[&str] = &["Dev One"];
|
||||
|
||||
if !version.is_empty() && !IGNORE_PRODUCTS.contains(&name) {
|
||||
strcat!(hardware_model, " (" version.trim() ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn operating_system(bump: &Bump, operating_system: &mut String) {
|
||||
let mut buffer = bumpalo::collections::Vec::new_in(bump);
|
||||
let Some(os_release) = read_to_string("/etc/os-release", &mut buffer) else {
|
||||
return;
|
||||
};
|
||||
|
||||
for line in os_release.lines() {
|
||||
if let Some(mut value) = line.strip_prefix("PRETTY_NAME=") {
|
||||
if let Some(v) = value.strip_prefix('"') {
|
||||
value = v;
|
||||
}
|
||||
|
||||
if let Some(v) = value.strip_suffix('"') {
|
||||
value = v;
|
||||
}
|
||||
|
||||
operating_system.push_str(value.trim());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn processor_name(bump: &Bump, name: &mut String) {
|
||||
if let Some(cpuinfo) = read_to_string(
|
||||
"/proc/cpuinfo",
|
||||
&mut bumpalo::collections::Vec::new_in(bump),
|
||||
) {
|
||||
for line in cpuinfo.lines() {
|
||||
if let Some(info) = line.strip_prefix("model name") {
|
||||
if let Some(info) = info.trim_start().strip_prefix(":") {
|
||||
name.push_str(info.trim());
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_to_string<'a, P: AsRef<OsStr>>(
|
||||
path: P,
|
||||
buffer: &'a mut bumpalo::collections::Vec<u8>,
|
||||
) -> Option<&'a str> {
|
||||
let mut file = std::fs::File::open(path.as_ref()).ok()?;
|
||||
|
||||
if let Ok(metadata) = file.metadata() {
|
||||
buffer.reserve_exact(metadata.len() as usize);
|
||||
}
|
||||
|
||||
let mut buf = [0; 16 * 1024];
|
||||
|
||||
loop {
|
||||
match file.read(&mut buf) {
|
||||
Ok(0) => break,
|
||||
Ok(read) => buffer.extend_from_slice(&buf[..read]),
|
||||
Err(_) => return None,
|
||||
}
|
||||
}
|
||||
|
||||
std::str::from_utf8(buffer.as_slice()).ok()
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue