diff --git a/bin/cros_make_image_bootable b/bin/cros_make_image_bootable
index 71d9db3504..99d33afb9c 100755
--- a/bin/cros_make_image_bootable
+++ b/bin/cros_make_image_bootable
@@ -33,7 +33,8 @@ assert_inside_chroot
# Load functions and constants for chromeos-install
. /usr/lib/installer/chromeos-common.sh || exit 1
-. "${SCRIPTS_DIR}/build_library/build_image_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
@@ -70,7 +71,10 @@ locate_gpt
set +e
# Now parse the build settings from ${OUTPUT_DIR}/boot.desc
-
+DEFINE_string board "${DEFAULT_BOARD}" \
+ "Board we're building for."
+DEFINE_string image_type "base" \
+ "Type of image we're building for (base/factory_install)."
DEFINE_string output_dir "/tmp" \
"Directory to place output in."
DEFINE_string image "chromiumos_base.img" \
@@ -141,6 +145,8 @@ FLAGS "${@}" || exit 1
[ -z "${FLAGS_verity_salt}" ] && FLAGS_verity_salt=$(make_salt)
+. "${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
@@ -238,10 +244,15 @@ make_image_bootable() {
fi
local rootfs_hash_size=$(stat -c '%s' ${FLAGS_rootfs_hash})
+ local rootfs_fs_size=$(get_filesystem_size ${FLAGS_image_type} 3)
+ local rootfs_partition_size=$(get_partition_size ${FLAGS_image_type} 3)
+ local rootfs_hash_pad=$(( rootfs_partition_size - rootfs_fs_size ))
info "Appending rootfs.hash (${rootfs_hash_size} bytes) to the root fs"
- if [[ ${rootfs_hash_size} -gt $((FLAGS_rootfs_hash_pad * 1024 * 1024)) ]]
+ if [[ ${rootfs_hash_size} -gt ${rootfs_hash_pad} ]]
then
- die "--rootfs_hash_pad reserves less than the needed ${rootfs_hash_size}"
+ die "rootfs_partition_size - rootfs_fs_size is less than the needed " \
+ "rootfs_hash_size (${rootfs_hash_size}), update your disk layout " \
+ "configuration"
fi
# Unfortunately, mount_gpt_image uses mount and not losetup to create the
# loop devices. This means that they are not the correct size. We have to
@@ -251,7 +262,7 @@ make_image_bootable() {
rootfs_file_size=$(stat -c '%s' ${root_dev})
hash_offset=$((hash_offset + (${rootfs_file_size} / 512)))
else
- hash_offset=$((hash_offset + ((1024 * 1024 * ${FLAGS_rootfs_size}) / 512)))
+ hash_offset=$((hash_offset + (${rootfs_fs_size} / 512)))
fi
sudo dd bs=512 \
seek=${hash_offset} \
@@ -267,7 +278,6 @@ make_image_bootable() {
sudo cp "${FLAGS_output_dir}/vmlinuz_hd.vblock" \
"${FLAGS_statefulfs_mountpoint}"
- # START_KERN_A is set by the first call to install the gpt.
local koffset="$(partoffset ${image} 2)"
sudo dd if="${FLAGS_output_dir}/vmlinuz.image" of="${image}" \
conv=notrunc bs=512 seek=${koffset}
diff --git a/build_image b/build_image
index f0a19cfeb6..047c9ba82f 100755
--- a/build_image
+++ b/build_image
@@ -12,7 +12,6 @@
SCRIPT_ROOT=$(dirname $(readlink -f "$0"))
. "${SCRIPT_ROOT}/build_library/build_common.sh" || exit 1
-
# Developer-visible flags.
DEFINE_string board "${DEFAULT_BOARD}" \
"The board to build an image for."
@@ -20,22 +19,12 @@ DEFINE_string boot_args "noinitrd" \
"Additional boot arguments to pass to the commandline"
DEFINE_boolean enable_rootfs_verification ${FLAGS_TRUE} \
"Default all bootloaders to use kernel-based root fs integrity checking."
-DEFINE_boolean full "${FLAGS_FALSE}" "Build full image with all partitions."
DEFINE_string output_root "${DEFAULT_BUILD_ROOT}/images" \
"Directory in which to place image result directories (named by version)"
-DEFINE_integer rootfs_hash_pad 8 \
- "MiBs reserved at the end of the rootfs image. \
- ceil(0.01 * rootfs_size) is a good minimum."
-DEFINE_integer rootfs_partition_size 1024 \
- "rootfs partition size in MiBs."
-DEFINE_integer rootfs_size 850 \
- "rootfs filesystem size in MiBs."
-DEFINE_integer rootfs_boost_size 0 \
- "MiBs by which to increase the rootfs allocations."
+DEFINE_string disk_layout "default" \
+ "The board to build an image for."
DEFINE_boolean standard_backdoor ${FLAGS_TRUE} \
"Install standard backdoor credentials for testing"
-DEFINE_integer statefulfs_size 1024 \
- "stateful filesystem size in MiBs."
DEFINE_string usb_disk /dev/sdb3 \
"Path syslinux should use to do a usb boot. Default: /dev/sdb3"
@@ -65,23 +54,12 @@ show_help_if_requested "$@"
# not needed for the typical developer workflow.
DEFINE_integer build_attempt 1 \
"The build attempt for this image build."
-DEFINE_boolean hybrid_mbr ${FLAGS_FALSE} \
- "Creates a hybrid MBR rather than a protective one"
DEFINE_integer jobs -1 \
"How many packages to build in parallel at maximum."
DEFINE_boolean replace ${FLAGS_FALSE} \
"Overwrite existing output, if any."
DEFINE_string symlink "latest" \
"Symlink name to use for this image."
-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_string verity_salt "" \
- "Root filesystem salt. Default: randomly generated."
DEFINE_string version "" \
"Overrides version number in name to this version."
@@ -99,7 +77,7 @@ OVERLAY_CHROMEOS_DIR="${SRC_ROOT}/third_party/chromiumos-overlay/chromeos"
# N.B. Ordering matters for some of the libraries below, because
# some of the files contain initialization used by later files.
. "${BUILD_LIBRARY_DIR}/board_options.sh" || exit 1
-. "${BUILD_LIBRARY_DIR}/build_gpt.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
@@ -116,25 +94,7 @@ for overlay in $(cros_overlay_list --board "$BOARD"); do
fi
done
-# Tweak sizes defaulted or given based on any boost given (or defaulted).
-# This is syntactic sugar to separate concerns in callers, and unify
-# default values here.
-if [[ $FLAGS_rootfs_boost_size -gt 0 ]]; then
- max() {
- echo $(( $1 > $2 ? $1 : $2 ))
- }
- root_boost() {
- echo $(( $1 + ( $1 * $FLAGS_rootfs_boost_size + $FLAGS_rootfs_size - 1 ) \
- / $FLAGS_rootfs_size ))
- }
- FLAGS_rootfs_hash_pad=$(root_boost $FLAGS_rootfs_hash_pad)
- FLAGS_rootfs_partition_size=$(root_boost $FLAGS_rootfs_partition_size)
- FLAGS_rootfs_size=$(root_boost $FLAGS_rootfs_size)
- FLAGS_rootfs_boost_size=0
- # Push up to the recommended minimum if we did not get there.
- FLAGS_rootfs_hash_pad=$(max $FLAGS_rootfs_hash_pad \
- $(( ( $FLAGS_rootfs_size + 99 ) / 100 )))
-fi
+# TODO:
# Tweak flags, configure extra USE flags, and add packages for the factory
# install shim.
@@ -143,16 +103,6 @@ if should_build_image ${CHROMEOS_FACTORY_INSTALL_SHIM_NAME}; then
# TODO: Build a separated ebuild for the install shim to reduce size.
INSTALL_MASK="${FACTORY_SHIM_INSTALL_MASK}"
- # Reduce the size of factory install shim. Note that 400M is too much, it
- # should be smaller, see http://crosbug.com/34167
- FLAGS_rootfs_size=400
- FLAGS_rootfs_partition_size=420
- FLAGS_statefulfs_size=140
- info "Fixing the rootfs size at ${FLAGS_rootfs_partition_size} MiB " \
- "for install shim"
- info "Fixing the statefulfs size at ${FLAGS_statefulfs_size} MiB " \
- "for install shim"
-
# Add the cros_factory_install boot arg.
FLAGS_boot_args="${FLAGS_boot_args} cros_factory_install"
@@ -172,11 +122,7 @@ if should_build_image ${CHROMEOS_FACTORY_INSTALL_SHIM_NAME}; then
fi
fi
-if [ $((FLAGS_rootfs_size + FLAGS_rootfs_hash_pad)) -gt \
- ${FLAGS_rootfs_partition_size} ] ; then
- die_notrace "rootfs ($((FLAGS_rootfs_size + FLAGS_rootfs_hash_pad)) MiB) is" \
- "bigger than partition (${FLAGS_rootfs_partition_size} MiB)."
-fi
+# TODO:
# If we are creating a developer image, also create a pristine image with a
# different name.
@@ -187,17 +133,8 @@ else
PRISTINE_IMAGE_NAME=${CHROMEOS_BASE_IMAGE_NAME}
fi
-ROOT_FS_DIR="${BUILD_DIR}/rootfs"
-STATEFUL_FS_DIR="${BUILD_DIR}/stateful_partition"
-ESP_FS_DIR=${BUILD_DIR}/esp
-
DEVKEYSDIR="/usr/share/vboot/devkeys"
-# ${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"
-
eclean-$BOARD -d packages
if [[ ${skip_blacklist_check} -ne 1 ]]; then
@@ -228,29 +165,10 @@ fi
# Create the output directory and temporary mount points.
mkdir -p "${BUILD_DIR}"
-mkdir -p "${ROOT_FS_DIR}" "${STATEFUL_FS_DIR}" "${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 the base image.
create_base_image ${PRISTINE_IMAGE_NAME}
-
-BOOT_FLAG=
-if should_build_image ${CHROMEOS_FACTORY_INSTALL_SHIM_NAME}; 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 pristine image if we built it.
-if should_build_image "${PRISTINE_IMAGE_NAME}"; then
- load_kernel_test "${BUILD_DIR}/${PRISTINE_IMAGE_NAME}" \
- "${DEVKEYSDIR}/recovery_key.vbpubk" ${BOOT_FLAG}
-fi
-
# Running board-specific setup if any exists.
if type board_setup &>/dev/null; then
board_setup "${BUILD_DIR}/${PRISTINE_IMAGE_NAME}"
@@ -274,8 +192,6 @@ if should_build_image ${CHROMEOS_FACTORY_TEST_IMAGE_NAME}; then
mod_image_for_test ${CHROMEOS_FACTORY_TEST_IMAGE_NAME}
fi
-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..."
@@ -283,7 +199,7 @@ generate_au_zip || echo "Failed generating AU zip file - ignoring Error..."
LINK_NAME="${FLAGS_output_root}/${BOARD}/${FLAGS_symlink}"
ln -sfT $(basename ${BUILD_DIR}) ${LINK_NAME}
-echo "Done. Image(s) created in ${BUILD_DIR}"
+echo "Done. Image(s) created in ${BUILD_DIR}"
# Print out the images we generated.
if should_build_image ${CHROMEOS_BASE_IMAGE_NAME}; then
diff --git a/build_library/base_image_util.sh b/build_library/base_image_util.sh
index 0e548d6b9b..dd9a6ecb3d 100755
--- a/build_library/base_image_util.sh
+++ b/build_library/base_image_util.sh
@@ -2,54 +2,29 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# Shell function library and global variable initialization for
-# creating an initial base image. The main function for export in
-# this library is 'create_base_image'; the remainder of the code is
-# not used outside this file.
+. "${SRC_ROOT}/platform/dev/toolchain_utils.sh" || exit 1
+cleanup_mounts() {
+ # Disable die on error.
+ set +e
-ROOT_LOOP_DEV=
-STATEFUL_LOOP_DEV=
-
-ROOT_FS_IMG="${BUILD_DIR}/rootfs.image"
-STATEFUL_FS_IMG="${BUILD_DIR}/stateful_partition.image"
-ESP_FS_IMG=${BUILD_DIR}/esp.image
-
-cleanup_rootfs_loop() {
# See if we ran out of space.
- local df=$(df -B 1M "${ROOT_FS_DIR}")
+ 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' | \
+ 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
- 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}"
-}
+ echo "Cleaning up mounts"
+ safe_umount_tree "${root_fs_dir}"
+ safe_umount_tree "${stateful_fs_dir}"
+ safe_umount_tree "${esp_fs_dir}"
-loopback_cleanup() {
- # Disable die on error.
- set +e
-
- if [[ -n "${STATEFUL_LOOP_DEV}" ]]; then
- cleanup_stateful_fs_loop
- STATEFUL_LOOP_DEV=
- fi
-
- if [[ -n "${ROOT_LOOP_DEV}" ]]; then
- cleanup_rootfs_loop
- ROOT_LOOP_DEV=
- fi
-
- # Turn die on error back on.
+ # Turn die on error back on.
set -e
}
@@ -58,43 +33,62 @@ zero_free_space() {
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.
+ info "${fs_mount_point}/filler"
( sudo dd if=/dev/zero of="${fs_mount_point}/filler" bs=4096 conv=fdatasync \
status=noxfer || true ) 2>&1 | grep -v "No space left on device"
sudo rm "${fs_mount_point}/filler"
}
-# Takes as an arg the name of the image to be created.
create_base_image() {
local image_name=$1
+ local rootfs_verification_enabled=$2
+ local image_type="base"
- trap "loopback_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)) status=noxfer
-
- ROOT_LOOP_DEV=$(sudo losetup --show -f "${ROOT_FS_IMG}")
- if [ -z "${ROOT_LOOP_DEV}" ] ; then
- die_notrace \
- "No free loop device. Free up a loop device or reboot. exiting. "
+ if [[ "${FLAGS_disk_layout}" != "default" ]]; then
+ image_type="${FLAGS_disk_layout}"
+ else
+ if should_build_image ${CHROMEOS_FACTORY_INSTALL_SHIM_NAME}; then
+ image_type="factory_install"
+ fi
fi
- # Specify a block size and block count to avoid using the hash pad.
- sudo mkfs.ext2 -q -b 4096 "${ROOT_LOOP_DEV}" "$((ROOT_SIZE_BYTES / 4096))"
+ info "Using image type ${image_type}"
- # 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}" \
+ root_fs_dir="${BUILD_DIR}/rootfs"
+ stateful_fs_dir="${BUILD_DIR}/stateful"
+ 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_img="${BUILD_DIR}/rootfs.image"
+ local root_fs_bytes=$(get_filesystem_size ${image_type} 3)
+ local root_fs_label=$(get_label ${image_type} 3)
+
+ local stateful_fs_img="${BUILD_DIR}/stateful.image"
+ local stateful_fs_bytes=$(get_filesystem_size ${image_type} 1)
+ local stateful_fs_label=$(get_label ${image_type} 1)
+ local stateful_fs_uuid=$(uuidgen)
+
+ local esp_fs_img="${BUILD_DIR}/esp.image"
+ local esp_fs_bytes=$(get_filesystem_size ${image_type} 12)
+ local esp_fs_label=$(get_label ${image_type} 12)
+
+ local oem_fs_img="${BUILD_DIR}/oem.image"
+ local oem_fs_bytes=$(get_filesystem_size ${image_type} 8)
+ local oem_fs_label=$(get_label ${image_type} 8)
+ local oem_fs_uuid=$(uuidgen)
+
+ local block_size=$(get_fs_block_size)
+
+ # Build root FS image.
+ info "Building ${root_fs_img}"
+ dd if=/dev/zero of="${root_fs_img}" bs=1 count=1 \
+ seek=$((root_fs_bytes - 1)) status=noxfer
+ sudo mkfs.ext2 -F -q -b $block_size "${root_fs_img}" \
+ "$((root_fs_bytes / block_size))"
+ sudo tune2fs -L "${root_fs_label}" \
-U clear \
-T 20091119110000 \
-c 0 \
@@ -102,46 +96,59 @@ create_base_image() {
-m 0 \
-r 0 \
-e remount-ro \
- "${ROOT_LOOP_DEV}"
- # TODO(wad) call tune2fs prior to finalization to set the mount count to 0.
- sudo mount -t ext2 "${ROOT_LOOP_DEV}" "${ROOT_FS_DIR}"
+ "${root_fs_img}"
+ mkdir -p "${root_fs_dir}"
+ sudo mount -o loop "${root_fs_img}" "${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)) status=noxfer
+ df -h "${root_fs_dir}"
- # 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
- die_notrace \
- "No free loop device. Free up a loop device or reboot. exiting. "
- fi
- sudo mkfs.ext4 -q "${STATEFUL_LOOP_DEV}"
- sudo tune2fs -L "${DISK_LABEL}" -U "${UUID}" -c 0 -i 0 "${STATEFUL_LOOP_DEV}"
- sudo mount -t ext4 "${STATEFUL_LOOP_DEV}" "${STATEFUL_FS_DIR}"
+ # Build stateful FS disk image.
+ info "Building ${stateful_fs_img}"
+ dd if=/dev/zero of="${stateful_fs_img}" bs=1 count=1 \
+ seek=$((stateful_fs_bytes - 1)) status=noxfer
+ sudo mkfs.ext4 -F -q "${stateful_fs_img}"
+ sudo tune2fs -L "${stateful_fs_label}" -U "${stateful_fs_uuid}" \
+ -c 0 -i 0 "${stateful_fs_img}"
+ mkdir -p "${stateful_fs_dir}"
+ sudo mount -o loop "${stateful_fs_img}" "${stateful_fs_dir}"
- # -- Install packages into the root file system --
+ # Build ESP disk image.
+ info "Building ${esp_fs_img}"
+ dd if=/dev/zero of="${esp_fs_img}" bs=1 count=1 \
+ seek=$((esp_fs_bytes - 1)) status=noxfer
+ sudo mkfs.vfat "${esp_fs_img}"
+
+ # Build OEM FS disk image.
+ info "Building ${oem_fs_img}"
+ dd if=/dev/zero of="${oem_fs_img}" bs=1 count=1 \
+ seek=$((oem_fs_bytes - 1)) status=noxfer
+ sudo mkfs.ext4 -F -q "${oem_fs_img}"
+ sudo 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 stateful partition with some pre-created directories.
- sudo mkdir -p "${DEV_IMAGE_ROOT}"
- sudo mkdir -p "${STATEFUL_FS_DIR}/var_overlay"
+ sudo mkdir "${stateful_fs_dir}/dev_image"
+ sudo mkdir "${stateful_fs_dir}/var_overlay"
# 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_overlay" \
- "${STATEFUL_FS_DIR}"
+ setup_symlinks_on_root "${stateful_fs_dir}/dev_image" \
+ "${stateful_fs_dir}/var_overlay" "${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.
info "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_overlay" "${ROOT_FS_DIR}/var"
- sudo mkdir -p "${ROOT_FS_DIR}/dev"
+ sudo mkdir -p "${root_fs_dir}/usr/local"
+ sudo mount --bind "${stateful_fs_dir}/dev_image" "${root_fs_dir}/usr/local"
+ sudo mkdir -p "${root_fs_dir}/var"
+ sudo mount --bind "${stateful_fs_dir}/var_overlay" "${root_fs_dir}/var"
+ sudo mkdir -p "${root_fs_dir}/dev"
+
+ 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"
# We need to install libc manually from the cross toolchain.
# TODO: Improve this? It would be ideal to use emerge to do this.
@@ -150,37 +157,47 @@ create_base_image() {
LIBC_PATH="${PKGDIR}/cross-${CHOST}/${LIBC_TAR}"
if ! [[ -e ${LIBC_PATH} ]]; then
- die_notrace \
- "${LIBC_PATH} does not exist. Try running ./setup_board" \
- "--board=${BOARD} to update the version of libc installed on that board."
+ die_notrace \
+ "${LIBC_PATH} does not exist. Try running ./setup_board" \
+ "--board=${BOARD} to update the version of libc installed on that board."
fi
- sudo tar jxpf "${LIBC_PATH}" -C "${ROOT_FS_DIR}" ./usr/${CHOST} \
- --strip-components=3 --exclude=usr/include --exclude=sys-include \
- --exclude=*.a --exclude=*.o
+ sudo tar jxpf "${LIBC_PATH}" -C "${root_fs_dir}" ./usr/${CHOST} \
+ --strip-components=3 --exclude=usr/include --exclude=sys-include \
+ --exclude=*.a --exclude=*.o
- . "${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
+ copy_gcc_libs "${root_fs_dir}" $atom
done
if should_build_image ${CHROMEOS_FACTORY_INSTALL_SHIM_NAME}; then
# Install our custom factory install kernel with the appropriate use flags
# to the image.
- emerge_custom_kernel "${ROOT_FS_DIR}"
+ emerge_custom_kernel "${root_fs_dir}"
fi
- # We "emerge --root=${ROOT_FS_DIR} --root-deps=rdeps --usepkgonly" all of the
+ # 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}
+ 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}"
+ --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 "${image_type}"
+
+ # Write out the GPT creation script.
+ # This MUST be done before writing bootloader templates else we'll break
+ # the hash on the root FS.
+ write_partition_script "${image_type}" \
+ "${root_fs_dir}/${PARTITION_SCRIPT_PATH}"
# Populates the root filesystem with legacy bootloader templates
# appropriate for the platform. The autoupdater and installer will
@@ -191,79 +208,53 @@ create_base_image() {
# not support verified boot yet (see create_legacy_bootloader_templates.sh)
# so rootfs verification is disabled if we are building with --factory_install
local enable_rootfs_verification=
- if [[ ${FLAGS_enable_rootfs_verification} -eq ${FLAGS_TRUE} ]]; then
- enable_rootfs_verification="--enable_rootfs_verification"
+ if [[ ${rootfs_verification_enabled} -eq 1 ]]; 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}
+ --to="${root_fs_dir}"/boot \
+ ${enable_rootfs_verification}
# Don't test the factory install shim
if ! should_build_image ${CHROMEOS_FACTORY_INSTALL_SHIM_NAME}; then
- if [[ ${skip_test_image_content} -ne 1 ]]; then
+ if [[ ${skip_test_image_content} -ne 1 ]]; then
# Check that the image has been correctly created.
- test_image_content "$ROOT_FS_DIR"
+ test_image_content "$root_fs_dir"
fi
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, unless
- # we are building a factory shim, in which case a larger room is
- # needed to allow two kernel blobs (each including initramfs) in
- # one EFI partition.
- if should_build_image ${CHROMEOS_FACTORY_INSTALL_SHIM_NAME}; then
- /usr/sbin/mkfs.vfat -C "${ESP_FS_IMG}" 32768
- else
- /usr/sbin/mkfs.vfat -C "${ESP_FS_IMG}" 16384
- fi
+ setup_symlinks_on_root "/usr/local" "/var" "${stateful_fs_dir}"
# Zero rootfs free space to make it more compressible so auto-update
# payloads become smaller
- zero_free_space "${ROOT_FS_DIR}"
- loopback_cleanup
- trap delete_prompt EXIT
+ zero_free_space "${root_fs_dir}"
- if [[ ${FLAGS_full} -eq ${FLAGS_TRUE} ]]; then
- dd if=/dev/zero of="${BUILD_DIR}/${image_name}" bs=1M count=3584
- fi
+ cleanup_mounts
# Create the GPT-formatted image.
build_gpt "${BUILD_DIR}/${image_name}" \
- "${ROOT_FS_IMG}" \
- "${STATEFUL_FS_IMG}" \
- "${ESP_FS_IMG}"
+ "${root_fs_img}" \
+ "${stateful_fs_img}" \
+ "${esp_fs_img}"
+
# Clean up temporary files.
- rm -f "${ROOT_FS_IMG}" "${STATEFUL_FS_IMG}" "${ESP_FS_IMG}"
+ rm -f "${root_fs_img}" "${stateful_fs_img}" "${esp_fs_img}" "{oem_fs_img}"
# Emit helpful scripts for testers, etc.
emit_gpt_scripts "${BUILD_DIR}/${image_name}" "${BUILD_DIR}"
- trap - EXIT
-
USE_DEV_KEYS=
if should_build_image ${CHROMEOS_FACTORY_INSTALL_SHIM_NAME}; then
USE_DEV_KEYS="--use_dev_keys"
fi
# Place flags before positional args.
- if should_build_image ${image_name}; then
- ${SCRIPTS_DIR}/bin/cros_make_image_bootable "${BUILD_DIR}" \
- ${image_name} \
- ${USE_DEV_KEYS}
- fi
-
- # Setup hybrid MBR if it was enabled
- if [[ ${FLAGS_hybrid_mbr} -eq ${FLAGS_TRUE} ]]; then
- install_hybrid_mbr "${BUILD_DIR}/${image_name}"
- fi
+ ${SCRIPTS_DIR}/bin/cros_make_image_bootable "${BUILD_DIR}" \
+ ${image_name} \
+ ${USE_DEV_KEYS}
}
diff --git a/build_library/build_common.sh b/build_library/build_common.sh
index e3f217e257..a6a9cfa0ac 100644
--- a/build_library/build_common.sh
+++ b/build_library/build_common.sh
@@ -17,5 +17,33 @@ restart_in_chroot_if_needed "$@"
INSTALLER_ROOT=/usr/lib/installer
. "${INSTALLER_ROOT}/chromeos-common.sh" || exit 1
-BUILD_LIBRARY_DIR=${SCRIPTS_DIR}/build_library
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..."
+ $COMMON_PV_CAT "${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_gpt.sh b/build_library/build_gpt.sh
deleted file mode 100755
index 74285d376b..0000000000
--- a/build_library/build_gpt.sh
+++ /dev/null
@@ -1,88 +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.
-
-emit_gpt_scripts() {
- local image="$1"
- local dir="$2"
-
- local pack="$dir/pack_partitions.sh"
- local unpack="$dir/unpack_partitions.sh"
-
- cat >"$unpack" <&2
- exit 1
-fi
-set -x
-HEADER
-
- $GPT show "$image" | sed -e 's/^/# /' >>"$unpack"
- cp "$unpack" "$pack"
-
- $GPT show -q "$image" |
- while read start size part x; do
- local file="part_$part"
- local target="\"\$TARGET\""
- local dd_args="bs=512 count=$size"
- echo "dd if=$target of=$file $dd_args skip=$start" >>"$unpack"
- echo "dd if=$file of=$target $dd_args seek=$start conv=notrunc" \
- >>"$pack"
- done
-
- chmod +x "$unpack" "$pack"
-}
-
-
-build_gpt() {
- local outdev="$1"
- local rootfs_img="$2"
- local stateful_img="$3"
- local esp_img="$4"
-
- # We'll need some code to put in the PMBR, for booting on legacy BIOS.
- local pmbr_img
- if [ "$ARCH" = "arm" ]; then
- pmbr_img=/dev/zero
- elif [[ "$ARCH" = "x86" || "$ARCH" = "amd64" ]]; then
- pmbr_img=$(readlink -f /usr/share/syslinux/gptmbr.bin)
- else
- error "Unknown architecture: $ARCH"
- return 1
- fi
-
- GPT_FULL="false"
- [ "${FLAGS_full}" -eq "${FLAGS_TRUE}" ] && GPT_FULL="true"
-
- # Create the GPT. This has the side-effect of setting some global vars
- # describing the partition table entries (see the comments in the source).
- install_gpt "$outdev" $(numsectors "$rootfs_img") \
- $(numsectors "$stateful_img") $pmbr_img $(numsectors "$esp_img") \
- $GPT_FULL $FLAGS_rootfs_partition_size
-
- local sudo=
- if [ ! -w "$outdev" ] ; then
- # use sudo when writing to a block device.
- sudo=sudo
- fi
-
- # Now populate the partitions.
- info "Copying stateful partition..."
- $sudo dd if="$stateful_img" of="$outdev" conv=notrunc bs=512 \
- seek=$START_STATEFUL
-
- info "Copying rootfs..."
- $sudo dd if="$rootfs_img" of="$outdev" conv=notrunc bs=512 \
- seek=$START_ROOTFS_A
-
- info "Copying EFI system partition..."
- $sudo dd if="$esp_img" of="$outdev" conv=notrunc bs=512 \
- seek=$START_ESP
-
- # 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 "$outdev"
-}
diff --git a/build_library/build_image_util.sh b/build_library/build_image_util.sh
index d355ad89e3..90c2c61f3b 100755
--- a/build_library/build_image_util.sh
+++ b/build_library/build_image_util.sh
@@ -22,6 +22,14 @@ BUILD_DIR="${FLAGS_output_root}/${BOARD}/${IMAGE_SUBDIR}"
OUTSIDE_OUTPUT_DIR="../build/images/${BOARD}/${IMAGE_SUBDIR}"
IMAGES_TO_BUILD=
+EMERGE_BOARD_CMD="$GCLIENT_ROOT/chromite/bin/parallel_emerge"
+EMERGE_BOARD_CMD="$EMERGE_BOARD_CMD --board=$BOARD"
+
+export INSTALL_MASK="${DEFAULT_INSTALL_MASK}"
+
+if [[ $FLAGS_jobs -ne -1 ]]; then
+ EMERGE_JOBS="--jobs=$FLAGS_jobs"
+fi
# Populates list of IMAGES_TO_BUILD from args passed in.
# Arguments should be the shortnames of images we want to build.
@@ -106,9 +114,9 @@ make_salt() {
xxd -l 32 -p -c 32 /dev/urandom
}
-# Takes no arguments and populates the configuration for
-# cros_make_image_bootable.
create_boot_desc() {
+ local image_type=$1
+
local enable_rootfs_verification_flag=""
if [[ ${FLAGS_enable_rootfs_verification} -eq ${FLAGS_TRUE} ]]; then
enable_rootfs_verification_flag="--enable_rootfs_verification"
@@ -116,17 +124,13 @@ create_boot_desc() {
[ -z "${FLAGS_verity_salt}" ] && FLAGS_verity_salt=$(make_salt)
cat < ${BUILD_DIR}/boot.desc
+ --board=${BOARD}
+ --image_type=${image_type}
--arch="${ARCH}"
- --boot_args="${FLAGS_boot_args}"
- --rootfs_size="${FLAGS_rootfs_size}"
- --rootfs_hash_pad="${FLAGS_rootfs_hash_pad}"
- --verity_error_behavior="${FLAGS_verity_error_behavior}"
- --verity_max_ios="${FLAGS_verity_max_ios}"
- --verity_algorithm="${FLAGS_verity_algorithm}"
- --verity_salt="${FLAGS_verity_salt}"
--keys_dir="${DEVKEYSDIR}"
--usb_disk="${FLAGS_usb_disk}"
--nocleanup_dirs
+ --verity_algorithm=sha1
${enable_rootfs_verification_flag}
EOF
}
@@ -159,3 +163,11 @@ generate_au_zip () {
info "Running ${lgenerateauzip} ${largs} for generating AU updater zip file"
$lgenerateauzip $largs
}
+
+# Basic command to emerge binary packages into the target image.
+# Arguments to this command are passed as addition options/arguments
+# to the basic emerge command.
+emerge_to_image() {
+ sudo -E ${EMERGE_BOARD_CMD} --root-deps=rdeps --usepkgonly -v \
+ "$@" ${EMERGE_JOBS}
+}
diff --git a/build_library/cgpt.py b/build_library/cgpt.py
new file mode 100755
index 0000000000..56d176ec8d
--- /dev/null
+++ b/build_library/cgpt.py
@@ -0,0 +1,407 @@
+#!/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 copy
+import json
+import os
+import sys
+
+# First sector we can use.
+START_SECTOR = 64
+
+class ConfigNotFound(Exception):
+ pass
+class PartitionNotFound(Exception):
+ pass
+class InvalidLayout(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
+ """
+
+ if not os.path.exists(filename):
+ raise ConfigNotFound("Partition config %s was not found!" % filename)
+ with open(filename) as f:
+ config = json.load(f)
+ f.close()
+
+ metadata = config["metadata"]
+ metadata["block_size"] = int(metadata["block_size"])
+
+ for layout_name, layout in config["layouts"].items():
+ for part in layout:
+ 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")
+
+ return config
+
+
+def GetTableTotals(config, partitions):
+ """Calculates total sizes/counts for a partition table.
+
+ Args:
+ config: Partition configuration file object
+ partitions: List of partitions to process
+ Returns:
+ Dict containing totals data
+ """
+
+ ret = {
+ "expand_count": 0,
+ "expand_min": 0,
+ "block_count": START_SECTOR * config["metadata"]["block_size"]
+ }
+
+ # Total up the size of all non-expanding partitions to get the minimum
+ # required disk size.
+ for partition in partitions:
+ if "features" in partition and "expand" in partition["features"]:
+ ret["expand_count"] += 1
+ ret["expand_min"] += partition["blocks"]
+ else:
+ ret["block_count"] += partition["blocks"]
+
+ # At present, only one expanding partition is permitted.
+ # Whilst it'd be possible to have two, we don't need this yet
+ # and it complicates things, so it's been left out for now.
+ if ret["expand_count"] > 1:
+ raise InvalidLayout("1 expand partition allowed, %d requested"
+ % ret["expand_count"])
+
+ ret["min_disk_size"] = ret["block_count"] + ret["expand_min"]
+
+ return ret
+
+
+def GetPartitionTable(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:
+ 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"]
+
+ 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
+
+ return partitions
+
+
+def GetScriptShell():
+ """Loads and returns the skeleton script for our output script.
+
+ Returns:
+ A string containg the skeleton script
+ """
+
+ script_shell_path = os.path.join(os.path.dirname(__file__), "cgpt_shell.sh")
+ with open(script_shell_path, "r") as f:
+ script_shell = "".join(f.readlines())
+ f.close()
+
+ # Before we return, insert the path to this tool so somebody reading the
+ # script later can tell where it was generated.
+ script_shell = script_shell.replace("@SCRIPT_GENERATOR@", script_shell_path)
+
+ return script_shell
+
+
+def WriteLayoutFunction(sfile, func_name, image_type, config):
+ """Writes a shell script function to write out a given partition table.
+
+ Args:
+ sfile: File handle we're writing to
+ func_name: Function name to write out for specified layout
+ image_type: Type of image eg base/test/dev/factory_install
+ config: Partition configuration file object
+ """
+
+ partitions = GetPartitionTable(config, image_type)
+ partition_totals = GetTableTotals(config, partitions)
+
+ sfile.write("%s() {\ncreate_image $1 %d %s\n" % (
+ func_name, partition_totals["min_disk_size"],
+ config["metadata"]["block_size"]))
+
+ sfile.write("CURR=%d\n" % START_SECTOR)
+ sfile.write("$GPT create $1\n")
+
+ # Pass 1: Set up the expanding partition size.
+ for partition in partitions:
+ if partition["type"] != "blank":
+ partition["var"] = partition["blocks"]
+
+ if partition["num"] == 1:
+ if "features" in partition and "expand" in partition["features"]:
+ sfile.write("if [ -b $1 ]; then\n")
+ sfile.write("STATEFUL_SIZE=$(( $(numsectors $1) - %d))\n" %
+ partition_totals["block_count"])
+ sfile.write("else\n")
+ sfile.write("STATEFUL_SIZE=%s\n" % partition["blocks"])
+ sfile.write("fi\n")
+ partition["var"] = "$STATEFUL_SIZE"
+
+ # Pass 2: Write out all the cgpt add commands.
+ for partition in partitions:
+ if partition["type"] != "blank":
+ sfile.write("$GPT add -i %d -b $CURR -s %s -t %s -l %s $1 && " % (
+ partition["num"], str(partition["var"]), partition["type"],
+ partition["label"]))
+
+ # Increment the CURR counter ready for the next partition.
+ sfile.write("CURR=$(( $CURR + %s ))\n" % partition["blocks"])
+
+ # Set default priorities on kernel partitions
+ sfile.write("$GPT add -i 2 -S 0 -T 15 -P 15 $1\n")
+ sfile.write("$GPT add -i 4 -S 0 -T 15 -P 0 $1\n")
+ sfile.write("$GPT add -i 6 -S 0 -T 15 -P 0 $1\n")
+
+ sfile.write("$GPT boot -p -b $2 -i 12 $1\n")
+ sfile.write("$GPT show $1\n")
+ sfile.write("}\n")
+
+
+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 WritePartitionScript(image_type, layout_filename, sfilename):
+ """Writes a shell script with functions for the base and requested layouts.
+
+ Args:
+ image_type: Type of image eg base/test/dev/factory_install
+ layout_filename: Path to partition configuration file
+ sfilename: Filename to write the finished script to
+ """
+
+ config = LoadPartitionConfig(layout_filename)
+
+ sfile = open(sfilename, "w")
+ script_shell = GetScriptShell()
+ sfile.write(script_shell)
+
+ WriteLayoutFunction(sfile, "write_base_table", "base", config)
+ WriteLayoutFunction(sfile, "write_partition_table", image_type, config)
+
+ sfile.close()
+
+
+def GetBlockSize(layout_filename):
+ """Returns the partition table block size.
+
+ Args:
+ 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(layout_filename):
+ """Returns the filesystem block size.
+
+ 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(image_type, layout_filename, num):
+ """Returns the partition size of a given partition for a given layout type.
+
+ Args:
+ 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
+ """
+
+ config = LoadPartitionConfig(layout_filename)
+ partitions = GetPartitionTable(config, image_type)
+ partition = GetPartitionByNumber(partitions, num)
+
+ return partition["bytes"]
+
+
+def GetFilesystemSize(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:
+ 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
+ """
+
+ config = LoadPartitionConfig(layout_filename)
+ partitions = GetPartitionTable(config, image_type)
+ partition = GetPartitionByNumber(partitions, num)
+
+ if "fs_bytes" in partition:
+ return partition["fs_bytes"]
+ else:
+ return partition["bytes"]
+
+
+def GetLabel(image_type, layout_filename, num):
+ """Returns the label for a given partition.
+
+ Args:
+ 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
+ """
+
+ config = LoadPartitionConfig(layout_filename)
+ partitions = GetPartitionTable(config, image_type)
+ partition = GetPartitionByNumber(partitions, num)
+
+ if "label" in partition:
+ return partition["label"]
+ else:
+ return "UNTITLED"
+
+
+def DoDebugOutput(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:
+ image_type: Type of image eg base/test/dev/factory_install
+ layout_filename: Path to partition configuration file
+ """
+ config = LoadPartitionConfig(layout_filename)
+ partitions = GetPartitionTable(config, 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 main(argv):
+ action_map = {
+ "write": {
+ "argc": 4,
+ "usage": " ",
+ "func": WritePartitionScript
+ },
+ "readblocksize": {
+ "argc": 2,
+ "usage": "",
+ "func": GetBlockSize
+ },
+ "readfsblocksize": {
+ "argc": 2,
+ "usage": "",
+ "func": GetFilesystemBlockSize
+ },
+ "readpartsize": {
+ "argc": 4,
+ "usage": " ",
+ "func": GetPartitionSize
+ },
+ "readfssize": {
+ "argc": 4,
+ "usage": " ",
+ "func": GetFilesystemSize
+ },
+ "readlabel": {
+ "argc": 4,
+ "usage": " ",
+ "func": GetLabel
+ },
+ "debug": {
+ "argc": 3,
+ "usage": " ",
+ "func": DoDebugOutput
+ }
+ }
+
+ if len(sys.argv) < 2 or sys.argv[1] not in action_map:
+ print "Usage: %s \n" % sys.argv[0]
+ print "Valid actions are:"
+ for action in action_map:
+ print " %s %s" % (action, action_map[action]["usage"])
+ sys.exit(1)
+ else:
+ action_name = sys.argv[1]
+ action = action_map[action_name]
+ if action["argc"] == len(sys.argv) - 1:
+ print action["func"](*sys.argv[2:])
+ else:
+ sys.exit("Usage: %s %s %s" % (sys.argv[0], sys.argv[1], action["usage"]))
+
+if __name__ == "__main__":
+ main(sys.argv)
diff --git a/build_library/cgpt_shell.sh b/build_library/cgpt_shell.sh
new file mode 100644
index 0000000000..68298f113d
--- /dev/null
+++ b/build_library/cgpt_shell.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+# 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.
+
+# This script is automatically generated by @SCRIPT_GENERATOR@
+# Do not edit!
+
+if ! type numsectors &>/dev/null; then
+ if [[ -f "/usr/sbin/chromeos-common.sh" ]]; then
+ . "/usr/sbin/chromeos-common.sh"
+ else
+ die "Can't load chromeos-common.sh, dying!"
+ fi
+fi
+locate_gpt
+
+# Usage: create_image
+# If is a block device, wipes out the GPT
+# If it's not, it creates a new file of the requested size
+create_image() {
+ local dev=$1
+ local min_disk_size=$2
+ local block_size=$3
+ if [[ -b "${dev}" ]]; then
+ # Zap any old partitions (otherwise gpt complains).
+ dd if=/dev/zero of="${dev}" conv=notrunc bs=512 count=32
+ dd if=/dev/zero of="${dev}" conv=notrunc bs=512 \
+ seek=$((${min_disk_size} - 1 - 33)) count=33
+ else
+ if [[ ! -e "${dev}" ]]; then
+ dd if=/dev/zero of="${dev}" bs=${block_size} count=1 \
+ seek=$((${min_disk_size} - 1))
+ fi
+ fi
+}
+
diff --git a/build_library/dev_image_util.sh b/build_library/dev_image_util.sh
index d80a0993ea..1e9f1c1e5f 100755
--- a/build_library/dev_image_util.sh
+++ b/build_library/dev_image_util.sh
@@ -16,73 +16,73 @@ install_dev_packages() {
trap "unmount_image ; delete_prompt" EXIT
- mount_image "${BUILD_DIR}/${image_name}" "${ROOT_FS_DIR}" \
- "${STATEFUL_FS_DIR}" "${ESP_FS_DIR}"
+ mount_image "${BUILD_DIR}/${image_name}" "${root_fs_dir}" \
+ "${stateful_fs_dir}" "${esp_fs_dir}"
# Determine the root dir for developer packages.
- local root_dev_dir="${ROOT_FS_DIR}/usr/local"
+ local root_dev_dir="${root_fs_dir}/usr/local"
# Install dev-specific init scripts into / from chromeos-dev-init.
- emerge_to_image --root="${ROOT_FS_DIR}" chromeos-dev-init
+ emerge_to_image --root="${root_fs_dir}" chromeos-dev-init
# Install developer packages described in chromeos-dev.
emerge_to_image --root="${root_dev_dir}" chromeos-dev
# Copy over the libc debug info so that gdb
# works with threads and also for a better debugging experience.
- sudo mkdir -p "${ROOT_FS_DIR}/usr/local/usr/lib/debug"
+ sudo mkdir -p "${root_fs_dir}/usr/local/usr/lib/debug"
pbzip2 -dc --ignore-trailing-garbage=1 "${LIBC_PATH}" | \
- sudo tar xpf - -C "${ROOT_FS_DIR}/usr/local/usr/lib/debug" \
+ sudo tar xpf - -C "${root_fs_dir}/usr/local/usr/lib/debug" \
./usr/lib/debug/usr/${CHOST} --strip-components=6
# Since gdb only looks in /usr/lib/debug, symlink the /usr/local
# path so that it is found automatically.
- sudo ln -s /usr/local/usr/lib/debug "${ROOT_FS_DIR}/usr/lib/debug"
+ sudo ln -s /usr/local/usr/lib/debug "${root_fs_dir}/usr/lib/debug"
# Install the bare necessary files so that the "emerge" command works
- sudo cp -a ${root_dev_dir}/share/portage ${ROOT_FS_DIR}/usr/share
+ 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
+ ${root_fs_dir}/usr/share/portage/config/make.globals
- sudo mkdir -p ${ROOT_FS_DIR}/etc/make.profile
+ 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}"
+ 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"
+ 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"
+ 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"
+ 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"
+ 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
+ "${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"
+ ${root_fs_dir}/usr/local/lib/python2.6/site-packages/pygtk.pth"
fi
# File searches /usr/share by default, so add a wrapper script so it
# can find the right path in /usr/local.
- local path="${ROOT_FS_DIR}/usr/local/bin/file"
+ local path="${root_fs_dir}/usr/local/bin/file"
if [[ -x ${path} ]]; then
sudo mv "${path}" "${path}.bin"
sudo_clobber "${path}" <"$unpack" <> "$unpack"
+
+ cat >>"${unpack}" <&2
+ exit 1
+fi
+set -x
+HEADER
+
+ $GPT show "${image}" | sed -e 's/^/# /' >>"${unpack}"
+ cp "${unpack}" "${pack}"
+
+ $GPT show -q "${image}" |
+ while read start size part x; do
+ local file="part_${part}"
+ local target="\"\${TARGET}\""
+ local dd_args="bs=512 count=${size}"
+ echo "dd if=${target} of=${file} ${dd_args} skip=${start}" >>"${unpack}"
+ echo "dd if=${file} of=${target} ${dd_args} seek=${start} conv=notrunc" \
+ >>"${pack}"
+ done
+
+ chmod +x "${unpack}" "${pack}"
+}
+
+write_partition_script() {
+ local image_type=$1
+ local partition_script_path=$2
+ get_disk_layout_path
+
+ sudo mkdir -p "$(dirname "${partition_script_path}")"
+
+ sudo "${BUILD_LIBRARY_DIR}/cgpt.py" "write" \
+ "${image_type}" "${DISK_LAYOUT_PATH}" "${partition_script_path}"
+}
+
+run_partition_script() {
+ local outdev=$1
+ local root_fs_img=$2
+
+ local pmbr_img
+ case ${ARCH} in
+ arm)
+ pmbr_img=/dev/zero
+ ;;
+ amd64|x86)
+ pmbr_img=$(readlink -f /usr/share/syslinux/gptmbr.bin)
+ ;;
+ *)
+ error "Unknown architecture: $ARCH"
+ return 1
+ ;;
+ esac
+
+ sudo mount -o loop "${root_fs_img}" "${root_fs_dir}"
+ . "${root_fs_dir}/${PARTITION_SCRIPT_PATH}"
+ write_partition_table "${outdev}" "${pmbr_img}"
+ sudo umount "${root_fs_dir}"
+}
+
+get_fs_block_size() {
+ get_disk_layout_path
+
+ echo $(${CGPT_PY} readfsblocksize ${DISK_LAYOUT_PATH})
+}
+
+get_block_size() {
+ get_disk_layout_path
+
+ echo $(${CGPT_PY} readblocksize ${DISK_LAYOUT_PATH})
+}
+
+get_partition_size() {
+ local image_type=$1
+ local part_id=$2
+ get_disk_layout_path
+
+ echo $(${CGPT_PY} readpartsize ${image_type} ${DISK_LAYOUT_PATH} ${part_id})
+}
+
+get_filesystem_size() {
+ local image_type=$1
+ local part_id=$2
+ get_disk_layout_path
+
+ echo $(${CGPT_PY} readfssize ${image_type} ${DISK_LAYOUT_PATH} ${part_id})
+}
+
+get_label() {
+ local image_type=$1
+ local part_id=$2
+ get_disk_layout_path
+
+ echo $(${CGPT_PY} readlabel ${image_type} ${DISK_LAYOUT_PATH} ${part_id})
+}
+
+get_disk_layout_type() {
+ DISK_LAYOUT_TYPE="base"
+ if should_build_image ${CHROMEOS_FACTORY_INSTALL_SHIM_NAME}; then
+ DISK_LAYOUT_TYPE="factory_install"
+ fi
+}
+
+emit_gpt_scripts() {
+ local image="$1"
+ local dir="$2"
+
+ local pack="${dir}/pack_partitions.sh"
+ local unpack="${dir}/unpack_partitions.sh"
+
+ cat >"${unpack}" <&2
+ exit 1
+fi
+set -x
+HEADER
+
+ $GPT show "${image}" | sed -e 's/^/# /' >>"${unpack}"
+ cp "${unpack}" "${pack}"
+
+ $GPT show -q "${image}" |
+ while read start size part x; do
+ local file="part_${part}"
+ local target="\"\$TARGET\""
+ local dd_args="bs=512 count=${size}"
+ echo "dd if=${target} of=${file} ${dd_args} skip=${start}" >>"${unpack}"
+ echo "dd if=${file} of=${target} ${dd_args} seek=${start} conv=notrunc" \
+ >>"${pack}"
+ done
+
+ chmod +x "${unpack}" "${pack}"
+}
+
+build_gpt() {
+ local outdev="$1"
+ local rootfs_img="$2"
+ local stateful_img="$3"
+ local esp_img="$4"
+
+ get_disk_layout_type
+ run_partition_script "${outdev}" "${rootfs_img}"
+
+ local sudo=
+ if [ ! -w "$outdev" ] ; then
+ # use sudo when writing to a block device.
+ sudo=sudo
+ fi
+
+ # Now populate the partitions.
+ info "Copying stateful partition..."
+ $sudo dd if="$stateful_img" of="$outdev" conv=notrunc bs=512 \
+ seek=$(partoffset ${outdev} 1)
+
+ info "Copying rootfs..."
+ $sudo dd if="$rootfs_img" of="$outdev" conv=notrunc bs=512 \
+ seek=$(partoffset ${outdev} 3)
+
+ info "Copying EFI system partition..."
+ $sudo dd if="$esp_img" of="$outdev" conv=notrunc bs=512 \
+ seek=$(partoffset ${outdev} 12)
+
+ # Pre-set "sucessful" bit in gpt, so we will never mark-for-death
+ # a partition on an SDCard/USB stick.
+ cgpt add -i 2 -S 1 "$outdev"
+}
diff --git a/build_library/legacy_disk_layout.json b/build_library/legacy_disk_layout.json
new file mode 100644
index 0000000000..766b0de64b
--- /dev/null
+++ b/build_library/legacy_disk_layout.json
@@ -0,0 +1,152 @@
+{
+ "metadata":{
+ "block_size": 512,
+ "fs_block_size": 4096
+ },
+ "layouts":{
+ "base":[
+ {
+ "num": 11,
+ "label":"RWFW",
+ "type":"firmware",
+ "blocks":"16384"
+ },
+ {
+ "num": 6,
+ "label":"KERN-C",
+ "type":"kernel",
+ "blocks":"1"
+ },
+ {
+ "num": 7,
+ "label":"ROOT-C",
+ "type":"rootfs",
+ "blocks":"1"
+ },
+ {
+ "num": 9,
+ "type":"reserved",
+ "label":"reserved",
+ "blocks":"1"
+ },
+ {
+ "num": 10,
+ "type":"reserved",
+ "label":"reserved",
+ "blocks":"1"
+ },
+ {
+ "type":"blank",
+ "blocks":"4028"
+ },
+ {
+ "num": 2,
+ "label":"KERN-A",
+ "type":"kernel",
+ "blocks":"32768"
+ },
+ {
+ "num": 4,
+ "label":"KERN-B",
+ "type":"kernel",
+ "blocks":"32768"
+ },
+ {
+ "num": 8,
+ "label":"OEM",
+ "type":"data",
+ "blocks":"32768"
+ },
+ {
+ "type":"blank",
+ "blocks":"131072"
+ },
+ {
+ "num": 12,
+ "label":"EFI-SYSTEM",
+ "type":"efi",
+ "blocks":"32768"
+ },
+ {
+ "num": 1,
+ "label":"STATE",
+ "type":"data",
+ "blocks":"2097152",
+ "features":["expand"]
+ },
+ {
+ "num": 5,
+ "label":"ROOT-B",
+ "type":"rootfs",
+ "blocks":"1"
+ },
+ {
+ "num": 3,
+ "label":"ROOT-A",
+ "type":"rootfs",
+ "blocks":"1757184",
+ "fs_blocks":"217600"
+ }
+ ],
+ "factory_install": [
+ {
+ "num": 1,
+ "label":"STATE",
+ "type":"data",
+ "blocks":"286720"
+ },
+ {
+ "num": 3,
+ "label":"ROOT-A",
+ "type":"rootfs",
+ "blocks":"860160",
+ "fs_blocks":"102400"
+ },
+ {
+ "num": 12,
+ "label":"EFI-SYSTEM",
+ "type":"efi",
+ "blocks":"65536"
+ }
+ ],
+ "vm": [
+ {
+ "num": 1,
+ "label":"STATE",
+ "type":"data",
+ "blocks":"6291456"
+ },
+ {
+ "num": 3,
+ "label":"ROOT-A",
+ "type":"rootfs",
+ "blocks":"2097152",
+ "fs_blocks":"217600"
+ },
+ {
+ "num": 5,
+ "label":"ROOT-B",
+ "type":"rootfs",
+ "blocks":"2097152",
+ "fs_blocks":"217600"
+ }
+ ],
+ "recovery": [
+ {
+ "num": 1,
+ "label":"STATE",
+ "type":"data",
+ "blocks":"4096"
+ }
+ ],
+ "pgo": [
+ {
+ "num": 3,
+ "label":"ROOT-A",
+ "type":"rootfs",
+ "blocks":"2662400",
+ "fs_blocks":"320000"
+ }
+ ]
+ }
+}
diff --git a/build_library/test_image_util.sh b/build_library/test_image_util.sh
index 112114c30a..a83588a83f 100755
--- a/build_library/test_image_util.sh
+++ b/build_library/test_image_util.sh
@@ -7,77 +7,13 @@
# functions and initialization shared between build_image and
# mod_image_for_test.sh.
#
-# TODO(jrbarnette): The two halves of this file aren't particularly
-# related; they're together merely to consolidate the shared code in
-# one file. Arguably, they should be broken up.
-
-
-# ----
-# The initialization and functions below are shared between
-# build_image and mod_image_for_test.sh. The code is not used
-# by the mod_image_for_test function.
-
-EMERGE_BOARD_CMD="$GCLIENT_ROOT/chromite/bin/parallel_emerge"
-EMERGE_BOARD_CMD="$EMERGE_BOARD_CMD --board=$BOARD"
-
-if [ $FLAGS_jobs -ne -1 ]; then
- EMERGE_JOBS="--jobs=$FLAGS_jobs"
-fi
-
-export INSTALL_MASK="${DEFAULT_INSTALL_MASK}"
-
-
-# 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..."
- $COMMON_PV_CAT "$src" >"$dst" || die "Cannot copy $1 to $2"
- else
- mv "${src}" "${dst}" || die "Cannot move $1 to $2"
- fi
-}
-
-# Basic command to emerge binary packages into the target image.
-# Arguments to this command are passed as addition options/arguments
-# to the basic emerge command.
-emerge_to_image() {
- sudo -E ${EMERGE_BOARD_CMD} --root-deps=rdeps --usepkgonly -v \
- "$@" ${EMERGE_JOBS}
-}
-
-# Returns 0 if any of the images was requested to be built, 1 otherwise.
-# $@ The name(s) of the images to check.
-should_build_image() {
- # Fast pass back if we should build all incremental images.
- local images="$@"
- local image_name
- local image_to_build
-
- for image_name in ${images}; do
- for image_to_build in ${IMAGES_TO_BUILD}; do
- [ ${image_to_build} = ${image_name} ] && return 0
- done
- done
-
- return 1
-}
-
-# ----
-# From here down, the main exported function is
-# 'mod_image_for_test'. The remainder of the code is not used
-# outside this file.
# 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"
+ local root_dev_dir="${root_fs_dir}/usr/local"
- emerge_to_image --root="${ROOT_FS_DIR}" chromeos-test-init
+ emerge_to_image --root="${root_fs_dir}" chromeos-test-init
emerge_to_image --root="${root_dev_dir}" chromeos-test
}
@@ -104,7 +40,7 @@ mod_image_for_test () {
trap unmount_image EXIT
mount_image "${BUILD_DIR}/${image_name}" \
- "${ROOT_FS_DIR}" "${STATEFUL_FS_DIR}"
+ "${root_fs_dir}" "${stateful_fs_dir}"
emerge_chromeos_test
@@ -115,8 +51,8 @@ mod_image_for_test () {
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}" \
+ sudo -E GCLIENT_ROOT="${GCLIENT_ROOT}" ROOT_FS_DIR="${root_fs_dir}" \
+ STATEFUL_DIR="${stateful_fs_dir}" ARCH="${ARCH}" BACKDOOR="${BACKDOOR}" \
BOARD_ROOT="${BOARD_ROOT}" \
"${mod_test_script}"
@@ -125,9 +61,9 @@ mod_image_for_test () {
if [ ${FLAGS_factory} -eq ${FLAGS_TRUE} ] ||
should_build_image "${CHROMEOS_FACTORY_TEST_IMAGE_NAME}"; then
- emerge_to_image --root="${ROOT_FS_DIR}" factorytest-init
+ emerge_to_image --root="${root_fs_dir}" factorytest-init
INSTALL_MASK="${FACTORY_TEST_INSTALL_MASK}"
- emerge_to_image --root="${ROOT_FS_DIR}/usr/local" \
+ emerge_to_image --root="${root_fs_dir}/usr/local" \
chromeos-base/autotest chromeos-base/autotest-all \
chromeos-base/chromeos-factory
prepare_hwid_for_factory "${BUILD_DIR}"
@@ -135,14 +71,14 @@ mod_image_for_test () {
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}" \
+ 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}"
+ sudo ldconfig -r "${root_fs_dir}"
- unmount_image
+ cleanup_mounts
trap - EXIT
# Now make it bootable with the flags from build_image.
diff --git a/common.sh b/common.sh
index 81ff811bab..daa916e76a 100644
--- a/common.sh
+++ b/common.sh
@@ -225,6 +225,7 @@ GCLIENT_ROOT=$(readlink -f "$GCLIENT_ROOT")
SRC_ROOT="$GCLIENT_ROOT/src"
SRC_INTERNAL="$GCLIENT_ROOT/src-internal"
SCRIPTS_DIR="$SRC_ROOT/scripts"
+BUILD_LIBRARY_DIR=${SCRIPTS_DIR}/build_library
# Load developer's custom settings. Default location is in scripts dir,
# since that's available both inside and outside the chroot. By convention,
diff --git a/image_to_vm.sh b/image_to_vm.sh
index 69baea065b..5c27c87708 100755
--- a/image_to_vm.sh
+++ b/image_to_vm.sh
@@ -10,6 +10,8 @@
# Helper scripts should be run from the same location as this script.
SCRIPT_ROOT=$(dirname "$(readlink -f "$0")")
. "${SCRIPT_ROOT}/common.sh" || exit 1
+. "${SCRIPT_ROOT}/build_library/disk_layout_util.sh" || exit 1
+. "${SCRIPT_ROOT}/build_library/build_common.sh" || exit 1
# Need to be inside the chroot to load chromeos-common.sh
assert_inside_chroot
@@ -33,30 +35,34 @@ DEFINE_string format "qemu" \
"Output format, either qemu, vmware or virtualbox"
DEFINE_string from "" \
"Directory containing rootfs.image and mbr.image"
-DEFINE_boolean full "${FLAGS_FALSE}" "Build full image with all partitions."
DEFINE_boolean make_vmx ${FLAGS_TRUE} \
"Create a vmx file for use with vmplayer (vmware only)."
DEFINE_integer mem "${DEFAULT_MEM}" \
"Memory size for the vm config in MBs (vmware only)."
-DEFINE_integer rootfs_partition_size 1024 \
- "rootfs parition size in MBs."
DEFINE_string state_image "" \
"Stateful partition image (defaults to creating new statful partition)"
-DEFINE_integer statefulfs_size 2048 \
- "Stateful partition size in MBs."
DEFINE_boolean test_image "${FLAGS_FALSE}" \
"Copies normal image to ${CHROMEOS_TEST_IMAGE_NAME}, modifies it for test."
DEFINE_string to "" \
"Destination folder for VM output file(s)"
DEFINE_string vbox_disk "${DEFAULT_VBOX_DISK}" \
"Filename for the output disk (virtualbox only)."
-DEFINE_integer vdisk_size 3072 \
- "virtual disk size in MBs."
DEFINE_string vmdk "${DEFAULT_VMDK}" \
"Filename for the vmware disk image (vmware only)."
DEFINE_string vmx "${DEFAULT_VMX}" \
"Filename for the vmware config (vmware only)."
+# The following arguments are ignored.
+# They are here as part of a transition for CL #29931 beacuse the buildbots
+# specify these arguments.
+DEFINE_integer vdisk_size 3072 \
+ "virtual disk size in MBs."
+DEFINE_boolean full "${FLAGS_FALSE}" "Build full image with all partitions."
+DEFINE_integer rootfs_partition_size 1024 \
+ "rootfs parition size in MBs."
+DEFINE_integer statefulfs_size 2048 \
+ "Stateful partition size in MBs."
+
# Parse command line
FLAGS "$@" || exit 1
eval set -- "${FLAGS_ARGV}"
@@ -68,15 +74,7 @@ if [ -z "${FLAGS_board}" ] ; then
die_notrace "--board is required."
fi
-if [ "${FLAGS_full}" -eq "${FLAGS_TRUE}" ] && \
- [[ ${FLAGS_vdisk_size} < ${MIN_VDISK_SIZE_FULL} || \
- ${FLAGS_statefulfs_size} < ${MIN_STATEFUL_FS_SIZE_FULL} ]]; then
- warn "Disk is too small for full, using minimum: vdisk size equal to \
-${MIN_VDISK_SIZE_FULL} and statefulfs size equal to \
-${MIN_STATEFUL_FS_SIZE_FULL}."
- FLAGS_vdisk_size=${MIN_VDISK_SIZE_FULL}
- FLAGS_statefulfs_size=${MIN_STATEFUL_FS_SIZE_FULL}
-fi
+BOARD="$FLAGS_board"
IMAGES_DIR="${DEFAULT_BUILD_ROOT}/images/${FLAGS_board}"
# Default to the most recent image
@@ -125,20 +123,17 @@ TEMP_KERN="${TEMP_DIR}"/part_2
if [ -n "${FLAGS_state_image}" ]; then
TEMP_STATE="${FLAGS_state_image}"
else
- # If we have a stateful fs size specified create a new state partition
- # of the specified size.
- if [ "${FLAGS_statefulfs_size}" -ne -1 ]; then
- STATEFUL_SIZE_BYTES=$((1024 * 1024 * ${FLAGS_statefulfs_size}))
- original_image_size=$(stat -c%s "${TEMP_STATE}")
- if [ "${original_image_size}" -gt "${STATEFUL_SIZE_BYTES}" ]; then
- die "Cannot resize stateful image to smaller than original. Exiting."
- fi
-
- echo "Resizing stateful partition to ${FLAGS_statefulfs_size}MB"
- # Extend the original file size to the new size.
- sudo e2fsck -pf "${TEMP_STATE}"
- sudo resize2fs "${TEMP_STATE}" ${FLAGS_statefulfs_size}M
+ STATEFUL_SIZE_BYTES=$(get_filesystem_size vm 1)
+ STATEFUL_SIZE_MEGABYTES=$(( STATEFUL_SIZE_BYTES / 1024 / 1024 ))
+ original_image_size=$(stat -c%s "${TEMP_STATE}")
+ if [ "${original_image_size}" -gt "${STATEFUL_SIZE_BYTES}" ]; then
+ die "Cannot resize stateful image to smaller than original. Exiting."
fi
+
+ echo "Resizing stateful partition to ${STATEFUL_SIZE_MEGABYTES}MB"
+ # Extend the original file size to the new size.
+ sudo e2fsck -pf "${TEMP_STATE}"
+ sudo resize2fs "${TEMP_STATE}" ${STATEFUL_SIZE_MEGABYTES}M
fi
TEMP_PMBR="${TEMP_DIR}"/pmbr
dd if="${SRC_IMAGE}" of="${TEMP_PMBR}" bs=512 count=1
@@ -164,26 +159,22 @@ sudo sed -i -e 's/sdb3/sda3/g' "${TEMP_MNT}/boot/syslinux/usb.A.cfg"
trap - INT TERM EXIT
cleanup
-# TOOD(adlr): pick a size that will for sure accomodate the partitions.
-dd if=/dev/zero of="${TEMP_IMG}" bs=1 count=1 \
- seek=$((${FLAGS_vdisk_size} * 1024 * 1024 - 1))
+# Set up a new partition table
+PARTITION_SCRIPT_PATH=$( tempfile )
+write_partition_script "vm" "${PARTITION_SCRIPT_PATH}"
+. "${PARTITION_SCRIPT_PATH}"
+write_partition_table "${TEMP_IMG}" "${TEMP_PMBR}"
+rm "${PARTITION_SCRIPT_PATH}"
-GPT_FULL="false"
-[ "${FLAGS_full}" -eq "${FLAGS_TRUE}" ] && GPT_FULL="true"
-
-# Set up the partition table
-install_gpt "${TEMP_IMG}" "$(numsectors $TEMP_ROOTFS)" \
- "$(numsectors $TEMP_STATE)" "${TEMP_PMBR}" "$(numsectors $TEMP_ESP)" \
- "${GPT_FULL}" ${FLAGS_rootfs_partition_size}
# Copy into the partition parts of the file
dd if="${TEMP_ROOTFS}" of="${TEMP_IMG}" conv=notrunc bs=512 \
- seek="${START_ROOTFS_A}"
+ seek=$(partoffset ${TEMP_IMG} 3)
dd if="${TEMP_STATE}" of="${TEMP_IMG}" conv=notrunc bs=512 \
- seek="${START_STATEFUL}"
+ seek=$(partoffset ${TEMP_IMG} 1)
dd if="${TEMP_KERN}" of="${TEMP_IMG}" conv=notrunc bs=512 \
- seek="${START_KERN_A}"
+ seek=$(partoffset ${TEMP_IMG} 2)
dd if="${TEMP_ESP}" of="${TEMP_IMG}" conv=notrunc bs=512 \
- seek="${START_ESP}"
+ seek=$(partoffset ${TEMP_IMG} 12)
# Make the built-image bootable and ensure that the legacy default usb boot
# uses /dev/sda instead of /dev/sdb3.
diff --git a/mod_image_for_recovery.sh b/mod_image_for_recovery.sh
index 1094562fdb..6be4613a94 100755
--- a/mod_image_for_recovery.sh
+++ b/mod_image_for_recovery.sh
@@ -11,6 +11,7 @@
SCRIPT_ROOT=$(dirname $(readlink -f "$0"))
. "${SCRIPT_ROOT}/build_library/build_common.sh" || exit 1
+. "${SCRIPT_ROOT}/build_library/disk_layout_util.sh" || exit 1
# Default recovery kernel name.
RECOVERY_KERNEL_NAME=recovery_vmlinuz.image
@@ -126,8 +127,8 @@ BOAT
create_recovery_kernel_image() {
local sysroot="$FACTORY_ROOT"
local vmlinuz="$sysroot/boot/vmlinuz"
- local root_offset=$(partoffset "$FLAGS_image" 3)
- local root_size=$(partsize "$FLAGS_image" 3)
+ local root_offset=$(partoffset "${RECOVERY_IMAGE}" 3)
+ local root_size=$(partsize "${RECOVERY_IMAGE}" 3)
local enable_rootfs_verification_flag=--noenable_rootfs_verification
if grep -q enable_rootfs_verification "${IMAGE_DIR}/boot.desc"; then
@@ -144,12 +145,12 @@ create_recovery_kernel_image() {
# recovery image generation. (Alternately, it means an image can be created,
# modified for recovery, then passed to a signer which can then sign both
# partitions appropriately without needing any external dependencies.)
- local kern_offset=$(partoffset "$FLAGS_image" 2)
- local kern_size=$(partsize "$FLAGS_image" 2)
+ local kern_offset=$(partoffset "${RECOVERY_IMAGE}" 2)
+ local kern_size=$(partsize "${RECOVERY_IMAGE}" 2)
local kern_tmp=$(mktemp)
local kern_hash=
- dd if="$FLAGS_image" bs=512 count=$kern_size \
+ dd if="${RECOVERY_IMAGE}" bs=512 count=$kern_size \
skip=$kern_offset of="$kern_tmp" 1>&2
# We're going to use the real signing block.
if [ $FLAGS_sync_keys -eq $FLAGS_TRUE ]; then
@@ -170,24 +171,23 @@ create_recovery_kernel_image() {
--keys_dir="${FLAGS_keys_dir}" \
${enable_rootfs_verification_flag} \
--nouse_dev_keys 1>&2 || failboat "build_kernel_image"
- sudo mount | sed 's/^/16651 /'
- sudo losetup -a | sed 's/^/16651 /'
+ #sudo mount | sed 's/^/16651 /'
+ #sudo losetup -a | sed 's/^/16651 /'
trap - RETURN
# Update the EFI System Partition configuration so that the kern_hash check
# passes.
- local efi_offset=$(partoffset "$FLAGS_image" 12)
- local efi_size=$(partsize "$FLAGS_image" 12)
+ local block_size=$(get_block_size)
+
+ local efi_offset=$(partoffset "${RECOVERY_IMAGE}" 12)
+ local efi_size=$(partsize "${RECOVERY_IMAGE}" 12)
+ local efi_offset_bytes=$(( $efi_offset * $block_size ))
+ local efi_size_bytes=$(( $efi_size * $block_size ))
- local efi_dev=$(sudo losetup --show -f \
- -o $((efi_offset * 512)) \
- --sizelimit $((efi_size * 512)) \
- "$FLAGS_image")
local efi_dir=$(mktemp -d)
- trap "sudo losetup -d $efi_dev && rmdir \"$efi_dir\"" EXIT
- echo "16651 mount: $efi_dev -> $efi_dir"
- sudo mount "$efi_dev" "$efi_dir"
- sudo mount | sed 's/^/16651 /'
+ sudo mount -o loop,offset=${efi_offset_bytes},sizelimit=${efi_size_bytes} \
+ "${RECOVERY_IMAGE}" "${efi_dir}"
+
sudo sed -i -e "s/cros_legacy/cros_legacy kern_b_hash=$kern_hash/g" \
"$efi_dir/syslinux/usb.A.cfg" || true
# This will leave the hash in the kernel for all boots, but that should be
@@ -195,8 +195,6 @@ create_recovery_kernel_image() {
sudo sed -i -e "s/cros_efi/cros_efi kern_b_hash=$kern_hash/g" \
"$efi_dir/efi/boot/grub.cfg" || true
safe_umount "$efi_dir"
- sudo losetup -a | sed 's/^/16651 /'
- sudo losetup -d "$efi_dev"
rmdir "$efi_dir"
trap - EXIT
}
@@ -269,48 +267,59 @@ update_partition_table() {
local resized_sectors=$3 # number of sectors in resized stateful partition
local temp_img=$4
- local kern_a_offset=$(partoffset ${src_img} 2)
+ local kern_a_dst_offset=$(partoffset ${temp_img} 2)
+ local kern_a_src_offset=$(partoffset ${src_img} 2)
local kern_a_count=$(partsize ${src_img} 2)
- local kern_b_offset=$(partoffset ${src_img} 4)
+
+ local kern_b_dst_offset=$(partoffset ${temp_img} 4)
+ local kern_b_src_offset=$(partoffset ${src_img} 4)
local kern_b_count=$(partsize ${src_img} 4)
- local rootfs_offset=$(partoffset ${src_img} 3)
+
+ local rootfs_dst_offset=$(partoffset ${temp_img} 3)
+ local rootfs_src_offset=$(partoffset ${src_img} 3)
local rootfs_count=$(partsize ${src_img} 3)
- local oem_offset=$(partoffset ${src_img} 8)
+
+ local oem_dst_offset=$(partoffset ${temp_img} 8)
+ local oem_src_offset=$(partoffset ${src_img} 8)
local oem_count=$(partsize ${src_img} 8)
- local esp_offset=$(partoffset ${src_img} 12)
+
+ local esp_dst_offset=$(partoffset ${temp_img} 12)
+ local esp_src_offset=$(partoffset ${src_img} 12)
local esp_count=$(partsize ${src_img} 12)
+ local state_dst_offset=$(partoffset ${temp_img} 1)
+
local temp_pmbr=$(mktemp "/tmp/pmbr.XXXXXX")
dd if="${src_img}" of="${temp_pmbr}" bs=512 count=1 &>/dev/null
trap "rm -rf \"${temp_pmbr}\"" EXIT
# Set up a new partition table
- install_gpt "${temp_img}" "${rootfs_count}" "${resized_sectors}" \
- "${temp_pmbr}" "${esp_count}" false \
- $(((rootfs_count * 512)/(1024 * 1024)))
+ PARTITION_SCRIPT_PATH=$( tempfile )
+ write_partition_script "recovery" "${PARTITION_SCRIPT_PATH}"
+ . "${PARTITION_SCRIPT_PATH}"
+ write_partition_table "${temp_img}" "${temp_pmbr}"
+ echo "${PARTITION_SCRIPT_PATH}"
+ #rm "${PARTITION_SCRIPT_PATH}"
# Copy into the partition parts of the file
dd if="${src_img}" of="${temp_img}" conv=notrunc bs=512 \
- seek="${START_ROOTFS_A}" skip=${rootfs_offset} count=${rootfs_count}
+ seek=${kern_a_dst_offset} skip=${kern_a_src_offset} count=${rootfs_count}
dd if="${temp_state}" of="${temp_img}" conv=notrunc bs=512 \
- seek="${START_STATEFUL}"
+ seek=${state_dst_offset}
# Copy the full kernel (i.e. with vboot sections)
dd if="${src_img}" of="${temp_img}" conv=notrunc bs=512 \
- seek="${START_KERN_A}" skip=${kern_a_offset} count=${kern_a_count}
+ seek=${kern_a_dst_offset} skip=${kern_a_src_offset} count=${kern_a_count}
dd if="${src_img}" of="${temp_img}" conv=notrunc bs=512 \
- seek="${START_KERN_B}" skip=${kern_b_offset} count=${kern_b_count}
+ seek=${kern_b_dst_offset} skip=${kern_b_src_offset} count=${kern_b_count}
dd if="${src_img}" of="${temp_img}" conv=notrunc bs=512 \
- seek="${START_OEM}" skip=${oem_offset} count=${oem_count}
+ seek=${oem_dst_offset} skip=${oem_src_offset} count=${oem_count}
dd if="${src_img}" of="${temp_img}" conv=notrunc bs=512 \
- seek="${START_ESP}" skip=${esp_offset} count=${esp_count}
+ seek=${esp_dst_offset} skip=${esp_src_offset} count=${esp_count}
}
maybe_resize_stateful() {
# If we're not minimizing, then just copy and go.
if [ $FLAGS_minimize_image -eq $FLAGS_FALSE ]; then
- if [ "$FLAGS_image" != "$RECOVERY_IMAGE" ]; then
- cp "$FLAGS_image" "$RECOVERY_IMAGE"
- fi
return 0
fi
@@ -337,7 +346,7 @@ maybe_resize_stateful() {
# Create a recovery image of the right size
# TODO(wad) Make the developer script case create a custom GPT with
# just the kernel image and stateful.
- update_partition_table "$FLAGS_image" "$small_stateful" 4096 \
+ update_partition_table "${RECOVERY_IMAGE}" "$small_stateful" 4096 \
"$RECOVERY_IMAGE" 1>&2
return $err
}
@@ -395,6 +404,10 @@ if [ $FLAGS_modify_in_place -eq $FLAGS_TRUE ]; then
die_notrace "Cannot use --modify_in_place and --minimize_image together."
fi
RECOVERY_IMAGE="${FLAGS_image}"
+else
+ if [[ ${FLAGS_modify_in_place} -eq ${FLAGS_FALSE} ]]; then
+ cp "${FLAGS_image}" "${RECOVERY_IMAGE}"
+ fi
fi
echo "Creating recovery image from ${FLAGS_image}"
@@ -422,10 +435,6 @@ if [ $FLAGS_kernel_image_only -eq $FLAGS_TRUE ]; then
exit 0
fi
-if [ $FLAGS_modify_in_place -eq $FLAGS_FALSE ]; then
- rm "$RECOVERY_IMAGE" || true # Start fresh :)
-fi
-
trap cleanup EXIT
maybe_resize_stateful # Also copies the image if needed.