OLD | NEW |
1 #!/bin/bash | 1 #!/bin/bash |
2 | 2 |
3 # Copyright (c) 2009 The Chromium OS Authors. All rights reserved. | 3 # Copyright (c) 2009 The Chromium OS 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 # This is the autoupdater for Memento. When called it consults Omaha to see | 7 # This is the autoupdater for Memento. When called it consults Omaha to see |
8 # if there's an update available. If so, it downloads it to the other | 8 # if there's an update available. If so, it downloads it to the other |
9 # partition on the Memento USB stick, then alters the MBR and partitions | 9 # partition on the Memento USB stick, then alters the MBR and partitions |
10 # as needed so the next reboot will boot into the newly installed partition. | 10 # as needed so the next reboot will boot into the newly installed partition. |
11 # Care is taken to ensure that when this exits the USB stick is configured | 11 # Care is taken to ensure that when this exits the USB stick is configured |
12 # to boot into the same partition as before or into the new partition, | 12 # to boot into the same partition as before or into the new partition, |
13 # however there may be a small time window when this is not the case. Such a | 13 # however there may be a small time window when this is not the case. Such a |
14 # window should be about 1 second or less, and we tolerate that since this | 14 # window should be about 1 second or less, and we tolerate that since this |
15 # is for testing and not a real autoupdate solution for the long run. | 15 # is for testing and not a real autoupdate solution for the long run. |
16 | 16 |
17 source `dirname "$0"`/memento_updater_logging.sh | 17 source `dirname "$0"`/memento_updater_logging.sh || exit 1 |
| 18 . /usr/lib/shflags || exit 1 |
| 19 |
| 20 DEFINE_boolean force_update $FLAGS_FALSE \ |
| 21 "Force update" |
| 22 DEFINE_string install_url "" \ |
| 23 "Skip Omaha; Install image at this URL." |
| 24 DEFINE_string install_url_checksum "" \ |
| 25 "When using --install_url, the corresponding checksum" |
| 26 DEFINE_string dst_partition "" \ |
| 27 "If set, force installation onto the partition given." |
| 28 DEFINE_boolean allow_removable_boot $FLAGS_FALSE \ |
| 29 "Run even if booted from removable media." |
| 30 DEFINE_string force_track "" \ |
| 31 "If set, force a given track to be sent to Omaha" |
| 32 |
| 33 # Parse command line |
| 34 FLAGS "$@" || exit 1 |
| 35 eval set -- "${FLAGS_ARGV}" |
18 | 36 |
19 # make sure we're root | 37 # make sure we're root |
20 if [ "root" != $(whoami) ] | 38 if [ "root" != $(whoami) ] |
21 then | 39 then |
22 echo run this script as root | 40 echo run this script as root |
23 exit 1 | 41 exit 1 |
24 fi | 42 fi |
25 | 43 |
26 # check that this script doesn't run concurrently | 44 # check that this script doesn't run concurrently |
27 PID_FILE=/tmp/memento_updater_lock | 45 PID_FILE=/tmp/memento_updater_lock |
28 if [[ -f "$PID_FILE" && ! -d /proc/`cat $PID_FILE` ]] | 46 if [[ -f "$PID_FILE" && ! -d /proc/`cat $PID_FILE` ]] |
29 then | 47 then |
30 # process holding lock file is dead. clean up lockfile | 48 # process holding lock file is dead. clean up lockfile |
31 rm -rf "$PID_FILE" | 49 rm -rf "$PID_FILE" |
32 fi | 50 fi |
33 | 51 |
34 # make sure we're not booted from USB | 52 # make sure we're not booted from USB |
35 HAS_INITRD=$(grep ' initrd=' /proc/cmdline | wc -l) | 53 ROOTDEV=$(rootdev) |
36 if [ "$HAS_INITRD" = "1" ] | 54 # Remove numbers at end of rootfs device. |
37 then | 55 SRC=${ROOTDEV%%[0-9]*} |
| 56 REMOVABLE=$(cat /sys/block/${SRC#/dev/}/removable) |
| 57 if [[ "$REMOVABLE" = "1" && \ |
| 58 "${FLAGS_allow_removable_boot}" = "${FLAGS_FALSE}" ]]; then |
38 log not updating because we booted from USB | 59 log not updating because we booted from USB |
39 exit 1 | 60 exit 1 |
40 fi | 61 fi |
41 | 62 |
42 # make sure update hasn't already completed | 63 if [ -z "${FLAGS_dst_partition}" ]; then |
43 UPDATED_COMPLETED_FILE="/tmp/memento_autoupdate_completed" | 64 # make sure update hasn't already completed |
44 if [ -f "$UPDATED_COMPLETED_FILE" ] | 65 UPDATED_COMPLETED_FILE="/tmp/memento_autoupdate_completed" |
45 then | 66 if [ -f "$UPDATED_COMPLETED_FILE" ] |
46 exit 0 | 67 then |
| 68 exit 0 |
| 69 fi |
47 fi | 70 fi |
48 | 71 |
49 if ( set -o noclobber; echo "$$" > "$PID_FILE") 2> /dev/null; | 72 if ( set -o noclobber; echo "$$" > "$PID_FILE") 2> /dev/null; |
50 then | 73 then |
51 true | 74 true |
52 else | 75 else |
53 log "Failed to acquire lockfile: $PID_FILE." | 76 log "Failed to acquire lockfile: $PID_FILE." |
54 log "Held by $(cat $PID_FILE)" | 77 log "Held by $(cat $PID_FILE)" |
55 exit 1 | 78 exit 1 |
56 fi | 79 fi |
57 # remove lockfile when we exit | 80 # remove lockfile when we exit |
58 trap 'rm -f "$PID_FILE"; log Memento AutoUpdate terminating; exit $?' \ | 81 trap 'rm -f "$PID_FILE"; log Memento AutoUpdate terminating; exit $?' \ |
59 INT TERM EXIT | 82 INT TERM EXIT |
60 | 83 |
61 if [ x$1 = "x-f" ]; then | |
62 log "Forced update requested" | |
63 ForceUpdate="yes" | |
64 shift | |
65 fi | |
66 | |
67 log Memento AutoUpdate starting | 84 log Memento AutoUpdate starting |
68 | 85 |
69 # See if we're forcing an update from a specific URL | 86 # See if we're forcing an update from a specific URL |
70 if [ "x" = "x$1" ] | 87 if [ -z "$FLAGS_install_url" ] |
71 then | 88 then |
72 # abort if autoupdates have been disabled, but only when an update image | 89 # abort if autoupdates have been disabled, but only when an update image |
73 # isn't forced | 90 # isn't forced |
74 UPDATES_DISABLED_FILE="/var/local/disable_software_update" | 91 UPDATES_DISABLED_FILE="/var/local/disable_software_update" |
75 if [ -f "$UPDATES_DISABLED_FILE" ] | 92 if [ -f "$UPDATES_DISABLED_FILE" ] |
76 then | 93 then |
77 log Updates disabled. Aborting. | 94 log Updates disabled. Aborting. |
78 exit 0 | 95 exit 0 |
79 fi | 96 fi |
80 | 97 |
81 # check w/ omaha to see if there's an update | 98 # check w/ omaha to see if there's an update |
82 if [ "$ForceUpdate" = "yes" ]; then | 99 EXTRA_PING_ARGS="" |
83 OMAHA_CHECK_OUTPUT=$(`dirname "$0"`/ping_omaha.sh "ForcedUpdate") | 100 if [ "${FLAGS_force_track}" != "" ]; then |
84 else | 101 EXTRA_PING_ARGS="${EXTRA_PING_ARGS} --track=${FLAGS_force_track}" |
85 OMAHA_CHECK_OUTPUT=$(`dirname "$0"`/ping_omaha.sh) | |
86 fi | 102 fi |
| 103 if [ ${FLAGS_force_update} -eq ${FLAGS_TRUE} ]; then |
| 104 EXTRA_PING_ARGS="${EXTRA_PING_ARGS} --app_version=ForcedUpdate" |
| 105 fi |
| 106 OMAHA_CHECK_OUTPUT=$(`dirname "$0"`/ping_omaha.sh ${EXTRA_PING_ARGS}) |
87 IMG_URL=$(echo "$OMAHA_CHECK_OUTPUT" | grep '^URL=' | cut -d = -f 2-) | 107 IMG_URL=$(echo "$OMAHA_CHECK_OUTPUT" | grep '^URL=' | cut -d = -f 2-) |
88 CHECKSUM=$(echo "$OMAHA_CHECK_OUTPUT" | grep '^HASH=' | cut -d = -f 2-) | 108 CHECKSUM=$(echo "$OMAHA_CHECK_OUTPUT" | grep '^HASH=' | cut -d = -f 2-) |
89 else | 109 else |
90 log User forced an update from: "$1" checksum: "$2" | 110 if [ -z "$FLAGS_install_url_checksum" ]; then |
91 IMG_URL="$1" | 111 log Specified --install_url, but not --install_url_checksum. Aborting. |
92 CHECKSUM="$2" | 112 exit 1 |
| 113 fi |
| 114 log User forced an update from: "$FLAGS_install_url" checksum: \ |
| 115 "$FLAGS_install_url_checksum" |
| 116 IMG_URL="$FLAGS_install_url" |
| 117 CHECKSUM="$FLAGS_install_url_checksum" |
93 fi | 118 fi |
94 | 119 |
95 APP_VERSION=$(echo "$OMAHA_CHECK_OUTPUT" | grep '^APP_VERSION=' | \ | 120 APP_VERSION=$(echo "$OMAHA_CHECK_OUTPUT" | grep '^APP_VERSION=' | \ |
96 cut -d = -f 2-) | 121 cut -d = -f 2-) |
97 | 122 |
98 if [[ -z "$IMG_URL" || -z "$CHECKSUM" ]] | 123 if [[ -z "$IMG_URL" || -z "$CHECKSUM" ]] |
99 then | 124 then |
100 log no update | 125 log no update |
101 exit 0 | 126 exit 0 |
102 fi | 127 fi |
103 # TODO(adlr): make sure we have enough space for the download. we are | 128 # TODO(adlr): make sure we have enough space for the download. This script is |
104 # already correct if we don't have space, but it would be nice to fail | 129 # already correct if we don't have space, but it would be nice to fail |
105 # fast. | 130 # fast. |
106 log Update Found: $IMG_URL checksum: $CHECKSUM | 131 log Update Found: $IMG_URL checksum: $CHECKSUM |
107 | 132 |
108 # Figure out which partition I'm on, and which to download to. | 133 # Figure out which partition I'm on, and which to download to. |
109 LOCAL_DEV=$(rootdev) | 134 LOCAL_DEV=$(rootdev) |
110 | 135 |
111 # We install onto the other partition so if we end in 3, other ends in 5, and | 136 # We install onto the other partition so if we end in 3, other ends in 5, and |
112 # vice versa | 137 # vice versa |
113 INSTALL_DEV=$(echo $LOCAL_DEV | tr '35' '53') | 138 if [ -n "${FLAGS_dst_partition}" ]; then |
| 139 INSTALL_DEV="${FLAGS_dst_partition}" |
| 140 else |
| 141 INSTALL_DEV=$(echo $LOCAL_DEV | tr '35' '53') |
| 142 fi |
114 NEW_PART_NUM=${INSTALL_DEV##*/*[a-z]} | 143 NEW_PART_NUM=${INSTALL_DEV##*/*[a-z]} |
115 # The kernel needs to be installed to its own partition. We'll handle that in | 144 # The kernel needs to be installed to its own partition. We'll handle that in |
116 # the postinst script (from the new rootfs). partitions 2&3 are image A, | 145 # the postinst script (from the new rootfs). partitions 2&3 are image A, |
117 # partitions 4&5 are image B. | 146 # partitions 4&5 are image B. |
118 KINSTALL_DEV=$(echo $INSTALL_DEV | tr '35' '24') | 147 KINSTALL_DEV=$(echo $INSTALL_DEV | tr '35' '24') |
119 | 148 |
120 # Find whole disk device. | 149 # Find whole disk device. |
121 ROOT_DEV=${LOCAL_DEV%%[0-9]*} | 150 ROOT_DEV=${INSTALL_DEV%%[0-9]*} |
122 | 151 |
123 # Do some device sanity checks. | 152 # Do some device sanity checks. |
124 if ! expr match "$LOCAL_DEV" '^/dev/[a-z][a-z]*[12345]$' > /dev/null | 153 if ! expr match "$LOCAL_DEV" '^/dev/[a-z][a-z]*[12345]$' > /dev/null |
125 then | 154 then |
126 log "didnt find good local device. local: $LOCAL_DEV install: $INSTALL_DEV" | 155 log "didnt find good local device. local: $LOCAL_DEV install: $INSTALL_DEV" |
127 exit 1 | 156 exit 1 |
128 fi | 157 fi |
129 if ! expr match "$INSTALL_DEV" '^/dev/[a-z][a-z]*[12345]$' > /dev/null | 158 if ! expr match "$INSTALL_DEV" '^/dev/[a-z][a-z]*[12345]$' > /dev/null |
130 then | 159 then |
131 log "didnt find good install device. local: $LOCAL_DEV install: $INSTALL_DEV" | 160 log "didnt find good install device. local: $LOCAL_DEV install: $INSTALL_DEV" |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
205 # it's best not to interrupt the script from this point on out, since it | 234 # it's best not to interrupt the script from this point on out, since it |
206 # should really be doing these things atomically. hopefully this part will | 235 # should really be doing these things atomically. hopefully this part will |
207 # run rather quickly. | 236 # run rather quickly. |
208 | 237 |
209 # tell the new image to make itself "ready" | 238 # tell the new image to make itself "ready" |
210 log running postinst on the downloaded image | 239 log running postinst on the downloaded image |
211 MOUNTPOINT=/tmp/newpart | 240 MOUNTPOINT=/tmp/newpart |
212 mkdir -p "$MOUNTPOINT" | 241 mkdir -p "$MOUNTPOINT" |
213 mount "$INSTALL_DEV" "$MOUNTPOINT" | 242 mount "$INSTALL_DEV" "$MOUNTPOINT" |
214 | 243 |
215 # Check version of new software | 244 # Check version of new software if not forcing a dst partition |
216 NEW_VERSION=$(grep ^GOOGLE_RELEASE "$MOUNTPOINT"/etc/lsb-release | \ | 245 if [ -z "${FLAGS_dst_partition}" ]; then |
217 cut -d = -f 2-) | 246 NEW_VERSION=$(grep ^GOOGLE_RELEASE "$MOUNTPOINT"/etc/lsb-release | \ |
218 if [ "x$NEW_VERSION" = "x" ] | 247 cut -d = -f 2-) |
219 then | 248 if [ "x$NEW_VERSION" = "x" ] |
220 log "Can't find new version number. aborting update" | |
221 umount "$MOUNTPOINT" | |
222 rmdir "$MOUNTPOINT" | |
223 exit 1 | |
224 else | |
225 # See if it's newer than us | |
226 if [ "$ForceUpdate" != "yes" ] && | |
227 version_number_greater_than "$APP_VERSION" "$NEW_VERSION" | |
228 then | 249 then |
229 log "Can't upgrade to older version: " "$NEW_VERSION" | 250 log "Can't find new version number. aborting update" |
230 umount "$MOUNTPOINT" | 251 umount "$MOUNTPOINT" |
231 rmdir "$MOUNTPOINT" | 252 rmdir "$MOUNTPOINT" |
232 exit 1 | 253 exit 1 |
| 254 else |
| 255 # See if it's newer than us |
| 256 if [ "${FLAGS_force_update}" != "${FLAGS_TRUE}" ] && |
| 257 version_number_greater_than "$APP_VERSION" "$NEW_VERSION" |
| 258 then |
| 259 log "Can't upgrade to older version: " "$NEW_VERSION" |
| 260 umount "$MOUNTPOINT" |
| 261 rmdir "$MOUNTPOINT" |
| 262 exit 1 |
| 263 fi |
233 fi | 264 fi |
234 fi | 265 fi |
235 | 266 |
236 "$MOUNTPOINT"/postinst "$INSTALL_DEV" "$KINSTALL_DEV" 2>&1 | \ | 267 "$MOUNTPOINT"/postinst "$INSTALL_DEV" "$KINSTALL_DEV" 2>&1 | \ |
237 cat >> "$MEMENTO_AU_LOG" | 268 cat >> "$MEMENTO_AU_LOG" |
238 [ "${PIPESTATUS[*]}" = "0 0" ] | 269 [ "${PIPESTATUS[*]}" = "0 0" ] |
239 POSTINST_RETURN_CODE=$? | 270 POSTINST_RETURN_CODE=$? |
240 umount "$MOUNTPOINT" | 271 umount "$MOUNTPOINT" |
241 rmdir "$MOUNTPOINT" | 272 rmdir "$MOUNTPOINT" |
242 | 273 |
243 # $1 is return code, $2 is command | 274 # $1 is return code, $2 is command |
244 function abort_update_if_cmd_failed_long { | 275 function abort_update_if_cmd_failed_long { |
245 if [ "$1" -ne "0" ] | 276 if [ "$1" -ne "0" ] |
246 then | 277 then |
247 log "$2 failed with error code $1 . aborting update" | 278 log "$2 failed with error code $1 . aborting update" |
248 exit 1 | 279 exit 1 |
249 fi | 280 fi |
250 } | 281 } |
251 | 282 |
252 function abort_update_if_cmd_failed { | 283 function abort_update_if_cmd_failed { |
253 abort_update_if_cmd_failed_long "$?" "!!" | 284 abort_update_if_cmd_failed_long "$?" "!!" |
254 } | 285 } |
255 | 286 |
256 # If it failed, don't update MBR but just to be safe, zero out a page of | 287 # If it failed, don't update MBR but just to be safe, zero out a page of |
257 # install device. | 288 # install device. |
258 abort_update_if_cmd_failed_long "$POSTINST_RETURN_CODE" "$MOUNTPOINT"/postinst | 289 abort_update_if_cmd_failed_long "$POSTINST_RETURN_CODE" "$MOUNTPOINT"/postinst |
259 | 290 |
260 # postinstall on new partition succeeded. | 291 # postinstall on new partition succeeded. |
261 # fix up MBR and make our own partition not something casper will find | |
262 | |
263 # update MBR to make the other partition bootable | |
264 # the slash-magic converts '/' -> '\/' so it's valid in a regex | |
265 log updating MBR of usb device | |
266 | 292 |
267 # flush linux caches; seems to be necessary | 293 # flush linux caches; seems to be necessary |
268 sync | 294 sync |
269 echo 3 > /proc/sys/vm/drop_caches | 295 echo 3 > /proc/sys/vm/drop_caches |
270 # Configure the PMBR to boot the new image. | 296 # Configure the PMBR to boot the new image. |
271 # TODO: ChromeOS EFI BIOS will need a different command to set the GPT | 297 # TODO: ChromeOS EFI BIOS will need a different command to set the GPT |
272 # partition attributes bits to mark the new image as bootable. | 298 # partition attributes bits to mark the new image as bootable. |
273 # NOTE: This won't work for ARM, because we'll need to regenerate the U-Boot | 299 # NOTE: This won't work for ARM, because we'll need to regenerate the U-Boot |
274 # script when the kernel size and location are changed. Luckily it won't | 300 # script when the kernel size and location are changed. Luckily it won't |
275 # matter because we'll ship with the GPT-based selection process. The U-Boot | 301 # matter because we'll ship with the GPT-based selection process. The U-Boot |
276 # script is just a temporary hack for bringup. | 302 # script is just a temporary hack for bringup. |
277 # FIX: The current gpt tool requires a -b arg to specify the PMBR bootcode. We | 303 # FIX: The current gpt tool requires a -b arg to specify the PMBR bootcode. We |
278 # don't want to change the code, so we have to extract it, then put it back. | 304 # don't want to change the code, so we have to extract it, then put it back. |
279 # We'll fix this RSN. | 305 # We'll fix this RSN. |
280 dd if=${ROOT_DEV} bs=512 count=1 of=/tmp/oldpmbr.bin | 306 dd if=${ROOT_DEV} bs=512 count=1 of=/tmp/oldpmbr.bin |
281 gpt -S boot -i $NEW_PART_NUM -b /tmp/oldpmbr.bin ${ROOT_DEV} 2>&1 | \ | 307 gpt -S boot -i $NEW_PART_NUM -b /tmp/oldpmbr.bin ${ROOT_DEV} 2>&1 | \ |
282 cat >> "$MEMENTO_AU_LOG" | 308 cat >> "$MEMENTO_AU_LOG" |
283 abort_update_if_cmd_failed | 309 abort_update_if_cmd_failed |
284 | 310 |
285 # mark update as complete so we don't try to update again | 311 if [ -z "${FLAGS_dst_partition}" ]; then |
286 touch "$UPDATED_COMPLETED_FILE" | 312 # mark update as complete so we don't try to update again |
| 313 touch "$UPDATED_COMPLETED_FILE" |
| 314 fi |
287 | 315 |
288 # tell user to reboot | 316 # tell user to reboot |
289 log Autoupdate applied. You should now reboot | 317 log Autoupdate applied. You should now reboot |
290 echo UPDATED | 318 echo UPDATED |
OLD | NEW |