1#!/bin/bash -p 2 3# Copyright (c) 2011 The Chromium Authors. All rights reserved. 4# Use of this source code is governed by a BSD-style license that can be 5# found in the LICENSE file. 6 7# Called by the application to install in a new location. Generally, this 8# means that the application is running from a disk image and wants to be 9# copied to /Applications. The application, when running from the disk image, 10# will call this script to perform the copy. 11# 12# This script will be run as root if the application determines that it would 13# not otherwise have permission to perform the copy. 14# 15# When running as root, this script will be invoked with the real user ID set 16# to the user's ID, but the effective user ID set to 0 (root). bash -p is 17# used on the first line to prevent bash from setting the effective user ID to 18# the real user ID (dropping root privileges). 19 20set -e 21 22# This script may run as root, so be paranoid about things like ${PATH}. 23export PATH="/usr/bin:/usr/sbin:/bin:/sbin" 24 25# If running as root, output the pid to stdout before doing anything else. 26# See chrome/browser/mac/authorization_util.h. 27if [ ${EUID} -eq 0 ] ; then 28 echo "${$}" 29fi 30 31if [ ${#} -ne 2 ] ; then 32 echo "usage: ${0} SRC DEST" >& 2 33 exit 2 34fi 35 36SRC=${1} 37DEST=${2} 38 39# Make sure that SRC is an absolute path and that it exists. 40if [ -z "${SRC}" ] || [ "${SRC:0:1}" != "/" ] || [ ! -d "${SRC}" ] ; then 41 echo "${0}: source ${SRC} sanity check failed" >& 2 42 exit 3 43fi 44 45# Make sure that DEST is an absolute path and that it doesn't yet exist. 46if [ -z "${DEST}" ] || [ "${DEST:0:1}" != "/" ] || [ -e "${DEST}" ] ; then 47 echo "${0}: destination ${DEST} sanity check failed" >& 2 48 exit 4 49fi 50 51# Do the copy. 52rsync -lrpt "${SRC}/" "${DEST}" 53 54# The remaining steps are not considered critical. 55set +e 56 57# Notify LaunchServices. 58CORESERVICES="/System/Library/Frameworks/CoreServices.framework" 59LAUNCHSERVICES="${CORESERVICES}/Frameworks/LaunchServices.framework" 60LSREGISTER="${LAUNCHSERVICES}/Support/lsregister" 61"${LSREGISTER}" -f "${DEST}" 62 63# If this script is not running as root and the application is installed 64# somewhere under /Applications, try to make it writable by all admin users. 65# This will allow other admin users to update the application from their own 66# user Keystone instances even if the Keystone ticket is not promoted to 67# system level. 68# 69# If the script is not running as root and the application is not installed 70# under /Applications, it might not be in a system-wide location, and it 71# probably won't be something that other users on the system are running, so 72# err on the side of safety and don't make it group-writable. 73# 74# If this script is running as root, a Keystone ticket promotion is expected, 75# and future updates can be expected to be applied as root, so 76# admin-writeability is not a concern. Set the entire thing to be owned by 77# root in that case, regardless of where it's installed, and drop any group 78# and other write permission. 79# 80# If this script is running as a user that is not a member of the admin group, 81# the chgrp operation will not succeed. Tolerate that case, because it's 82# better than the alternative, which is to make the application 83# world-writable. 84CHMOD_MODE="a+rX,u+w,go-w" 85if [ ${EUID} -ne 0 ] ; then 86 if [ "${DEST:0:14}" = "/Applications/" ] && 87 chgrp -Rh admin "${DEST}" >& /dev/null ; then 88 CHMOD_MODE="a+rX,ug+w,o-w" 89 fi 90else 91 chown -Rh root:wheel "${DEST}" >& /dev/null 92fi 93 94chmod -R "${CHMOD_MODE}" "${DEST}" >& /dev/null 95 96# On the Mac, or at least on HFS+, symbolic link permissions are significant, 97# but chmod -R and -h can't be used together. Do another pass to fix the 98# permissions on any symbolic links. 99find "${DEST}" -type l -exec chmod -h "${CHMOD_MODE}" {} + >& /dev/null 100 101# Host OS version check, to be able to take advantage of features on newer 102# systems and fall back to slow ways of doing things on older systems. 103OS_VERSION=$(sw_vers -productVersion) 104OS_MAJOR=$(sed -Ene 's/^([0-9]+).*/\1/p' <<< ${OS_VERSION}) 105OS_MINOR=$(sed -Ene 's/^([0-9]+)\.([0-9]+).*/\2/p' <<< ${OS_VERSION}) 106 107# Because this script is launched by the application itself, the installation 108# process inherits the quarantine bit (LSFileQuarantineEnabled). Any files or 109# directories created during the update will be quarantined in that case, 110# which may cause Launch Services to display quarantine UI. That's bad, 111# especially if it happens when the outer .app launches a quarantined inner 112# helper. Since the user approved the application launch if quarantined, it 113# it can be assumed that the installed copy should not be quarantined. Use 114# xattr to drop the quarantine attribute. 115QUARANTINE_ATTR=com.apple.quarantine 116if [ ${OS_MAJOR} -gt 10 ] || 117 ([ ${OS_MAJOR} -eq 10 ] && [ ${OS_MINOR} -ge 6 ]) ; then 118 # On 10.6, xattr supports -r for recursive operation. 119 xattr -d -r "${QUARANTINE_ATTR}" "${DEST}" >& /dev/null 120else 121 # On earlier systems, xattr doesn't support -r, so run xattr via find. 122 find "${DEST}" -exec xattr -d "${QUARANTINE_ATTR}" {} + >& /dev/null 123fi 124 125# Great success! 126exit 0 127