use crate::error::Error;
use crate::session::{Session, SessionEnd};
use crate::terminal::{enter_raw_mode, install_signal_handlers, restore_terminal};
use crate::Config;
#[derive(Debug, Clone, Copy)]
pub struct RunOutput {
pub exit_code: i32,
}
pub fn run(config: &Config) -> Result<RunOutput, Error> {
if let Some(p) = &config.build_snapshot {
crate::vz::snapshot::build(config, p)?;
return Ok(RunOutput { exit_code: 0 });
}
if let Some(p) = &config.resume_snapshot {
let code = crate::vz::snapshot::resume(config, p)?;
return Ok(RunOutput { exit_code: code });
}
install_signal_handlers();
enter_raw_mode();
let session = match Session::start(config) {
Ok(s) => s,
Err(e) => {
restore_terminal();
return Err(e);
}
};
if !config.quiet {
eprint_banner(config, session.cmdline(), session.vsock_port());
}
let end = session.wait();
restore_terminal();
match end {
SessionEnd::Exited(code) => {
if !config.quiet {
eprintln!("\r\n[vmette] guest stopped (exit {})\r", code);
}
std::process::exit(code);
}
SessionEnd::TimedOut => {
if !config.quiet {
eprintln!(
"\r\n[vmette] timeout {}s reached; guest force-stopped (exit 124)\r",
config.timeout_seconds.unwrap_or(0)
);
}
std::process::exit(124);
}
SessionEnd::Stopped => {
if !config.quiet {
eprintln!("\r\n[vmette] guest stopped (exit 0)\r");
}
std::process::exit(0);
}
SessionEnd::Error(msg) => {
eprintln!("\r\n[vmette] guest stopped with error: {}\r", msg);
std::process::exit(1);
}
}
}
fn eprint_banner(config: &Config, cmdline: &str, vsock_port: Option<u32>) {
let rootfs = if let Some(rb) = &config.rootfs_block {
format!("{} ({} block, ro)", rb.path.display(), rb.fstype)
} else if let Some(r) = &config.rootfs_share {
format!(
"{}{}",
r.path.display(),
if r.read_only { " (ro)" } else { "" }
)
} else {
"(none)".into()
};
let vsock = match vsock_port {
None => "(disabled)".into(),
Some(p) => p.to_string(),
};
eprintln!(
"[vmette] kernel {}\n\
[vmette] initramfs {}\n\
[vmette] cmdline {}\n\
[vmette] rootfs {}\n\
[vmette] shares {}\n\
[vmette] disks {}\n\
[vmette] exec {}\n\
[vmette] vsock-port {}\n\
[vmette] switch-root {}\n\
[vmette] net {}\n\
[vmette] timeout {}s\n\
[vmette] vcpus {}, memMiB {}\n",
config.kernel.display(),
config.initramfs.display(),
cmdline,
rootfs,
config.shares.len(),
config.disks.len(),
config.exec_cmd.as_deref().unwrap_or("(none — interactive)"),
vsock,
if config.switch_root { "yes" } else { "no" },
if config.net { "yes (NAT)" } else { "no" },
config.timeout_seconds.unwrap_or(0),
config.vcpus,
config.mem_mib,
);
}