Console
The console provides raw serial port access. For command execution, use the agent instead.
When to Use the Console
- Waiting for boot output
- Interactive troubleshooting
- VMs without agent support
Enabling Console Access
Enable the console on your VM builder:
rust,no_run
let vm = capsa::vm(boot)
.console_enabled()
.build()
.await?;
let console = vm.console().await?;Waiting for Boot
Use wait_for() to detect when the VM has booted:
rust,no_run
// Wait for login prompt
console.wait_for("login:", Duration::from_secs(30)).await?;
// Or wait for shell prompt
console.wait_for("# ", Duration::from_secs(30)).await?;Writing to Console
Send text to the console:
rust,no_run
// Write a line (includes newline)
console.write_line("root").await?;
// Write raw bytes
console.write(b"password\n").await?;Reading Output
Read available output without blocking:
rust,no_run
let output = console.read_available().await?;
println!("Console output: {}", output);Control Signals
Send control characters:
rust,no_run
// Send Ctrl+C (interrupt)
console.send_interrupt().await?;
// Send Ctrl+D (EOF)
console.send_eof().await?;Split Reader/Writer
For advanced async I/O, split the console:
rust,no_run
let (mut reader, mut writer) = console.into_split().await?;
// Now you can read and write concurrently
tokio::spawn(async move {
let mut buf = [0u8; 1024];
loop {
let n = reader.read(&mut buf).await.unwrap();
if n == 0 { break; }
print!("{}", String::from_utf8_lossy(&buf[..n]));
}
});
writer.write_all(b"ls /\n").await?;Capturing Boot Failures
When a VM fails to boot, use the console to capture output:
rust,no_run
let vm = capsa::vm(boot)
.console_enabled()
.build()
.await?;
let console = vm.console().await?;
// Try to wait for prompt
match console.wait_for("# ", Duration::from_secs(30)).await {
Ok(_) => println!("Boot successful"),
Err(e) => {
// Capture whatever output we got
let output = console.read_available().await?;
eprintln!("Boot failed: {}", e);
eprintln!("Console output:\n{}", output);
}
}Complete Example
rust,no_run
use capsa::boot::LinuxDirectBoot;
use std::time::Duration;
async fn boot_and_run() -> capsa::Result<()> {
let boot = LinuxDirectBoot::new("./kernel", "./initrd");
let vm = capsa::vm(boot)
.cpus(2)
.memory_mb(1024)
.cmdline_arg("console", "ttyS0")
.console_enabled()
.build()
.await?;
let console = vm.console().await?;
// Wait for login prompt
console.wait_for("login:", Duration::from_secs(30)).await?;
// Log in
console.write_line("root").await?;
console.wait_for("# ", Duration::from_secs(5)).await?;
// Run a command manually
console.write_line("uname -a").await?;
// Read output
tokio::time::sleep(Duration::from_millis(100)).await;
let output = console.read_available().await?;
println!("Output: {}", output);
vm.shutdown().await?;
Ok(())
}Next Steps
- Custom Kernels - Configure custom VMs
- Host-Guest Communication - Vsock for structured I/O
- Running Commands - Use agent for command execution