use clap::Parser;
use std::path::PathBuf;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::time::Duration;
use uefi_run::*;
fn main() {
let args = Args::parse();
let terminating = Arc::new(AtomicBool::new(false));
{
let term = terminating.clone();
ctrlc::set_handler(move || {
println!("uefi-run terminating...");
term.store(true, Ordering::SeqCst);
})
.expect("Error setting termination handler");
}
let temp_dir = tempfile::tempdir().expect("Unable to create temporary directory");
let temp_dir_path = PathBuf::from(temp_dir.path());
let image_file_path = {
let mut path_buf = temp_dir_path;
path_buf.push("image.fat");
path_buf
};
{
let mut image =
EfiImage::new(&image_file_path, args.size * 0x10_0000).expect("Failed to create image");
if args.boot {
image.copy_host_file(&args.efi_exe, "EFI/Boot/BootX64.efi")
} else {
image
.copy_host_file(&args.efi_exe, "run.efi")
.and_then(|_| image.set_file_contents("startup.nsh", DEFAULT_STARTUP_NSH))
}
.expect("Failed to copy EFI executable");
for (outer, inner) in args.parse_add_file_args().map(|x| x.unwrap()) {
image
.copy_host_file(outer, inner)
.expect("Failed to copy user-defined file");
}
}
let mut qemu_config = QemuConfig {
qemu_path: args.qemu_path,
bios_path: args.bios_path,
drives: vec![QemuDriveConfig {
file: image_file_path.to_str().unwrap().to_string(),
media: "disk".to_string(),
format: "raw".to_string(),
}],
..Default::default()
};
qemu_config
.additional_args
.extend(args.qemu_args.iter().cloned());
let mut qemu_process = qemu_config.run().expect("Failed to start qemu");
let mut qemu_exit_code;
loop {
qemu_exit_code = qemu_process.wait(Duration::from_millis(500));
if qemu_exit_code.is_some() || terminating.load(Ordering::SeqCst) {
break;
}
}
if qemu_exit_code.is_none() {
qemu_exit_code = qemu_process.wait(Duration::from_secs(1));
}
if qemu_exit_code.is_none() {
qemu_process
.kill()
.or_else(|e| match e.kind() {
std::io::ErrorKind::InvalidInput => Ok(()),
_ => Err(e),
})
.expect("Unable to kill qemu process");
qemu_exit_code = qemu_process.wait(Duration::from_secs(1));
}
let exit_code = qemu_exit_code.expect("qemu should have exited by now but did not");
std::process::exit(exit_code);
}