termina_build_image: transition to Python version

The shipping Crostini Termina images are built by a reimplementation of
termina_build_image in Python, which lives in the container-guest-tools
repository. The Python version also works outside of the cros_sdk chroot
environment.

In order to reduce duplication and minimize confusion, replace the bash
implementation with a transitional script that calls the Python version.

BUG=chromium:999698
TEST=./termina_build_image --image=chromiumos_test_image.bin --output=/tmp/termina

Change-Id: Ibac7c5963892e76f4a606540e9943a057c26e529
Signed-off-by: Daniel Verkamp <dverkamp@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/1779154
Legacy-Commit-Queue: Commit Bot <commit-bot@chromium.org>
Reviewed-by: Chris McDonald <cjmcdonald@chromium.org>
Reviewed-by: Stephen Barber <smbarber@chromium.org>
diff --git a/termina_build_image b/termina_build_image
index 6bbe3d3..3593ab0 100755
--- a/termina_build_image
+++ b/termina_build_image
@@ -7,6 +7,9 @@
 . "${SCRIPT_ROOT}/build_library/build_common.sh" || exit 1
 . "${SCRIPT_ROOT}/build_library/filesystem_util.sh" || exit 1
 
+TERMINA_BUILD_IMAGE_PY="${SCRIPT_ROOT}/../platform/container-guest-tools/termina/termina_build_image.py"
+TERMINA_BUILD_IMAGE_PY="$(readlink -f "${TERMINA_BUILD_IMAGE_PY}")"
+
 assert_inside_chroot "$@"
 
 DEFINE_string arch "amd64" \
@@ -28,156 +31,9 @@
 eval set -- "${FLAGS_ARGV}"
 switch_to_strict_mode
 
