OLD | NEW |
1 #!/bin/bash | 1 #!/bin/bash |
2 | 2 |
3 # Copyright (c) 2009 The Chromium Authors. All rights reserved. | 3 # Copyright (c) 2009 The Chromium Authors. All rights reserved. |
4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
6 | 6 |
7 # Called by the Keystone system to update the installed application with a new | 7 # Called by the Keystone system to update the installed application with a new |
8 # version from a disk image. | 8 # version from a disk image. |
9 | 9 |
10 # Return values: | 10 # Return values: |
11 # 0 Happiness | 11 # 0 Happiness |
12 # 1 Unknown failure | 12 # 1 Unknown failure |
13 # 2 Basic sanity check destination failure (e.g. ticket points to nothing) | 13 # 2 Basic sanity check destination failure (e.g. ticket points to nothing) |
14 # 3 Could not prepare existing installed version to receive update | 14 # 3 Could not prepare existing installed version to receive update |
15 # 4 rsync failed (could not assure presence of Versions directory) | 15 # 4 rsync failed (could not assure presence of Versions directory) |
16 # 5 rsync failed (could not copy new versioned directory to Versions) | 16 # 5 rsync failed (could not copy new versioned directory to Versions) |
17 # 6 rsync failed (could not update outer .app bundle) | 17 # 6 rsync failed (could not update outer .app bundle) |
18 # 7 Could not get the version, update URL, or channel after update | 18 # 7 Could not get the version, update URL, or channel after update |
19 # 8 Updated application does not have the version number from the update | 19 # 8 Updated application does not have the version number from the update |
20 # 9 ksadmin failure | 20 # 9 ksadmin failure |
21 # 10 Basic sanity check source failure (e.g. no app on disk image) | 21 # 10 Basic sanity check source failure (e.g. no app on disk image) |
22 | 22 |
23 set -e | 23 set -e |
24 | 24 |
25 # Returns 0 (true) if the parameter exists, is a symbolic link, and appears | 25 # Returns 0 (true) if the parameter exists, is a symbolic link, and appears |
26 # writeable on the basis of its POSIX permissions. This is used to determine | 26 # writable on the basis of its POSIX permissions. This is used to determine |
27 # writeability like test's -w primary, but -w resolves symbolic links and this | 27 # writeability like test's -w primary, but -w resolves symbolic links and this |
28 # function does not. | 28 # function does not. |
29 function is_writeable_symlink() { | 29 function is_writable_symlink() { |
30 SYMLINK=${1} | 30 SYMLINK=${1} |
31 LINKMODE=$(stat -f %Sp "${SYMLINK}" 2> /dev/null || true) | 31 LINKMODE=$(stat -f %Sp "${SYMLINK}" 2> /dev/null || true) |
32 if [ -z "${LINKMODE}" ] || [ "${LINKMODE:0:1}" != "l" ] ; then | 32 if [ -z "${LINKMODE}" ] || [ "${LINKMODE:0:1}" != "l" ] ; then |
33 return 1 | 33 return 1 |
34 fi | 34 fi |
35 LINKUSER=$(stat -f %u "${SYMLINK}" 2> /dev/null || true) | 35 LINKUSER=$(stat -f %u "${SYMLINK}" 2> /dev/null || true) |
36 LINKGROUP=$(stat -f %g "${SYMLINK}" 2> /dev/null || true) | 36 LINKGROUP=$(stat -f %g "${SYMLINK}" 2> /dev/null || true) |
37 if [ -z "${LINKUSER}" ] || [ -z "${LINKGROUP}" ] ; then | 37 if [ -z "${LINKUSER}" ] || [ -z "${LINKGROUP}" ] ; then |
38 return 1 | 38 return 1 |
39 fi | 39 fi |
(...skipping 22 matching lines...) Expand all Loading... |
62 return 1 | 62 return 1 |
63 fi | 63 fi |
64 | 64 |
65 # Check the other-write bit. | 65 # Check the other-write bit. |
66 if [ "${LINKMODE:8:1}" = "w" ] ; then | 66 if [ "${LINKMODE:8:1}" = "w" ] ; then |
67 return 0 | 67 return 0 |
68 fi | 68 fi |
69 return 1 | 69 return 1 |
70 } | 70 } |
71 | 71 |
72 # If SYMLINK exists and is a symbolic link, but is not writeable according to | 72 # If SYMLINK exists and is a symbolic link, but is not writable according to |
73 # is_writeable_symlink, this function attempts to replace it with a new | 73 # is_writable_symlink, this function attempts to replace it with a new |
74 # writeable symbolic link. If FROM does not exist, is not a symbolic link, or | 74 # writable symbolic link. If FROM does not exist, is not a symbolic link, or |
75 # is already writeable, this function does nothing. This function always | 75 # is already writable, this function does nothing. This function always |
76 # returns 0 (true). | 76 # returns 0 (true). |
77 function ensure_writeable_symlink() { | 77 function ensure_writable_symlink() { |
78 SYMLINK=${1} | 78 SYMLINK=${1} |
79 if [ -L "${SYMLINK}" ] && ! is_writeable_symlink "${SYMLINK}" ; then | 79 if [ -L "${SYMLINK}" ] && ! is_writable_symlink "${SYMLINK}" ; then |
80 # If ${SYMLINK} refers to a directory, doing this naively might result in | 80 # If ${SYMLINK} refers to a directory, doing this naively might result in |
81 # the new link being placed in that directory, instead of replacing the | 81 # the new link being placed in that directory, instead of replacing the |
82 # existing link. ln -fhs is supposed to handle this case, but it does so | 82 # existing link. ln -fhs is supposed to handle this case, but it does so |
83 # by unlinking (removing) the existing symbolic link before creating a new | 83 # by unlinking (removing) the existing symbolic link before creating a new |
84 # one. That leaves a small window during which the symbolic link is not | 84 # one. That leaves a small window during which the symbolic link is not |
85 # present on disk at all. | 85 # present on disk at all. |
86 # | 86 # |
87 # To avoid that possibility, a new symbolic link is created in a temporary | 87 # To avoid that possibility, a new symbolic link is created in a temporary |
88 # location and then swapped into place with mv. An extra temporary | 88 # location and then swapped into place with mv. An extra temporary |
89 # directory is used to convince mv to replace the symbolic link: again, if | 89 # directory is used to convince mv to replace the symbolic link: again, if |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
204 IFS=$(printf '\n\t') | 204 IFS=$(printf '\n\t') |
205 | 205 |
206 # Only consider symbolic links in ${SRC}. If there are any other links in | 206 # Only consider symbolic links in ${SRC}. If there are any other links in |
207 # ${DEST} not present in ${SRC}, rsync will delete them as needed later. | 207 # ${DEST} not present in ${SRC}, rsync will delete them as needed later. |
208 LINKS=$(cd "${SRC}" && find . -type l) | 208 LINKS=$(cd "${SRC}" && find . -type l) |
209 | 209 |
210 for link in ${LINKS} ; do | 210 for link in ${LINKS} ; do |
211 # ${link} is relative to ${SRC}. Prepending ${DEST} looks for the same | 211 # ${link} is relative to ${SRC}. Prepending ${DEST} looks for the same |
212 # link already on disk. | 212 # link already on disk. |
213 DESTLINK="${DEST}/${link}" | 213 DESTLINK="${DEST}/${link}" |
214 ensure_writeable_symlink "${DESTLINK}" | 214 ensure_writable_symlink "${DESTLINK}" |
215 done | 215 done |
216 | 216 |
217 # Go back to how things were. | 217 # Go back to how things were. |
218 IFS="${IFS_OLD}" | 218 IFS="${IFS_OLD}" |
219 set -e | 219 set -e |
220 fi | 220 fi |
221 | 221 |
222 # Don't use rsync -a, because -a expands to -rlptgoD. -g and -o copy owners | 222 # Don't use rsync -a, because -a expands to -rlptgoD. -g and -o copy owners |
223 # and groups, respectively, from the source, and that is undesirable in this | 223 # and groups, respectively, from the source, and that is undesirable in this |
224 # case. -D copies devices and special files; copying devices only works | 224 # case. -D copies devices and special files; copying devices only works |
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
407 grep -Fqx "${PS_STRING}") && | 407 grep -Fqx "${PS_STRING}") && |
408 (! lsof "${LSOF_FILE}" >& /dev/null) ; then | 408 (! lsof "${LSOF_FILE}" >& /dev/null) ; then |
409 # It doesn't look like anything is using this versioned directory. Get rid | 409 # It doesn't look like anything is using this versioned directory. Get rid |
410 # of it. | 410 # of it. |
411 rm -rf "${versioned_dir}" | 411 rm -rf "${versioned_dir}" |
412 fi | 412 fi |
413 done | 413 done |
414 | 414 |
415 # If this script is not running as root (indicating an update driven by a user | 415 # If this script is not running as root (indicating an update driven by a user |
416 # Keystone ticket) and the application is installed somewhere under | 416 # Keystone ticket) and the application is installed somewhere under |
417 # /Applications, try to make it writeable by all admin users. This will allow | 417 # /Applications, try to make it writable by all admin users. This will allow |
418 # other admin users to update the application from their own user Keystone | 418 # other admin users to update the application from their own user Keystone |
419 # instances. | 419 # instances. |
420 # | 420 # |
421 # If the script is not running as root and the application is not installed | 421 # If the script is not running as root and the application is not installed |
422 # under /Applications, it might not be in a system-wide location, and it | 422 # under /Applications, it might not be in a system-wide location, and it |
423 # probably won't be something that other users on the system are running, so | 423 # probably won't be something that other users on the system are running, so |
424 # err on the side of safety and don't make it group-writeable. | 424 # err on the side of safety and don't make it group-writable. |
425 # | 425 # |
426 # If this script is running as root, it's driven by a system Keystone ticket, | 426 # If this script is running as root, it's driven by a system Keystone ticket, |
427 # and future updates can be expected to be applied the same way, so | 427 # and future updates can be expected to be applied the same way, so |
428 # admin-writeability is not a concern. Set the entire thing to be owned by | 428 # admin-writeability is not a concern. Set the entire thing to be owned by |
429 # root in that case, regardless of where it's installed, and drop any group | 429 # root in that case, regardless of where it's installed, and drop any group |
430 # and other write permission. | 430 # and other write permission. |
431 # | 431 # |
432 # If this script is running as a user that is not a member of the admin group, | 432 # If this script is running as a user that is not a member of the admin group, |
433 # the chgrp operation will not succeed. Tolerate that case, because it's | 433 # the chgrp operation will not succeed. Tolerate that case, because it's |
434 # better than the alternative, which is to make the application | 434 # better than the alternative, which is to make the application |
435 # world-writeable. | 435 # world-writable. |
436 CHMOD_MODE="a+rX,u+w,go-w" | 436 CHMOD_MODE="a+rX,u+w,go-w" |
437 if [ ${EUID} -ne 0 ] ; then | 437 if [ ${EUID} -ne 0 ] ; then |
438 if [ "${DEST:0:14}" = "/Applications/" ] && | 438 if [ "${DEST:0:14}" = "/Applications/" ] && |
439 chgrp -Rh admin "${DEST}" >& /dev/null ; then | 439 chgrp -Rh admin "${DEST}" >& /dev/null ; then |
440 CHMOD_MODE="a+rX,ug+w,o-w" | 440 CHMOD_MODE="a+rX,ug+w,o-w" |
441 fi | 441 fi |
442 else | 442 else |
443 chown -Rh root:wheel "${DEST}" >& /dev/null | 443 chown -Rh root:wheel "${DEST}" >& /dev/null |
444 fi | 444 fi |
445 | 445 |
(...skipping 28 matching lines...) Expand all Loading... |
474 ([ ${OS_MAJOR} -eq 10 ] && [ ${OS_MINOR} -ge 6 ]) ; then | 474 ([ ${OS_MAJOR} -eq 10 ] && [ ${OS_MINOR} -ge 6 ]) ; then |
475 # On 10.6, xattr supports -r for recursive operation. | 475 # On 10.6, xattr supports -r for recursive operation. |
476 xattr -d -r "${QUARANTINE_ATTR}" "${DEST}" >& /dev/null | 476 xattr -d -r "${QUARANTINE_ATTR}" "${DEST}" >& /dev/null |
477 else | 477 else |
478 # On earlier systems, xattr doesn't support -r, so run xattr via find. | 478 # On earlier systems, xattr doesn't support -r, so run xattr via find. |
479 find "${DEST}" -exec xattr -d "${QUARANTINE_ATTR}" {} + >& /dev/null | 479 find "${DEST}" -exec xattr -d "${QUARANTINE_ATTR}" {} + >& /dev/null |
480 fi | 480 fi |
481 | 481 |
482 # Great success! | 482 # Great success! |
483 exit 0 | 483 exit 0 |
OLD | NEW |