#!/bin/bash
#
# Rosetta 2 installer for Apple Silicon Macs.
#
# 1. Exit immediately (success, no action) on non-arm64 hardware.
# 2. Exit immediately (success, no action) if Rosetta 2 is already installed.
# 3. Otherwise install it non-interactively, then verify that translation is
#    actually *live* by exec'ing a known x86_64 binary rather than sleeping for
#    a fixed guess. `softwareupdate --install-rosetta` is synchronous and the
#    runtime is on disk when it returns 0, but the very first x86_64 exec after
#    install can still fail with "Bad CPU type in executable" before oahd is
#    spawnable.
# 4. Reboot, so the agents start cleanly under the new runtime. Only reached
#    when this run actually installed Rosetta - so at most once per machine.
#
# Runs as root from an MDM policy. Idempotent and safe to run repeatedly: every
# run re-checks from scratch and exits early when there is nothing to do. The
# MDM owns the schedule and the retry - this script has no timer of its own.
#
# Exit codes:
#   0 - nothing to do, or Rosetta 2 installed successfully
#   1 - installation failed (retry on the next scheduled run)
#

set -u

LOG_TAG="rosetta_check"

# /var/log is root:wheel 755. Deliberately NOT /tmp (mode 1777 - the sticky bit
# stops deletion, not creation) and not /Library/Logs (admin-writable): on those
# an unprivileged local user can pre-create this path as a symlink, and the root
# redirect below would then truncate whatever it points at.
INSTALL_LOG="/var/log/rosetta_install.log"

# Ceiling, not a cost: polled, and returns as soon as it succeeds.
ROSETTA_READY_TIMEOUT=60
ROSETTA_READY_INTERVAL=2

# Reboot once Rosetta 2 has been installed. Set to 0 to log that a reboot is
# needed and leave it to the MDM or the user.
REBOOT_AFTER_INSTALL=1

# Grace period before the reboot, in minutes. Raise it if these machines are
# likely to be in use when the policy runs. 0 reboots immediately.
REBOOT_DELAY_MINUTES=1

log() {
    echo "$(/bin/date -u +'%Y-%m-%dT%H:%M:%SZ') [${LOG_TAG}] $*"
}

machine_arch="$(/usr/bin/uname -m)"
log "uname -m=${machine_arch}"
if [ "${machine_arch}" != "arm64" ]; then
    log "Not Apple Silicon hardware (${machine_arch}); Rosetta 2 is not required here. Exiting."
    exit 0
fi

rosetta_installed() {
    # The runtime file on disk is the authoritative signal, and /Library/Apple
    # is SIP-protected, so no local user can fake it.
    #
    # Deliberately NOT `pgrep oahd`: pgrep matches on process name, so any
    # unprivileged user can run a process called "oahd" and make this return
    # true - suppressing the install while the MDM policy still reports success.
    # oahd is also spawned lazily by the first Intel exec, so its absence never
    # meant Rosetta was missing in the first place.
    [ -e "/Library/Apple/usr/libexec/oah/libRosettaRuntime" ]
}

# rosetta_translation_ready actually exercises translation instead of
# inferring it. /usr/bin/true is a universal binary on macOS, so forcing it
# through the x86_64 slice is the cheapest possible end-to-end proof that the
# kernel can exec an Intel binary *right now* - which can still be false for a
# moment after `softwareupdate --install-rosetta` returns.
rosetta_translation_ready() {
    /usr/bin/arch -x86_64 /usr/bin/true >/dev/null 2>&1
}

wait_for_rosetta_ready() {
    waited=0
    while [ "${waited}" -lt "${ROSETTA_READY_TIMEOUT}" ]; do
        if rosetta_translation_ready; then
            log "Rosetta translation verified live after ${waited}s."
            return 0
        fi
        /bin/sleep "${ROSETTA_READY_INTERVAL}"
        waited=$((waited + ROSETTA_READY_INTERVAL))
    done

    log "WARNING: could not verify Rosetta translation within ${ROSETTA_READY_TIMEOUT}s."
    return 1
}

# --- Install Rosetta 2 only if it is missing -------------------------------

if rosetta_installed; then
    log "Rosetta 2 is already installed; nothing to do. Exiting."
    exit 0
fi

log "Rosetta 2 not detected; attempting non-interactive install."
if /usr/sbin/softwareupdate --install-rosetta --agree-to-license >"${INSTALL_LOG}" 2>&1; then
    log "Rosetta 2 installation succeeded."
else
    install_exit_code=$?
    log "Rosetta 2 installation failed (exit ${install_exit_code}); see ${INSTALL_LOG}. Will retry on next scheduled run."
    exit 1
fi

# --- Confirm translation is actually usable --------------------------------

wait_for_rosetta_ready

# --- Reboot to complete setup ----------------------------------------------
#
# Only reachable when this run installed Rosetta 2: the "already installed"
# and "install failed" paths both exit above. The reboot is what gets the
# agents running, since they were started before Rosetta existed and launchd
# has throttled them.

if [ "${REBOOT_AFTER_INSTALL}" -ne 1 ]; then
    log "Rosetta 2 installed. A reboot is required to complete setup, but REBOOT_AFTER_INSTALL=0, so leaving the machine up."
    exit 0
fi

if [ "${REBOOT_DELAY_MINUTES}" -le 0 ]; then
    log "Rosetta 2 installed; rebooting now."
    /sbin/shutdown -r now
else
    log "Rosetta 2 installed; rebooting in ${REBOOT_DELAY_MINUTES} minute(s)."
    # Backgrounded so the MDM policy can complete and record success rather
    # than blocking for the whole grace period.
    /usr/bin/nohup /sbin/shutdown -r "+${REBOOT_DELAY_MINUTES}" \
        "Rosetta 2 has been installed. This Mac will restart to complete setup." \
        >/dev/null 2>&1 &
fi

exit 0
