#!/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. # Script to preserve the on-disk file layout of the specified image and # the latest shipping image. This is accomplished by copying the new rootfs # over a template rootfs (aka the latest shipping image) to preserve as much # of the metadata from the shipping rootfs as possible. This will ensure # minimal disk shuffling when applying the auto-update. # # Note: This script does not recompute the rootfs hash. # Load common library. This should be the first executable line. # The path to common.sh should be relative to your script's location. . "$(dirname "$0")/common.sh" load_shflags # Flags. DEFINE_string image "" \ "The image that needs to be aligned to the latest shipping image." DEFINE_string src_image "" \ "The image to align against." # Copies the rootfs from |SRC_IMAGE| to the |DST_ROOT_FS| and preserves as # much of the file system metadata in |DST_ROOT_FS| as possible. # Args: SRC_IMAGE DST_ROOT_FS copy_root_fs() { local src_image=$1 local dst_root_fs=$2 # Mount the src and dst rootfs. local src_root_fs_dir=$(mktemp -d "/tmp/align_root_fs_src_mount_dir.XXXX") add_cleanup_action "sudo rm -rf \"${src_root_fs_dir}\"" mount_image_partition_ro "${src_image}" 3 "${src_root_fs_dir}" add_cleanup_action "sudo umount \"${src_root_fs_dir}\"" local dst_root_fs_dir=$(mktemp -d "/tmp/align_root_fs_dst_mount_dir.XXXX") add_cleanup_action "sudo rm -rf \"${dst_root_fs_dir}\"" sudo mount -o loop "${dst_root_fs}" "${dst_root_fs_dir}" -o loop add_cleanup_action "sudo umount \"${dst_root_fs_dir}\"" # Temporarily make immutable files on the dst rootfs mutable. # We'll need to track these files in ${immutable_files} so we can make them # mutable again. local immutable_files=() sudo find "${dst_root_fs_dir}" -xdev -type f | while read -r file; do immutable=$(sudo lsattr "${file}" | cut -d' ' -f1 | grep -q i ; echo $?) if [ $immutable -eq 0 ]; then immutable_files=("${immutable_files[@]}" "${file}") sudo chattr -i "${file}" fi done # Copy files from the src rootfs over top of dst rootfs. # Use the --inplace flag to preserve as much of the file system metadata # as possible. sudo rsync -v -a -H -A -x --force --inplace --numeric-ids --delete \ "${src_root_fs_dir}"/ "${dst_root_fs_dir}" # Make immutable files immutable again. for file in ${immutable_files[*]} ; do sudo chattr +i "${file}" done # Unmount the src and dst root fs so that we can replace the rootfs later. perform_latest_cleanup_action perform_latest_cleanup_action perform_latest_cleanup_action perform_latest_cleanup_action } # Zeroes the rootfs free space in the specified image. # Args: IMAGE zero_root_fs_free_space() { local image=$1 local root_fs_dir=$(mktemp -d "/tmp/align_rootfs_zero_free_space_dir.XXXX") add_cleanup_action "sudo rm -rf \"${root_fs_dir}\"" mount_image_partition "${image}" 3 "${root_fs_dir}" add_cleanup_action "sudo umount \"${root_fs_dir}\"" info "Zeroing free space in rootfs" sudo dd if=/dev/zero of="${root_fs_dir}/filler" oflag=sync bs=4096 || true sudo rm -f "${root_fs_dir}/filler" sudo sync perform_latest_cleanup_action perform_latest_cleanup_action } main() { # Parse command line. FLAGS "$@" || exit 1 eval set -- "${FLAGS_ARGV}" # Only now can we die on error. shflags functions leak non-zero error codes, # so will die prematurely if 'set -e' is specified before now. set -e # Make sure we have the required parameters. if [ -z "${FLAGS_image}" ]; then die "--image is required." fi if [ ! -f "${FLAGS_image}" ]; then die "Cannot find the specified image." fi if [ -z "${FLAGS_src_image}" ]; then die "--src_image is required." fi if [ ! -f "${FLAGS_src_image}" ]; then die "Cannot find the specified source image." fi # Make sure the two rootfs are the same size. # If they are not, then there is nothing for us to do. # Note: Exit with a zero code so we do not break the build workflow. local src_root_fs_size=$(partsize "${FLAGS_src_image}" 3) local new_root_fs_size=$(partsize "${FLAGS_image}" 3) if [ ${src_root_fs_size} -ne ${new_root_fs_size} ]; then warn "The source rootfs and the new rootfs are not the same size." exit 0 fi # Extract the rootfs from the src image and use this as a template # for the new image. temp_root_fs=$(mktemp "/tmp/align_rootfs_temp_rootfs.XXXX") add_cleanup_action "sudo rm -f \"${temp_root_fs}\"" info "Extracting rootfs from src image" extract_image_partition "${FLAGS_src_image}" 3 "${temp_root_fs}" enable_rw_mount "${temp_root_fs}" # Perform actual copy of the two root file systems. info "Copying rootfs" copy_root_fs "${FLAGS_image}" "${temp_root_fs}" # Replace the rootfs in the new image with the aligned version. info "Replacing rootfs" replace_image_partition "${FLAGS_image}" 3 "${temp_root_fs}" # Zero rootfs free space. zero_root_fs_free_space "${FLAGS_image}" } main "$@"