mirror of
https://github.com/flatcar/scripts.git
synced 2025-09-23 14:41:31 +02:00
Migrated function definition to the beginning of the code; some minor cosmetics. This is a preliminary fix to the actual feature mentioned in the cited issue. BUG=chromium-os:26010 TEST=Executed in chroot environment with various combinations of flags and connected devices Change-Id: Ib73328e738ebecc38e6faafbd4feb33ced8804ad Reviewed-on: https://gerrit.chromium.org/gerrit/15438 Reviewed-by: Chris Sosa <sosa@chromium.org> Commit-Ready: Gilad Arnold <garnold@chromium.org> Tested-by: Gilad Arnold <garnold@chromium.org>
314 lines
10 KiB
Bash
Executable File
314 lines
10 KiB
Bash
Executable File
#!/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}"
|
|
|
|
# Generates a descriptive string of a removable device. Includes the
|
|
# manufacturer (if non-empty), product and a human-readable size.
|
|
function get_disk_string() {
|
|
local disk="${1##*/}"
|
|
local manufacturer_string=$(get_disk_info $disk manufacturer)
|
|
local product_string=$(get_disk_info $disk product)
|
|
local disk_size=$(sudo fdisk -l /dev/$disk 2>/dev/null | grep Disk |
|
|
head -n 1 | cut -d' ' -f3-4 | sed 's/,//g')
|
|
# I've seen one case where manufacturer only contains spaces, hence the test.
|
|
if [ -n "${manufacturer_string// }" ]; then
|
|
echo -n "${manufacturer_string} "
|
|
fi
|
|
echo "${product_string}, ${disk_size}"
|
|
}
|
|
|
|
|
|
# Prohibit mutually exclusive factory/install flags.
|
|
if [ ${FLAGS_factory} -eq ${FLAGS_TRUE} -a \
|
|
${FLAGS_factory_install} -eq ${FLAGS_TRUE} ] ; then
|
|
die "Factory test image is incompatible with factory install shim"
|
|
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
|
|
die "Cannot find image directory ${FLAGS_from}"
|
|
fi
|
|
|
|
if [ -n "${FLAGS_to_product}" ]; then
|
|
if [ "${FLAGS_to}" != "/dev/sdX" ]; then
|
|
die "Cannot specify both --to and --to_product"
|
|
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
|
|
die "Multiple devices match product '${FLAGS_to_product}', aborting"
|
|
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
|
|
|
|
# No target provided, attempt autodetection.
|
|
if [ "${FLAGS_to}" == "/dev/sdX" ]; then
|
|
echo "No target device was specified, autodetecting..."
|
|
|
|
# Obtain list of USB and MMC device names.
|
|
disk_list=( $(list_usb_disks) $(list_mmc_disks) )
|
|
if (( ! ${#disk_list[*]} )); then
|
|
die "No target device could be detected"
|
|
fi
|
|
|
|
# Build list of descriptive strings for detected devices.
|
|
unset disk_string_list
|
|
for disk in "${disk_list[@]}"; do
|
|
disk_string=$(get_disk_string /dev/${disk})
|
|
disk_string_list=( "${disk_string_list[@]}" \
|
|
"/dev/${disk}: ${disk_string}" )
|
|
done
|
|
|
|
# Prompt for selection, or autoselect if only one device was found.
|
|
if (( ${#disk_string_list[*]} > 1 )); then
|
|
PS3="Select a target device: "
|
|
select disk_string in "${disk_string_list[@]}"; do
|
|
if [ -z "${disk_string}" ]; then
|
|
die "Invalid selection"
|
|
fi
|
|
break
|
|
done
|
|
else
|
|
disk_string="${disk_string_list}"
|
|
echo "Found ${disk_string}"
|
|
fi
|
|
|
|
FLAGS_to="${disk_string%%:*}"
|
|
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}`
|
|
|
|
# Check whether target device is USB/MMC, and obtain a string descriptor for it.
|
|
unset disk_string
|
|
if [ -b "${FLAGS_to}" ]; then
|
|
if list_usb_disks | grep -q '^'${FLAGS_to##*/}'$' ||
|
|
list_mmc_disks | grep -q '^'${FLAGS_to##*/}'$'; then
|
|
disk_string=$(get_disk_string ${FLAGS_to})
|
|
elif [ ${FLAGS_force_non_usb} -ne ${FLAGS_TRUE} ]; then
|
|
# Safeguard against writing to a real non-USB disk or non-SD disk
|
|
die "${FLAGS_to} does not appear to be a USB/MMC disk," \
|
|
"use --force_non_usb to override"
|
|
fi
|
|
fi
|
|
|
|
STATEFUL_DIR="${FLAGS_from}/stateful_partition"
|
|
mkdir -p "${STATEFUL_DIR}"
|
|
|
|
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
|
|
|
|
if [ ! -f "${SRC_IMAGE}" ]; then
|
|
die "Image not found: ${SRC_IMAGE}"
|
|
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 ${FLAGS_to}..."
|
|
else
|
|
echo "Installing image ${SRC_IMAGE} to ${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
|
|
warn "${FLAGS_to} looks like a partition; did you mean ${drive}?"
|
|
fi
|
|
fi
|
|
|
|
# Make sure this is really what the user wants, before nuking the device
|
|
if [ ${FLAGS_yes} -ne ${FLAGS_TRUE} ]; then
|
|
warning_str="this will erase all data on ${FLAGS_to}"
|
|
if [ -n "${disk_string}" ]; then
|
|
warning_str="${warning_str}: ${disk_string}"
|
|
else
|
|
warning_str="${warning_str}, which does not appear to be a USB/MMC disk!"
|
|
fi
|
|
warn "${warning_str}"
|
|
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
|
|
fi
|
|
fi
|
|
|
|
echo "Attempting to unmount any mounts on the target device..."
|
|
for i in $(mount | grep ^"${FLAGS_to}" | awk '{print $1}'); do
|
|
if sudo umount "$i" 2>&1 >/dev/null | grep "not found"; then
|
|
die "Device ${FLAGS_to} needs to be unmounted outside the chroot"
|
|
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
|
|
die "Installation must be done from inside the chroot"
|
|
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
|