104 lines
3.7 KiB
Rust
104 lines
3.7 KiB
Rust
#![allow(clippy::redundant_else)]
|
|
|
|
use clap::Parser;
|
|
use eyre::WrapErr;
|
|
use std::io::Write;
|
|
|
|
mod cli;
|
|
mod vm;
|
|
|
|
use vm::{SpawnArguments, VirtualMachine};
|
|
|
|
fn main() -> eyre::Result<()> {
|
|
color_eyre::install()?;
|
|
|
|
let mut args = std::env::args().collect::<Vec<_>>();
|
|
let ignore_opts = String::from("--");
|
|
if let Some(run_pos) = args.iter().position(|e| e == "run") {
|
|
if !args.contains(&ignore_opts) && args.get(run_pos + 1).is_some_and(|arg| arg != "--help")
|
|
{
|
|
args.insert(run_pos + 1, ignore_opts);
|
|
}
|
|
}
|
|
let opts = cli::App::parse_from(args);
|
|
|
|
match opts.subcommand {
|
|
cli::Commands::Start { memory } => {
|
|
let spawn_args = SpawnArguments {
|
|
memory: memory.clone(),
|
|
..Default::default()
|
|
};
|
|
let vm = VirtualMachine::start(spawn_args)?;
|
|
let pid = vm.pid();
|
|
std::fs::write(&opts.lockfile, pid.to_string()).with_context(|| {
|
|
format!(
|
|
"could not write PID {pid} to {lockfile}",
|
|
lockfile = opts.lockfile.display(),
|
|
)
|
|
})?;
|
|
}
|
|
cli::Commands::Stop => {
|
|
let spawn_arguments = SpawnArguments::default();
|
|
let vm = VirtualMachine::load(spawn_arguments, None)?;
|
|
vm.kill()?;
|
|
}
|
|
cli::Commands::Shell => {
|
|
todo!("custom args to starting a VM and piping stdin/stdout are not yet implemented");
|
|
}
|
|
cli::Commands::Status => {
|
|
let spawn_arguments = SpawnArguments::default();
|
|
let mut vm = VirtualMachine::load(spawn_arguments, None)?;
|
|
let result = vm.execute("guest-get-host-name", serde_json::json!({}))?;
|
|
let hostname = result
|
|
.get("host-name")
|
|
.ok_or(eyre::eyre!("no hostname"))?
|
|
.as_str()
|
|
.ok_or(eyre::eyre!("hostname is not str"))?;
|
|
let uptime = vm.run_command("uptime", [])?;
|
|
eprintln!("hostname: {hostname}");
|
|
eprint!("{}", String::from_utf8_lossy(&uptime.0));
|
|
}
|
|
cli::Commands::Attach { device } => {
|
|
let spawn_arguments = SpawnArguments::default();
|
|
let mut vm = VirtualMachine::load(spawn_arguments, None)?;
|
|
vm.execute_host("qmp_capabilities", serde_json::json!({}))?;
|
|
vm.execute_host(
|
|
"device_add",
|
|
serde_json::json!({
|
|
"driver": "usb-host",
|
|
"bus": "usb.0",
|
|
"vendorid": device.vendor_id,
|
|
"productid": device.device_id,
|
|
}),
|
|
)?;
|
|
}
|
|
cli::Commands::Push {
|
|
local_path,
|
|
remote_path,
|
|
} => {
|
|
let spawn_arguments = SpawnArguments::default();
|
|
let mut vm = VirtualMachine::load(spawn_arguments, None)?;
|
|
vm.push(local_path, remote_path)?;
|
|
}
|
|
cli::Commands::Pull {
|
|
remote_path,
|
|
local_path,
|
|
} => {
|
|
let spawn_arguments = SpawnArguments::default();
|
|
let mut vm = VirtualMachine::load(spawn_arguments, None)?;
|
|
vm.pull(remote_path, local_path)?;
|
|
}
|
|
cli::Commands::Run { command, args } => {
|
|
let spawn_arguments = SpawnArguments::default();
|
|
let mut vm = VirtualMachine::load(spawn_arguments, None)?;
|
|
let (response, exit_code) = vm.run_command(&command, args)?;
|
|
std::io::stdout().write_all(&response)?;
|
|
std::process::exit(
|
|
i32::try_from(exit_code).context(eyre::eyre!("bad PID: pid < i32::MAX << 1"))?,
|
|
);
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|