Make autoexec.ipxe the boot script, not the opt-in - #1190
Merged
Conversation
fog-ipxe v2.0.0-fog.8 stops embedding a script in any EFI binary, so every one of them downloads autoexec.ipxe and runs it. This is the installer half: publish that script at the TFTP root, hard-link it beside every EFI binary, retire the autoexec/ tree that no longer ships, and add --boot-delay so the 10-second STP/powersave sleep is a setting rather than a second set of binaries. WHAT REVERSED configureTFTPandPXE() used to DELETE any autoexec.ipxe at the TFTP root, and the comment explaining why is worth keeping in mind because the reasoning still holds -- it is the premise that changed, not the logic: efi_probe() calls efi_autoexec_load() unconditionally, so an EMBED-marked binary downloads autoexec.ipxe and then never runs it, because first_image() returns the embedded script ahead of it. Nothing unregisters it, so initrd_load_all() concatenates 2 KB of iPXE script ahead of init.xz and the kernel panics with "VFS: Unable to mount root fs on /dev/ram0" (forums #18213). efi_autoexec_network() falls back to /autoexec.ipxe when the binary's own directory has none, so one embedded EFI binary anywhere was enough to poison every client that fell back to the root. With no EFI binary embedding anything, the script is EXECUTED rather than merely registered, and image_exec() unregisters it for the duration -- so it is gone before boot runs. Legacy BIOS is untouched: it has no efi_autoexec_load(), so a root autoexec.ipxe is a file it never asks for. --boot-delay Seconds of sleep before the first DHCP attempt, for switches slow out of STP or powersave. Bounded 0-120 -- this is a wait every client sits through on every boot, and a fat-fingered 600 is indistinguishable from a hung PXE stack to whoever is standing at the machine. _applyBootDelay() brackets the inserted lines with sentinel comments rather than matching on the sleep line, so an admin's own sleep is never eaten and the option works in both directions: lowering or clearing the delay rewrites the block exactly like raising it. It writes in place with a redirect rather than a temp-and-mv, because by then the file may already be hard-linked and a rename would leave those links on the old inode -- the drift the links exist to prevent. BIOS cannot be served this way and 10secdelay/ is exactly ten seconds, so _biosBootFile() maps any non-zero delay to that build and the run says so when the two cannot agree. THE MANIFEST TRAP _copyIpxeTree() hashes each file as it lays it down, and _applyBootDelay() rewrites autoexec.ipxe afterwards. Without re-stamping, the next run reads the difference as "the admin replaced this file", declines to update it, and the boot script is frozen for good -- the same trap _signLocalIpxe() hits, for the same reason. _restampIpxeManifest() is called for autoexec.ipxe and every path it is linked into. BREAKING A DHCP filename beginning "autoexec/" stops resolving. Drop the prefix: autoexec/snponly.efi becomes snponly.efi. FOG's own generated dhcpd.conf and Kea config never used those paths, so only hand-written configs are affected. _retireAutoexecDir() deletes the stale tree rather than leaving it -- it would otherwise go on serving whichever release last created it, getting quietly older every upgrade while looking maintained -- and prints the mapping.
The release the change above needs. v2.0.0-fog.8 is the first tarball whose EFI binaries carry no embedded script and whose tree publishes autoexec.ipxe at the root, which is what configureTFTPandPXE() now links from. Deliberately in the same PR rather than a follow-up: against v2.0.0-fog.7 the installer would delete the autoexec/ tree that release still depends on, and find no root autoexec.ipxe to replace it with. The two halves are one change.
This was referenced Aug 18, 2026
mastacontrola
added a commit
that referenced
this pull request
Aug 18, 2026
#1190 retired autoexec/ but not 10secdelay/'s EFI files, and that is the half that actually breaks a client. Those .efi are EMBED-marked, and the root now carries an autoexec.ipxe. efi_autoexec_network() falls back to /autoexec.ipxe when the binary's own directory has none -- and 10secdelay/ has none -- so one of them downloads the script, never runs it (first_image() returns its embedded one), nothing unregisters it, and initrd_load_all() concatenates 2 KB of iPXE script ahead of init.xz. The client panics with VFS: Unable to mount root fs on "/dev/ram0" or unknown-block(1,0) That is precisely the failure the EMBED-less change exists to make impossible, reintroduced by an upgrade on a path that worked before it. _copyIpxeTree() cannot clear them: it only ever writes, so anything a release stops shipping stays on disk. Observed on a server that had just upgraded -- the stale 10secdelay/snponly.efi still had "Sleeping 10 seconds" in its strings, and _signLocalIpxe() had given it a fresh mtime, so it looked current. _retireAutoexecDir() therefore becomes _retireStaleEfiPaths() and sweeps: autoexec/ both there and under stock/ 10secdelay/*.efi the loose files beside the BIOS builds 10secdelay/{i386,arm64}-efi/ and the same under stock/ The BIOS files in 10secdelay/ stay -- they are why the directory still exists, since legacy BIOS has no efi_autoexec_load() and so cannot take a --boot-delay. An admin who deliberately placed their own .efi there loses it. Accepted: every EFI binary that can legitimately sit in that directory now is one that would panic the client booting it, and a file that cannot be booted safely is not worth keeping over one that can. Also rejoins _copyIpxeTree()'s leading comment, which #1190 split mid-sentence by inserting these helpers through the middle of it. They now sit above the block rather than inside it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Installer half of fog-ipxe#7, which stops embedding a script in any EFI binary. Publish
autoexec.ipxeat the TFTP root, hard-link it beside every EFI binary, retire theautoexec/tree that no longer ships, and add--boot-delayso the 10-second STP/powersave sleep is a setting rather than a second set of binaries.What reversed
configureTFTPandPXE()used to delete anyautoexec.ipxeat the TFTP root. That comment is worth keeping in mind, because the reasoning still holds — it is the premise that changed:With no EFI binary embedding anything, the script is executed rather than merely registered, and
image_exec()unregisters it for the duration — so it is gone beforebootruns. Legacy BIOS is untouched: noefi_autoexec_load()there, so a rootautoexec.ipxeis a file it never asks for.--boot-delaySeconds of sleep before the first DHCP attempt. Bounded 0–120: this is a wait every client sits through on every boot, and a fat-fingered 600 is indistinguishable from a hung PXE stack to whoever is standing at the machine.
_applyBootDelay()brackets the inserted lines with sentinel comments rather than matching on thesleepline, so an admin's own sleep is never eaten and the option works in both directions — lowering or clearing rewrites the block exactly like raising it. Verified as a unit: insert → change value → clear round-trips to a file byte-identical to the original, and re-applying the same value is stable.It writes in place with a redirect rather than a temp-and-mv, because by then the file may already be hard-linked and a rename would leave those links on the old inode — the drift the links exist to prevent.
BIOS cannot be served this way and
10secdelay/is exactly ten seconds, so_biosBootFile()maps any non-zero delay to that build (both the ISC and Kea generators) and the run says so when the two cannot agree.The manifest trap
_copyIpxeTree()hashes each file as it lays it down, and_applyBootDelay()rewritesautoexec.ipxeafterwards. Without re-stamping, the next run reads the difference as "the admin replaced this file", declines to update it, and the boot script is frozen for good — the same trap_signLocalIpxe()hits, for the same reason._restampIpxeManifest()is called forautoexec.ipxeand every path it is linked into.Breaking
A DHCP
filenamebeginningautoexec/stops resolving; drop the prefix. FOG's own generateddhcpd.confand Kea config never used those paths, so only hand-written configs are affected._retireAutoexecDir()deletes the stale tree rather than leaving it — it would otherwise go on serving whichever release last created it, getting quietly older every upgrade while looking maintained — and prints the mapping.Still to do on this PR
FOG_IPXE_VERSION→v2.0.0-fog.8once taggedfog-docsnote for theautoexec/filename change🤖 Generated with Claude Code