-get_version() {
-  local output_dir="$1"
-  awk -F'=' -v key='CHROMEOS_RELEASE_VERSION' '$1==key { print $2 }' \
-    "${output_dir}"/lsb-release
-}
-
-read_le_int() {
-  local disk="$1"
-  local offset="$2"
-  local size="$3"
-
-  case "${size}" in
-  1 | 2 | 4 | 8)
-    ;;
-  *) die "${size} is not a valid int size to read"
-    ;;
-  esac
-
-  local raw="$(xxd -g ${size} -e -s ${offset} -l ${size} ${disk} | cut -d' ' -f2)"
-  local result="$(( 16#${raw} ))"
-
-  echo "${result}"
-}
-
-extract_squashfs_partition() {
-  local src_disk="$1"
-  local src_part="$2"
-  local dst_file="$3"
-
-  local part_start_blks="$(cgpt show -i "${src_part}" -b "${src_disk}")"
-  local part_start_bytes="$(( part_start_blks * 512 ))"
-  local part_size_blks="$(cgpt show -i "${src_part}" -s "${src_disk}")"
-  local part_size_bytes="$(( part_size_blks * 512 ))"
-
-  # To be sure we're extracting a squashfs partition, verify the magic.
-  # See fs/squashfs/squashfs_fs.h.
-  local magic="$(read_le_int ${src_disk} ${part_start_bytes} 4)"
-  if [[ "${magic}" -ne 0x73717368 ]]; then
-    die "Partition ${src_part} doesn't look like a squashfs partition"
-  fi
-
-  dd if="${src_disk}" of="${dst_file}" skip="${part_start_bytes}c" \
-    count="${part_size_bytes}c" iflag=skip_bytes,count_bytes
-}
-
-can_hardlink() {
-  local file1=$1
-  local file2=$2
-
-  # The file is considered hard-linkable if the access rights, user, and group
-  # are the same.
-  [[ "$(sudo stat -c '%a' ${prev_line})" = "$(sudo stat -c '%a' ${line})" ]] && \
-     [[ "$(sudo stat -c '%u' ${prev_line})" = "$(sudo stat -c '%u' ${line})" ]] && \
-     [[ "$(sudo stat -c '%g' ${prev_line})" = "$(sudo stat -c '%g' ${line})" ]]
-}
-
-do_hardlinks() {
-  local dir=$1
-
-  local line prev_line=""
-  if [ -z $(command -v fdupes) ]; then
-    warn "Please install fdupes for removing dups"
-  fi
-  while read line; do
-    # Treat the first file as the original.
-    if [[ -n "${prev_line}" && -n "${line}" ]]; then
-      if can_hardlink "${prev_line}" "${line}"; then
-        sudo ln -f "${prev_line}" "${line}"
-      fi
-    fi
-
-    prev_line="${line}"
-  done < <(sudo fdupes --recurse ${dir})
-}
-
-# Repack termina rootfs.
-repack_rootfs() {
-  local output_dir="$1"
-  local fs_type="$2"
-  local arch="$3"
-  local rootfs_img="${output_dir}/vm_rootfs.img"
-  local stateful_img="${output_dir}/vm_stateful.img"
-
-  # Create image in a temporary directory to avoid the need for extra space
-  # on the final rootfs.
-  local rootfs="${output_dir}/rootfs"
-  local stateful="${output_dir}/stateful"
-
-  sudo unsquashfs -d "${rootfs}" "${rootfs_img}"
-  sudo unsquashfs -d "${stateful}" "${stateful_img}"
-
-  # Remove source images.
-  sudo rm -f "${rootfs_img}" "${stateful_img}"
-
-  # Fix up rootfs.
-
-  # Remove efi cruft.
-  sudo rm -rf "${rootfs}/boot"/{efi,syslinux}
-  # Don't need firmware if you don't have hardware!
-  sudo rm -rf "${rootfs}/lib/firmware"
-  # Get rid of stateful, it's not needed on termina.
-  sudo rm -rf "${rootfs}/mnt/stateful_partition"
-  # Create container stateful and shared dirs.
-  sudo mkdir "${rootfs}"/mnt/{stateful,shared}
-  # Copy the dev_image into its location at /usr/local.
-  sudo cp -aT "${stateful}"/dev_image "${rootfs}/usr/local"
-
-  if [[ "${arch}" == "arm" ]]; then
-    cp "${rootfs}"/boot/Image-* "${output_dir}/vm_kernel"
-  else
-    cp "${rootfs}"/boot/vmlinuz "${output_dir}/vm_kernel"
-  fi
-
-  # Remove vmlinuz from the rootfs; it's not necessary.
-  sudo rm -rf "${rootfs}"/boot/vmlinuz*
-
-  do_hardlinks "${rootfs}"
-
-  sudo cp "${rootfs}/etc/lsb-release" "${output_dir}/lsb-release"
-  sudo cp "${rootfs}/opt/google/chrome/resources/about_os_credits.html" \
-      "${output_dir}/about_os_credits.html"
-
-  case "${fs_type}" in
-  squashfs)
-    sudo mksquashfs "${rootfs}" "${rootfs_img}" -comp lzo
-    ;;
-  ext4)
-    # Start with 110% rootfs size, then shrink.
-    local image_size=$(sudo du -sxm "${rootfs}" | awk '{print $1}')
-    let image_size=image_size*11/10
-    truncate --size "${image_size}M" "${rootfs_img}"
-    /sbin/mkfs.ext4 -F -m 0 -i 16384 -b 4096 -O "^has_journal" "${rootfs_img}"
-    local rootfs_mnt="$(mktemp -d)"
-    fs_mount "${rootfs_img}" "${rootfs_mnt}" ext4 rw
-    sudo cp -aT "${rootfs}" "${rootfs_mnt}"
-    fs_umount "${rootfs_img}" "${rootfs_mnt}" ext4 rw
-    # Shrink to minimum size.
-    /sbin/e2fsck -f "${rootfs_img}"
-    /sbin/resize2fs -M "${rootfs_img}"
-    rmdir "${rootfs_mnt}"
-    ;;
-  *)
-    die_notrace "Unsupported fs type ${fs_type}."
-    ;;
-  esac
-
-  sudo rm -rf "${rootfs}" "${stateful}"
-}
-
 main() {
+  warn "termina_build_image is deprecated. Please use termina_build_image.py."
+
   if [[ -z "${FLAGS_image}" ]]; then
     die_notrace "Please provide an image using --image"
   elif [[ ! -f "${FLAGS_image}" ]]; then
@@ -188,32 +44,16 @@
     die_notrace "Architecture '${FLAGS_arch}' is not valid. Options are 'amd64' and 'arm'"
   fi
 
-  case "${FLAGS_filesystem}" in
-  squashfs|ext4)
-    ;;
-  *)
-    die_notrace "Filesystem '${FLAGS_filesystem}' is not valid. Options are 'squashfs' and 'ext4'"
-    ;;
-  esac
-
-  if [[ -z "${FLAGS_output}" ]]; then
-    die_notrace "Output directory was not specified"
-  elif [[ -e "${FLAGS_output}" ]]; then
-    die_notrace "${FLAGS_output} already exists"
+  if [[ "${FLAGS_filesystem}" != "ext4" ]]; then
+    die_notrace "Filesystem '${FLAGS_filesystem}' is not valid. 'ext4' is valid."
   fi
 
-  local output_dir="${FLAGS_output}"
-  local stateful_img="${output_dir}/vm_stateful.img"
-  local rootfs_img="${output_dir}/vm_rootfs.img"
-  local image="${FLAGS_image}"
+  info "Equivalent termina_build_image.py command:"
+  info "${TERMINA_BUILD_IMAGE_PY} ${FLAGS_image} ${FLAGS_output}"
 
-  mkdir -p "${output_dir}"
-  extract_squashfs_partition "${image}" "3" "${rootfs_img}"
-  extract_squashfs_partition "${image}" "1" "${stateful_img}"
+  sudo "${TERMINA_BUILD_IMAGE_PY}" "${FLAGS_image}" "${FLAGS_output}"
 
-  repack_rootfs "${output_dir}" "${FLAGS_filesystem}" "${FLAGS_arch}"
-
-  info "Done! The resulting image is in '${output_dir}'"
+  info "Done! The resulting image is in '${FLAGS_output}'"
 }
 
 main "$@"