#!/bin/bash
# linaro-media-create - Create an installation media from a Linaro image

# Copyright 2010 Robert Nelson <robertcnelson@gmail.com>
# Copyright 2010 Linaro
# Based on rcn's setup_sdcard.sh script.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 3 as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

set -e

unset DEVICE BOOTFS ROOTFS IMAGE_FILE HWPACK_FILE UBOOT_FLAVOR KERNEL_ADDR
unset INITRD_ADDR CREATE_SWAP SWAP_SIZE DEPLOY_STEPS

#Defaults
RFS=ext3
BINARY_TARBALL='binary-tar.tar.gz'
BOOT_LABEL=boot
RFS_LABEL=rootfs
IS_LIVE=
FAT_SIZE=32
IMAGE_SIZE=2G
MMC_PART_OFFSET=0
BOOTFS_STEP="create_boot_cmd populate_boot"
ROOTFS_STEP="populate_rootfs"
PARTITION_STEP="create_partitions"

DIR=$PWD
TMP_DIR=$(mktemp -d)
cleanup_tempfiles() {
  rm -r "$TMP_DIR"

  cleanup_tempfiles() { :; }
}

BOOT_DISK="${DIR}/boot-disc"
ROOT_DISK="${DIR}/root-disc"

cleanup_mountpoints() {

  local dir

  for dir in "$BOOT_DISK" "$ROOT_DISK"; do
    if [ -d "$dir" ]; then
      rmdir -v "$dir"
    fi
  done

}

PATH="$(dirname "$(readlink -f "$0")"):$PATH"

ensure_command() {
  # ensure_command foo foo-package
  which "$1" 2>/dev/null 1>/dev/null || ( echo "Installing required command $1 from package $2" && sudo apt-get install "$2" )
}

ensure_command sfdisk util-linux
ensure_command fdisk util-linux

usage() {
  echo "usage: $(basename $0) --mmc /dev/sdd"
  echo "<or>"
  echo "usage: $(basename $0) --image_file mmc.img"
  cat <<EOF

required options:
--mmc </dev/sdX>
    Unformatted Storage Device
<or>
--image_file <xxx>
    specify name of image file

--dev <board>
    use development boot options; this includes setting up serial ttys as well
    as enabling normal debug options for the target board. Current board values:
    * beagle
    * igep
    * mx51evk
    * panda
    * ux500
    * vexpress

Additional/Optional options:
-h --help
    this help

--rootfs <fs_type>
    ext2
    ext3 - <set as default>
    ext4
    btrfs

--boot_label <boot_label>
    boot partition label

--rfs_label <rfs_label>
    rootfs partition label

--swap_file <xxx>
    Creats a Swap file of (xxx)MB's

--live
    Create boot command for casper/live images; if this is not
    provided a UUID for the rootfs is generated and used as the root=
    option

--live-256m
    Create boot command for casper/live images; adds only-ubiquity option
    to allow use of live installer on boards with 256M memory - like beagle

--console <ttyXY>
    add a console to kernel boot parameter; this parameter can be defined
    multiple times.

--hwpack <filename>
    A hardware pack that should be installed in the rootfs.

--image_size nnnG or nnnM
    specify size of SD image to create; use with --image_file only (default: 2G)

--binary <filename>
    specify file used to create the bootable system. Default binary-tar.tar.gz

--no-rootfs
    do not deploy the root filesystem

--no-bootfs
    do not deploy the boot filesystem

--no-part
    reuse existing partitions on the deploy media
EOF
  exit
}

check_device() {
  FDISK=$(sudo LC_ALL=C sfdisk -l 2>/dev/null | grep "Disk ${DEVICE}" | awk '{print $2}')

  if test "-$FDISK-" = "-$DEVICE:-"
  then
    echo ""
    echo "I see..."
    echo "sudo sfdisk -l:"
    sudo LC_ALL=C sfdisk -l 2>/dev/null | grep "Disk /dev/" --color=never
    echo ""
    echo "mount:"
    LC_ALL=C mount | grep -v none | grep "/dev/" --color=never
    echo ""
    read -p "Are you 100% sure, on selecting [${DEVICE}] (y/n)? "
    [ "$REPLY" == "y" ] || exit
    echo ""
  else
    echo ""
    echo "Are you sure? I Don't see [${DEVICE}], here is what I do see..."
    echo ""
    echo "sudo sfdisk -l:"
    sudo LC_ALL=C sfdisk -l 2>/dev/null| grep "Disk /dev/" --color=never
    echo ""
    echo "mount:"
    LC_ALL=C mount | grep -v none | grep "/dev/" --color=never
    echo ""
    exit
  fi
}

