use std::process;
#[cfg(target_os = "linux")]
use microsandbox_agentd::{AgentdError, BootParams, agent, clock, handoff, init};
#[cfg(not(target_os = "linux"))]
fn main() {
eprintln!("agentd is only supported on Linux");
process::exit(1);
}
#[cfg(target_os = "linux")]
fn main() {
let boot_time_ns = clock::boottime_ns();
if let Err(e) = init::prepare_bootstrap_console() {
eprintln!("agentd: early init failed: {e}");
process::exit(1);
}
let port = match agent::open_serial_port() {
Ok(port) => port,
Err(e) => {
eprintln!("agentd: console open failed: {e}");
process::exit(1);
}
};
let (bootstrap, mut boot_console) = match agent::receive_bootstrap(&port) {
Ok(result) => result,
Err(e) => {
exit_startup_failure(
&port,
&mut agent::BootConsoleState::default(),
"bootstrap receive",
&e,
);
}
};
let (mut boot, config) = match BootParams::from_bootstrap(bootstrap) {
Ok(result) => result,
Err(e) => {
exit_startup_failure(&port, &mut boot_console, "bootstrap validation", &e);
}
};
config.install_default_env();
let handoff_spec = boot.take_handoff_init();
let init_start = clock::boottime_ns();
if let Err(e) = init::init(boot, || {
agent::report_init_context(&port, &mut boot_console, config.user())
}) {
exit_startup_failure(&port, &mut boot_console, "init", &e);
}
let init_time_ns = clock::boottime_ns() - init_start;
if let Some(spec) = handoff_spec
&& let Err(e) = handoff::do_handoff(spec)
{
exit_startup_failure(&port, &mut boot_console, "handoff", &e);
}
let rt = match tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
{
Ok(rt) => rt,
Err(e) => exit_startup_failure(&port, &mut boot_console, "async runtime setup", &e.into()),
};
let bulk_port = match agent::open_and_bind_bulk_port() {
Ok(port) => port,
Err(e) => {
exit_startup_failure(&port, &mut boot_console, "bulk transport binding", &e);
}
};
rt.block_on(async {
match agent::run(
boot_time_ns,
init_time_ns,
&config,
port,
boot_console,
bulk_port,
)
.await
{
Ok(()) => {}
Err(AgentdError::Shutdown) => {}
Err(e) => {
eprintln!("agentd: agent loop error: {e}");
process::exit(1);
}
}
});
process::exit(0);
}
#[cfg(target_os = "linux")]
fn exit_startup_failure(
port: &std::fs::File,
boot_console: &mut agent::BootConsoleState,
stage: &str,
error: &AgentdError,
) -> ! {
let message = format!("{stage} failed: {error}");
eprintln!("agentd: {message}");
if let Err(report_error) = agent::report_init_failure(port, boot_console, &message, error) {
eprintln!("agentd: could not report startup failure: {report_error}");
}
process::exit(1);
}