vmix.nix/lib/images/macos/guest/pe.sh
Git Sagar 8dc8f4265d macOS: drive the install and all customization from a Recovery "PE", no GUI
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
2026-09-10 13:33:38 -03:00

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