banger/scripts/make-void-kernel.sh
Thales Maciel 572bf32424
Remove runtime-bundle image dependencies
Hard-cut banger away from source-checkout runtime bundles as an implicit source of\nimage and host defaults. Managed images now own their full boot set,\nimage build starts from an existing registered image, and daemon startup\nno longer synthesizes a default image from host paths.\n\nResolve Firecracker from PATH or firecracker_bin, make SSH keys config-owned\nwith an auto-managed XDG default, replace the external name generator and\npackage manifests with Go code, and keep the vsock helper as a companion\nbinary instead of a user-managed runtime asset.\n\nUpdate the manual scripts, web/CLI forms, config surface, and docs around\nthe new build/manual flow and explicit image registration semantics.\n\nValidation: GOCACHE=/tmp/banger-gocache go test ./..., bash -n scripts/*.sh,\nand make build.
2026-03-21 18:34:53 -03:00

386 lines
11 KiB
Bash
Executable file

#!/usr/bin/env bash
set -euo pipefail
log() {
printf '[make-void-kernel] %s\n' "$*"
}
usage() {
cat <<'EOF'
Usage: ./scripts/make-void-kernel.sh [--out-dir <path>] [--mirror <url>] [--arch <arch>] [--kernel-package <name>] [--print-register-flags]
Download and stage a Void Linux kernel under ./build/manual/void-kernel for
the
experimental Void guest flow.
Defaults:
--out-dir ./build/manual/void-kernel
--mirror https://repo-default.voidlinux.org
--arch x86_64
--kernel-package linux6.12
The staged output contains:
boot/vmlinux-<version> Firecracker-usable kernel extracted from vmlinuz
boot/vmlinuz-<version> Raw distro boot image from the Void package
boot/initramfs-<version>.img Matching initramfs generated with dracut
boot/config-<version> Void kernel config
lib/modules/<version>/ Matching kernel modules tree
If --print-register-flags is passed, the script does not download anything. It
prints the banger image register flags for an existing staged Void kernel.
EOF
}
require_command() {
local name="$1"
command -v "$name" >/dev/null 2>&1 || {
log "required command not found: $name"
exit 1
}
}
normalize_mirror() {
local mirror="${1%/}"
mirror="${mirror%/current}"
mirror="${mirror%/static}"
printf '%s\n' "$mirror"
}
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
}
find_latest_matching() {
local dir="$1"
local pattern="$2"
if [[ ! -d "$dir" ]]; then
return 1
fi
find "$dir" -maxdepth 1 -type f -name "$pattern" | sort | tail -n 1
}
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
}
print_register_flags() {
local kernel=""
local initrd=""
local modules=""
kernel="$(find_latest_matching "$OUT_DIR/boot" 'vmlinux-*' || true)"
initrd="$(find_latest_matching "$OUT_DIR/boot" 'initramfs-*' || true)"
modules="$(find_latest_module_dir "$OUT_DIR/lib/modules" || true)"
if [[ -z "$kernel" || -z "$modules" ]]; then
log "staged Void kernel not found under $OUT_DIR"
exit 1
fi
printf -- '--kernel %q ' "$kernel"
if [[ -n "$initrd" ]]; then
printf -- '--initrd %q ' "$initrd"
fi
printf -- '--modules %q\n' "$modules"
}
check_elf() {
local path="$1"
readelf -h "$path" >/dev/null 2>&1
}
ensure_stage_root_layout() {
mkdir -p "$STAGE_ROOT/usr"
if [[ ! -e "$STAGE_ROOT/bin" ]]; then
ln -snf usr/bin "$STAGE_ROOT/bin"
fi
if [[ ! -e "$STAGE_ROOT/sbin" ]]; then
ln -snf usr/bin "$STAGE_ROOT/sbin"
fi
if [[ ! -e "$STAGE_ROOT/usr/sbin" ]]; then
ln -snf bin "$STAGE_ROOT/usr/sbin"
fi
if [[ ! -e "$STAGE_ROOT/lib" ]]; then
ln -snf usr/lib "$STAGE_ROOT/lib"
fi
if [[ ! -e "$STAGE_ROOT/lib64" ]]; then
ln -snf usr/lib "$STAGE_ROOT/lib64"
fi
if [[ ! -e "$STAGE_ROOT/usr/lib64" ]]; then
ln -snf lib "$STAGE_ROOT/usr/lib64"
fi
if [[ -x "$STAGE_ROOT/usr/bin/udevd" ]]; then
mkdir -p "$STAGE_ROOT/usr/lib/udev" "$STAGE_ROOT/usr/lib/systemd"
if [[ ! -e "$STAGE_ROOT/usr/lib/udev/udevd" ]]; then
ln -snf ../../bin/udevd "$STAGE_ROOT/usr/lib/udev/udevd"
fi
if [[ ! -e "$STAGE_ROOT/usr/lib/systemd/systemd-udevd" ]]; then
ln -snf ../../bin/udevd "$STAGE_ROOT/usr/lib/systemd/systemd-udevd"
fi
fi
}
sync_host_dracut_tree() {
if [[ ! -d /usr/lib/dracut ]]; then
log "host dracut support files not found under /usr/lib/dracut"
exit 1
fi
rm -rf "$STAGE_ROOT/usr/lib/dracut"
mkdir -p "$STAGE_ROOT/usr/lib"
cp -a /usr/lib/dracut "$STAGE_ROOT/usr/lib/dracut"
}
build_initramfs() {
local kver="$1"
local modules_dir="$2"
local out="$3"
local config_dir="$TMP_DIR/dracut.conf.d"
local tmpdir="$TMP_DIR/dracut-tmp"
local force_drivers="virtio virtio_ring virtio_mmio virtio_blk virtio_net virtio_console ext4 vsock vmw_vsock_virtio_transport"
mkdir -p "$config_dir" "$tmpdir"
ensure_stage_root_layout
sync_host_dracut_tree
log "generating initramfs for kernel $kver with host dracut against the staged Void sysroot"
env dracutbasedir="/usr/lib/dracut" dracut \
--force \
--kver "$kver" \
--sysroot "$STAGE_ROOT" \
--kmoddir "$modules_dir" \
--conf /dev/null \
--confdir "$config_dir" \
--tmpdir "$tmpdir" \
--no-hostonly \
--filesystems "ext4" \
--force-drivers "$force_drivers" \
--gzip \
"$out"
}
extract_vmlinux() {
local image="$1"
local out="$2"
local tmp="$TMP_DIR/vmlinux.extract"
if check_elf "$image"; then
install -m 0644 "$image" "$out"
return 0
fi
try_decompress() {
local header="$1"
local marker="$2"
local command="$3"
local pos=""
while IFS= read -r pos; do
[[ -n "$pos" ]] || continue
pos="${pos%%:*}"
tail -c+"$pos" "$image" | eval "$command" >"$tmp" 2>/dev/null || true
if check_elf "$tmp"; then
install -m 0644 "$tmp" "$out"
return 0
fi
done < <(tr "$header\n$marker" "\n$marker=" < "$image" | grep -abo "^$marker" || true)
return 1
}
try_decompress '\037\213\010' "xy" "gunzip" && return 0
try_decompress '\3757zXZ\000' "abcde" "unxz" && return 0
try_decompress "BZh" "xy" "bunzip2" && return 0
try_decompress '\135\000\000\000' "xxx" "unlzma" && return 0
try_decompress '\002!L\030' "xxx" "lz4 -d" && return 0
try_decompress '(\265/\375' "xxx" "unzstd" && return 0
return 1
}
resolve_kernel_package_file() {
local escaped_name=""
escaped_name="$(printf '%s\n' "$KERNEL_PACKAGE" | sed 's/[.[\*^$()+?{|]/\\&/g')"
curl -fsSL "$REPO_URL/" |
grep -o "${escaped_name}-[0-9][^\" >]*\\.${ARCH}\\.xbps" |
sort -u |
tail -n 1
}
cleanup() {
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)"
MANUAL_DIR="${BANGER_MANUAL_DIR:-$REPO_ROOT/build/manual}"
OUT_DIR="$MANUAL_DIR/void-kernel"
MIRROR="https://repo-default.voidlinux.org"
ARCH="x86_64"
KERNEL_PACKAGE="linux6.12"
PRINT_REGISTER_FLAGS=0
while [[ $# -gt 0 ]]; do
case "$1" in
--out-dir)
OUT_DIR="${2:-}"
shift 2
;;
--mirror)
MIRROR="${2:-}"
shift 2
;;
--arch)
ARCH="${2:-}"
shift 2
;;
--kernel-package)
KERNEL_PACKAGE="${2:-}"
shift 2
;;
--print-register-flags)
PRINT_REGISTER_FLAGS=1
shift
;;
-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 [[ "$PRINT_REGISTER_FLAGS" == "1" ]]; then
print_register_flags
exit 0
fi
if [[ "$ARCH" != "x86_64" ]]; then
log "unsupported arch: $ARCH"
log "this experimental downloader currently supports only x86_64"
exit 1
fi
mkdir -p "$RUNTIME_DIR"
if [[ -e "$OUT_DIR" ]]; then
log "output directory already exists: $OUT_DIR"
log "remove it first if you want to re-stage a different Void kernel"
exit 1
fi
require_command curl
require_command tar
require_command cp
require_command find
require_command grep
require_command cut
require_command readelf
require_command file
require_command install
require_command tail
require_command xz
require_command gzip
require_command bzip2
require_command dracut
TMP_DIR="$(mktemp -d -t banger-void-kernel-XXXXXX)"
STATIC_DIR="$TMP_DIR/static"
STAGE_ROOT="$TMP_DIR/root"
STAGE_OUT="$TMP_DIR/out"
STATIC_ARCHIVE="$TMP_DIR/xbps-static.tar.xz"
trap cleanup EXIT
mkdir -p "$STATIC_DIR" "$STAGE_ROOT/var/db/xbps/keys" "$STAGE_OUT/boot" "$STAGE_OUT/lib/modules"
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)"
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
cp -a "$STATIC_KEYS_DIR/." "$STAGE_ROOT/var/db/xbps/keys/"
KERNEL_PACKAGE_FILE="$(resolve_kernel_package_file)"
if [[ -z "$KERNEL_PACKAGE_FILE" ]]; then
log "failed to resolve a package file for $KERNEL_PACKAGE in $REPO_URL"
exit 1
fi
log "staging $KERNEL_PACKAGE_FILE into a temporary root"
env XBPS_ARCH="$ARCH" "$XBPS_INSTALL" -S -y -U -r "$STAGE_ROOT" -R "$REPO_URL" linux-base "$KERNEL_PACKAGE" dracut eudev >/dev/null
VMLINUX_RAW="$(find_latest_matching "$STAGE_ROOT/boot" 'vmlinuz-*' || true)"
KERNEL_CONFIG="$(find_latest_matching "$STAGE_ROOT/boot" 'config-*' || true)"
MODULES_DIR="$(find_latest_module_dir "$STAGE_ROOT/usr/lib/modules" || true)"
KERNEL_VERSION="$(basename "$MODULES_DIR")"
INITRAMFS_NAME="initramfs-${KERNEL_VERSION}.img"
INITRAMFS_RAW="$STAGE_OUT/boot/$INITRAMFS_NAME"
if [[ -z "$VMLINUX_RAW" || -z "$KERNEL_CONFIG" || -z "$MODULES_DIR" ]]; then
log "staged Void kernel is missing expected boot artifacts"
exit 1
fi
if [[ ! -x "$STAGE_ROOT/usr/bin/udevd" ]]; then
log "staged Void sysroot is missing /usr/bin/udevd after package install"
exit 1
fi
VMLINUX_BASE="$(basename "$VMLINUX_RAW")"
VMLINUX_OUT="$STAGE_OUT/boot/vmlinux-${VMLINUX_BASE#vmlinuz-}"
install -m 0644 "$VMLINUX_RAW" "$STAGE_OUT/boot/$VMLINUX_BASE"
install -m 0644 "$KERNEL_CONFIG" "$STAGE_OUT/boot/$(basename "$KERNEL_CONFIG")"
build_initramfs "$KERNEL_VERSION" "$MODULES_DIR" "$INITRAMFS_RAW"
cp -a "$MODULES_DIR" "$STAGE_OUT/lib/modules/"
log "extracting Firecracker kernel from $(basename "$VMLINUX_RAW")"
if ! extract_vmlinux "$VMLINUX_RAW" "$VMLINUX_OUT"; then
log "failed to extract an uncompressed vmlinux from $VMLINUX_RAW"
log "raw kernel image type: $(file -b "$VMLINUX_RAW")"
exit 1
fi
cat >"$STAGE_OUT/metadata.json" <<EOF
{
"package": "$KERNEL_PACKAGE_FILE",
"kernel_path": "$OUT_DIR/boot/$(basename "$VMLINUX_OUT")",
"raw_kernel_path": "$OUT_DIR/boot/$VMLINUX_BASE",
"config_path": "$OUT_DIR/boot/$(basename "$KERNEL_CONFIG")",
"initrd_path": "$OUT_DIR/boot/$INITRAMFS_NAME",
"modules_dir": "$OUT_DIR/lib/modules/$(basename "$MODULES_DIR")"
}
EOF
mv "$STAGE_OUT" "$OUT_DIR"
log "staged Void kernel artifacts in $OUT_DIR"
log "kernel image: $OUT_DIR/boot/$(basename "$VMLINUX_OUT")"
log "initrd image: $OUT_DIR/boot/$INITRAMFS_NAME"
log "modules dir: $OUT_DIR/lib/modules/$(basename "$MODULES_DIR")"