1#!/bin/bash 2 3# Copyright (c) 2012 The Chromium OS Authors. All rights reserved. 4# Use of this source code is governed by a BSD-style license that can be 5# found in the LICENSE file. 6 7# Script to preserve the on-disk file layout of the specified image and 8# the latest shipping image. This is accomplished by copying the new rootfs 9# over a template rootfs (aka the latest shipping image) to preserve as much 10# of the metadata from the shipping rootfs as possible. This will ensure 11# minimal disk shuffling when applying the auto-update. 12# 13# Note: This script does not recompute the rootfs hash. 14 15# Load common library. This should be the first executable line. 16# The path to common.sh should be relative to your script's location. 17. "$(dirname "$0")/common.sh" 18 19load_shflags 20 21# Flags. 22DEFINE_string image "" \ 23 "The image that needs to be aligned to the latest shipping image." 24DEFINE_string src_image "" \ 25 "The image to align against." 26 27# Copies the rootfs from |SRC_IMAGE| to the |DST_ROOT_FS| and preserves as 28# much of the file system metadata in |DST_ROOT_FS| as possible. 29# Args: SRC_IMAGE DST_ROOT_FS 30copy_root_fs() { 31 local src_image=$1 32 local dst_root_fs=$2 33 34 # Mount the src and dst rootfs. 35 local src_root_fs_dir=$(mktemp -d "/tmp/align_root_fs_src_mount_dir.XXXX") 36 add_cleanup_action "sudo rm -rf \"${src_root_fs_dir}\"" 37 mount_image_partition_ro "${src_image}" 3 "${src_root_fs_dir}" 38 add_cleanup_action "sudo umount \"${src_root_fs_dir}\"" 39 40 local dst_root_fs_dir=$(mktemp -d "/tmp/align_root_fs_dst_mount_dir.XXXX") 41 add_cleanup_action "sudo rm -rf \"${dst_root_fs_dir}\"" 42 sudo mount -o loop "${dst_root_fs}" "${dst_root_fs_dir}" -o loop 43 add_cleanup_action "sudo umount \"${dst_root_fs_dir}\"" 44 45 # Temporarily make immutable files on the dst rootfs mutable. 46 # We'll need to track these files in ${immutable_files} so we can make them 47 # mutable again. 48 local immutable_files=() 49 sudo find "${dst_root_fs_dir}" -xdev -type f | 50 while read -r file; do 51 immutable=$(sudo lsattr "${file}" | cut -d' ' -f1 | grep -q i ; echo $?) 52 if [ $immutable -eq 0 ]; then 53 immutable_files=("${immutable_files[@]}" "${file}") 54 sudo chattr -i "${file}" 55 fi 56 done 57 58 # Copy files from the src rootfs over top of dst rootfs. 59 # Use the --inplace flag to preserve as much of the file system metadata 60 # as possible. 61 sudo rsync -v -a -H -A -x --force --inplace --numeric-ids --delete \ 62 "${src_root_fs_dir}"/ "${dst_root_fs_dir}" 63 64 # Make immutable files immutable again. 65 for file in ${immutable_files[*]} ; do 66 sudo chattr +i "${file}" 67 done 68 69 # Unmount the src and dst root fs so that we can replace the rootfs later. 70 perform_latest_cleanup_action 71 perform_latest_cleanup_action 72 perform_latest_cleanup_action 73 perform_latest_cleanup_action 74} 75 76# Zeroes the rootfs free space in the specified image. 77# Args: IMAGE 78zero_root_fs_free_space() { 79 local image=$1 80 local root_fs_dir=$(mktemp -d "/tmp/align_rootfs_zero_free_space_dir.XXXX") 81 add_cleanup_action "sudo rm -rf \"${root_fs_dir}\"" 82 mount_image_partition "${image}" 3 "${root_fs_dir}" 83 add_cleanup_action "sudo umount \"${root_fs_dir}\"" 84 85 info "Zeroing free space in rootfs" 86 sudo dd if=/dev/zero of="${root_fs_dir}/filler" oflag=sync bs=4096 || true 87 sudo rm -f "${root_fs_dir}/filler" 88 sudo sync 89 90 perform_latest_cleanup_action 91 perform_latest_cleanup_action 92} 93 94main() { 95 # Parse command line. 96 FLAGS "$@" || exit 1 97 eval set -- "${FLAGS_ARGV}" 98 99 # Only now can we die on error. shflags functions leak non-zero error codes, 100 # so will die prematurely if 'set -e' is specified before now. 101 set -e 102 103 # Make sure we have the required parameters. 104 if [ -z "${FLAGS_image}" ]; then 105 die "--image is required." 106 fi 107 108 if [ ! -f "${FLAGS_image}" ]; then 109 die "Cannot find the specified image." 110 fi 111 112 if [ -z "${FLAGS_src_image}" ]; then 113 die "--src_image is required." 114 fi 115 116 if [ ! -f "${FLAGS_src_image}" ]; then 117 die "Cannot find the specified source image." 118 fi 119 120 # Make sure the two rootfs are the same size. 121 # If they are not, then there is nothing for us to do. 122 # Note: Exit with a zero code so we do not break the build workflow. 123 local src_root_fs_size=$(partsize "${FLAGS_src_image}" 3) 124 local new_root_fs_size=$(partsize "${FLAGS_image}" 3) 125 if [ ${src_root_fs_size} -ne ${new_root_fs_size} ]; then 126 warn "The source rootfs and the new rootfs are not the same size." 127 exit 0 128 fi 129 130 # Extract the rootfs from the src image and use this as a template 131 # for the new image. 132 temp_root_fs=$(mktemp "/tmp/align_rootfs_temp_rootfs.XXXX") 133 add_cleanup_action "sudo rm -f \"${temp_root_fs}\"" 134 info "Extracting rootfs from src image" 135 extract_image_partition "${FLAGS_src_image}" 3 "${temp_root_fs}" 136 enable_rw_mount "${temp_root_fs}" 137 138 # Perform actual copy of the two root file systems. 139 info "Copying rootfs" 140 copy_root_fs "${FLAGS_image}" "${temp_root_fs}" 141 142 # Replace the rootfs in the new image with the aligned version. 143 info "Replacing rootfs" 144 replace_image_partition "${FLAGS_image}" 3 "${temp_root_fs}" 145 146 # Zero rootfs free space. 147 zero_root_fs_free_space "${FLAGS_image}" 148} 149 150main "$@" 151