smbioslib/unix/
platform.rs1use crate::*;
2use std::{io::Error, io::ErrorKind};
3
4#[cfg(any(target_os = "linux"))]
5pub const SYS_ENTRY_FILE: &'static str = "/sys/firmware/dmi/tables/smbios_entry_point";
7
8#[cfg(any(target_os = "linux"))]
9pub const SYS_TABLE_FILE: &'static str = "/sys/firmware/dmi/tables/DMI";
11
12pub const DEV_MEM_FILE: &'static str = "/dev/mem";
14
15#[cfg(any(target_os = "linux"))]
48pub fn table_load_from_device() -> Result<SMBiosData, Error> {
50 let version: SMBiosVersion;
51 let entry_path = std::path::Path::new(SYS_ENTRY_FILE);
52
53 match SMBiosEntryPoint64::try_load_from_file(entry_path) {
54 Ok(entry_point) => {
55 version = SMBiosVersion {
56 major: entry_point.major_version(),
57 minor: entry_point.minor_version(),
58 revision: entry_point.docrev(),
59 }
60 }
61 Err(err) => match err.kind() {
62 ErrorKind::InvalidData => match SMBiosEntryPoint32::try_load_from_file(entry_path) {
63 Ok(entry_point) => {
64 version = SMBiosVersion {
65 major: entry_point.major_version(),
66 minor: entry_point.minor_version(),
67 revision: 0,
68 }
69 }
70 Err(err) => return Err(err),
71 },
72 _ => return Err(err),
73 },
74 }
75
76 SMBiosData::try_load_from_file(SYS_TABLE_FILE, Some(version))
77}
78
79#[cfg(any(target_os = "freebsd"))]
80pub fn table_load_from_device() -> Result<SMBiosData, Error> {
82 const RANGE_START: u64 = 0x000F0000u64;
83 const RANGE_END: u64 = 0x000FFFFFu64;
84 let structure_table_address: u64;
85 let structure_table_length: u32;
86 let version: SMBiosVersion;
87
88 let mut dev_mem = std::fs::File::open(DEV_MEM_FILE)?;
89
90 match SMBiosEntryPoint32::try_scan_from_file(&mut dev_mem, RANGE_START..=RANGE_END) {
91 Ok(entry_point) => {
92 structure_table_address = entry_point.structure_table_address() as u64;
93 structure_table_length = entry_point.structure_table_length() as u32;
94
95 version = SMBiosVersion {
96 major: entry_point.major_version(),
97 minor: entry_point.minor_version(),
98 revision: 0,
99 }
100 }
101 Err(error) => {
102 if error.kind() != ErrorKind::UnexpectedEof {
103 return Err(error);
104 }
105
106 let entry_point =
107 SMBiosEntryPoint64::try_scan_from_file(&mut dev_mem, RANGE_START..=RANGE_END)?;
108
109 structure_table_address = entry_point.structure_table_address();
110 structure_table_length = entry_point.structure_table_maximum_size();
111
112 version = SMBiosVersion {
113 major: entry_point.major_version(),
114 minor: entry_point.minor_version(),
115 revision: entry_point.docrev(),
116 }
117 }
118 }
119
120 if structure_table_address + structure_table_length as u64 > RANGE_END {
121 return Err(Error::new(
122 ErrorKind::InvalidData,
123 format!(
124 "The entry point has given a length which exceeds the range: {}",
125 structure_table_length
126 ),
127 ));
128 }
129
130 let table = UndefinedStructTable::try_load_from_file_offset(
131 &mut dev_mem,
132 structure_table_address,
133 structure_table_length as usize,
134 )?;
135
136 Ok(SMBiosData::new(table, Some(version)))
137}
138
139#[cfg(any(target_os = "linux"))]
140pub fn raw_smbios_from_device() -> Result<Vec<u8>, Error> {
142 Ok(std::fs::read(SYS_TABLE_FILE)?)
143}
144
145#[cfg(any(target_os = "freebsd"))]
146pub fn raw_smbios_from_device() -> Result<Vec<u8>, Error> {
148 use std::io::{prelude::*, SeekFrom};
149 const RANGE_START: u64 = 0x000F0000u64;
150 const RANGE_END: u64 = 0x000FFFFFu64;
151 let structure_table_address: u64;
152 let structure_table_length: usize;
153
154 let mut dev_mem = std::fs::File::open(DEV_MEM_FILE)?;
155
156 match SMBiosEntryPoint32::try_scan_from_file(&mut dev_mem, RANGE_START..=RANGE_END) {
157 Ok(entry_point) => {
158 structure_table_address = entry_point.structure_table_address() as u64;
159 structure_table_length = entry_point.structure_table_length() as usize;
160 }
161 Err(error) => {
162 if error.kind() != ErrorKind::UnexpectedEof {
163 return Err(error);
164 }
165
166 let entry_point =
167 SMBiosEntryPoint64::try_scan_from_file(&mut dev_mem, RANGE_START..=RANGE_END)?;
168
169 structure_table_address = entry_point.structure_table_address();
170 structure_table_length = entry_point.structure_table_maximum_size() as usize;
171 }
172 }
173
174 if structure_table_address < RANGE_START || structure_table_address > RANGE_END {
175 return Err(Error::new(
176 ErrorKind::InvalidData,
177 format!(
178 "The entry point has given an out of range start address for the table: {}",
179 structure_table_address
180 ),
181 ));
182 }
183
184 if structure_table_address + structure_table_length as u64 > RANGE_END {
185 return Err(Error::new(
186 ErrorKind::InvalidData,
187 format!(
188 "The entry point has given a length which exceeds the range: {}",
189 structure_table_length
190 ),
191 ));
192 }
193
194 if structure_table_length < Header::SIZE + 2 {
195 return Err(Error::new(
196 ErrorKind::InvalidData,
197 format!("The table has an invalid size: {}", structure_table_length),
198 ));
199 }
200
201 dev_mem.seek(SeekFrom::Start(structure_table_address))?;
202 let mut table = Vec::with_capacity(structure_table_length);
203 table.resize(structure_table_length, 0);
204 dev_mem.read_exact(&mut table)?;
205
206 Ok(table)
207}
208
209#[cfg(test)]
210mod tests {
211 use super::*;
212 use std::fs::File;
213 use std::io;
214
215 #[test]
216 fn test_dev_mem_scan() -> io::Result<()> {
217 const RANGE_START: u64 = 0x000F0000u64;
218 const RANGE_END: u64 = 0x000FFFFFu64;
219 let mut dev_mem = File::open(DEV_MEM_FILE)?;
220 let structure_table_address: u64;
221 let structure_table_length: u32;
222
223 match SMBiosEntryPoint32::try_scan_from_file(&mut dev_mem, RANGE_START..=RANGE_END) {
224 Ok(entry_point) => {
225 structure_table_address = entry_point.structure_table_address() as u64;
226 structure_table_length = entry_point.structure_table_length() as u32;
227 println!(
228 "SMBIOS {}.{} present.",
229 entry_point.major_version(),
230 entry_point.minor_version()
231 );
232 println!(
233 "{} structures occupying {} bytes.",
234 entry_point.number_of_smbios_structures(),
235 entry_point.structure_table_length()
236 );
237 println!("Table at: {:#010X}.", entry_point.structure_table_address());
238 }
239 Err(error) => {
240 if error.kind() != ErrorKind::UnexpectedEof {
241 return Err(error);
242 }
243
244 let entry_point =
245 SMBiosEntryPoint64::try_scan_from_file(&mut dev_mem, RANGE_START..=RANGE_END)?;
246
247 structure_table_address = entry_point.structure_table_address();
248 structure_table_length = entry_point.structure_table_maximum_size();
249
250 println!(
251 "SMBIOS {}.{}.{} present.",
252 entry_point.major_version(),
253 entry_point.minor_version(),
254 entry_point.docrev()
255 );
256 println!(
257 "Occupying {} bytes maximum.",
258 entry_point.structure_table_maximum_size()
259 );
260 println!("Table at: {:#010X}.", entry_point.structure_table_address());
261 }
262 }
263
264 if structure_table_address + structure_table_length as u64 > RANGE_END {
265 return Err(Error::new(
266 ErrorKind::InvalidData,
267 format!(
268 "The entry point has given a length which exceeds the range: {}",
269 structure_table_length
270 ),
271 ));
272 }
273
274 let table = UndefinedStructTable::try_load_from_file_offset(
275 &mut dev_mem,
276 structure_table_address,
277 structure_table_length as usize,
278 )?;
279 println!("{:#X?}", table);
280
281 Ok(())
282 }
283}