| Index: chrome/installer/mac/keystone_install.sh
|
| diff --git a/chrome/installer/mac/keystone_install.sh b/chrome/installer/mac/keystone_install.sh
|
| index 1dbb6ed5945834bed577829fdb2455b7f4640cf5..401e65fcb2550bb8a19d213f68f6c15a5ffeb0cf 100755
|
| --- a/chrome/installer/mac/keystone_install.sh
|
| +++ b/chrome/installer/mac/keystone_install.sh
|
| @@ -29,13 +29,10 @@
|
| # 9 Could not get the version, update URL, or channel after update
|
| # 10 Updated application does not have the version number from the update
|
| # 11 ksadmin failure
|
| -# 12 dirpatcher failed for versioned directory
|
| -# 13 dirpatcher failed for outer .app bundle
|
| #
|
| -# The following exit codes are not used by this script, but can be used to
|
| -# convey special meaning to Keystone:
|
| +# The following exit codes can be used to convey special meaning to Keystone:
|
| # 66 (unused) success, request reboot
|
| -# 77 (unused) try installation again later
|
| +# 77 try installation again later
|
|
|
| set -eu
|
|
|
| @@ -61,6 +58,8 @@ shopt -s nullglob
|
| ME="$(basename "${0}")"
|
| readonly ME
|
|
|
| +readonly KS_CHANNEL_KEY="KSChannelID"
|
| +
|
| # Workaround for http://code.google.com/p/chromium/issues/detail?id=83180#c3
|
| # In bash 4.0, "declare VAR" no longer initializes VAR if not already set.
|
| : ${GOOGLE_CHROME_UPDATER_DEBUG:=}
|
| @@ -451,6 +450,14 @@ ksadmin_supports_versionpath_versionkey() {
|
| # return value.
|
| }
|
|
|
| +has_32_bit_only_cpu() {
|
| + local cpu_64_bit_capable="$(sysctl -n hw.cpu64bit_capable 2>/dev/null)"
|
| + [[ -z "${cpu_64_bit_capable}" || "${cpu_64_bit_capable}" -eq 0 ]]
|
| +
|
| + # The return value of the comparison is used as this function's return
|
| + # value.
|
| +}
|
| +
|
| # Runs "defaults read" to obtain the value of a key in a property list. As
|
| # with "defaults read", an absolute path to a plist is supplied, without the
|
| # ".plist" extension.
|
| @@ -484,6 +491,115 @@ infoplist_read() {
|
| __CFPREFERENCES_AVOID_DAEMON=1 defaults read "${@}"
|
| }
|
|
|
| +# When a patch update fails because the old installed copy doesn't match the
|
| +# expected state, mark_failed_patch_update updates the Keystone ticket by
|
| +# adding "-full" to the tag. The server will see this on a subsequent update
|
| +# attempt and will provide a full update (as opposed to a patch) to the
|
| +# client.
|
| +#
|
| +# Even if mark_failed_patch_update fails to modify the tag, the user will
|
| +# eventually be updated. Patch updates are only provided for successive
|
| +# releases on a particular channel, to update version o to version o+1. If a
|
| +# patch update fails in this case, eventually version o+2 will be released,
|
| +# and no patch update will exist to update o to o+2, so the server will
|
| +# provide a full update package.
|
| +mark_failed_patch_update() {
|
| + local product_id="${1}"
|
| + local want_full_installer_path="${2}"
|
| + local old_ks_plist="${3}"
|
| + local old_version_app="${4}"
|
| + local system_ticket="${5}"
|
| +
|
| + set +e
|
| +
|
| + note "marking failed patch update"
|
| +
|
| + local channel
|
| + channel="$(infoplist_read "${old_ks_plist}" "${KS_CHANNEL_KEY}" 2> /dev/null)"
|
| +
|
| + local tag="${channel}"
|
| + local tag_key="${KS_CHANNEL_KEY}"
|
| + if has_32_bit_only_cpu; then
|
| + tag="${tag}-32bit"
|
| + tag_key="${tag_key}-32bit"
|
| + fi
|
| +
|
| + tag="${tag}-full"
|
| + tag_key="${tag_key}-full"
|
| +
|
| + note "tag = ${tag}"
|
| + note "tag_key = ${tag_key}"
|
| +
|
| + # ${old_ks_plist}, used for --tag-path, is the Info.plist for the old
|
| + # version of Chrome. It may not contain the keys for the "-full" tag suffix.
|
| + # If it doesn't, just bail out without marking the patch update as failed.
|
| + local read_tag="$(infoplist_read "${old_ks_plist}" "${tag_key}" 2> /dev/null)"
|
| + note "read_tag = ${read_tag}"
|
| + if [[ -z "${read_tag}" ]]; then
|
| + note "couldn't mark failed patch update"
|
| + return 0
|
| + fi
|
| +
|
| + # Chrome can't easily read its Keystone ticket prior to registration, and
|
| + # when Chrome registers with Keystone, it obliterates old tag values in its
|
| + # ticket. Therefore, an alternative mechanism is provided to signal to
|
| + # Chrome that a full installer is desired. If the .want_full_installer file
|
| + # is present and it contains Chrome's current version number, Chrome will
|
| + # include "-full" in its tag when it registers with Keystone. This allows
|
| + # "-full" to persist in the tag even after Chrome is relaunched, which on a
|
| + # user ticket, triggers a re-registration.
|
| + #
|
| + # .want_full_installer is placed immediately inside the .app bundle as a
|
| + # sibling to the Contents directory. In this location, it's outside of the
|
| + # view of the code signing and code signature verification machinery. This
|
| + # file can safely be added, modified, and removed without affecting the
|
| + # signature.
|
| + rm -f "${want_full_installer_path}" 2> /dev/null
|
| + echo "${old_version_app}" > "${want_full_installer_path}"
|
| +
|
| + # See the comment below in the "setting permissions" section for an
|
| + # explanation of the groups and modes selected here.
|
| + local chmod_mode="644"
|
| + if [[ -z "${system_ticket}" ]] &&
|
| + [[ "${want_full_installer_path:0:14}" = "/Applications/" ]] &&
|
| + chgrp admin "${want_full_installer_path}" 2> /dev/null; then
|
| + chmod_mode="664"
|
| + fi
|
| + note "chmod_mode = ${chmod_mode}"
|
| + chmod "${chmod_mode}" "${want_full_installer_path}" 2> /dev/null
|
| +
|
| + local old_ks_plist_path="${old_ks_plist}.plist"
|
| +
|
| + # Using ksadmin without --register only updates specified values in the
|
| + # ticket, without changing other existing values.
|
| + local ksadmin_args=(
|
| + --productid "${product_id}"
|
| + )
|
| +
|
| + if ksadmin_supports_tag; then
|
| + ksadmin_args+=(
|
| + --tag "${tag}"
|
| + )
|
| + fi
|
| +
|
| + if ksadmin_supports_tagpath_tagkey; then
|
| + ksadmin_args+=(
|
| + --tag-path "${old_ks_plist_path}"
|
| + --tag-key "${tag_key}"
|
| + )
|
| + fi
|
| +
|
| + note "ksadmin_args = ${ksadmin_args[*]}"
|
| +
|
| + if ! ksadmin "${ksadmin_args[@]}"; then
|
| + err "ksadmin failed"
|
| + fi
|
| +
|
| + note "marked failed patch update"
|
| +
|
| + set -e
|
| +}
|
| +
|
| usage() {
|
| echo "usage: ${ME} update_dmg_mount_point" >& 2
|
| }
|
| @@ -513,7 +629,6 @@ main() {
|
| readonly KS_VERSION_KEY="KSVersion"
|
| readonly KS_PRODUCT_KEY="KSProductID"
|
| readonly KS_URL_KEY="KSUpdateURL"
|
| - readonly KS_CHANNEL_KEY="KSChannelID"
|
| readonly KS_BRAND_KEY="KSBrandID"
|
|
|
| readonly QUARANTINE_ATTR="com.apple.quarantine"
|
| @@ -740,6 +855,9 @@ main() {
|
| fi
|
| note "installed_app = ${installed_app}"
|
|
|
| + local want_full_installer_path="${installed_app}/.want_full_installer"
|
| + note "want_full_installer_path = ${want_full_installer_path}"
|
| +
|
| if [[ "${installed_app:0:1}" != "/" ]] ||
|
| ! [[ -d "${installed_app}" ]]; then
|
| err "installed_app must be an absolute path to a directory"
|
| @@ -902,7 +1020,12 @@ main() {
|
| "${patch_versioned_dir}" \
|
| "${versioned_dir_target}"; then
|
| err "dirpatcher of versioned directory failed, status ${PIPESTATUS[0]}"
|
| - exit 12
|
| + mark_failed_patch_update "${product_id}" \
|
| + "${want_full_installer_path}" \
|
| + "${old_ks_plist}" \
|
| + "${old_version_app}" \
|
| + "${system_ticket}"
|
| + exit 77
|
| fi
|
| fi
|
|
|
| @@ -956,7 +1079,12 @@ main() {
|
| "${patch_app_dir}" \
|
| "${update_app}"; then
|
| err "dirpatcher of app directory failed, status ${PIPESTATUS[0]}"
|
| - exit 13
|
| + mark_failed_patch_update "${product_id}" \
|
| + "${want_full_installer_path}" \
|
| + "${old_ks_plist}" \
|
| + "${old_version_app}" \
|
| + "${system_ticket}"
|
| + exit 77
|
| fi
|
| fi
|
|
|
| @@ -1004,6 +1132,11 @@ main() {
|
| note "g_temp_dir = ${g_temp_dir}"
|
| fi
|
|
|
| + # Clean up any old .want_full_installer files from previous dirpatcher
|
| + # failures. This is not considered a critical step, because this file
|
| + # normally does not exist at all.
|
| + rm -f "${want_full_installer_path}" || true
|
| +
|
| # If necessary, touch the outermost .app so that it appears to the outside
|
| # world that something was done to the bundle. This will cause
|
| # LaunchServices to invalidate the information it has cached about the
|
| @@ -1057,6 +1190,15 @@ main() {
|
| "${KS_CHANNEL_KEY}" 2> /dev/null || true)"
|
| note "channel = ${channel}"
|
|
|
| + local tag="${channel}"
|
| + local tag_key="${KS_CHANNEL_KEY}"
|
| + if has_32_bit_only_cpu; then
|
| + tag="${tag}-32bit"
|
| + tag_key="${tag_key}-32bit"
|
| + fi
|
| + note "tag = ${tag}"
|
| + note "tag_key = ${tag_key}"
|
| +
|
| # Make sure that the update was successful by comparing the version found in
|
| # the update with the version now on disk.
|
| if [[ "${new_version_ks}" != "${update_version_ks}" ]]; then
|
| @@ -1165,14 +1307,14 @@ main() {
|
|
|
| if ksadmin_supports_tag; then
|
| ksadmin_args+=(
|
| - --tag "${channel}"
|
| + --tag "${tag}"
|
| )
|
| fi
|
|
|
| if ksadmin_supports_tagpath_tagkey; then
|
| ksadmin_args+=(
|
| --tag-path "${installed_app_plist_path}"
|
| - --tag-key "${KS_CHANNEL_KEY}"
|
| + --tag-key "${tag_key}"
|
| )
|
| fi
|
|
|
|
|