foundry
Foundry OS: the operating system built on the Rustbelt kernel
| author | Grok Bot <grokbot@localhost> | 2026-10-31 19:55:48 -0700 |
|---|---|---|
| commit | d53297804ff1320f8ca72f01c75460da6c0f33f9 | |
| parent | 12ef9f02ff29a6368263916f136b091398bd13c5 | |
| tree | browse files at this commit | |
scripts/mkimage-v2.sh: one GPT disk with ext2 root, FAT32 data and single-FAT exFAT share
| A | scripts/mkimage-v2.sh | +66 -0 |
1 file changed, 66 insertions, 0 deletions
@@ -0,0 +1,66 @@+#!/usr/bin/env bash+# Build the boot-contract-v2 disk image (docs/boot-contract.md): ONE disk,+# GPT, three partitions, each file system made as its own file first and+# then copied into place (no root, no loop mounts):+#+# p1 ROOT_MIB Linux root (x86-64) ext2 mke2fs -d A: /+# p2 DATA_MIB Microsoft basic data FAT32 mkfs.vfat+mtools B: /mnt/disk0+# p3 SHARE_MIB Microsoft basic data exFAT mkfs.exfat + scripts/exfat.py+# C: /mnt/share+#+# Rustbelt 0.21 mounts the first Linux-root partition holding ext2 at /,+# the first basic-data exFAT partition at /mnt/share, and numbers the+# others /mnt/disk0, /mnt/disk1, ... -- so the FAT32 one is /mnt/disk0.+#+# Usage: scripts/mkimage-v2.sh STAGING IMAGE "B:/bin order..."+# STAGING/root, STAGING/data, STAGING/share: the three trees.+set -euo pipefail+STAGING=$1 IMAGE=$2 ORDER=$3+ROOT_MIB=${ROOT_MIB:-32} DATA_MIB=${DATA_MIB:-40} SHARE_MIB=${SHARE_MIB:-16}+PATH=$PATH:/usr/sbin:/sbin+export MTOOLS_SKIP_CHECK=1 E2FSPROGS_FAKE_TIME=1767225600 # 2026-01-01, for repeatable ext2 times+HERE=$(cd "$(dirname "$0")" && pwd)+MIB=2048 # sectors per MiB+P1=$MIB P2=$((P1 + ROOT_MIB * MIB)) P3=$((P2 + DATA_MIB * MIB))+END=$((P3 + SHARE_MIB * MIB)) # then 1 MiB for the backup GPT+rm -f "$IMAGE" "$IMAGE".p?++# p1: ext2. -b 1024 like the kernel's own test root; -m 0: no blocks+# reserved for root; root_owner: files owned by root, not by whoever builds.+mke2fs -q -t ext2 -b 1024 -m 0 -L foundry-root -U 466f756e-6472-794f-5300-726f6f740001 \+ -E root_owner=0:0,hash_seed=466f756e-6472-794f-5300-726f6f740002 \+ -d "$STAGING/root" "$IMAGE.p1" $((ROOT_MIB * 1024))++# p2: FAT32, filled with mtools: the top level, then bin/ in ORDER.+mkfs.vfat -F 32 -s 1 -n FOUNDRY -i 466f6e64 -C "$IMAGE.p2" $((DATA_MIB * 1024)) >/dev/null+for entry in $(cd "$STAGING/data" && ls -A | LC_ALL=C sort); do+ [ "$entry" = bin ] && continue+ mcopy -s -i "$IMAGE.p2" "$STAGING/data/$entry" ::/+done+mmd -i "$IMAGE.p2" ::/bin+for p in $ORDER; do+ [ -f "$STAGING/data/bin/$p" ] || { echo "[mkimage-v2] missing $STAGING/data/bin/$p"; exit 1; }+ mcopy -i "$IMAGE.p2" "$STAGING/data/bin/$p" "::/bin/$p"+done++# p3: exFAT, one FAT (two would be TexFAT, which Rustbelt mounts read-only).+truncate -s $((SHARE_MIB * 1024 * 1024)) "$IMAGE.p3"+mkfs.exfat -q -L SHARE "$IMAGE.p3" >/dev/null+python3 "$HERE/exfat.py" "$IMAGE.p3" put "$STAGING/share"+fsck.exfat -n "$IMAGE.p3" >/dev/null || { echo "[mkimage-v2] fsck.exfat failed on the share"; exit 1; }++# The disk: zeros + GPT, then the three file systems.+truncate -s $(((END + MIB) * 512)) "$IMAGE"+sfdisk --quiet "$IMAGE" <<GPT+label: gpt+label-id: 466F756E-6472-794F-5300-000000000000+start=$P1, size=$((ROOT_MIB * MIB)), type=4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709, uuid=466F756E-6472-794F-5300-000000000001, name="root"+start=$P2, size=$((DATA_MIB * MIB)), type=EBD0A0A2-B9E5-4433-87C0-68B6B72699C7, uuid=466F756E-6472-794F-5300-000000000002, name="data"+start=$P3, size=$((SHARE_MIB * MIB)), type=EBD0A0A2-B9E5-4433-87C0-68B6B72699C7, uuid=466F756E-6472-794F-5300-000000000003, name="share"+GPT+for i in 1 2 3; do+ eval start=\$P$i+ dd if="$IMAGE.p$i" of="$IMAGE" bs=512 seek="$start" conv=notrunc status=none+ rm -f "$IMAGE.p$i"+done+echo "[mkimage-v2] $IMAGE: $(( (END + MIB) / MIB )) MiB, GPT: ext2 root ${ROOT_MIB} MiB (A:), FAT32 data ${DATA_MIB} MiB (B:), exFAT share ${SHARE_MIB} MiB (C:)"