chore(code): move load options parsing to crates/eficore

This commit is contained in:
2025-11-03 23:45:35 -05:00
parent 532fb38d5a
commit 503a9cba0a
7 changed files with 22 additions and 23 deletions

View File

@@ -3,9 +3,6 @@ use alloc::collections::BTreeMap;
use alloc::string::{String, ToString};
use anyhow::{Context, Result, bail};
/// Acquire arguments from UEFI environment.
pub mod env;
/// The Sprout options parser.
pub mod parser;

View File

@@ -1,77 +0,0 @@
use alloc::string::{String, ToString};
use alloc::vec::Vec;
use anyhow::{Context, Result, bail};
use uefi::proto::loaded_image::{LoadOptionsError, LoadedImage};
/// Loads the command-line arguments passed to Sprout.
pub fn args() -> Result<Vec<String>> {
// Acquire the image handle of Sprout.
let handle = uefi::boot::image_handle();
// Open the LoadedImage protocol for Sprout.
let loaded_image = uefi::boot::open_protocol_exclusive::<LoadedImage>(handle)
.context("unable to open loaded image protocol for sprout")?;
// Load the command-line argument string.
let options = match loaded_image.load_options_as_cstr16() {
// Load options were passed. We will return them for processing.
Ok(options) => options,
// No load options were passed. We will return an empty vector.
Err(LoadOptionsError::NotSet) => {
return Ok(Vec::new());
}
Err(LoadOptionsError::NotAligned) => {
bail!("load options are not properly aligned");
}
Err(LoadOptionsError::InvalidString(error)) => {
bail!("load options are not a valid string: {}", error);
}
};
// Convert the options to a string.
let options = options.to_string();
// Use shlex to parse the options.
// If shlex fails, we will fall back to a simple whitespace split.
let mut args = shlex::split(&options).unwrap_or_else(|| {
options
.split_ascii_whitespace()
.map(|string| string.to_string())
.collect::<Vec<_>>()
});
// If there is a first argument, check if it is not an option.
// If it is not, we will assume it is the path to the executable and remove it.
if let Some(arg) = args.first()
&& !arg.starts_with('-')
{
args.remove(0);
}
// Correct firmware that may add invalid arguments at the start.
// Witnessed this on a Dell Precision 5690 when direct booting.
loop {
// Grab the first argument or break.
let Some(arg) = args.first() else {
break;
};
// Check if the argument is a valid character.
// If it is not, remove it and continue.
let Some(first_character) = arg.chars().next() else {
break;
};
// If the character is not a printable character or a backtick, remove it and continue.
if first_character < 0x1f as char || first_character == '`' {
args.remove(0);
continue;
}
break;
}
Ok(args)
}

View File

@@ -1,8 +1,8 @@
use crate::options::env;
use alloc::collections::BTreeMap;
use alloc::string::{String, ToString};
use anyhow::{Context, Result, bail};
use core::ptr::null_mut;
use eficore::env;
use log::info;
use uefi_raw::Status;
@@ -18,7 +18,7 @@ pub enum OptionForm {
Help,
}
/// The description of an option, used in the options parser
/// The description of an option, used in the option parser
/// to make decisions about how to progress.
#[derive(Debug, Clone)]
pub struct OptionDescription<'a> {
@@ -35,8 +35,8 @@ pub trait OptionsRepresentable {
type Output;
/// The configured options for this type. This should describe all the options
/// that are valid to produce the type. The left hand side is the name of the option,
/// and the right hand side is the description.
/// that are valid to produce the type. The left-hand side is the name of the option,
/// and the right-hand side is the description.
fn options() -> &'static [(&'static str, OptionDescription<'static>)];
/// Produces the type by taking the `options` and processing it into the output.
@@ -44,7 +44,7 @@ pub trait OptionsRepresentable {
/// For minimalism, we don't want a full argument parser. Instead, we use
/// a simple --xyz = xyz: None and --abc 123 = abc: Some("123") format.
/// We also support --abc=123 = abc: Some("123") format.
/// We also support the format: --abc=123
fn parse_raw() -> Result<BTreeMap<String, Option<String>>> {
// Access the configured options for this type.
let configured: BTreeMap<_, _> = BTreeMap::from_iter(Self::options().to_vec());