#!/bin/sh ################################################################################ # # File: licensed_unload.sh # # Contains: Shell script that unloads the PACE Eden License Daemon. # This script must be run as root in order to work. # # Copyright: 2013 - 2025 by PACE Anti-Piracy, all rights reserved. # ################################################################################ #------------------------------------------------------------------------------- # Initialize script globals #------------------------------------------------------------------------------- # Define the daemon plist and path constants gDaemonLabel="com.paceap.eden.licensed" gDaemonPlistPath="/Library/LaunchDaemons/$gDaemonLabel.plist" gDaemonServiceTarget="system/$gDaemonLabel" # Define the version of the OS where we start supporting launchctl 2.0. Even though # launchctl 2.0 was introduced on 10.10 Yosemite, we only support the new commands on # 10.11 El Capitan and above because the Yosemite support was apparently incomplete # (i.e. the "unbootstrap" command wasn't implemented and was replaced with "bootout"). gLaunchctl2MajorVersion=15 # Get the OS version gOsVersion=`uname -r` gOsMajorVersion=${gOsVersion%%.*} #echo "Running OS vers $gOsVersion, major version $gOsMajorVersion." # Define the launchctl tool to use. For standalone scripts, this should include the # "sudo" command. gLaunchctlCommand="/bin/launchctl" # Possible result codes from launchctl under Catalina gEINPROGRESS=36 # Operation now in progress result code gEALREADY=37 # Operation already in progress #------------------------------------------------------------------------------- fatalError() { echo "Error: $1" exit 1 } #------------------------------------------------------------------------------- # If a file or folder exists at the specified path, then delete it. If it's a # directory, then its entire contents is deleted. #------------------------------------------------------------------------------- deleteIfExists() { if [[ -e "$1" ]]; then # If it's a directory, then make sure it contains no locked files if [[ -d "$1" ]]; then chflags -R nouchg "$1" fi # Do the remove and check for an error. /bin/rm -rf "$1" if [[ $? -ne 0 ]]; then fatalError "Unable to delete $1." fi fi } #------------------------------------------------------------------------------- # If LicenseD is running, then stop it now. After stopping it, clean up by # removing LicenseD's socket file if found. #------------------------------------------------------------------------------- unloadLicenseDManually() { echo "Unloading license daemon as needed..." # If an instance of the daemon is currently running, unload it using launchctl. # We may have to wait for it to be gone. `$gLaunchctlCommand list | /usr/bin/grep -q "$gDaemonLabel"` if [[ $? -eq 0 ]]; then # LicenseD is running so we need to unload it. If this is a new enough OS, then # use the launchctl 2.0 bootstrap commands. Otherwise fall back and use the legacy # launchctl commands. result=0 waitForLicenseDToQuit=0 if [[ $gOsMajorVersion -ge $gLaunchctl2MajorVersion ]]; then # Use launchctl 2.0 bootout command on this system. If the plist exists, then # use the plist's path to do the remove. If it doesn't exist, use the service # target instead. if [[ -f "$gDaemonPlistPath" ]]; then echo "Unbootstrapping the license daemon service from the system domain by plist..." `$gLaunchctlCommand bootout system "$gDaemonPlistPath"` result=$? # Apple indicated that EINPROGRESS is a possible valid result code (as seen # on Catalina), so we handle it here. We also accept EALREADY because it # seems possible, even if we haven't seen it in the field yet. if [[ $result -ne 0 && $result -ne $gEINPROGRESS && $result -ne $gEALREADY ]]; then fatalError "launchctl bootout by plist failed with error $result" fi else # We have no plist so we have to remove by service target. Unfortunately # we've seen cases where launchctl returns immediately with an error even # though it did tell the service to quit. Therefore we ignore any errors # and remember that we need to wait for LicenseD to quit below. echo "Unbootstrapping the license daemon service from the system domain by service target..." `$gLaunchctlCommand bootout $gDaemonServiceTarget` result=$? if [[ $result -ne 0 ]]; then echo "launchctl bootout by service target returned error $result. This is considered non-fatal." result=0 fi # Remember that we need to wait for LicenseD to quit below. waitForLicenseDToQuit=1 fi # The LicenseD plist file is missing else # If the plist file exists, use the unload command (which blocks until LicenseD # is unloaded. If the plist file does not exist, and if the OS is Leopard or # above then use the remove command. But since remove returns immediately, we # have to remember to wait for LicenseD to stop. if [[ -f "$gDaemonPlistPath" ]]; then echo "Unloading LicenseD from launchctl by plist..." `$gLaunchctlCommand unload "$gDaemonPlistPath"` result=$? if [[ $result -ne 0 ]]; then fatalError "launchctl unload failed with error $result" fi else # We have no plist so we have to remove LicenseD by its label. We can only # do that on Leopard or above. if [[ $gOsMajorVersion -ge 9 ]]; then echo "Removing LicenseD from launchctl by label..." `$gLaunchctlCommand remove "$gDaemonLabel"` result=$? # Since "remove" returns immediately, remember that we want to wait for LicenseD # to quit below. waitForLicenseDToQuit=1 else # This system is older than Leopard so we cannot remove the service by label. # Since the plist is missing, this means we cannot unload LicenseD. Oh well. fatalError "The LicenseD plist is missing so we cannot unload it on this OS." fi fi # The LicenseD plist file is missing # Check the unload or remove result if [[ $result -ne 0 ]]; then fatalError "launchctl unload or remove failed with error $result" fi fi # The OS too old for launchctl 2.0 syntax # Since some of the logic above results in calls to launchctl that return immediately, # double-check that the daemon was successfully removed if we were told to do so. # # To do this, we loop up to 60 times with a 1-second delay between checks. This # gives LicenseD a full minute to quit. if [[ $waitForLicenseDToQuit -ne 0 ]]; then daemonStopped=0 daemonCheckCount=0 for (( daemonCheckCount=0 ; $daemonCheckCount != 60 ; daemonCheckCount=daemonCheckCount+1 )) do `$gLaunchctlCommand list | /usr/bin/grep -q "$gDaemonLabel"` if [[ $? -ne 0 ]]; then daemonStopped=1 echo "The license daemon has stopped." break fi echo "Waiting for the license daemon to stop..." sleep 1 # give it more time done # If we LicenseD was not stopped, report the error and fail if [[ $daemonStopped -eq 0 ]]; then fatalError "LicenseD still found under launchctl control after $daemonCheckCount seconds." fi fi # Double check that LicenseD was unloaded. # LicenseD was successfully unloaded echo "License daemon was successfully unloaded." else # LicenseD was not running echo "License daemon is not running. Nothing to do." fi # Clean out the sockets directory and remove it in case it has the wrong # owner or permissions. deleteIfExists "/var/tmp/com.paceap.eden.licensed" echo } #------------------------------------------------------------------------------- # Script starts here #------------------------------------------------------------------------------- # Unload LicenseD, if it's running, then clean up after it. unloadLicenseDManually # Exit with success exit 0