From a24e1efe31d65e3ef37d06cc4839c9fc5cc33696 Mon Sep 17 00:00:00 2001 From: Joakim Hulthe Date: Fri, 11 Sep 2026 17:55:53 +0200 Subject: [PATCH] Rebrand to boco --- Cargo.lock | 44 +++++++++---------- Cargo.toml | 2 +- README.md | 24 +++++----- example/test.sh | 112 +++++++++++++++++++++++------------------------ init/Cargo.toml | 2 +- init/src/main.rs | 26 +++++------ kernel/config | 2 +- src/build.rs | 6 +-- src/inject.rs | 12 ++--- src/main.rs | 10 ++--- src/qemu.rs | 30 ++++++------- src/registry.rs | 14 +++--- 12 files changed, 142 insertions(+), 142 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7035487..562ad9b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -76,6 +76,28 @@ version = "2.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" +[[package]] +name = "boco" +version = "0.1.0" +dependencies = [ + "anyhow", + "base64", + "clap", + "flate2", + "serde", + "serde_json", + "tempfile", + "xdg", +] + +[[package]] +name = "boco-init" +version = "0.1.0" +dependencies = [ + "base64", + "nix", +] + [[package]] name = "cfg-if" version = "1.0.4" @@ -337,28 +359,6 @@ version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" -[[package]] -name = "slim" -version = "0.1.0" -dependencies = [ - "anyhow", - "base64", - "clap", - "flate2", - "serde", - "serde_json", - "tempfile", - "xdg", -] - -[[package]] -name = "slim-init" -version = "0.1.0" -dependencies = [ - "base64", - "nix", -] - [[package]] name = "strsim" version = "0.11.1" diff --git a/Cargo.toml b/Cargo.toml index 0fe7469..1c6ed46 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ lto = true strip = true [package] -name = "slim" +name = "boco" version = "0.1.0" edition = "2024" diff --git a/README.md b/README.md index b3b18b6..b246e7e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# slim +# boco Turning containers into bootable VMs @@ -6,27 +6,27 @@ Turning containers into bootable VMs ```sh # Build the container -podman build ./example/alpine -t slim-alpine +podman build ./example/alpine -t boco-alpine -# Make the container bootable. slim injects /slim/init and /slim/exec, +# Make the container bootable. boco injects /boco/init and /boco/exec, # then packs the rootfs as a qcow2 disk. -slim build qcow2 slim-alpine +boco build qcow2 boco-alpine # Boot the image using QEMU. The container's CMD runs automatically. -slim run slim-alpine +boco boot boco-alpine # Override the command at runtime (base64-encoded on the kernel cmdline): -slim run slim-alpine --cmd '/bin/sh' +boco boot boco-alpine --cmd '/bin/sh' -# Override the command at build time (baked into /slim/exec): -slim build qcow2 slim-alpine --cmd '/bin/sh' +# Override the command at build time (baked into /boco/exec): +boco build qcow2 boco-alpine --cmd '/bin/sh' # Cleanup -slim image rm slim-alpine -podman image rm slim-alpine +boco image rm boco-alpine +podman image rm boco-alpine ``` ## Kernel -slim boots VMs using a shared kernel at `$XDG_DATA_HOME/slim-rs/registry/vmlinuz`. -Place a suitable x86 bzImage there before running `slim run`. +boco boots VMs using a shared kernel at `$XDG_DATA_HOME/boco/registry/vmlinuz`. +Place a suitable x86 bzImage there before running `boco boot`. diff --git a/example/test.sh b/example/test.sh index 8cffec4..3da3b38 100755 --- a/example/test.sh +++ b/example/test.sh @@ -1,12 +1,12 @@ #!/bin/bash -# Test script for slim - boots containers and verifies CMD inference/override. +# Test script for boco - boots containers and verifies CMD inference/override. # Requires: podman, qemu-system-x86_64, KVM, curl, and a kernel at -# $XDG_DATA_HOME/slim-rs/registry/vmlinuz. +# $XDG_DATA_HOME/boco/registry/vmlinuz. set -u SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" TARGET_DIR="${CARGO_TARGET_DIR:-$SCRIPT_DIR/../target}" -SLIM_BIN="$TARGET_DIR/debug/slim" +BOCO_BIN="$TARGET_DIR/debug/boco" TIMEOUT=120 pass=0 @@ -34,7 +34,7 @@ check_output() { } cleanup() { - "$SLIM_BIN" image rm "$1" >/dev/null 2>&1 || true + "$BOCO_BIN" image rm "$1" >/dev/null 2>&1 || true podman image rm "$2" >/dev/null 2>&1 || true } @@ -54,10 +54,10 @@ FROM $from $extra_setup CMD ["/bin/sh", "-c", "echo CMD_INFERRED_OK; wget -q -O /dev/null http://1.1.1.1 2>/dev/null && echo CONN_OK; wget -q -O /dev/null http://example.org 2>/dev/null && echo DNS_OK; poweroff -f"] EOF - img="slim-test-$distro-infer" + img="boco-test-$distro-infer" if podman build -t "$img" -f "$work/Containerfile.infer" >/dev/null 2>&1; then - "$SLIM_BIN" build qcow2 "$img" >/dev/null 2>&1 - output=$(timeout "$TIMEOUT" "$SLIM_BIN" run "$img" 2>&1 || true) + "$BOCO_BIN" build qcow2 "$img" >/dev/null 2>&1 + output=$(timeout "$TIMEOUT" "$BOCO_BIN" boot "$img" 2>&1 || true) check_output "$output" "CMD_INFERRED_OK" "$distro CMD-inferred" check_output "$output" "CONN_OK" "$distro connect to 1.1.1.1" check_output "$output" "DNS_OK" "$distro DNS lookup" @@ -66,34 +66,34 @@ EOF fi cleanup "$img" "$img" - # === Test 2: slim run --cmd override === - echo "-- Test 2: slim run --cmd override" + # === Test 2: boco boot --cmd override === + echo "-- Test 2: boco boot --cmd override" cat > "$work/Containerfile.run" </dev/null 2>&1; then - "$SLIM_BIN" build qcow2 "$img" >/dev/null 2>&1 - output=$(timeout "$TIMEOUT" "$SLIM_BIN" run "$img" --cmd 'echo RUN_OVERRIDE_OK; poweroff -f' 2>&1 || true) - check_output "$output" "RUN_OVERRIDE_OK" "$distro run --cmd override" + "$BOCO_BIN" build qcow2 "$img" >/dev/null 2>&1 + output=$(timeout "$TIMEOUT" "$BOCO_BIN" boot "$img" --cmd 'echo RUN_OVERRIDE_OK; poweroff -f' 2>&1 || true) + check_output "$output" "RUN_OVERRIDE_OK" "$distro boot --cmd override" else - report fail "$distro run --cmd override (podman build failed)" + report fail "$distro boot --cmd override (podman build failed)" fi cleanup "$img" "$img" - # === Test 3: slim build --cmd override === - echo "-- Test 3: slim build --cmd override" + # === Test 3: boco build --cmd override === + echo "-- Test 3: boco build --cmd override" cat > "$work/Containerfile.build" </dev/null 2>&1; then - "$SLIM_BIN" build qcow2 "$img" --cmd 'echo BUILD_OVERRIDE_OK; poweroff -f' >/dev/null 2>&1 - output=$(timeout "$TIMEOUT" "$SLIM_BIN" run "$img" 2>&1 || true) + "$BOCO_BIN" build qcow2 "$img" --cmd 'echo BUILD_OVERRIDE_OK; poweroff -f' >/dev/null 2>&1 + output=$(timeout "$TIMEOUT" "$BOCO_BIN" boot "$img" 2>&1 || true) check_output "$output" "BUILD_OVERRIDE_OK" "$distro build --cmd override" else report fail "$distro build --cmd override (podman build failed)" @@ -107,7 +107,7 @@ test_user() { echo "=== Testing USER directive ===" work="$(mktemp -d)" - img="slim-test-user" + img="boco-test-user" cat > "$work/Containerfile" <<'EOF' FROM alpine:latest @@ -124,13 +124,13 @@ EOF fi echo "-- Test 1: build-time CMD runs as USER" - "$SLIM_BIN" build qcow2 "$img" >/dev/null 2>&1 - output=$(timeout "$TIMEOUT" "$SLIM_BIN" run "$img" 2>&1 || true) + "$BOCO_BIN" build qcow2 "$img" >/dev/null 2>&1 + output=$(timeout "$TIMEOUT" "$BOCO_BIN" boot "$img" 2>&1 || true) check_output "$output" "USER_BUILD_OK:1500:testuser" "USER build-time CMD runs as testuser" - echo "-- Test 2: run --cmd override runs as USER" - output=$(timeout "$TIMEOUT" "$SLIM_BIN" run "$img" --cmd 'echo USER_RUN_OK:$(id -u):$(whoami); poweroff -f' 2>&1 || true) - check_output "$output" "USER_RUN_OK:1500:testuser" "USER run --cmd override runs as testuser" + echo "-- Test 2: boot --cmd override runs as USER" + output=$(timeout "$TIMEOUT" "$BOCO_BIN" boot "$img" --cmd 'echo USER_RUN_OK:$(id -u):$(whoami); poweroff -f' 2>&1 || true) + check_output "$output" "USER_RUN_OK:1500:testuser" "USER boot --cmd override runs as testuser" cleanup "$img" "$img" rm -rf "$work" @@ -142,7 +142,7 @@ test_mount() { work="$(mktemp -d)" # --- Image 1: no WORKINGDIR, test host:guest and multi-mount --- - img="slim-test-mount" + img="boco-test-mount" share_dir="$work/share" share_dir2="$work/share2" guest_dir="/mnt/guest" @@ -164,9 +164,9 @@ EOF return fi - echo "-- Building slim VM..." - if ! "$SLIM_BIN" build qcow2 "$img" >/dev/null 2>&1; then - report fail "--mount (slim build failed)" + echo "-- Building boco VM..." + if ! "$BOCO_BIN" build qcow2 "$img" >/dev/null 2>&1; then + report fail "--mount (boco build failed)" cleanup "$img" "$img" rm -rf "$work" return @@ -176,14 +176,14 @@ EOF share_canon2=$(readlink -f "$share_dir2") echo "-- Test 1: --mount host:guest (absolute guest path, multi-mount)..." - output=$(timeout "$TIMEOUT" "$SLIM_BIN" run "$img" \ + output=$(timeout "$TIMEOUT" "$BOCO_BIN" boot "$img" \ --mount "${share_dir}:${guest_dir}" \ --mount "${share_dir2}:${guest_dir2}" \ --cmd "for f in /sys/bus/virtio/drivers/9pnet_virtio/virtio*/mount_tag; do [ -f \"\$f\" ] && echo \"\$f: \$(tr -d '\\0' < \"\$f\")\"; done; mount -v; cat ${guest_dir}/testfile.txt 2>/dev/null || echo NO_FILE; cat ${guest_dir2}/testfile2.txt 2>/dev/null || echo NO_FILE2; echo MOUNT_VERIFY_DONE; poweroff -f" \ 2>&1 || true) - check_output "$output" "mount_tag: slim0" "--mount 9p share detected" - check_output "$output" "mount_tag: slim1" "--mount second 9p share detected" + check_output "$output" "mount_tag: boco0" "--mount 9p share detected" + check_output "$output" "mount_tag: boco1" "--mount second 9p share detected" check_output "$output" "type 9p" "--mount 9p filesystem in mount list" check_output "$output" "hello from host" "--mount file accessible at guest path" check_output "$output" "second share" "--mount second file accessible at guest path" @@ -192,7 +192,7 @@ EOF cleanup "$img" "$img" # --- Image 2: with WORKINGDIR, test relative guest path --- - img="slim-test-mount-wd" + img="boco-test-mount-wd" share_dir3="$work/share3" mkdir -p "$share_dir3" @@ -211,16 +211,16 @@ EOF return fi - echo "-- Building slim VM..." - if ! "$SLIM_BIN" build qcow2 "$img" >/dev/null 2>&1; then - report fail "--mount relative (slim build failed)" + echo "-- Building boco VM..." + if ! "$BOCO_BIN" build qcow2 "$img" >/dev/null 2>&1; then + report fail "--mount relative (boco build failed)" cleanup "$img" "$img" rm -rf "$work" return fi echo "-- Test 2: --mount host:relative-guest (resolved against WORKINGDIR)..." - output=$(timeout "$TIMEOUT" "$SLIM_BIN" run "$img" \ + output=$(timeout "$TIMEOUT" "$BOCO_BIN" boot "$img" \ --mount "${share_dir3}:data" \ --cmd "mount -v; cat /app/data/relfile.txt 2>/dev/null || echo NO_REL_FILE; echo REL_VERIFY_DONE; poweroff -f" \ 2>&1 || true) @@ -236,7 +236,7 @@ EOF test_service() { echo "=== Testing nextcloud service ===" - img="slim-test-nextcloud" + img="boco-test-nextcloud" host_port=18080 work="$(mktemp -d)" @@ -252,16 +252,16 @@ EOF return fi - echo "-- Building slim VM..." - if ! "$SLIM_BIN" build qcow2 "$img" >/dev/null 2>&1; then - report fail "nextcloud service (slim build failed)" + echo "-- Building boco VM..." + if ! "$BOCO_BIN" build qcow2 "$img" >/dev/null 2>&1; then + report fail "nextcloud service (boco build failed)" cleanup "$img" "$img" rm -rf "$work" return fi echo "-- Booting VM with port forward (host :${host_port} -> guest :80)..." - setsid timeout 300 "$SLIM_BIN" run "$img" \ + setsid timeout 300 "$BOCO_BIN" boot "$img" \ --forward "tcp:0.0.0.0:${host_port}-:80" \ --memory 2048M >/dev/null 2>&1 & vm_pid=$! @@ -299,11 +299,11 @@ test_systemd() { echo "=== Testing systemd as init ===" work="$(mktemp -d)" - img="slim-test-systemd" + img="boco-test-systemd" - cat > "$work/slim-test.service" <<'SVC' + cat > "$work/boco-test.service" <<'SVC' [Unit] -Description=slim systemd test +Description=boco systemd test After=multi-user.target [Service] @@ -316,10 +316,10 @@ SVC cat > "$work/Containerfile" </dev/null 2>&1; then - report fail "systemd as init (slim build failed)" + echo "-- Building boco VM..." + if ! "$BOCO_BIN" build qcow2 "$img" >/dev/null 2>&1; then + report fail "systemd as init (boco build failed)" cleanup "$img" "$img" rm -rf "$work" return fi echo "-- Booting VM (systemd as PID 1)..." - output=$(timeout "$TIMEOUT" "$SLIM_BIN" run "$img" 2>&1 || true) + output=$(timeout "$TIMEOUT" "$BOCO_BIN" boot "$img" 2>&1 || true) check_output "$output" "SYSTEMD_TEST_OK" "systemd boots and runs service" check_output "$output" "reboot: Power down" "systemd shuts down cleanly" @@ -347,11 +347,11 @@ EOF rm -rf "$work" } -echo "Building slim..." +echo "Building boco..." cargo build 2>&1 -cargo build --release -p slim-init --target x86_64-unknown-linux-musl 2>&1 -cp target/x86_64-unknown-linux-musl/release/slim-init \ - "${XDG_DATA_HOME:-$HOME/.local/share}/slim-rs/slim-init" +cargo build --release -p boco-init --target x86_64-unknown-linux-musl 2>&1 +cp "$TARGET_DIR/x86_64-unknown-linux-musl/release/boco-init" \ + "${XDG_DATA_HOME:-$HOME/.local/share}/boco/boco-init" test_distro "alpine" "alpine:latest" "" test_distro "archlinux" "archlinux:latest" "RUN pacman -Sy --noconfirm iproute2 wget; pacman -Sc --noconfirm" diff --git a/init/Cargo.toml b/init/Cargo.toml index 8841b26..8d2f86e 100644 --- a/init/Cargo.toml +++ b/init/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "slim-init" +name = "boco-init" version = "0.1.0" edition = "2024" diff --git a/init/src/main.rs b/init/src/main.rs index 0bba306..c510a74 100644 --- a/init/src/main.rs +++ b/init/src/main.rs @@ -1,6 +1,6 @@ -//! slim universal init. +//! boco universal init. //! -//! Injected by `slim build` at /slim/init and invoked via init=/slim/init. +//! Injected by `boco build` at /boco/init and invoked via init=/boco/init. //! Sets up devices, filesystems, networking, and 9p shares, then execs the //! container's CMD/ENTRYPOINT (or a runtime override) with execvp so the //! command becomes PID 1 directly. @@ -19,7 +19,7 @@ use std::path::Path; use std::process::Command; fn warn(msg: &str) { - eprintln!("slim-init: {msg}"); + eprintln!("boco-init: {msg}"); } /// Run a fallible operation, logging on error. @@ -219,7 +219,7 @@ fn setup_9p_shares(workdir: &str) { let b64 = base64::engine::general_purpose::STANDARD; for tok in cmdline.split_whitespace() { - if let Some(rest) = tok.strip_prefix("slim.mount=") { + if let Some(rest) = tok.strip_prefix("boco.mount=") { let Some((tag, dest_b64)) = rest.split_once(':') else { continue; }; @@ -270,11 +270,11 @@ fn split_null_delimited(data: &[u8]) -> Vec { } fn read_argv() -> Vec { - // Check for runtime override: slim.cmd= + // Check for runtime override: boco.cmd= let b64 = base64::engine::general_purpose::STANDARD; if let Ok(cmdline) = fs::read_to_string("/proc/cmdline") { for tok in cmdline.split_whitespace() { - if let Some(rest) = tok.strip_prefix("slim.cmd=") + if let Some(rest) = tok.strip_prefix("boco.cmd=") && let Ok(decoded) = b64.decode(rest) { let argv = split_null_delimited(&decoded); @@ -285,15 +285,15 @@ fn read_argv() -> Vec { } } - // Fall back to build-time argv from /slim/exec - match fs::read("/slim/exec") { + // Fall back to build-time argv from /boco/exec + match fs::read("/boco/exec") { Ok(data) => { let argv = split_null_delimited(&data); if !argv.is_empty() { return argv; } } - Err(e) => warn(&format!("read /slim/exec: {e}")), + Err(e) => warn(&format!("read /boco/exec: {e}")), } warn("no command found, falling back to /bin/sh"); @@ -301,7 +301,7 @@ fn read_argv() -> Vec { } fn apply_env() { - if let Ok(data) = fs::read("/slim/env") { + if let Ok(data) = fs::read("/boco/env") { for entry in split_null_delimited(&data) { if let Some((key, val)) = entry.split_once('=') { // SAFETY: we are single-threaded before fork/exec. @@ -312,7 +312,7 @@ fn apply_env() { } fn apply_workdir() { - if let Some(dir) = read_file_opt("/slim/workdir") { + if let Some(dir) = read_file_opt("/boco/workdir") { try_io("set working directory", || env::set_current_dir(&dir)); } } @@ -413,7 +413,7 @@ fn main() { setup_networking(); // === 9p shares === - let workdir = read_file_opt("/slim/workdir").unwrap_or_default(); + let workdir = read_file_opt("/boco/workdir").unwrap_or_default(); setup_9p_shares(&workdir); // === Environment & working directory === @@ -421,7 +421,7 @@ fn main() { apply_workdir(); // === Resolve user for privilege drop === - let user = read_file_opt("/slim/user").and_then(|spec| resolve_user(&spec)); + let user = read_file_opt("/boco/user").and_then(|spec| resolve_user(&spec)); // === Execute the configured command === let argv = read_argv(); diff --git a/kernel/config b/kernel/config index e1d9e79..534454c 100644 --- a/kernel/config +++ b/kernel/config @@ -41,7 +41,7 @@ CONFIG_THREAD_INFO_IN_TASK=y CONFIG_INIT_ENV_ARG_LIMIT=32 # CONFIG_COMPILE_TEST is not set CONFIG_WERROR=y -CONFIG_LOCALVERSION="-slim" +CONFIG_LOCALVERSION="-boco" CONFIG_LOCALVERSION_AUTO=y CONFIG_BUILD_SALT="" CONFIG_HAVE_KERNEL_GZIP=y diff --git a/src/build.rs b/src/build.rs index 47f5400..87bf108 100644 --- a/src/build.rs +++ b/src/build.rs @@ -1,4 +1,4 @@ -//! Build: mount a podman image, inject /slim/ scripts, and pack the rootfs +//! Build: mount a podman image, inject /boco/ scripts, and pack the rootfs //! as a gzipped cpio initrd or qcow2 disk in the registry. use anyhow::{Context, Result, bail}; @@ -41,7 +41,7 @@ pub(crate) fn build( }: BuildCmd, ) -> Result<()> { let image = &name; - let container = format!("slim-build-{}", image.replace(':', "-")); + let container = format!("boco-build-{}", image.replace(':', "-")); let mount_path = mount_container(image, &container)?; println!("Mounted at: {}", mount_path.display()); @@ -86,7 +86,7 @@ fn build_inner( config.user.as_deref(), config.working_dir.as_deref(), )?; - println!("Injected /slim/ (init + exec)"); + println!("Injected /boco/ (init + exec)"); match kind { ImageKind::Initrd => build_initrd(image, mount_path), diff --git a/src/inject.rs b/src/inject.rs index 845a65d..1bb772d 100644 --- a/src/inject.rs +++ b/src/inject.rs @@ -1,5 +1,5 @@ //! Inject: inspect a podman image's config, infer the default command argv, -//! and inject the slim init binary + null-delimited argv/env files into the +//! and inject the boco init binary + null-delimited argv/env files into the //! mounted rootfs. use anyhow::{Context, Result, anyhow}; @@ -68,21 +68,21 @@ pub fn null_delimited(items: &[String]) -> Vec { data } -/// Install `content` into the mounted rootfs at `/slim/` with +/// Install `content` into the mounted rootfs at `/boco/` with /// the given mode. fn install_into_rootfs(mount: &str, name: &str, mode: &str, content: &[u8]) -> Result<()> { let temp = tempfile::NamedTempFile::new()?; fs::write(temp.path(), content)?; let src = temp.path().to_str().context("temp path is not UTF-8")?; - let dest = format!("{mount}/slim/{name}"); + let dest = format!("{mount}/boco/{name}"); cmd(&[ "podman", "unshare", "--", "install", "-D", "-m", mode, src, &dest, ])?; Ok(()) } -/// Inject /slim/init (binary), /slim/exec (null-delimited argv), /slim/env -/// (null-delimited env), and optionally /slim/user and /slim/workdir into a +/// Inject /boco/init (binary), /boco/exec (null-delimited argv), /boco/env +/// (null-delimited env), and optionally /boco/user and /boco/workdir into a /// mounted container image rootfs. pub fn inject( mount_path: &Path, @@ -93,7 +93,7 @@ pub fn inject( ) -> Result<()> { let mount_str = mount_path.to_str().context("mount path is not UTF-8")?; - let init_binary = fs::read(init_binary_path()?).context("Failed to read slim-init binary")?; + let init_binary = fs::read(init_binary_path()?).context("Failed to read boco-init binary")?; let exec_data = null_delimited(argv); let env_data = null_delimited(env); diff --git a/src/main.rs b/src/main.rs index 3151ff7..7acf046 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,7 +9,7 @@ mod registry; use anyhow::Result; use clap::{Parser, Subcommand}; -use crate::{build::BuildCmd, image::ImageCmd, qemu::RunCmd}; +use crate::{build::BuildCmd, image::ImageCmd, qemu::BootCmd}; #[derive(Parser, Debug)] #[command(about = "Turn containers into bootable VMs")] @@ -23,8 +23,8 @@ enum Commands { /// Build initrd from an image (podman image must exist) Build(BuildCmd), /// Launch a previously built VM via QEMU. - Run(RunCmd), - /// List slim images in the registry + Boot(BootCmd), + /// List boco images in the registry #[command(subcommand)] Image(ImageCmd), } @@ -35,8 +35,8 @@ fn main() -> Result<()> { Commands::Build(cmd) => { build::build(cmd)?; } - Commands::Run(cmd) => { - qemu::run(cmd)?; + Commands::Boot(cmd) => { + qemu::boot(cmd)?; } Commands::Image(cmd) => { image::run(cmd)?; diff --git a/src/qemu.rs b/src/qemu.rs index c054f27..7d2ab5e 100644 --- a/src/qemu.rs +++ b/src/qemu.rs @@ -1,8 +1,8 @@ //! QEMU: boot a registry entry with qemu-system-x86_64 using direct kernel //! boot (-kernel/-initrd or -drive). The kernel is shared across all VMs -//! at $XDG_DATA_HOME/slim-rs/registry/vmlinuz. A universal /slim/init script (injected -//! at build time) handles VM bootstrap; /slim/exec runs the container's -//! CMD/ENTRYPOINT. Runtime overrides are delivered as `slim.cmd=` +//! at $XDG_DATA_HOME/boco/registry/vmlinuz. A universal /boco/init script (injected +//! at build time) handles VM bootstrap; /boco/exec runs the container's +//! CMD/ENTRYPOINT. Runtime overrides are delivered as `boco.cmd=` //! on the kernel cmdline. use anyhow::{Context, Result, bail}; @@ -16,7 +16,7 @@ use crate::{ }; #[derive(Args, Debug)] -pub struct RunCmd { +pub struct BootCmd { /// Image tag / registry subdir name name: String, @@ -29,7 +29,7 @@ pub struct RunCmd { forward: Vec, /// Override the command to exec in the VM (base64-encoded on the kernel - /// cmdline as slim.cmd=). Overrides the CMD inferred at build time. + /// cmdline as boco.cmd=). Overrides the CMD inferred at build time. #[clap(long)] cmd: Option, @@ -41,14 +41,14 @@ pub struct RunCmd { mount: Vec, } -pub(crate) fn run( - RunCmd { +pub(crate) fn boot( + BootCmd { name, memory, forward, cmd, mount, - }: RunCmd, + }: BootCmd, ) -> Result<()> { let reg_dir = registry_dir(&name)?; let vmlinuz_path = registry_base_dir()?.join("vmlinuz"); @@ -67,7 +67,7 @@ pub(crate) fn run( "rw".into(), "earlyprintk=serial".into(), "nokaslr".into(), - "init=/slim/init".into(), + "init=/boco/init".into(), "devtmpfs.mount=1".into(), // Automatically mount /dev at boot ]; @@ -81,19 +81,19 @@ pub(crate) fn run( fs_args = vec!["-initrd".to_string(), initrd_str]; cmdline.push("root=/dev/ram0".into()); } else { - bail!("Registry missing rootfs/initrd for '{name}'. Run `slim build` first."); + bail!("Registry missing rootfs/initrd for '{name}'. Run `boco build` first."); } if let Some(cmd) = &cmd { let argv = ["/bin/sh".to_string(), "-c".to_string(), cmd.clone()]; let data: Vec = argv.join("\0").into_bytes(); let encoded = base64::engine::general_purpose::STANDARD.encode(&data); - cmdline.push(format!("slim.cmd={encoded}")); + cmdline.push(format!("boco.cmd={encoded}")); } - // Build 9p shares for each --mount. Tags are short (slim0, slim1, …) + // Build 9p shares for each --mount. Tags are short (boco0, boco1, …) // because 9p mount_tag has a ~31-byte limit. The guest destination path - // is passed on the kernel cmdline as slim.mount=:. + // is passed on the kernel cmdline as boco.mount=:. // If no guest path is specified, the host path is used as the guest path. let mut virtfs_args: Vec = Vec::new(); for (i, spec) in mount.iter().enumerate() { @@ -107,7 +107,7 @@ pub(crate) fn run( let host_str = canonical .to_str() .context("Mount path is not valid UTF-8")?; - let tag = format!("slim{i}"); + let tag = format!("boco{i}"); let dest_b64 = base64::engine::general_purpose::STANDARD.encode(guest_path.as_bytes()); // QEMU's QemuOpts splits on commas — escape literal commas in the @@ -117,7 +117,7 @@ pub(crate) fn run( virtfs_args.push(format!( "local,path={host_escaped},mount_tag={tag},security_model=mapped-xattr" )); - cmdline.push(format!("slim.mount={tag}:{dest_b64}")); + cmdline.push(format!("boco.mount={tag}:{dest_b64}")); } println!("Booting {name} from registry: {}", reg_dir.display()); diff --git a/src/registry.rs b/src/registry.rs index 33e6602..8caf92e 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -1,12 +1,12 @@ //! Registry: local storage of built VM artifacts under -//! `$XDG_DATA_HOME/slim-rs/registry//`. +//! `$XDG_DATA_HOME/boco/registry//`. use anyhow::{Context, Result, anyhow, bail}; use std::{fs, io, path::PathBuf}; /// Validate a user-supplied image name before it is used in a registry path. /// -/// The name becomes a directory under `$XDG_DATA_HOME/slim-rs/registry/`, so +/// The name becomes a directory under `$XDG_DATA_HOME/boco/registry/`, so /// path separators and `.`/`..` would allow escaping that directory. /// Allow-list: ASCII alphanumerics plus `.`, `_`, `:`, `-` (covers image /// refs like `alpine:3.15`). @@ -27,15 +27,15 @@ pub(crate) fn validate_image_name(name: &str) -> Result<()> { } pub(crate) fn registry_base_dir() -> Result { - let base = xdg::BaseDirectories::with_prefix("slim-rs"); + let base = xdg::BaseDirectories::with_prefix("boco"); base.create_data_directory("registry") .context("Failed to create XDG_DATA_HOME subdirectory") } pub(crate) fn init_binary_path() -> Result { - let base = xdg::BaseDirectories::with_prefix("slim-rs"); - base.get_data_file("slim-init") - .context("slim-init not found in XDG data dir") + let base = xdg::BaseDirectories::with_prefix("boco"); + base.get_data_file("boco-init") + .context("boco-init not found in XDG data dir") } pub(crate) fn registry_dir(image: &str) -> Result { @@ -62,7 +62,7 @@ mod tests { fn accepts_valid_image_names() { for name in [ "alpine:3.15", - "slim", + "boco", "mock-vm", "my_vm", "a.b.c",