Skip to content

Instantly share code, notes, and snippets.

@thegranddesign
Created September 10, 2020 19:21
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save thegranddesign/fef254a615c6d1bf67f83c176da8869d to your computer and use it in GitHub Desktop.
Save thegranddesign/fef254a615c6d1bf67f83c176da8869d to your computer and use it in GitHub Desktop.
Updater For macOS Launch Services
#!/bin/bash
###
### bisect - Helps troubleshoot disabled services to track down the one that is
### causing offense.
###
### Description
### ================================================================================
###
### While striving to minimize CPU and memory usage, maximize privacy, and reduce
### possible surface area of attacks, many users wish to disable unused or uneeded
### services.
###
### Unfortunately removing some of these services can cause undesirable behavior.
### Some of which may not be known immediately after the initial attempt to disable
### them.
###
### On top of that, newer versions of macOS do not allow the user to modify these
### services while the OS is running normally and therefore the user must restart
### their system for it to take effect.
###
### For all these reasons and more, having an efficient way to track down offending
### services is very important. That's what this script aims to do.
###
### The user will initially run `bisect.sh start` (see full usages below) and the
### script will create a temporary 'holding file' containing which services it
### disabled.
###
### After each run the user will restart their system to test. Regardless of
### whether the desirable behavior is witness, the user will restart again back into
### recovery mode and rerun this script either as `bisect.sh good` or `bisect.sh
### bad` depending on whether the behavior still works as anticipated or not.
###
### The user will continue doing this until eventually the script narrows down the
### offending service to a single possibility.
###
### Note On Mounting Filesystem
### ================================================================================
###
### * See `update.sh help`
###
### Agent/Daemon List File Format
### ================================================================================
###
### * See `update.sh help`
###
### Prerequisites
### ================================================================================
###
### * Filesystem mounted in Read/Write mode (see above)
###
### * A file containing *all* of the possible agents/daemons you would like to
### eventually disable (see format below)
###
### * The file should be named `launch_<launch_type>.txt` and should be in the same
### directory as this script.
###
### --------------------------------------------------------------------------------
###
### Usage:
### ./bisect.sh start <launch_type> <system_volume>
###
### Description:
### Starts a new bisect session. This will discard the old session with no
### warning.
###
### Options:
### <launch_type> Should be either `agents` or `daemons`
### <system_volume> The path to the volume the system resides on
### (eg `/Volumes/Macintosh\ HD`)
###
### Usage:
### ./bisect.sh good <launch_type> <system_volume>
###
### Description:
### Tells bisect that the services it disabled last time didn't cause any issues.
### It will pick new ones to test.
###
### Options:
### <launch_type> Should be either `agents` or `daemons`
### <system_volume> The path to the volume the system resides on
### (eg `/Volumes/Macintosh\ HD`)
###
### Usage:
### ./bisect.sh bad <launch_type> <system_volume>
###
### Description:
### Tells bisect that one or more of the services it disabled last time caused a
### problem. It will:
###
### * Re-enable all the services it disabled in the previous run
### * Disable one or more of those services
###
### Options:
### <launch_type> Should be either `agents` or `daemons`
### <system_volume> The path to the volume the system resides on
### (eg `/Volumes/Macintosh\ HD`)
###
set -euo pipefail
_sin_bisect_start() {
launch_type="$1"
system_volume="$2"
script_directory="$("${system_volume}/usr/bin/dirname" "${BASH_SOURCE[0]}")"
launch_type_capitalized="$(tr '[:lower:]' '[:upper:]' <<< "${launch_type:0:1}")${launch_type:1}"
launch_filename="${script_directory}/launch_${launch_type}.txt"
temp_filename="${script_directory}/bisect.temp"
bisect_filename="${script_directory}/bisect.txt"
echo "Before running a bisection, you should make sure that you are starting"
echo "with all services _enabled._"
echo ""
echo "In order to do this, we will now remove the .bak extension from all"
echo "Launch${launch_type_capitalized} files."
echo ""
echo "Press any key to continue... "
"${system_volume}/usr/bin/read" -n 1 -s -r
echo ""
IFS=$'\n'
# shellcheck disable=SC2044
for filename in $(find "${system_volume}/System/Library/Launch${launch_type_capitalized}" -maxdepth 1 -name '*.bak'); do
echo " * '${filename%.bak}'"
mv "${filename}" "${filename%.bak}"
done
IFS=' '
echo ""
echo " * Copying Fresh Bisection File..."
cp -f "${launch_filename}" "${temp_filename}"
echo " * Sanitizing Bisection File..."
"${system_volume}/usr/bin/sed" '/^#/d' "${temp_filename}" > "${temp_filename}2"
"${system_volume}/usr/bin/sed" '/^$/d' "${temp_filename}2" > "${temp_filename}"
"${system_volume}/usr/bin/sort" -u --output="${temp_filename}" "${temp_filename}"
rm -f "${temp_filename}2"
echo " * Creating Initial Bisect Split..."
_sin_split_file "${system_volume}" "${temp_filename}" "${bisect_filename}"
echo " * Running Initial Service Update..."
echo ""
"${script_directory}/update.sh" "${launch_type}" "disable" "${system_volume}" "${bisect_filename}"
rm -f "${temp_filename}"
echo ""
echo "You can now reboot and test the bisection..."
echo ""
}
_sin_bisect_good() {
launch_type="$1"
system_volume="$2"
script_directory="$("${system_volume}/usr/bin/dirname" "${BASH_SOURCE[0]}")"
launch_type_capitalized="$(tr '[:lower:]' '[:upper:]' <<< "${launch_type:0:1}")${launch_type:1}"
temp_filename="${script_directory}/bisect.temp"
bisect_filename="${script_directory}/bisect.txt"
! [ -e "${bisect_filename}" ] && echo "Can't find an existing bisect file. Run 'bisect start'." && exit 1
echo " * Updating Bisection File..."
"${system_volume}/usr/bin/grep" '^# ' "${bisect_filename}" | "${system_volume}/usr/bin/sed" 's/^# //' > "${temp_filename}"
_sin_knows_offending_service "${temp_filename}" "${system_volume}" && exit 0
echo " * Calculating Bisect Split..."
_sin_split_file "${system_volume}" "${temp_filename}" "${bisect_filename}"
echo " * Running Bisection..."
echo ""
"${script_directory}/update.sh" "${launch_type}" "disable" "${system_volume}" "${bisect_filename}"
rm -f "${temp_filename}"
echo ""
echo "You can now reboot and test the bisection..."
echo ""
}
_sin_bisect_bad() {
launch_type="$1"
system_volume="$2"
script_directory="$("${system_volume}/usr/bin/dirname" "${BASH_SOURCE[0]}")"
launch_type_capitalized="$(tr '[:lower:]' '[:upper:]' <<< "${launch_type:0:1}")${launch_type:1}"
temp_filename="${script_directory}/bisect.temp"
bisect_filename="${script_directory}/bisect.txt"
! [ -e "${bisect_filename}" ] && echo "Can't find an existing bisect file. Run 'bisect start'." && exit 1
echo " * Updating Bisection File..."
"${system_volume}/usr/bin/grep" --invert-match '^# ' "${bisect_filename}" > "${temp_filename}"
echo " * Re-Enabling All Possible Responsible ${launch_type_capitalized}..."
echo ""
"${script_directory}/update.sh" "${launch_type}" "enable" "${system_volume}" "${temp_filename}"
_sin_knows_offending_service "${temp_filename}" "${system_volume}" && exit 0
echo ""
echo " * Calculating Bisect Split..."
_sin_split_file "${system_volume}" "${temp_filename}" "${bisect_filename}"
echo " * Running Bisection..."
echo ""
"${script_directory}/update.sh" "${launch_type}" "disable" "${system_volume}" "${bisect_filename}"
rm -f "${temp_filename}"
echo ""
echo "You can now reboot and test the bisection..."
echo ""
}
_sin_bisect_reset() {
system_volume="$1"
script_directory="$("${system_volume}/usr/bin/dirname" "${BASH_SOURCE[0]}")"
rm -f "bisect.txt"
rm -f "bisect.temp"
return 0
}
_sin_split_file() {
system_volume="$1"
temp_filename="$2"
bisect_filename="$3"
total_lines="$(_sin_total_lines_in_file "${temp_filename}" "${system_volume}")"
head_lines="$((total_lines / 2))"
tail_lines="$((total_lines - head_lines))"
"${system_volume}/usr/bin/head" -n "${head_lines}" "${temp_filename}" > "${bisect_filename}"
"${system_volume}/usr/bin/tail" -n "${tail_lines}" "${temp_filename}" | "${system_volume}/usr/bin/sed" 's/^/# /' >> "${bisect_filename}"
}
_sin_knows_offending_service() {
local filename="$1"
local system_volume="$2"
if [[ "$(_sin_total_lines_in_file "${temp_filename}" "${system_volume}")" == "1" ]]; then
echo ""
echo "We have determined the offending agent/daemon to be:"
echo ""
cat "${temp_filename}"
echo ""
_sin_bisect_reset "${system_volume}"
exit 0
else
return 1
fi
}
_sin_total_lines_in_file() {
local filename="$1"
local system_volume="$2"
# shellcheck disable=SC2016
"${system_volume}/usr/bin/wc" -l "${filename}" | "${system_volume}/usr/bin/awk" '{print $1}'
}
subcommand="${1:-}";
[ "$#" -gt 0 ] && shift 1;
case "${subcommand}" in
start)
_sin_bisect_start "$@"
;;
reset|stop)
_sin_bisect_reset "$@"
;;
good)
_sin_bisect_good "$@"
;;
bad)
_sin_bisect_bad "$@"
;;
help)
sed -rn 's/^### ?//;T;p' "$0"
;;
*)
echo "I don't understand the command '${subcommand}'"
;;
esac
################################################################################
# PROBLEMATIC AGENTS
#
# Will Freeze Edit Menus
# com.apple.speech.speechdatainstallerd
# com.apple.speech.speechsynthesisd
# com.apple.speech.synthesisserver
#
# Will Prevent Saving Prompt From Being Shown
# com.apple.bird
#
# Required For Sandboxed Applications To Track Files (This Is Not Related To Web Bookmarks)
# com.apple.scopedbookmarkagent.xpc
#
# Prevents Auto-Refresh Of Calendars
# com.apple.CalendarAgent
#
# Stops Photo Analysis
# com.apple.photoanalysisd
#
################################################################################
# iCloud
#
com.apple.cloudd
com.apple.cloudpaird
com.apple.cloudphotod
com.apple.followupd
com.apple.iCloudUserNotifications
com.apple.icloud.findmydeviced.findmydevice-user-agent
com.apple.icloud.fmfd
com.apple.icloud.searchpartyuseragent
com.apple.protectedcloudstorage.protectedcloudkeysyncing
com.apple.security.cloudkeychainproxy3
################################################################################
# Safari
#
com.apple.Safari.SafeBrowsing.Service
com.apple.SafariBookmarksSyncAgent
com.apple.SafariCloudHistoryPushAgent
com.apple.SafariHistoryServiceAgent
com.apple.SafariLaunchAgent
com.apple.SafariNotificationAgent
com.apple.SafariPlugInUpdateNotifier
com.apple.WebKit.PluginAgent
com.apple.swcd
com.apple.webinspectord
################################################################################
# iMessage / Facetime
#
com.apple.avconferenced
com.apple.imagent
com.apple.imautomatichistorydeletionagent
com.apple.imklaunchagent
com.apple.imtransferagent
################################################################################
# Game Center / Passbook / Apple TV / Homekit
#
com.apple.CommCenter-osx
com.apple.Maps.pushdaemon
com.apple.gamed
com.apple.homed
com.apple.passd
com.apple.videosubscriptionsd
################################################################################
# Ad-Related
#
com.apple.ap.adprivacyd
com.apple.ap.adservicesd
################################################################################
# Screensharing
#
com.apple.screensharing.MessagesAgent
com.apple.screensharing.agent
com.apple.screensharing.menuextra
################################################################################
# Siri
#
com.apple.Siri.agent
com.apple.assistant_service
com.apple.assistantd
com.apple.parsec-fbf
com.apple.siri-distributed-evaluation
com.apple.siri.context.service
com.apple.siriknowledged
################################################################################
# VoiceOver / Accessibility
#
com.apple.ScreenReaderUIServer
com.apple.VoiceOver
com.apple.accessibility.AXVisualSupportAgent
com.apple.accessibility.MotionTrackingAgent
com.apple.accessibility.dfrhud
com.apple.accessibility.heard
com.apple.scrod
com.apple.voicememod
################################################################################
# Quicklook
#
# com.apple.quicklook
com.apple.quicklook.ThumbnailsAgent
# com.apple.quicklook.ui.helper
################################################################################
# Sidecar
#
com.apple.sidecar-hid-relay
com.apple.sidecar-relay
################################################################################
# Debugging Process
#
com.apple.DiagnosticReportCleanup
com.apple.ReportCrash
com.apple.ReportGPURestart
com.apple.ReportPanic
com.apple.TrustEvaluationAgent
com.apple.spindump_agent
################################################################################
# Screentime / Parental Controls
#
com.apple.ScreenTimeAgent
com.apple.UsageTrackingAgent
com.apple.familycircled
com.apple.familycontrols.useragent
com.apple.familynotificationd
################################################################################
# Classroom
#
com.apple.progressd
################################################################################
# Others
#
com.apple.AMPArtworkAgent
com.apple.AMPLibraryAgent
com.apple.AOSHeartbeat
com.apple.AOSPushRelay
com.apple.AirPlayUIAgent
com.apple.AirPortBaseStationAgent
com.apple.CallHistoryPluginHelper
com.apple.CallHistorySyncHelper
com.apple.EscrowSecurityAlert
com.apple.FileProvider
com.apple.KeyboardAccessAgent
com.apple.ManagedClientAgent.agent
com.apple.ManagedClientAgent.enrollagent
com.apple.RemoteDesktop
com.apple.RemoteUI
com.apple.SocialPushAgent
com.apple.amp.mediasharingd
com.apple.amsaccountsd
com.apple.appleseed.seedusaged
com.apple.appleseed.seedusaged.postinstall
com.apple.appsleepd
com.apple.appstoreagent
com.apple.askpermissiond
com.apple.commerce
com.apple.ctkd
com.apple.exchange.exchangesyncd
com.apple.findmymacmessenger
com.apple.helpd
com.apple.icdd
com.apple.identityservicesd
com.apple.java.InstallOnDemand
com.apple.keyboardservicesd
com.apple.knowledge-agent
com.apple.macos.studentd
com.apple.mediaanalysisd
com.apple.mediaremoteagent
com.apple.mobileactivationd
com.apple.mobileassetd
com.apple.parentalcontrols.check
com.apple.parsecd
com.apple.podcasts.PodcastContentService
com.apple.powerchime
com.apple.rapportd-user
com.apple.remindd
com.apple.routined
com.apple.security.keychain-circle-notification
com.apple.sharingd
com.apple.suggestd
com.apple.syncdefaultsd
com.apple.telephonyutilities.callservicesd
com.apple.touristd
################################################################################
# iCloud
#
com.apple.analyticsd
com.apple.icloud.findmydeviced
################################################################################
# Debugging Process
#
com.apple.systemstats.analysis
com.apple.systemstats.daily
com.apple.systemstats.microstackshot_periodic
################################################################################
# Others
#
# com.apple.ManagedClient Prevents mobileconfig Profiles
# com.apple.ManagedClient.enroll Prevents mobileconfig Profiles
# com.apple.ManagedClient.startup Prevents mobileconfig Profiles
com.apple.AirPlayXPCHelper
com.apple.AssetCacheLocatorService
com.apple.ManagedClient.cloudconfigurationd
com.apple.ManagedClient.mechanism
com.apple.RFBEventHelper
com.apple.RemoteDesktop.PrivilegeProxy
com.apple.SubmitDiagInfo
com.apple.appleseed.fbahelperd
com.apple.appstored
com.apple.apsd
com.apple.captiveagent
com.apple.commerced
com.apple.eapolcfg_auth
com.apple.efax
com.apple.locate
com.apple.locationd
com.apple.mediaremoted
com.apple.netbiosd
com.apple.nis.ypbind
com.apple.preferences.timezone.admintool
com.apple.rapportd
com.apple.remotepairtool
com.apple.rtcreportingd
com.apple.screensharing
com.apple.security.FDERecoveryAgent
com.apple.webdavfs_load_kext
#!/bin/bash
###
### update - Allows files containing a list of services to either be enabled or
### disabled.
###
### Description
### ================================================================================
###
### While striving to minimize CPU and memory usage, maximize privacy, and reduce
### possible surface area of attacks, many users wish to disable unused or uneeded
### services.
###
### In order to make this as painless as possible, this script provides a way to
### standardize enabling and disabling those services as well as handling the most
### common types of errors that may arise during that process.
###
### Note On Mounting Filesystem
### ================================================================================
###
### This script was designed to work with the tools available on a fresh macOS
### installation. All applicable commands are prefixed with the mounted volume path
### which will need to be mounted with read/write access prior to running this
### script.
###
### From Catalina onwards, this means that you:
###
### * Boot into recovery mode
### * Open Disk Utility
### * Mount your system volume
### * Close Disk Utility
###
### Once that's completed, you'll need to open Terminal (Utilities -> Terminal) and
### navigate to the location where this script lives.
###
### Agent/Daemon List File Format
### ================================================================================
###
### * Lines beginning with `#` are considered comments and are ignored
### * Lines should contain *only* the domain portion of the agent filename.
###
### Valid Items:
###
### com.apple.security.keychain-circle-notification
### com.apple.sharingd
###
### Invalid Items:
###
### /System/Library/LaunchAgents/com.apple.sharingd.plist
### com.apple.sharingd.plist
### com.apple.*
###
### Prerequisites
### ================================================================================
###
### * Filesystem mounted in Read/Write mode (see above)
###
### * A file containing *all* of the possible agents/daemons you would like to
### eventually disable (see format below)
###
### * The file should be named `launch_<launch_type>.txt` and should be in the same
### directory as this script.
###
### References
### ================================================================================
###
### * https://gist.github.com/pwnsdx/1217727ca57de2dd2a372afdd7a0fc21
###
### --------------------------------------------------------------------------------
###
### Usage:
### ./update.sh all <action> <system_volume>
###
### Description:
### Either enables or disables all services listed in the list files.
###
### Options:
### <action> Should be either `enable` or `disable`
### <system_volume> The path to the volume the system resides on
### (eg `/Volumes/Macintosh\ HD`)
###
### Usage:
### ./update.sh agents <action> <system_volume>
###
### Description:
### Either enables or disables all agents listed in the agent list file.
###
### Options:
### <action> Should be either `enable` or `disable`
### <system_volume> The path to the volume the system resides on
### (eg `/Volumes/Macintosh\ HD`)
###
### Usage:
### ./update.sh daemons <action> <system_volume>
###
### Description:
### Either enables or disables all daemons listed in the daemon list file.
###
### Options:
### <action> Should be either `enable` or `disable`
### <system_volume> The path to the volume the system resides on
### (eg `/Volumes/Macintosh\ HD`)
###
set -euo pipefail
_sin_update_all() {
action="$1"
system_volume="$2"
_sin_update "agents" "${action}" "${system_volume}"
_sin_update "daemons" "${action}" "${system_volume}"
}
_sin_update() {
launch_type="$1"
action="$2"
system_volume="$3"
script_directory="$("${system_volume}/usr/bin/dirname" "${BASH_SOURCE[0]}")"
list_filename="${4:-"${script_directory}/launch_${launch_type}.txt"}";
_sin_run_update "${action}" "${launch_type}" "${list_filename}" "${system_volume}"
}
_sin_run_update() {
action="$1"
launch_type="$2"
list_filename="$3"
system_volume="$4"
[ -z "${action}" ] && echo "Missing action: '${action}'" && exit 1
[ -z "${launch_type}" ] && echo "Missing launch_type: '${launch_type}'" && exit 1
[ -z "${list_filename}" ] && echo "Missing list_filename: '${list_filename}'" && exit 1
[ -z "${system_volume}" ] && echo "Missing system_volume: '${system_volume}'" && exit 1
IFS=$'\n'
# shellcheck disable=SC2013
for agent in $(sed '/^#/d' "${list_filename}" | sed '/^$/d' | sort -u); do
enabled_filename="${system_volume}/System/Library/Launch${launch_type}/${agent}.plist"
disabled_filename="${system_volume}/System/Library/Launch${launch_type}/${agent}.plist.bak"
file_status=""
if [[ "${action}" == "enable" ]]; then
source_filename="${disabled_filename}"
destination_filename="${enabled_filename}"
elif [[ "${action}" == "disable" ]]; then
source_filename="${enabled_filename}"
destination_filename="${disabled_filename}"
else
echo "Invalid Action: '${action}'"
exit 1
fi
if [ -e "${destination_filename}" ]; then
file_status="[EXISTS ]"
elif ! [ -e "${source_filename}" ] && ! [ -h "${source_filename}" ]; then
file_status="[MISSING]"
elif mv "${source_filename}" "${destination_filename}" 2> /dev/null; then
file_status="[OK ]"
else
file_status="[ERROR ]"
fi
echo -e "${file_status} ${launch_type}\t'${agent}'"
done
}
subcommand="${1:-}";
[ "$#" -gt 0 ] && shift 1;
case "${subcommand}" in
all)
_sin_update_all "$@"
;;
agents)
_sin_update "Agents" "$@"
;;
daemons)
_sin_update "Daemons" "$@"
;;
help)
sed -rn 's/^### ?//;T;p' "$0"
;;
*)
echo "I don't understand the command '${subcommand}'"
;;
esac
@roblav96
Copy link

One-liners for those who might be interested:

curl https://gist.githubusercontent.com/thegranddesign/fef254a615c6d1bf67f83c176da8869d/raw/68d20561706d3f618cca20b475b8b7baba8f3978/launch_agents.txt | sed -e '/^[ ]*#/d' -e '/^$/d' | while read AGENT; do (echo; echo "$AGENT"; launchctl unload -w "/System/Library/LaunchAgents/$AGENT.plist"); done
curl https://gist.githubusercontent.com/thegranddesign/fef254a615c6d1bf67f83c176da8869d/raw/68d20561706d3f618cca20b475b8b7baba8f3978/launch_daemons.txt | sed -e '/^[ ]*#/d' -e '/^$/d' | while read DAEMON; do (echo; echo "$DAEMON"; sudo launchctl unload -w "/System/Library/LaunchDaemons/$DAEMON.plist"); done

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment