mirror of
https://github.com/Klipper4FlashForge/firmware.git
synced 2026-10-21 21:02:16 -05:00
The software component existed to give the mod one exec hook. It is not needed for that any more, so a release now carries our installer and our payload and nothing else: 26MB smaller, 21MB of which was FlashForge's own firmwareExe travelling back to the partition it was already on, along with their klippy tree, their wifi module and their configs. WHAT IT GIVES BACK. /usr/prog/PROGRAM/software is no longer rewritten, so the version directory there stays FlashForge's with their genuine firmwareExe inside it -- and app_startup.sh's five-second watchdog, which copies one out of that directory when nothing by that name is running, has something to copy again. A printer whose payload fails to install now comes up on the stock UI instead of a blank screen. That recovery has been broken since we started deleting their binary out of a component we shipped; docs/how-it-works.md claimed it worked throughout. THE ROOT PASSWORD moves with it, because it used to ride in the component's shadow file. bin/pack.sh bakes ROOT_PW_HASH into the installer, single-quoted -- an unquoted $6$... would have the printer's shell expand $6 as a positional parameter and ship a truncated hash -- and the installer writes it to /usr/prog/etc/shadow. The random-password path asks one question instead of four: FlashForge ship the same root hash on every machine, so a live shadow still carrying it means nobody has set a password and it is ours to set. The .prev-root-hash recording, the shipped-vs-live comparison and the restore-it- afterwards step were all machinery for surviving a file that nothing overwrites any more, and are gone. pack.sh checks the hardcoded constant against the stock package it built from, because getting it wrong is silent and total: every printer would read as "already set" and none would ever get a password. bin/patch.sh is bin/payload.sh. It patched nothing any more -- no splice, no shadow edit, no firmwareExe deletion -- and what is left is the payload: the feed installed by the printer's own opkg, the seeded config, the manifest. Its sections are renumbered 1-5 with no gaps, and the five tombstone comments marking where removed sections used to be are gone with them. test_recipe_layout.py loses six of its nine tests. Each compared the tree against a description of the tree -- no fourth directory kind, each kind still used, 3rdparty carries no files of ours, installer/ holds exactly two named files -- and none could go red for a reason a printer would notice, while all six went red the moment the layout legitimately changed. The two that bite are kept: a payload/ path escaping $MODDIR, and a recipe name at both levels, which makes pkg_dir silently build the wrong package. SW_VER is deleted from config.env.example and both workflows: it stamped a component that is not built. Gates: 112 static tests pass. The generated installer is verified after substitution -- all four lines present, and `sh -n` over the result, because a hash with a stray character in it would otherwise reach a printer as a syntax error whose only symptom is a package that installs nothing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CH7Yb4wuPhnppHAB25UX7e
2.8 KiB
2.8 KiB
The printer replica
A container that runs the printer's own userland: the real
rootfs.squashfs extracted from FlashForge's package, chrooted, with its
MIPS binaries executing under qemu. uname -m says mips and busybox applets
behave exactly as they do on the machine.
It lives under tools/ rather than test/ because it is not a test. Three
different things drive it, and only one of them is a suite:
| driver | what it does with it |
|---|---|
bin/payload.sh -> bin/build-payload.py |
the build path. The payload is assembled by running the PRINTER'S OWN opkg against /, inside here. Nothing on the host can do that |
qa/lib/replica.py |
the replica lane's printer fixture -- holds one container open and probes it |
make boot-screen-sim |
rendering the boot frames on the cross-built CPython |
printer/ the machine itself, SHELL on purpose: it is executed
by the printer's ash under qemu, and that it survives
that is a large part of what the suite proves
Dockerfile the container: qemu-user-static, rsync, openssl,
dosfstools. It contributes no userland worth speaking
of -- everything real comes from the chroot
Dockerfile.full the same, plus the firmware baked in: a prebuilt
PRINTER_IMAGE, so a run does not unpack 93MB
binfmt.sh registers a handler for the printer's binaries. The
stock qemu-mipsel registration does not match them:
its mask requires e_ident[EI_ABIVERSION] == 0 and
every binary the Ingenic toolchain built has 3 there
assemble.sh the mount layout -- read-only root, writable prog and
data partitions, optionally a real FAT USB stick
seed-prog.sh a /usr/prog that looks like a printer's
entrypoint.sh setup, then the case script it was given
entrypoint-out.sh the same, plus a writable /out inside the chroot
bake.sh, bake-case.sh install a package and commit the result as an image
ffsim/ the host half. NOT a test framework -- it was one,
and 1,657 lines of it are gone; what is left starts
containers and reads config.env/test.env
build-printer-image.sh bakes a prebuilt replica image (`make printer-image`)
sim-boot-screen.py `make boot-screen-sim`
--privileged buys exactly two things: the binfmt registration, and the mount
layout. Nothing here needs it for any other reason.
See docs/printer-replica.md for what the replica can and cannot prove, and docs/testing.md for the suites.