#!/bin/bash -p # Copyright 2011 The Chromium Authors # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. # Called by the application to install in a new location. Generally, this # means that the application is running from a disk image and wants to be # copied to /Applications. The application, when running from the disk image, # will call this script to perform the copy. # # This script will be run as root if the application determines that it would # not otherwise have permission to perform the copy. # # When running as root, this script will be invoked with the real user ID set # to the user's ID, but the effective user ID set to 0 (root). bash -p is # used on the first line to prevent bash from setting the effective user ID to # the real user ID (dropping root privileges). set -eu # This script may run as root, so be paranoid about things like ${PATH}. export PATH="/usr/bin:/usr/sbin:/bin:/sbin" # Uses "defaults read" to obtain the value of a key in a property list. # # See chrome/installer/mac/keystone_install.sh for more details. infoplist_read() { __CFPREFERENCES_AVOID_DAEMON=1 defaults read "${@}" } # If running as root, output the pid to stdout before doing anything else. # See chrome/browser/mac/authorization_util.h. if [ ${EUID} -eq 0 ] ; then echo "${$}" fi if [ ${#} -ne 2 ] ; then echo "usage: ${0} SRC DEST" >& 2 exit 2 fi SRC=${1} DEST=${2} # Make sure that SRC is an absolute path and that it exists. if [ -z "${SRC}" ] || [ "${SRC:0:1}" != "/" ] || [ ! -d "${SRC}" ] ; then echo "${0}: source ${SRC} sanity check failed" >& 2 exit 3 fi # Make sure that DEST is an absolute path and that it doesn't yet exist. if [ -z "${DEST}" ] || [ "${DEST:0:1}" != "/" ] || [ -e "${DEST}" ] ; then echo "${0}: destination ${DEST} sanity check failed" >& 2 exit 4 fi # Do the copy. rsync --links --recursive --perms --times "${SRC}/" "${DEST}" # The remaining steps are not considered critical. set +e # Notify LaunchServices. CORESERVICES="/System/Library/Frameworks/CoreServices.framework" LAUNCHSERVICES="${CORESERVICES}/Frameworks/LaunchServices.framework" LSREGISTER="${LAUNCHSERVICES}/Support/lsregister" "${LSREGISTER}" -f "${DEST}" # If this script is not running as root and the application is installed # somewhere under /Applications, try to make it writable by all admin users. # This will allow other admin users to update the application from their own # user Keystone instances even if the Keystone ticket is not promoted to # system level. # # If the script is not running as root and the application is not installed # under /Applications, it might not be in a system-wide location, and it # probably won't be something that other users on the system are running, so # err on the side of safety and don't make it group-writable. # # If this script is running as root, a Keystone ticket promotion is expected, # and future updates can be expected to be applied as root, so # admin-writeability is not a concern. Set the entire thing to be owned by # root in that case, regardless of where it's installed, and drop any group # and other write permission. # # If this script is running as a user that is not a member of the admin group, # the chgrp operation will not succeed. Tolerate that case, because it's # better than the alternative, which is to make the application # world-writable. CHMOD_MODE="a+rX,u+w,go-w" if [ ${EUID} -ne 0 ] ; then if [ "${DEST:0:14}" = "/Applications/" ] && chgrp -Rh admin "${DEST}" >& /dev/null ; then CHMOD_MODE="a+rX,ug+w,o-w" fi else chown -Rh root:wheel "${DEST}" >& /dev/null fi chmod -R "${CHMOD_MODE}" "${DEST}" >& /dev/null # On the Mac, or at least on HFS+, symbolic link permissions are significant, # but chmod -R and -h can't be used together. Do another pass to fix the # permissions on any symbolic links. find "${DEST}" -type l -exec chmod -h "${CHMOD_MODE}" {} + >& /dev/null # Because this script is launched by the application itself, the installation # process inherits the quarantine bit (LSFileQuarantineEnabled). Any files or # directories created during the update will be quarantined in that case, # which may cause Launch Services to display quarantine UI. That's bad, # especially if it happens when the outer .app launches a quarantined inner # helper. Since the user approved the application launch if quarantined, it # it can be assumed that the installed copy should not be quarantined. Use # xattr to drop the quarantine attribute. QUARANTINE_ATTR=com.apple.quarantine xattr -d -r "${QUARANTINE_ATTR}" "${DEST}" >& /dev/null # Install the updater at system level when running as root. # (At user level, Chrome will install it and register as needed when run). if [ ${EUID} -eq 0 ] ; then readonly CHROME_APP_INFO_PLIST="${DEST}/Contents/Info.plist" # Create the brand file, if specified. brand_file_written="false" brand="$(infoplist_read "${CHROME_APP_INFO_PLIST}" "KSBrandID")" if [[ -n "${brand}" ]]; then readonly BRAND_PLIST="/Library/Google/Google Chrome Brand.plist" defaults write "${BRAND_PLIST}" "KSBrandID" \ -string "${brand}" \ && chmod 644 "${BRAND_PLIST}" \ && brand_file_written="true" fi set -e "${DEST}/Contents/Frameworks/Google Chrome Framework.framework/Helpers/GoogleUpdater.app/Contents/MacOS/GoogleUpdater" "--install" "--system" readonly KS_ADMIN="/Library/Google/GoogleSoftwareUpdate/GoogleSoftwareUpdate.bundle/Contents/MacOS/ksadmin" product="$(infoplist_read "${CHROME_APP_INFO_PLIST}" "KSProductID")" version="$(infoplist_read "${CHROME_APP_INFO_PLIST}" "KSVersion")" ksadmin_args=( --register --productid "${product}" --version "${version}" --xcpath "${DEST}" --tag-path "${CHROME_APP_INFO_PLIST}" --tag-key "KSChannelID" --version-path "${CHROME_APP_INFO_PLIST}" --version-key "KSVersion" ) # Tag to use if the app info plist is gone (i.e. the program is uninstalled). if channel="$(infoplist_read "${CHROME_APP_INFO_PLIST}" "KSChannelID")"; then ksadmin_args+=( --tag "${channel}" ) fi if [[ "${brand_file_written}" == "true" ]]; then ksadmin_args+=( --brand-path "${BRAND_PLIST}" --brand-key "KSBrandID" ) fi "${KS_ADMIN}" "${ksadmin_args[@]}" set +e fi # Great success! exit 0