RustForge

foundry

Foundry OS: the operating system built on the Rustbelt kernel

foundry / scripts / check-v2-image.sh
3591 bytes ยท raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#!/usr/bin/env bash
# After `make test-v2`: check, on the host, the disk image the run wrote to.
#   * every file system is still consistent: e2fsck (A:), fsck.fat (B:),
#     fsck.exfat (C:), all read-only (-n);
#   * the share is a plain single-FAT exFAT volume, and the file the
#     self-test left there (dash's /mnt/share/from-foundry.txt) reads back
#     on the host -- through scripts/exfat.py, not the kernel's driver;
#   * the files the self-test created and deleted are really gone.
# Nothing is mounted (no root needed). Usage: scripts/check-v2-image.sh IMAGE
set -euo pipefail
IMAGE=$1
PATH=$PATH:/usr/sbin:/sbin
HERE=$(cd "$(dirname "$0")" && pwd)
WORK=$(mktemp -d); trap 'rm -rf "$WORK"' EXIT
fail=0
ok()  { echo "[check-v2] ok   $*"; }
bad() { echo "[check-v2] FAIL $*"; fail=1; }

# Partition start/size in sectors, from the GPT.
read -r S1 N1 S2 N2 S3 N3 < <(sfdisk --dump "$IMAGE" | sed -n 's/.*start= *\([0-9]*\), size= *\([0-9]*\).*/\1 \2/p' | tr '\n' ' '; echo)
for i in 1 2 3; do
    eval "dd if=\"\$IMAGE\" of=\"\$WORK/p$i\" bs=512 skip=\$S$i count=\$N$i status=none"
done

e2fsck -fn "$WORK/p1" > "$WORK/e2fsck.txt" 2>&1 && ok "e2fsck -fn: A: (ext2 root) is clean: $(tail -1 "$WORK/e2fsck.txt")" \
    || { bad "e2fsck on A:"; cat "$WORK/e2fsck.txt"; }
# The FAT "dirty" bit (boot sector byte 65, bit 0): the kernel's FAT driver
# (the fatfs crate) sets it on the first write. Since Rustbelt 0.21.1 the
# kernel unmounts every file system when pid 1 exits (the "[shutdown]
# unmounted ..." lines), which clears it again. A set bit means the volume
# was not cleanly unmounted (K12, docs/kernel-requests.md): a hard failure.
if [ $(( $(od -An -tu1 -j65 -N1 "$WORK/p2") & 1 )) = 1 ]; then
    bad "B: has the FAT dirty bit set: it was not cleanly unmounted (K12)"
else
    ok "B: FAT dirty bit is clear (the kernel unmounted it at shutdown)"
fi
fsck.fat -n "$WORK/p2" > "$WORK/fsck-fat.txt" 2>&1 && ok "fsck.fat -n: B: (FAT32) is clean: $(tail -1 "$WORK/fsck-fat.txt")" \
    || { bad "fsck.fat on B:"; cat "$WORK/fsck-fat.txt"; }
fsck.exfat -n "$WORK/p3" > "$WORK/fsck-exfat.txt" 2>&1 && ok "fsck.exfat -n: C: (exFAT share) is clean: $(tail -1 "$WORK/fsck-exfat.txt")" \
    || { bad "fsck.exfat on C:"; cat "$WORK/fsck-exfat.txt"; }

info=$(python3 "$HERE/exfat.py" "$WORK/p3" info)
case $info in *"1 FAT(s)"*) ok "share: $info" ;; *) bad "share is not single-FAT: $info" ;; esac
got=$(python3 "$HERE/exfat.py" "$WORK/p3" cat /from-foundry.txt 2>&1 || true)
[ "$got" = "written on Foundry OS by dash" ] && ok "host reads C:/from-foundry.txt: \"$got\"" \
    || bad "C:/from-foundry.txt on the host: '$got'"
listing=$(python3 "$HERE/exfat.py" "$WORK/p3" ls)
echo "$listing" | sed 's/^/[check-v2]      C:\//'
for gone in v2-test.txt v2dir todo.txt made-here seq.txt; do
    echo "$listing" | grep -qw -- "$gone" && bad "C:/$gone should have been deleted" || true
done
echo "$listing" | grep -q "README.TXT" || bad "C:/README.TXT is missing"
# A: and B: through e2fsprogs/mtools: the test files are gone, /etc is there.
debugfs -R "ls -l /" "$WORK/p1" 2>/dev/null | grep -q "v2-test-root.txt" && bad "A:/v2-test-root.txt should be gone" || true
[ "$(debugfs -R 'cat /etc/motd' "$WORK/p1" 2>/dev/null)" = "Welcome to Foundry OS, running on the Rustbelt kernel." ] \
    && ok "A:/etc/motd reads back through debugfs" || bad "A:/etc/motd"
MTOOLS_SKIP_CHECK=1 mdir -b -i "$WORK/p2" ::/ 2>/dev/null | grep -qi "v2-test-b" && bad "B:/v2-test-b.txt should be gone" || true

[ $fail = 0 ] && echo "[check-v2] all host checks passed" || { echo "[check-v2] FAILED"; exit 1; }