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::io;
213
214 #[test]
215 #[cfg(any(target_os = "linux"))]
216 fn test_dev_mem_scan() -> io::Result<()> {
217 let entry_path = std::path::Path::new(SYS_ENTRY_FILE);
218
219 match SMBiosEntryPoint64::try_load_from_file(entry_path) {
220 Ok(entry_point) => {
221 println!(
222 "SMBIOS {}.{}.{} present.",
223 entry_point.major_version(),
224 entry_point.minor_version(),
225 entry_point.docrev()
226 );
227 println!(
228 "Occupying {} bytes maximum.",
229 entry_point.structure_table_maximum_size()
230 );
231 println!("Table at: {:#018X}.", entry_point.structure_table_address());
232 }
233 Err(err) => match err.kind() {
234 ErrorKind::InvalidData => {
235 let entry_point = SMBiosEntryPoint32::try_load_from_file(entry_path)?;
236 println!(
237 "SMBIOS {}.{} present.",
238 entry_point.major_version(),
239 entry_point.minor_version()
240 );
241 println!(
242 "{} structures occupying {} bytes.",
243 entry_point.number_of_smbios_structures(),
244 entry_point.structure_table_length()
245 );
246 println!("Table at: {:#010X}.", entry_point.structure_table_address());
247 }
248 _ => return Err(err),
249 },
250 }
251
252 let data = SMBiosData::try_load_from_file(SYS_TABLE_FILE, None)?;
253 println!("{:#X?}", data);
254
255 Ok(())
256 }
257
258 #[test]
259 #[cfg(any(target_os = "freebsd"))]
260 fn test_dev_mem_scan() -> io::Result<()> {
261 use std::fs::File;
262
263 const RANGE_START: u64 = 0x000F0000u64;
264 const RANGE_END: u64 = 0x000FFFFFu64;
265 let mut dev_mem = File::open(DEV_MEM_FILE)?;
266 let structure_table_address: u64;
267 let structure_table_length: u32;
268
269 match SMBiosEntryPoint32::try_scan_from_file(&mut dev_mem, RANGE_START..=RANGE_END) {
270 Ok(entry_point) => {
271 structure_table_address = entry_point.structure_table_address() as u64;
272 structure_table_length = entry_point.structure_table_length() as u32;
273 println!(
274 "SMBIOS {}.{} present.",
275 entry_point.major_version(),
276 entry_point.minor_version()
277 );
278 println!(
279 "{} structures occupying {} bytes.",
280 entry_point.number_of_smbios_structures(),
281 entry_point.structure_table_length()
282 );
283 println!("Table at: {:#010X}.", entry_point.structure_table_address());
284 }
285 Err(error) => {
286 if error.kind() != ErrorKind::UnexpectedEof {
287 return Err(error);
288 }
289
290 let entry_point =
291 SMBiosEntryPoint64::try_scan_from_file(&mut dev_mem, RANGE_START..=RANGE_END)?;
292
293 structure_table_address = entry_point.structure_table_address();
294 structure_table_length = entry_point.structure_table_maximum_size();
295
296 println!(
297 "SMBIOS {}.{}.{} present.",
298 entry_point.major_version(),
299 entry_point.minor_version(),
300 entry_point.docrev()
301 );
302 println!(
303 "Occupying {} bytes maximum.",
304 entry_point.structure_table_maximum_size()
305 );
306 println!("Table at: {:#010X}.", entry_point.structure_table_address());
307 }
308 }
309
310 if structure_table_address + structure_table_length as u64 > RANGE_END {
311 return Err(Error::new(
312 ErrorKind::InvalidData,
313 format!(
314 "The entry point has given a length which exceeds the range: {}",
315 structure_table_length
316 ),
317 ));
318 }
319
320 let table = UndefinedStructTable::try_load_from_file_offset(
321 &mut dev_mem,
322 structure_table_address,
323 structure_table_length as usize,
324 )?;
325 println!("{:#X?}", table);
326
327 Ok(())
328 }
329}