#!/bin/bash # variables APPDIR="/Applications/" TMPDIR=$(dirname "$(realpath "$INSTALLER_PATH")") # functions quit_and_track_application() { local bundle_id="$1" local var_name="APP_WAS_RUNNING_$(echo "$bundle_id" | tr '.-' '__')" local timeout_duration=10 # check if the application is running local app_running app_running=$(osascript -e "application id \"$bundle_id\" is running" 2>/dev/null) if [[ "$app_running" != "true" ]]; then eval "export $var_name=0" return fi local console_user console_user=$(stat -f "%Su" /dev/console) if [[ -z "$console_user" || "$console_user" == "root" || "$console_user" == "loginwindow" ]]; then echo "Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'." eval "export $var_name=0" return fi # App was running, mark it for relaunch eval "export $var_name=1" echo "Application '$bundle_id' was running; will relaunch after installation." echo "Quitting application '$bundle_id'..." # try to quit the application within the timeout period local quit_success=false SECONDS=0 while (( SECONDS < timeout_duration )); do if osascript -e "tell application id \"$bundle_id\" to quit" >/dev/null 2>&1; then if ! pgrep -f "$bundle_id" >/dev/null 2>&1; then echo "Application '$bundle_id' quit successfully." quit_success=true break fi fi sleep 1 done if [[ "$quit_success" = false ]]; then echo "Application '$bundle_id' did not quit." fi } relaunch_application() { local bundle_id="$1" local var_name="APP_WAS_RUNNING_$(echo "$bundle_id" | tr '.-' '__')" local was_running # Check if the app was running before installation eval "was_running=\$$var_name" if [[ "$was_running" != "1" ]]; then return fi local console_user console_user=$(stat -f "%Su" /dev/console) if [[ -z "$console_user" || "$console_user" == "root" || "$console_user" == "loginwindow" ]]; then echo "Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'." return fi echo "Relaunching application '$bundle_id'..." # Launch the app in the logged-in user's GUI session. Apps launched by root # won't register with the user's Dock/GUI, so run 'open' as the console user. # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace # and GUI session — 'sudo -u' alone doesn't do this, which can cause # LSOpenURLsWithRole() failures even when 'open' exits 0. local open_status=0 if [[ $EUID -eq 0 ]]; then local console_uid console_uid=$(id -u "$console_user") /bin/launchctl asuser "$console_uid" sudo -u "$console_user" open -b "$bundle_id" >/dev/null 2>&1 || open_status=$? else open -b "$bundle_id" >/dev/null 2>&1 || open_status=$? fi if [[ $open_status -eq 0 ]]; then echo "Application '$bundle_id' relaunched successfully." else echo "Failed to relaunch application '$bundle_id'." fi } remove_stale_upgrade_bundles() { # Webex's own auto-updater stages downloaded updates under # "Cisco Spark/Webexteams_upgrades_*" (one dir per architecture) and leaves # older, fully formed Webex.app bundles behind after applying them. osquery's # apps table indexes those staged bundles by their (old) bundle_short_version # and bundle_identifier ('Cisco-Systems.Spark'), so version-based patch # policies keep reporting the host as out of date even after the app in # /Applications has been updated. Removing them is safe: they are cached, # already-applied updates that Webex re-downloads as needed, and Webex only # ever stages versions at or newer than what is installed. local home for home in /Users/*; do [ -d "$home" ] || continue rm -rf "$home/Library/Application Support/Cisco Spark/Webexteams_upgrades_"* done } # extract contents MOUNT_POINT=$(mktemp -d /tmp/dmg_mount_XXXXXX) yes | hdiutil attach -plist -nobrowse -readonly -mountpoint "$MOUNT_POINT" "$INSTALLER_PATH" || exit 1 if ! sudo cp -R "$MOUNT_POINT"/* "$TMPDIR"; then hdiutil detach "$MOUNT_POINT" || true exit 1 fi hdiutil detach "$MOUNT_POINT" || true # copy to the applications folder quit_and_track_application 'Cisco-Systems.Spark' if [ -d "$APPDIR/Webex.app" ]; then sudo mv "$APPDIR/Webex.app" "$TMPDIR/Webex.app.bkp" || exit $? fi if ! sudo cp -R "$TMPDIR/Webex.app" "$APPDIR"; then # remove the partial copy so a failed install isn't inventoried as the new # version, then restore the previous version if there was one sudo rm -rf "$APPDIR/Webex.app" if [ -d "$TMPDIR/Webex.app.bkp" ]; then sudo mv "$TMPDIR/Webex.app.bkp" "$APPDIR/Webex.app" fi exit 1 fi remove_stale_upgrade_bundles relaunch_application 'Cisco-Systems.Spark'