mirror of
https://github.com/flatcar/scripts.git
synced 2025-09-23 22:51:03 +02:00
mod_image_for_recovery: supprt new recovery model
With a change for chromeos-installer and http://codereview.chromium.org/4120005, switched to a kernel image based approach. BUG=chromium-os:7451 TEST= See http://codereview.chromium.org/4120005 Review URL: http://codereview.chromium.org/4107003 Change-Id: I84ac794dae652578682c04fdfdbfaa3f0c5c8b33
This commit is contained in:
parent
b4b09d40a7
commit
53320366b5
122
make_developer_script_runner.sh
Executable file
122
make_developer_script_runner.sh
Executable file
@ -0,0 +1,122 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright (c) 2010 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 script modifies a base image to act as a recovery installer.
|
||||
# If a developer payload is supplied, it will be used.
|
||||
# It is very straight forward, top to bottom to show clearly what is
|
||||
# little is needed to create a developer shim to run a signed script.
|
||||
|
||||
# Load common constants. This should be the first executable line.
|
||||
# The path to common.sh should be relative to your script's location.
|
||||
. "$(dirname "$0")/common.sh"
|
||||
|
||||
# Load functions and constants for chromeos-install
|
||||
. "$(dirname "$0")/chromeos-common.sh"
|
||||
|
||||
DEFINE_integer statefulfs_size 2 \
|
||||
"Number of mebibytes to use for the stateful filesystem"
|
||||
DEFINE_string developer_private_key \
|
||||
"/usr/share/vboot/devkeys/kernel_data_key.vbprivk" \
|
||||
"Path to the developer's private key"
|
||||
DEFINE_string developer_keyblock \
|
||||
"/usr/share/vboot/devkeys/kernel.keyblock" \
|
||||
"Path to the developer's keyblock"
|
||||
DEFINE_string developer_script "" \
|
||||
"Path to the developer script if desired."
|
||||
# TODO(wad) wire up support for just swapping a pre-made kernel
|
||||
# Skips the build steps and just does the kernel swap.
|
||||
DEFINE_string kernel_image "" \
|
||||
"Path to a pre-built recovery kernel"
|
||||
DEFINE_boolean verbose $FLAGS_FALSE \
|
||||
"Emits stderr too" v
|
||||
DEFINE_string image "dev_runner_image.bin" \
|
||||
"Path to output image to"
|
||||
|
||||
# Parse command line
|
||||
FLAGS "$@" || exit 1
|
||||
eval set -- "${FLAGS_ARGV}"
|
||||
|
||||
if [ $FLAGS_verbose -eq $FLAGS_FALSE ]; then
|
||||
exec 2>/dev/null
|
||||
fi
|
||||
set -x # Make debugging with -v easy.
|
||||
|
||||
if [ -z "$FLAGS_kernel_image" ]; then
|
||||
die "--kernel_image with a recovery kernel is needed"
|
||||
fi
|
||||
|
||||
if [ -z "$FLAGS_developer_script" ]; then
|
||||
die "--developer_script must be supplied."
|
||||
fi
|
||||
|
||||
locate_gpt
|
||||
|
||||
set -eu
|
||||
|
||||
header_offset=34
|
||||
stateful_sectors=$(((FLAGS_statefulfs_size * 1024 * 1024) / 512))
|
||||
stateful_sectors=$(roundup $stateful_sectors)
|
||||
|
||||
if [ -b "$FLAGS_image" ]; then
|
||||
sudo=sudo
|
||||
else
|
||||
max_kern_size=32768
|
||||
dd if=/dev/zero of="${FLAGS_image}" bs=512 count=0 \
|
||||
seek=$((1 + max_kern_size + header_offset + stateful_sectors))
|
||||
sudo=""
|
||||
fi
|
||||
|
||||
## STATEFUL
|
||||
|
||||
stateful_image=$(mktemp)
|
||||
trap "rm $stateful_image" EXIT
|
||||
|
||||
dd if=/dev/zero of="$stateful_image" bs=512 \
|
||||
seek=$stateful_sectors count=0
|
||||
/sbin/mkfs.ext3 -F -b 4096 $stateful_image 1>&2
|
||||
|
||||
stateful_mnt=$(mktemp -d)
|
||||
sudo mount -o loop $stateful_image "$stateful_mnt" || exit 1
|
||||
userdir="$stateful_mnt/userdir"
|
||||
userfile="$userdir/runme"
|
||||
sudo mkdir -p "$userdir"
|
||||
sudo cp "$FLAGS_developer_script" "$userfile"
|
||||
sudo chmod +x "$userfile"
|
||||
sudo dev_sign_file --sign "$userfile" \
|
||||
--keyblock "$FLAGS_developer_keyblock" \
|
||||
--signprivate "$FLAGS_developer_private_key" \
|
||||
--vblock "${userfile}.vblock"
|
||||
sudo umount -d "$stateful_mnt"
|
||||
rmdir "$stateful_mnt"
|
||||
|
||||
## GPT
|
||||
|
||||
kernel_bytes=$(stat -c '%s' $FLAGS_kernel_image)
|
||||
kernel_sectors=$((kernel_bytes / 512))
|
||||
kernel_sectors=$(roundup $kernel_sectors)
|
||||
|
||||
$sudo $GPT create $FLAGS_image
|
||||
trap "rm $FLAGS_image" ERR
|
||||
|
||||
offset=$header_offset
|
||||
$sudo $GPT add -b $offset -s $stateful_sectors \
|
||||
-t data -l "STATE" $FLAGS_image
|
||||
$sudo dd if=$stateful_image of=$FLAGS_image bs=512 conv=notrunc \
|
||||
seek=$offset count=$stateful_sectors
|
||||
|
||||
offset=$((offset + stateful_sectors))
|
||||
$sudo $GPT add -b $offset -s $kernel_sectors \
|
||||
-t kernel -l "KERN-A" -S 0 -T 15 -P 15 $FLAGS_image
|
||||
$sudo dd if=$FLAGS_kernel_image of=$FLAGS_image bs=512 conv=notrunc \
|
||||
seek=$offset count=$kernel_sectors
|
||||
# The kernel will ignore GPT without a legacymbr.
|
||||
PMBRCODE=$(readlink -f /usr/share/syslinux/gptmbr.bin)
|
||||
# Have it legacy boot off of stateful, not that it should matter.
|
||||
$sudo $GPT boot -p -b "$PMBRCODE" -i 1 $FLAGS_image 1>&2
|
||||
|
||||
$sudo $GPT show $FLAGS_image
|
||||
|
||||
echo "Done."
|
@ -1,120 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright (c) 2010 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 create a Chrome OS dev recovery image using a dev install shim
|
||||
|
||||
# Source constants and utility functions
|
||||
. "$(dirname "$0")/resize_stateful_partition.sh"
|
||||
|
||||
get_default_board
|
||||
|
||||
# Constants
|
||||
TEMP_IMG=$(mktemp "/tmp/temp_img.XXXXXX")
|
||||
|
||||
DEFINE_string board "$DEFAULT_BOARD" "Board for which the image was built \
|
||||
Default: ${DEFAULT_BOARD}"
|
||||
DEFINE_string dev_install_shim "" "Path of the developer install shim. \
|
||||
Default: (empty)"
|
||||
DEFINE_string payload_dir "" "Directory containing developer payload and \
|
||||
(optionally) a custom install script. Default: (empty)"
|
||||
|
||||
# Parse command line
|
||||
FLAGS "$@" || exit 1
|
||||
eval set -- "${FLAGS_ARGV}"
|
||||
|
||||
set -e
|
||||
|
||||
# No board set and no default set then we can't proceed
|
||||
if [ -z $FLAGS_board ] ; then
|
||||
setup_board_warning
|
||||
die "No board set"
|
||||
fi
|
||||
|
||||
# Abort early if --payload_dir is not set, invalid or empty
|
||||
if [ -z $FLAGS_payload_dir ] ; then
|
||||
die "flag --payload_dir not set"
|
||||
fi
|
||||
|
||||
if [ ! -d "${FLAGS_payload_dir}" ] ; then
|
||||
die "${FLAGS_payload_dir} is not a directory"
|
||||
fi
|
||||
|
||||
PAYLOAD_DIR_SIZE=
|
||||
if [ -z "$(ls -A $FLAGS_payload_dir)" ] ; then
|
||||
die "${FLAGS_payload_dir} is empty"
|
||||
else
|
||||
# Get directory size in 512-byte sectors so we can resize stateful partition
|
||||
PAYLOAD_DIR_SIZE=\
|
||||
"$(du --apparent-size -B 512 ${FLAGS_payload_dir} | awk '{print $1}')"
|
||||
info "${FLAGS_payload_dir} has ${PAYLOAD_DIR_SIZE} 512-byte sectors"
|
||||
fi
|
||||
|
||||
DEV_INSTALL_SHIM="dev_install_shim.bin"
|
||||
# We have a board name but no dev_install_shim set. Try find a recent one
|
||||
if [ -z $FLAGS_dev_install_shim ] ; then
|
||||
IMAGES_DIR="${DEFAULT_BUILD_ROOT}/images/${FLAGS_board}"
|
||||
FLAGS_dev_install_shim=\
|
||||
"${IMAGES_DIR}/$(ls -t $IMAGES_DIR 2>&-| head -1)/${DEV_INSTALL_SHIM}"
|
||||
fi
|
||||
|
||||
# Turn relative path into an absolute path.
|
||||
FLAGS_dev_install_shim=$(eval readlink -f ${FLAGS_dev_install_shim})
|
||||
|
||||
# Abort early if we can't find the install shim
|
||||
if [ ! -f $FLAGS_dev_install_shim ] ; then
|
||||
die "No dev install shim found at $FLAGS_dev_install_shim"
|
||||
else
|
||||
info "Using a recent dev install shim at ${FLAGS_dev_install_shim}"
|
||||
fi
|
||||
|
||||
# Constants
|
||||
INSTALL_SHIM_DIR="$(dirname "$FLAGS_dev_install_shim")"
|
||||
DEV_RECOVERY_IMAGE="dev_recovery_image.bin"
|
||||
|
||||
# Creates a dev recovery image using an existing dev install shim
|
||||
# If successful, content of --payload_dir is copied to a directory named
|
||||
# "dev_payload" under the root of stateful partition.
|
||||
create_dev_recovery_image() {
|
||||
local temp_state=$(mktemp "/tmp/temp_state.XXXXXX")
|
||||
local stateful_offset=$(partoffset ${FLAGS_dev_install_shim} 1)
|
||||
local stateful_count=$(partsize ${FLAGS_dev_install_shim} 1)
|
||||
dd if="${FLAGS_dev_install_shim}" of="${temp_state}" conv=notrunc bs=512 \
|
||||
skip=${stateful_offset} count=${stateful_count} &>/dev/null
|
||||
|
||||
local resized_sectors=$(enlarge_partition_image $temp_state $PAYLOAD_DIR_SIZE)
|
||||
|
||||
# Mount resized stateful FS and copy payload content to its root directory
|
||||
local temp_mnt=$(mktemp -d "/tmp/temp_mnt.XXXXXX")
|
||||
local loop_dev=$(get_loop_dev)
|
||||
trap "cleanup_loop_dev ${loop_dev}" EXIT
|
||||
mkdir -p "${temp_mnt}"
|
||||
sudo mount -o loop=${loop_dev} "${temp_state}" "${temp_mnt}"
|
||||
trap "umount_from_loop_dev ${temp_mnt} && rm -f \"${temp_state}\"" EXIT
|
||||
sudo cp -R "${FLAGS_payload_dir}" "${temp_mnt}/dev_payload"
|
||||
|
||||
# Mark image as dev recovery
|
||||
sudo touch "${temp_mnt}/.recovery"
|
||||
sudo touch "${temp_mnt}/.dev_recovery"
|
||||
|
||||
# TODO(tgao): handle install script (for default and custom cases)
|
||||
(update_partition_table $FLAGS_dev_install_shim $temp_state \
|
||||
$resized_sectors $TEMP_IMG)
|
||||
|
||||
# trap handler will clean up loop device and temp mount point
|
||||
}
|
||||
|
||||
# Main
|
||||
DST_PATH="${INSTALL_SHIM_DIR}/${DEV_RECOVERY_IMAGE}"
|
||||
info "Attempting to create dev recovery image using dev install shim \
|
||||
${FLAGS_dev_install_shim}"
|
||||
(create_dev_recovery_image)
|
||||
|
||||
if [ -n ${TEMP_IMG} ] && [ -f ${TEMP_IMG} ]; then
|
||||
mv -f $TEMP_IMG $DST_PATH
|
||||
info "Dev recovery image created at ${DST_PATH}"
|
||||
else
|
||||
info "Failed to create developer recovery image"
|
||||
fi
|
@ -4,35 +4,70 @@
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
# Script to modify a pristine/dev Chrome OS image to be used for recovery
|
||||
# This script modifies a base image to act as a recovery installer.
|
||||
# If no kernel image is supplied, it will build a devkeys signed recovery
|
||||
# kernel. Alternatively, a signed recovery kernel can be used to
|
||||
# create a Chromium OS recovery image.
|
||||
|
||||
# Load common constants. This should be the first executable line.
|
||||
# The path to common.sh should be relative to your script's location.
|
||||
. "$(dirname "$0")/common.sh"
|
||||
|
||||
# Load functions and constants for chromeos-install
|
||||
. "$(dirname "$0")/chromeos-common.sh"
|
||||
|
||||
# For update_partition_table
|
||||
. "$(dirname "$0")/resize_stateful_partition.sh"
|
||||
|
||||
# Script must be run inside the chroot.
|
||||
restart_in_chroot_if_needed $*
|
||||
|
||||
# We need to be in the chroot to emerge test packages.
|
||||
assert_inside_chroot
|
||||
|
||||
get_default_board
|
||||
|
||||
# Constants
|
||||
TEMP_IMG=$(mktemp "/tmp/temp_img.XXXXXX")
|
||||
RECOVERY_IMAGE="recovery_image.bin"
|
||||
DEFINE_string board "$DEFAULT_BOARD" "Board for which the image was built" b
|
||||
DEFINE_integer statefulfs_sectors 4096 \
|
||||
"Number of sectors to use for the stateful filesystem"
|
||||
# Skips the build steps and just does the kernel swap.
|
||||
DEFINE_string kernel_image "" \
|
||||
"Path to a pre-built recovery kernel"
|
||||
DEFINE_string kernel_outfile "" \
|
||||
"Filename and path to emit the kernel outfile to. \
|
||||
If empty, emits to IMAGE_DIR."
|
||||
DEFINE_string image "" "Path to the image to use"
|
||||
DEFINE_string to "" \
|
||||
"Path to the image to create. If empty, defaults to \
|
||||
IMAGE_DIR/recovery_image.bin."
|
||||
DEFINE_boolean kernel_image_only $FLAGS_FALSE \
|
||||
"Emit the recovery kernel image only"
|
||||
DEFINE_boolean sync_keys $FLAGS_TRUE \
|
||||
"Update the kernel to be installed with the vblock from stateful"
|
||||
DEFINE_integer jobs -1 \
|
||||
"How many packages to build in parallel at maximum." j
|
||||
DEFINE_string build_root "/build" \
|
||||
"The root location for board sysroots."
|
||||
|
||||
DEFINE_string board "$DEFAULT_BOARD" "Board for which the image was built"
|
||||
DEFINE_string image "" "Location of the rootfs raw image file"
|
||||
DEFINE_string output "${RECOVERY_IMAGE}" \
|
||||
"(optional) output image name. Default: ${RECOVERY_IMAGE}"
|
||||
DEFINE_string rootfs_hash "/tmp/rootfs.hash" \
|
||||
"Path where the rootfs hash should be stored."
|
||||
|
||||
# Keep in sync with build_image.
|
||||
DEFINE_string keys_dir "/usr/share/vboot/devkeys" \
|
||||
"Directory containing the signing keys."
|
||||
|
||||
# Parse command line
|
||||
FLAGS "$@" || exit 1
|
||||
eval set -- "${FLAGS_ARGV}"
|
||||
|
||||
EMERGE_CMD="emerge"
|
||||
EMERGE_BOARD_CMD="emerge-${FLAGS_board}"
|
||||
|
||||
# No board, no default and no image set then we can't find the image
|
||||
if [ -z $FLAGS_image ] && [ -z $FLAGS_board ] ; then
|
||||
setup_board_warning
|
||||
die "mod_image_for_recovery failed. No board set and no image set"
|
||||
fi
|
||||
|
||||
# We have a board name but no image set. Use image at default location
|
||||
# We have a board name but no image set. Use image at default location
|
||||
if [ -z $FLAGS_image ] ; then
|
||||
IMAGES_DIR="${DEFAULT_BUILD_ROOT}/images/${FLAGS_board}"
|
||||
FILENAME="chromiumos_image.bin"
|
||||
@ -40,7 +75,7 @@ if [ -z $FLAGS_image ] ; then
|
||||
fi
|
||||
|
||||
# Turn path into an absolute path.
|
||||
FLAGS_image=$(eval readlink -f ${FLAGS_image})
|
||||
FLAGS_image=`eval readlink -f ${FLAGS_image}`
|
||||
|
||||
# Abort early if we can't find the image
|
||||
if [ ! -f $FLAGS_image ] ; then
|
||||
@ -48,73 +83,284 @@ if [ ! -f $FLAGS_image ] ; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set -u
|
||||
set -e
|
||||
# What cross-build are we targeting?
|
||||
. "${FLAGS_build_root}/${FLAGS_board}/etc/make.conf.board_setup"
|
||||
# Figure out ARCH from the given toolchain.
|
||||
# TODO: Move to common.sh as a function after scripts are switched over.
|
||||
TC_ARCH=$(echo "${CHOST}" | awk -F'-' '{ print $1 }')
|
||||
case "${TC_ARCH}" in
|
||||
arm*)
|
||||
ARCH="arm"
|
||||
error "ARM recovery mode is still in the works. Use a normal image for now."
|
||||
;;
|
||||
*86)
|
||||
ARCH="x86"
|
||||
;;
|
||||
*)
|
||||
error "Unable to determine ARCH from toolchain: ${CHOST}"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
# Constants
|
||||
IMAGE_DIR="$(dirname "$FLAGS_image")"
|
||||
get_install_vblock() {
|
||||
# If it exists, we need to copy the vblock over to stateful
|
||||
# This is the real vblock and not the recovery vblock.
|
||||
local stateful_offset=$(partoffset "$FLAGS_image" 1)
|
||||
local stateful_mnt=$(mktemp -d)
|
||||
local out=$(mktemp)
|
||||
|
||||
# Creates a dev recovery image using an existing dev install shim
|
||||
# If successful, content of --payload_dir is copied to a directory named
|
||||
# "dev_payload" under the root of stateful partition.
|
||||
create_recovery_image() {
|
||||
local src_img=$1 # base image
|
||||
local src_state=$(mktemp "/tmp/src_state.XXXXXX")
|
||||
local stateful_offset=$(partoffset ${src_img} 1)
|
||||
local stateful_count=$(partsize ${src_img} 1)
|
||||
set +e
|
||||
sudo mount -o ro,loop,offset=$((stateful_offset * 512)) \
|
||||
"$FLAGS_image" $stateful_mnt
|
||||
sudo cp "$stateful_mnt/vmlinuz_hd.vblock" "$out"
|
||||
sudo chown $USER "$out"
|
||||
|
||||
dd if="${src_img}" of="${src_state}" conv=notrunc bs=512 \
|
||||
skip=${stateful_offset} count=${stateful_count}
|
||||
|
||||
# Mount original stateful partition to figure out its actual size
|
||||
local src_loop_dev=$(get_loop_dev)
|
||||
trap "cleanup_loop_dev ${src_loop_dev}" EXIT
|
||||
|
||||
# Setup loop dev
|
||||
sudo losetup $src_loop_dev $src_state
|
||||
local block_size=$(sudo /sbin/dumpe2fs $src_loop_dev | grep "Block size:" \
|
||||
| tr -d ' ' | cut -f2 -d:)
|
||||
echo "block_size = $block_size"
|
||||
local min_size=$(sudo /sbin/resize2fs -P $src_loop_dev | tr -d ' ' \
|
||||
| cut -f2 -d:)
|
||||
echo "min_size = $min_size $block_size blocks"
|
||||
|
||||
# Add 20%, convert to 512-byte sectors and round up to 2Mb boundary
|
||||
local min_sectors=$(roundup $(((min_size * block_size * 120) / (512 * 100))))
|
||||
echo "min_sectors = ${min_sectors} 512-byte blocks"
|
||||
sudo e2fsck -fp "${src_loop_dev}"
|
||||
# Resize using 512-byte sectors
|
||||
sudo /sbin/resize2fs $src_loop_dev ${min_sectors}s
|
||||
|
||||
# Delete the loop
|
||||
trap - EXIT
|
||||
cleanup_loop_dev ${src_loop_dev}
|
||||
|
||||
# Truncate the image at the new size
|
||||
dd if=/dev/zero of=$src_state bs=512 seek=$min_sectors count=0
|
||||
|
||||
# Mount and touch .recovery # Soon not to be needed :/
|
||||
local new_mnt=$(mktemp -d "/tmp/src_mnt.XXXXXX")
|
||||
mkdir -p "${new_mnt}"
|
||||
local new_loop_dev=$(get_loop_dev)
|
||||
trap "cleanup_loop_dev ${new_loop_dev} && rmdir ${new_mnt} && \
|
||||
rm -f ${src_state}" EXIT
|
||||
sudo mount -o loop=${new_loop_dev} "${src_state}" "${new_mnt}"
|
||||
trap "umount_from_loop_dev ${new_mnt} && rm -f ${src_state}" EXIT
|
||||
sudo touch "${new_mnt}/.recovery"
|
||||
|
||||
(update_partition_table $src_img $src_state $min_sectors $TEMP_IMG)
|
||||
# trap handler will handle unmount and clean up of loop device and temp files
|
||||
sudo umount -d "$stateful_mnt"
|
||||
rmdir "$stateful_mnt"
|
||||
set -e
|
||||
echo "$out"
|
||||
}
|
||||
|
||||
# Main
|
||||
DST_PATH="${IMAGE_DIR}/${FLAGS_output}"
|
||||
echo "Making a copy of original image ${FLAGS_image}"
|
||||
(create_recovery_image $FLAGS_image)
|
||||
emerge_recovery_kernel() {
|
||||
echo "Emerging custom recovery initramfs and kernel"
|
||||
local emerge_flags="-uDNv1 --usepkg=n --selective=n"
|
||||
|
||||
if [ -n ${TEMP_IMG} ] && [ -f ${TEMP_IMG} ]; then
|
||||
mv -f $TEMP_IMG $DST_PATH
|
||||
echo "Recovery image created at ${DST_PATH}"
|
||||
else
|
||||
echo "Failed to create recovery image"
|
||||
$EMERGE_BOARD_CMD \
|
||||
$emerge_flags --binpkg-respect-use=y \
|
||||
chromeos-initramfs || die "no initramfs"
|
||||
USE="initramfs" $EMERGE_BOARD_CMD \
|
||||
$emerge_flags --binpkg-respect-use=y \
|
||||
virtual/kernel
|
||||
}
|
||||
|
||||
create_recovery_kernel_image() {
|
||||
local sysroot="${FLAGS_build_root}/${FLAGS_board}"
|
||||
local vmlinuz="$sysroot/boot/vmlinuz"
|
||||
local root_dev=$(sudo losetup -f)
|
||||
local root_offset=$(partoffset "$FLAGS_image" 3)
|
||||
local root_size=$(partsize "$FLAGS_image" 3)
|
||||
|
||||
sudo losetup \
|
||||
-o $((root_offset * 512)) \
|
||||
--sizelimit $((root_size * 512)) \
|
||||
"$root_dev" \
|
||||
"$FLAGS_image"
|
||||
|
||||
trap "sudo losetup -d $root_dev" EXIT
|
||||
|
||||
cros_root=/dev/sd%D%P
|
||||
if [[ "${ARCH}" = "arm" ]]; then
|
||||
cros_root='/dev/${devname}${rootpart}'
|
||||
fi
|
||||
if grep -q enable_rootfs_verification "${IMAGE_DIR}/boot.desc"; then
|
||||
cros_root=/dev/dm-0
|
||||
fi
|
||||
# TODO(wad) LOAD FROM IMAGE KERNEL AND NOT BOOT.DESC
|
||||
local verity_args=$(grep -- '--verity_' "${IMAGE_DIR}/boot.desc")
|
||||
# Convert the args to the right names and clean up extra quoting.
|
||||
# TODO(wad) just update these everywhere
|
||||
verity_args=$(echo $verity_args | sed \
|
||||
-e 's/verity_algorithm/verity_hash_alg/g' \
|
||||
-e 's/verity_depth/verity_tree_depth/g' \
|
||||
-e 's/"//g')
|
||||
|
||||
# Tie the installed recovery kernel to the final kernel. If we don't
|
||||
# do this, a normal recovery image could be used to drop an unsigned
|
||||
# kernel on without a key-change check.
|
||||
# Doing this here means that the kernel and initramfs creation can
|
||||
# be done independently from the image to be modified as long as the
|
||||
# chromeos-recovery interfaces are the same. It allows for the signer
|
||||
# to just compute the new hash and update the kernel command line during
|
||||
# recovery image generation. (Alternately, it means an image can be created,
|
||||
# modified for recovery, then passed to a signer which can then sign both
|
||||
# partitions appropriately without needing any external dependencies.)
|
||||
local kern_offset=$(partoffset "$FLAGS_image" 2)
|
||||
local kern_size=$(partsize "$FLAGS_image" 2)
|
||||
local kern_tmp=$(mktemp)
|
||||
local kern_hash=
|
||||
|
||||
dd if="$FLAGS_image" bs=512 count=$kern_size skip=$kern_offset of="$kern_tmp"
|
||||
# We're going to use the real signing block.
|
||||
if [ $FLAGS_sync_keys -eq $FLAGS_TRUE ]; then
|
||||
dd if="$INSTALL_VBLOCK" of="$kern_tmp" conv=notrunc
|
||||
fi
|
||||
local kern_hash=$(sha1sum "$kern_tmp" | cut -f1 -d' ')
|
||||
rm "$kern_tmp"
|
||||
|
||||
# TODO(wad) add FLAGS_boot_args support too.
|
||||
${SCRIPTS_DIR}/build_kernel_image.sh \
|
||||
--arch="${ARCH}" \
|
||||
--to="$RECOVERY_KERNEL_IMAGE" \
|
||||
--hd_vblock="$RECOVERY_KERNEL_VBLOCK" \
|
||||
--vmlinuz="$vmlinuz" \
|
||||
--working_dir="${IMAGE_DIR}" \
|
||||
--boot_args="panic=60 cros_recovery kern_b_hash=$kern_hash" \
|
||||
--keep_work \
|
||||
--rootfs_image=${root_dev} \
|
||||
--rootfs_hash=${FLAGS_rootfs_hash} \
|
||||
--root=${cros_root} \
|
||||
--keys_dir="${FLAGS_keys_dir}" \
|
||||
--nouse_dev_keys \
|
||||
${verity_args}
|
||||
sudo rm "$FLAGS_rootfs_hash"
|
||||
sudo losetup -d "$root_dev"
|
||||
trap - RETURN
|
||||
|
||||
# Update the EFI System Partition configuration so that the kern_hash check
|
||||
# passes.
|
||||
local efi_dev=$(sudo losetup -f)
|
||||
local efi_offset=$(partoffset "$FLAGS_image" 12)
|
||||
local efi_size=$(partsize "$FLAGS_image" 12)
|
||||
|
||||
sudo losetup \
|
||||
-o $((efi_offset * 512)) \
|
||||
--sizelimit $((efi_size * 512)) \
|
||||
"$efi_dev" \
|
||||
"$FLAGS_image"
|
||||
local efi_dir=$(mktemp -d)
|
||||
trap "sudo losetup -d $efi_dev && rmdir \"$efi_dir\"" EXIT
|
||||
sudo mount "$efi_dev" "$efi_dir"
|
||||
sudo sed -i -e "s/cros_legacy/cros_legacy kern_b_hash=$kern_hash/g" \
|
||||
"$efi_dir/syslinux/usb.A.cfg" || true
|
||||
# This will leave the hash in the kernel for all boots, but that should be
|
||||
# safe.
|
||||
sudo sed -i -e "s/cros_efi/cros_efi kern_b_hash=$kern_hash/g" \
|
||||
"$efi_dir/efi/boot/grub.cfg" || true
|
||||
sudo umount "$efi_dir"
|
||||
sudo losetup -d "$efi_dev"
|
||||
rmdir "$efi_dir"
|
||||
trap - EXIT
|
||||
}
|
||||
|
||||
install_recovery_kernel() {
|
||||
local kern_a_offset=$(partoffset "$RECOVERY_IMAGE" 2)
|
||||
local kern_a_size=$(partsize "$RECOVERY_IMAGE" 2)
|
||||
local kern_b_offset=$(partoffset "$RECOVERY_IMAGE" 4)
|
||||
local kern_b_size=$(partsize "$RECOVERY_IMAGE" 4)
|
||||
# Backup original kernel to KERN-B
|
||||
dd if="$RECOVERY_IMAGE" of="$RECOVERY_IMAGE" bs=512 \
|
||||
count=$kern_a_size \
|
||||
skip=$kern_a_offset \
|
||||
seek=$kern_b_offset \
|
||||
conv=notrunc
|
||||
|
||||
# We're going to use the real signing block.
|
||||
if [ $FLAGS_sync_keys -eq $FLAGS_TRUE ]; then
|
||||
dd if="$INSTALL_VBLOCK" of="$RECOVERY_IMAGE" bs=512 \
|
||||
seek=$kern_b_offset \
|
||||
conv=notrunc
|
||||
fi
|
||||
|
||||
# Install the recovery kernel as primary.
|
||||
dd if="$RECOVERY_KERNEL_IMAGE" of="$RECOVERY_IMAGE" bs=512 \
|
||||
seek=$kern_a_offset \
|
||||
count=$kern_a_size \
|
||||
conv=notrunc
|
||||
|
||||
# Repeat for the legacy bioses.
|
||||
# Replace vmlinuz.A with the recovery version
|
||||
local sysroot="${FLAGS_build_root}/${FLAGS_board}"
|
||||
local vmlinuz="$sysroot/boot/vmlinuz"
|
||||
local esp_offset=$(partoffset "$RECOVERY_IMAGE" 12)
|
||||
local esp_mnt=$(mktemp -d)
|
||||
set +e
|
||||
local failed=0
|
||||
sudo mount -o loop,offset=$((esp_offset * 512)) "$RECOVERY_IMAGE" "$esp_mnt"
|
||||
sudo cp "$vmlinuz" "$esp_mnt/syslinux/vmlinuz.A" || failed=1
|
||||
sudo umount -d "$esp_mnt"
|
||||
rmdir "$esp_mnt"
|
||||
set -e
|
||||
if [ $failed -eq 1 ]; then
|
||||
echo "Failed to copy recovery kernel to ESP"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
maybe_resize_stateful() {
|
||||
# Rebuild the image with a 1 sector stateful partition
|
||||
local err=0
|
||||
local small_stateful=$(mktemp)
|
||||
dd if=/dev/zero of="$small_stateful" bs=512 \
|
||||
count=${FLAGS_statefulfs_sectors}
|
||||
trap "rm $small_stateful" RETURN
|
||||
# Don't bother with ext3 for such a small image.
|
||||
/sbin/mkfs.ext2 -F -b 4096 "$small_stateful"
|
||||
|
||||
# If it exists, we need to copy the vblock over to stateful
|
||||
# This is the real vblock and not the recovery vblock.
|
||||
local new_stateful_mnt=$(mktemp -d)
|
||||
|
||||
set +e
|
||||
sudo mount -o loop $small_stateful $new_stateful_mnt
|
||||
sudo cp "$INSTALL_VBLOCK" "$new_stateful_mnt/vmlinuz_hd.vblock"
|
||||
sudo mkdir "$new_stateful_mnt/var"
|
||||
sudo umount -d "$new_stateful_mnt"
|
||||
rmdir "$new_stateful_mnt"
|
||||
set -e
|
||||
|
||||
# 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" "$small_stateful" 4096 "$RECOVERY_IMAGE"
|
||||
return $err
|
||||
}
|
||||
|
||||
# main process begins here.
|
||||
|
||||
# Make sure this is really what the user wants, before nuking the device
|
||||
echo "Creating recovery image ${FLAGS_to} from ${FLAGS_image} . . . "
|
||||
|
||||
set -e
|
||||
set -u
|
||||
|
||||
IMAGE_DIR="$(dirname "$FLAGS_image")"
|
||||
IMAGE_NAME="$(basename "$FLAGS_image")"
|
||||
RECOVERY_IMAGE="${FLAGS_to:-$IMAGE_DIR/recovery_image.bin}"
|
||||
RECOVERY_KERNEL_IMAGE=\
|
||||
"${FLAGS_kernel_outfile:-${IMAGE_DIR}/recovery_vmlinuz.image}"
|
||||
RECOVERY_KERNEL_VBLOCK="${RECOVERY_KERNEL_IMAGE}.vblock"
|
||||
STATEFUL_DIR="$IMAGE_DIR/stateful_partition"
|
||||
SCRIPTS_DIR=$(dirname "$0")
|
||||
|
||||
# Mounts gpt image and sets up var, /usr/local and symlinks.
|
||||
# If there's a dev payload, mount stateful
|
||||
# offset=$(partoffset "${FLAGS_from}/${filename}" 1)
|
||||
# sudo mount ${ro_flag} -o loop,offset=$(( offset * 512 )) \
|
||||
# "${FLAGS_from}/${filename}" "${FLAGS_stateful_mountpt}"
|
||||
# If not, resize stateful to 1 sector.
|
||||
#
|
||||
|
||||
if [ $FLAGS_kernel_image_only -eq $FLAGS_TRUE -a \
|
||||
-n "$FLAGS_kernel_image" ]; then
|
||||
die "Cannot use --kernel_image_only with --kernel_image"
|
||||
fi
|
||||
|
||||
INSTALL_VBLOCK=$(get_install_vblock)
|
||||
if [ -z "$INSTALL_VBLOCK" ]; then
|
||||
die "Could not copy the vblock from stateful."
|
||||
fi
|
||||
|
||||
if [ -z "$FLAGS_kernel_image" ]; then
|
||||
emerge_recovery_kernel
|
||||
create_recovery_kernel_image
|
||||
else
|
||||
RECOVERY_KERNEL_IMAGE="$FLAGS_kernel_image"
|
||||
fi
|
||||
echo "Kernel emitted: $RECOVERY_KERNEL_IMAGE."
|
||||
|
||||
if [ $FLAGS_kernel_image_only -eq $FLAGS_TRUE ]; then
|
||||
echo "Kernel emitted. Stopping there."
|
||||
rm "$INSTALL_VBLOCK"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
rm "$RECOVERY_IMAGE" || true # Start fresh :)
|
||||
|
||||
trap "rm \"$RECOVERY_IMAGE\" && rm \"$INSTALL_VBLOCK\"" EXIT
|
||||
|
||||
maybe_resize_stateful # Also copies the image
|
||||
|
||||
install_recovery_kernel
|
||||
|
||||
print_time_elapsed
|
||||
trap - EXIT
|
||||
|
@ -64,8 +64,10 @@ update_partition_table() {
|
||||
local resized_sectors=$3 # number of sectors in resized stateful partition
|
||||
local temp_img=$4
|
||||
|
||||
local kernel_offset=$(partoffset ${src_img} 2)
|
||||
local kernel_count=$(partsize ${src_img} 2)
|
||||
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)
|
||||
@ -79,7 +81,8 @@ update_partition_table() {
|
||||
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 $(roundup ${rootfs_count})
|
||||
"${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 \
|
||||
@ -88,7 +91,9 @@ update_partition_table() {
|
||||
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=${kernel_offset} count=${kernel_count}
|
||||
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 \
|
||||
|
Loading…
x
Reference in New Issue
Block a user