#!/usr/bin/env bash # # Build a bootable initramfs from the installed package set and (optionally) # launch it in QEMU to test the Weston desktop. # # Approach: the entire root filesystem is packed into a single initramfs and # booted straight from RAM (no disk image, no loop mounts, no root needed). # dinit runs as PID 1, brings up udev/seatd, autologins, and starts Weston. # # Usage: # scripts/mkimage.sh [-C build-dir] [--run] [--mem MB] # # -C, --build-dir orchid build dir (default: $ORCHID_BUILD or build-x86_64) # --out DIR output dir for artifacts (default: /qemu) # --mem MB QEMU RAM in MiB (default: 4096) # --run launch QEMU after building (otherwise just print the command) # # Artifacts written to : rootfs/ (installed tree), vmlinuz, initramfs.cpio.gz set -euo pipefail here=$(cd "$(dirname "$0")/.." && pwd) orchid="$here/orchid" build_dir=${ORCHID_BUILD:-build-x86_64} out="" mem=4096 run=0 while [ $# -gt 0 ]; do case "$1" in -C|--build-dir) build_dir=$2; shift 2 ;; --out) out=$2; shift 2 ;; --mem) mem=$2; shift 2 ;; --run) run=1; shift ;; -h|--help) sed -n '2,20p' "$0"; exit 0 ;; *) echo "unknown argument: $1" >&2; exit 2 ;; esac done [ -d "$build_dir" ] || { echo "build dir not found: $build_dir" >&2; exit 1; } out=${out:-$build_dir/qemu} rootfs="$out/rootfs" mkdir -p "$out" echo ">> installing packages into $rootfs" rm -rf "$rootfs" "$orchid" install -C "$build_dir" "$rootfs" echo ">> wiring up init" # The kernel execs /init from an initramfs but does NOT auto-mount devtmpfs, so # dinit would have no /dev/null to set up service stdio. This tiny bootstrap # mounts the kernel vfs, then hands off to dinit (PID 1) which runs the rest. mkdir -p "$rootfs"/{proc,sys,dev,run,tmp} cat > "$rootfs/init" <<'EOF' #!/bin/bash export PATH=/usr/bin:/usr/sbin:/bin:/sbin mount -t devtmpfs dev /dev 2>/dev/null || true mount -t proc proc /proc 2>/dev/null || true mount -t sysfs sys /sys 2>/dev/null || true exec /sbin/init EOF chmod +x "$rootfs/init" echo ">> regenerating ld.so.cache" # Target libs are split across /lib, /usr/lib and /usr/lib64; without a cache # the loader can't find e.g. libstdc++ for dinit (PID 1, before any service # runs). base-files ships /etc/ld.so.conf + the /lib64 and /bin compat links; # build the cache now from the assembled rootfs. # Prefer the *target* ldconfig (run via the target loader) so the cache is in a # format the target glibc loader accepts; fall back to the host ldconfig. loader="$rootfs/lib/ld-linux-x86-64.so.2" tgt_ldconfig="$rootfs/sbin/ldconfig" if [ -x "$loader" ] && [ -e "$tgt_ldconfig" ]; then "$loader" --library-path "$rootfs/lib:$rootfs/usr/lib:$rootfs/usr/lib64" \ "$tgt_ldconfig" -r "$rootfs" elif command -v ldconfig >/dev/null; then ldconfig -r "$rootfs" else echo " warning: no ldconfig available; libraries may not resolve" >&2 fi echo ">> extracting kernel" kernel=$(ls -1 "$rootfs"/boot/vmlinuz-* 2>/dev/null | head -n1 || true) if [ -z "$kernel" ]; then echo "no kernel in $rootfs/boot (build the 'linux' recipe first)" >&2 exit 1 fi cp "$kernel" "$out/vmlinuz" if [ ! -d "$rootfs"/lib/modules ] && [ ! -d "$rootfs"/usr/lib/modules ]; then echo "warning: no /lib/modules in rootfs — DRM/input drivers built as" >&2 echo " modules won't load (rebuild 'linux' with modules_install)." >&2 fi echo ">> packing initramfs" # Pack as a newc cpio + gzip. Run from within rootfs so paths are relative. ( cd "$rootfs" && find . -print0 | cpio --null --create --format=newc --quiet ) \ | gzip -9 > "$out/initramfs.cpio.gz" echo " initramfs: $(du -h "$out/initramfs.cpio.gz" | cut -f1)" # Assemble the QEMU command. virtio-gpu gives Weston a DRM/KMS device; virtio # keyboard/tablet feed libinput; serial is the console for boot logs. kvm=() [ -w /dev/kvm ] && kvm=(-enable-kvm -cpu host) cmd=( qemu-system-x86_64 "${kvm[@]}" -m "$mem" -smp 4 -kernel "$out/vmlinuz" -initrd "$out/initramfs.cpio.gz" -append "console=ttyS0,115200 loglevel=6" -device virtio-gpu-pci -device virtio-keyboard-pci -device virtio-tablet-pci -display gtk,gl=on -serial mon:stdio ) echo "" echo ">> QEMU command:" printf ' %q' "${cmd[@]}"; echo if [ "$run" -eq 1 ]; then echo ">> launching QEMU (Ctrl-A X to quit the serial console)" exec "${cmd[@]}" fi