• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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