check_fs_type() {
  case "$RFS" in
    ext2|ext3|ext4|btrfs)
      :
    ;;
    *)
      usage
    ;;
  esac
}

checkparm() {
  case "$1" in
    -*)
      echo "E: Need an argument" >&2
      usage
    ;;
  esac
}

consoles=""

# parse commandline options
while [ ! -z "$1" ]; do
  case "$1" in
    -h|--help)
      usage
      ;;
    --hwpack)
      checkparm "$2"
      HWPACK_FILE="$2"
      ;;
    --mmc)
      checkparm "$2"
      DEVICE="$2"
      check_device
      ;;
    --image_file)
      checkparm "$2"
      IMAGE_FILE="$2"
      ;;
    --image_size)
      checkparm "$2"
      IMAGE_SIZE=$2
      ;;
    --rootfs)
      checkparm "$2"
      RFS="$2"
      check_fs_type
      ;;
    --boot_label)
      checkparm "$2"
      BOOT_LABEL="$2"
      ;;
    --rfs_label)
      checkparm "$2"
      RFS_LABEL="$2"
      ;;
    --swap_file)
      checkparm "$2"
      SWAP_SIZE="$2"
      CREATE_SWAP=1
      ;;
    --live)
      IS_LIVE=1
      ;;
    --live-256m)
      IS_LIVE=1
      IS_LOWMEM=1
      ;;
    --console)
      checkparm "$2"
      consoles="$consoles $2"
      ;;
    --dev)
      checkparm "$2"
      DEVIMAGE=$2
      ;;
    --binary)
      checkparm "$2"
      BINARY_TARBALL="$2"
      ;;
    --no-rootfs)
      ROOTFS_STEP=""
      ;;
    --no-bootfs)
      BOOTFS_STEP=""
      ;;
    --no-part)
      PARTITION_STEP=""
      ;;
  esac
  shift
done

DEPLOY_STEPS="$PARTITION_STEP prepare_partitions $BOOTFS_STEP $ROOTFS_STEP"

ensure_command mkimage uboot-mkimage
ensure_command uuidgen uuid-runtime
ensure_command parted parted
ensure_command wget wget
ensure_command md5sum coreutils
ensure_command realpath realpath
case "$RFS" in
  ext2|ext3|ext4)
    ensure_command "mkfs.$RFS" e2fsprogs
    ;;
  btrfs)
    ensure_command mkfs.btrfs btrfs-tools
    ;;
esac

case "$DEVIMAGE" in
  beagle)
    UBOOT_FLAVOR="omap3_beagle"
  ;;
  panda)
    UBOOT_FLAVOR="omap4_panda"
  ;;    
  vexpress)
    UBOOT_FLAVOR="ca9x4_ct_vxp"
  ;;
esac

RFS_UUID=`uuidgen -r`

