Home | History | Annotate | Download | only in image_signing
      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 
     19 load_shflags
     20 
     21 # Flags.
     22 DEFINE_string image "" \
     23   "The image that needs to be aligned to the latest shipping image."
     24 DEFINE_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
     30 copy_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
     78 zero_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 
     94 main() {
     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 
    150 main "$@"
    151