flatcar-scripts/build_image
Rong Chang c291a48995 Add "blkdevram" USE flag when building ARM factory install kernel
Default netroot factory install kernel mounts rootfs in ram. The
USE flag "blkdevram" was implemented in
  http://gerrit.chromium.org/gerrit/#change,1802

BUG=None
TEST=Build factory install kernel and rootfs uimg. Kernel should
be able to mount the in-ram initrd downloaded from tftp.

Change-Id: Idb83375e0587432c5dec87357a8aa8e229f40af2
Reviewed-on: http://gerrit.chromium.org/gerrit/1803
Reviewed-by: Rong Chang <rongchang@chromium.org>
Tested-by: Rong Chang <rongchang@chromium.org>
2011-06-03 00:30:15 -07:00

827 lines
28 KiB
Bash
Executable File

#!/bin/bash
# Copyright (c) 2011 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 build a bootable keyfob-based chromeos system image from within
# a chromiumos setup. This assumes that all needed packages have been built into
# the given target's root with binary packages turned on. This script will
# build the Chrome OS image using only pre-built binary packages.
# 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 "$0"))
local path
SCRIPT_ROOT=
for path in "${common_paths[@]}"; do
local common="${path}/common.sh"
if ([ -r "${common}" ] && . "${common}" && [ -d "${SCRIPTS_DIR}" ]); then
SCRIPT_ROOT=${path}
break
fi
done
}
find_common_sh
. "${SCRIPT_ROOT}/common.sh" || ! echo "Unable to load common.sh" || exit 1
# 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"
locate_gpt
# Script must be run inside the chroot.
restart_in_chroot_if_needed "$@"
get_default_board
# Flags.
DEFINE_string board "${DEFAULT_BOARD}" \
"The board to build an image for."
DEFINE_string build_root "/build" \
"The root location for board sysroots."
DEFINE_integer build_attempt 1 \
"The build attempt for this image build."
DEFINE_string output_root "${DEFAULT_BUILD_ROOT}/images" \
"Directory in which to place image result directories (named by version)"
DEFINE_boolean eclean ${FLAGS_TRUE} \
"Perform eclean-<board> -d as part of this script to remove obsolete packages"
DEFINE_boolean replace ${FLAGS_FALSE} \
"Overwrite existing output, if any."
DEFINE_boolean withdev ${FLAGS_TRUE} \
"Include useful developer friendly utilities in the image."
DEFINE_boolean installmask ${FLAGS_TRUE} \
"Use INSTALL_MASK to shrink the resulting image."
DEFINE_integer jobs -1 \
"How many packages to build in parallel at maximum."
DEFINE_boolean statefuldev ${FLAGS_TRUE} \
"Install development packages on stateful partition rather than the rootfs"
DEFINE_string to "" \
"The target image file or device"
DEFINE_boolean factory_install ${FLAGS_FALSE} \
"Build a smaller image to overlay the factory install shim on; this argument \
is also required in image_to_usb."
DEFINE_integer rootfs_partition_size 1024 \
"rootfs partition size in MiBs."
DEFINE_integer rootfs_size 850 \
"rootfs filesystem size in MiBs."
# ceil(0.1 * rootfs_size) is a good minimum.
DEFINE_integer rootfs_hash_pad 8 \
"MiBs reserved at the end of the rootfs image."
DEFINE_integer statefulfs_size 1024 \
"stateful filesystem size in MiBs."
DEFINE_boolean preserve ${FLAGS_FALSE} \
"Attempt to preserve the previous build image if one can be found (unstable, \
kernel/firmware not updated)"
DEFINE_boolean fast ${DEFAULT_FAST} \
"Call many emerges in parallel"
DEFINE_string boot_args "noinitrd" \
"Additional boot arguments to pass to the commandline"
DEFINE_string usb_disk /dev/sdb3 \
"Path syslinux should use to do a usb boot. Default: /dev/sdb3"
# TODO(clchiou): Remove this flag after arm verified boot is stable
DEFINE_boolean crosbug12352_arm_kernel_signing ${FLAGS_TRUE} \
"Sign kernel partition for ARM images (temporary hack)."
DEFINE_boolean enable_rootfs_verification ${FLAGS_TRUE} \
"Default all bootloaders to use kernel-based root fs integrity checking."
DEFINE_integer verity_error_behavior 3 \
"Kernel verified boot error behavior (0: I/O errors, 1: panic, 2: nothing, \
3: cros) Default: 3"
DEFINE_integer verity_max_ios -1 \
"Number of outstanding I/O operations dm-verity caps at. Default: -1"
DEFINE_string verity_algorithm "sha1" \
"Cryptographic hash algorithm used for kernel vboot. Default : sha1"
# 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 'set -e' is specified before now.
set -e
if [ -z "${FLAGS_board}" ] ; then
error "--board is required."
exit 1
fi
# Perform an eclean to remove packages which are not installed
if [[ ${FLAGS_eclean} -eq ${FLAGS_TRUE} ]]; then
eclean-${FLAGS_board} -d packages
fi
check_blacklist() {
info "Verifying that the base image does not contain a blacklisted package."
info "Generating list of packages for chromeos-base/chromeos."
local package_blacklist_file="${SCRIPTS_DIR}/chromeos_blacklist"
if [ ! -e "${package_blacklist_file}" ]; then
warn "Missing blacklist file."
return
fi
local blacklisted_packages=$(${SCRIPTS_DIR}/get_package_list \
--board="${FLAGS_board}" chromeos-base/chromeos \
| grep -x -f "${package_blacklist_file}")
if [ -n "${blacklisted_packages}" ]; then
die "Blacklisted packages found: ${blacklisted_packages}."
fi
info "No blacklisted packages found."
}
check_blacklist
# TODO(vlaviano): Validate command line flags. Check for conflicting flags and
# reconcile them if possible. Exit with an error message otherwise.
export INSTALL_MASK=""
if [ ${FLAGS_installmask} -eq ${FLAGS_TRUE} ] ; then
INSTALL_MASK="${DEFAULT_INSTALL_MASK}"
fi
# Reduce the size of factory install shim.
if [ ${FLAGS_factory_install} -eq ${FLAGS_TRUE} ]; then
# Disable --withdev flag when --factory_install is set to True. Otherwise, the
# dev image produced will be based on install shim, rather than a pristine
# image
if [ ${FLAGS_withdev} -eq ${FLAGS_TRUE} ]; then
info "Incompatible flags: --withdev and --factory_install cannot both be \
set to True. Resetting --withdev to False."
FLAGS_withdev=${FLAGS_FALSE}
fi
# TODO: Build a separated ebuild for the install shim to reduce size.
INSTALL_MASK="${INSTALL_MASK} ${FACTORY_INSTALL_MASK}"
info "Fixing the rootfs size at 300 MiB for install shim"
FLAGS_rootfs_size=280
FLAGS_rootfs_partition_size=300
info "Fixing the statefulfs size at 140 MiB for install shim"
FLAGS_statefulfs_size=140
fi
if [ $((FLAGS_rootfs_size + FLAGS_rootfs_hash_pad)) -gt \
${FLAGS_rootfs_partition_size} ] ; then
die "rootfs ($((FLAGS_rootfs_size + FLAGS_rootfs_hash_pad)) MiB) is \
bigger than partition (${FLAGS_rootfs_partition_size} MiB)."
fi
EMERGE_BOARD_CMD="emerge-${FLAGS_board}"
if [ ${FLAGS_fast} -eq ${FLAGS_TRUE} ]; then
echo "Using alternate emerge"
EMERGE_CMD="${GCLIENT_ROOT}/chromite/bin/parallel_emerge"
EMERGE_BOARD_CMD="${EMERGE_CMD} --board=${FLAGS_board}"
fi
OVERLAY_CHROMEOS_DIR="${SRC_ROOT}/third_party/chromiumos-overlay/chromeos/"
# Determine build version.
. "${OVERLAY_CHROMEOS_DIR}/config/chromeos_version.sh"
BOARD="${FLAGS_board}"
BOARD_ROOT="${FLAGS_build_root}/${BOARD}"
# What cross-build are we targeting?
. "${BOARD_ROOT}/etc/make.conf.board_setup"
LIBC_VERSION=${LIBC_VERSION}
# 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"
;;
*86)
ARCH="x86"
;;
*x86_64)
ARCH="amd64"
;;
*)
error "Unable to determine ARCH from toolchain: ${CHOST}"
exit 1
esac
# Configure extra USE or packages for this type of build.
EXTRA_PACKAGES=""
if [ ${FLAGS_factory_install} -eq ${FLAGS_TRUE} ] ; then
# Factory install needs to have the factory installer added.
EXTRA_PACKAGES="${EXTRA_PACKAGES} chromeos-base/chromeos-factoryinstall"
# On x86, we boot the factory install shim from an SD card using
# initramfs for our root. On ARM, we boot the factory install shim
# over the network, so we don't require initramfs, but we do require
# fbconsole to fix a display driver bug.
if [ "${ARCH}" = "x86" ] ; then
export USE="${USE} initramfs"
fi
# CONFIG_BLK_DEV_RAM is disabled by default.
# But tftp install needs it to mount rootfs in ram
if [ "${ARCH}" = "arm" ] ; then
export USE="${USE} fbconsole blkdevram"
fi
fi
emerge_to_image() {
sudo -E ${EMERGE_BOARD_CMD} --root-deps=rdeps --usepkgonly \
"$@" ${EMERGE_JOBS}
}
# Check that the build root is sane.
"${SCRIPTS_DIR}/test_build_root" --root="${BOARD_ROOT}"
# Freshen kernel with correct USE flags. This is a noop if we have
# the right kernel prebuilt. Factory install uses USE="initramfs".
# We don't allow building from source with the image as a target,
# and it's not possible to store prebuilts for the same package
# with different use flags.
sudo -E ${EMERGE_BOARD_CMD} -uDNv -g virtual/kernel
# Use canonical path since some tools (e.g. mount) do not like symlinks.
# Append build attempt to output directory.
IMAGE_SUBDIR="${CHROMEOS_VERSION_STRING}-a${FLAGS_build_attempt}"
OUTPUT_DIR="${FLAGS_output_root}/${FLAGS_board}/${IMAGE_SUBDIR}"
OUTSIDE_OUTPUT_DIR="../build/images/${FLAGS_board}/${IMAGE_SUBDIR}"
# If we are creating a developer image, also create a pristine image with a
# different name.
DEVELOPER_IMAGE_NAME=
PRISTINE_IMAGE_NAME=chromiumos_image.bin
if [ ${FLAGS_withdev} -eq ${FLAGS_TRUE} ]; then
PRISTINE_IMAGE_NAME=chromiumos_base_image.bin
DEVELOPER_IMAGE_NAME=chromiumos_image.bin
# Rename pristine image for factory install shim
elif [ ${FLAGS_factory_install} -eq ${FLAGS_TRUE} ]; then
PRISTINE_IMAGE_NAME=factory_install_shim.bin
fi
PRISTINE_IMG="${OUTPUT_DIR}/${PRISTINE_IMAGE_NAME}"
DEVELOPER_IMG="${OUTPUT_DIR}/${DEVELOPER_IMAGE_NAME}"
ROOT_FS_IMG="${OUTPUT_DIR}/rootfs.image"
ROOT_FS_DIR="${OUTPUT_DIR}/rootfs"
ROOT_FS_HASH="${OUTPUT_DIR}/rootfs.hash"
STATEFUL_FS_IMG="${OUTPUT_DIR}/stateful_partition.image"
STATEFUL_FS_DIR="${OUTPUT_DIR}/stateful_partition"
ESP_FS_IMG=${OUTPUT_DIR}/esp.image
ESP_FS_DIR=${OUTPUT_DIR}/esp
DEVKEYSDIR="/usr/share/vboot/devkeys"
LOOP_DEV=
STATEFUL_LOOP_DEV=
ESP_LOOP_DEV=
# ${DEV_IMAGE_ROOT} specifies the location of where developer packages will
# be installed on the stateful dir. On a Chromium OS system, this will
# translate to /usr/local.
DEV_IMAGE_ROOT="${STATEFUL_FS_DIR}/dev_image"
if [ ${FLAGS_jobs} -ne -1 ]; then
EMERGE_JOBS="--jobs=${FLAGS_jobs}"
fi
if [[ ${FLAGS_crosbug12352_arm_kernel_signing} -eq ${FLAGS_TRUE} ]]; then
crosbug12352_flag="--crosbug12352_arm_kernel_signing"
else
crosbug12352_flag="--nocrosbug12352_arm_kernel_signing"
fi
if [[ ${FLAGS_enable_rootfs_verification} -eq ${FLAGS_TRUE} ]]; then
enable_rootfs_verification_flag="--enable_rootfs_verification"
fi
# Hack to fix bug where x86_64 CHOST line gets incorrectly added.
# ToDo(msb): remove this hack.
PACKAGES_FILE="${BOARD_ROOT}/packages/Packages"
sudo sed -e "s/CHOST: x86_64-pc-linux-gnu//" -i "${PACKAGES_FILE}"
# Handle existing directory.
if [[ -e "${OUTPUT_DIR}" ]]; then
if [[ ${FLAGS_replace} -eq ${FLAGS_TRUE} ]]; then
sudo rm -rf "${OUTPUT_DIR}"
else
echo "Directory ${OUTPUT_DIR} already exists."
echo "Use --build_attempt option to specify an unused attempt."
echo "Or use --replace if you want to overwrite this directory."
exit 1
fi
fi
# Find previous build, if any...
PREVIOUS_DIR=$($SCRIPTS_DIR/get_latest_image.sh --board="$BOARD")
cleanup_rootfs_loop() {
sudo umount -d "${ROOT_FS_DIR}"
}
cleanup_stateful_fs_loop() {
sudo umount "${ROOT_FS_DIR}/usr/local"
sudo umount "${ROOT_FS_DIR}/var"
sudo umount -d "${STATEFUL_FS_DIR}"
}
cleanup_esp_loop() {
sudo umount -d "${ESP_FS_DIR}"
}
cleanup() {
# Disable die on error.
set +e
if [[ -n "${STATEFUL_LOOP_DEV}" ]]; then
cleanup_stateful_fs_loop
STATEFUL_LOOP_DEV=
fi
if [[ -n "${LOOP_DEV}" ]]; then
cleanup_rootfs_loop
LOOP_DEV=
fi
if [[ -n "${ESP_LOOP_DEV}" ]]; then
cleanup_esp_loop
ESP_LOOP_DEV=
fi
# Turn die on error back on.
set -e
}
delete_prompt() {
echo "An error occurred in your build so your latest output directory" \
"is invalid."
# Only prompt if both stdin and stdout are a tty. If either is not a tty,
# then the user may not be present, so we shouldn't bother prompting.
if tty -s && tty -s <&1 && [ "${USER}" != 'chrome-bot' ]; then
read -p "Would you like to delete the output directory (y/N)? " SURE
SURE="${SURE:0:1}" # Get just the first character.
else
SURE="y"
echo "Running in non-interactive mode so deleting output directory."
fi
if [ "${SURE}" == "y" ] ; then
sudo rm -rf "${OUTPUT_DIR}"
echo "Deleted ${OUTPUT_DIR}"
else
echo "Not deleting ${OUTPUT_DIR}."
fi
}
# $1 - Directory where developer rootfs is mounted.
# $2 - Directory where developer stateful_partition is mounted.
# $3 - Directory where the ESP partition is mounted.
mount_gpt_cleanup() {
local rootfs="${1-$ROOT_FS_DIR}"
local statefs="${2-$STATEFUL_FS_DIR}"
local espfs="${3-$ESP_FS_DIR}"
"${SCRIPTS_DIR}/mount_gpt_image.sh" \
-u -r "${rootfs}" -s "${statefs}" -e "${espfs}"
delete_prompt
}
# Takes no arguments and populates the configuration for
# cros_make_image_bootable.
create_boot_desc() {
cat <<EOF > ${OUTPUT_DIR}/boot.desc
--arch="${ARCH}"
--output_dir="${OUTPUT_DIR}"
--boot_args="${FLAGS_boot_args}"
--rootfs_size="${FLAGS_rootfs_size}"
--rootfs_hash_pad="${FLAGS_rootfs_hash_pad}"
--rootfs_hash="${ROOT_FS_HASH}"
--rootfs_mountpoint="${ROOT_FS_DIR}"
--statefulfs_mountpoint="${STATEFUL_FS_DIR}"
--espfs_mountpoint="${ESP_FS_DIR}"
--verity_error_behavior="${FLAGS_verity_error_behavior}"
--verity_max_ios="${FLAGS_verity_max_ios}"
--verity_algorithm="${FLAGS_verity_algorithm}"
--keys_dir="${DEVKEYSDIR}"
--usb_disk="${FLAGS_usb_disk}"
--nocleanup_dirs
${crosbug12352_flag}
${enable_rootfs_verification_flag}
EOF
}
# Modifies an existing image to add development packages
update_dev_packages() {
local image_name=$1
echo "Adding developer packages to ${image_name}"
trap "mount_gpt_cleanup" EXIT
${SCRIPTS_DIR}/mount_gpt_image.sh --from "${OUTPUT_DIR}" \
--image "${image_name}" -r "${ROOT_FS_DIR}" \
-s "${STATEFUL_FS_DIR}" -e "${ESP_FS_DIR}"
# Determine the root dir for developer packages.
local root_dev_dir="${ROOT_FS_DIR}"
[ ${FLAGS_statefuldev} -eq ${FLAGS_TRUE} ] && \
root_dev_dir="${ROOT_FS_DIR}/usr/local"
# Install developer packages described in chromeos-dev.
emerge_to_image --root="${root_dev_dir}" -uDNv chromeos-dev
if [[ $FLAGS_preserve -eq ${FLAGS_TRUE} ]] ; then
# Clean out unused packages
emerge_to_image --root="${ROOT_FS_DIR}" --depclean
fi
# Install the bare necessary files so that the "emerge" command works
if [ ${FLAGS_statefuldev} -eq ${FLAGS_TRUE} ]; then
sudo cp -a ${root_dev_dir}/share/portage ${ROOT_FS_DIR}/usr/share
sudo sed -i s,/usr/bin/wget,wget, \
${ROOT_FS_DIR}/usr/share/portage/config/make.globals
fi
sudo mkdir -p ${ROOT_FS_DIR}/etc/make.profile
# Re-run ldconfig to fix /etc/ldconfig.so.cache.
sudo /sbin/ldconfig -r "${ROOT_FS_DIR}"
# Mark the image as a developer image (input to chromeos_startup).
sudo mkdir -p "${ROOT_FS_DIR}/root"
sudo touch "${ROOT_FS_DIR}/root/.dev_mode"
# Additional changes to developer image.
# Leave core files for developers to inspect.
sudo touch "${ROOT_FS_DIR}/root/.leave_core"
# This hack is only needed for devs who have old versions of glibc, which
# filtered out ldd when cross-compiling. TODO(davidjames): Remove this hack
# once everybody has upgraded to a new version of glibc.
if [[ ! -x "${ROOT_FS_DIR}/usr/bin/ldd" ]]; then
sudo cp -a "$(which ldd)" "${ROOT_FS_DIR}/usr/bin"
fi
# If vim is installed, then a vi symlink would probably help.
if [[ -x "${ROOT_FS_DIR}/usr/local/bin/vim" ]]; then
sudo ln -sf vim "${ROOT_FS_DIR}/usr/local/bin/vi"
fi
# If pygtk is installed in stateful-dev, then install a path.
if [[ -d \
"${ROOT_FS_DIR}/usr/local/lib/python2.6/site-packages/gtk-2.0" ]]; then
sudo bash -c "\
echo gtk-2.0 > \
${ROOT_FS_DIR}/usr/local/lib/python2.6/site-packages/pygtk.pth"
fi
# If python is installed on stateful-dev, fix python symlinks.
local python_path="/usr/local/bin/python2.6"
if [ -e "${ROOT_FS_DIR}${python_path}" ]; then
info "Fixing python symlinks for developer and test images."
local python_paths="/usr/bin/python /usr/local/bin/python \
/usr/bin/python2 /usr/local/bin/python2"
for path in ${python_paths}; do
sudo rm -f "${ROOT_FS_DIR}${path}"
sudo ln -s ${python_path} "${ROOT_FS_DIR}${path}"
done
fi
# Check that the image has been correctly created. Only do it if not
# building a factory install shim, as the INSTALL_MASK for it will make
# test_image fail.
if [ ${FLAGS_factory_install} -eq ${FLAGS_FALSE} ]; then
"${SCRIPTS_DIR}/test_image" \
--root="${ROOT_FS_DIR}" \
--target="${ARCH}"
fi
echo "Developer image built and stored at ${image_name}"
trap - EXIT
${SCRIPTS_DIR}/mount_gpt_image.sh -u -r "${ROOT_FS_DIR}" \
-s "${STATEFUL_FS_DIR}" -e "${ESP_FS_DIR}"
}
# Update the base package on an existing image.
update_base_packages() {
local image_name=$1
echo "Updating base packages on ${image_name}"
# Create stateful partition of the same size as the rootfs.
trap "mount_gpt_cleanup" EXIT
${SCRIPTS_DIR}/mount_gpt_image.sh --from "${OUTPUT_DIR}" \
--image "${image_name}" -r "${ROOT_FS_DIR}" \
-s "${STATEFUL_FS_DIR}" -e "${ESP_FS_DIR}"
# Emerge updated packages, exactly like when creating base image
emerge_to_image --root="${ROOT_FS_DIR}" -uDNv chromeos ${EXTRA_PACKAGES}
# Clean out unused packages
emerge_to_image --root="${ROOT_FS_DIR}" --depclean
trap - EXIT
${SCRIPTS_DIR}/mount_gpt_image.sh -u -r "${ROOT_FS_DIR}" \
-s "${STATEFUL_FS_DIR}" -e "${ESP_FS_DIR}"
}
zero_free_space() {
local fs_mount_point=$1
info "Zeroing freespace in ${fs_mount_point}"
# dd is a silly thing and will produce a "No space left on device" message
# that cannot be turned off and is confusing to unsuspecting victims.
( sudo dd if=/dev/zero of="${fs_mount_point}/filler" oflag=sync bs=4096 \
|| true ) 2>&1 |grep -v "No space left on device"
sudo rm -f "${fs_mount_point}/filler"
sudo sync
}
create_base_image() {
local image_name=$1
trap "cleanup && delete_prompt" EXIT
# Create and format the root file system.
# Check for loop device before creating image.
LOOP_DEV=$(sudo losetup -f)
if [ -z "${LOOP_DEV}" ] ; then
echo "No free loop device. Free up a loop device or reboot. exiting. "
exit 1
fi
# Create root file system disk image.
ROOT_SIZE_BYTES=$((1024 * 1024 * ${FLAGS_rootfs_size}))
# Pad out for the hash tree.
ROOT_HASH_PAD=$((FLAGS_rootfs_hash_pad * 1024 * 1024))
info "Padding the rootfs image by ${ROOT_HASH_PAD} bytes for hash data"
dd if=/dev/zero of="${ROOT_FS_IMG}" bs=1 count=1 \
seek=$((ROOT_SIZE_BYTES + ROOT_HASH_PAD - 1))
sudo losetup "${LOOP_DEV}" "${ROOT_FS_IMG}"
# Specify a block size and block count to avoid using the hash pad.
sudo mkfs.ext2 -b 4096 "${LOOP_DEV}" "$((ROOT_SIZE_BYTES / 4096))"
# Tune and mount rootfs.
DISK_LABEL="C-ROOT"
# Disable checking and minimize metadata differences across builds
# and wasted reserved space.
sudo tune2fs -L "${DISK_LABEL}" \
-U clear \
-T 20091119110000 \
-c 0 \
-i 0 \
-m 0 \
-r 0 \
-e remount-ro \
"${LOOP_DEV}"
# TODO(wad) call tune2fs prior to finalization to set the mount count to 0.
sudo mount -t ext2 "${LOOP_DEV}" "${ROOT_FS_DIR}"
# Create stateful partition of the same size as the rootfs.
STATEFUL_LOOP_DEV=$(sudo losetup -f)
if [ -z "${STATEFUL_LOOP_DEV}" ] ; then
echo "No free loop device. Free up a loop device or reboot. exiting. "
exit 1
fi
STATEFUL_SIZE_BYTES=$((1024 * 1024 * ${FLAGS_statefulfs_size}))
dd if=/dev/zero of="${STATEFUL_FS_IMG}" bs=1 count=1 \
seek=$((STATEFUL_SIZE_BYTES - 1))
# Tune and mount the stateful partition.
UUID=$(uuidgen)
DISK_LABEL="C-STATE"
sudo losetup "${STATEFUL_LOOP_DEV}" "${STATEFUL_FS_IMG}"
sudo mkfs.ext3 "${STATEFUL_LOOP_DEV}"
sudo tune2fs -L "${DISK_LABEL}" -U "${UUID}" -c 0 -i 0 "${STATEFUL_LOOP_DEV}"
sudo mount -t ext3 "${STATEFUL_LOOP_DEV}" "${STATEFUL_FS_DIR}"
# -- Install packages into the root file system --
# We need to install libc manually from the cross toolchain.
# TODO: Improve this? We only want libc and not the whole toolchain.
# TODO(raymes): Remove this check after some time which ensures
# backward compatibility with the crossdev location change.
PKGDIR="/var/lib/portage/pkgs"
LIBC_TAR="glibc-${LIBC_VERSION}.tbz2"
NEW_LIBC_PATH="${PKGDIR}/cross-${CHOST}/${LIBC_TAR}"
OLD_LIBC_PATH="${PKGDIR}/cross/${CHOST}/cross-${CHOST}/${LIBC_TAR}"
if [ -e "${NEW_LIBC_PATH}" ] ; then
LIBC_PATH="${NEW_LIBC_PATH}"
else
LIBC_PATH="${OLD_LIBC_PATH}"
fi
sudo tar jxvpf "${LIBC_PATH}" -C "${ROOT_FS_DIR}" --strip-components=3 \
--exclude=usr/include --exclude=sys-include --exclude=*.a --exclude=*.o
# We need to install libstdc++ manually from the cross toolchain.
# TODO: Figure out a better way of doing this?
sudo cp -a "${BOARD_ROOT}"/lib/libgcc_s.so* "${ROOT_FS_DIR}/lib"
sudo cp -a "${BOARD_ROOT}"/usr/lib/libstdc++.so* "${ROOT_FS_DIR}/usr/lib"
# Prepare stateful partition with some pre-created directories.
sudo mkdir -p "${DEV_IMAGE_ROOT}"
sudo mkdir -p "${STATEFUL_FS_DIR}/var"
# Create symlinks so that /usr/local/usr based directories are symlinked to
# /usr/local/ directories e.g. /usr/local/usr/bin -> /usr/local/bin, etc.
setup_symlinks_on_root "${DEV_IMAGE_ROOT}" "${STATEFUL_FS_DIR}/var" \
"${STATEFUL_FS_DIR}"
# Perform binding rather than symlinking because directories must exist
# on rootfs so that we can bind at run-time since rootfs is read-only.
echo "Binding directories from stateful partition onto the rootfs"
sudo mkdir -p "${ROOT_FS_DIR}/usr/local"
sudo mount --bind "${DEV_IMAGE_ROOT}" "${ROOT_FS_DIR}/usr/local"
sudo mkdir -p "${ROOT_FS_DIR}/var"
sudo mount --bind "${STATEFUL_FS_DIR}/var" "${ROOT_FS_DIR}/var"
sudo mkdir -p "${ROOT_FS_DIR}/dev"
# We "emerge --root=${ROOT_FS_DIR} --root-deps=rdeps --usepkgonly" all of the
# runtime packages for chrome os. This builds up a chrome os image from
# binary packages with runtime dependencies only. We use INSTALL_MASK to
# trim the image size as much as possible.
emerge_to_image --root="${ROOT_FS_DIR}" chromeos ${EXTRA_PACKAGES}
# Set /etc/lsb-release on the image.
"${OVERLAY_CHROMEOS_DIR}/scripts/cros_set_lsb_release" \
--root="${ROOT_FS_DIR}" \
--board="${BOARD}"
# Populates the root filesystem with legacy bootloader templates
# appropriate for the platform. The autoupdater and installer will
# use those templates to update the legacy boot partition (12/ESP)
# on update.
# (This script does not populate vmlinuz.A and .B needed by syslinux.)
enable_rootfs_verification=
if [[ ${FLAGS_enable_rootfs_verification} -eq ${FLAGS_TRUE} ]]; then
enable_rootfs_verification="--enable_rootfs_verification"
fi
${SCRIPTS_DIR}/create_legacy_bootloader_templates.sh \
--arch=${ARCH} \
--to="${ROOT_FS_DIR}"/boot \
--boot_args="${FLAGS_boot_args}" \
--install \
${enable_rootfs_verification}
# Don't test the factory install shim
if [ ${FLAGS_factory_install} -eq ${FLAGS_FALSE} ]; then
# Check that the image has been correctly created.
"${SCRIPTS_DIR}/test_image" \
--root="${ROOT_FS_DIR}" \
--target="${ARCH}"
fi
# Clean up symlinks so they work on a running target rooted at "/".
# Here development packages are rooted at /usr/local. However, do not
# create /usr/local or /var on host (already exist on target).
setup_symlinks_on_root "/usr/local" "/var" "${STATEFUL_FS_DIR}"
# cros_make_image_bootable will clobber vmlinuz.image for x86.
# Until then, just copy the kernel to vmlinuz.image. It is
# expected in build_gpt.sh.
cp "${ROOT_FS_DIR}/boot/vmlinuz" "${OUTPUT_DIR}/vmlinuz.image"
# Create an empty esp image to be updated in by update_bootloaders.sh.
${SCRIPTS_DIR}/create_esp.sh --to="${ESP_FS_IMG}"
# Zero rootfs free space to make it more compressible so auto-update
# payloads become smaller
zero_free_space "${ROOT_FS_DIR}"
cleanup
trap delete_prompt EXIT
# Create the GPT-formatted image.
${SCRIPTS_DIR}/build_gpt.sh \
--arch=${ARCH} \
--board=${FLAGS_board} \
--rootfs_partition_size=${FLAGS_rootfs_partition_size} \
"${OUTPUT_DIR}" \
"${OUTPUT_DIR}/${image_name}"
# Pre-set "sucessful" bit in gpt, so we will never mark-for-death
# a partition on an SDCard/USB stick.
${GPT} add -i 2 -S 1 "${OUTPUT_DIR}/${image_name}"
trap - EXIT
}
generate_au_zip () {
local lgenerateauzip="${SCRIPTS_DIR}/generate_au_zip.py"
local largs="-o ${OUTPUT_DIR}"
test ! -d "${OUTPUT_DIR}" && mkdir -p "${OUTPUT_DIR}"
info "Running ${lgenerateauzip} ${largs} for generating AU updater zip file"
$lgenerateauzip $largs
}
# Create the output directory.
mkdir -p "${OUTPUT_DIR}"
mkdir -p "${ROOT_FS_DIR}"
mkdir -p "${STATEFUL_FS_DIR}"
mkdir -p "${ESP_FS_DIR}"
# Preserve old images by copying them forward for --preserve.
if [[ $FLAGS_preserve -eq ${FLAGS_TRUE} ]] ; then
if [[ -f ${PREVIOUS_DIR}/${PRISTINE_IMAGE_NAME} ]] ; then
# Copy forward pristine image, and associated files
cp ${PREVIOUS_DIR}/*.sh ${PREVIOUS_DIR}/config.txt ${OUTPUT_DIR}
cp ${PREVIOUS_DIR}/${PRISTINE_IMAGE_NAME} ${OUTPUT_DIR}
# Copy forward the developer image, if we already copied forward the base.
if [[ ${FLAGS_withdev} -eq ${FLAGS_TRUE} ]] && \
[[ -f ${PREVIOUS_DIR}/${DEVELOPER_IMAGE_NAME} ]] ; then
cp ${PREVIOUS_DIR}/${DEVELOPER_IMAGE_NAME} ${OUTPUT_DIR}
fi
fi
fi
# Create the boot.desc file which stores the build-time configuration
# information needed for making the image bootable after creation with
# cros_make_image_bootable.
create_boot_desc
if [[ -f ${PRISTINE_IMG} ]] ; then
update_base_packages ${PRISTINE_IMAGE_NAME}
else
create_base_image ${PRISTINE_IMAGE_NAME}
fi
USE_DEV_KEYS=
if [ ${FLAGS_factory_install} -eq ${FLAGS_TRUE} ]; then
USE_DEV_KEYS="--use_dev_keys"
fi
# Place flags before positional args
${SCRIPTS_DIR}/bin/cros_make_image_bootable "${OUTPUT_DIR}" \
"${PRISTINE_IMAGE_NAME}" \
${USE_DEV_KEYS} \
${crosbug12352_flag}
# FIXME Test x86 image, and test arm image if enabled;
# should unconditionally test an image after crosbug12352 is fixed
if [[ "${ARCH}" = "x86" ]] ||
[[ "${ARCH}" = "arm" &&
${FLAGS_crosbug12352_arm_kernel_signing} -eq ${FLAGS_TRUE} ]]; then
BOOT_FLAG=
if [ ${FLAGS_factory_install} -eq ${FLAGS_TRUE} ]; then
BOOT_FLAG="-b 1" # BOOT_FLAG_DEVELOPER value defined in load_kernel_fw.h
info "--factory_install set, pass BOOT_FLAG_DEVELOPER flag to \
load_kernel_test"
fi
# Verify the final image.
load_kernel_test "${OUTPUT_DIR}/${PRISTINE_IMAGE_NAME}" \
"${DEVKEYSDIR}/recovery_key.vbpubk" ${BOOT_FLAG}
fi
# Create a developer image based on the chromium os base image.
if [ ${FLAGS_withdev} -eq ${FLAGS_TRUE} ] ; then
if [[ ! -f ${DEVELOPER_IMG} ]] ; then
echo "Creating developer image from base image ${PRISTINE_IMAGE_NAME}"
cp ${PRISTINE_IMG} ${DEVELOPER_IMG}
fi
update_dev_packages ${DEVELOPER_IMAGE_NAME}
${SCRIPTS_DIR}/bin/cros_make_image_bootable "${OUTPUT_DIR}" \
"${DEVELOPER_IMAGE_NAME}" \
${crosbug12352_flag}
fi
# Clean up temporary files.
rm -f "${ROOT_FS_IMG}" "${STATEFUL_FS_IMG}" "${OUTPUT_DIR}/vmlinuz.image" \
"${ESP_FS_IMG}" "${OUTPUT_DIR}/vmlinuz_hd.vblock"
rmdir "${ROOT_FS_DIR}" "${STATEFUL_FS_DIR}" "${ESP_FS_DIR}"
# Generating AU generator zip file to run outside chroot
generate_au_zip || echo "Failed generating AU zip file - ignoring Error..."
# Create a 'latest' link
rm -f ${FLAGS_output_root}/${FLAGS_board}/latest
ln -s $(basename ${OUTPUT_DIR}) ${FLAGS_output_root}/${FLAGS_board}/latest
echo "Done. Image created in ${OUTPUT_DIR}"
echo "Chromium OS image created as ${PRISTINE_IMAGE_NAME}"
if [ ${FLAGS_withdev} -eq ${FLAGS_TRUE} ]; then
echo "Developer image created as ${DEVELOPER_IMAGE_NAME}"
fi
print_time_elapsed
echo "To copy to USB keyfob, do something like:"
echo " ./image_to_usb.sh --from=${OUTSIDE_OUTPUT_DIR} --to=/dev/sdX"
echo "To convert to VMWare image, INSIDE the chroot, do something like:"
echo " ./image_to_vm.sh --from=${OUTSIDE_OUTPUT_DIR} --board=${BOARD}"
echo "from the scripts directory where you entered the chroot."