Skip to content

Commit e8fbeed

Browse files
committed
Implement efivarfs variable parsing
1 parent bb90970 commit e8fbeed

File tree

10 files changed

+138
-50
lines changed

10 files changed

+138
-50
lines changed

meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ lib_refivar = static_library(
5353
[
5454
'src/lib/efivar/mod.rs',
5555
'src/lib/efivar/efi_guids.rs',
56+
'src/lib/efivar/efi_variable_attributes.rs',
5657
lib_refivar_efi_guids_list_path_rs
5758
],
5859
{

src/bin/efivar.rs

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use crate::efivar::print_mode::{Decimal, Verbose};
2+
use crate::efivar::types::PrintMode;
13
use clap;
24
use efivar;
35
use ignore_result::Ignore;
@@ -118,16 +120,16 @@ fn list_variables(_parser_args: clap::ArgMatches) -> ExitCode {
118120
println!("{}", v);
119121
}
120122
return std::process::ExitCode::from(0);
121-
},
123+
}
122124
Err(_) => {
123-
let mut efivar_variables: efivar::efivar::EfiVariables = Default::default();
125+
let efivar_variables: efivar::efivar::EfiVariables = Default::default();
124126
match efivar_variables.list() {
125127
Ok(variables) => {
126128
for v in variables {
127129
println!("{}", v);
128130
}
129131
return std::process::ExitCode::from(0);
130-
},
132+
}
131133
Err(e) => {
132134
eprintln!("Failed to access EFI variables: {}", e);
133135
return std::process::ExitCode::from(1);
@@ -138,7 +140,40 @@ fn list_variables(_parser_args: clap::ArgMatches) -> ExitCode {
138140
}
139141

140142
fn print_variable(parser_args: clap::ArgMatches, print_mode: efivar::types::PrintMode) -> ExitCode {
141-
return std::process::ExitCode::from(0);
143+
match parser_args.get_one::<String>("name") {
144+
Some(name) => {
145+
let efivar_fs_variables: efivar::efivarfs::EfiVariables = Default::default();
146+
match efivar_fs_variables.get_variable(name) {
147+
Ok(var) => {
148+
match print_mode {
149+
PrintMode::VERBOSE => println!("{}", Verbose(&var)),
150+
PrintMode::DECIMAL => println!("{}", Decimal(&var)),
151+
}
152+
return std::process::ExitCode::from(0);
153+
}
154+
Err(_) => {
155+
let efivar_variables: efivar::efivar::EfiVariables = Default::default();
156+
match efivar_variables.get_variable(name) {
157+
Ok(var) => {
158+
match print_mode {
159+
PrintMode::VERBOSE => println!("{}", Verbose(&var)),
160+
PrintMode::DECIMAL => println!("{}", Decimal(&var)),
161+
}
162+
return std::process::ExitCode::from(0);
163+
}
164+
Err(e) => {
165+
eprintln!("Failed to read variable: {}", e);
166+
return std::process::ExitCode::from(1);
167+
}
168+
}
169+
}
170+
};
171+
}
172+
None => {
173+
eprintln!("No variable name given");
174+
return std::process::ExitCode::from(1);
175+
}
176+
};
142177
}
143178

144179
fn append_attributes(parser_args: clap::ArgMatches) -> ExitCode {
@@ -193,7 +228,11 @@ fn main() -> ExitCode {
193228
} else if matches.get_one::<&str>("export").is_some() {
194229
return export_variable(matches);
195230
} else {
196-
parser.write_help(&mut io::stderr()).ignore();
197-
return std::process::ExitCode::from(1);
231+
if matches.get_one::<String>("name").is_some() {
232+
return print_variable(matches, efivar::types::PrintMode::VERBOSE);
233+
} else {
234+
parser.write_help(&mut io::stderr()).ignore();
235+
return std::process::ExitCode::from(1);
236+
}
198237
}
199238
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
use crate::types::EfiVariableAttribute;
2+
use std::collections::HashSet;
3+
4+
pub static NON_VOLATILE: EfiVariableAttribute = EfiVariableAttribute::init("Non-Volatile", 0x1);
5+
pub static BOOTSERVICE_ACCESS: EfiVariableAttribute =
6+
EfiVariableAttribute::init("Boot Service Access", 0x2);
7+
pub static RUNTIME_ACCESS: EfiVariableAttribute =
8+
EfiVariableAttribute::init("Runtime Service Access", 0x4);
9+
pub static HARDWARE_ERROR_RECORD: EfiVariableAttribute =
10+
EfiVariableAttribute::init("Hardware Error Record", 0x8);
11+
pub static AUTHENTICATED_WRITE_ACCESS: EfiVariableAttribute =
12+
EfiVariableAttribute::init("Authenticated Write Access", 0x10);
13+
pub static TIME_BASED_AUTHENTICATED_WRITE_ACCESS: EfiVariableAttribute =
14+
EfiVariableAttribute::init("Time-Based Authenticated Write Access", 0x20);
15+
pub static APPEND_WRITE: EfiVariableAttribute = EfiVariableAttribute::init("Append Write", 0x40);
16+
pub static ENHANCED_AUTHENTICATED_ACCESS: EfiVariableAttribute =
17+
EfiVariableAttribute::init("Enhanced Authenticated Access", 0x80);
18+
19+
pub static EFI_VARIABLE_ATTRIBUTES: &'static [&EfiVariableAttribute] = &[
20+
&NON_VOLATILE,
21+
&BOOTSERVICE_ACCESS,
22+
&RUNTIME_ACCESS,
23+
&HARDWARE_ERROR_RECORD,
24+
&AUTHENTICATED_WRITE_ACCESS,
25+
&TIME_BASED_AUTHENTICATED_WRITE_ACCESS,
26+
&APPEND_WRITE,
27+
&ENHANCED_AUTHENTICATED_ACCESS,
28+
];
29+
30+
pub fn parse_attributes<'a>(value: u32) -> HashSet<&'a EfiVariableAttribute> {
31+
let mut set: HashSet<&'a EfiVariableAttribute> = HashSet::new();
32+
for attr in EFI_VARIABLE_ATTRIBUTES.iter() {
33+
if u32::from(*attr) & value != 0 {
34+
set.insert(*attr);
35+
}
36+
};
37+
return set;
38+
}

src/lib/efivar/efivar/efi_variables.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::efivarfs;
2+
use crate::types::EfiVariable;
23
use std::io;
34
use std::path::PathBuf;
45

@@ -27,4 +28,8 @@ impl EfiVariables {
2728
e.set_path(self.path.clone());
2829
return e.list();
2930
}
31+
32+
pub fn get_variable(&self, name: &str) -> io::Result<EfiVariable> {
33+
return Err(io::ErrorKind::Other.into());
34+
}
3035
}

src/lib/efivar/efivarfs/efi_variables.rs

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
use crate::types::EfiGuid;
1+
use crate::types::{EfiGuid, EfiVariable};
2+
use crate::efi_variable_attributes::parse_attributes;
23
use std::fs::{self, ReadDir};
3-
use std::path::PathBuf;
44
use std::io;
5+
use std::path::PathBuf;
56

67
const EFIVARFS_PATH: &'static str = "/sys/firmware/efi/efivars";
78

@@ -30,15 +31,14 @@ fn convert_name(name: Option<&str>) -> Result<String, String> {
3031
));
3132
}
3233
let guid_bytes = &n[n.len() - MIN_VAR_FILE_NAME_LEN + 2..n.len()];
33-
let guid: Option<EfiGuid> = match guid_bytes.try_into() {
34-
Ok(g) => Some(g),
35-
Err(_) => None,
34+
match EfiGuid::try_from(guid_bytes) {
35+
Ok(_) => (),
36+
Err(_) => {
37+
return Err(format!(
38+
"file name {n} does not represent an EFI variable name"
39+
))
40+
}
3641
};
37-
if guid.is_none() {
38-
return Err(format!(
39-
"file name {n} does not represent an EFI variable name"
40-
));
41-
}
4242
let suffix = &n[0..n.len() - MIN_VAR_FILE_NAME_LEN + 1];
4343

4444
return Ok(String::new() + guid_bytes + &"-" + suffix);
@@ -100,8 +100,39 @@ impl EfiVariables {
100100
* instead.
101101
*/
102102
return Err(io::ErrorKind::NotFound.into());
103-
},
103+
}
104104
Err(e) => Err(e),
105105
};
106106
}
107+
108+
pub fn get_variable(&self, name: &str) -> io::Result<EfiVariable> {
109+
if name.len() < MIN_VAR_FILE_NAME_LEN
110+
|| name.bytes().nth(MIN_VAR_FILE_NAME_LEN - 2).unwrap() != b'-'
111+
{
112+
return Err(io::ErrorKind::InvalidInput.into());
113+
}
114+
let guid_bytes = &name[0..MIN_VAR_FILE_NAME_LEN - 2];
115+
let guid = match EfiGuid::try_from(guid_bytes) {
116+
Ok(g) => Some(g),
117+
Err(_) => {
118+
return Err(io::ErrorKind::InvalidInput.into());
119+
}
120+
}.unwrap();
121+
let prefix = &name[MIN_VAR_FILE_NAME_LEN - 1..];
122+
let full_path = self.path.join(String::new() + prefix + &"-" + guid_bytes);
123+
let bytes: Vec<u8> = match fs::read(full_path) {
124+
Ok(bytes) => bytes,
125+
Err(e) => return Err(e),
126+
};
127+
if bytes.len() < 4 {
128+
return Err(io::ErrorKind::InvalidData.into());
129+
}
130+
let attrs = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
131+
return Ok(EfiVariable {
132+
name: name[MIN_VAR_FILE_NAME_LEN - 1..].into(),
133+
attributes: parse_attributes(attrs).into(),
134+
data: bytes[4..].to_vec(),
135+
guid,
136+
});
137+
}
107138
}

