RustForge

foundry

Foundry OS: the operating system built on the Rustbelt kernel

foundry / scripts / mkimage-v2.sh
4130 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
#!/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))
# mke2fs -d copies each file's owner from the build machine (root_owner only
# covers the top directory), so everything would belong to whoever ran
# `make` (uid 1000 here). Make every file root's (uid 0, gid 0), and give
# /home/tyler to tyler (1000:1000, as in /etc/passwd), with debugfs.
( cd "$STAGING/root" && find . -mindepth 1 | LC_ALL=C sort | sed 's|^\.||' |
  while read -r f; do
      case $f in /home/tyler) u=1000 ;; *) u=0 ;; esac
      echo "sif $f uid $u"; echo "sif $f gid $u"
  done ) > "$IMAGE.owners"
debugfs -w -f "$IMAGE.owners" "$IMAGE.p1" > /dev/null 2>&1
rm -f "$IMAGE.owners"

# 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:)"