efivars: Parse efivar as UTF-16 LE bytes#1633
Conversation
Signed-off-by: Pragyan Poudyal <pragyanpoudyal41999@gmail.com>
There was a problem hiding this comment.
Code Review
This pull request refactors the EFI variable reading logic into a new utility function read_uefi_var. This function correctly parses the variables as UTF-16 LE, which is a great improvement for correctness. The overall change improves code organization and maintainability. I've added a few suggestions to further improve code clarity and adhere to Rust idioms.
| EfiError::SystemNotUEFI => return Ok(Bootloader::Grub), | ||
| EfiError::MissingVar => return Ok(Bootloader::Grub), |
There was a problem hiding this comment.
The match arms for EfiError::SystemNotUEFI and EfiError::MissingVar have the same logic. They can be combined into a single arm using the | operator for conciseness and better readability.
| EfiError::SystemNotUEFI => return Ok(Bootloader::Grub), | |
| EfiError::MissingVar => return Ok(Bootloader::Grub), | |
| EfiError::SystemNotUEFI | EfiError::MissingVar => return Ok(Bootloader::Grub), |
| #[allow(dead_code)] | ||
| InvalidData(&'static str), | ||
| #[allow(dead_code)] | ||
| Io(std::io::Error), |
There was a problem hiding this comment.
The #[allow(dead_code)] attributes on the InvalidData and Io variants of EfiError are unnecessary. The InvalidData variant is used in read_uefi_var, and the Io variant is used via the From<std::io::Error> implementation and the ? operator. Removing these attributes will make the code cleaner and avoid suppressing potential future warnings about genuinely unused code.
| #[allow(dead_code)] | |
| InvalidData(&'static str), | |
| #[allow(dead_code)] | |
| Io(std::io::Error), | |
| InvalidData(&'static str), | |
| Io(std::io::Error), |
| pub fn read_uefi_var(var_name: &str) -> Result<String, EfiError> { | ||
| use crate::install::EFIVARFS; | ||
| use cap_std_ext::cap_std::ambient_authority; | ||
|
|
||
| let efivarfs = match Dir::open_ambient_dir(EFIVARFS, ambient_authority()) { | ||
| Ok(dir) => dir, | ||
| Err(e) if e.kind() == std::io::ErrorKind::NotFound => return Err(EfiError::SystemNotUEFI), | ||
| Err(e) => Err(e)?, | ||
| }; | ||
|
|
||
| match efivarfs.read(var_name) { | ||
| Ok(loader_bytes) => { | ||
| if loader_bytes.len() % 2 != 0 { | ||
| return Err(EfiError::InvalidData( | ||
| "EFI var length is not valid UTF-16 LE", | ||
| )); | ||
| } | ||
|
|
||
| // EFI vars are UTF-16 LE | ||
| let loader_u16_bytes: Vec<u16> = loader_bytes | ||
| .chunks_exact(2) | ||
| .map(|x| u16::from_le_bytes([x[0], x[1]])) | ||
| .collect(); | ||
|
|
||
| let loader = String::from_utf16(&loader_u16_bytes) | ||
| .map_err(|_| EfiError::InvalidData("EFI var is not UTF-16"))?; | ||
|
|
||
| return Ok(loader); | ||
| } | ||
|
|
||
| Err(e) if e.kind() == std::io::ErrorKind::NotFound => { | ||
| return Err(EfiError::MissingVar); | ||
| } | ||
|
|
||
| Err(e) => Err(e)?, | ||
| } | ||
| } |
There was a problem hiding this comment.
The read_uefi_var function can be refactored to be more idiomatic and readable by using the ? operator for error handling and avoiding multiple match statements with early returns. This improves maintainability.
pub fn read_uefi_var(var_name: &str) -> Result<String, EfiError> {
use crate::install::EFIVARFS;
use cap_std_ext::cap_std::ambient_authority;
let efivarfs = Dir::open_ambient_dir(EFIVARFS, ambient_authority()).map_err(|e| {
if e.kind() == std::io::ErrorKind::NotFound {
EfiError::SystemNotUEFI
} else {
e.into()
}
})?;
let loader_bytes = efivarfs.read(var_name).map_err(|e| {
if e.kind() == std::io::ErrorKind::NotFound {
EfiError::MissingVar
} else {
e.into()
}
})?;
if loader_bytes.len() % 2 != 0 {
return Err(EfiError::InvalidData(
"EFI var length is not valid UTF-16 LE",
));
}
// EFI vars are UTF-16 LE
let loader_u16_bytes: Vec<u16> = loader_bytes
.chunks_exact(2)
.map(|x| u16::from_le_bytes([x[0], x[1]]))
.collect();
String::from_utf16(&loader_u16_bytes)
.map_err(|_| EfiError::InvalidData("EFI var is not UTF-16"))
}| return Ok(loader); | ||
| } | ||
|
|
||
| Err(e) if e.kind() == std::io::ErrorKind::NotFound => { |
There was a problem hiding this comment.
I did coreos/cap-std-ext#78 motivated by this btw
No description provided.