src/lib/efivar/mod.rs

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,8 @@
11
pub mod efi_guids;
2+
pub mod efi_variable_attributes;
23
pub mod efivar;
34
pub mod efivarfs;
45
pub mod print_mode;
56
pub mod types;
67

78
mod efi_guids_list_path;
8-
9-
pub mod efi_variable_attributes {
10-
use crate::types::EfiVariableAttribute;
11-
12-
pub static NON_VOLATILE: EfiVariableAttribute = EfiVariableAttribute::init("Non-Volatile", 0x1);
13-
14-
pub static BOOTSERVICE_ACCESS: EfiVariableAttribute =
15-
EfiVariableAttribute::init("Boot Service Access", 0x2);
16-
17-
pub static RUNTIME_ACCESS: EfiVariableAttribute =
18-
EfiVariableAttribute::init("Runtime Service Access", 0x4);
19-
20-
pub static HARDWARE_ERROR_RECORD: EfiVariableAttribute =
21-
EfiVariableAttribute::init("Hardware Error Record", 0x8);
22-
23-
pub static AUTHENTICATED_WRITE_ACCESS: EfiVariableAttribute =
24-
EfiVariableAttribute::init("Authenticated Write Access", 0x10);
25-
26-
pub static TIME_BASED_AUTHENTICATED_WRITE_ACCESS: EfiVariableAttribute =
27-
EfiVariableAttribute::init("Time-Based Authenticated Write Access", 0x20);
28-
29-
pub static APPEND_WRITE: EfiVariableAttribute =
30-
EfiVariableAttribute::init("Append Write", 0x40);
31-
32-
pub static ENHANCED_AUTHENTICATED_ACCESS: EfiVariableAttribute =
33-
EfiVariableAttribute::init("Enhanced Authenticated Access", 0x80);
34-
}

