use crate::*;
use std::{io::Error, io::ErrorKind};
#[cfg(any(target_os = "linux"))]
pub const SYS_ENTRY_FILE: &'static str = "/sys/firmware/dmi/tables/smbios_entry_point";
#[cfg(any(target_os = "linux"))]
pub const SYS_TABLE_FILE: &'static str = "/sys/firmware/dmi/tables/DMI";
pub const DEV_MEM_FILE: &'static str = "/dev/mem";
#[cfg(any(target_os = "linux"))]
pub fn table_load_from_device() -> Result<SMBiosData, Error> {
let version: SMBiosVersion;
let entry_path = std::path::Path::new(SYS_ENTRY_FILE);
match SMBiosEntryPoint64::try_load_from_file(entry_path) {
Ok(entry_point) => {
version = SMBiosVersion {
major: entry_point.major_version(),
minor: entry_point.minor_version(),
revision: entry_point.docrev(),
}
}
Err(err) => match err.kind() {
ErrorKind::InvalidData => {
match SMBiosEntryPoint32::try_load_from_file(entry_path) {
Ok(entry_point) => {
version = SMBiosVersion {
major: entry_point.major_version(),
minor: entry_point.minor_version(),
revision: 0,
}
}
Err(err) => return Err(err),
}
}
_ => return Err(err),
},
}
SMBiosData::try_load_from_file(SYS_TABLE_FILE, Some(version))
}
#[cfg(any(target_os = "freebsd"))]
pub fn table_load_from_device() -> Result<SMBiosData, Error> {
const RANGE_START: u64 = 0x000F0000u64;
const RANGE_END: u64 = 0x000FFFFFu64;
let structure_table_address: u64;
let structure_table_length: u32;
let version: SMBiosVersion;
let mut dev_mem = std::fs::File::open(DEV_MEM_FILE)?;
match SMBiosEntryPoint32::try_scan_from_file(&mut dev_mem, RANGE_START..=RANGE_END) {
Ok(entry_point) => {
structure_table_address = entry_point.structure_table_address() as u64;
structure_table_length = entry_point.structure_table_length() as u32;
version = SMBiosVersion {
major: entry_point.major_version(),
minor: entry_point.minor_version(),
revision: 0,
}
}
Err(error) => {
if error.kind() != ErrorKind::UnexpectedEof {
return Err(error);
}
let entry_point =
SMBiosEntryPoint64::try_scan_from_file(&mut dev_mem, RANGE_START..=RANGE_END)?;
structure_table_address = entry_point.structure_table_address();
structure_table_length = entry_point.structure_table_maximum_size();
version = SMBiosVersion {
major: entry_point.major_version(),
minor: entry_point.minor_version(),
revision: entry_point.docrev(),
}
}
}
if structure_table_address < RANGE_START || structure_table_address > RANGE_END {
return Err(Error::new(
ErrorKind::InvalidData,
format!(
"The entry point has given an out of range start address for the table: {}",
structure_table_address
),
));
}
if structure_table_address + structure_table_length as u64 > RANGE_END {
return Err(Error::new(
ErrorKind::InvalidData,
format!(
"The entry point has given a length which exceeds the range: {}",
structure_table_length
),
));
}
let table = UndefinedStructTable::try_load_from_file_offset(
&mut dev_mem,
structure_table_address,
structure_table_length as usize,
)?;
Ok(SMBiosData::new(table, Some(version)))
}
#[cfg(any(target_os = "linux"))]
pub fn raw_smbios_from_device() -> Result<Vec<u8>, Error> {
Ok(std::fs::read(SYS_TABLE_FILE)?)
}
#[cfg(any(target_os = "freebsd"))]
pub fn raw_smbios_from_device() -> Result<Vec<u8>, Error> {
use std::io::{prelude::*, SeekFrom};
const RANGE_START: u64 = 0x000F0000u64;
const RANGE_END: u64 = 0x000FFFFFu64;
let structure_table_address: u64;
let structure_table_length: usize;
let mut dev_mem = std::fs::File::open(DEV_MEM_FILE)?;
match SMBiosEntryPoint32::try_scan_from_file(&mut dev_mem, RANGE_START..=RANGE_END) {
Ok(entry_point) => {
structure_table_address = entry_point.structure_table_address() as u64;
structure_table_length = entry_point.structure_table_length() as usize;
}
Err(error) => {
if error.kind() != ErrorKind::UnexpectedEof {
return Err(error);
}
let entry_point =
SMBiosEntryPoint64::try_scan_from_file(&mut dev_mem, RANGE_START..=RANGE_END)?;
structure_table_address = entry_point.structure_table_address();
structure_table_length = entry_point.structure_table_maximum_size() as usize;
}
}
if structure_table_address < RANGE_START || structure_table_address > RANGE_END {
return Err(Error::new(
ErrorKind::InvalidData,
format!(
"The entry point has given an out of range start address for the table: {}",
structure_table_address
),
));
}
if structure_table_address + structure_table_length as u64 > RANGE_END {
return Err(Error::new(
ErrorKind::InvalidData,
format!(
"The entry point has given a length which exceeds the range: {}",
structure_table_length
),
));
}
if structure_table_length < Header::SIZE + 2 {
return Err(Error::new(
ErrorKind::InvalidData,
format!("The table has an invalid size: {}", structure_table_length),
));
}
dev_mem.seek(SeekFrom::Start(structure_table_address))?;
let mut table = Vec::with_capacity(structure_table_length);
table.resize(structure_table_length, 0);
dev_mem.read_exact(&mut table)?;
Ok(table)
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs::File;
use std::io;
#[test]
fn test_dev_mem_scan() -> io::Result<()> {
const RANGE_START: u64 = 0x000F0000u64;
const RANGE_END: u64 = 0x000FFFFFu64;
let mut dev_mem = File::open(DEV_MEM_FILE)?;
let structure_table_address: u64;
let structure_table_length: u32;
match SMBiosEntryPoint32::try_scan_from_file(&mut dev_mem, RANGE_START..=RANGE_END) {
Ok(entry_point) => {
structure_table_address = entry_point.structure_table_address() as u64;
structure_table_length = entry_point.structure_table_length() as u32;
println!(
"SMBIOS {}.{} present.",
entry_point.major_version(),
entry_point.minor_version()
);
println!(
"{} structures occupying {} bytes.",
entry_point.number_of_smbios_structures(),
entry_point.structure_table_length()
);
println!("Table at: {:#010X}.", entry_point.structure_table_address());
}
Err(error) => {
if error.kind() != ErrorKind::UnexpectedEof {
return Err(error);
}
let entry_point =
SMBiosEntryPoint64::try_scan_from_file(&mut dev_mem, RANGE_START..=RANGE_END)?;
structure_table_address = entry_point.structure_table_address();
structure_table_length = entry_point.structure_table_maximum_size();
println!(
"SMBIOS {}.{}.{} present.",
entry_point.major_version(),
entry_point.minor_version(),
entry_point.docrev()
);
println!(
"Occupying {} bytes maximum.",
entry_point.structure_table_maximum_size()
);
println!("Table at: {:#010X}.", entry_point.structure_table_address());
}
}
if structure_table_address < RANGE_START || structure_table_address > RANGE_END {
return Err(Error::new(
ErrorKind::InvalidData,
format!(
"The entry point has given an out of range start address for the table: {}",
structure_table_address
),
));
}
if structure_table_address + structure_table_length as u64 > RANGE_END {
return Err(Error::new(
ErrorKind::InvalidData,
format!(
"The entry point has given a length which exceeds the range: {}",
structure_table_length
),
));
}
let table = UndefinedStructTable::try_load_from_file_offset(
&mut dev_mem,
structure_table_address,
structure_table_length as usize,
)?;
println!("{:#X?}", table);
Ok(())
}
}