blob: 836d83f539244965f2dc25880ec98e1233cd89e3 [file] [log] [blame]
#!/bin/bash
# Copyright (c) 2012 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.
# This grows a signed recovery image's stateful partition to
# --statefulfs_sectors, and adds the decryption flag file. It is designed
# to be run from outside of the chroot.
SCRIPT_ROOT=/usr/lib/crosutils
. "${SCRIPT_ROOT}/common.sh" || exit 1
. /usr/lib/installer/chromeos-common.sh || exit 1
locate_gpt
assert_inside_chroot
# Default to 3GB stateful for decryption. 2097152 is 1GB.
DEFINE_integer statefulfs_sectors 6291456 \
"number of sectors in stateful filesystem when growing"
DEFINE_string image "" \
"source image to use (${CHROMEOS_IMAGE_NAME} if empty)"
DEFINE_string to "" \
"emit recovery image to path/file (${CHROMEOS_RECOVERY_IMAGE_NAME} if empty)"
DEFINE_boolean verbose ${FLAGS_FALSE} \
"log all commands to stdout" v
# Parse command line
FLAGS "$@" || exit 1
eval set -- "${FLAGS_ARGV}"
# Only now can we die on error. shflags functions leak non-zero error codes,
# so will die prematurely if 'switch_to_strict_mode' is specified before now.
switch_to_strict_mode
if [[ ${FLAGS_verbose} -eq ${FLAGS_TRUE} ]]; then
# Make debugging with -v easy.
set -x
fi
#TODO: this function be moved into a common library (perhaps along
# with the gpt functions?)
update_partition_table() {
local src_img=$1 # source image
local temp_state=$2 # stateful partition image
local resized_sectors=$3 # number of sectors in resized stateful partition
local temp_img=$4
local kern_a_offset=$(partoffset ${src_img} 2)
local kern_a_count=$(partsize ${src_img} 2)
local kern_b_offset=$(partoffset ${src_img} 4)
local kern_b_count=$(partsize ${src_img} 4)
local rootfs_offset=$(partoffset ${src_img} 3)
local rootfs_count=$(partsize ${src_img} 3)
local oem_offset=$(partoffset ${src_img} 8)
local oem_count=$(partsize ${src_img} 8)
local esp_offset=$(partoffset ${src_img} 12)
local esp_count=$(partsize ${src_img} 12)
local temp_pmbr=$(mktemp -t pmbr.XXXXXX)
dd if="${src_img}" of="${temp_pmbr}" bs=512 count=1 &>/dev/null
trap "rm -rf '${temp_pmbr}'" EXIT
# Set up a new partition table
install_gpt "${temp_img}" "${rootfs_count}" "${resized_sectors}" \
"${temp_pmbr}" "${esp_count}" false \
$(((rootfs_count * 512)/(1024 * 1024)))
# Copy into the partition parts of the file
dd if="${src_img}" of="${temp_img}" conv=notrunc bs=512 \
seek="${START_ROOTFS_A}" skip=${rootfs_offset} count=${rootfs_count}
dd if="${temp_state}" of="${temp_img}" conv=notrunc bs=512 \
seek="${START_STATEFUL}"
# Copy the full kernel (i.e. with vboot sections)
dd if="${src_img}" of="${temp_img}" conv=notrunc bs=512 \
seek="${START_KERN_A}" skip=${kern_a_offset} count=${kern_a_count}
dd if="${src_img}" of="${temp_img}" conv=notrunc bs=512 \
seek="${START_KERN_B}" skip=${kern_b_offset} count=${kern_b_count}
dd if="${src_img}" of="${temp_img}" conv=notrunc bs=512 \
seek="${START_OEM}" skip=${oem_offset} count=${oem_count}
dd if="${src_img}" of="${temp_img}" conv=notrunc bs=512 \
seek="${START_ESP}" skip=${esp_offset} count=${esp_count}
}
resize_stateful() {
# Rebuild the image with larger stateful.
local err=0
local large_stateful=$(mktemp)
truncate --size $(( $FLAGS_statefulfs_sectors * 512 )) "${large_stateful}"
trap "rm ${large_stateful}" RETURN
/sbin/mkfs.ext4 -F -b 4096 "${large_stateful}" 1>&2
# Create a recovery image of the right size
# TODO(wad) Make the developer script case create a custom GPT with
# just the kernel image and stateful.
update_partition_table "${FLAGS_image}" "${large_stateful}" \
"${FLAGS_statefulfs_sectors}" "${RECOVERY_IMAGE}" 1>&2
return $err
}
install_decryption_flag() {
stateful_mnt=$(mktemp -d)
offset=$(partoffset "${RECOVERY_IMAGE}" 1)
sudo mount -o loop,offset=$(( offset * 512 )) \
"${RECOVERY_IMAGE}" "${stateful_mnt}"
echo -n "1" | sudo_clobber "${stateful_mnt}"/decrypt_stateful >/dev/null
sudo umount "${stateful_mnt}"
rmdir "${stateful_mnt}"
}
cleanup() {
set +e
if [[ "${FLAGS_image}" != "${RECOVERY_IMAGE}" ]]; then
rm "${RECOVERY_IMAGE}"
fi
}
# Main process begins here.
set -u
# No image was provided, use standard latest image path.
if [[ -z "${FLAGS_image}" ]]; then
echo "--image required" >&2
exit 1
fi
# Abort early if we can't find the image.
if [[ ! -f "${FLAGS_image}" ]]; then
die_notrace "Image not found: ${FLAGS_image}"
fi
# Turn path into an absolute path.
FLAGS_image=$(readlink -f "${FLAGS_image}")
IMAGE_DIR="$(dirname "${FLAGS_image}")"
IMAGE_NAME="$(basename "${FLAGS_image}")"
RECOVERY_IMAGE="${FLAGS_to:-$IMAGE_DIR/$CHROMEOS_RECOVERY_IMAGE_NAME}"
STATEFUL_DIR="${IMAGE_DIR}/stateful_partition"
echo "Creating decryption recovery image from ${FLAGS_image}"
trap cleanup EXIT
resize_stateful
install_decryption_flag
okboat
echo "Decryption recovery image created at ${RECOVERY_IMAGE}"
print_time_elapsed
trap - EXIT