src/lib/efivar/print_mode/verbose.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ impl fmt::Display for Verbose<'_> {
2424
for j in i..i + 16 {
2525
match line_iter.next() {
2626
Some(c) => {
27-
if (0x20 < *c) && (*c < 0x7e) {
27+
if (0x1f < *c) && (*c < 0x7f) {
2828
decode[j - i] = u32::from(*c) as u8;
2929
} else {
3030
decode[j - i] = u32::from('.') as u8;
@@ -43,7 +43,7 @@ impl fmt::Display for Verbose<'_> {
4343
}
4444
f.write_str(&format!(" |{}|\n", std::str::from_utf8(&decode).unwrap()))?;
4545
}
46-
f.write_str(&format!("{:08x}\n", self.0.data.len()))?;
46+
f.write_str(&format!("{:08x}", self.0.data.len()))?;
4747
return Ok(());
4848
}
4949
}

src/lib/efivar/types/efi_guid.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::EfiGuidError;
1+
use crate::types::EfiGuidError;
22
use std::cmp::Ordering;
33
use std::convert::TryFrom;
44
use std::fmt;

src/lib/efivar/types/efi_guid_list_entry.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::efi_guid::EfiGuid;
1+
use crate::types::efi_guid::EfiGuid;
22
use std::fmt;
33

44
#[derive(PartialEq)]

src/lib/efivar/types/efi_variable.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
use super::efi_guid::EfiGuid;
2-
use super::efi_variable_attribute::EfiVariableAttribute;
1+
use crate::types::efi_guid::EfiGuid;
2+
use crate::types::efi_variable_attribute::EfiVariableAttribute;
33
use std::collections::HashSet;
44

55
pub struct EfiVariable<'a> {

0 commit comments

Comments
 (0)