Per-repo documentation — each repo's docs/ and README, ingested and associated with the repo. Rendered through the <<<RepoDocs>>> tag.
← squashpi docs · README.md
Build a read-only squashfs Raspberry Pi SD image from a source .img. Clean rebuild of the old squashfs-main / rsync2img scripts.
source .img → loop-mount (boot p1 vfat, root p2 ext4) → fresh partitioned target img → copy boot + rsync root → mksquashfs read-only root → (next: chroot customize + assemble bootable squashfs SD image). Geometry is a model (vfat boot + ext4 root, sized in MB).
The privileged steps (losetup, mkfs.*, mksquashfs, mount, chroot) are Linux + root. They do not run on macOS — use the bundled privileged Docker builder.
# anywhere (no privilege): inspect environment + plan
python -m squashpi.cli doctor rpi.img
python -m squashpi.cli plan rpi.img --boot-mb 256 --root-mb 3840
# real build — in the privileged Linux container
docker build -t squashpi .
docker run --rm --privileged \
-v "$PWD/output:/work/output" -v "/path/to/rpi.img:/work/rpi.img" \
squashpi build /work/rpi.img --out /work/output
doctor reports missing tools / non-Linux host; plan is a safe dry-run of the whole sequence. Works for RPi images (e.g. raspios-trixie-arm64-lite.img).
qemu-system-arm runs natively on Apple Silicon, so you can boot the image without hardware. On M1, RPi2 (raspi2b, ARMv7) is the stable target — raspi0/raspi-zero and raspi3b/4b emulation are buggy on M1. RPi2 is 32-bit, so use the armhf image + kernel7.img + bcm2709-rpi-2-b.dtb (extract those from the image's boot partition; on macOS via hdiutil attach -imagekey diskimage-class=CRawDiskImage <img>).
# preview the exact qemu invocation (safe anywhere)
python -m squashpi.cli emulate card.img --dry-run
# boot it (raspi2b default); pass extracted kernel/dtb if not in cwd
python -m squashpi.cli emulate card.img --kernel kernel7.img --dtb bcm2709-rpi-2-b.dtb
Customize the rootfs before squashing — apt update && apt full-upgrade by default — via a chroot using qemu-user-static binfmt (so ARM apt runs in the x86/arm64 builder):
python -m squashpi.cli customize /output/root # default: apt update/upgrade
python -m squashpi.cli customize /output/root --script my.sh # custom packages/config
The generated busybox initramfs loop-mounts root.squashfs (lower) and an overlay upper layer, then switch_roots. The layer type is a boot-time choice via cmdline.txt: - squashpi.overlay=tmpfs — RAM upper, ephemeral, SD-wear-free (default) - squashpi.overlay=persist — upper on a writable ext4 partition, survives reboot
assemble_squash_image() builds the bootable SD: a vfat partition with firmware + kernel + dtb + initramfs.cpio.gz + root.squashfs, config.txt declaring the initramfs, and cmdline.txt selecting the overlay. (Both phases run in the privileged Docker builder.)