use alloc::string::String;
use alloc::vec::Vec;
use core::{slice, str};
use ahash::RandomState;
use hashbrown::hash_map::Iter;
use hashbrown::HashMap;
use hermit_entry::boot_info::PlatformInfo;
use hermit_sync::OnceCell;
pub use crate::arch::kernel::{
get_base_address, get_cmdline, get_cmdsize, get_image_size, get_ram_address, get_tls_align,
get_tls_filesz, get_tls_memsz, get_tls_start,
};
use crate::kernel::boot_info;
static CLI: OnceCell<Cli> = OnceCell::new();
pub fn init() {
CLI.set(Cli::default()).unwrap();
}
#[derive(Debug)]
struct Cli {
#[allow(dead_code)]
image_path: Option<String>,
freq: Option<u16>,
env_vars: HashMap<String, String, RandomState>,
args: Vec<String>,
}
pub fn is_uhyve() -> bool {
matches!(boot_info().platform_info, PlatformInfo::Uhyve { .. })
}
fn get_cmdline_str() -> &'static str {
let cmdsize = get_cmdsize();
let cmdline = get_cmdline().as_ptr::<u8>();
if cmdline.is_null() {
""
} else {
let slice = unsafe { slice::from_raw_parts(cmdline, cmdsize) };
str::from_utf8(slice).unwrap().trim_matches(char::from(0))
}
}
impl Default for Cli {
fn default() -> Self {
let mut image_path = None;
let mut freq = None;
let mut env_vars = HashMap::<String, String, RandomState>::with_hasher(
RandomState::with_seeds(0, 0, 0, 0),
);
let mut args = Vec::new();
let words = shell_words::split(get_cmdline_str()).unwrap();
debug!("cli_words = {words:?}");
let mut words = words.into_iter();
let expect_arg = |arg: Option<String>, name: &str| {
arg.unwrap_or_else(|| {
panic!("The argument '{name}' requires a value but none was supplied")
})
};
while let Some(word) = words.next() {
match word.as_str() {
"-freq" => {
let s = expect_arg(words.next(), word.as_str());
freq = Some(s.parse().unwrap());
}
"-ip" => {
let ip = expect_arg(words.next(), word.as_str());
env_vars.insert(String::from("HERMIT_IP"), ip);
}
"-mask" => {
let mask = expect_arg(words.next(), word.as_str());
env_vars.insert(String::from("HERMIT_MASK"), mask);
}
"-gateway" => {
let gateway = expect_arg(words.next(), word.as_str());
env_vars.insert(String::from("HERMIT_GATEWAY"), gateway);
}
"--" => args.extend(&mut words),
_ if image_path.is_none() => image_path = Some(word),
word => panic!(
"Found argument '{word}' which wasn't expected, or isn't valid in this context
If you tried to supply `{word}` as a value rather than a flag, use `-- {word}`"
),
};
}
Self {
image_path,
freq,
env_vars,
args,
}
}
}
pub fn freq() -> Option<u16> {
CLI.get().unwrap().freq
}
#[allow(dead_code)]
pub fn var(key: &str) -> Option<&String> {
CLI.get().unwrap().env_vars.get(key)
}
pub fn vars() -> Iter<'static, String, String> {
CLI.get().unwrap().env_vars.iter()
}
pub fn args() -> &'static [String] {
CLI.get().unwrap().args.as_slice()
}