virtfw-varstore 0.3.1

efi variable store
Documentation
///
/// test utility: dump pcap files
///
use std::process::ExitCode;
use uguid::Guid;

use log::{error, info};

use virtfw_libefi::guids;
use virtfw_varstore::json::JsonEfiVarStore;
use virtfw_varstore::mm::core::MmCore;
use virtfw_varstore::mm::util;
use virtfw_varstore::mm::variable::{MmVariableHeader, MmVariableRequest};
use virtfw_varstore::pcap::parse::{VarstorePcapItem, VarstorePcapParser};
use virtfw_varstore::pcap::replay::replay_pcap;
use virtfw_varstore::store::EfiVarStore;

fn print_request(data: &[u8]) {
    let core = MmCore::new(data).unwrap();
    let guid = Guid::from_bytes(core.guid);
    match guid {
        guids::EfiSmmVariableProtocol => {
            let var_res = MmVariableRequest::new(core.data);
            if let Err(e) = var_res.as_ref() {
                error!("variable/req/parse: {e}");
                return;
            }
            let parsed = var_res.unwrap().parsed;
            if parsed.is_none() {
                error!("variable/req/parse: error");
                return;
            }
            println!("variable/req: {}", parsed.unwrap());
        }
        _ => {
            println!("core/req: {}", core);
        }
    }
}

fn print_reply(data: &[u8]) {
    let core = MmCore::new(data).unwrap();
    let guid = Guid::from_bytes(core.guid);
    match guid {
        guids::EfiSmmVariableProtocol => {
            let hdr_res = MmVariableHeader::new(core.data);
            if let Err(e) = hdr_res.as_ref() {
                error!("{e}");
            };
            let status = util::u64_to_status(hdr_res.unwrap().0.status);
            println!("variable/rsp: {}", status);
        }
        _ => {
            println!("core/rsp: {}", core);
        }
    }
}

fn print_pcap(filename: &str) -> std::io::Result<()> {
    let parser = VarstorePcapParser::new_file(filename)?;

    for p in parser {
        match p {
            VarstorePcapItem::Request(d) => {
                print_request(&d);
            }
            VarstorePcapItem::Reply(d) => {
                print_reply(&d);
            }
            _ => {
                println!("{}", p);
            }
        }
    }
    Ok(())
}

fn parse_args() -> Option<getopts::Matches> {
    let args: Vec<String> = std::env::args().collect();
    let mut opts = getopts::Options::new();
    opts.optflag("h", "help", "print this help text");
    opts.optflag("d", "debug", "turn on debug logging");
    opts.optflag("p", "print", "print pcap file");
    opts.optflag("", "replay", "replay pcap file");
    opts.optopt("", "pcap", "pcap file (print or replay)", "PCAP");
    opts.optopt("", "json", "json file (initial replay state)", "JSON");

    let cfg_res = opts.parse(&args[1..]);
    let Ok(cfg) = cfg_res else {
        println!("{:?}", cfg_res.err());
        return None;
    };
    if cfg.opt_present("help") {
        print!("{}", opts.usage("dump varstore pcap files"));
        return None;
    };

    Some(cfg)
}

fn loginit(cfg: &getopts::Matches) {
    let loglevel = if cfg.opt_present("debug") {
        stderrlog::LogLevelNum::Debug
    } else {
        stderrlog::LogLevelNum::Info
    };
    stderrlog::new()
        .module(module_path!())
        .module("virtfw_libefi")
        .module("virtfw_varstore")
        .verbosity(loglevel)
        .init()
        .unwrap();
}

fn main() -> ExitCode {
    let Some(cfg) = parse_args() else {
        return ExitCode::from(1);
    };
    loginit(&cfg);

    if let Some(pcap) = cfg.opt_str("pcap") {
        if cfg.opt_present("print") {
            let res = print_pcap(&pcap);
            if let Err(e) = res {
                error!("{e}");
            } else {
                info!("ok");
            }
        }

        if cfg.opt_present("replay") {
            let mut store = EfiVarStore::new();

            if let Some(filename) = cfg.opt_str("json") {
                let Ok(content) = std::fs::read_to_string(filename) else {
                    error!("read json file");
                    return ExitCode::from(1);
                };
                let Ok(jstore) = serde_json::from_str::<JsonEfiVarStore>(&content) else {
                    error!("parse json file");
                    return ExitCode::from(1);
                };
                store.json_import(&jstore);
            }

            let parser = VarstorePcapParser::new_file(&pcap).expect("open pcap file");
            replay_pcap(parser, &mut store);
        }
    }

    ExitCode::from(0)
}