mirror of
https://github.com/flatcar/scripts.git
synced 2025-08-15 00:46:58 +02:00
The main benefit of this change is that it is no longer necessary to specify custom use flags to build_image because it just merges what you already have installed in your buildroot. It does not second guess the packages you already have installed and just installs them, as it should. 1. Packages in the developer image should already be up to date, so there is no need to specify '-u' for --update or '-D' for --deep. 2. The developer image should have identical use flags to the base image, so there is no need to specify -N for '--newuse'. 3. The --verbose flag is generally useful, so I've updated all emerges to use them so you can see what the use flags are used for the emerges. BUG=chromium-os:19078 TEST=Verify build_image builds same image and installs same packages with and without change. Verified specifying USE= is not necessary if a few dev packages were customized. Change-Id: I4c205c961cca84ca3161b49f59cdd37a5a4ed5b1 Reviewed-on: http://gerrit.chromium.org/gerrit/5816 Reviewed-by: Mike Frysinger <vapier@chromium.org> Reviewed-by: Richard Barnette <jrbarnette@chromium.org> Reviewed-by: Don Garrett <dgarrett@chromium.org> Tested-by: David James <davidjames@chromium.org>
839 lines
29 KiB
Bash
Executable File
839 lines
29 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.
|
|
|
|
SCRIPT_ROOT=$(dirname "$0")
|
|
. "${SCRIPT_ROOT}/build_library/build_common.sh" || exit 1
|
|
|
|
|
|
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_boolean test ${FLAGS_FALSE} \
|
|
"Modify the image for automated testing"
|
|
DEFINE_boolean factory ${FLAGS_FALSE} \
|
|
"Modify the image for manufacturing testing"
|
|
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 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"
|
|
|
|
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"
|
|
DEFINE_boolean standard_backdoor ${FLAGS_TRUE} \
|
|
"Install standard backdoor credentials for testing"
|
|
DEFINE_string symlink "latest" \
|
|
"Symlink name to use for this image."
|
|
|
|
# TODO(clchiou): Remove this flag after buildbot is fixed
|
|
DEFINE_boolean crosbug12352_arm_kernel_signing ${FLAGS_TRUE} \
|
|
"A dummy this flag for preventing buildbot fail"
|
|
|
|
# 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
|
|
|
|
. "${SCRIPT_ROOT}/build_library/board_options.sh" || exit 1
|
|
|
|
# Determine build version.
|
|
OVERLAY_CHROMEOS_DIR="${SRC_ROOT}/third_party/chromiumos-overlay/chromeos"
|
|
. "${OVERLAY_CHROMEOS_DIR}/config/chromeos_version.sh" || exit 1
|
|
|
|
. "${SCRIPT_ROOT}/build_library/build_gpt.sh" || exit 1
|
|
|
|
|
|
EMERGE_BOARD_CMD="emerge-$BOARD"
|
|
if [ $FLAGS_fast -eq $FLAGS_TRUE ]; then
|
|
echo "Using alternate emerge"
|
|
EMERGE_BOARD_CMD="$GCLIENT_ROOT/chromite/bin/parallel_emerge"
|
|
EMERGE_BOARD_CMD="$EMERGE_BOARD_CMD --board=$BOARD"
|
|
fi
|
|
if [ $FLAGS_jobs -ne -1 ]; then
|
|
EMERGE_JOBS="--jobs=$FLAGS_jobs"
|
|
fi
|
|
|
|
# Perform an eclean to remove packages which are not installed
|
|
if [ $FLAGS_eclean -eq $FLAGS_TRUE ]; then
|
|
eclean-$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="${BUILD_LIBRARY_DIR}/chromeos_blacklist"
|
|
if [ ! -e "${package_blacklist_file}" ]; then
|
|
warn "Missing blacklist file."
|
|
return
|
|
fi
|
|
local blacklisted_packages=$(${SCRIPTS_DIR}/get_package_list \
|
|
--board="${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
|
|
|
|
# Look at flags to determine which image types we should build
|
|
if [ ${FLAGS_factory_install} -eq ${FLAGS_TRUE} ]; then
|
|
if [ ${FLAGS_factory} -eq ${FLAGS_TRUE} ]; then
|
|
info "Incompatible flags: --factory and --factory_install cannot both be \
|
|
set to True. Resetting --factory to False."
|
|
FLAGS_factory=${FLAGS_FALSE}
|
|
fi
|
|
if [ ${FLAGS_test} -eq ${FLAGS_TRUE} ]; then
|
|
info "Incompatible flags: --test and --factory_install cannot both be \
|
|
set to True. Resetting --test to False."
|
|
FLAGS_test=${FLAGS_FALSE}
|
|
fi
|
|
# 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
|
|
fi
|
|
if [ ${FLAGS_factory} -eq ${FLAGS_TRUE} ]; then
|
|
if [ ${FLAGS_test} -eq ${FLAGS_FALSE} ]; then
|
|
info "Incompatible flags: --factory implies --test. Resetting --test to \
|
|
True."
|
|
FLAGS_test=${FLAGS_TRUE}
|
|
fi
|
|
fi
|
|
if [ ${FLAGS_test} -eq ${FLAGS_TRUE} ]; then
|
|
if [ ${FLAGS_withdev} -eq ${FLAGS_FALSE} ]; then
|
|
info "Incompatible flags: --test implies --withdev. Resetting --withdev \
|
|
to True."
|
|
FLAGS_withdev=${FLAGS_TRUE}
|
|
fi
|
|
fi
|
|
|
|
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
|
|
# 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
|
|
|
|
# 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 -v \
|
|
"$@" ${EMERGE_JOBS}
|
|
}
|
|
|
|
# Check that the build root is sane.
|
|
"${BUILD_LIBRARY_DIR}/test_build_root" --root="${BOARD_ROOT}"
|
|
|
|
# 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}/${BOARD}/${IMAGE_SUBDIR}"
|
|
|
|
OUTSIDE_OUTPUT_DIR="../build/images/${BOARD}/${IMAGE_SUBDIR}"
|
|
|
|
# If we are creating a developer image, also create a pristine image with a
|
|
# different name.
|
|
# TODO(vlaviano): fix all image names to match those in uploaded archive
|
|
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}"
|
|
TEST_IMG="${OUTPUT_DIR}/${CHROMEOS_TEST_IMAGE_NAME}"
|
|
FACTORY_IMG="${OUTPUT_DIR}/${CHROMEOS_FACTORY_TEST_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=
|
|
|
|
# ${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_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
|
|
|
|
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() {
|
|
# 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
|
|
|
|
# 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
|
|
${enable_rootfs_verification_flag}
|
|
EOF
|
|
}
|
|
|
|
# Modifies an existing image to add development packages
|
|
install_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}" chromeos-dev
|
|
|
|
# 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).
|
|
# TODO(arkaitzr): Remove this file when applications no longer rely on it
|
|
# (crosbug.com/16648). The preferred way of determining developer mode status
|
|
# is via crossystem cros_debug?1 (checks boot args for "cros_debug").
|
|
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
|
|
"${BUILD_LIBRARY_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}"
|
|
}
|
|
|
|
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" bs=4096 \
|
|
|| true ) 2>&1 |grep -v "No space left on device"
|
|
sudo sync
|
|
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.
|
|
|
|
# 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))
|
|
|
|
LOOP_DEV=$(sudo losetup --show -f "${ROOT_FS_IMG}")
|
|
if [ -z "${LOOP_DEV}" ] ; then
|
|
echo "No free loop device. Free up a loop device or reboot. exiting. "
|
|
exit 1
|
|
fi
|
|
|
|
# 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_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"
|
|
STATEFUL_LOOP_DEV=$(sudo losetup --show -f "${STATEFUL_FS_IMG}")
|
|
if [ -z "${STATEFUL_LOOP_DEV}" ] ; then
|
|
echo "No free loop device. Free up a loop device or reboot. exiting. "
|
|
exit 1
|
|
fi
|
|
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 --
|
|
|
|
# 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 need to install libc manually from the cross toolchain.
|
|
# TODO: Improve this? It would be ideal to use emerge to do this.
|
|
PKGDIR="/var/lib/portage/pkgs"
|
|
LIBC_TAR="glibc-${LIBC_VERSION}.tbz2"
|
|
LIBC_PATH="${PKGDIR}/cross-${CHOST}/${LIBC_TAR}"
|
|
|
|
sudo tar jxvpf "${LIBC_PATH}" -C "${ROOT_FS_DIR}" ./usr/${CHOST} \
|
|
--strip-components=3 --exclude=usr/include --exclude=sys-include \
|
|
--exclude=*.a --exclude=*.o
|
|
|
|
# If it's a developer image, also copy over the libc debug info so that gdb
|
|
# works with threads and also for a better debugging experience.
|
|
if [[ ${FLAGS_withdev} -eq ${FLAGS_TRUE} ]] ; then
|
|
sudo mkdir -p "${ROOT_FS_DIR}/usr/local/lib/debug"
|
|
sudo tar jxvpf "${LIBC_PATH}" -C "${ROOT_FS_DIR}/usr/local/lib/debug" \
|
|
./usr/lib/debug/usr/${CHOST} --strip-components=6
|
|
fi
|
|
|
|
. "${SRC_ROOT}/platform/dev/toolchain_utils.sh"
|
|
board_ctarget=$(get_ctarget_from_board "${BOARD}")
|
|
for atom in $(portageq match / cross-$board_ctarget/gcc); do
|
|
copy_gcc_libs "${ROOT_FS_DIR}" $atom
|
|
done
|
|
|
|
if [ ${FLAGS_factory_install} -eq ${FLAGS_TRUE} ]; then
|
|
# Install our custom factory install kernel with the appropriate use flags
|
|
# to the image.
|
|
emerge_custom_kernel "${ROOT_FS_DIR}"
|
|
fi
|
|
|
|
# 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
|
|
|
|
${BUILD_LIBRARY_DIR}/create_legacy_bootloader_templates.sh \
|
|
--arch=${ARCH} \
|
|
--to="${ROOT_FS_DIR}"/boot \
|
|
--boot_args="${FLAGS_boot_args}" \
|
|
${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.
|
|
"${BUILD_LIBRARY_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}"
|
|
|
|
# Create EFI System Partition to boot stock EFI BIOS (but not
|
|
# ChromeOS EFI BIOS). ARM uses this space to determine which
|
|
# partition is bootable. NOTE: The size argument for mkfs.vfat is
|
|
# in 1024-byte blocks. We'll hard-code it to 16M for now.
|
|
/usr/sbin/mkfs.vfat -C "${ESP_FS_IMG}" 16384
|
|
|
|
# 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.
|
|
build_gpt "${OUTPUT_DIR}/${image_name}" \
|
|
"${ROOT_FS_IMG}" \
|
|
"${STATEFUL_FS_IMG}" \
|
|
"${ESP_FS_IMG}"
|
|
|
|
# Emit helpful scripts for testers, etc.
|
|
emit_gpt_scripts "${OUTPUT_DIR}/${image_name}" "${OUTPUT_DIR}"
|
|
|
|
trap - EXIT
|
|
}
|
|
|
|
generate_au_zip () {
|
|
local lgenerateauzip="${BUILD_LIBRARY_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
|
|
}
|
|
|
|
mod_image_for_test_cleanup() {
|
|
"${SCRIPTS_DIR}/mount_gpt_image.sh" -u -r "${ROOT_FS_DIR}" \
|
|
-s "${STATEFUL_FS_DIR}"
|
|
}
|
|
|
|
# Emerges chromeos-test onto the image.
|
|
emerge_chromeos_test() {
|
|
# Determine the root dir for test packages.
|
|
local root_dev_dir="${ROOT_FS_DIR}/usr/local"
|
|
|
|
emerge_to_image --root="${root_dev_dir}" chromeos-test
|
|
}
|
|
|
|
install_autotest_for_factory() {
|
|
local autotest_src="${BOARD_ROOT}/usr/local/autotest"
|
|
local stateful_root="${ROOT_FS_DIR}/usr/local"
|
|
local autotest_client="${stateful_root}/autotest"
|
|
|
|
echo "Install autotest into stateful partition from ${autotest_src}"
|
|
|
|
sudo mkdir -p "${autotest_client}"
|
|
|
|
# Remove excess files from stateful partition.
|
|
sudo rm -rf "${autotest_client}/"*
|
|
sudo rm -rf "${stateful_root}/autotest-pkgs"
|
|
sudo rm -rf "${stateful_root}/lib/icedtea6"
|
|
|
|
sudo rsync --delete --delete-excluded -au \
|
|
--exclude=deps/realtimecomm_playground \
|
|
--exclude=tests/ltp \
|
|
--exclude=site_tests/graphics_O3DSelenium \
|
|
--exclude=site_tests/realtimecomm_GTalk\* \
|
|
--exclude=site_tests/platform_StackProtector \
|
|
--exclude=deps/chrome_test \
|
|
--exclude=site_tests/desktopui_BrowserTest \
|
|
--exclude=site_tests/desktopui_PageCyclerTests \
|
|
--exclude=site_tests/desktopui_UITest \
|
|
--exclude=.svn \
|
|
"${autotest_src}/client/"* "${autotest_client}"
|
|
|
|
sudo chmod 755 "${autotest_client}"
|
|
sudo chown -R 1000:1000 "${autotest_client}"
|
|
}
|
|
|
|
# convert a dev image into a test or factory test image
|
|
mod_image_for_test () {
|
|
local image_to_mod=$1
|
|
|
|
# Copy the image to a test location before modifying it
|
|
local test_pathname="${TEST_IMG}"
|
|
local typename="test"
|
|
if [ ${FLAGS_factory} -eq ${FLAGS_TRUE} ]; then
|
|
test_pathname="${FACTORY_IMG}"
|
|
typename="factory"
|
|
fi
|
|
echo "Creating ${typename} image from original..."
|
|
${COMMON_PV_CAT} ${image_to_mod} > ${test_pathname} ||
|
|
die "Cannot copy ${image_to_mod} to ${typename} image"
|
|
# Abort early if we can't find the image
|
|
if [ ! -f ${test_pathname} ] ; then
|
|
die "No image found at ${test_pathname} to modify"
|
|
fi
|
|
echo "Modifying image ${test_pathname} for ${typename}..."
|
|
|
|
local image_dir=$(dirname ${test_pathname})
|
|
local image_name=$(basename ${test_pathname})
|
|
|
|
trap mod_image_for_test_cleanup EXIT
|
|
|
|
# Mounts gpt image and sets up var, /usr/local and symlinks.
|
|
"${SCRIPTS_DIR}/mount_gpt_image.sh" -i "${image_name}" -f "${image_dir}" \
|
|
-r "${ROOT_FS_DIR}" -s "${STATEFUL_FS_DIR}"
|
|
|
|
emerge_chromeos_test
|
|
|
|
BACKDOOR=0
|
|
if [ $FLAGS_standard_backdoor -eq $FLAGS_TRUE ]; then
|
|
BACKDOOR=1
|
|
fi
|
|
|
|
local mod_test_script="${SCRIPTS_DIR}/mod_for_test_scripts/test_setup.sh"
|
|
# Run test setup script to modify the image
|
|
sudo -E GCLIENT_ROOT="${GCLIENT_ROOT}" ROOT_FS_DIR="${ROOT_FS_DIR}" \
|
|
STATEFUL_DIR="${STATEFUL_FS_DIR}" ARCH="${ARCH}" BACKDOOR="${BACKDOOR}" \
|
|
"${mod_test_script}"
|
|
|
|
if [ ${FLAGS_factory} -eq ${FLAGS_TRUE} ]; then
|
|
emerge_to_image --root="${ROOT_FS_DIR}" factorytest-init
|
|
|
|
install_autotest_for_factory
|
|
|
|
local mod_factory_script
|
|
mod_factory_script="${SCRIPTS_DIR}/mod_for_factory_scripts/factory_setup.sh"
|
|
# Run factory setup script to modify the image
|
|
sudo -E GCLIENT_ROOT="${GCLIENT_ROOT}" ROOT_FS_DIR="${ROOT_FS_DIR}" \
|
|
BOARD="${BOARD}" "${mod_factory_script}"
|
|
fi
|
|
|
|
# Re-run ldconfig to fix /etc/ldconfig.so.cache.
|
|
sudo ldconfig -r "${ROOT_FS_DIR}"
|
|
|
|
mod_image_for_test_cleanup
|
|
|
|
# Now make it bootable with the flags from build_image
|
|
"${SCRIPTS_DIR}/bin/cros_make_image_bootable" "${image_dir}" "${image_name}" \
|
|
--force_developer_mode
|
|
|
|
print_time_elapsed
|
|
|
|
trap - EXIT
|
|
}
|
|
|
|
# Create the output directory.
|
|
mkdir -p "${OUTPUT_DIR}"
|
|
mkdir -p "${ROOT_FS_DIR}"
|
|
mkdir -p "${STATEFUL_FS_DIR}"
|
|
mkdir -p "${ESP_FS_DIR}"
|
|
|
|
# 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
|
|
|
|
create_base_image ${PRISTINE_IMAGE_NAME}
|
|
|
|
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}
|
|
|
|
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}
|
|
|
|
# Create a developer image based on the chromium os base image.
|
|
if [ ${FLAGS_withdev} -eq ${FLAGS_TRUE} ] ; then
|
|
cp ${PRISTINE_IMG} ${DEVELOPER_IMG}
|
|
install_dev_packages ${DEVELOPER_IMAGE_NAME}
|
|
${SCRIPTS_DIR}/bin/cros_make_image_bootable "${OUTPUT_DIR}" \
|
|
"${DEVELOPER_IMAGE_NAME}" \
|
|
--force_developer_mode
|
|
fi
|
|
|
|
# Create a test or factory test image if desired
|
|
if [ ${FLAGS_test} -eq ${FLAGS_TRUE} ] ; then
|
|
mod_image_for_test ${DEVELOPER_IMG}
|
|
fi
|
|
|
|
# Clean up temporary files.
|
|
rm -f "${ROOT_FS_IMG}" "${STATEFUL_FS_IMG}" "${ESP_FS_IMG}"
|
|
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 named symlink.
|
|
LINK_NAME="${FLAGS_output_root}/${BOARD}/${FLAGS_symlink}"
|
|
ln -sfT $(basename ${OUTPUT_DIR}) ${LINK_NAME}
|
|
|
|
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
|
|
if [ ${FLAGS_factory} -eq ${FLAGS_TRUE} ]; then
|
|
echo "Factory test image created as ${CHROMEOS_FACTORY_TEST_IMAGE_NAME}"
|
|
elif [ ${FLAGS_test} -eq ${FLAGS_TRUE} ]; then
|
|
echo "Test image created as ${CHROMEOS_TEST_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."
|