#[cfg(not(target_os = "linux"))]
fn main() {
eprintln!(
"dirge-microvm-runner: the microVM sandbox is only supported on Linux \
(requires KVM and libkrun)."
);
std::process::exit(1);
}
#[cfg(target_os = "linux")]
use std::ffi::CString;
#[cfg(target_os = "linux")]
fn main() {
let config_json = std::env::args()
.nth(1)
.expect("usage: dirge-microvm-runner '<json-config>'");
let config: serde_json::Value =
serde_json::from_str(&config_json).expect("invalid JSON config");
let rootfs_path = config["rootfs_path"].as_str().expect("missing rootfs_path");
let workspace_path = config["workspace_path"]
.as_str()
.expect("missing workspace_path");
let ssh_port: u16 = config["ssh_port"].as_u64().unwrap_or(0) as u16;
let cpus: u8 = config["cpus"].as_u64().unwrap_or(2) as u8;
let memory_mib: u32 = config["memory_mib"].as_u64().unwrap_or(512) as u32;
unsafe {
libkrun_sys::krun_set_log_level(0);
let ctx = libkrun_sys::krun_create_ctx();
assert!(ctx >= 0, "krun_create_ctx failed: {ctx}");
let rc = libkrun_sys::krun_set_vm_config(ctx as u32, cpus, memory_mib);
assert!(rc == 0, "krun_set_vm_config failed: {rc}");
let mut rlim: libc::rlimit = std::mem::zeroed();
assert!(
libc::getrlimit(libc::RLIMIT_NOFILE, &mut rlim) == 0,
"getrlimit(RLIMIT_NOFILE) failed"
);
rlim.rlim_cur = rlim.rlim_max;
assert!(
libc::setrlimit(libc::RLIMIT_NOFILE, &rlim) == 0,
"setrlimit(RLIMIT_NOFILE) failed"
);
let nofile_rlimit = format!(
"{}={}:{}",
libc::RLIMIT_NOFILE,
rlim.rlim_cur,
rlim.rlim_max
);
let nofile_cstr = to_cstr(&nofile_rlimit);
let rlimits: [*const std::ffi::c_char; 2] = [nofile_cstr.as_ptr(), std::ptr::null()];
let rc = libkrun_sys::krun_set_rlimits(ctx as u32, rlimits.as_ptr());
assert!(rc == 0, "krun_set_rlimits failed: {rc}");
let root_cstr = to_cstr(rootfs_path);
let rc = libkrun_sys::krun_set_root(ctx as u32, root_cstr.as_ptr());
assert!(rc == 0, "krun_set_root failed: {rc}");
let ws_cstr = to_cstr(workspace_path);
let tag_cstr = to_cstr("workspace");
let rc = libkrun_sys::krun_add_virtiofs(ctx as u32, tag_cstr.as_ptr(), ws_cstr.as_ptr());
assert!(rc == 0, "krun_add_virtiofs failed: {rc}");
if ssh_port > 0 {
let port_map_str = format!("{ssh_port}:22");
let pm_cstr = to_cstr(&port_map_str);
let port_maps = [pm_cstr.as_ptr(), std::ptr::null()];
let rc = libkrun_sys::krun_set_port_map(ctx as u32, port_maps.as_ptr());
assert!(rc == 0, "krun_set_port_map failed: {rc}");
}
let rc = libkrun_sys::krun_start_enter(ctx as u32);
assert!(rc == 0, "krun_start_enter failed: {rc}");
}
}
#[cfg(target_os = "linux")]
fn to_cstr(s: &str) -> CString {
CString::new(s).unwrap_or_else(|_| CString::new("").unwrap())
}