use std::fs;
use std::fs::{File, OpenOptions};
use std::io::prelude::*;
use std::io::{BufReader, BufWriter};
use std::str::FromStr;
use super::LinuxSystemManager;
use crate::efi::{Variable, VariableFlags};
use crate::{Error, VarEnumerator, VarManager, VarReader, VarWriter};
pub const EFIVARS_ROOT: &str = "/sys/firmware/efi/vars";
pub struct SystemManager;
impl SystemManager {
pub fn new() -> SystemManager {
SystemManager {}
}
}
impl LinuxSystemManager for SystemManager {
#[cfg(test)]
fn supported(&self) -> bool {
fs::metadata(EFIVARS_ROOT).is_ok()
}
}
impl VarEnumerator for SystemManager {
fn get_all_vars<'a>(&'a self) -> crate::Result<Box<dyn Iterator<Item = Variable> + 'a>> {
fs::read_dir(EFIVARS_ROOT)
.map(|list| {
list.filter_map(Result::ok)
.filter(|entry| match entry.file_type() {
Ok(file_type) => file_type.is_dir(),
_ => false,
})
.filter_map(|entry| {
entry
.file_name()
.into_string()
.map_err(|_str| Error::InvalidUTF8)
.and_then(|s| Variable::from_str(&s))
.ok()
})
})
.map(|it| -> Box<dyn Iterator<Item = Variable>> { Box::new(it) })
.map_err(Error::UnknownIoError) }
}
impl VarReader for SystemManager {
fn read(&self, var: &Variable) -> crate::Result<(Vec<u8>, VariableFlags)> {
let attributes_filename = format!("{EFIVARS_ROOT}/{var}/attributes");
let f = File::open(attributes_filename).map_err(|error| Error::for_variable(error, var))?;
let reader = BufReader::new(&f);
let mut flags = VariableFlags::empty();
for line in reader.lines() {
let line = line.map_err(|error| Error::for_variable(error, var))?;
let parsed = VariableFlags::from_str(&line)?;
flags |= parsed;
}
let filename = format!("{EFIVARS_ROOT}/{var}/data");
let mut f = File::open(filename).map_err(|error| Error::for_variable(error, var))?;
let mut value: Vec<u8> = vec![];
f.read_to_end(&mut value)
.map_err(|error| Error::for_variable(error, var))?;
log::debug!(
"Read variable {var} with attributes {flags:?} (value length: {})",
value.len()
);
Ok((value, flags))
}
}
impl VarWriter for SystemManager {
fn write(
&mut self,
var: &Variable,
attributes: VariableFlags,
value: &[u8],
) -> crate::Result<()> {
let attributes_filename = format!("{EFIVARS_ROOT}/{var}/attributes");
let mut f =
File::open(attributes_filename).map_err(|error| Error::for_variable(error, var))?;
let mut writer = BufWriter::new(&mut f);
writer
.write_all(attributes.to_string().as_bytes())
.map_err(|error| Error::for_variable(error, var))?;
let filename = format!("{EFIVARS_ROOT}/{var}/data");
let mut f = OpenOptions::new()
.write(true)
.truncate(true)
.open(filename)
.map_err(|error| Error::for_variable(error, var))?;
f.write(value)
.map_err(|error| Error::for_variable(error, var))?;
log::debug!(
"Wrote variable {var} with attributes {attributes:?} (value length: {})",
value.len()
);
Ok(())
}
fn delete(&mut self, _var: &Variable) -> crate::Result<()> {
unimplemented!("Variable deletion not supported on efivars sysfs. See https://github.com/iTrooz/efivar-rs/issues/55");
}
}
impl VarManager for SystemManager {}