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