From 2aed42a221970d77ffe646bff667acf084f3d3bf Mon Sep 17 00:00:00 2001 From: Val Packett Date: Thu, 23 Oct 2025 20:12:38 -0300 Subject: [PATCH 1/7] Add a flag to run a custom init instead of muvm-guest Allow the user to replace muvm-guest with a custom init process. With updated libkrun, it will even run as PID 1, making it possible to run systemd. Of course, this is not the suggested way to use muvm, but some use cases necesitate the use of systemd. The next few commits will facilitate running individual parts of muvm-guest as separate processes under a custom service manager. Signed-off-by: Val Packett --- crates/muvm/src/bin/muvm.rs | 28 ++++++++++++++++++++-------- crates/muvm/src/cli_options.rs | 9 +++++++++ 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/crates/muvm/src/bin/muvm.rs b/crates/muvm/src/bin/muvm.rs index 0827e8db..64608d1b 100644 --- a/crates/muvm/src/bin/muvm.rs +++ b/crates/muvm/src/bin/muvm.rs @@ -429,13 +429,21 @@ fn main() -> Result { .to_str() .context("Temporary directory path contains invalid UTF-8")? .to_owned(); - let muvm_guest_args = vec![ - muvm_guest_path - .to_str() - .context("Failed to process `muvm-guest` path as it contains invalid UTF-8")? - .to_owned(), - muvm_config_path, - ]; + let custom_init = options.custom_init_cmdline.is_some(); + let muvm_guest_args = if let Some(cmdline) = options.custom_init_cmdline { + cmdline + .split_whitespace() + .map(|a| a.to_owned()) + .collect::>() + } else { + vec![ + muvm_guest_path + .to_str() + .context("Failed to process `muvm-guest` path as it contains invalid UTF-8")? + .to_owned(), + muvm_config_path, + ] + }; // And forward XAUTHORITY. This will be modified to fix the // display name in muvm-guest. @@ -470,7 +478,11 @@ fn main() -> Result { let krun_config_env = CString::new(format!("KRUN_CONFIG={}", config_file.path().display())) .context("Failed to process config_file var as it contains NUL character")?; - let env: Vec<*const c_char> = vec![krun_config_env.as_ptr(), std::ptr::null()]; + let mut env: Vec<*const c_char> = vec![krun_config_env.as_ptr()]; + if custom_init { + env.push(c"KRUN_INIT_PID1=1".as_ptr()); + } + env.push(std::ptr::null()); { // Sets environment variables to be configured in the context of the executable. diff --git a/crates/muvm/src/cli_options.rs b/crates/muvm/src/cli_options.rs index 5080c911..69326da0 100644 --- a/crates/muvm/src/cli_options.rs +++ b/crates/muvm/src/cli_options.rs @@ -47,6 +47,7 @@ pub struct Options { pub emulator: Option, pub init_commands: Vec, pub user_init_commands: Vec, + pub custom_init_cmdline: Option, pub command: PathBuf, pub command_args: Vec, } @@ -179,6 +180,13 @@ pub fn options() -> OptionParser { ) .argument("COMMAND") .many(); + let custom_init_cmdline = long("custom-init-cmdline") + .help( + "Command and arguments to run as PID 1, replacing muvm's own init. + (Warning: this will break many muvm features, unless your init reimplements them.)", + ) + .argument("CMDLINE") + .optional(); let command = positional("COMMAND").help("the command you want to execute in the vm"); let command_args = any::("COMMAND_ARGS", |arg| { (!["--help", "-h"].contains(&&*arg)).then_some(arg) @@ -202,6 +210,7 @@ pub fn options() -> OptionParser { emulator, init_commands, user_init_commands, + custom_init_cmdline, // positionals command, command_args, From f2ee79293409d1fb1ed350669a5925f55898fef4 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Thu, 23 Oct 2025 20:55:08 -0300 Subject: [PATCH 2/7] muvm-guest: Add support for running as muvm-remote and muvm-configure-network To better support running under a custom service manager (e.g. systemd), allow running individual functions of the guest binary when called with distinct binary names. Signed-off-by: Val Packett --- crates/muvm/src/guest/bin/muvm-guest.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/crates/muvm/src/guest/bin/muvm-guest.rs b/crates/muvm/src/guest/bin/muvm-guest.rs index 6bac1838..075a6ab0 100644 --- a/crates/muvm/src/guest/bin/muvm-guest.rs +++ b/crates/muvm/src/guest/bin/muvm-guest.rs @@ -2,6 +2,7 @@ use std::fs::File; use std::io::Read; use std::os::fd::AsFd; use std::panic::catch_unwind; +use std::path::PathBuf; use std::process::{Command, ExitCode}; use std::{cmp, env, fs, thread}; @@ -27,6 +28,19 @@ const KRUN_CONFIG: &str = "KRUN_CONFIG"; fn main() -> Result { env_logger::init(); + let binary_path = env::args().next().context("arg0")?; + let bb = binary_path.split('/').next_back().context("arg0 split")?; + match bb { + "muvm-configure-network" => return configure_network(), + "muvm-remote" => { + let rt = tokio::runtime::Runtime::new().unwrap(); + let mut command_args = env::args().skip(1); + let command = command_args.next().context("command name")?; + return rt.block_on(server_main(PathBuf::from(command), command_args.collect())); + }, + _ => { /* continue with all-in-one mode */ }, + } + if let Ok(val) = env::var("__X11BRIDGE_DEBUG") { start_x11bridge(val.parse()?); return Ok(ExitCode::SUCCESS); From f3e1c6c9f63bbdf0c438b89d297fc0c399e7bb9b Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 24 Oct 2025 01:07:32 -0300 Subject: [PATCH 3/7] muvm-guest: Add support for running as muvm-pwbridge Support running the PipeWire bridge as a separate process, optionally with systemd socket activation. Signed-off-by: Val Packett --- Cargo.lock | 34 ++++++++++++++++++++++++ crates/muvm/Cargo.toml | 1 + crates/muvm/src/guest/bin/muvm-guest.rs | 9 +++++-- crates/muvm/src/guest/bridge/common.rs | 18 +++++++++++-- crates/muvm/src/guest/bridge/pipewire.rs | 11 +++----- 5 files changed, 62 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0fc95df5..7206262b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -500,6 +500,17 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" +[[package]] +name = "listenfd" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b87bc54a4629b4294d0b3ef041b64c40c611097a677d9dc07b2c67739fe39dba" +dependencies = [ + "libc", + "uuid", + "winapi", +] + [[package]] name = "lock_api" version = "0.4.12" @@ -569,6 +580,7 @@ dependencies = [ "input-linux", "input-linux-sys", "krun-sys", + "listenfd", "log", "neli", "nix 0.30.1", @@ -1062,6 +1074,28 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-sys" version = "0.48.0" diff --git a/crates/muvm/Cargo.toml b/crates/muvm/Cargo.toml index b90d276c..9e833fb2 100644 --- a/crates/muvm/Cargo.toml +++ b/crates/muvm/Cargo.toml @@ -29,6 +29,7 @@ tokio = { version = "1.38.0", default-features = false, features = ["io-util", " tokio-stream = { version = "0.1.15", default-features = false, features = ["net", "sync"] } udev = { version = "0.9.0", default-features = false, features = [] } uuid = { version = "1.10.0", default-features = false, features = ["serde", "std", "v7"] } +listenfd = "1.0.2" [[bin]] name = "muvm" diff --git a/crates/muvm/src/guest/bin/muvm-guest.rs b/crates/muvm/src/guest/bin/muvm-guest.rs index 075a6ab0..73044826 100644 --- a/crates/muvm/src/guest/bin/muvm-guest.rs +++ b/crates/muvm/src/guest/bin/muvm-guest.rs @@ -8,7 +8,8 @@ use std::{cmp, env, fs, thread}; use anyhow::{anyhow, Context, Result}; use muvm::guest::box64::setup_box; -use muvm::guest::bridge::pipewire::start_pwbridge; +use muvm::guest::bridge::common::{bridge_loop, bridge_loop_with_listenfd}; +use muvm::guest::bridge::pipewire::{pipewire_sock_path, PipeWireProtocolHandler}; use muvm::guest::bridge::x11::start_x11bridge; use muvm::guest::fex::setup_fex; use muvm::guest::hidpipe::start_hidpipe; @@ -32,6 +33,10 @@ fn main() -> Result { let bb = binary_path.split('/').next_back().context("arg0 split")?; match bb { "muvm-configure-network" => return configure_network(), + "muvm-pwbridge" => { + bridge_loop_with_listenfd::(pipewire_sock_path); + return Ok(()); + }, "muvm-remote" => { let rt = tokio::runtime::Runtime::new().unwrap(); let mut command_args = env::args().skip(1); @@ -169,7 +174,7 @@ fn main() -> Result { }); thread::spawn(|| { - if catch_unwind(start_pwbridge).is_err() { + if catch_unwind(|| bridge_loop::(&pipewire_sock_path())).is_err() { eprintln!("pwbridge thread crashed, pipewire passthrough will no longer function"); } }); diff --git a/crates/muvm/src/guest/bridge/common.rs b/crates/muvm/src/guest/bridge/common.rs index 04b047bc..ac97a5dd 100644 --- a/crates/muvm/src/guest/bridge/common.rs +++ b/crates/muvm/src/guest/bridge/common.rs @@ -971,10 +971,24 @@ impl<'a, T: ProtocolHandler> SubPoll<'a, T> { } } +pub fn bridge_loop_with_listenfd(fallback_sock_path: impl Fn() -> String) { + if let Some(listen_sock) = listenfd::ListenFd::from_env() + .take_unix_listener(0) + .unwrap() + { + bridge_loop_sock::(listen_sock) + } else { + bridge_loop::(&fallback_sock_path()) + } +} + pub fn bridge_loop(sock_path: &str) { - let epoll = Epoll::new(EpollCreateFlags::empty()).unwrap(); _ = fs::remove_file(sock_path); - let listen_sock = UnixListener::bind(sock_path).unwrap(); + bridge_loop_sock::(UnixListener::bind(sock_path).unwrap()); +} + +pub fn bridge_loop_sock(listen_sock: UnixListener) { + let epoll = Epoll::new(EpollCreateFlags::empty()).unwrap(); epoll .add( &listen_sock, diff --git a/crates/muvm/src/guest/bridge/pipewire.rs b/crates/muvm/src/guest/bridge/pipewire.rs index 343dd211..005f8a25 100644 --- a/crates/muvm/src/guest/bridge/pipewire.rs +++ b/crates/muvm/src/guest/bridge/pipewire.rs @@ -9,7 +9,6 @@ use nix::errno::Errno; use nix::sys::epoll::EpollFlags; use nix::sys::eventfd::{EfdFlags, EventFd}; -use crate::guest::bridge::common; use crate::guest::bridge::common::{ Client, CrossDomainHeader, CrossDomainResource, MessageResourceFinalizer, ProtocolHandler, StreamRecvResult, StreamSendResult, @@ -165,7 +164,7 @@ impl PipeWireHeader { } } -struct PipeWireResourceFinalizer; +pub struct PipeWireResourceFinalizer; impl MessageResourceFinalizer for PipeWireResourceFinalizer { type Handler = PipeWireProtocolHandler; @@ -194,7 +193,7 @@ impl ClientNodeData { } } -struct PipeWireProtocolHandler { +pub struct PipeWireProtocolHandler { client_nodes: HashMap, guest_to_host_eventfds: HashMap, host_to_guest_eventfds: HashMap, @@ -405,8 +404,6 @@ impl ProtocolHandler for PipeWireProtocolHandler { } } -pub fn start_pwbridge() { - let sock_path = format!("{}/pipewire-0", env::var("XDG_RUNTIME_DIR").unwrap()); - - common::bridge_loop::(&sock_path) +pub fn pipewire_sock_path() -> String { + format!("{}/pipewire-0", env::var("XDG_RUNTIME_DIR").unwrap()) } From 208527ac5da0454cfd4ca1e22d717c63447c21e1 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 21 Nov 2025 03:38:48 -0300 Subject: [PATCH 4/7] x11: use get_or_init instead of the set/get dance for the offset This is how OnceLock is really meant to be used.. This will be helpful for the custom init support, where various ways of starting the bridge loop will be used. Signed-off-by: Val Packett --- crates/muvm/src/guest/bridge/x11.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/crates/muvm/src/guest/bridge/x11.rs b/crates/muvm/src/guest/bridge/x11.rs index fa4c1125..870dcf47 100644 --- a/crates/muvm/src/guest/bridge/x11.rs +++ b/crates/muvm/src/guest/bridge/x11.rs @@ -4,7 +4,6 @@ use std::ffi::{c_long, c_void, CString}; use std::fs::{read_to_string, remove_file, File}; use std::io::{IoSlice, Write}; use std::os::fd::{AsFd, AsRawFd, BorrowedFd, OwnedFd}; -use std::process::exit; use std::ptr::NonNull; use std::sync::atomic::{AtomicBool, AtomicU32, Ordering}; use std::sync::{Arc, OnceLock}; @@ -714,7 +713,7 @@ impl RemoteCaller { // Find the vDSO and the address of a syscall instruction within it let (vdso_start, _) = find_vdso(Some(pid))?; - let syscall_addr = vdso_start + SYSCALL_OFFSET.get().unwrap(); + let syscall_addr = vdso_start + SYSCALL_OFFSET.get_or_init(find_syscall_offset); let mut regs = old_regs; arch::set_syscall_addr(&mut regs, syscall_addr); @@ -857,9 +856,7 @@ fn find_vdso(pid: Option) -> Result<(usize, usize), Errno> { Err(Errno::EINVAL) } -pub fn start_x11bridge(display: u32) { - let sock_path = format!("/tmp/.X11-unix/X{display}"); - +fn find_syscall_offset() -> usize { // Look for a syscall instruction in the vDSO. We assume all processes map // the same vDSO (which should be true if they are running under the same // kernel!) @@ -868,14 +865,13 @@ pub fn start_x11bridge(display: u32) { let addr = vdso_start + off; let val = unsafe { std::ptr::read(addr as *const arch::SyscallInstr) }; if val == arch::SYSCALL_INSTR { - SYSCALL_OFFSET.set(off).unwrap(); - break; + return off; } } - if SYSCALL_OFFSET.get().is_none() { - eprintln!("Failed to find syscall instruction in vDSO"); - exit(1); - } + panic!("Failed to find syscall instruction in vDSO"); +} +pub fn start_x11bridge(display: u32) { + let sock_path = format!("/tmp/.X11-unix/X{display}"); common::bridge_loop::(&sock_path) } From df28f556502795028a93297b8d1622936ec18192 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 21 Nov 2025 03:41:13 -0300 Subject: [PATCH 5/7] muvm-guest: add support for running as muvm-x11bridge Signed-off-by: Val Packett --- crates/muvm/src/guest/bin/muvm-guest.rs | 6 +++++- crates/muvm/src/guest/bridge/x11.rs | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/crates/muvm/src/guest/bin/muvm-guest.rs b/crates/muvm/src/guest/bin/muvm-guest.rs index 73044826..de029ece 100644 --- a/crates/muvm/src/guest/bin/muvm-guest.rs +++ b/crates/muvm/src/guest/bin/muvm-guest.rs @@ -10,7 +10,7 @@ use anyhow::{anyhow, Context, Result}; use muvm::guest::box64::setup_box; use muvm::guest::bridge::common::{bridge_loop, bridge_loop_with_listenfd}; use muvm::guest::bridge::pipewire::{pipewire_sock_path, PipeWireProtocolHandler}; -use muvm::guest::bridge::x11::start_x11bridge; +use muvm::guest::bridge::x11::{start_x11bridge, X11ProtocolHandler}; use muvm::guest::fex::setup_fex; use muvm::guest::hidpipe::start_hidpipe; use muvm::guest::mount::mount_filesystems; @@ -37,6 +37,10 @@ fn main() -> Result { bridge_loop_with_listenfd::(pipewire_sock_path); return Ok(()); }, + "muvm-x11bridge" => { + bridge_loop_with_listenfd::(|| "/tmp/.X11-unix/X1".to_owned()); + return Ok(ExitCode::SUCCESS); + }, "muvm-remote" => { let rt = tokio::runtime::Runtime::new().unwrap(); let mut command_args = env::args().skip(1); diff --git a/crates/muvm/src/guest/bridge/x11.rs b/crates/muvm/src/guest/bridge/x11.rs index 870dcf47..de46c8a4 100644 --- a/crates/muvm/src/guest/bridge/x11.rs +++ b/crates/muvm/src/guest/bridge/x11.rs @@ -155,7 +155,7 @@ struct CrossDomainFutexDestroy { pad: u32, } -enum X11ResourceFinalizer { +pub enum X11ResourceFinalizer { Gem(GemHandleFinalizer), Futex(u32), } @@ -186,7 +186,7 @@ impl MessageResourceFinalizer for X11ResourceFinalizer { } } -struct X11ProtocolHandler { +pub struct X11ProtocolHandler { // futex_watchers gets dropped first futex_watchers: HashMap, got_first_req: bool, From ff15cc25d2b341680f215e2b4a2dce25c4a961aa Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 21 Nov 2025 03:54:18 -0300 Subject: [PATCH 6/7] muvm-guest: add support for running as muvm-hidpipe Signed-off-by: Val Packett --- crates/muvm/src/guest/bin/muvm-guest.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/crates/muvm/src/guest/bin/muvm-guest.rs b/crates/muvm/src/guest/bin/muvm-guest.rs index de029ece..94291f3f 100644 --- a/crates/muvm/src/guest/bin/muvm-guest.rs +++ b/crates/muvm/src/guest/bin/muvm-guest.rs @@ -41,6 +41,14 @@ fn main() -> Result { bridge_loop_with_listenfd::(|| "/tmp/.X11-unix/X1".to_owned()); return Ok(ExitCode::SUCCESS); }, + "muvm-hidpipe" => { + let config_path = + env::var("MUVM_REMOTE_CONFIG").context("expected MUVM_REMOTE_CONFIG to be set")?; + let options = parse_config(config_path)?; + let uid = options.uid; + start_hidpipe(uid); + return Ok(ExitCode::SUCCESS); + }, "muvm-remote" => { let rt = tokio::runtime::Runtime::new().unwrap(); let mut command_args = env::args().skip(1); From ae7dbd49aac04e9732a14a424572e99a81eb1298 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 31 Oct 2025 04:37:38 -0300 Subject: [PATCH 7/7] muvm-guest: pass config to split remote process Signed-off-by: Val Packett --- crates/muvm/src/bin/muvm.rs | 10 ++++++ crates/muvm/src/guest/bin/muvm-guest.rs | 45 ++++++++++++++----------- 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/crates/muvm/src/bin/muvm.rs b/crates/muvm/src/bin/muvm.rs index 64608d1b..d839c639 100644 --- a/crates/muvm/src/bin/muvm.rs +++ b/crates/muvm/src/bin/muvm.rs @@ -478,9 +478,19 @@ fn main() -> Result { let krun_config_env = CString::new(format!("KRUN_CONFIG={}", config_file.path().display())) .context("Failed to process config_file var as it contains NUL character")?; + #[allow(unused_assignments)] // wat? + let mut muvm_config_env = None; // keep in this scope let mut env: Vec<*const c_char> = vec![krun_config_env.as_ptr()]; if custom_init { env.push(c"KRUN_INIT_PID1=1".as_ptr()); + muvm_config_env = Some( + CString::new(format!( + "MUVM_REMOTE_CONFIG={}", + muvm_config_file.path().display() + )) + .context("Failed to process internal config path as it contains NUL character")?, + ); + env.push(muvm_config_env.as_ref().unwrap().as_ptr()); } env.push(std::ptr::null()); diff --git a/crates/muvm/src/guest/bin/muvm-guest.rs b/crates/muvm/src/guest/bin/muvm-guest.rs index 94291f3f..757780d9 100644 --- a/crates/muvm/src/guest/bin/muvm-guest.rs +++ b/crates/muvm/src/guest/bin/muvm-guest.rs @@ -2,7 +2,6 @@ use std::fs::File; use std::io::Read; use std::os::fd::AsFd; use std::panic::catch_unwind; -use std::path::PathBuf; use std::process::{Command, ExitCode}; use std::{cmp, env, fs, thread}; @@ -26,16 +25,32 @@ use rustix::process::{getrlimit, setrlimit, Resource}; const KRUN_CONFIG: &str = "KRUN_CONFIG"; +fn parse_config(config_path: String) -> Result { + let mut config_file = File::open(&config_path)?; + let mut config_buf = Vec::new(); + config_file.read_to_end(&mut config_buf)?; + fs::remove_file(config_path).context("Unable to delete temporary muvm configuration file")?; + if let Ok(krun_config_path) = env::var(KRUN_CONFIG) { + fs::remove_file(krun_config_path) + .context("Unable to delete temporary krun configuration file")?; + // SAFETY: We are single-threaded at this point + env::remove_var(KRUN_CONFIG); + } + // SAFETY: We are single-threaded at this point + env::remove_var("KRUN_WORKDIR"); + Ok(serde_json::from_slice::(&config_buf)?) +} + fn main() -> Result { env_logger::init(); let binary_path = env::args().next().context("arg0")?; let bb = binary_path.split('/').next_back().context("arg0 split")?; match bb { - "muvm-configure-network" => return configure_network(), + "muvm-configure-network" => return configure_network().map(|()| ExitCode::SUCCESS), "muvm-pwbridge" => { bridge_loop_with_listenfd::(pipewire_sock_path); - return Ok(()); + return Ok(ExitCode::SUCCESS); }, "muvm-x11bridge" => { bridge_loop_with_listenfd::(|| "/tmp/.X11-unix/X1".to_owned()); @@ -51,9 +66,13 @@ fn main() -> Result { }, "muvm-remote" => { let rt = tokio::runtime::Runtime::new().unwrap(); - let mut command_args = env::args().skip(1); - let command = command_args.next().context("command name")?; - return rt.block_on(server_main(PathBuf::from(command), command_args.collect())); + let config_path = + env::var("MUVM_REMOTE_CONFIG").context("expected MUVM_REMOTE_CONFIG to be set")?; + let options = parse_config(config_path)?; + return rt.block_on(server_main( + options.command.command, + options.command.command_args, + )); }, _ => { /* continue with all-in-one mode */ }, } @@ -66,19 +85,7 @@ fn main() -> Result { let config_path = env::args() .nth(1) .context("expected configuration file path")?; - let mut config_file = File::open(&config_path)?; - let mut config_buf = Vec::new(); - config_file.read_to_end(&mut config_buf)?; - fs::remove_file(config_path).context("Unable to delete temporary muvm configuration file")?; - if let Ok(krun_config_path) = env::var(KRUN_CONFIG) { - fs::remove_file(krun_config_path) - .context("Unable to delete temporary krun configuration file")?; - // SAFETY: We are single-threaded at this point - env::remove_var(KRUN_CONFIG); - } - // SAFETY: We are single-threaded at this point - env::remove_var("KRUN_WORKDIR"); - let options = serde_json::from_slice::(&config_buf)?; + let options = parse_config(config_path)?; { const ESYNC_RLIMIT_NOFILE: u64 = 524288;