blob: 737135879ec268ef4518e214b1f1349042c56b32 [file] [log] [blame]
#!/bin/sh
# Copyright 2015 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 merge multiple USB installation disk images.
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
. "$SCRIPT_DIR/factory_common.sh" || exit 1
# Temp file to store image resources.
RESOURCE_FILE="$(mktemp)"
alert() {
echo "$*" >&2
}
die() {
alert "ERROR: $*"
exit 1
}
check_output_on_exit() {
local output_file="$1"
if [ ! -f "$output_file" ]; then
alert "Failed to generate the output file: $output_file."
alert "This may be related to not enough space left on /tmp."
alert "Please try to specify TMPDIR to another location."
alert "For example, TMPDIR=/some/other/dir $0"
fi
on_exit
}
on_exit() {
rm -f "$RESOURCE_FILE"
image_clean_temp
}
usage_die() {
alert "Usage: $SCRIPT [-f] output usbimg1 [usbimg2 usbimg3 ...]"
exit 1
}
# Clones the partition GPT info (type, attr, label).
clone_partition_type() {
local input_file="$1" input_part="$2" output_file="$3" output_part="$4"
local part_type="$(cgpt show -q -n -t -i "$input_part" "$input_file")"
local part_attr="$(cgpt show -q -n -A -i "$input_part" "$input_file")"
local part_label="$(cgpt show -q -n -l -i "$input_part" "$input_file")"
cgpt add -t "${part_type}" -l "${part_label}" -A "${part_attr}" \
-i "${output_part}" "${output_file}"
}
# Merge multiple USB installation disk images.
#
# The usbimg should have factory_install kernel and rootfs in (2, 3) and
# resources in stateful partition cros_payloads.
# This function extracts merges all stateful partitions and invoke
# make_universal_factory_shim.sh to generate the output image by merging the
# resource file to partition 1 and merging partition 2/3 of each input image.
#
# The layout of the merged output image:
# --------------------------------
# 1 stateful [cros_payloads from all usbimgX]
# 2 kernel [install-usbimg1]
# 3 rootfs [install-usbimg1]
# 4 kernel [install-usbimg2]
# 5 rootfs [install-usbimg2]
# 6 kernel [install-usbimg3]
# 7 rootfs [install-usbimg3]
# ...
# --------------------------------
merge_images() {
local output_file="$1"
local image
local pygpt="${SCRIPT_DIR}/pygpt"
shift
# Basically the output file should be sized in sum of all input files.
info "Scanning input files..."
local sectors_list=""
local new_sectors=0
for image_file in "$@"; do
: $((new_sectors += $("${pygpt}" show -i 1 -s "${image_file}") ))
sectors_list="${sectors_list} $("${pygpt}" show -i 2 -s "${image_file}")"
sectors_list="${sectors_list} $("${pygpt}" show -i 3 -s "${image_file}")"
done
# Put new stateful partition in first (partition 1).
sectors_list="${new_sectors} ${sectors_list}"
image_geometry_build_file "${sectors_list}" "${output_file}"
local new_size="$(stat --format="%s" "${output_file}")"
info "Creating new image file in $((new_size / 1048576))M..."
# Clone and resize stateful partition.
clone_partition_type "$1" 1 "${output_file}" 1
image_partition_overwrite "${image_file}" "1" "${output_file}" "1"
local state_dev="$(image_map_partition "${output_file}" 1)"
sudo e2fsck -f "${state_dev}"
sudo resize2fs "${state_dev}"
image_unmap_partition "${state_dev}"
# Clone root and kernel partitions
local index=2
for image_file in "$@"; do
info "Copying kernel and rootfs from ${image_file}..."
clone_partition_type "${image_file}" "2" "${output_file}" "${index}"
image_partition_copy "${image_file}" "2" "${output_file}" "${index}"
: $((index += 1))
clone_partition_type "${image_file}" "3" "${output_file}" "${index}"
image_partition_copy "${image_file}" "3" "${output_file}" "${index}"
: $((index += 1))
done
local all_payloads="$(mktemp -d)" stateful="$(mktemp -d)"
image_add_temp "${all_payloads}"
image_add_temp "${stateful}"
image_mount_partition "${output_file}" 1 "${all_payloads}" "rw"
sudo mkdir -p "${all_payloads}/cros_payloads"
# This must be the last loop on $@.
# $@ is changed since here because stateful partition in first image is
# already copied.
shift
for image_file in "$@"; do
info "Collecting RMA payloads from ${image_file}..."
image_mount_partition "${image_file}" 1 "${stateful}" "ro"
sudo cp -pr "${stateful}"/cros_payloads/* "${all_payloads}/cros_payloads/."
image_umount_partition "${stateful}"
done
image_umount_partition "${all_payloads}"
info "Merged new image created successfully: ${output_file}."
}
main() {
local force=""
local output=""
umask 022
while [ "$#" -gt 1 ]; do
case "$1" in
"-f" )
force="True"
shift
;;
* )
break
esac
done
if [ "$#" -lt 2 ]; then
alert "ERROR: invalid number of parameters ($#)."
usage_die
fi
output="$1"
shift
if [ -f "$output" -a -z "$force" ]; then
die "Output file $output already exists. To overwrite the file, add -f."
fi
[ -z "$force" ] || rm -f "$output"
# Reset trap here to check whether output file is generated or not.
# Use double quote to expand the local variable ${output} now.
# shellcheck disable=SC2064
trap "check_output_on_exit ${output}" EXIT
merge_images "$output" "$@"
}
set -e
trap on_exit EXIT
main "$@"