import { cp, mkdir, mkdtemp, rm } from "node:fs/promises"; import { tmpdir } from "node:os"; import path, { join } from "node:path"; import { canAccess, execFile } from "./helpers/better-api.js"; import { sudoChownToRunningUser } from "./helpers/sudo.js"; export async function runQemu( squashfs: string, kernel: { initramfs: string; vmlinuz: string }, { graphic, noShutdown }: { graphic?: boolean; noShutdown?: boolean } = { graphic: true, noShutdown: false, } ) { await sudoChownToRunningUser(kernel.initramfs); await sudoChownToRunningUser(kernel.vmlinuz); await sudoChownToRunningUser(squashfs); const tmp = await mkdtemp(path.join(tmpdir(), "define-alpine-qemu-")); try { // const disk = path.join(tmp, "tmp.ext4"); const disk = "tmp.ext4"; if (!(await canAccess(disk))) { await execFile("fallocate", ["--length", "1G", disk]); await execFile("mkfs.ext4", ["-F", disk]); } { const mountpoint = join(tmp, "persist-mount"); await mkdir(mountpoint); await execFile("sudo", ["mount", disk, mountpoint]); try { await execFile("sudo", [ "cp", squashfs, join(mountpoint, "current.squashfs"), ]); } finally { await execFile("sudo", ["umount", mountpoint]); } } let kernelAppend = [ "root=/dev/sda", "rootfstype=ext4", "modules=ext4", "quiet", "init=/sbin/runit-init", ]; let qemuAppend: string[] = []; if (!graphic) { kernelAppend.push("console=ttyS0"); qemuAppend.push("-nographic"); } if (noShutdown) qemuAppend.push("-no-shutdown"); // sudo chown root:$(id -u) -R boot/ && sudo chmod g+rw -R boot/ await execFile("qemu-system-x86_64", [ "-enable-kvm", "-m", "2048", // "-drive", // `file=${squashfs},media=disk,format=raw`, "-drive", `file=${disk},media=disk,format=raw`, "-net", "nic,model=virtio-net-pci", "-net", "user,hostfwd=tcp:127.0.0.1:8080-:80", "-kernel", kernel.vmlinuz, "-initrd", kernel.initramfs, "-append", kernelAppend.join(" "), ...qemuAppend, ]); // -append "root=/dev/sda rootfstype=squashfs modules=ext4 quiet init=/sbin/runit-init $append" $qemuappend } finally { await rm(tmp, { recursive: true, force: true }); } } await runQemu( "artifacts/image.squashfs", { initramfs: "artifacts/kernel/initramfs", vmlinuz: "artifacts/kernel/vmlinuz", }, { graphic: true, noShutdown: true } );