blob: 606bd07700d4e740c0081da4af6549c803754af2 [file] [log] [blame]
#!/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 convert the output of build_image.sh to a usb or SD image.
# --- BEGIN COMMON.SH BOILERPLATE ---
# Load common CrOS utilities. Inside the chroot this file is installed in
# /usr/lib/crosutils. Outside the chroot we find it relative to the script's
# location.
find_common_sh() {
local common_paths=(/usr/lib/crosutils $(dirname "$(readlink -f "$0")"))
local path
SCRIPT_ROOT=
for path in "${common_paths[@]}"; do
if [ -r "${path}/common.sh" ]; then
SCRIPT_ROOT=${path}
break
fi
done
}
find_common_sh
. "${SCRIPT_ROOT}/common.sh" || { echo "Unable to load common.sh"; exit 1; }
# --- END COMMON.SH BOILERPLATE ---
# Load functions and constants for chromeos-install
[ -f /usr/lib/installer/chromeos-common.sh ] && \
INSTALLER_ROOT=/usr/lib/installer || \
INSTALLER_ROOT=$(dirname "$(readlink -f "$0")")
. "${INSTALLER_ROOT}/chromeos-common.sh" || \
die "Unable to load chromeos-common.sh"
# In case chromeos-common.sh doesn't support MMC yet
declare -F list_mmc_disks >/dev/null || list_mmc_disks() { true; }
get_default_board
# Flags
DEFINE_string board "${DEFAULT_BOARD}" "Board for which the image was built"
DEFINE_string from "" \
"Directory containing ${CHROMEOS_IMAGE_NAME}, or filename"
DEFINE_string to "/dev/sdX" "Write to a specific disk or image file."
DEFINE_string to_product "" \
"Write to a disk with product name matching a pattern."
DEFINE_boolean yes ${FLAGS_FALSE} "Answer yes to all prompts" "y"
DEFINE_boolean force_copy ${FLAGS_FALSE} "Always rebuild test image"
DEFINE_boolean force_non_usb ${FLAGS_FALSE} \
"Write out image even if target (--to) doesn't look like a USB or MMC disk"
DEFINE_boolean factory_install ${FLAGS_FALSE} \
"Whether to generate a factory install shim."
DEFINE_boolean factory ${FLAGS_FALSE} \
"Whether to generate a factory runin image. Implies aututest and test"
DEFINE_boolean copy_kernel ${FLAGS_FALSE} \
"Copy the kernel to the fourth partition."
DEFINE_boolean test_image "${FLAGS_FALSE}" \
"Copies normal image to ${CHROMEOS_TEST_IMAGE_NAME}, modifies it for test."
DEFINE_string image_name "${CHROMEOS_IMAGE_NAME}" \
"Base name of the image" i
DEFINE_string build_root "/build" \
"The root location for board sysroots."
DEFINE_boolean install ${FLAGS_FALSE} "Install to the USB or MMC device."
DEFINE_string arch "" "Architecture of the image."
# Parse command line
FLAGS "$@" || exit 1
eval set -- "${FLAGS_ARGV}"
if [ ${FLAGS_factory} -eq ${FLAGS_TRUE} ] ; then
if [ ${FLAGS_factory_install} -eq ${FLAGS_TRUE} ] ; then
echo "Factory test image is incompatible with factory install shim."
exit 1
fi
fi
# Allow --from /foo/file.bin
if [ -f "${FLAGS_from}" ]; then
pathname=$(dirname "${FLAGS_from}")
filename=$(basename "${FLAGS_from}")
FLAGS_image_name="${filename}"
FLAGS_from="${pathname}"
fi
# Require autotest for manucaturing image.
if [ ${FLAGS_factory} -eq ${FLAGS_TRUE} ] ; then
echo "Factory image requires --test_image, setting."
FLAGS_test_image=${FLAGS_TRUE}
fi
# Require test for for factory install shim.
if [ ${FLAGS_factory_install} -eq ${FLAGS_TRUE} ] ; then
echo "Factory install shim requires --test_image, setting."
FLAGS_test_image=${FLAGS_TRUE}
fi
# Die on any errors.
set -e
# No board, no default and no image set then we can't find the image
if [ -z ${FLAGS_from} ] && [ -z ${FLAGS_board} ] ; then
setup_board_warning
exit 1
fi
# No board set during install
if [ -z "${FLAGS_board}" ] && [ ${FLAGS_install} -eq ${FLAGS_TRUE} ]; then
setup_board_warning
exit 1
fi
# We have a board name but no image set. Use image at default location
if [ -z "${FLAGS_from}" ]; then
FLAGS_from="$($SCRIPT_ROOT/get_latest_image.sh --board=${FLAGS_board})"
fi
if [ ! -d "${FLAGS_from}" ] ; then
echo "Cannot find image directory ${FLAGS_from}"
exit 1
fi
if [ -n "${FLAGS_to_product}" ]; then
if [ "${FLAGS_to}" != "/dev/sdX" ]; then
echo "Cannot specify both --to and --to_product"
exit 1
fi
match=""
for disk in $(list_usb_disks) $(list_mmc_disks); do
if [[ "$(get_disk_info $disk product)" = ${FLAGS_to_product} ]]; then
if [ -n "${match}" ]; then
echo "Found multiple devices matching product" \
"'${FLAGS_to_product}'; aborting."
exit 1
fi
match="$disk"
fi
done
if [ -z "${match}" ]; then
echo "Failed to find a devices matching product '${FLAGS_to_product}'"
# Leave FLAGS_to set to its default and fall through to the error report.
else
FLAGS_to="/dev/${match}"
fi
fi
if [ "${FLAGS_to}" == "/dev/sdX" ]; then
echo "You must specify a file or device to write to using one of" \
"--to or --to_product."
disks="$(list_usb_disks) $(list_mmc_disks)"
if [ -n "$disks" ]; then
echo "Available USB & MMC disks:"
for disk in $disks; do
echo " /dev/$disk:"
echo " Manufacturer: $(get_disk_info $disk manufacturer)"
echo " Product: $(get_disk_info $disk product)"
echo " Size: $[$(cat /sys/block/$disk/size) * 512] bytes"
done
fi
exit 1
fi
# Guess ARCH if it's unset
if [ "${FLAGS_arch}" = "" ]; then
if echo "${FLAGS_board}" | grep -qs "x86"; then
FLAGS_arch=INTEL
else
FLAGS_arch=ARM
fi
fi
# Convert args to paths. Need eval to un-quote the string so that shell
# chars like ~ are processed; just doing FOO=`readlink -f ${FOO}` won't work.
FLAGS_from=`eval readlink -f ${FLAGS_from}`
FLAGS_to=`eval readlink -f ${FLAGS_to}`
# One last check to make sure user is not shooting themselves in the foot
if [ -b "${FLAGS_to}" ]; then
if list_usb_disks | grep -q '^'${FLAGS_to##*/}'$' ||
list_mmc_disks | grep -q '^'${FLAGS_to##*/}'$'; then
disk_manufacturer=$(get_disk_info ${FLAGS_to##*/} manufacturer)
disk_product=$(get_disk_info ${FLAGS_to##*/} product)
elif [ ${FLAGS_force_non} -ne ${FLAGS_TRUE} ]; then
# Safeguard against writing to a real non-USB disk or non-SD disk
echo "Error: Device ${FLAGS_to} does not appear to be a USB or MMC disk!"
echo " To override this safeguard, use the --force_non_usb flag"
exit 1
fi
fi
STATEFUL_DIR="${FLAGS_from}/stateful_partition"
mkdir -p "${STATEFUL_DIR}"
function do_cleanup {
echo "Cleaning loopback devices: ${STATEFUL_LOOP_DEV}"
if [ "${STATEFUL_LOOP_DEV}" != "" ]; then
sudo umount "${STATEFUL_DIR}"
sudo losetup -d "${STATEFUL_LOOP_DEV}"
rmdir "${STATEFUL_DIR}"
echo "Cleaned"
fi
}
if [ ${FLAGS_test_image} -eq ${FLAGS_TRUE} ] ; then
# Make a test image - this returns the test filename in CHROMEOS_RETURN_VAL
prepare_test_image "${FLAGS_from}" "${FLAGS_image_name}"
SRC_IMAGE="${CHROMEOS_RETURN_VAL}"
else
# Use the standard image
SRC_IMAGE="${FLAGS_from}/${FLAGS_image_name}"
fi
# Let's do it.
if [ -b "${FLAGS_to}" ]; then
# Output to a block device (i.e., a real USB key / SD card), so need sudo dd
if [ ${FLAGS_install} -ne ${FLAGS_TRUE} ]; then
echo "Copying USB image ${SRC_IMAGE} to device ${FLAGS_to}..."
else
echo "Installing image ${SRC_IMAGE} to device ${FLAGS_to}..."
fi
# Warn if it looks like they supplied a partition as the destination.
if echo "${FLAGS_to}" | grep -q '[0-9]$'; then
drive=$(echo "${FLAGS_to}" | sed -re 's/[0-9]+$//')
if [ -b "${drive}" ]; then
echo
echo "NOTE: It looks like you may have supplied a partition as the "
echo "destination. This script needs to write to the drive's device "
echo "node instead (i.e. ${drive} rather than ${FLAGS_to})."
echo
fi
fi
# Make sure this is really what the user wants, before nuking the device
if [ ${FLAGS_yes} -ne ${FLAGS_TRUE} ]; then
sudo fdisk -l "${FLAGS_to}" 2>/dev/null | grep Disk | head -1
[ -n "$disk_manufacturer" ] && echo "Manufacturer: $disk_manufacturer"
[ -n "$disk_product" ] && echo "Product: $disk_product"
echo "This will erase all data on this device:"
read -p "Are you sure (y/N)? " SURE
SURE="${SURE:0:1}" # Get just the first character
if [ "${SURE}" != "y" ]; then
echo "Ok, better safe than sorry."
exit 1
fi
fi
echo "Attempting to unmount any mounts on the USB/MMC device..."
for i in $(mount | grep ^"${FLAGS_to}" | awk '{print $1}'); do
if sudo umount "$i" 2>&1 >/dev/null | grep "not found"; then
echo
echo "The device you have specified is already mounted at some point "
echo "that is not visible from inside the chroot. Please unmount the "
echo "device manually from outside the chroot and try again."
echo
exit 1
fi
done
sleep 3
if [ ${FLAGS_install} -ne ${FLAGS_TRUE} ]; then
echo "Copying with dd ${SRC_IMAGE} to ${FLAGS_to}..."
sudo ${COMMON_PV_CAT} "${SRC_IMAGE}" |
sudo dd of="${FLAGS_to}" bs=4M oflag=sync status=noxfer
sync
else
if [ ${INSIDE_CHROOT} -ne 1 ]; then
echo "Installation must be done from inside the chroot."
exit 1
fi
echo "Installing ${SRC_IMAGE} to ${FLAGS_to}..."
"${FLAGS_build_root}/${FLAGS_board}/usr/sbin/chromeos-install" \
--yes \
--skip_src_removable \
--skip_dst_removable \
--arch="${FLAGS_arch}" \
--payload_image="${SRC_IMAGE}" \
--dst="${FLAGS_to}"
fi
echo "Done."
else
# Output to a file, so just make a copy.
if [ "${SRC_IMAGE}" != "${FLAGS_to}" ]; then
echo "Copying ${SRC_IMAGE} to ${FLAGS_to}..."
${COMMON_PV_CAT} "${SRC_IMAGE}" >"${FLAGS_to}"
fi
echo "Done. To copy to a USB/MMC drive, do something like:"
echo " sudo dd if=${FLAGS_to} of=/dev/sdX bs=4M oflag=sync"
echo "where /dev/sdX is the entire drive."
fi