get_device_by_id() {
  if [ ! "${IMAGE_FILE}" ]; then
    for device in /dev/disk/by-id/*; do
      if [ `realpath $device` = $DEVICE ]; then
        case "$device" in
          *-part[0-9]*)
            echo "device $DEVICE must not be a partition part ($device)" >&2
            exit 1
          ;;
        esac
        for part_id in `ls "$device-part"*`; do
          part=`realpath $part_id`
          part_no=`echo $part_id | sed -e 's/.*-part//g'`
          # echo "part $part_no found: $part_id" 1>&2
          # if there is a non-fs-data part (e.g. mx51evk), MMC_PART_OFFSET=1
          if test "$part_no" = $((1 + $MMC_PART_OFFSET)); then
            BOOTFS=$part
          elif test "$part_no" = $((2 + $MMC_PART_OFFSET)) ; then
            ROOTFS=$part
          fi
        done
        break
      fi
    done
  fi
}

install_hwpack() {
  chroot=${DIR}/binary
  # Make sure we unmount /proc in the chroot or else it can't be moved to the
  # rootfs.

  LINARO_HWPACK_INSTALL=$(which linaro-hwpack-install)

  sudo mv -f ${chroot}/etc/resolv.conf ${TMP_DIR}/resolv.conf.orig
  sudo cp /etc/resolv.conf ${chroot}/etc/resolv.conf

  sudo mv -f ${chroot}/etc/hosts ${TMP_DIR}/hosts.orig
  sudo cp /etc/hosts ${chroot}/etc/hosts

  local arch_is_arm=no
  case `uname -m` in
    arm*)
      arch_is_arm=yes
      ;;
    *)
      ensure_command qemu-arm-static qemu-arm-static
      ensure_command qemu-img qemu-kvm
      sudo cp /usr/bin/qemu-arm-static ${chroot}/usr/bin
      ;;
  esac
  sudo cp "$LINARO_HWPACK_INSTALL" "${chroot}/usr/bin"
  sudo cp "$HWPACK_FILE" "$chroot"

  # Actually install the hwpack.
  sudo mount proc ${chroot}/proc -t proc
  cleanup_chroot() {
    sudo umount -v "$chroot/proc"
  }

  sudo LC_ALL=C chroot "$chroot" linaro-hwpack-install /"$(basename "$HWPACK_FILE")"

  # Revert some changes we did to the rootfs as we don't want them in the
  # image.
  sudo umount ${chroot}/proc
  cleanup_chroot() { :; }

  sudo mv -f ${TMP_DIR}/resolv.conf.orig ${chroot}/etc/resolv.conf
  sudo mv -f ${TMP_DIR}/hosts.orig ${chroot}/etc/hosts
  if [ "arch_is_arm" = no ]; then
    sudo rm -f ${chroot}/usr/bin/qemu-arm-static
  fi
  sudo rm -f ${chroot}/usr/bin/linaro-hwpack-install
  sudo rm -f "${chroot}/$(basename "$HWPACK_FILE")"
}

unpack_binary_tarball() {
  # Remove the binary/ directory so that previous runs don't interfere here.
  remove_binary_dir

  sudo tar --numeric-owner -xf "$BINARY_TARBALL"
}

create_boot_cmd() {
  if [ "$IS_LIVE" ]; then
    boot_snippet='boot=casper'
    [ "$IS_LOWMEM" ] && lowmem_opt=only-ubiquity
  else
    boot_snippet='root=UUID='${RFS_UUID}
  fi

  # set board defaults
  mmc_option="0:1"
  boot_args_options="rootwait ro"

  # set board specific options
  case "$DEVIMAGE" in
    beagle|igep)
      boot_args_options="$boot_args_options earlyprintk fixrtc nocompcache vram=12M omapfb.debug=y omapfb.mode=dvi:1280x720MR-16@60"
    ;;
    
    panda)
      boot_args_options="$boot_args_options earlyprintk fixrtc nocompcache vram=32M omapfb.debug=y omapfb.vram=0:8M mem=463M ip=none"
    ;;
      
    mx51evk)
      mmc_option="0:2"
    ;;
    
    ux500)
      boot_args_options="$boot_args_options earlyprintk rootdelay=1 fixrtc nocompcache"
      boot_args_options="$boot_args_options mem=96M@0 mem_modem=32M@96M mem=44M@128M pmem=22M@172M mem=30M@194M mem_mali=32M@224M pmem_hwb=54M@256M hwmem=48M@302M mem=152M@360M"
      mmc_option="1:1"
    ;;
  esac
  
    # write out boot options
    cat > ${TMP_DIR}/boot.cmd << BOOTCMD
setenv bootcmd 'fatload mmc $mmc_option $KERNEL_ADDR uImage; fatload mmc $mmc_option $INITRD_ADDR uInitrd; bootm $KERNEL_ADDR $INITRD_ADDR'
setenv bootargs '${serial_opts} ${splash_opts} ${lowmem_opt} ${boot_snippet} ${boot_args_options}'
boot
BOOTCMD
}

cleanup_sd() {

  echo ""
  echo "Umounting Partitions"
  echo ""

  if test -n "$BOOTFS"; then
    sudo umount ${BOOTFS} &> /dev/null || true
  fi
  if test -n "$ROOTFS"; then
    sudo umount ${ROOTFS} &> /dev/null || true
  fi
}

loop_devices=

cleanup_loopbacks() {

  local d

  if [ -n "$loop_devices" ]; then

    echo
    echo "Releasing loop devices."

    for d in $loop_devices; do
      if [ -n "$d" ]; then
	sudo losetup -d "$d"
      fi
    done

  fi
}

register_loopback() {
  loop_devices="$loop_devices $1"
}

create_partitions() {
  if [ "${DEVICE}" ]; then
    sudo parted -s ${DEVICE} mklabel msdos
  fi

  if [ "${IMAGE_FILE}" ]; then
    partdev=${IMAGE_FILE}
  else
    partdev=${DEVICE}
  fi

  if [ "$FAT_SIZE" = "32" ]; then
    PARTITION_TYPE="0x0C"
  else
    PARTITION_TYPE="0x0E"
  fi

  # Create:
  # - on mx51evk, a one cylinder partition for fixed-offset bootloader data at
  #   the beginning of the image (size is one cylinder, so 8224768 bytes with
  #   the first sector for MBR),
  # - a VFAT or FAT16 partition of 9 cylinders (74027520 bytes, ~70 MiB)
  #    and a linux partition of the rest
  # - a Linux type rootfs for the rest of the space
  (
    if [ "$DEVIMAGE" = mx51evk ]; then
      cat <<EOF
,1,0xDA
EOF
    fi
    cat <<EOF
,9,$PARTITION_TYPE,*
,,,-
EOF
  ) | sudo sfdisk -D -H $HEADS -S $SECTORS $CYLINDER_ARG $partdev

  if [ "${IMAGE_FILE}" ]; then
  VFATOFFSET=$(($(LC_ALL=C fdisk -l -u "$IMAGE_FILE" | grep FAT | awk '{print $3}')*512))
  VFATSIZE2=$(($(LC_ALL=C fdisk -l -u "$IMAGE_FILE" | grep FAT | awk '{print $4}')))
  VFATSIZE1=$(($(LC_ALL=C fdisk -l -u "$IMAGE_FILE" | grep FAT | awk '{print $3}')))
  VFATSIZE=$((((VFATSIZE2+1-VFATSIZE1)/2)*1024))
  ROOTOFFSET=$(($(LC_ALL=C fdisk -l -u "$IMAGE_FILE" | grep Linux | awk '{print $2}')*512))
  ROOTSIZE2=$(($(LC_ALL=C fdisk -l -u "$IMAGE_FILE" | grep Linux | awk '{print $3}')))
  ROOTSIZE1=$(($(LC_ALL=C fdisk -l -u "$IMAGE_FILE" | grep Linux | awk '{print $2}')))
  ROOTSIZE=$((((ROOTSIZE2+1-ROOTSIZE1)/2)*1024))
  BOOTFS=$(sudo losetup -f --show "$IMAGE_FILE" --offset $VFATOFFSET --sizelimit $VFATSIZE)
  register_loopback "$BOOTFS"
  ROOTFS=$(sudo losetup -f --show "$IMAGE_FILE" --offset $ROOTOFFSET --sizelimit $ROOTSIZE)
  register_loopback "$ROOTFS"
  fi
}


prepare_partitions() {

echo -n "waiting for partitioning to settle ..."
sync
sleep 3
echo "done."
get_device_by_id

if [ "$BOOTFS_STEP" ]; then
  echo ""
  echo "Formating Boot Partition"
  echo ""
  if [ -z "$BOOTFS" ]; then
    echo "Partition $BOOTFS does not exist"
    exit 2
  else
    sudo mkfs.vfat -F ${FAT_SIZE} ${BOOTFS} -n ${BOOT_LABEL}
  fi
fi

if [ "$ROOTFS_STEP" ]; then
  echo ""
  echo "Formating ${RFS} Partition"
  echo ""
  if [ -z "$ROOTFS" ]; then
    echo "Partition $ROOTFS does not exist"
    exit 2
  else
    sudo mkfs.${RFS} -U "$RFS_UUID" ${ROOTFS} -L ${RFS_LABEL}
  fi
fi
}

populate_boot() {
  echo ""
  echo "Populating Boot Partition"
  echo ""
 
  echo ""
  echo "Installing Boot Loader"
  echo ""
 
  if [ "$IS_LIVE" ]; then
    parts_dir=casper
  else
    parts_dir=boot
  fi
 
  mkdir -p "${BOOT_DISK}"
  sudo mount ${BOOTFS} "${BOOT_DISK}"

  if [ -n "$UBOOT_FLAVOR" ]; then
      sudo cp -v "binary/usr/lib/u-boot/${UBOOT_FLAVOR}/u-boot.bin" \
               "${BOOT_DISK}"
  fi

  case "$DEVIMAGE" in
    beagle|igep)
      if [ "$DEVIMAGE" = "beagle" ]; then
        sudo cp -v binary/usr/lib/x-loader-omap/MLO "${BOOT_DISK}"
      fi
      sync
      echo "done"

      sudo mkimage -A arm -O linux -T kernel -C none -a 0x80008000 \
           -e 0x80008000 -n Linux \
           -d "${DIR}/binary/${parts_dir}"/vmlinuz-*-linaro-omap \
           "${BOOT_DISK}/uImage"
      sudo mkimage -A arm -O linux -T ramdisk -C none -a 0 \
           -e 0 -n initramfs \
           -d "${DIR}/binary/${parts_dir}"/initrd.img-*-linaro-omap \
           "${BOOT_DISK}/uInitrd"
      sudo mkimage -A arm -O linux -T script -C none -a 0 \
           -e 0 -n "boot script" -d "${TMP_DIR}/boot.cmd" \
           "${BOOT_DISK}/boot.scr"
      sudo cp -v "${BOOT_DISK}/boot.scr" "${BOOT_DISK}/boot.ini"
      ;;

    panda)
      sudo cp -v binary/usr/lib/x-loader-omap4/MLO "${BOOT_DISK}"
      sync
      echo "done"
  
      sudo mkimage -A arm -O linux -T kernel -C none -a 0x80008000 \
           -e 0x80008000 -n Linux \
           -d "${DIR}/binary/${parts_dir}"/vmlinuz-*-omap4 \
           "${BOOT_DISK}/uImage"
      sudo mkimage -A arm -O linux -T ramdisk -C none -a 0 \
           -e 0 -n initramfs \
           -d "${DIR}/binary/${parts_dir}"/initrd.img-*-omap4 \
           "${BOOT_DISK}/uInitrd"
      sudo mkimage -A arm -O linux -T script -C none -a 0 \
           -e 0 -n "boot script" -d "${TMP_DIR}/boot.cmd" \
           "${BOOT_DISK}/boot.scr"
      sudo cp -v "${BOOT_DISK}/boot.scr" "${BOOT_DISK}/boot.ini"
      ;;

    ux500)
      sudo mkimage -A arm -O linux -T kernel -C none -a 0x00008000 \
           -e 0x00008000 -n Linux \
           -d "${DIR}/binary/${parts_dir}"/vmlinuz-*-ux500 \
           "${BOOT_DISK}/uImage"
      sudo mkimage -A arm -O linux -T ramdisk -C none -a 0 \
           -e 0 -n initramfs \
           -d "${DIR}/binary/${parts_dir}"/initrd.img-*-ux500 \
           "${BOOT_DISK}/uInitrd"
      sudo mkimage -A arm -O linux -T script -C none -a 0 \
           -e 0 -n "boot script" -d "${TMP_DIR}/boot.cmd" \
           "${BOOT_DISK}/flash.scr"
      ;;

    vexpress)
      sudo mkimage -A arm -O linux -T kernel -C none -a "$KERNEL_ADDR" \
           -e "$KERNEL_ADDR" -n Linux \
           -d "${DIR}/binary/${parts_dir}"/vmlinuz-*-linaro-vexpress \
           "${BOOT_DISK}/uImage"
      sudo mkimage -A arm -O linux -T ramdisk -C none -a "$INITRD_ADDR" \
           -e "$INITRD_ADDR" -n initramfs \
           -d "${DIR}/binary/${parts_dir}"/initrd.img-*-linaro-vexpress \
           "${BOOT_DISK}/uInitrd"
      ;;

    mx51evk)
      sudo dd if=binary/usr/lib/u-boot/mx51evk/u-boot.imx of="${DEVICE:-$IMAGE_FILE}" \
           bs=1024 seek=1 conv=notrunc
      sudo mkimage -A arm -O linux -T kernel -C none -a 0x90008000 \
           -e 0x90008000 -n Linux \
           -d "${DIR}/binary/${parts_dir}"/vmlinuz-*-linaro-mx51 \
           "${BOOT_DISK}/uImage"
      sudo mkimage -A arm -O linux -T ramdisk -C none -a 0 \
           -e 0 -n initramfs \
           -d "${DIR}/binary/${parts_dir}"/initrd.img-*-linaro-mx51 \
           "${BOOT_DISK}/uInitrd"
      sudo mkimage -A arm -O linux -T script -C none -a 0 \
           -e 0 -n "boot script" -d "${TMP_DIR}/boot.cmd" \
           "${BOOT_DISK}/boot.scr"
      ;;
    *)
      echo "Internal error; missing support for $DEVIMAGE" >&2
      exit 1
      ;;
  esac

  sync
  sync
  sudo umount "${BOOT_DISK}" || true
}

populate_rootfs() {
  echo ""
  echo "Populating rootfs Partition"
  echo "Be patient, this may take a few minutes"
  echo ""
  mkdir -p "${ROOT_DISK}"
  sudo mount ${ROOTFS} "${ROOT_DISK}"

  sudo mv ${DIR}/binary/* "$ROOT_DISK"

  # add fstab entry for rootfs and boot
  echo "UUID=${RFS_UUID} / ${RFS}  errors=remount-ro 0 1 " | sudo tee -a "${ROOT_DISK}/etc/fstab"

  if [ "$CREATE_SWAP" ] ; then

    echo ""
    echo "Creating SWAP File"
    echo ""

    SPACE_LEFT=$(LC_ALL=C df "${ROOT_DISK}" | grep ${ROOTFS} | awk '{print $4}')

    let SIZE=$SWAP_SIZE*1024

    if [ $SPACE_LEFT -ge $SIZE ] ; then
      sudo dd if=/dev/zero "of=${ROOT_DISK}/SWAP.swap" bs=1M count=$SWAP_SIZE
      sudo mkswap "${ROOT_DISK}/SWAP.swap"
      echo "/SWAP.swap  none  swap  sw  0 0" | sudo tee -a "${ROOT_DISK}/etc/fstab"
    else
      echo "SWAP file bigger then whats left on partition"
    fi
  fi

  echo ""
  echo "Creating /etc/flash-kernel.conf"
  echo ""

  echo "UBOOT_PART=${TARGET_BOOT_DEV}" | sudo tee "${ROOT_DISK}/etc/flash-kernel.conf" >/dev/null

  sync
  sync
  sudo umount "${ROOT_DISK}" || true
}

calculatesize() {
  IMAGE_SIZE=${IMAGE_SIZE/G/M*1024}
  IMAGE_SIZE=${IMAGE_SIZE/M/K*1024}
  IMAGE_SIZE=${IMAGE_SIZE/K/*1024}
  IMAGE_SIZE=$(($IMAGE_SIZE))
}

setup_sizes() {
  HEADS=255
  SECTORS=63
  SECTORSIZE=512
  if [ "${IMAGE_FILE}" ]; then
    calculatesize
    CYLINDERSIZE=$(($HEADS*$SECTORS*$SECTORSIZE))
    CYLINDERS=$(($IMAGE_SIZE/$CYLINDERSIZE))
    CYLINDER_ARG="-C $CYLINDERS"
    IMAGE_SIZE=$(($CYLINDERS*$CYLINDERSIZE))
    # Round the size of the raw disk image up to a multiple of 256K
    # so it is an exact number of SD card erase blocks in length.
    # Otherwise Linux under qemu cannot access the last part of the
    # card and is likely to complain that the last partition on the
    # disk has been truncated.
    IMAGE_SIZE=$(((($IMAGE_SIZE-1)/(1024*256)+1)*(1024*256)))
  else
    CYLINDER_ARG=""
  fi
}

setup_image() {
  sudo qemu-img create -f raw "$IMAGE_FILE" $IMAGE_SIZE
}

remove_binary_dir() {
  if [ -d binary/ ]; then
    sudo rm -rf binary/
  fi
}

remove_image_file() {
  if [ -f "$IMAGE_FILE" ]; then
    rm -v $IMAGE_FILE
  fi
}

signal_handler() {
  cleanup_handler
  exit 2
}

# Initially, no action is needed to clean up mounts in the chroot.
# install_hwpack will temporarily define this function when needed.
cleanup_chroot() { :; }

cleanup_handler() {
  status=$?

  trap - EXIT INT TERM

  set +e

  if [ $status != 0 ]; then
    echo >&2 "$0: FAILED"
  fi

  echo
  echo "Performing cleanup..."
  echo

  cleanup_chroot
  cleanup_sd
  cleanup_mountpoints
  cleanup_tempfiles
  cleanup_loopbacks
  remove_binary_dir

  if [ "$status" != 0 ]; then
      remove_image_file
  fi

  # According to POSIX, for the EXIT trap the shell will now exit with the
  # exit status of the failing command which triggered the EXIT, or 0 if the
  # script terminated successfully.

  # For the INT/TERM trap, return to signal_handler.
}

# Call cleanup_handler as appropriate.
# The EXIT trap gets called both on normal exit or exit-on-error (set -e)
# so we get called either way.
trap cleanup_handler EXIT
trap signal_handler INT TERM

setup_sizes
if [ "${IMAGE_FILE}" ]; then
  setup_image
fi

serial_opts=""
if [ "$consoles" ]; then
  for c in ${consoles}; do
    serial_opts="$serial_opts console=$c"
  done
  if [ "$IS_LIVE" ]; then
    serial_opts="$serial_opts serialtty=ttyS2"
  fi
fi

case "$DEVIMAGE" in
  beagle|igep|mx51evk|panda|ux500|vexpress)
    :
  ;;
  "")
    echo "Please set some target device with --dev" >&2
    usage
  ;;
  *)
    echo "Unknown target device $DEVIMAGE" >&2
    usage
  ;;
esac

if [ "$DEVIMAGE" ]; then
  case "$DEVIMAGE" in
    beagle|igep)
      serial_opts="$serial_opts console=tty0 console=ttyS2,115200n8"
      if [ "$IS_LIVE" ]; then
        serial_opts="$serial_opts serialtty=ttyS2"
      fi
      KERNEL_ADDR="0x80000000"
      INITRD_ADDR="0x81600000"
      ;;
    panda)
      serial_opts="$serial_opts console=tty0 console=ttyO2,115200n8"
      if [ "$IS_LIVE" ]; then
        serial_opts="$serial_opts serialtty=ttyO2"
      fi
      KERNEL_ADDR="0x80200000"
      INITRD_ADDR="0x81600000"
      ;;
    ux500)
      serial_opts="$serial_opts console=tty0 console=ttyAMA2,115200n8"
      if [ "$IS_LIVE" ]; then
        serial_opts="$serial_opts serialtty=ttyAMA2"
      fi
      KERNEL_ADDR="0x00100000"
      INITRD_ADDR="0x08000000"
      ;;
    mx51evk)
      serial_opts="$serial_opts console=tty0 console=ttymxc0,115200n8"
      if [ "$IS_LIVE" ]; then
        serial_opts="$serial_opts serialtty=ttymxc0"
      fi
      KERNEL_ADDR="0x90000000"
      INITRD_ADDR="0x90800000"
      MMC_PART_OFFSET=1
      ;;
    vexpress)
      serial_opts="$serial_opts console=tty0 console=ttyAMA0,38400n8"
      if [ "$IS_LIVE" ]; then
        serial_opts="$serial_opts serialtty=ttyAMA0"
      fi
      KERNEL_ADDR="0x60008000"
      INITRD_ADDR="0x81000000"
      # ARM Boot Monitor is used to load u-boot, uImage etc. into flash and
      # only allows for FAT16
      FAT_SIZE=16
      ;;
    *)
      echo "Internal error; missing support for $DEVIMAGE" >&2
      exit 1
      ;;
  esac
else
  if [ "$IS_LIVE" ]; then
    splash_opts="quiet splash"
  fi
fi

TARGET_BOOT_DEV=/dev/mmcblk0p$(( 1 + $MMC_PART_OFFSET ))
TARGET_ROOT_DEV=/dev/mmcblk0p$(( 2 + $MMC_PART_OFFSET ))

if [ ! "${DEVICE}" -a ! "${IMAGE_FILE}" ]; then
  usage
fi

# The bootfs and rootfs deploy options are only available with physical 
# devices.  These options are intended for deploying to different devices like
# a USB drive and an MMC device.  The options do not apply to qemu image_files.
if [ "${IMAGE_FILE}" ]; then
  if [ -z "${ROOTFS_STEP}" ] || [ -z "${BOOTFS_STEP}" ]; then
    echo "Do not use --no-rootfs or --no-bootfs with the --image_file option"
    exit
  fi
fi

unpack_binary_tarball
if [ "$HWPACK_FILE" ]; then
  install_hwpack
else
  echo "Warning, --hwpack <filename> was not specified, the result is unlikely to be functional without manual effort to setup uImage, MLO, u-boot.bin and so as as appropriate for your hardware."
fi
get_device_by_id
for func in $DEPLOY_STEPS; do
  $func
done

