| #!/bin/sh |
| # |
| # Copyright (c) 2011 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| # Script to generate an universal factory install shim image, by merging |
| # multiple images signed by different keys. |
| # CAUTION: Recovery shim images are not supported yet because they require the |
| # kernel partitions to be laid out in a special way |
| |
| SCRIPT="$0" |
| set -e |
| |
| # CGPT Header: PMBR, header, table; sec_table, sec_header |
| CGPT_START_SIZE=$((1 + 1 + 32)) |
| CGPT_END_SIZE=$((32 + 1)) |
| CGPT_BS="512" |
| |
| STATE_PARTITION="1" |
| LEGACY_PARTITIONS="8 9 10 11 12" |
| RESERVED_PARTITION="9" |
| |
| die() { |
| echo "ERROR: $*" >&2 |
| exit 1 |
| } |
| |
| # TODO(hungte) support parted if cgpt is not available |
| image_get_partition_offset() { |
| cgpt show -n -i "$2" -b "$1" |
| } |
| |
| image_get_partition_size() { |
| cgpt show -n -i "$2" -s "$1" |
| } |
| |
| image_get_partition_type() { |
| cgpt show -n -i "$2" -t "$1" |
| } |
| |
| image_get_partition_label() { |
| cgpt show -n -i "$2" -l "$1" |
| } |
| |
| image_enable_kernel() { |
| cgpt add -P 1 -S 1 -i "$2" "$1" |
| } |
| |
| image_copy_partition() { |
| local from_image="$1" |
| local from_part="$2" |
| local to_image="$3" |
| local to_part="$4" |
| |
| local from_offset="$(image_get_partition_offset "$from_image" "$from_part")" |
| local from_size="$(image_get_partition_size "$from_image" "$from_part")" |
| local to_offset="$(image_get_partition_offset "$to_image" "$to_part")" |
| local to_size="$(image_get_partition_size "$to_image" "$to_part")" |
| |
| if [ "$from_size" -ne "$to_size" ]; then |
| die "Failed to copy partition: $from_image#$from_part -> $to_image#$to_part" |
| fi |
| |
| # TODO(hungte) Speed up by increasing bs |
| dd if="$from_image" of="$to_image" bs="$CGPT_BS" conv=notrunc \ |
| count=$from_size skip="$from_offset" seek="$to_offset" |
| } |
| |
| images_get_total_size() { |
| local image="" |
| local total="0" |
| local index |
| |
| # copy most partitions from first image |
| total="$((total + CGPT_START_SIZE + CGPT_END_SIZE))" |
| for index in $STATE_PARTITION $LEGACY_PARTITIONS; do |
| total="$((total + $(image_get_partition_size "$1" $index) ))" |
| done |
| |
| for image in "$1" "$2" "$3"; do |
| if [ -z "$image" ]; then |
| total="$((total + $(image_get_partition_size "$1" $RESERVED_PARTITION)))" |
| total="$((total + $(image_get_partition_size "$1" $RESERVED_PARTITION)))" |
| continue |
| fi |
| total="$((total + $(image_get_partition_size "$image" 2)))" |
| total="$((total + $(image_get_partition_size "$image" 3)))" |
| done |
| echo "$total" |
| } |
| |
| image_append_partition() { |
| local from_image="$1" |
| local to_image="$2" |
| local from_part="$3" |
| local last_part="$(cgpt show "$to_image" | grep Label | wc -l)" |
| local to_part="$((last_part + 1))" |
| echo "image_append_partition: $from_image#$from_part -> $to_image#$to_part" |
| |
| local guid="$(image_get_partition_type "$from_image" "$from_part")" |
| local size="$(image_get_partition_size "$from_image" "$from_part")" |
| local label="$(image_get_partition_label "$from_image" "$from_part")" |
| local offset="$CGPT_START_SIZE" |
| |
| if [ "$last_part" -gt 0 ]; then |
| offset="$(( $(image_get_partition_offset "$to_image" "$last_part") + |
| $(image_get_partition_size "$to_image" "$last_part") ))" |
| fi |
| |
| echo cgpt add "$to_image" -t "$guid" -b "$offset" -s "$size" -l "$label" |
| cgpt add "$to_image" -t "$guid" -b "$offset" -s "$size" -l "$label" |
| image_copy_partition "$from_image" "$from_part" "$to_image" "$to_part" |
| } |
| |
| main() { |
| local force="" |
| if [ "$1" = "-f" ]; then |
| shift |
| force="True" |
| fi |
| if [ "$#" -lt 2 -o "$#" -gt 4 ]; then |
| echo "Usage: $SCRIPT [-f] output shim_image_1 [shim_2 [shim_3]]" |
| exit 1 |
| fi |
| |
| local image="" |
| local output="$1" |
| local main_source="$2" |
| local index="" |
| local slots="0" |
| shift |
| |
| if [ -f "$output" -a -z "$force" ]; then |
| die "Output file $output already exists. To overwrite the file, add -f." |
| fi |
| for image in "$@"; do |
| if [ ! -f "$image" ]; then |
| die "Cannot find input file $image." |
| fi |
| done |
| |
| # build output |
| local total_size="$(images_get_total_size "$@")" |
| # echo "Total size from [$@]: $total_size" |
| truncate "$output" -s "$((total_size * CGPT_BS))" |
| cgpt create "$output" |
| cgpt boot -p "$output" |
| |
| # copy most partitions from first image |
| image_append_partition "$main_source" "$output" $STATE_PARTITION |
| local kpart=2 |
| local rootfs_part=3 |
| for image in "$1" "$2" "$3"; do |
| if [ -z "$image" ]; then |
| image="$1" |
| kpart="$RESERVED_PARTITION" |
| rootfs_part="$RESERVED_PARTITION" |
| fi |
| image_append_partition "$image" "$output" "$kpart" |
| image_append_partition "$image" "$output" "$rootfs_part" |
| slots="$((slots + 1))" |
| image_enable_kernel "$output" "$((slots * 2))" |
| done |
| for index in $LEGACY_PARTITIONS; do |
| image_append_partition "$main_source" "$output" "$index" |
| done |
| } |
| |
| main "$@" |