summaryrefslogtreecommitdiffstats
path: root/scripts/lib.sh
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-11-01 15:53:29 +0100
committersalmonik <salmonik@tuta.io>2026-11-01 15:53:29 +0100
commit7958276c9f0d230053520ba20f2a00f5ecda18e4 (patch)
tree596f5f71ad597ed951bae98de818cb37f171a18d /scripts/lib.sh
parentfs: /bin alias for the system volume (diff)
downloadrs-dos-7958276c9f0d230053520ba20f2a00f5ecda18e4.tar.gz
rs-dos-7958276c9f0d230053520ba20f2a00f5ecda18e4.zip
scripts: rebuild the dev loop around build.sh/run.sh
`make` did not parse at all (missing separator at line 139), so every make target was dead. The folder also carried three overlapping launchers (boot.sh, qemu.sh, boot-image.sh) plus a fourth partial one in the Makefile, `cargo build --package rsdos` copy-pasted eight times, the QEMU invocation copy-pasted per script, and the test helpers (fail/wait_log/wait_qemu_exit/qemu_hmp) duplicated in five tests. New layout: - scripts/lib.sh: single config (image, OVMF, mem/smp), the one cargo invocation (build_all), the one QEMU shape (qemu_args), and the test harness (test_boot, wait_log, wait_qemu_exit, qemu_hmp, sendkeys) - scripts/build.sh: kernel + every bins/* in one pass - scripts/mksystem.sh: freshness-aware image build that now stages every bins/*.efi into /bin/cli|gui (they were never copied before) - scripts/run.sh: build + stage + boot in one command; --headless, --debug (GDB stub), --monitor (HMP socket), --fresh, --mem/--smp/ --bios/--image; on Wayland it auto-selects XWayland plus grab-on-hover so the mouse can be captured (Ctrl+Alt+G toggles) - scripts/tests/: the five automated tests on the shared harness - deleted: boot.sh, qemu.sh, boot-image.sh, lib-boot-args.sh, build-image-release.sh, build-bootloader.sh (rsboot chain dropped) The Makefile is now a thin wrapper: make run, make test, make system, make inspect, make help. Two-command flow: ./scripts/build.sh then ./scripts/run.sh (run.sh alone also works). Stale test assumptions fixed so the suite is green again: test-gfx waited for "gfx: check" while the shell prints "gfx check: PASS"; test-mouse/test-msg hardcoded msgrecv = task 3 (wm-input took slot 3 — ids are parsed from the log now); the queue-full probe targeted task 0, whose exec pump drains its own queue as completion codes (moved to the cursor task, which never recvs). Verified in QEMU: make test -> test-disk, test-gfx, test-mouse, test-msg, test-fault all PASS.
Diffstat (limited to '')
-rw-r--r--scripts/lib.sh168
1 files changed, 168 insertions, 0 deletions
diff --git a/scripts/lib.sh b/scripts/lib.sh
new file mode 100644
index 0000000..d5aecac
--- /dev/null
+++ b/scripts/lib.sh
@@ -0,0 +1,168 @@
1#!/usr/bin/env bash
2#
3# scripts/lib.sh — shared config and helpers for the rs-dos scripts.
4#
5# Sourced, never executed. Everything here is the single definition of
6# "how we build and how we boot": the build script, the image assembler,
7# the QEMU runner and the tests all read their settings from this file.
8#
9# Config is environment-overridable (TARGET, PROFILE, SYSTEM_IMG, OVMF,
10# QEMU, MEM, SMP) so callers and CI can tune it without editing scripts.
11set -euo pipefail
12
13SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
14PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
15TESTS_DIR="$SCRIPT_DIR/tests"
16
17# ---- config ---------------------------------------------------------------
18TARGET="${TARGET:-x86_64-unknown-uefi}"
19PROFILE="${PROFILE:-release}"
20OUT_DIR="${OUT_DIR:-$PROJECT_DIR/target/$TARGET/$PROFILE}"
21KERNEL="$OUT_DIR/rsdos.efi"
22SYSTEM_IMG="${SYSTEM_IMG:-/tmp/system.img}"
23OVMF="${OVMF:-/usr/share/edk2/x64/OVMF.4m.fd}"
24QEMU="${QEMU:-qemu-system-x86_64}"
25MEM="${MEM:-256M}"
26SMP="${SMP:-1}"
27
28# Binaries whose launch surface is a window rather than a terminal
29# (ADR 0006): staged into /bin/gui, everything else into /bin/cli.
30GUI_BINS="paint"
31
32cd "$PROJECT_DIR"
33
34# ---- build ----------------------------------------------------------------
35#
36# The one and only cargo invocation in the repo. Builds the kernel and
37# every external binary in a single pass so the image can stage both.
38
39cargo_flags() {
40 [ "$PROFILE" = "release" ] && printf '%s' "--release"
41}
42
43build_all() {
44 echo "=== build (kernel + bins, $PROFILE) ==="
45 # shellcheck disable=SC2046 # cargo_flags is a flag word, intentionally split
46 cargo build --workspace --target "$TARGET" $(cargo_flags)
47}
48
49# ---- system image ---------------------------------------------------------
50
51# stage_image [mksystem args...] — assemble /tmp/system.img if it is stale.
52# Freshness is decided inside mksystem.sh; an up-to-date image is never
53# touched, so files written at runtime survive.
54stage_image() {
55 "$SCRIPT_DIR/mksystem.sh" "$@"
56}
57
58# ---- QEMU -----------------------------------------------------------------
59
60# qemu_args — the common machine every boot shares: OVMF, the system
61# image as the single SATA drive, 256M q35. Callers append display,
62# monitor and serial choices.
63qemu_args() {
64 printf '%s\n' \
65 -bios "$OVMF" \
66 -drive "file=$SYSTEM_IMG,format=raw,if=none,id=disk" \
67 -device ide-hd,drive=disk,bus=ide.0 \
68 -m "$MEM" \
69 -machine q35 \
70 -cpu qemu64 \
71 -no-reboot \
72 -smp "$SMP"
73}
74
75# ---- test harness ---------------------------------------------------------
76#
77# Every test-*.sh does:
78# TNAME=disk; source lib.sh; test_boot # waits for the shell
79# sendkeys "ls /disk" "poweroff"
80# wait_qemu_exit
81# Runtime files are namespaced per test so parallel runs cannot collide.
82
83TNAME="${TNAME:-rsdos}"
84QPID="/tmp/rsdos-$TNAME-qpid"
85SOCK="/tmp/rsdos-$TNAME-qmon.sock"
86LOG="/tmp/rsdos-$TNAME-serial.log"
87QLOG="/tmp/rsdos-$TNAME-qemu.log"
88
89fail() {
90 echo "FAIL: $1"
91 [ -f "$LOG" ] && tail -40 "$LOG"
92 exit 1
93}
94
95# wait_log FILE PATTERN TIMEOUT-SECONDS — poll a file for a regex.
96wait_log() {
97 local i=0
98 while [ "$i" -lt $((${3:-60} * 10)) ]; do
99 grep -q "$2" "$1" 2>/dev/null && return 0
100 sleep 0.1
101 i=$((i + 1))
102 done
103 return 1
104}
105
106# wait_qemu_exit TIMEOUT-SECONDS — poll until the pid is gone.
107wait_qemu_exit() {
108 local i=0
109 while [ "$i" -lt $((${1:-30} * 10)) ]; do
110 kill -0 "$(cat "$QPID" 2>/dev/null)" 2>/dev/null || return 0
111 sleep 0.1
112 i=$((i + 1))
113 done
114 return 1
115}
116
117# qemu_hmp CMD — run one HMP command on the monitor socket.
118qemu_hmp() {
119 python3 - "$SOCK" "$1" <<'EOF'
120import socket, sys, time
121s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
122s.connect(sys.argv[1])
123s.sendall((sys.argv[2] + "\n").encode())
124time.sleep(0.4)
125EOF
126}
127
128# sendkeys "line" ... — type shell commands into the guest via sendkeys.py.
129sendkeys() {
130 python3 "$TESTS_DIR/sendkeys.py" --sock "$SOCK" "$@"
131}
132
133# test_cleanup — reap a leftover QEMU from a previous run of this test
134# and clear this test's runtime files. Called before test_boot.
135test_cleanup() {
136 kill "$(cat "$QPID" 2>/dev/null)" 2>/dev/null || true
137 rm -f "$SOCK" "$LOG"
138}
139
140# test_on_exit — EXIT trap: never leave a QEMU behind, but keep the logs
141# (they are the post-mortem for a failed test).
142test_on_exit() {
143 kill "$(cat "$QPID" 2>/dev/null)" 2>/dev/null || true
144}
145
146# test_boot [extra-qemu-args...] — boot the system image headless with the
147# serial log at $LOG and a monitor socket at $SOCK, then wait for the
148# shell. Extra args attach more drives (e.g. a CRASHLOG stick).
149test_boot() {
150 test_cleanup
151 trap test_on_exit EXIT
152 # A stale/poisoned OVMF varstore makes the firmware skip the
153 # \EFI\BOOT fallback entirely — every test boots from a fresh copy.
154 # Namespaced per test so parallel runs cannot race on it.
155 local nv="/tmp/rsdos-ovmf-vars-$TNAME.fd"
156 rm -f "$nv"
157 cp "$OVMF" "$nv"
158 local -a qargs
159 mapfile -t qargs < <(qemu_args)
160 "$QEMU" -bios "$nv" \
161 "${qargs[@]}" \
162 -serial "file:$LOG" \
163 -monitor "unix:$SOCK,server,nowait" \
164 -display none \
165 "$@" >"$QLOG" 2>&1 &
166 echo $! >"$QPID"
167 wait_log "$LOG" "boot: entering shell" 90 || fail "kernel never reached the shell"
168}