From 97691620d87d3ecc7071a6a235870c28c176b205 Mon Sep 17 00:00:00 2001 From: MikeBeaton Date: Sun, 2 Oct 2022 15:46:02 +0100 Subject: [PATCH] Utilities: Update LogoutHook/Launchd.command for earlier macOS - Compatible with earlier macOS (Snow Leopard+ tested) - Automatically installs as launch daemon (Yosemite+) or logout hook --- Changelog.md | 4 + Utilities/LogoutHook/Launchd.command | 524 ++++++++++++++++----------- 2 files changed, 311 insertions(+), 217 deletions(-) diff --git a/Changelog.md b/Changelog.md index 062cd423..984bad01 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,9 @@ OpenCore Changelog ================== +#### v0.8.6 +- Updated emulated NVRAM save script for compatibilty with earlier macOS (Snow Leopard+ tested) +- Updated emulated NVRAM save script to automatically install as launch daemon (Yosemite+) or logout hook + #### v0.8.5 - Updated builtin firmware versions for SMBIOS and the rest - Moved CPU objects that exist only in Windows Server 2022 into `SSDT-HV-DEV-WS2022.dsl` diff --git a/Utilities/LogoutHook/Launchd.command b/Utilities/LogoutHook/Launchd.command index da631a2e..77190b27 100755 --- a/Utilities/LogoutHook/Launchd.command +++ b/Utilities/LogoutHook/Launchd.command @@ -1,49 +1,54 @@ #!/bin/bash # -# Copyright © 2019-2022 Rodion Shingarev, PMheart, vit9696, mikebeaton. -# -# Includes logic to install and run this script as one or more of -# agent, daemon or logout hook. Can also be run directly for testing, -# use CTRL+C for script termination. -# -# Currently installs just as launch daemon, which is the only one that -# on shutdown can access NVRAM after macOS installer vars are set. +# Copyright © 2022 Mike Beaton. All rights reserved. +# SPDX-License-Identifier: BSD-3-Clause # # Examine log at /var/log/org.acidanthera.nvramhook.launchd/launchd.log. # - -if [ ! -x /usr/bin/dirname ] || - [ ! -x /usr/bin/basename ] || - [ ! -x /usr/bin/wc ] || - [ ! -x /usr/sbin/diskutil ] || - [ ! -x /usr/sbin/nvram ] ; then - abort "Unix environment is broken!" -fi - -# Non-installed script can be run directly as 'agent' or 'daemon', i.e. script -# is started and runs as if launched that way by launchd, for debugging purposes. +# Script can run immediately or be installed as daemon or logout hook. Installs as +# launch daemon on Yosemite and above, which is the only supported approach that on +# shutdown reads NVRAM after macOS installer vars are set, in more recent macOS +# installers (e.g. Monterey). # -# Agent is currently a null install, mainly since it seemed a shame to remove -# that code - i.e. it installs, and stops and starts correctly, but unlike -# daemon it does not actually do anything at stop and start. (Daemon is sudo -# so not everything that daemon does can be done by agent, also not everything -# that daemon does needs to be done, by agent.) +# Non-installed script can be run directly as 'daemon' or 'logout' hook by +# specifying one of those options on the command line. For 'logout' this saves NVRAM +# immediately, for 'daemon' this waits to be terminated e.g. CTRL+C before saving. # -# Note that agent shutdown is to early to pick up NVRAM changes made by macOS -# installer before first restart, whereas daemon is not. +# TO DO: rc.shutdown.d approach discussed in +# https://github.com/acidanthera/bugtracker/issues/2106 +# might be a viable alternative (needs testing re timing of picking up NVRAM changes). # +# Credits: +# - Rodion Shingarev (with additional contributions by vit9696 and PMheart) for +# original LogoutHook.command +# - Rodion Shingarev for nvramdump command +# - Mike Beaton for this script +# + usage() { - echo "Usage: ${SELFNAME} [install|uninstall|status] [logout|agent|daemon]" - echo " - [install|uninstall|status] with no type uses recommended type (daemon)." + echo "Usage: ${SELFNAME} [install|uninstall|status] [logout|daemon]" + echo " - [install|uninstall] without type uses recommended type for macOS version" + echo " - 'status' shows status of daemon and logout hook" + echo " - 'status daemon' gives additional detail on daemon" echo "" } doLog() { - if [ ! "${PREFIX}" = "" ] ; then - echo "$(date) (${PREFIX}) ${1}" >> "${LOG}" + # 'sudo tee' to write to log file as root (could also 'sh -c') for installation steps; + # will be root anyway when running installed as daemon or logout hook + if [ ! "${LOG_PREFIX}" = "" ] ; then + sudo tee -a "${LOGFILE}" > /dev/null << EOF +$(date +"${DATEFORMAT}") (${LOG_PREFIX}) ${1} +EOF else - echo "${1}" >> "${LOG}" + sudo tee -a "${LOGFILE}" > /dev/null << EOF +${1} +EOF + fi + + if [ ! "$INSTALLED" = "1" ] ; then + echo "${1}" fi } @@ -52,102 +57,31 @@ abort() { exit 1 } -NVRAM_DIR="NVRAM" - -WRITE_HOOK_LOG=0 - -LOG=/dev/stdout - -OCNVRAMGUID="4D1FDA02-38C7-4A6A-9CC6-4BCCA8B30102" - -# OC generated NVRAM var -BOOT_PATH="${OCNVRAMGUID}:boot-path" - -# temp storage name for this hook -BOOT_NODE="${OCNVRAMGUID}:boot-node" - -# re-use as unique directory name for mount point when needed -UNIQUE_DIR="${BOOT_NODE}" - -PRIVILEGED_HELPER_TOOLS="/Library/PrivilegedHelperTools" - -ORG="org.acidanthera.nvramhook" -NVRAMDUMP="/Library/PrivilegedHelperTools/${ORG}.nvramdump.helper" - -DAEMON_PLIST="/Library/LaunchDaemons/${ORG}.daemon.plist" -AGENT_PLIST="/Library/LaunchAgents/${ORG}.agent.plist" - -HELPER="/Library/PrivilegedHelperTools/${ORG}.helper" -LOGDIR="/var/log/${ORG}.launchd" -LOGFILE="${LOGDIR}/launchd.log" - -SELFDIR="$(/usr/bin/dirname "${0}")" -SELFNAME="$(/usr/bin/basename "${0}")" - -USERID=$(id -u) - -for arg; -do - case $arg in - install ) - INSTALL=1 - ;; - uninstall ) - UNINSTALL=1 - ;; - agent ) - AGENT=1 - PREFIX="Agent" - ;; - daemon ) - DAEMON=1 - PREFIX="Daemon" - ;; - logout ) - LOGOUT=1 - ;; - status ) - STATUS=1 - ;; - * ) - usage - exit 0 - ;; - esac -done +# abort without logging or requiring sudo +earlyAbort() { + echo "Fatal error: ${1}" > /dev/stderr + exit 1 +} -if [ ! "$SELFNAME" = "Launchd.command" ] ; then - USE_NVRAMDUMP="${NVRAMDUMP}" - INSTALLED=1 -else - cd "${SELFDIR}" || abort "Failed to enter working directory!" +getDarwinMajorVersion() { + darwin_ver=$(uname -r) + # Cannot add -r in earlier macOS + # shellcheck disable=SC2162 + IFS="." read -a darwin_ver_array <<< "$darwin_ver" + echo "${darwin_ver_array[0]}" +} - if [ ! -x ./nvramdump ] ; then - abort "nvramdump is not found!" +installLog() { + FAIL="Failed to install log!" + if [ ! -d "${LOGDIR}" ] ; then + sudo mkdir "${LOGDIR}" || abort "${FAIL}" fi - USE_NVRAMDUMP="./nvramdump" - INSTALLED=0 -fi - -# When installed runs as logout hook - i.e. dump immediately - unless specified otherwise. -if [ ! "$AGENT" = "1" ] && - [ ! "$DAEMON" = "1" ] && - [ ! "$LOGOUT" = "1" ] ; then - if [ "$INSTALL" = "1" ] || - [ "$UNINSTALL" = "1" ] ; then - DAEMON=1 - else - if [ "$INSTALLED" = "0" ] && - [ ! "$STATUS" = "1" ] ; then - usage - exit 0 - fi - LOGOUT=1 + if [ ! -f "${LOGFILE}" ] ; then + sudo touch "${LOGFILE}" || abort "${FAIL}" fi -fi +} -# Install one or more of agent, daemon and logout hook. install() { FAIL="Failed to install!" @@ -155,52 +89,23 @@ install() { sudo mkdir "${PRIVILEGED_HELPER_TOOLS}" || abort "${FAIL}" fi - if [ "$LOGOUT" = "1" ] ; then - # logout hook from more permanent location if available - if [ "$AGENT" = "1" ] || - [ "$DAEMON" = "1" ] ; then - HOOKPATH="${HELPER}" - else - HOOKPATH="$(pwd)/${SELFNAME}" - fi - sudo defaults write com.apple.loginwindow LogoutHook "${HOOKPATH}" || abort "${FAIL}" - fi - + # Copy executable files into place. sudo cp "${SELFNAME}" "${HELPER}" || abort "${FAIL}" sudo cp nvramdump "${NVRAMDUMP}" || abort "${FAIL}" - # customise Launchd.command.plist for agent - if [ "$AGENT" = "1" ] ; then - sed "s/\$LABEL/${ORG}.agent/g;s/\$HELPER/$(sed 's/\//\\\//g' <<< $HELPER)/g;s/\$PARAM/agent/g;s/\$LOGFILE/$(sed 's/\//\\\//g' <<< $LOGFILE)/g" "Launchd.command.plist" > "/tmp/Launchd.command.plist" || abort "${FAIL}" - sudo cp "/tmp/Launchd.command.plist" "${AGENT_PLIST}" || abort "${FAIL}" - rm -f /tmp/Launchd.command.plist + # Install logout hook. + if [ "$LOGOUT" = "1" ] ; then + sudo defaults write com.apple.loginwindow LogoutHook "${HELPER}" || abort "${FAIL}" fi - # customise Launchd.command.plist for daemon + # Make customised Launchd.command.plist for daemon. if [ "$DAEMON" = "1" ] ; then - sed "s/\$LABEL/${ORG}.daemon/g;s/\$HELPER/$(sed 's/\//\\\//g' <<< $HELPER)/g;s/\$PARAM/daemon/g;s/\$LOGFILE/$(sed 's/\//\\\//g' <<< $LOGFILE)/g" "Launchd.command.plist" > "/tmp/Launchd.command.plist" || abort "${FAIL}" + sed "s/\$LABEL/${ORG}.daemon/g;s/\$HELPER/$(sed 's/\//\\\//g' <<< "$HELPER")/g;s/\$PARAM/daemon/g;s/\$LOGFILE/$(sed 's/\//\\\//g' <<< "$LOGFILE")/g" "Launchd.command.plist" > "/tmp/Launchd.command.plist" || abort "${FAIL}" sudo cp "/tmp/Launchd.command.plist" "${DAEMON_PLIST}" || abort "${FAIL}" rm -f /tmp/Launchd.command.plist fi - if [ ! -d "${LOGDIR}" ] ; then - sudo mkdir "${LOGDIR}" || abort "${FAIL}" - fi - - if [ ! -f "${LOGFILE}" ] ; then - sudo touch "${LOGFILE}" || abort "${FAIL}" - fi - - if [ "$AGENT" = "1" ] ; then - # Allow agent to access log - sudo chmod 666 "${LOGFILE}" || abort "${FAIL}" - fi - - if [ "$AGENT" = "1" ] ; then - # sudo for agent commands to get better logging of errors - sudo launchctl bootstrap "gui/${USERID}" "${AGENT_PLIST}" || abort "${FAIL}" - fi - + # Launch already installed daemon. if [ "$DAEMON" = "1" ] ; then sudo launchctl load "${DAEMON_PLIST}" || abort "${FAIL}" fi @@ -208,48 +113,67 @@ install() { echo "Installed." } -uninstall() { - UNINSTALLED=1 - - if [ "$LOGOUT" = "1" ] ; then - sudo defaults delete com.apple.loginwindow LogoutHook || UNINSTALLED=0 +# On older macOS, previous version of this script would install and uninstall +# harmless (i.e. takes no actions) agent script if requested, but fail to report +# it as installed, and fail to start it immediately, so clean up. +# +# Working agent (probably never much use) requires: +# - chmod for logfile access +# - non-sudo log writer (agent is not sudo and cannot gain it) +# - customised agent.plist +# - load with launchctl load (earlier macOS) or sudo launchctl bootstrap +# - unload with launchctl unload (earlier macOS) or sudo launchctl bootout +# +uninstallAgent() { + if [ -f "${AGENT_PLIST}" ] ; then + sudo rm -f "${AGENT_PLIST}" + echo "Uninstalled agent." fi +} - if [ "$AGENT" = "1" ] ; then - sudo launchctl bootout "gui/${USERID}" "${AGENT_PLIST}" || UNINSTALLED=0 - sudo rm -f "${AGENT_PLIST}" || UNINSTALLED=0 - fi +uninstall() { + UNINSTALLED=1 if [ "$DAEMON" = "1" ] ; then - # Special value in saved device node so that nvram.plist is not upadated at uninstall - sudo /usr/sbin/nvram "${BOOT_NODE}=null" || abort "Failed to save null boot device!" - sudo launchctl unload "${DAEMON_PLIST}" || UNINSTALLED=0 - sudo rm -f "${DAEMON_PLIST}" || UNINSTALLED=0 + if [ "$DAEMON_PID" = "" ] ; then + UNINSTALLED=2 + echo "Daemon was not installed!" > /dev/stderr + else + # Place special value in saved device node so that nvram.plist is not updated at uninstall + sudo /usr/sbin/nvram "${BOOT_NODE}=null" || abort "Failed to save null boot device!" + sudo launchctl unload "${DAEMON_PLIST}" || UNINSTALLED=0 + DAEMON_PID= + fi + sudo rm -f "${DAEMON_PLIST}" + elif [ "$LOGOUT" = "1" ] ; then + if [ "$LOGOUT_HOOK" = "" ] ; then + UNINSTALLED=2 + echo "Logout hook was not installed!" > /dev/stderr + else + sudo defaults delete com.apple.loginwindow LogoutHook || UNINSTALLED=0 + LOGOUT_HOOK= + fi fi - sudo rm -f "${HELPER}" || UNINSTALLED=0 - sudo rm -f "${NVRAMDUMP}" || UNINSTALLED=0 + if [ "$DAEMON_PID" = "" ] && + [ "$LOGOUT_HOOK" = "" ] ; then + sudo rm -f "${HELPER}" + sudo rm -f "${NVRAMDUMP}" + fi - if [ "$UNINSTALLED" = "1" ] ; then - echo "Uninstalled." - else + if [ "$UNINSTALLED" = "0" ] ; then echo "Could not uninstall!" + elif [ "$UNINSTALLED" = "1" ] ; then + echo "Uninstalled." fi } status() { - if [ ! "$AGENT" = "1" ] && - [ ! "$DAEMON" = "1" ] ; then - # summary info - echo "Daemon pid = $(sudo launchctl print "system/${ORG}.daemon" 2>/dev/null | sed -n 's/.*pid = *//p')" - echo "Agent pid = $(launchctl print "gui/${USERID}/${ORG}.agent" 2>/dev/null | sed -n 's/.*pid = *//p')" - echo "LogoutHook = $(sudo defaults read com.apple.loginwindow LogoutHook 2>/dev/null)" + if [ ! "$DAEMON" = "1" ] ; then + echo "Daemon pid = ${DAEMON_PID}" + echo "LogoutHook = ${LOGOUT_HOOK}" else - # detailed info on whatever is selected - if [ "$AGENT" = "1" ] ; then - launchctl print "gui/${USERID}/${ORG}.agent" - fi - + # Detailed info on daemon. if [ "$DAEMON" = "1" ] ; then sudo launchctl print "system/${ORG}.daemon" fi @@ -285,15 +209,15 @@ saveMount() { # to mount the drive on daemon exit; mounting and unmounting on daemon # start here fixes this. # Doing this introduces a different problem, since this early mount sometimes - # fails initially, however (as with `diskutil info` above) in that case the + # fails initially, however (as with 'diskutil info' above) in that case the # script gets restarted by launchd after ~5s, and eventually either succeeds or - # finds the drive already mounted (when applicable, i.e. not the ESP). + # finds the drive already mounted (when applicable, i.e. not marked as ESP). mount_path=$(mount | sed -n "s:${node} on \(.*\) (.*$:\1:p") if [ ! "${mount_path}" = "" ] ; then doLog "Early mount not needed, already mounted at ${mount_path}" else - /usr/sbin/diskutil mount "${node}" 1>/dev/null || abort "Early mount failed!" - /usr/sbin/diskutil unmount "${node}" 1>/dev/null || abort "Early unmount failed!" + sudo /usr/sbin/diskutil mount "${node}" 1>/dev/null || abort "Early mount failed!" + sudo /usr/sbin/diskutil unmount "${node}" 1>/dev/null || abort "Early unmount failed!" doLog "Early mount/unmount succeeded" fi @@ -311,8 +235,8 @@ saveMount() { saveNvram() { if [ "${1}" = "1" ] ; then # . matches tab, note that \t for tab cannot be used in earlier macOS (e.g Mojave) - node=$(nvram "$BOOT_NODE" | sed -n "s/${BOOT_NODE}.//p") - if [ "$INSTALLED" = "0" ] ; then + node=$(/usr/sbin/nvram "$BOOT_NODE" | sed -n "s/${BOOT_NODE}.//p") + if [ ! "$INSTALLED" = "1" ] ; then # don't trash saved value if daemon is live launchctl print "system/${ORG}.daemon" 2>/dev/null 1>/dev/null || sudo /usr/sbin/nvram -d "$BOOT_NODE" else @@ -334,17 +258,18 @@ saveNvram() { else # use reasonably assumed unique path mount_path="/Volumes/${UNIQUE_DIR}" - sudo mkdir "${mount_path}" || abort "Failed to make directory!" + sudo mkdir -p "${mount_path}" || abort "Failed to make directory!" sudo mount -t msdos "${node}" "${mount_path}" || abort "Failed to mount!" - doLog "Successfully mounted at ${mount_path}" + doLog "Mounted at ${mount_path}" + MOUNTED=1 fi if [ "${NVRAM_DIR}" = "" ] ; then - nvram_dir=$mount_path + nvram_dir="${mount_path}" else nvram_dir="${mount_path}/${NVRAM_DIR}" if [ ! -d "${nvram_dir}" ] ; then - sudo mkdir $nvram_dir || abort "Failed to make directory ${nvram_dir}" + sudo mkdir "${nvram_dir}" || abort "Failed to make directory ${nvram_dir}" fi fi @@ -366,15 +291,29 @@ saveNvram() { doLog "Deleted nvram.used" fi - if [ "${WRITE_HOOK_LOG}" = "1" ] ; then - date >> "${nvram_dir}/${2}.hook.log" || abort "Failed to write to ${2}.hook.log!" + # We would like to always unmount here if we made the mount point, but at exit of + # installed daemon umount fails with "Resource busy" and diskutil is not available. + # This should not cause any problem except that the boot drive will be left mounted + # at the unique path if the daemon process gets killed (the process would then be + # restarted by macOS and NVRAM should still be saved at exit). + if [ "$MOUNTED" = "1" ] ; then + # For logout hook or if running in immediate mode, we can clean up. + if [ "$LOGOUT" = "1" ] || + [ ! "$INSTALLED" = "1" ] ; then + # Depending on how installed and macOS version, either unmount may be needed. + # (On Lion failure of 'diskutil unmount' may be to say volume is already unmounted when it is not.) + MOUNTED=0 + sudo diskutil unmount "${node}" 1>/dev/null 2>/dev/null || MOUNTED=1 + + if [ "$MOUNTED" = "0" ] ; then + doLog "Unmounted with diskutil" + else + sudo umount "${node}" || abort "Failed to unmount!" + sudo rmdir "${mount_path}" || abort "Failed to remove directory!" + doLog "Unmounted with umount" + fi + fi fi - - # We would like to unmount here, but umount fails with "Resource busy" - # and diskutil is not available. This should not cause any problem except - # that the boot drive will be left mounted at the unique path if the - # daemon process gets killed (the process would then be restarted by macOS - # and NVRAM should still be saved at exit). } onComplete() { @@ -386,7 +325,7 @@ onComplete() { doLog "Ended." - # Needed if running directly (launchd kills any orphaned child processes by default). + # Required if running directly (launchd kills any orphaned child processes by default). # ShellCheck ref: https://github.com/koalaman/shellcheck/issues/648#issuecomment-208306771 # shellcheck disable=SC2046 kill $(jobs -p) @@ -394,25 +333,177 @@ onComplete() { exit 0 } -if [ "$INSTALL" = "1" ] ; then - # Get root immediately (not required, looks nicer than doing a bunch of stuff and then asking) - sudo echo -n +if [ ! -x /usr/bin/dirname ] || + [ ! -x /usr/bin/basename ] || + [ ! -x /usr/bin/wc ] || + [ ! -x /usr/sbin/diskutil ] || + [ ! -x /usr/sbin/nvram ] ; then + earlyAbort "Unix environment is broken!" +fi - # Save nvram immediately, will become the fallback after the first daemon shutdown. - # Do not install if this fails, since this indicates that required boot path from - # OC is not available, or other fatal error. - if [ "$DAEMON" = "1" ] ; then +NVRAM_DIR="NVRAM" + +OCNVRAMGUID="4D1FDA02-38C7-4A6A-9CC6-4BCCA8B30102" + +# Darwin version from which we can wake a sleeping daemon, corresponds to Yosemite and upwards. +LAUNCHD_DARWIN=14 + +# OC generated NVRAM var +BOOT_PATH="${OCNVRAMGUID}:boot-path" + +# temp storage var for this script +BOOT_NODE="${OCNVRAMGUID}:boot-node" + +# re-use as unique directory name for mount point when needed +UNIQUE_DIR="${BOOT_NODE}" + +PRIVILEGED_HELPER_TOOLS="/Library/PrivilegedHelperTools" + +ORG="org.acidanthera.nvramhook" +NVRAMDUMP="${PRIVILEGED_HELPER_TOOLS}/${ORG}.nvramdump.helper" + +DAEMON_PLIST="/Library/LaunchDaemons/${ORG}.daemon.plist" +AGENT_PLIST="/Library/LaunchAgents/${ORG}.agent.plist" + +HELPER="${PRIVILEGED_HELPER_TOOLS}/${ORG}.helper" + +LOGDIR="/var/log/${ORG}.launchd" +# launchd .plist configuration is set in install() to redirect stdout and stderr (useful) to LOGFILE anyway. +LOGFILE="${LOGDIR}/launchd.log" + +SELFDIR="$(/usr/bin/dirname "${0}")" +SELFNAME="$(/usr/bin/basename "${0}")" + +# -R sets this, on newer macOS only; date format is required because root from user sudo and root +# when running daemons or logout hooks are picking up different date formats. +DATEFORMAT="%a, %d %b %Y %T %z" + +# Detect whether we're running renamed, i.e. installed copy, or else presumably from distribution directory. +if [ ! "$SELFNAME" = "Launchd.command" ] ; then + USE_NVRAMDUMP="${NVRAMDUMP}" + INSTALLED=1 +else + cd "${SELFDIR}" || earlyAbort "Failed to enter working directory!" + + if [ ! -x ./nvramdump ] ; then + earlyAbort "Compiled nvramdump is not found!" + fi + + USE_NVRAMDUMP="./nvramdump" +fi + +for arg; +do + case $arg in + install ) + INSTALL=1 + ;; + uninstall ) + UNINSTALL=1 + ;; + daemon ) + DAEMON=1 + ;; + logout ) + LOGOUT=1 + ;; + status ) + STATUS=1 + ;; + # Usage for invalid param. + # Note script called as logout hook gets passed name of user logging out as a param. + * ) + if [ ! "$INSTALLED" = "1" ] ; then + usage + exit 0 + fi + ;; + esac +done + +# If not told what to do, work it out. +# When running as daemon, 'daemon' is specified as a param. +if [ ! "$DAEMON" = "1" ] && + [ ! "$LOGOUT" = "1" ] ; then + if [ "$INSTALL" = "1" ] || + [ "$UNINSTALL" = "1" ] ; then + # When not specified, choose to (un)install daemon or logout hook depending on macOS version. + if [ "$(getDarwinMajorVersion)" -ge ${LAUNCHD_DARWIN} ] ; then + echo "Darwin $(uname -r) >= ${LAUNCHD_DARWIN}, using daemon" + DAEMON=1 + else + echo "Darwin $(uname -r) < ${LAUNCHD_DARWIN}, using logout hook." + LOGOUT=1 + fi + else + if [ "$INSTALLED" = "1" ] ; then + # If installed with no type as a param, we are installed as logout hook. + LOGOUT=1 + elif [ ! "$STATUS" = "1" ] ; then + # Usage for no params. + usage + exit 0 + fi + fi +fi + +if [ "$DAEMON" = "1" ] ; then + LOG_PREFIX="Daemon" +elif [ "$LOGOUT" = "1" ] ; then + LOG_PREFIX="Logout" +fi + +if [ ! "$INSTALLED" = "1" ] ; then + LOG_PREFIX="${LOG_PREFIX}-Immediate" +fi + +if [ "$INSTALL" = "1" ] || + [ "$UNINSTALL" = "1" ] || + [ "$STATUS" = "1" ] ; then + # Get root immediately + sudo echo -n || earlyAbort "Could not obtain sudo!" + + if [ "$UNINSTALL" = "1" ] || + [ "$STATUS" = "1" ] ; then + # For agent/daemon pid prefer 'launchctl list' as it works on older macOS where 'launchtl print' does not. + DAEMON_PID="$(sudo launchctl list | sed -n "s/\([0-9\-]*\).*${ORG}.daemon/\1/p" | sed 's/-/Failed to start!/')" + LOGOUT_HOOK="$(sudo defaults read com.apple.loginwindow LogoutHook 2>/dev/null)" + fi +fi + +if [ "$INSTALL" = "1" ] || + [ "$UNINSTALL" = "1" ] ; then + uninstallAgent +fi + +if [ "$INSTALL" = "1" ] ; then + installLog + + # Save NVRAM immediately, this will become the fallback NVRAM after the first shutdown. + # Do not install if this fails, since this indicates that required boot path from OC is + # not available, or other fatal error. + if [ "$DAEMON" = "1" ] || + [ "$LOGOUT" = "1" ] ; then + doLog "Installing…" doLog "Saving initial nvram.plist…" saveMount 0 - saveNvram 0 "daemon" + if [ "$DAEMON" = "1" ] ; then + saveNvram 0 "daemon" + else + saveNvram 0 "logout" + fi fi install + exit 0 fi if [ "$UNINSTALL" = "1" ] ; then - uninstall + msg="$(uninstall)" + if [ ! "${msg}" = "" ] ; then + doLog "${msg}" + fi exit 0 fi @@ -422,7 +513,6 @@ if [ "$STATUS" = "1" ] ; then fi if [ "${LOGOUT}" = "1" ] ; then - #LOG="${SELFDIR}/error.log" saveMount 0 saveNvram 0 "logout" exit 0 @@ -431,8 +521,8 @@ fi # Useful for trapping all signals to see what we get. #for s in {1..31} ;do trap "onComplete $s" $s ;done -# Trap CTRL+C for testing when running in immediate mode, and trap agent/daemon termination. -# Separate trap commands so we can log which was caught. +# Trap CTRL+C for testing for immediate mode, and trap normal or forced daemon +# or agent termination. Separate trap commands so we can log which was caught. trap "onComplete SIGINT" SIGINT trap "onComplete SIGTERM" SIGTERM -- GitLab