diff --git a/MANUAL-UNINSTALL.md b/MANUAL-UNINSTALL.md new file mode 100644 index 0000000..7b535d0 --- /dev/null +++ b/MANUAL-UNINSTALL.md @@ -0,0 +1,30 @@ + + +# Manual Uninstall + +- Delete `Background Music.app` from `/Applications`. +- Delete `Background Music Device.driver` from `/Library/Audio/Plug-Ins/HAL`. +- Pause apps that are playing audio, if you can. +- Restart `coreaudiod`: + (Open `/Applications/Utilities/Terminal.app` and paste the following at the prompt.) + + ```shell + sudo launchctl kill SIGTERM system/com.apple.audio.coreaudiod || sudo killall coreaudiod + ``` +- Go to the Sound section in System Preferences and change your default output device at least once. (If you only have + one device now, either use `Audio MIDI Setup.app` to create a temporary aggregate device, restart any audio apps that + have stopped working or just restart your system.) + +## Optional + +- Delete `BGMXPCHelper.xpc` from `/usr/local/libexec` or possibly `/Library/Application Support/Background Music`. +- Unregister BGMXPCHelper, delete its user and group, and delete its launchd.plist: + + ```shell + sudo launchctl bootout system /Library/LaunchDaemons/com.bearisdriving.BGM.XPCHelper.plist + sudo rm /Library/LaunchDaemons/com.bearisdriving.BGM.XPCHelper.plist + sudo dscl . -delete /Users/_BGMXPCHelper + sudo dscl . -delete /Groups/_BGMXPCHelper + ``` + + diff --git a/README.md b/README.md index 5c086a3..76b0bf5 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,11 @@ apps playing audio. one device now, either use `Audio MIDI Setup.app` to create a temporary aggregate device, restart any audio apps that have stopped working or just restart your system.) +### Manual Uninstall + +Try following the instructions in `MANUAL-UNINSTALL.md` if `uninstall.sh` fails. (You might consider submitting a bug +report, too.) + ## Troubleshooting If Background Music crashes and system audio stops working, open the Sound panel in System Preferences and change your diff --git a/uninstall.sh b/uninstall.sh index 18391f2..d56aa3a 100755 --- a/uninstall.sh +++ b/uninstall.sh @@ -1,5 +1,29 @@ #!/bin/bash -e +# This file is part of Background Music. +# +# Background Music is free software: you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation, either version 2 of the +# License, or (at your option) any later version. +# +# Background Music is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Background Music. If not, see . + +# +# uninstall.sh +# +# Copyright © 2016 Nick Jacques +# Copyright © 2016 Kyle Neideck +# +# Removes BGMApp, BGMDriver and BGMXPCHelper from the system. +# + bold=$(tput bold) normal=$(tput sgr0) @@ -8,60 +32,111 @@ driver_path="/Library/Audio/Plug-Ins/HAL/Background Music Device.driver" xpc_path1="/usr/local/libexec/BGMXPCHelper.xpc" xpc_path2="/Library/Application Support/Background Music/BGMXPCHelper.xpc" +# Check that files/directories are at most this big before we delete them, just to be safe. +max_size_mb_for_rm=5 + file_paths=("${app_path}" "${driver_path}" "${xpc_path1}" "${xpc_path2}") -launchd_plist="/Library/LaunchDaemons/com.bearisdriving.BGM.XPCHelper.plist" +bgmapp_process_name="Background Music" + +launchd_plist_label="com.bearisdriving.BGM.XPCHelper" +launchd_plist="/Library/LaunchDaemons/${launchd_plist_label}.plist" user_group_name="_BGMXPCHelper" -clear -echo "${bold}You are about to uninstall BackgroundMusic and its components!${normal}" -echo "Please pause all audio before continuing." -echo "You must be able to run 'sudo' commands to continue." -echo "" -read -p "Continue (y/n)? " user_prompt +# We move files to this temp directory and then move the directory to the user's trash at the end of the script. +# Unfortunately, this means that if the user tries to use the "put back" feature the files will just go back to the +# temp directory. +trash_dir="$(mktemp -d -t UninstalledBackgroundMusicFiles)/" -if [ "$user_prompt" == "y" ]; then +# Takes a path to a file or directory and returns false if the file/directory is larger than $max_size_mb_for_rm. +function size_check { + local size="$(du -sm "$1" 2>/dev/null | awk '{ print $1 }')" + [[ "${size}" =~ ^[0-9]+$ ]] && [[ "${size}" -le ${max_size_mb_for_rm} ]] +} + +clear +echo "${bold}You are about to uninstall Background Music and its components!${normal}" +echo "Please pause all audio before continuing." +echo "You must be able to run 'sudo' commands to continue. (But don't worry if you don't know what that means.)" +echo "" +read -p "Continue (y/N)? " user_prompt + +if [ "$user_prompt" == "y" ] || [ "$user_prompt" == "Y" ]; then # Ensure that the user can use sudo sudo -v is_sudo=$? if [[ "$is_sudo" -ne 0 ]]; then - echo "ERROR: This script must be run by a user with sudo permissions" + echo "ERROR: This script must be run by a user with administrator (sudo) privileges." exit 1 fi echo "" + # Try to kill Background Music.app, in case it's running. + killall "${bgmapp_process_name}" &>/dev/null || true + + # TODO: Use + # mdfind kMDItemCFBundleIdentifier = "com.bearisdriving.BGM.App" + # to offer alternatives if Background Music.app isn't installed to /Applications. Or we could open it with + # open -b "com.bearisdriving.BGM.App" -- delete-yourself + # and have Background Music.app delete itself and close when it gets the "delete-yourself" argument. Though + # that wouldn't be backwards compatible. + # Remove the files defined in file_paths for path in "${file_paths[@]}"; do - if [ -e "${path}" ]; then - echo "Deleting \"${path}\"" - rm -rf "\"${path}\"" + if [ -e "${path}" ] && size_check "${path}"; then + echo "Moving \"${path}\" to the trash." + sudo mv -f "${path}" "${trash_dir}" &>/dev/null fi done - echo "Removing BackgroundMusic launchd service" - launchctl list | grep "${launchd_plist}" >/dev/null && sudo launchctl bootout system "${launchd_plist}" || echo " Service does not exist" + echo "Removing Background Music launchd service." + sudo launchctl list | grep "${launchd_plist_label}" >/dev/null && \ + (sudo launchctl bootout system "${launchd_plist}" &>/dev/null || \ + # Try an older version of the command in case the user has an old version of launchctl. + sudo launchctl unload "${launchd_plist}" >/dev/null) || \ + echo " Service does not exist." - echo "Removing BackgroundMusic launchd service configuration file" + echo "Removing Background Music launchd service configuration file." if [ -e "${launchd_plist}" ]; then - sudo rm "${launchd_plist}" + sudo mv -f "${launchd_plist}" "${trash_dir}" fi - echo "Removing BackgroundMusic user" - dscl . -read /Users/"${user_group_name}" 2>/dev/null && sudo dscl . -delete /Users/"${user_group_name}" || echo " User does not exist" + # Be paranoid about user_group_name because we really don't want to delete every user account. + if ! [[ -z ${user_group_name} ]] && [[ "${user_group_name}" != "" ]]; then + echo "Removing Background Music user." + dscl . -read /Users/"${user_group_name}" &>/dev/null && \ + sudo dscl . -delete /Users/"${user_group_name}" 1>/dev/null || \ + echo " User does not exist." - echo "Removing BackgroundMusic group" - dscl . -read /Groups/"${user_group_name}" 2>/dev/null && sudo dscl . -delete /Groups/"${user_group_name}" || echo " Group does not exist" + echo "Removing Background Music group." + dscl . -read /Groups/"${user_group_name}" &>/dev/null && \ + sudo dscl . -delete /Groups/"${user_group_name}" 1>/dev/null || \ + echo " Group does not exist." + else + echo "Warning: could not delete the Background Music user/group due to an internal error in $0." + fi + + # We're done removing files, so now actually move trash_dir into the trash. + osascript -e 'tell application "Finder" to move the POSIX file "'"${trash_dir}"'" to trash' >/dev/null + + echo "Restarting Core Audio." + # The extra or-clauses are fallback versions of the command that restarts coreaudiod. Apparently some of these commands + # don't work with older versions of launchctl. + (sudo launchctl kill SIGTERM system/com.apple.audio.coreaudiod &>/dev/null || \ + sudo launchctl kill -15 system/com.apple.audio.coreaudiod &>/dev/null || \ + (sudo launchctl unload /System/Library/LaunchDaemons/com.apple.audio.coreaudiod.plist &>/dev/null && \ + sudo launchctl load /System/Library/LaunchDaemons/com.apple.audio.coreaudiod.plist &>/dev/null) || \ + sudo killall coreaudiod &>/dev/null) && \ + sleep 5 - echo "Restarting CoreAudio" - sudo launchctl kill SIGTERM system/com.apple.audio.coreaudiod && sleep 5 - # Invalidate sudo ticket sudo -k echo -e "\n${bold}Done! Toggle your sound output device in the Sound control panel to complete the uninstall.${normal}" + osascript -e 'tell application "System Preferences" activate reveal anchor "output" of pane "Sound" @@ -71,3 +146,5 @@ if [ "$user_prompt" == "y" ]; then else echo "Uninstall cancelled." fi + +