banger/scripts/make-rootfs-void.sh
Thales Maciel 01c7cb5e65
Reorganize the source checkout layout
Separate tracked source from generated artifacts so the repo root stops accumulating helper scripts, manifests, and local runtime outputs.

Move manual shell entrypoints under scripts/, manifests under config/, and the Firecracker API reference under docs/reference/. Make build and runtimebundle now target build/bin, build/runtime, and build/dist as the canonical source-checkout paths.

Update runtime discovery, helper scripts, tests, and docs to follow the new layout while keeping legacy source-checkout runtime fallbacks for existing local bundles during migration.

Validated with bash -n on the moved scripts, make build, and GOCACHE=/tmp/banger-gocache go test ./....
2026-03-21 17:22:57 -03:00

624 lines
18 KiB
Bash
Executable file

#!/usr/bin/env bash
set -euo pipefail
log() {
printf '[make-rootfs-void] %s\n' "$*"
}
usage() {
cat <<'EOF'
Usage: ./scripts/make-rootfs-void.sh [--out <path>] [--size <size>] [--mirror <url>] [--arch <arch>] [--packages <path>]
Build an experimental Void Linux rootfs image plus a matching /root work-seed.
Defaults:
--out ./build/runtime/rootfs-void.ext4
--size 2G
--mirror https://repo-default.voidlinux.org
--arch x86_64
--packages ./config/packages.void
This path is experimental and local-only. If ./build/runtime/void-kernel exists
it uses the staged Void kernel modules from that directory; otherwise it falls
back to the current runtime bundle modules. It does not change the default
Debian image flow.
EOF
}
parse_size() {
local raw="$1"
if [[ "$raw" =~ ^([0-9]+)([KMG])?$ ]]; then
local num="${BASH_REMATCH[1]}"
local unit="${BASH_REMATCH[2]}"
case "$unit" in
K) printf '%s\n' $((num * 1024)) ;;
M|"") printf '%s\n' $((num * 1024 * 1024)) ;;
G) printf '%s\n' $((num * 1024 * 1024 * 1024)) ;;
esac
return 0
fi
return 1
}
require_command() {
local name="$1"
command -v "$name" >/dev/null 2>&1 || {
log "required command not found: $name"
exit 1
}
}
resolve_banger_bin() {
if [[ -n "${BANGER_BIN:-}" ]]; then
printf '%s\n' "$BANGER_BIN"
return
fi
if [[ -x "$REPO_ROOT/build/bin/banger" ]]; then
printf '%s\n' "$REPO_ROOT/build/bin/banger"
return
fi
if [[ -x "$REPO_ROOT/banger" ]]; then
printf '%s\n' "$REPO_ROOT/banger"
return
fi
if command -v banger >/dev/null 2>&1; then
command -v banger
return
fi
log "banger binary not found; build it first with 'make build' or set BANGER_BIN"
exit 1
}
normalize_mirror() {
local mirror="${1%/}"
mirror="${mirror%/current}"
mirror="${mirror%/static}"
printf '%s\n' "$mirror"
}
bundle_path() {
local key="$1"
local fallback="$2"
local rel=""
if [[ -f "$BUNDLE_METADATA" ]] && command -v jq >/dev/null 2>&1; then
rel="$(jq -r --arg key "$key" '.[$key] // empty' "$BUNDLE_METADATA" 2>/dev/null || true)"
fi
if [[ -n "$rel" && "$rel" != "null" ]]; then
printf '%s\n' "$RUNTIME_DIR/$rel"
return
fi
printf '%s\n' "$fallback"
}
find_latest_module_dir() {
local root="$1"
if [[ ! -d "$root" ]]; then
return 1
fi
find "$root" -mindepth 1 -maxdepth 1 -type d | sort | tail -n 1
}
find_static_binary() {
local name="$1"
find "$STATIC_DIR" -type f \( -name "$name" -o -name "$name.static" \) -perm -u+x | sort | head -n 1
}
find_static_keys_dir() {
find "$STATIC_DIR" -type d -path '*/var/db/xbps/keys' | sort | head -n 1
}
install_root_authorized_key() {
local public_key
public_key="$(ssh-keygen -y -f "$SSH_KEY")"
sudo mkdir -p "$ROOT_MOUNT/root/.ssh"
printf '%s\n' "$public_key" | sudo tee "$ROOT_MOUNT/root/.ssh/authorized_keys" >/dev/null
sudo chmod 700 "$ROOT_MOUNT/root/.ssh"
sudo chmod 600 "$ROOT_MOUNT/root/.ssh/authorized_keys"
}
ensure_sshd_include() {
local cfg="$ROOT_MOUNT/etc/ssh/sshd_config"
local tmp_cfg="$TMP_DIR/sshd_config"
local include_line="Include /etc/ssh/sshd_config.d/*.conf"
sudo mkdir -p "$ROOT_MOUNT/etc/ssh/sshd_config.d"
if sudo test -f "$cfg"; then
sudo cat "$cfg" > "$tmp_cfg"
else
: > "$tmp_cfg"
fi
if ! grep -Eq '^[[:space:]]*Include[[:space:]]+/etc/ssh/sshd_config\.d/\*\.conf([[:space:]]|$)' "$tmp_cfg"; then
{
printf '%s\n' "$include_line"
cat "$tmp_cfg"
} > "${tmp_cfg}.new"
mv "${tmp_cfg}.new" "$tmp_cfg"
sudo install -m 0644 "$tmp_cfg" "$cfg"
fi
}
install_vsock_service() {
local service_dir="$ROOT_MOUNT/etc/sv/banger-vsock-agent"
local run_path="$service_dir/run"
local finish_path="$service_dir/finish"
sudo mkdir -p "$service_dir"
cat <<'EOF' | sudo tee "$run_path" >/dev/null
#!/bin/sh
modprobe vsock 2>/dev/null || true
modprobe vmw_vsock_virtio_transport 2>/dev/null || true
exec /usr/local/bin/banger-vsock-agent
EOF
cat <<'EOF' | sudo tee "$finish_path" >/dev/null
#!/bin/sh
exit 0
EOF
sudo chmod 0755 "$run_path" "$finish_path"
sudo mkdir -p "$ROOT_MOUNT/etc/runit/runsvdir/default"
sudo ln -snf /etc/sv/banger-vsock-agent "$ROOT_MOUNT/etc/runit/runsvdir/default/banger-vsock-agent"
}
install_opencode_service() {
local service_dir="$ROOT_MOUNT/etc/sv/banger-opencode"
local run_path="$service_dir/run"
local finish_path="$service_dir/finish"
sudo mkdir -p "$service_dir"
cat <<'EOF' | sudo tee "$run_path" >/dev/null
#!/bin/sh
set -e
export HOME=/root
cd /root
exec /usr/local/bin/opencode serve --hostname 0.0.0.0 --port 4096
EOF
cat <<'EOF' | sudo tee "$finish_path" >/dev/null
#!/bin/sh
exit 0
EOF
sudo chmod 0755 "$run_path" "$finish_path"
sudo mkdir -p "$ROOT_MOUNT/etc/runit/runsvdir/default"
sudo ln -snf /etc/sv/banger-opencode "$ROOT_MOUNT/etc/runit/runsvdir/default/banger-opencode"
}
install_guest_network_bootstrap() {
sudo mkdir -p "$ROOT_MOUNT/usr/local/libexec" "$ROOT_MOUNT/etc/runit/core-services"
sudo install -m 0755 "$GUESTNET_BOOTSTRAP_SCRIPT" "$ROOT_MOUNT/usr/local/libexec/banger-network-bootstrap"
sudo install -m 0644 "$GUESTNET_VOID_CORE_SERVICE" "$ROOT_MOUNT/etc/runit/core-services/20-banger-network.sh"
}
configure_docker_bootstrap() {
local modules_conf="$ROOT_MOUNT/etc/modules-load.d/docker-netfilter.conf"
local sysctl_conf="$ROOT_MOUNT/etc/sysctl.d/99-docker.conf"
local service_dir="$ROOT_MOUNT/etc/sv/docker"
local run_path="$service_dir/run"
local orig_run_path="$service_dir/run.orig"
local preflight_path="$ROOT_MOUNT/usr/local/bin/banger-docker-preflight"
sudo mkdir -p "$ROOT_MOUNT/etc/modules-load.d" "$ROOT_MOUNT/etc/sysctl.d" "$ROOT_MOUNT/usr/local/bin"
cat <<'EOF' | sudo tee "$modules_conf" >/dev/null
nf_tables
nft_chain_nat
veth
br_netfilter
overlay
EOF
cat <<'EOF' | sudo tee "$sysctl_conf" >/dev/null
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
cat <<'EOF' | sudo tee "$preflight_path" >/dev/null
#!/bin/sh
for module in nf_tables nft_chain_nat veth br_netfilter overlay; do
modprobe "$module" 2>/dev/null || true
done
if command -v sysctl >/dev/null 2>&1; then
sysctl --load /etc/sysctl.d/99-docker.conf >/dev/null 2>&1 || true
fi
EOF
if [[ ! -f "$run_path" ]]; then
log "Void rootfs is missing /etc/sv/docker/run after docker install"
exit 1
fi
sudo install -m 0755 "$run_path" "$orig_run_path"
cat <<'EOF' | sudo tee "$run_path" >/dev/null
#!/bin/sh
set -e
/usr/local/bin/banger-docker-preflight
exec /etc/sv/docker/run.orig
EOF
sudo chmod 0644 "$modules_conf" "$sysctl_conf"
sudo chmod 0755 "$preflight_path" "$run_path" "$orig_run_path"
}
enable_sshd_service() {
if [[ ! -d "$ROOT_MOUNT/etc/sv/sshd" ]]; then
log "Void rootfs is missing /etc/sv/sshd after openssh install"
exit 1
fi
sudo mkdir -p "$ROOT_MOUNT/etc/runit/runsvdir/default"
sudo ln -snf /etc/sv/sshd "$ROOT_MOUNT/etc/runit/runsvdir/default/sshd"
}
enable_docker_service() {
if [[ ! -d "$ROOT_MOUNT/etc/sv/docker" ]]; then
log "Void rootfs is missing /etc/sv/docker after docker install"
exit 1
fi
sudo mkdir -p "$ROOT_MOUNT/etc/runit/runsvdir/default"
sudo ln -snf /etc/sv/docker "$ROOT_MOUNT/etc/runit/runsvdir/default/docker"
}
normalize_root_shell() {
local passwd="$ROOT_MOUNT/etc/passwd"
local shells="$ROOT_MOUNT/etc/shells"
local wanted_shell="/bin/bash"
local tmp_passwd="$TMP_DIR/passwd"
local root_shell=""
if [[ ! -x "$ROOT_MOUNT$wanted_shell" ]]; then
log "required root shell is missing from the Void image: $wanted_shell"
exit 1
fi
if [[ ! -f "$shells" ]]; then
log "Void image is missing /etc/shells"
exit 1
fi
if ! sudo grep -Fxq "$wanted_shell" "$shells"; then
log "Void image does not allow $wanted_shell in /etc/shells"
exit 1
fi
sudo cat "$passwd" > "$tmp_passwd"
awk -F: -v OFS=: -v shell="$wanted_shell" '
$1 == "root" {
$7 = shell
found = 1
}
{ print }
END {
if (!found) {
exit 1
}
}
' "$tmp_passwd" > "${tmp_passwd}.new" || {
log "failed to rewrite root shell in /etc/passwd"
exit 1
}
mv "${tmp_passwd}.new" "$tmp_passwd"
sudo install -m 0644 "$tmp_passwd" "$passwd"
root_shell="$(sudo awk -F: '$1 == "root" { print $7 }' "$passwd")"
if [[ "$root_shell" != "$wanted_shell" ]]; then
log "root shell normalization failed: expected $wanted_shell, got ${root_shell:-<empty>}"
exit 1
fi
}
configure_root_bash_prompt() {
local bashrc="$ROOT_MOUNT/root/.bashrc"
local bash_profile="$ROOT_MOUNT/root/.bash_profile"
local profile_prompt="$ROOT_MOUNT/etc/profile.d/banger-bash-prompt.sh"
sudo mkdir -p "$ROOT_MOUNT/root" "$ROOT_MOUNT/etc/profile.d"
cat <<'EOF' | sudo tee "$bashrc" >/dev/null
# banger: default interactive prompt for experimental Void guests
case "$-" in
*i*) ;;
*) return ;;
esac
if [ -z "${BANGER_MISE_ACTIVATED:-}" ] && [ -x '/usr/local/bin/mise' ]; then
export BANGER_MISE_ACTIVATED=1
eval "$(/usr/local/bin/mise activate bash)"
fi
PS1='\u@\h:\w\$ '
EOF
cat <<'EOF' | sudo tee "$bash_profile" >/dev/null
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
EOF
cat <<'EOF' | sudo tee "$profile_prompt" >/dev/null
case "$-" in
*i*) ;;
*) return 0 2>/dev/null || exit 0 ;;
esac
if [ -n "${BASH_VERSION:-}" ]; then
PS1='\u@\h:\w\$ '
fi
EOF
sudo chmod 0644 "$bashrc" "$bash_profile" "$profile_prompt"
}
install_mise_and_opencode() {
local profile_mise="$ROOT_MOUNT/etc/profile.d/mise.sh"
sudo mkdir -p "$ROOT_MOUNT/etc/profile.d"
if [[ -r /etc/resolv.conf ]]; then
sudo install -m 0644 /etc/resolv.conf "$ROOT_MOUNT/etc/resolv.conf"
fi
sudo env \
HOME=/root \
PATH=/usr/local/bin:/usr/bin:/bin \
chroot "$ROOT_MOUNT" /bin/bash -se <<EOF
set -euo pipefail
curl -fsSL https://mise.run | MISE_INSTALL_PATH="$MISE_INSTALL_PATH" MISE_VERSION="$MISE_VERSION" sh
"$MISE_INSTALL_PATH" use -g "$OPENCODE_TOOL"
"$MISE_INSTALL_PATH" reshim
if [[ ! -e /root/.local/share/mise/shims/opencode ]]; then
echo "opencode shim not found after mise install" >&2
exit 1
fi
ln -snf /root/.local/share/mise/shims/opencode /usr/local/bin/opencode
EOF
cat <<'EOF' | sudo tee "$profile_mise" >/dev/null
if [ -n "${BASH_VERSION:-}" ] && [ -z "${BANGER_MISE_ACTIVATED:-}" ] && [ -x '/usr/local/bin/mise' ]; then
export BANGER_MISE_ACTIVATED=1
eval "$(/usr/local/bin/mise activate bash)"
fi
EOF
sudo chmod 0644 "$profile_mise"
}
cleanup() {
if [[ -n "${ROOT_MOUNT:-}" ]] && command -v mountpoint >/dev/null 2>&1 && mountpoint -q "$ROOT_MOUNT"; then
sudo umount "$ROOT_MOUNT" || true
fi
if [[ "${BUILD_DONE:-0}" != "1" ]]; then
rm -f "${OUT_ROOTFS:-}" "${WORK_SEED:-}" "${OUT_ROOTFS:-}.packages.sha256"
fi
if [[ -n "${TMP_DIR:-}" && -d "${TMP_DIR:-}" ]]; then
rm -rf "$TMP_DIR"
fi
}
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
PACKAGES_FILE="$REPO_ROOT/config/packages.void"
export BANGER_APT_PACKAGES_FILE="$PACKAGES_FILE"
source "$SCRIPT_DIR/lib/packages.sh"
DEFAULT_RUNTIME_DIR="$REPO_ROOT/build/runtime"
if [[ ! -d "$DEFAULT_RUNTIME_DIR" && -d "$REPO_ROOT/runtime" ]]; then
DEFAULT_RUNTIME_DIR="$REPO_ROOT/runtime"
fi
RUNTIME_DIR="${BANGER_RUNTIME_DIR:-$DEFAULT_RUNTIME_DIR}"
if [[ ! -d "$RUNTIME_DIR" ]]; then
log "runtime bundle not found: $RUNTIME_DIR"
log "run 'make runtime-bundle' or set BANGER_RUNTIME_DIR"
exit 1
fi
BUNDLE_METADATA="$RUNTIME_DIR/bundle.json"
SSH_KEY="$(bundle_path ssh_key_path "$RUNTIME_DIR/id_ed25519")"
OUT_ROOTFS="$RUNTIME_DIR/rootfs-void.ext4"
SIZE_SPEC="2G"
MIRROR="https://repo-default.voidlinux.org"
ARCH="x86_64"
MISE_VERSION="v2025.12.0"
MISE_INSTALL_PATH="/usr/local/bin/mise"
OPENCODE_TOOL="github:anomalyco/opencode"
GUESTNET_BOOTSTRAP_SCRIPT="$REPO_ROOT/internal/guestnet/assets/bootstrap.sh"
GUESTNET_VOID_CORE_SERVICE="$REPO_ROOT/internal/guestnet/assets/void-core-service.sh"
MODULES_DIR="$(bundle_path default_modules_dir "$RUNTIME_DIR/wtf/root/lib/modules/6.8.0-94-generic")"
VOID_KERNEL_MODULES_DIR="$(find_latest_module_dir "$RUNTIME_DIR/void-kernel/lib/modules" || true)"
VSOCK_AGENT="$(bundle_path vsock_agent_path "$RUNTIME_DIR/banger-vsock-agent")"
if [[ "$VSOCK_AGENT" == "$RUNTIME_DIR/banger-vsock-agent" && ! -x "$VSOCK_AGENT" ]]; then
VSOCK_AGENT="$(bundle_path vsock_ping_helper_path "$RUNTIME_DIR/banger-vsock-pingd")"
fi
if [[ -n "$VOID_KERNEL_MODULES_DIR" ]]; then
MODULES_DIR="$VOID_KERNEL_MODULES_DIR"
fi
while [[ $# -gt 0 ]]; do
case "$1" in
--out)
OUT_ROOTFS="${2:-}"
shift 2
;;
--size)
SIZE_SPEC="${2:-}"
shift 2
;;
--mirror)
MIRROR="${2:-}"
shift 2
;;
--arch)
ARCH="${2:-}"
shift 2
;;
--packages)
PACKAGES_FILE="${2:-}"
export BANGER_APT_PACKAGES_FILE="$PACKAGES_FILE"
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
log "unknown option: $1"
usage
exit 1
;;
esac
done
MIRROR="$(normalize_mirror "$MIRROR")"
REPO_URL="$MIRROR/current"
STATIC_ARCHIVE_URL="$MIRROR/static/xbps-static-latest.x86_64-musl.tar.xz"
if [[ "$ARCH" != "x86_64" ]]; then
log "unsupported arch: $ARCH"
log "this experimental builder currently supports only x86_64-glibc"
exit 1
fi
if [[ ! -f "$PACKAGES_FILE" ]]; then
log "package manifest not found: $PACKAGES_FILE"
exit 1
fi
if [[ ! -d "$MODULES_DIR" ]]; then
log "modules dir not found: $MODULES_DIR"
exit 1
fi
if [[ ! -x "$VSOCK_AGENT" ]]; then
log "vsock agent not found or not executable: $VSOCK_AGENT"
log "run 'make build' or refresh the runtime bundle"
exit 1
fi
if [[ ! -f "$GUESTNET_BOOTSTRAP_SCRIPT" ]]; then
log "guest network bootstrap script not found: $GUESTNET_BOOTSTRAP_SCRIPT"
exit 1
fi
if [[ ! -f "$GUESTNET_VOID_CORE_SERVICE" ]]; then
log "guest network core-service shim not found: $GUESTNET_VOID_CORE_SERVICE"
exit 1
fi
if [[ -e "$OUT_ROOTFS" ]]; then
log "output rootfs already exists: $OUT_ROOTFS"
exit 1
fi
require_command curl
require_command tar
require_command sudo
require_command mkfs.ext4
require_command ssh-keygen
require_command mount
require_command umount
require_command install
require_command find
require_command awk
require_command sed
require_command sha256sum
require_command truncate
require_command mountpoint
VOID_PACKAGES=()
if ! banger_packages_read_array VOID_PACKAGES "$PACKAGES_FILE"; then
log "package manifest is empty: $PACKAGES_FILE"
exit 1
fi
if ! PACKAGES_HASH="$(banger_packages_manifest_hash "$PACKAGES_FILE")"; then
log "failed to hash package manifest: $PACKAGES_FILE"
exit 1
fi
if ! SIZE_BYTES="$(parse_size "$SIZE_SPEC")"; then
log "invalid size: $SIZE_SPEC"
exit 1
fi
BANGER_BIN="$(resolve_banger_bin)"
if [[ "$OUT_ROOTFS" == *.ext4 ]]; then
WORK_SEED="${OUT_ROOTFS%.ext4}.work-seed.ext4"
else
WORK_SEED="${OUT_ROOTFS}.work-seed"
fi
TMP_DIR="$(mktemp -d -t banger-void-rootfs-XXXXXX)"
STATIC_DIR="$TMP_DIR/static"
ROOT_MOUNT="$TMP_DIR/rootfs"
STATIC_ARCHIVE="$TMP_DIR/xbps-static.tar.xz"
BUILD_DONE=0
trap cleanup EXIT
mkdir -p "$STATIC_DIR" "$ROOT_MOUNT"
log "downloading static XBPS from $STATIC_ARCHIVE_URL"
curl -fsSL "$STATIC_ARCHIVE_URL" -o "$STATIC_ARCHIVE"
tar -xf "$STATIC_ARCHIVE" -C "$STATIC_DIR"
XBPS_INSTALL="$(find_static_binary xbps-install)"
XBPS_QUERY="$(find_static_binary xbps-query)"
STATIC_KEYS_DIR="$(find_static_keys_dir)"
if [[ -z "$XBPS_INSTALL" || ! -x "$XBPS_INSTALL" ]]; then
log "failed to locate xbps-install in the static archive"
exit 1
fi
if [[ -z "$STATIC_KEYS_DIR" || ! -d "$STATIC_KEYS_DIR" ]]; then
log "failed to locate Void repository keys in the static archive"
exit 1
fi
log "creating $OUT_ROOTFS ($SIZE_SPEC)"
truncate -s "$SIZE_BYTES" "$OUT_ROOTFS"
mkfs.ext4 -F -m 0 -L banger-void-root "$OUT_ROOTFS" >/dev/null
sudo mount -o loop "$OUT_ROOTFS" "$ROOT_MOUNT"
sudo mkdir -p "$ROOT_MOUNT/var/db/xbps/keys"
sudo cp -a "$STATIC_KEYS_DIR/." "$ROOT_MOUNT/var/db/xbps/keys/"
log "installing Void packages into the rootfs"
sudo env XBPS_ARCH="$ARCH" "$XBPS_INSTALL" -S -y -r "$ROOT_MOUNT" -R "$REPO_URL" "${VOID_PACKAGES[@]}"
if [[ -n "$XBPS_QUERY" && -x "$XBPS_QUERY" ]]; then
log "installed package set:"
sudo env XBPS_ARCH="$ARCH" "$XBPS_QUERY" -r "$ROOT_MOUNT" -l | awk '/^ii/ {print " " $2}' || true
fi
if [[ -n "$VOID_KERNEL_MODULES_DIR" ]]; then
log "copying staged Void kernel modules into the guest"
else
log "copying bundled kernel modules into the guest"
fi
sudo mkdir -p "$ROOT_MOUNT/lib/modules"
sudo cp -a "$MODULES_DIR" "$ROOT_MOUNT/lib/modules/"
log "installing the guest-side vsock agent"
sudo mkdir -p "$ROOT_MOUNT/usr/local/bin"
sudo install -m 0755 "$VSOCK_AGENT" "$ROOT_MOUNT/usr/local/bin/banger-vsock-agent"
log "preparing SSH and runit services"
install_guest_network_bootstrap
ensure_sshd_include
enable_sshd_service
install_vsock_service
configure_docker_bootstrap
enable_docker_service
normalize_root_shell
configure_root_bash_prompt
log "installing mise and opencode"
install_mise_and_opencode
install_opencode_service
install_root_authorized_key
sudo touch "$ROOT_MOUNT/etc/fstab" "$ROOT_MOUNT/etc/hostname"
sudo chroot "$ROOT_MOUNT" /usr/bin/ssh-keygen -A
log "removing bulky caches, docs, and stale installer artifacts from the experimental image"
sudo rm -rf \
"$ROOT_MOUNT/var/cache/xbps" \
"$ROOT_MOUNT/usr/share/doc" \
"$ROOT_MOUNT/usr/share/info" \
"$ROOT_MOUNT/usr/share/man"
sudo rm -f \
"$ROOT_MOUNT/root/get-docker" \
"$ROOT_MOUNT/root/get-docker.sh" \
"$ROOT_MOUNT/root/.cache/opencode" \
"$ROOT_MOUNT/tmp/get-docker" \
"$ROOT_MOUNT/tmp/get-docker.sh"
sudo rm -rf \
"$ROOT_MOUNT/root/.cache/mise" \
"$ROOT_MOUNT/root/.local/share/mise/downloads" \
"$ROOT_MOUNT/root/.local/share/mise/tmp"
sudo umount "$ROOT_MOUNT"
banger_write_rootfs_manifest_metadata "$OUT_ROOTFS" "$PACKAGES_HASH"
log "building work-seed $WORK_SEED"
"$BANGER_BIN" internal work-seed --rootfs "$OUT_ROOTFS" --out "$WORK_SEED"
BUILD_DONE=1
log "built experimental Void rootfs: $OUT_ROOTFS"
log "built experimental Void work-seed: $WORK_SEED"
log "use examples/void-exp.config.toml as the local config override template"