summaryrefslogtreecommitdiffstats
path: root/scripts/test-disk.sh
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-08-01 02:19:07 +0200
committersalmonik <salmonik@tuta.io>2026-08-01 02:19:07 +0200
commit92ed4f6668efccf6af73f45654405d333e6a318c (patch)
treebb9b651dc36edcc90ae0289d7c4223d983454440 /scripts/test-disk.sh
parentscripts: automate the data-disk workflow (mkdisk / sendkeys / test-disk) (diff)
downloadrs-dos-92ed4f6668efccf6af73f45654405d333e6a318c.tar.gz
rs-dos-92ed4f6668efccf6af73f45654405d333e6a318c.zip
fat: mount every FAT32 volume under /disk/<UID>/, fix multi-entry LFN
- fat.rs: VOL: Option<Volume> → VOLS: Vec<Volume>; try_mount() returns a Volume per disk and init() mounts every valid FAT32 volume found. Volume UID = sanitized uppercase label + 8-hex volume serial (e.g. RSDOS-5BD1E55F): unique per format, stable across reboots, human-recognizable, machine-parseable (^[A-Z0-9_]+-[0-9A-F]{8}$); cloned volumes get a -N suffix. Public ops take a vol index and select it (select_vol also picks the backing AHCI disk), matching the ahci::select pattern - fs.rs: /disk is now a plain directory whose children are one Disk node per mounted volume, named by UID; DiskInfo carries vol - LFN fix: entries are stored last-first on disk — both the writer (head-entry first) and reader (append in disk order) were reversed and cancelled out for ≤13-char names; multi-entry names (>13 chars) read back mangled (e.g. 'from-kernel.txt' as 'xt'). Writer now places seq=1 closest to the SFN and seq=N|0x40 first; reader places chunks by sequence number and trims at the first NUL. Verified with a 25-char filename round trip: kernel ls/cat correct, mtools shows the full LFN, fsck clean on both volumes - test-disk.sh: test file renamed to disk-test-.txt (>13 chars, exercises multi-entry LFN); UID discovered from the boot log; QEMU stdio redirected to a log file + EXIT trap so an orphaned QEMU can never hang a piped caller (it previously did, 400s)
Diffstat (limited to 'scripts/test-disk.sh')
-rwxr-xr-xscripts/test-disk.sh35
1 files changed, 26 insertions, 9 deletions
diff --git a/scripts/test-disk.sh b/scripts/test-disk.sh
index f7be7c6..f7337ef 100755
--- a/scripts/test-disk.sh
+++ b/scripts/test-disk.sh
@@ -31,8 +31,13 @@ ESP_DIR="$PROJECT_DIR/esp"
31QPID=/tmp/rsdos-test-qpid 31QPID=/tmp/rsdos-test-qpid
32SOCK=/tmp/rsdos-test-qmon.sock 32SOCK=/tmp/rsdos-test-qmon.sock
33LOG=/tmp/rsdos-test-serial.log 33LOG=/tmp/rsdos-test-serial.log
34QLOG=/tmp/rsdos-test-qemu.log
34STAMP="$(date +%s)" 35STAMP="$(date +%s)"
35 36
37# Never leave a QEMU behind (an orphan holding our stdout would hang any
38# caller that pipes our output).
39trap 'kill "$(cat "$QPID" 2>/dev/null)" 2>/dev/null || true' EXIT
40
36fail() { 41fail() {
37 echo "FAIL: $1" 42 echo "FAIL: $1"
38 [ -f "$LOG" ] && tail -20 "$LOG" 43 [ -f "$LOG" ] && tail -20 "$LOG"
@@ -42,7 +47,7 @@ fail() {
42# wait_log FILE PATTERN TIMEOUT-SECONDS — poll a file for a regex. 47# wait_log FILE PATTERN TIMEOUT-SECONDS — poll a file for a regex.
43wait_log() { 48wait_log() {
44 local i=0 49 local i=0
45 while [ "$i" -lt $(( ${3:-60} * 10 )) ]; do 50 while [ "$i" -lt $((${3:-60} * 10)) ]; do
46 grep -q "$2" "$1" 2>/dev/null && return 0 51 grep -q "$2" "$1" 2>/dev/null && return 0
47 sleep 0.1 52 sleep 0.1
48 i=$((i + 1)) 53 i=$((i + 1))
@@ -53,7 +58,7 @@ wait_log() {
53# wait_qemu_exit TIMEOUT-SECONDS — poll until the pid is gone. 58# wait_qemu_exit TIMEOUT-SECONDS — poll until the pid is gone.
54wait_qemu_exit() { 59wait_qemu_exit() {
55 local i=0 60 local i=0
56 while [ "$i" -lt $(( ${1:-30} * 10 )) ]; do 61 while [ "$i" -lt $((${1:-30} * 10)) ]; do
57 kill -0 "$(cat "$QPID" 2>/dev/null)" 2>/dev/null || return 0 62 kill -0 "$(cat "$QPID" 2>/dev/null)" 2>/dev/null || return 0
58 sleep 0.1 63 sleep 0.1
59 i=$((i + 1)) 64 i=$((i + 1))
@@ -80,18 +85,29 @@ rm -f "$SOCK" "$LOG"
80 -device ide-hd,drive=esp,bus=ide.1 \ 85 -device ide-hd,drive=esp,bus=ide.1 \
81 -serial file:"$LOG" \ 86 -serial file:"$LOG" \
82 -monitor unix:"$SOCK",server,nowait \ 87 -monitor unix:"$SOCK",server,nowait \
83 -m 256M -machine q35 -cpu qemu64 -no-reboot -display none & 88 -m 256M -machine q35 -cpu qemu64 -no-reboot -display none \
84echo $! > "$QPID" 89 >"$QLOG" 2>&1 &
90echo $! >"$QPID"
85 91
86wait_log "$LOG" "boot: entering shell" 90 || fail "kernel never reached the shell" 92wait_log "$LOG" "boot: entering shell" 90 || fail "kernel never reached the shell"
87sleep 1 93sleep 1
88 94
95# Volumes mount under /disk/<UID>/ where UID = "LABEL-SERIAL" (e.g.
96# RSDOS-5BD1E55F). Discover it from the boot log so the test works on
97# any image without knowing the serial in advance.
98VOL_UID="$(grep -a 'fat: mounted' "$LOG" | sed -n 's/.*at \/disk\/\([^ )]*\).*/\1/p' | head -1)"
99[ -n "$VOL_UID" ] || fail "no FAT32 volume was mounted (look for 'fat: mounted' in the log)"
100echo " mounted volume UID: $VOL_UID"
101
89echo "==> 4/6 drive the shell (ls / mkdir / echo > / cat / poweroff)" 102echo "==> 4/6 drive the shell (ls / mkdir / echo > / cat / poweroff)"
103# The filename is deliberately >13 chars so the FAT LFN path gets
104# multi-entry entries (they're stored last-first on disk).
105TESTFILE="disk-test-$STAMP.txt"
90python3 "$SCRIPT_DIR/sendkeys.py" --sock "$SOCK" \ 106python3 "$SCRIPT_DIR/sendkeys.py" --sock "$SOCK" \
91 "ls /disk" \ 107 "ls /disk" \
92 "mkdir /disk/sub" \ 108 "mkdir /disk/$VOL_UID/sub" \
93 "echo disk-test-$STAMP > /disk/sub/hello.txt" \ 109 "echo disk-test-$STAMP > /disk/$VOL_UID/sub/$TESTFILE" \
94 "cat /disk/sub/hello.txt" \ 110 "cat /disk/$VOL_UID/sub/$TESTFILE" \
95 "poweroff" 111 "poweroff"
96 112
97echo "==> 5/6 wait for shutdown" 113echo "==> 5/6 wait for shutdown"
@@ -102,10 +118,11 @@ grep -a "disk-test-$STAMP" "$LOG" >/dev/null || fail "cat output missing from se
102if ! fsck.fat -n "$IMG" >/tmp/rsdos-fsck.out 2>&1; then 118if ! fsck.fat -n "$IMG" >/tmp/rsdos-fsck.out 2>&1; then
103 fail "fsck.fat reports problems: $(cat /tmp/rsdos-fsck.out | tail -3)" 119 fail "fsck.fat reports problems: $(cat /tmp/rsdos-fsck.out | tail -3)"
104fi 120fi
105MT="$(mtype -i "$IMG" "::/sub/hello.txt" 2>/dev/null || true)" 121MT="$(mtype -i "$IMG" "::/sub/$TESTFILE" 2>/dev/null || true)"
106[ "$MT" = "disk-test-$STAMP" ] || fail "mtype mismatch: got '$MT'" 122[ "$MT" = "disk-test-$STAMP" ] || fail "mtype mismatch: got '$MT'"
107 123
108echo "" 124echo ""
109echo "PASS — disk round trip OK (fsck clean, file survived poweroff)" 125echo "PASS — disk round trip OK (fsck clean, file survived poweroff)"
110echo " image: $IMG" 126echo " image: $IMG"
111echo " written: /disk/sub/hello.txt = \"disk-test-$STAMP\"" 127echo " volume: /disk/$VOL_UID"
128echo " written: /disk/$VOL_UID/sub/$TESTFILE = \"disk-test-$STAMP\""