OLD | NEW |
1 #!/bin/bash | 1 #!/bin/bash |
2 | 2 |
3 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 3 # Copyright (c) 2010 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 script modifies a base image to act as a recovery installer. | 7 # This script modifies a base image to act as a recovery installer. |
8 # If no kernel image is supplied, it will build a devkeys signed recovery | 8 # If no kernel image is supplied, it will build a devkeys signed recovery |
9 # kernel. Alternatively, a signed recovery kernel can be used to | 9 # kernel. Alternatively, a signed recovery kernel can be used to |
10 # create a Chromium OS recovery image. | 10 # create a Chromium OS recovery image. |
11 | 11 |
12 # Load common constants. This should be the first executable line. | 12 # Load common constants. This should be the first executable line. |
13 # The path to common.sh should be relative to your script's location. | 13 # The path to common.sh should be relative to your script's location. |
14 . "$(dirname "$0")/common.sh" | 14 . "$(dirname "$0")/common.sh" |
15 | 15 |
16 # Load functions and constants for chromeos-install | 16 # Load functions and constants for chromeos-install |
17 . "$(dirname "$0")/chromeos-common.sh" | 17 . "$(dirname "$0")/chromeos-common.sh" |
18 | 18 |
19 # For update_partition_table | 19 # For update_partition_table |
20 . "$(dirname "$0")/resize_stateful_partition.sh" | 20 . "$(dirname "$0")/resize_stateful_partition.sh" |
21 | 21 |
22 | 22 |
23 # We need to be in the chroot to emerge test packages. | 23 # We need to be in the chroot to emerge test packages. |
24 assert_inside_chroot | 24 assert_inside_chroot |
25 | 25 |
26 get_default_board | 26 get_default_board |
27 | 27 |
28 DEFINE_string board "$DEFAULT_BOARD" "Board for which the image was built" b | 28 DEFINE_string board "$DEFAULT_BOARD" "Board for which the image was built" b |
29 DEFINE_integer statefulfs_sectors 4096 \ | 29 DEFINE_integer statefulfs_sectors 4096 \ |
30 "Number of sectors to use for the stateful filesystem" | 30 "Number of sectors to use for the stateful filesystem when minimizing" |
31 # Skips the build steps and just does the kernel swap. | 31 # Skips the build steps and just does the kernel swap. |
32 DEFINE_string kernel_image "" \ | 32 DEFINE_string kernel_image "" \ |
33 "Path to a pre-built recovery kernel" | 33 "Path to a pre-built recovery kernel" |
34 DEFINE_string kernel_outfile "" \ | 34 DEFINE_string kernel_outfile "" \ |
35 "Filename and path to emit the kernel outfile to. \ | 35 "Filename and path to emit the kernel outfile to. \ |
36 If empty, emits to IMAGE_DIR." | 36 If empty, emits to IMAGE_DIR." |
37 DEFINE_string image "" "Path to the image to use" | 37 DEFINE_string image "" "Path to the image to use" |
38 DEFINE_string to "" \ | 38 DEFINE_string to "" \ |
39 "Path to the image to create. If empty, defaults to \ | 39 "Path to the image to create. If empty, defaults to \ |
40 IMAGE_DIR/recovery_image.bin." | 40 IMAGE_DIR/recovery_image.bin." |
41 DEFINE_boolean kernel_image_only $FLAGS_FALSE \ | 41 DEFINE_boolean kernel_image_only $FLAGS_FALSE \ |
42 "Emit the recovery kernel image only" | 42 "Emit the recovery kernel image only" |
43 DEFINE_boolean sync_keys $FLAGS_TRUE \ | 43 DEFINE_boolean sync_keys $FLAGS_TRUE \ |
44 "Update the kernel to be installed with the vblock from stateful" | 44 "Update the kernel to be installed with the vblock from stateful" |
| 45 DEFINE_boolean minimize_image $FLAGS_TRUE \ |
| 46 "Decides if the original image is used or a minimal recovery image is \ |
| 47 created." |
| 48 DEFINE_boolean modify_in_place $FLAGS_FALSE \ |
| 49 "Modifies the source image in place. This cannot be used with \ |
| 50 --minimize_image." |
45 DEFINE_integer jobs -1 \ | 51 DEFINE_integer jobs -1 \ |
46 "How many packages to build in parallel at maximum." j | 52 "How many packages to build in parallel at maximum." j |
47 DEFINE_string build_root "/build" \ | 53 DEFINE_string build_root "/build" \ |
48 "The root location for board sysroots." | 54 "The root location for board sysroots." |
49 | 55 |
50 DEFINE_string rootfs_hash "/tmp/rootfs.hash" \ | 56 DEFINE_string rootfs_hash "/tmp/rootfs.hash" \ |
51 "Path where the rootfs hash should be stored." | 57 "Path where the rootfs hash should be stored." |
52 | 58 |
| 59 DEFINE_boolean verbose $FLAGS_FALSE \ |
| 60 "Log all commands to stdout." v |
| 61 |
53 # Keep in sync with build_image. | 62 # Keep in sync with build_image. |
54 DEFINE_string keys_dir "/usr/share/vboot/devkeys" \ | 63 DEFINE_string keys_dir "/usr/share/vboot/devkeys" \ |
55 "Directory containing the signing keys." | 64 "Directory containing the signing keys." |
56 | 65 |
57 # Parse command line | 66 # Parse command line |
58 FLAGS "$@" || exit 1 | 67 FLAGS "$@" || exit 1 |
59 eval set -- "${FLAGS_ARGV}" | 68 eval set -- "${FLAGS_ARGV}" |
60 | 69 |
| 70 if [ $FLAGS_verbose -eq $FLAGS_FALSE ]; then |
| 71 exec 2>/dev/null |
| 72 # Redirecting to stdout instead of stderr since |
| 73 # we silence stderr above. |
| 74 die() { |
| 75 echo -e "${V_BOLD_RED}ERROR : $1${V_VIDOFF}" |
| 76 exit 1 |
| 77 } |
| 78 fi |
| 79 set -x # Make debugging with -v easy. |
| 80 |
61 EMERGE_CMD="emerge" | 81 EMERGE_CMD="emerge" |
62 EMERGE_BOARD_CMD="emerge-${FLAGS_board}" | 82 EMERGE_BOARD_CMD="emerge-${FLAGS_board}" |
63 | 83 |
64 # No board, no default and no image set then we can't find the image | 84 # No board, no default and no image set then we can't find the image |
65 if [ -z $FLAGS_image ] && [ -z $FLAGS_board ] ; then | 85 if [ -z $FLAGS_image ] && [ -z $FLAGS_board ] ; then |
66 setup_board_warning | 86 setup_board_warning |
67 die "mod_image_for_recovery failed. No board set and no image set" | 87 die "mod_image_for_recovery failed. No board set and no image set" |
68 fi | 88 fi |
69 | 89 |
70 # We have a board name but no image set. Use image at default location | 90 # We have a board name but no image set. Use image at default location |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
171 # chromeos-recovery interfaces are the same. It allows for the signer | 191 # chromeos-recovery interfaces are the same. It allows for the signer |
172 # to just compute the new hash and update the kernel command line during | 192 # to just compute the new hash and update the kernel command line during |
173 # recovery image generation. (Alternately, it means an image can be created, | 193 # recovery image generation. (Alternately, it means an image can be created, |
174 # modified for recovery, then passed to a signer which can then sign both | 194 # modified for recovery, then passed to a signer which can then sign both |
175 # partitions appropriately without needing any external dependencies.) | 195 # partitions appropriately without needing any external dependencies.) |
176 local kern_offset=$(partoffset "$FLAGS_image" 2) | 196 local kern_offset=$(partoffset "$FLAGS_image" 2) |
177 local kern_size=$(partsize "$FLAGS_image" 2) | 197 local kern_size=$(partsize "$FLAGS_image" 2) |
178 local kern_tmp=$(mktemp) | 198 local kern_tmp=$(mktemp) |
179 local kern_hash= | 199 local kern_hash= |
180 | 200 |
181 dd if="$FLAGS_image" bs=512 count=$kern_size skip=$kern_offset of="$kern_tmp" | 201 dd if="$FLAGS_image" bs=512 count=$kern_size \ |
| 202 skip=$kern_offset of="$kern_tmp" 1>&2 |
182 # We're going to use the real signing block. | 203 # We're going to use the real signing block. |
183 if [ $FLAGS_sync_keys -eq $FLAGS_TRUE ]; then | 204 if [ $FLAGS_sync_keys -eq $FLAGS_TRUE ]; then |
184 dd if="$INSTALL_VBLOCK" of="$kern_tmp" conv=notrunc | 205 dd if="$INSTALL_VBLOCK" of="$kern_tmp" conv=notrunc 1>&2 |
185 fi | 206 fi |
186 local kern_hash=$(sha1sum "$kern_tmp" | cut -f1 -d' ') | 207 local kern_hash=$(sha1sum "$kern_tmp" | cut -f1 -d' ') |
187 rm "$kern_tmp" | 208 rm "$kern_tmp" |
188 | 209 |
189 # TODO(wad) add FLAGS_boot_args support too. | 210 # TODO(wad) add FLAGS_boot_args support too. |
190 ${SCRIPTS_DIR}/build_kernel_image.sh \ | 211 ${SCRIPTS_DIR}/build_kernel_image.sh \ |
191 --arch="${ARCH}" \ | 212 --arch="${ARCH}" \ |
192 --to="$RECOVERY_KERNEL_IMAGE" \ | 213 --to="$RECOVERY_KERNEL_IMAGE" \ |
193 --hd_vblock="$RECOVERY_KERNEL_VBLOCK" \ | 214 --hd_vblock="$RECOVERY_KERNEL_VBLOCK" \ |
194 --vmlinuz="$vmlinuz" \ | 215 --vmlinuz="$vmlinuz" \ |
195 --working_dir="${IMAGE_DIR}" \ | 216 --working_dir="${IMAGE_DIR}" \ |
196 --boot_args="panic=60 cros_recovery kern_b_hash=$kern_hash" \ | 217 --boot_args="panic=60 cros_recovery kern_b_hash=$kern_hash" \ |
197 --keep_work \ | 218 --keep_work \ |
198 --rootfs_image=${root_dev} \ | 219 --rootfs_image=${root_dev} \ |
199 --rootfs_hash=${FLAGS_rootfs_hash} \ | 220 --rootfs_hash=${FLAGS_rootfs_hash} \ |
200 --root=${cros_root} \ | 221 --root=${cros_root} \ |
201 --keys_dir="${FLAGS_keys_dir}" \ | 222 --keys_dir="${FLAGS_keys_dir}" \ |
202 --nouse_dev_keys \ | 223 --nouse_dev_keys \ |
203 ${verity_args} | 224 ${verity_args} 1>&2 |
204 sudo rm "$FLAGS_rootfs_hash" | 225 sudo rm "$FLAGS_rootfs_hash" |
205 sudo losetup -d "$root_dev" | 226 sudo losetup -d "$root_dev" |
206 trap - RETURN | 227 trap - RETURN |
207 | 228 |
208 # Update the EFI System Partition configuration so that the kern_hash check | 229 # Update the EFI System Partition configuration so that the kern_hash check |
209 # passes. | 230 # passes. |
210 local efi_dev=$(sudo losetup -f) | 231 local efi_dev=$(sudo losetup -f) |
211 local efi_offset=$(partoffset "$FLAGS_image" 12) | 232 local efi_offset=$(partoffset "$FLAGS_image" 12) |
212 local efi_size=$(partsize "$FLAGS_image" 12) | 233 local efi_size=$(partsize "$FLAGS_image" 12) |
213 | 234 |
(...skipping 15 matching lines...) Expand all Loading... |
229 sudo losetup -d "$efi_dev" | 250 sudo losetup -d "$efi_dev" |
230 rmdir "$efi_dir" | 251 rmdir "$efi_dir" |
231 trap - EXIT | 252 trap - EXIT |
232 } | 253 } |
233 | 254 |
234 install_recovery_kernel() { | 255 install_recovery_kernel() { |
235 local kern_a_offset=$(partoffset "$RECOVERY_IMAGE" 2) | 256 local kern_a_offset=$(partoffset "$RECOVERY_IMAGE" 2) |
236 local kern_a_size=$(partsize "$RECOVERY_IMAGE" 2) | 257 local kern_a_size=$(partsize "$RECOVERY_IMAGE" 2) |
237 local kern_b_offset=$(partoffset "$RECOVERY_IMAGE" 4) | 258 local kern_b_offset=$(partoffset "$RECOVERY_IMAGE" 4) |
238 local kern_b_size=$(partsize "$RECOVERY_IMAGE" 4) | 259 local kern_b_size=$(partsize "$RECOVERY_IMAGE" 4) |
| 260 |
| 261 if [ $kern_b_size -eq 1 ]; then |
| 262 echo "Image was created with no KERN-B partition reserved!" 1>&2 |
| 263 echo "Cannot proceed." 1>&2 |
| 264 return 1 |
| 265 fi |
| 266 |
239 # Backup original kernel to KERN-B | 267 # Backup original kernel to KERN-B |
240 dd if="$RECOVERY_IMAGE" of="$RECOVERY_IMAGE" bs=512 \ | 268 dd if="$RECOVERY_IMAGE" of="$RECOVERY_IMAGE" bs=512 \ |
241 count=$kern_a_size \ | 269 count=$kern_a_size \ |
242 skip=$kern_a_offset \ | 270 skip=$kern_a_offset \ |
243 seek=$kern_b_offset \ | 271 seek=$kern_b_offset \ |
244 conv=notrunc | 272 conv=notrunc |
245 | 273 |
246 # We're going to use the real signing block. | 274 # We're going to use the real signing block. |
247 if [ $FLAGS_sync_keys -eq $FLAGS_TRUE ]; then | 275 if [ $FLAGS_sync_keys -eq $FLAGS_TRUE ]; then |
248 dd if="$INSTALL_VBLOCK" of="$RECOVERY_IMAGE" bs=512 \ | 276 dd if="$INSTALL_VBLOCK" of="$RECOVERY_IMAGE" bs=512 \ |
(...skipping 21 matching lines...) Expand all Loading... |
270 rmdir "$esp_mnt" | 298 rmdir "$esp_mnt" |
271 set -e | 299 set -e |
272 if [ $failed -eq 1 ]; then | 300 if [ $failed -eq 1 ]; then |
273 echo "Failed to copy recovery kernel to ESP" | 301 echo "Failed to copy recovery kernel to ESP" |
274 return 1 | 302 return 1 |
275 fi | 303 fi |
276 return 0 | 304 return 0 |
277 } | 305 } |
278 | 306 |
279 maybe_resize_stateful() { | 307 maybe_resize_stateful() { |
| 308 # If we're not minimizing, then just copy and go. |
| 309 if [ $FLAGS_minimize_image -eq $FLAGS_FALSE ]; then |
| 310 if [ "$FLAGS_image" != "$RECOVERY_IMAGE" ]; then |
| 311 cp "$FLAGS_image" "$RECOVERY_IMAGE" |
| 312 fi |
| 313 return 0 |
| 314 fi |
| 315 |
280 # Rebuild the image with a 1 sector stateful partition | 316 # Rebuild the image with a 1 sector stateful partition |
281 local err=0 | 317 local err=0 |
282 local small_stateful=$(mktemp) | 318 local small_stateful=$(mktemp) |
283 dd if=/dev/zero of="$small_stateful" bs=512 \ | 319 dd if=/dev/zero of="$small_stateful" bs=512 \ |
284 count=${FLAGS_statefulfs_sectors} | 320 count=${FLAGS_statefulfs_sectors} 1>&2 |
285 trap "rm $small_stateful" RETURN | 321 trap "rm $small_stateful" RETURN |
286 # Don't bother with ext3 for such a small image. | 322 # Don't bother with ext3 for such a small image. |
287 /sbin/mkfs.ext2 -F -b 4096 "$small_stateful" | 323 /sbin/mkfs.ext2 -F -b 4096 "$small_stateful" 1>&2 |
288 | 324 |
289 # If it exists, we need to copy the vblock over to stateful | 325 # If it exists, we need to copy the vblock over to stateful |
290 # This is the real vblock and not the recovery vblock. | 326 # This is the real vblock and not the recovery vblock. |
291 local new_stateful_mnt=$(mktemp -d) | 327 local new_stateful_mnt=$(mktemp -d) |
292 | 328 |
293 set +e | 329 set +e |
294 sudo mount -o loop $small_stateful $new_stateful_mnt | 330 sudo mount -o loop $small_stateful $new_stateful_mnt |
295 sudo cp "$INSTALL_VBLOCK" "$new_stateful_mnt/vmlinuz_hd.vblock" | 331 sudo cp "$INSTALL_VBLOCK" "$new_stateful_mnt/vmlinuz_hd.vblock" |
296 sudo mkdir "$new_stateful_mnt/var" | 332 sudo mkdir "$new_stateful_mnt/var" |
297 sudo umount -d "$new_stateful_mnt" | 333 sudo umount -d "$new_stateful_mnt" |
298 rmdir "$new_stateful_mnt" | 334 rmdir "$new_stateful_mnt" |
299 set -e | 335 set -e |
300 | 336 |
301 # Create a recovery image of the right size | 337 # Create a recovery image of the right size |
302 # TODO(wad) Make the developer script case create a custom GPT with | 338 # TODO(wad) Make the developer script case create a custom GPT with |
303 # just the kernel image and stateful. | 339 # just the kernel image and stateful. |
304 update_partition_table "$FLAGS_image" "$small_stateful" 4096 "$RECOVERY_IMAGE" | 340 update_partition_table "$FLAGS_image" "$small_stateful" 4096 \ |
| 341 "$RECOVERY_IMAGE" 1>&2 |
305 return $err | 342 return $err |
306 } | 343 } |
307 | 344 |
| 345 cleanup() { |
| 346 set +e |
| 347 if [ "$FLAGS_image" != "$RECOVERY_IMAGE" ]; then |
| 348 rm "$RECOVERY_IMAGE" |
| 349 fi |
| 350 rm "$INSTALL_VBLOCK" |
| 351 } |
| 352 |
308 # main process begins here. | 353 # main process begins here. |
309 | 354 |
310 # Make sure this is really what the user wants, before nuking the device | |
311 echo "Creating recovery image ${FLAGS_to} from ${FLAGS_image} . . . " | |
312 | |
313 set -e | 355 set -e |
314 set -u | 356 set -u |
315 | 357 |
316 IMAGE_DIR="$(dirname "$FLAGS_image")" | 358 IMAGE_DIR="$(dirname "$FLAGS_image")" |
317 IMAGE_NAME="$(basename "$FLAGS_image")" | 359 IMAGE_NAME="$(basename "$FLAGS_image")" |
318 RECOVERY_IMAGE="${FLAGS_to:-$IMAGE_DIR/recovery_image.bin}" | 360 RECOVERY_IMAGE="${FLAGS_to:-$IMAGE_DIR/recovery_image.bin}" |
319 RECOVERY_KERNEL_IMAGE=\ | 361 RECOVERY_KERNEL_IMAGE=\ |
320 "${FLAGS_kernel_outfile:-${IMAGE_DIR}/recovery_vmlinuz.image}" | 362 "${FLAGS_kernel_outfile:-${IMAGE_DIR}/recovery_vmlinuz.image}" |
321 RECOVERY_KERNEL_VBLOCK="${RECOVERY_KERNEL_IMAGE}.vblock" | 363 RECOVERY_KERNEL_VBLOCK="${RECOVERY_KERNEL_IMAGE}.vblock" |
322 STATEFUL_DIR="$IMAGE_DIR/stateful_partition" | 364 STATEFUL_DIR="$IMAGE_DIR/stateful_partition" |
323 SCRIPTS_DIR=$(dirname "$0") | 365 SCRIPTS_DIR=$(dirname "$0") |
324 | 366 |
325 # Mounts gpt image and sets up var, /usr/local and symlinks. | 367 # Mounts gpt image and sets up var, /usr/local and symlinks. |
326 # If there's a dev payload, mount stateful | 368 # If there's a dev payload, mount stateful |
327 # offset=$(partoffset "${FLAGS_from}/${filename}" 1) | 369 # offset=$(partoffset "${FLAGS_from}/${filename}" 1) |
328 # sudo mount ${ro_flag} -o loop,offset=$(( offset * 512 )) \ | 370 # sudo mount ${ro_flag} -o loop,offset=$(( offset * 512 )) \ |
329 # "${FLAGS_from}/${filename}" "${FLAGS_stateful_mountpt}" | 371 # "${FLAGS_from}/${filename}" "${FLAGS_stateful_mountpt}" |
330 # If not, resize stateful to 1 sector. | 372 # If not, resize stateful to 1 sector. |
331 # | 373 # |
332 | 374 |
333 if [ $FLAGS_kernel_image_only -eq $FLAGS_TRUE -a \ | 375 if [ $FLAGS_kernel_image_only -eq $FLAGS_TRUE -a \ |
334 -n "$FLAGS_kernel_image" ]; then | 376 -n "$FLAGS_kernel_image" ]; then |
335 die "Cannot use --kernel_image_only with --kernel_image" | 377 die "Cannot use --kernel_image_only with --kernel_image" |
336 fi | 378 fi |
337 | 379 |
| 380 if [ $FLAGS_modify_in_place -eq $FLAGS_TRUE ]; then |
| 381 if [ $FLAGS_minimize_image -eq $FLAGS_TRUE ]; then |
| 382 die "Cannot use --modify_in_place and --minimize_image together." |
| 383 fi |
| 384 RECOVERY_IMAGE="${FLAGS_image}" |
| 385 fi |
| 386 |
| 387 echo "Creating recovery image from ${FLAGS_image}" |
| 388 |
338 INSTALL_VBLOCK=$(get_install_vblock) | 389 INSTALL_VBLOCK=$(get_install_vblock) |
339 if [ -z "$INSTALL_VBLOCK" ]; then | 390 if [ -z "$INSTALL_VBLOCK" ]; then |
340 die "Could not copy the vblock from stateful." | 391 die "Could not copy the vblock from stateful." |
341 fi | 392 fi |
342 | 393 |
343 if [ -z "$FLAGS_kernel_image" ]; then | 394 if [ -z "$FLAGS_kernel_image" ]; then |
344 emerge_recovery_kernel | 395 emerge_recovery_kernel |
345 create_recovery_kernel_image | 396 create_recovery_kernel_image |
| 397 echo "Recovery kernel created at $RECOVERY_KERNEL_IMAGE" |
346 else | 398 else |
347 RECOVERY_KERNEL_IMAGE="$FLAGS_kernel_image" | 399 RECOVERY_KERNEL_IMAGE="$FLAGS_kernel_image" |
348 fi | 400 fi |
349 echo "Kernel emitted: $RECOVERY_KERNEL_IMAGE." | |
350 | 401 |
351 if [ $FLAGS_kernel_image_only -eq $FLAGS_TRUE ]; then | 402 if [ $FLAGS_kernel_image_only -eq $FLAGS_TRUE ]; then |
352 echo "Kernel emitted. Stopping there." | 403 echo "Kernel emitted. Stopping there." |
353 rm "$INSTALL_VBLOCK" | 404 rm "$INSTALL_VBLOCK" |
354 exit 0 | 405 exit 0 |
355 fi | 406 fi |
356 | 407 |
357 rm "$RECOVERY_IMAGE" || true # Start fresh :) | 408 if [ $FLAGS_modify_in_place -eq $FLAGS_FALSE ]; then |
| 409 rm "$RECOVERY_IMAGE" || true # Start fresh :) |
| 410 fi |
358 | 411 |
359 trap "rm \"$RECOVERY_IMAGE\" && rm \"$INSTALL_VBLOCK\"" EXIT | 412 trap cleanup EXIT |
360 | 413 |
361 maybe_resize_stateful # Also copies the image | 414 maybe_resize_stateful # Also copies the image if needed. |
362 | 415 |
363 install_recovery_kernel | 416 install_recovery_kernel |
364 | 417 |
| 418 echo "Recovery image created at $RECOVERY_IMAGE" |
365 print_time_elapsed | 419 print_time_elapsed |
366 trap - EXIT | 420 trap - EXIT |
OLD | NEW |