Replace the screenshot/OCR/keystroke driving of Apple's Recovery with a "PE": BaseSystem.dmg (a journaled HFS+ volume, writable from Linux) with one LaunchDaemon added (makeRecoveryPE) that runs /Volumes/VMIX/run.sh as root at boot, records the status and powers off. launchd loads it alongside its signed cache (verified on Tahoe 26.6.2); same idea as AutoNBI/Imagr NetBoot images. - makeImage: the PE runs vmix-install.sh (erase, installer app, SharedSupport pkgdmg, startosinstall). Progress is read from the serial console (boot-args serial=3 -v, VMIX-* markers) and screenshots (brightness only). Fully offline; prepare now takes ~5 min instead of ~10. - customizeImage: boots the PE with the image attached and runs the template offline against the mounted System/Data volumes; OpenCore ScanPolicy restricted to HFS+/SATA so only the PE can boot. One PE boot ~30 s. The installed macOS is never booted for customization, so nothing depends on launchd/BTM approval or a first-boot agent (removed). - templates rewritten for offline use: generalize creates the user with dscl -f (admin, home, auto-login kcpassword, Setup Assistant suppression, hostname, locale, timezone, keyboard type, container resize); remote-access, no-updates, performance edit the target's plists. - makeBootDisk: build-time OpenCore variant (serial console, ScanPolicy). - vm-driver.py rewritten: passive observation only (serial markers, kernel boots, panics, brightness), disk+serial-aware hang watchdog, reboot-death reset, halt/loginwindow detection. No OCR/tesseract. - OpenCore: four SMBIOS DIMMs for MacPro7,1 (no "Memory Modules Misconfigured" warning). - tools/soak.sh: repeatability harness. Verified on daku: base install 23 min end to end; basic + generalize in three ~30 s PE boots; the result auto-logs into the desktop with the created user. Root cause of the "first-boot hang" (from the serial log): the guest's restart path panics (IOPlatformHaltRestartAction -> AppleSMC, SMCWDT smcWriteKey kSMCBadCommand, nested panic) because the pinned OSX-KVM Lilu disables itself on macOS 26, so VirtualSMC never loads. Handled by the driver (reset within 60 s); kext update to follow. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XsESshRCoBoUVWV9qKURUF
40 lines
1.4 KiB
Bash
Executable file
40 lines
1.4 KiB
Bash
Executable file
#!/bin/bash
|
|
# vmix PE hook. Runs as root from launchd when the patched Recovery boots
|
|
# (injected by makeRecoveryPE). If a VMIX volume is attached it runs
|
|
# /Volumes/VMIX/run.sh, records the exit status on the volume and powers off;
|
|
# without one it does nothing and the recovery behaves normally.
|
|
# Everything printed here goes to /dev/console, i.e. the host's serial log.
|
|
exec >/dev/console 2>&1
|
|
echo "VMIX-PE: hook started $(date) uid=$(id -u)"
|
|
V=/Volumes/VMIX
|
|
i=0
|
|
while [ ! -f "$V/run.sh" ] && [ $i -lt 90 ]; do
|
|
diskutil mount VMIX >/dev/null 2>&1
|
|
sleep 2; i=$((i + 1))
|
|
done
|
|
if [ ! -f "$V/run.sh" ]; then
|
|
echo "VMIX-PE: no VMIX volume, leaving the recovery alone"
|
|
exit 0
|
|
fi
|
|
echo "VMIX-PE: VMIX mounted after $i retries"
|
|
caffeinate -dimsu -t 86400 >/dev/null 2>&1 &
|
|
[ -f "$V/vmix.conf" ] && . "$V/vmix.conf"
|
|
# certificate checks need a sane clock; a fresh VM RTC can be off
|
|
[ -n "${BUILD_DATE:-}" ] && date -u "$BUILD_DATE" >/dev/null 2>&1 && echo "VMIX-PE: clock set to $(date -u)"
|
|
export V
|
|
cd "$V"
|
|
echo "VMIX-PE: running run.sh"
|
|
/bin/bash "$V/run.sh" 2>&1 | tee "$V/vmix-run.log"
|
|
rc=${PIPESTATUS[0]}
|
|
echo "$rc" > "$V/vmix-run.status"
|
|
echo "VMIX-PE: run.sh exited $rc"
|
|
if [ -f "$V/vmix-reboot" ]; then
|
|
rm -f "$V/vmix-reboot"; sync
|
|
echo "VMIX-PE: rebooting as requested"
|
|
reboot
|
|
exit 0
|
|
fi
|
|
sync; sleep 1
|
|
diskutil unmount force "$V" >/dev/null 2>&1
|
|
echo "VMIX-PE-DONE rc=$rc"
|
|
shutdown -h now
|