diff --git a/bin/cros_make_image_bootable b/bin/cros_make_image_bootable deleted file mode 100755 index 6d33cf1cfd..0000000000 --- a/bin/cros_make_image_bootable +++ /dev/null @@ -1,299 +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 which ensures that a given image has an up-to-date -# kernel partition, rootfs integrity hashes, and legacy bootloader configs. - -# --- 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=("$(dirname "$(readlink -f "$0")")/.." /usr/lib/crosutils) - local path - - SCRIPT_ROOT="${common_paths[0]}" - 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" || exit 1 -# --- END COMMON.SH BOILERPLATE --- - -# Need to be inside the chroot to load chromeos-common.sh -assert_inside_chroot - -# Load functions and constants for chromeos-install -. /usr/lib/installer/chromeos-common.sh || exit 1 -. "${BUILD_LIBRARY_DIR}/toolchain_util.sh" || exit 1 -. "${BUILD_LIBRARY_DIR}/build_image_util.sh" || exit 1 -. "${BUILD_LIBRARY_DIR}/disk_layout_util.sh" || exit 1 - -switch_to_strict_mode - -if [ $# -lt 2 ]; then - echo "Usage: ${0} /PATH/TO/IMAGE IMAGE.BIN [shflags overrides]" - exit 1 -fi - -IMAGE_DIR="$(readlink -f "${1}")" -BOOT_DESC_FILE="${IMAGE_DIR}/boot.desc" -IMAGE="${IMAGE_DIR}/${2}" -shift -shift -FLAG_OVERRIDES="${@}" - -if [ ! -r "${BOOT_DESC_FILE}" ]; then - warn "${BOOT_DESC_FILE} cannot be read!" - warn "Falling back to command line parsing" - BOOT_DESC="${@}" -else - BOOT_DESC="$(cat ${BOOT_DESC_FILE} | tr -s '\n' ' ')" - info "Boot-time configuration for $(dirname "${IMAGE}"): " - cat ${BOOT_DESC_FILE} | while read line; do - info " ${line}" - done -fi - -if [ ! -r "${IMAGE}" ]; then - die "${IMAGE} cannot be read!" -fi - - -locate_gpt -set +e - -# Now parse the build settings from ${OUTPUT_DIR}/boot.desc -DEFINE_string adjust_part "" \ - "Adjustments to apply to the partition table" -DEFINE_string board "${DEFAULT_BOARD}" \ - "Board we're building for." -DEFINE_string output_dir "/tmp" \ - "Directory to place output in." -DEFINE_string image "coreos_base.img" \ - "Full path to the coreos image to make bootable." -DEFINE_string arch "x86" \ - "Architecture to make bootable for: arm, x86, or amd64" -DEFINE_boolean cleanup_dirs ${FLAGS_TRUE} \ - "Whether the mount dirs should be removed on completion." - -DEFINE_string boot_args "noinitrd" \ - "Additional boot arguments to pass to the commandline" - -DEFINE_boolean enable_rootfs_verification ${FLAGS_FALSE} \ - "Default all bootloaders to NOT use kernel-based root fs integrity checking." - -DEFINE_string keys_dir "/usr/share/vboot/devkeys" \ - "Directory containing the signing keys." - -DEFINE_string au_key "" \ - "Filename of the au_key to install" - -DEFINE_string production_track "" \ - "Use production values and a given track for update service." - -DEFINE_string rootfs_mountpoint "/tmp/rootfs" \ - "Path where the rootfs can be safely mounted" -DEFINE_string statefulfs_mountpoint "/tmp/statefulfs" \ - "Path where the statefulfs can be safely mounted" -DEFINE_string espfs_mountpoint "/tmp/espfs" \ - "Path where the espfs can be safely mounted" - -DEFINE_boolean use_dev_keys ${FLAGS_FALSE} \ - "Use developer keys for signing. (Default: false)" - -DEFINE_boolean fsck_rootfs ${FLAGS_FALSE} \ - "Check integrity of the rootfs on the modified image." - -# TODO(pkumar): Remove once known that no images are using this flag -DEFINE_boolean crosbug12352_arm_kernel_signing ${FLAGS_FALSE} \ - "This flag is deprecated but the bots still need parse old images." - -# TODO(sosa): Remove once known images no longer use this in their config. -DEFINE_string arm_extra_bootargs "" "DEPRECATED FLAG. Do not use." - -DEFINE_boolean force_developer_mode ${FLAGS_FALSE} \ - "Add cros_debug to boot args." - -DEFINE_boolean enable_squashfs ${FLAGS_FALSE} \ - "Make the rootfs of the image squashfs." -DEFINE_string squash_sort_file "" \ - "Specify the priority of files when squashing the rootfs." - - -# Parse the boot.desc and any overrides -eval set -- "${BOOT_DESC} ${FLAG_OVERRIDES}" -FLAGS "${@}" || exit 1 - -. "${BUILD_LIBRARY_DIR}/board_options.sh" || exit 1 - -# Only now can we die on error. shflags functions leak non-zero error codes, -# so will die prematurely if 'switch_to_strict_mode' is specified before now. -switch_to_strict_mode -u - -# $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-$FLAGS_rootfs_mountpoint}" - local statefs="${2-$FLAGS_statefulfs_mountpoint}" - local espfs="${3-$FLAGS_espfs_mountpoint}" - "${SCRIPTS_DIR}/mount_gpt_image.sh" \ - -u -r "${rootfs}" -s "${statefs}" -e "${espfs}" -} - -make_image_bootable() { - local image="$1" - local use_dev_keys= - - # Default to non-verified - local enable_rootfs_verification_flag=--noenable_rootfs_verification - if [[ ${FLAGS_enable_rootfs_verification} -eq ${FLAGS_TRUE} ]]; then - enable_rootfs_verification_flag=--enable_rootfs_verification - fi - - trap "mount_gpt_cleanup" EXIT - "${SCRIPTS_DIR}/mount_gpt_image.sh" --from "$(dirname "${image}")" \ - --image "$(basename ${image})" -r "${FLAGS_rootfs_mountpoint}" \ - -s "${FLAGS_statefulfs_mountpoint}" - - legacy_offset_size_export ${image} - - if [ -n "${FLAGS_production_track}" ]; then - # Replace /etc/lsb-release on the image. - "${BUILD_LIBRARY_DIR}/set_lsb_release" \ - --production_track="${FLAGS_production_track}" \ - --root="${FLAGS_rootfs_mountpoint}" \ - --board="${BOARD}" - fi - - # Install an auto update key on the root before sealing it off - if [ ! -z "${FLAGS_au_key}" ]; then - local key_location=${FLAGS_rootfs_mountpoint}"/usr/share/update_engine/" - sudo mkdir -p "${key_location}" - sudo cp "${FLAGS_au_key}" "$key_location/update-payload-key.pub.pem" - sudo chown root:root "$key_location/update-payload-key.pub.pem" - sudo chmod 644 "$key_location/update-payload-key.pub.pem" - echo "AU verification key was installed. Do not forget to resign the image!" - fi - - # The rootfs should never be mounted rw again after this point without - # re-calling make_image_bootable. - sudo mount -o remount,ro "${FLAGS_rootfs_mountpoint}" - # Newer `mount` will decode the filename backing the loop device, - # so we need to dig deeper and find the answer ourselves. - root_dev=$(awk -v mnt="${FLAGS_rootfs_mountpoint}" \ - '$2 == mnt { print $1 }' /proc/mounts) - - # Make the filesystem un-mountable as read-write. - # mount_gpt_image.sh will undo this as needed. - # TODO(wad) make sure there is parity in the signing scripts. - if [ ${FLAGS_enable_rootfs_verification} -eq ${FLAGS_TRUE} ]; then - # TODO(wad) this would be a good place to reset any other ext2 metadata. - warn "Disabling r/w mount of the root filesystem" - disable_rw_mount "$root_dev" - fi - - if [ ${FLAGS_use_dev_keys} -eq ${FLAGS_TRUE} ]; then - use_dev_keys="--use_dev_keys" - fi - - if [ ${FLAGS_force_developer_mode} -eq ${FLAGS_TRUE} ]; then - FLAGS_boot_args="${FLAGS_boot_args} cros_debug" - fi - - local squash_sort_flag= - if [ -n "${FLAGS_squash_sort_file}" ]; then - squash_sort_flag="-sort ${FLAGS_squash_sort_file}" - fi - - if [ $FLAGS_enable_squashfs -eq $FLAGS_TRUE ]; then - local squashfs_img="${FLAGS_output_dir}/squashfs.image" - sudo mksquashfs "${FLAGS_rootfs_mountpoint}" ${squashfs_img} -comp lzo \ - -noI -noF -ef ${SCRIPTS_DIR}/exclude-list -wildcards ${squash_sort_flag} - root_dev=$squashfs_img - fi - - # We should update the esp in place in the image. - local bootloader_to="${image}" - local esp_offset="$(partoffset ${image} ${NUM_ESP})" - esp_offset=$((esp_offset * 512)) # sectors to bytes - local esp_size="$(partsize ${image} ${NUM_ESP})" - esp_size=$((esp_size * 512)) # sectors to bytes - local bootloader_to_flags="--to_offset=${esp_offset} --to_size=${esp_size}" - - # Update ESP partition - # NOTE: Boot kernel is identical to regular kernel for now - ${SCRIPTS_DIR}/update_bootloaders.sh \ - --arch=${FLAGS_arch} \ - --to="${bootloader_to}" \ - --from="${FLAGS_rootfs_mountpoint}"/boot \ - --vmlinuz_boot_kernel="${FLAGS_rootfs_mountpoint}"/boot/vmlinuz \ - --vmlinuz="${FLAGS_rootfs_mountpoint}"/boot/vmlinuz \ - ${bootloader_to_flags} - - trap - EXIT - ${SCRIPTS_DIR}/mount_gpt_image.sh -u -r "${FLAGS_rootfs_mountpoint}" \ - -s "${FLAGS_statefulfs_mountpoint}" - - # I can only copy the squashfs image to the image only when it is umounted. - if [ $FLAGS_enable_squashfs -eq $FLAGS_TRUE ]; then - # copy the squashfs image to the partition - info "copy the squashfs to the partition" - local part_offset="$(partoffset ${image} ${NUM_ROOTFS_A})" - sudo dd bs=512 if="${squashfs_img}" of="${image}" \ - seek=${part_offset} conv=notrunc status=none - sudo rm "${squashfs_img}" - fi -} - -verify_image_rootfs() { - local image=$1 - local rootfs_offset="$(partoffset ${image} 3)" - - local rootfs_tmp_file=$(mktemp) - trap "rm ${rootfs_tmp_file}" EXIT - sudo dd if="${image}" of="${rootfs_tmp_file}" bs=512 skip="${rootfs_offset}" \ - status=none - - # This flips the read-only compatibility flag, so that - # e2fsck does not complain about unknown file system capabilities. - enable_rw_mount "${rootfs_tmp_file}" - info "Running e2fsck to check root file system for errors" - sudo e2fsck -fn "${rootfs_tmp_file}" || - die "Root file system has errors, please ensure boot.desc and/or \ -command line parameters are correct" -} - -# Store output and temporary files next to image. -FLAGS_output_dir="${IMAGE_DIR}" -FLAGS_rootfs_mountpoint="${IMAGE_DIR}/rootfs_dir" -FLAGS_statefulfs_mountpoint="${IMAGE_DIR}/stateful_dir" -FLAGS_espfs_mountpoint="${IMAGE_DIR}/esp" - -# Create the directories if they don't exist. -mkdir -p ${FLAGS_rootfs_mountpoint} -mkdir -p ${FLAGS_statefulfs_mountpoint} -mkdir -p ${FLAGS_espfs_mountpoint} - -make_image_bootable "${IMAGE}" -# We can't verify the image if squashfs is enabled because the kernel -# on the host does not support squashfs with LZO -if [ ${FLAGS_fsck_rootfs} -eq ${FLAGS_TRUE} \ - -a ${FLAGS_enable_squashfs} -eq ${FLAGS_FALSE} ]; then - verify_image_rootfs "${IMAGE}" -fi - -if [ ${FLAGS_cleanup_dirs} -eq ${FLAGS_TRUE} ]; then - rmdir ${FLAGS_rootfs_mountpoint} - rmdir ${FLAGS_statefulfs_mountpoint} - rmdir ${FLAGS_espfs_mountpoint} -fi diff --git a/build_image b/build_image index e28fa96635..e033414df0 100755 --- a/build_image +++ b/build_image @@ -10,11 +10,9 @@ # build the Chrome OS image using only pre-built binary packages. SCRIPT_ROOT=$(dirname $(readlink -f "$0")) -. "${SCRIPT_ROOT}/build_library/build_common.sh" || exit 1 +. "${SCRIPT_ROOT}/common.sh" || exit 1 # Developer-visible flags. -DEFINE_string adjust_part "" \ - "Adjustments to apply to the partition table" DEFINE_string board "${DEFAULT_BOARD}" \ "The board to build an image for." DEFINE_string boot_args "" \ @@ -23,7 +21,7 @@ DEFINE_boolean enable_rootfs_verification ${FLAGS_TRUE} \ "Default all bootloaders to use kernel-based root fs integrity checking." DEFINE_string output_root "${DEFAULT_BUILD_ROOT}/images" \ "Directory in which to place image result directories (named by version)" -DEFINE_string disk_layout "default" \ +DEFINE_string disk_layout "base" \ "The disk layout type to use for this image." # include upload options @@ -75,10 +73,9 @@ check_gsutil_opts # some of the files contain initialization used by later files. . "${BUILD_LIBRARY_DIR}/toolchain_util.sh" || exit 1 . "${BUILD_LIBRARY_DIR}/board_options.sh" || exit 1 -. "${BUILD_LIBRARY_DIR}/disk_layout_util.sh" || exit 1 -. "${BUILD_LIBRARY_DIR}/mount_gpt_util.sh" || exit 1 . "${BUILD_LIBRARY_DIR}/build_image_util.sh" || exit 1 . "${BUILD_LIBRARY_DIR}/base_image_util.sh" || exit 1 +. "${BUILD_LIBRARY_DIR}/prod_image_util.sh" || exit 1 . "${BUILD_LIBRARY_DIR}/dev_image_util.sh" || exit 1 . "${BUILD_LIBRARY_DIR}/test_image_content.sh" || exit 1 @@ -123,7 +120,7 @@ fi mkdir -p "${BUILD_DIR}" # Create the base image. -create_base_image ${PRISTINE_IMAGE_NAME} ${FLAGS_enable_rootfs_verification} +create_base_image ${PRISTINE_IMAGE_NAME} if should_build_image ${PRISTINE_IMAGE_NAME}; then upload_image "${BUILD_DIR}/${PRISTINE_IMAGE_NAME}" fi @@ -148,11 +145,8 @@ fi if should_build_image ${COREOS_PRODUCTION_IMAGE_NAME}; then copy_image ${CHROMEOS_BASE_IMAGE_NAME} ${COREOS_PRODUCTION_IMAGE_NAME} - ${SCRIPTS_DIR}/bin/cros_make_image_bootable \ - "${BUILD_DIR}" \ - ${COREOS_PRODUCTION_IMAGE_NAME} \ - --production_track="dev-channel" \ - --au_key=${SRC_ROOT}/third_party/coreos-overlay/coreos-base/coreos-au-key/files/update-payload-key.pub.pem + setup_prod_image ${COREOS_PRODUCTION_IMAGE_NAME} "dev-channel" \ + ${SRC_ROOT}/third_party/coreos-overlay/coreos-base/coreos-au-key/files/update-payload-key.pub.pem upload_image "${BUILD_DIR}/${COREOS_PRODUCTION_IMAGE_NAME}" fi diff --git a/build_library/base_image_util.sh b/build_library/base_image_util.sh index 52331b3fab..27e7f47986 100755 --- a/build_library/base_image_util.sh +++ b/build_library/base_image_util.sh @@ -4,142 +4,22 @@ . "${SRC_ROOT}/platform/dev/toolchain_utils.sh" || exit 1 -# Overlays are parts of the disk that live on the state partition -ROOT_OVERLAYS=(var opt srv home usr/local) - -cleanup_mounts() { - local prev_ret=$? - - # Disable die on error. - set +e - - # See if we ran out of space. Only show if we errored out via a trap. - if [[ ${prev_ret} -ne 0 ]]; then - local df=$(df -B 1M "${root_fs_dir}") - if [[ ${df} == *100%* ]]; then - error "Here are the biggest files (by disk usage):" - # Send final output to stderr to match `error` behavior. - sudo find "${root_fs_dir}" -xdev -type f -printf '%b %P\n' | \ - awk '$1 > 16 { $1 = $1 * 512; print }' | sort -n | tail -100 1>&2 - error "Target image has run out of space:" - error "${df}" - fi - fi - - echo "Cleaning up mounts" - safe_umount_tree "${root_fs_dir}" - safe_umount_tree "${state_fs_dir}" - safe_umount_tree "${esp_fs_dir}" - safe_umount_tree "${oem_fs_dir}" - - # Turn die on error back on. - set -e -} - create_base_image() { local image_name=$1 local rootfs_verification_enabled=$2 - get_disk_layout_type - local image_type="${DISK_LAYOUT_TYPE}" + local disk_layout="${FLAGS_disk_layout:-base}" + local disk_img="${BUILD_DIR}/${image_name}" + local mbr_img="/usr/share/syslinux/gptmbr.bin" + local root_fs_dir="${BUILD_DIR}/rootfs" - check_valid_layout "base" - check_valid_layout ${image_type} + info "Using image type ${disk_layout}" + "${BUILD_LIBRARY_DIR}/disk_util" --disk_layout="${disk_layout}" \ + format --mbr_boot_code="${mbr_img}" "${disk_img}" - info "Using image type ${image_type}" - - root_fs_dir="${BUILD_DIR}/rootfs" - state_fs_dir="${BUILD_DIR}/state" - esp_fs_dir="${BUILD_DIR}/esp" - oem_fs_dir="${BUILD_DIR}/oem" - - trap "cleanup_mounts && delete_prompt" EXIT - cleanup_mounts &> /dev/null - - local root_fs_label="ROOT-A" - local root_fs_num=$(get_num ${image_type} ${root_fs_label}) - local root_fs_img="${BUILD_DIR}/rootfs.image" - local root_fs_bytes=$(get_filesystem_size ${image_type} ${root_fs_num}) - - local state_fs_label="STATE" - local state_fs_num=$(get_num ${image_type} ${state_fs_label}) - local state_fs_img="${BUILD_DIR}/state.image" - local state_fs_bytes=$(get_filesystem_size ${image_type} ${state_fs_num}) - local state_fs_uuid=$(uuidgen) - - local esp_fs_label="EFI-SYSTEM" - local esp_fs_num=$(get_num ${image_type} ${esp_fs_label}) - local esp_fs_img="${BUILD_DIR}/esp.image" - local esp_fs_bytes=$(get_filesystem_size ${image_type} ${esp_fs_num}) - - local oem_fs_label="OEM" - local oem_fs_num=$(get_num ${image_type} ${oem_fs_label}) - local oem_fs_img="${BUILD_DIR}/oem.image" - local oem_fs_bytes=$(get_filesystem_size ${image_type} ${oem_fs_num}) - local oem_fs_uuid=$(uuidgen) - - local fs_block_size=$(get_fs_block_size) - - # Build root FS image. - info "Building ${root_fs_img}" - truncate --size="${root_fs_bytes}" "${root_fs_img}" - /sbin/mkfs.ext2 -F -q -b ${fs_block_size} "${root_fs_img}" \ - "$((root_fs_bytes / fs_block_size))" - /sbin/tune2fs -L "${root_fs_label}" \ - -U clear \ - -T 20091119110000 \ - -c 0 \ - -i 0 \ - -m 0 \ - -r 0 \ - -e remount-ro \ - "${root_fs_img}" - mkdir -p "${root_fs_dir}" - sudo mount -o loop "${root_fs_img}" "${root_fs_dir}" - - df -h "${root_fs_dir}" - - # Build state FS disk image. - info "Building ${state_fs_img}" - truncate --size="${state_fs_bytes}" "${state_fs_img}" - /sbin/mkfs.ext4 -F -q "${state_fs_img}" - /sbin/tune2fs -L "${state_fs_label}" -U "${state_fs_uuid}" \ - -c 0 -i 0 "${state_fs_img}" - mkdir -p "${state_fs_dir}" - sudo mount -o loop "${state_fs_img}" "${state_fs_dir}" - - # Build ESP disk image. - info "Building ${esp_fs_img}" - truncate --size="${esp_fs_bytes}" "${esp_fs_img}" - /usr/sbin/mkfs.vfat "${esp_fs_img}" - - # Build OEM FS disk image. - info "Building ${oem_fs_img}" - truncate --size="${oem_fs_bytes}" "${oem_fs_img}" - /sbin/mkfs.ext4 -F -q "${oem_fs_img}" - /sbin/tune2fs -L "${oem_fs_label}" -U "${oem_fs_uuid}" \ - -c 0 -i 0 "${oem_fs_img}" - mkdir -p "${oem_fs_dir}" - sudo mount -o loop "${oem_fs_img}" "${oem_fs_dir}" - - # Prepare state partition with some pre-created directories. - info "Binding directories from state partition onto the rootfs" - for i in "${ROOT_OVERLAYS[@]}"; do - sudo mkdir -p "${state_fs_dir}/overlays/$i" - sudo mkdir -p "${root_fs_dir}/$i" - sudo mount --bind "${state_fs_dir}/overlays/$i" "${root_fs_dir}/$i" - done - - # TODO(bp): remove these temporary fixes for /mnt/stateful_partition going moving - sudo mkdir -p "${root_fs_dir}/mnt/stateful_partition/" - sudo ln -s /media/state/overlays/usr/local "${root_fs_dir}/mnt/stateful_partition/dev_image" - sudo ln -s /media/state/overlays/home "${root_fs_dir}/mnt/stateful_partition/home" - sudo ln -s /media/state/overlays/var "${root_fs_dir}/mnt/stateful_partition/var_overlay" - sudo ln -s /media/state/etc "${root_fs_dir}/mnt/stateful_partition/etc" - - info "Binding directories from OEM partition onto the rootfs" - sudo mkdir -p "${root_fs_dir}/usr/share/oem" - sudo mount --bind "${oem_fs_dir}" "${root_fs_dir}/usr/share/oem" + "${BUILD_LIBRARY_DIR}/disk_util" --disk_layout="${disk_layout}" \ + mount "${disk_img}" "${root_fs_dir}" + trap "cleanup_mounts '${root_fs_dir}' && delete_prompt" EXIT # First thing first, install baselayout with USE=build to create a # working directory tree. Don't use binpkgs due to the use flag change. @@ -171,53 +51,19 @@ create_base_image() { --root="${root_fs_dir}" \ --board="${BOARD}" - # 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 - - # 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. - local enable_rootfs_verification= - if [[ ${rootfs_verification_enabled} -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} - - if [[ ${skip_test_image_content} -ne 1 ]]; then - # Check that the image has been correctly created. - test_image_content "$root_fs_dir" - fi + --boot_dir="${root_fs_dir}"/boot \ + --esp_dir="${root_fs_dir}"/boot/efi \ + --boot_args="${FLAGS_boot_args}" # Zero all fs free space to make it more compressible so auto-update # payloads become smaller, not fatal since it won't work on linux < 3.2 sudo fstrim "${root_fs_dir}" || true - sudo fstrim "${state_fs_dir}" || true - - cleanup_mounts - - # Create the GPT-formatted image. - build_gpt "${BUILD_DIR}/${image_name}" \ - "${root_fs_img}" \ - "${state_fs_img}" \ - "${esp_fs_img}" \ - "${oem_fs_img}" - - # Clean up temporary files. - rm -f "${root_fs_img}" "${state_fs_img}" "${esp_fs_img}" "{oem_fs_img}" - - # Emit helpful scripts for testers, etc. - emit_gpt_scripts "${BUILD_DIR}/${image_name}" "${BUILD_DIR}" - - ${SCRIPTS_DIR}/bin/cros_make_image_bootable "${BUILD_DIR}" \ - ${image_name} --adjust_part="${FLAGS_adjust_part}" + if [[ -d "${root_fs_dir}/media/state" ]]; then + sudo fstrim "${root_fs_dir}/media/state" || true + fi + cleanup_mounts "${root_fs_dir}" trap - EXIT } diff --git a/build_library/build_common.sh b/build_library/build_common.sh deleted file mode 100644 index 92e2ee6391..0000000000 --- a/build_library/build_common.sh +++ /dev/null @@ -1,49 +0,0 @@ -# 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. - -# Common library file to be sourced by build_image, -# mod_image_for_test.sh, and mod_image_for_recovery.sh. This -# file ensures that library source files needed by all the scripts -# are included once, and also takes care of certain bookeeping tasks -# common to all the scripts. - -# SCRIPT_ROOT must be set prior to sourcing this file -. "${SCRIPT_ROOT}/common.sh" || exit 1 - -# All scripts using this file must be run inside the chroot. -restart_in_chroot_if_needed "$@" - -INSTALLER_ROOT=/usr/lib/installer -. "${INSTALLER_ROOT}/chromeos-common.sh" || exit 1 - -locate_gpt - -should_build_image() { - # Fast pass back if we should build all incremental images. - local image_name - local image_to_build - - for image_name in "$@"; do - for image_to_build in ${IMAGES_TO_BUILD}; do - [ "${image_to_build}" = "${image_name}" ] && return 0 - done - done - - return 1 -} - -# Utility function for creating a copy of an image prior to -# modification from the BUILD_DIR: -# $1: source filename -# $2: destination filename -copy_image() { - local src="${BUILD_DIR}/$1" - local dst="${BUILD_DIR}/$2" - if should_build_image $1; then - echo "Creating $2 from $1..." - cp --sparse=always "${src}" "${dst}" || die "Cannot copy $1 to $2" - else - mv "${src}" "${dst}" || die "Cannot move $1 to $2" - fi -} diff --git a/build_library/build_image_util.sh b/build_library/build_image_util.sh index f2ce6406d0..fb46c20975 100755 --- a/build_library/build_image_util.sh +++ b/build_library/build_image_util.sh @@ -55,6 +55,35 @@ parse_build_image_args() { get_images_to_build ${FLAGS_ARGV} } +should_build_image() { + # Fast pass back if we should build all incremental images. + local image_name + local image_to_build + + for image_name in "$@"; do + for image_to_build in ${IMAGES_TO_BUILD}; do + [ "${image_to_build}" = "${image_name}" ] && return 0 + done + done + + return 1 +} + +# Utility function for creating a copy of an image prior to +# modification from the BUILD_DIR: +# $1: source filename +# $2: destination filename +copy_image() { + local src="${BUILD_DIR}/$1" + local dst="${BUILD_DIR}/$2" + if should_build_image $1; then + echo "Creating $2 from $1..." + cp --sparse=always "${src}" "${dst}" || die "Cannot copy $1 to $2" + else + mv "${src}" "${dst}" || die "Cannot move $1 to $2" + fi +} + check_blacklist() { info "Verifying that the base image does not contain a blacklisted package." info "Generating list of packages for ${BASE_PACKAGE}." @@ -80,20 +109,9 @@ make_salt() { xxd -l 32 -p -c 32 /dev/urandom } -create_boot_desc() { - local enable_rootfs_verification_flag="" - if [[ ${FLAGS_enable_rootfs_verification} -eq ${FLAGS_TRUE} ]]; then - enable_rootfs_verification_flag="--enable_rootfs_verification" - fi - - cat < ${BUILD_DIR}/boot.desc - --board=${BOARD} - --arch="${ARCH}" - --keys_dir="${DEVKEYSDIR}" - --boot_args="${FLAGS_boot_args}" - --nocleanup_dirs - ${enable_rootfs_verification_flag} -EOF +cleanup_mounts() { + echo "Cleaning up mounts" + "${BUILD_LIBRARY_DIR}/disk_util" umount "$1" || true } delete_prompt() { diff --git a/build_library/cgpt.py b/build_library/cgpt.py deleted file mode 100755 index 0299730204..0000000000 --- a/build_library/cgpt.py +++ /dev/null @@ -1,580 +0,0 @@ -#!/usr/bin/python -# Copyright (c) 2012 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. - -import json -import os -import re -import subprocess -import sys -import uuid -from optparse import OptionParser - -# First sector we can use. -GPT_RESERVED_SECTORS = 34 - -class ConfigNotFound(Exception): - pass -class PartitionNotFound(Exception): - pass -class InvalidLayout(Exception): - pass -class InvalidAdjustment(Exception): - pass - - -def LoadPartitionConfig(filename): - """Loads a partition tables configuration file into a Python object. - - Args: - filename: Filename to load into object - Returns: - Object containing disk layout configuration - """ - - valid_keys = set(('_comment', 'metadata', 'layouts')) - valid_layout_keys = set(( - '_comment', 'type', 'num', 'label', 'blocks', 'block_size', 'fs_blocks', - 'fs_block_size', 'features', 'uuid', 'alignment')) - - if not os.path.exists(filename): - raise ConfigNotFound('Partition config %s was not found!' % filename) - with open(filename) as f: - config = json.load(f) - - try: - metadata = config['metadata'] - for key in ('alignment', 'block_size', 'fs_block_size'): - metadata[key] = int(metadata[key]) - - # Sometimes qemu-img expects disks sizes aligned to 64k - align_bytes = metadata['alignment'] * metadata['block_size'] - if align_bytes < 65536 or align_bytes % 65536 != 0: - raise InvalidLayout('Invalid alignment, 64KB or better required') - - unknown_keys = set(config.keys()) - valid_keys - if unknown_keys: - raise InvalidLayout('Unknown items: %r' % unknown_keys) - - if len(config['layouts']) <= 0: - raise InvalidLayout('Missing "layouts" entries') - - for layout_name, layout in config['layouts'].items(): - for part in layout: - unknown_keys = set(part.keys()) - valid_layout_keys - if unknown_keys: - raise InvalidLayout('Unknown items in layout %s: %r' % - (layout_name, unknown_keys)) - - if part['type'] != 'blank': - for s in ('num', 'label'): - if not s in part: - raise InvalidLayout('Layout "%s" missing "%s"' % (layout_name, s)) - - part['alignment'] = int(part.get('alignment', metadata['alignment'])) - part['blocks'] = int(part['blocks']) - part['bytes'] = part['blocks'] * metadata['block_size'] - - if 'fs_blocks' in part: - part['fs_blocks'] = int(part['fs_blocks']) - part['fs_bytes'] = part['fs_blocks'] * metadata['fs_block_size'] - - if part['fs_bytes'] > part['bytes']: - raise InvalidLayout( - 'Filesystem may not be larger than partition: %s %s: %d > %d' % - (layout_name, part['label'], part['fs_bytes'], part['bytes'])) - - if 'uuid' in part: - try: - # double check the string formatting - part['uuid'] = str(uuid.UUID(part['uuid'])) - except ValueError as e: - raise InvalidLayout('Invalid uuid %r: %s' % (part['uuid'], e)) - else: - part['uuid'] = str(uuid.uuid4()) - except KeyError as e: - raise InvalidLayout('Layout is missing required entries: %s' % e) - - return config - - - - -def GetPartitionTable(options, config, image_type): - """Generates requested image_type layout from a layout configuration. - This loads the base table and then overlays the requested layout over - the base layout. - - Args: - options: Flags passed to the script - config: Partition configuration file object - image_type: Type of image eg base/test/dev/factory_install - Returns: - Object representing a selected partition table - """ - - partitions = config['layouts']['base'] - metadata = config['metadata'] - - if image_type != 'base': - for partition_t in config['layouts'][image_type]: - for partition in partitions: - if partition['type'] == 'blank' or partition_t['type'] == 'blank': - continue - if partition_t['num'] == partition['num']: - for k, v in partition_t.items(): - partition[k] = v - - for adjustment_str in options.adjust_part.split(): - adjustment = adjustment_str.split(':') - if len(adjustment) < 2: - raise InvalidAdjustment('Adjustment specified was incomplete') - - label = adjustment[0] - operator = adjustment[1][0] - operand = adjustment[1][1:] - ApplyPartitionAdjustment(partitions, metadata, label, operator, operand) - - return partitions - - -def ApplyPartitionAdjustment(partitions, metadata, label, operator, operand): - """Applies an adjustment to a partition specified by label - - Args: - partitions: Partition table to modify - metadata: Partition table metadata - label: The label of the partition to adjust - operator: Type of adjustment (+/-/=) - operand: How much to adjust by - """ - - partition = GetPartitionByLabel(partitions, label) - - operand_digits = re.sub('\D', '', operand) - size_factor = block_factor = 1 - suffix = operand[len(operand_digits):] - if suffix: - size_factors = { 'B': 0, 'K': 1, 'M': 2, 'G': 3, 'T': 4, } - try: - size_factor = size_factors[suffix[0].upper()] - except KeyError: - raise InvalidAdjustment('Unknown size type %s' % suffix) - if size_factor == 0 and len(suffix) > 1: - raise InvalidAdjustment('Unknown size type %s' % suffix) - block_factors = { '': 1024, 'B': 1000, 'IB': 1024, } - try: - block_factor = block_factors[suffix[1:].upper()] - except KeyError: - raise InvalidAdjustment('Unknown size type %s' % suffix) - - operand_bytes = int(operand_digits) * pow(block_factor, size_factor) - - if operand_bytes % metadata['block_size'] == 0: - operand_blocks = operand_bytes / metadata['block_size'] - else: - raise InvalidAdjustment('Adjustment size not divisible by block size') - - if operator == '+': - partition['blocks'] += operand_blocks - partition['bytes'] += operand_bytes - elif operator == '-': - partition['blocks'] -= operand_blocks - partition['bytes'] -= operand_bytes - elif operator == '=': - partition['blocks'] = operand_blocks - partition['bytes'] = operand_bytes - else: - raise ValueError('unknown operator %s' % operator) - - if partition['type'] == 'rootfs': - # If we're adjusting a rootFS partition, we assume the full partition size - # specified is being used for the filesytem, minus the space reserved for - # the hashpad. - partition['fs_bytes'] = partition['bytes'] - partition['fs_blocks'] = partition['fs_bytes'] / metadata['fs_block_size'] - partition['blocks'] = int(partition['blocks'] * 1.15) - partition['bytes'] = partition['blocks'] * metadata['block_size'] - - -def GetPartitionTableFromConfig(options, layout_filename, image_type): - """Loads a partition table and returns a given partition table type - - Args: - options: Flags passed to the script - layout_filename: The filename to load tables from - image_type: The type of partition table to return - """ - - config = LoadPartitionConfig(layout_filename) - partitions = GetPartitionTable(options, config, image_type) - - return partitions - - -def WritePartitionTable(options, image_type, layout_filename, disk_filename): - """Writes the given partition table to a disk image or device. - - Args: - options: Flags passed to the script - image_type: Type of image eg base/test/dev/factory_install - layout_filename: Path to partition configuration file - disk_filename: Path to disk image or device file - """ - - def Cgpt(*args): - subprocess.check_call(['cgpt'] + [str(a) for a in args]) - - def Align(count, alignment): - offset = count % alignment - if offset: - count += alignment - offset - return count - - config = LoadPartitionConfig(layout_filename) - metadata = config['metadata'] - partitions = GetPartitionTable(options, config, image_type) - disk_block_count = GPT_RESERVED_SECTORS - - for partition in partitions: - disk_block_count = Align(disk_block_count, partition['alignment']) - disk_block_count += partition['blocks'] - - disk_block_count += GPT_RESERVED_SECTORS - # Sometimes qemu-img expects disks sizes aligned to 64k - disk_block_count = Align(disk_block_count, config['metadata']['alignment']) - - Cgpt('create', '-c', '-s', disk_block_count, disk_filename) - - sector = GPT_RESERVED_SECTORS - for partition in partitions: - sector = Align(sector, partition['alignment']) - if partition['type'] != 'blank': - Cgpt('add', '-i', partition['num'], - '-b', sector, - '-s', partition['blocks'], - '-t', partition['type'], - '-l', partition['label'], - '-u', partition['uuid'], - disk_filename) - - sector += partition['blocks'] - - Cgpt('show', disk_filename) - - -def WriteMbrBoot(options, image_type, layout_filename, - disk_filename, mbr_filename): - """Writes the protective MBR with the given boot code. - - The EFI System Partition will be marked as the 'boot' partition. - - Args: - options: Flags passed to the script - image_type: Type of image eg base/test/dev/factory_install - layout_filename: Path to partition configuration file - disk_filename: Path to disk image or device file - mbr_filename: Path to boot code, usually gptmbr.bin from syslinux. - """ - - config = LoadPartitionConfig(layout_filename) - partitions = GetPartitionTable(options, config, image_type) - - esp_number = None - for partition in partitions: - if partition['type'] == 'efi': - esp_number = partition['num'] - break - if esp_number is None: - raise InvalidLayout('Table does not include an EFI partition.') - - subprocess.check_call(['cgpt', 'boot', '-p', '-b', mbr_filename, - '-i', str(partition['num']), disk_filename]) - - -def GetPartitionByNumber(partitions, num): - """Given a partition table and number returns the partition object. - - Args: - partitions: List of partitions to search in - num: Number of partition to find - Returns: - An object for the selected partition - """ - for partition in partitions: - if partition['type'] == 'blank': - continue - if partition['num'] == int(num): - return partition - - raise PartitionNotFound('Partition not found') - - -def GetPartitionByLabel(partitions, label): - """Given a partition table and label returns the partition object. - - Args: - partitions: List of partitions to search in - label: Label of partition to find - Returns: - An object for the selected partition - """ - for partition in partitions: - if 'label' not in partition: - continue - if partition['label'] == label: - return partition - - raise PartitionNotFound('Partition not found') - - -def GetBlockSize(options, layout_filename): - """Returns the partition table block size. - - Args: - options: Flags passed to the script - layout_filename: Path to partition configuration file - Returns: - Block size of all partitions in the layout - """ - - config = LoadPartitionConfig(layout_filename) - return config['metadata']['block_size'] - - -def GetFilesystemBlockSize(options, layout_filename): - """Returns the filesystem block size. - - Args: - options: Flags passed to the script - - This is used for all partitions in the table that have filesystems. - - Args: - layout_filename: Path to partition configuration file - Returns: - Block size of all filesystems in the layout - """ - - config = LoadPartitionConfig(layout_filename) - return config['metadata']['fs_block_size'] - - -def GetPartitionSize(options, image_type, layout_filename, num): - """Returns the partition size of a given partition for a given layout type. - - Args: - options: Flags passed to the script - image_type: Type of image eg base/test/dev/factory_install - layout_filename: Path to partition configuration file - num: Number of the partition you want to read from - Returns: - Size of selected partition in bytes - """ - - partitions = GetPartitionTableFromConfig(options, layout_filename, image_type) - partition = GetPartitionByNumber(partitions, num) - - return partition['bytes'] - - -def GetFilesystemSize(options, image_type, layout_filename, num): - """Returns the filesystem size of a given partition for a given layout type. - - If no filesystem size is specified, returns the partition size. - - Args: - options: Flags passed to the script - image_type: Type of image eg base/test/dev/factory_install - layout_filename: Path to partition configuration file - num: Number of the partition you want to read from - Returns: - Size of selected partition filesystem in bytes - """ - - partitions = GetPartitionTableFromConfig(options, layout_filename, image_type) - partition = GetPartitionByNumber(partitions, num) - - if 'fs_bytes' in partition: - return partition['fs_bytes'] - else: - return partition['bytes'] - - -def GetLabel(options, image_type, layout_filename, num): - """Returns the label for a given partition. - - Args: - options: Flags passed to the script - image_type: Type of image eg base/test/dev/factory_install - layout_filename: Path to partition configuration file - num: Number of the partition you want to read from - Returns: - Label of selected partition, or 'UNTITLED' if none specified - """ - - partitions = GetPartitionTableFromConfig(options, layout_filename, image_type) - partition = GetPartitionByNumber(partitions, num) - - if 'label' in partition: - return partition['label'] - else: - return 'UNTITLED' - - -def GetNum(options, image_type, layout_filename, label): - """Returns the number for a given label. - - Args: - options: Flags passed to the script - image_type: Type of image eg base/test/dev/factory_install - layout_filename: Path to partition configuration file - label: Label of the partition you want to read from - Returns: - Number of selected partition, or '-1' if there is no number - """ - - partitions = GetPartitionTableFromConfig(options, layout_filename, image_type) - partition = GetPartitionByLabel(partitions, label) - - if 'num' in partition: - return partition['num'] - else: - return '-1' - - -def GetUuid(options, image_type, layout_filename, label): - """Returns the unique partition UUID for a given label. - - Note: Only useful if the UUID is specified in the config file, otherwise - the value returned unlikely to be what is actually used in the image. - - Args: - options: Flags passed to the script - image_type: Type of image eg base/test/dev/prod - layout_filename: Path to partition configuration file - label: Label of the partition you want to read from - Returns: - String containing the requested UUID - """ - - partitions = GetPartitionTableFromConfig(options, layout_filename, image_type) - partition = GetPartitionByLabel(partitions, label) - return partition['uuid'] - - -def DoDebugOutput(options, image_type, layout_filename): - """Prints out a human readable disk layout in on-disk order. - - This will round values larger than 1MB, it's exists to quickly - visually verify a layout looks correct. - - Args: - options: Flags passed to the script - image_type: Type of image eg base/test/dev/factory_install - layout_filename: Path to partition configuration file - """ - partitions = GetPartitionTableFromConfig(options, layout_filename, image_type) - - for partition in partitions: - if partition['bytes'] < 1024 * 1024: - size = '%d bytes' % partition['bytes'] - else: - size = '%d MB' % (partition['bytes'] / 1024 / 1024) - if 'label' in partition: - if 'fs_bytes' in partition: - if partition['fs_bytes'] < 1024 * 1024: - fs_size = '%d bytes' % partition['fs_bytes'] - else: - fs_size = '%d MB' % (partition['fs_bytes'] / 1024 / 1024) - print '%s - %s/%s' % (partition['label'], fs_size, size) - else: - print '%s - %s' % (partition['label'], size) - else: - print 'blank - %s' % size - - -def DoParseOnly(options, image_type, layout_filename): - """Parses a layout file only, used before reading sizes to check for errors. - - Args: - options: Flags passed to the script - image_type: Type of image eg base/test/dev/factory_install - layout_filename: Path to partition configuration file - """ - partitions = GetPartitionTableFromConfig(options, layout_filename, image_type) - - -def main(argv): - action_map = { - 'write_gpt': { - 'usage': ['', '', ''], - 'func': WritePartitionTable, - }, - 'write_mbr': { - 'usage': ['', '', '', - ''], - 'func': WriteMbrBoot, - }, - 'readblocksize': { - 'usage': [''], - 'func': GetBlockSize, - }, - 'readfsblocksize': { - 'usage': [''], - 'func': GetFilesystemBlockSize, - }, - 'readpartsize': { - 'usage': ['', '', ''], - 'func': GetPartitionSize, - }, - 'readfssize': { - 'usage': ['', '', ''], - 'func': GetFilesystemSize, - }, - 'readlabel': { - 'usage': ['', '', ''], - 'func': GetLabel, - }, - 'readnum': { - 'usage': ['', '', '