RustForge

rust-kernel

Rustbelt: a hobby x86_64 kernel written in Rust

rust-kernel / scripts / exfat-check.sh
4704 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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#!/usr/bin/env bash
# Check Rustbelt's exFAT writes with the host's own tools (exfatprogs).
#
#   1. fsck.exfat the pristine images build.rs made (this checks the
#      build-time populator, build/exfat_populate.rs).
#   2. Copy them to target/fsck/ and boot Rustbelt on the *writable* copies
#      (no snapshot=on), so whatever it writes really lands in the files:
#        - the shell self-test (cp B:/C: -> D:, cp D: -> C:, md, echo >)
#        - the tests/exfat.rs kernel (create/write/append/truncate/unlink/
#          rmdir, NoFatChain -> FAT chain, a directory grown to 200 files,
#          root directory growth; 4 KiB and 512-byte clusters)
#   3. `fsck.exfat -n` every copy: -n = open read-only and answer "no" to
#      every question (report, don't fix). It checks the boot checksum,
#      bitmap vs. cluster chains, SetChecksums, name hashes... Any
#      complaint means the driver wrote something inconsistent.
#   4. Show the self-test copy's root directory and one new file with
#      dump.exfat, and read that file's bytes straight off the image.
#
# Usage: ./scripts/exfat-check.sh   (after `cargo build` and
#        `cargo test --test exfat`, which build the images and the kernels)
set -euo pipefail
cd "$(dirname "$0")/.."
export PATH="$HOME/.cargo/bin:$PATH:/usr/sbin:/sbin"
for tool in fsck.exfat dump.exfat qemu-system-x86_64; do
    command -v $tool >/dev/null || { echo "need $tool (apt install exfatprogs qemu-system-x86)"; exit 1; }
done

fsck() { # fsck <image> <title>
    echo "== fsck.exfat -n $1 ($2)"
    fsck.exfat -n "$1" || { echo "!! fsck.exfat found problems in $1"; status=1; }
}
status=0

for img in target/exfat.img target/exfat-512.img; do
    fsck $img "pristine, as built"
done

mkdir -p target/fsck
cp target/exfat.img target/fsck/selftest-exfat.img
for img in exfat exfat-512; do cp target/$img.img target/fsck/tests-$img.img; done

echo "== boot the shell self-test on target/fsck/selftest-exfat.img"
EXFAT_IMG=target/fsck/selftest-exfat.img ./scripts/run-headless.sh >/dev/null && echo "self-test OK"

echo "== run the tests/exfat.rs kernel on target/fsck/tests-exfat*.img"
KERNEL=$(ls -t target/x86_64-rust_kernel/debug/build/rustbelt/*/out/bootimage-exfat-*.bin 2>/dev/null | head -1 || true)
[ -n "$KERNEL" ] || { echo "no test kernel: run 'cargo test --test exfat' first"; exit 1; }
set +e
timeout 120 qemu-system-x86_64 -drive format=raw,file="$KERNEL" -no-reboot \
    -drive file=target/disk.img,format=raw,if=virtio,snapshot=on \
    -drive file=target/ext2.img,format=raw,if=virtio,snapshot=on \
    -drive file=target/fsck/tests-exfat.img,format=raw,if=virtio \
    -drive file=target/btrfs.img,format=raw,if=virtio,snapshot=on \
    -drive file=target/ext2-4k.img,format=raw,if=virtio,snapshot=on \
    -drive file=target/ext2-rev0.img,format=raw,if=virtio,snapshot=on \
    -drive file=target/fsck/tests-exfat-512.img,format=raw,if=virtio \
    -device isa-debug-exit,iobase=0xf4,iosize=0x04 \
    -serial stdio -display none > target/fsck/tests-exfat.log
code=$?
set -e
grep -c "\[ok\]" target/fsck/tests-exfat.log | sed 's/$/ exFAT tests ok/'
[ $code = 33 ] || { echo "!! test kernel failed (exit $code), see target/fsck/tests-exfat.log"; exit 1; }

for img in target/fsck/selftest-exfat.img target/fsck/tests-exfat.img target/fsck/tests-exfat-512.img; do
    fsck "$img" "after Rustbelt wrote to it"
done

IMG=target/fsck/selftest-exfat.img
echo "== dump.exfat: what is in / on the self-test copy"
dump.exfat -s / $IMG 2>/dev/null | sed -n 's/^Path: /  /p'
# (dump.exfat -s, a directory scan, rather than -d "/New Folder/Note.txt":
# exfatprogs 1.2.9's -d can't find files inside some directories, e.g.
# "NewFolder", even on images only mkfs + our populator ever touched.)
echo "== dump.exfat -s \"/New Folder\": the entry set Rustbelt wrote for Note.txt"
set_info=$(dump.exfat -s "/New Folder" $IMG 2>/dev/null)
echo "$set_info" | grep -E "^Path|Entrytype|SetChecksum|GeneralSecondaryFlags|NameLength|NameHash|FirstCluster|DataLength" | sed 's/^ */  /'
# Read the file's bytes straight from the image: cluster N starts at
# ClusterHeapOffset + (N - 2) * cluster size.
info=$(dump.exfat $IMG 2>/dev/null)
heap=$(echo "$info" | sed -n 's/^Cluster Heap Offset (sector offset): *//p')
spc=$(echo "$info" | sed -n 's/^Sectors per Cluster: *//p')
first=$(echo "$set_info" | sed -n 's/^ *FirstCluster: *//p' | head -1)
len=$(echo "$set_info" | sed -n 's/^ *DataLength: *//p' | head -1)
echo "== its $len bytes at cluster $first, read with dd:"
dd if=$IMG bs=512 skip=$((heap + (first - 2) * spc)) count=1 status=none | head -c "$len"

[ $status = 0 ] && echo "== all images are clean" || echo "== fsck.exfat found problems"
exit $status