#!/bin/bash

# this script installs a new release image into a running "union-installed"
# system to the new release. the specified image is a release ISO image.
# the script sets up a new union mount for the new release. a reboot is
# then required to boot into the newly installed release.

NEW_ISO=$1

PI_ROOT=''
SQUASH_MOUNT=''
ISO_MOUNT=''
TMP_DIR=''

vyatta_sysconfdir=/opt/vyatta/etc

failure_exit () {
  echo "$*"
  exit 1
}

clean_up () {
  if [ -n "$PI_ROOT" ] && [ -d "$PI_ROOT" ]; then
    umount $PI_ROOT >&/dev/null || true
  fi
  if [ -n "$SQUASH_MOUNT" ] && [ -d "$SQUASH_MOUNT" ]; then
    umount $SQUASH_MOUNT >&/dev/null || true
  fi
  if [ -n "$ISO_MOUNT" ] && [ -d "$ISO_MOUNT" ]; then
    umount $ISO_MOUNT >&/dev/null || true
  fi
  if [ -n "$TMP_DIR" ] && [ -d "$TMP_DIR" ]; then
    rm -rf $TMP_DIR
  fi
  PI_ROOT=''
  SQUASH_MOUNT=''
  ISO_MOUNT=''
  TMP_DIR=''
}

sig_handler () {
  echo "ERROR: Signal received. Exiting..."
  clean_up
  echo "Done"
  trap - EXIT
  exit 1
}

exit_handler () {
  echo "Exiting..."
  clean_up
  echo "Done"
}

trap sig_handler INT KILL
trap exit_handler EXIT

if [ `whoami` != 'root' ] ; then
  failure_exit 'This script must be run with root privileges.'
fi

# make sure it's a union-installed system
CURVER=$(sed -n 's/^Version \+: \+\([^ ]\+\)$/\1/p' \
           ${vyatta_sysconfdir}/version 2>/dev/null)
if [ -z "$CURVER" ]; then
  failure_exit 'Cannot find current version.'
fi
if [ ! -d "/live/image/boot/$CURVER" ] \
    || ! grep -q ' /live/image ' /proc/mounts \
    || grep -q ' /live/image iso9660 ' /proc/mounts \
    || ! grep -q " /$CURVER.squashfs " /proc/mounts; then
  failure_exit 'This script can only be used on a "union-installed" system.'
fi

# check the ISO
if [ ! -f "$NEW_ISO" ] || ! (file $NEW_ISO | grep -q 9660); then
  failure_exit "\"$NEW_ISO\" is not a valid ISO image file."
fi
TMP_DIR=$(mktemp -d /tmp/install-image.XXXXXX) \
  || failure_exit 'Failed to create temporary directory.'
ISO_MOUNT=$TMP_DIR/iso-mount
if ! mkdir $ISO_MOUNT || ! mount -o loop,ro "$NEW_ISO" $ISO_MOUNT; then
  failure_exit 'Failed to mount ISO image.'
fi

# check the squashfs image
SQUASH_FILE=$ISO_MOUNT/live/filesystem.squashfs
if [ ! -f "$SQUASH_FILE" ] || ! (file $SQUASH_FILE | grep -q Squashfs) \
    || ! grep -q '^ii  vyatta-version ' $ISO_MOUNT/live/packages.txt; then
  failure_exit "\"$NEW_ISO\" is not a Vyatta ISO image file."
fi
SQUASH_MOUNT=$TMP_DIR/squash-mount
if ! mkdir $SQUASH_MOUNT \
    || ! mount -o loop,ro "$SQUASH_FILE" $SQUASH_MOUNT; then
  failure_exit 'Failed to mount squashfs image.'
fi

# get version string
NEWVER=$(grep '^Version ' ${SQUASH_MOUNT}${vyatta_sysconfdir}/version \
          | tr -s ' ' | cut -d ' ' -f 3)
if [ -z "$NEWVER" ]; then
  failure_exit 'Cannot find new release version.'
fi
if [ "$CURVER" == "$NEWVER" ]; then
  failure_exit "Cannot install the same release version \"$NEWVER\"."
fi

# start the install
echo "Installing \"$NEWVER\" release."

# create the new release directories
REL_ROOT="/live/image/boot/$NEWVER"
RW_DIR="$REL_ROOT/live-rw"
if ! mkdir -p "$RW_DIR"; then
  failure_exit 'Cannot create directory for new release.'
fi

# copy the squashfs image and boot files
echo -n "Copying new release files..."
cp -p $SQUASH_FILE $REL_ROOT/$NEWVER.squashfs >&/dev/null
cp -p $SQUASH_MOUNT/boot/* $REL_ROOT/ >&/dev/null
echo " Done"

# mount copied squashfs
umount $SQUASH_MOUNT
SQUASH_FILE=$REL_ROOT/$NEWVER.squashfs
if ! mount -o loop,ro "$SQUASH_FILE" $SQUASH_MOUNT; then
  failure_exit 'Failed to mount new squashfs image.'
fi

# set up root for postinst
PI_ROOT=$TMP_DIR/pi_root
if ! mkdir $PI_ROOT \
    || ! mount -t unionfs -o noatime,dirs=$RW_DIR=rw:$SQUASH_MOUNT=ro unionfs \
          $PI_ROOT; then
  failure_exit 'Failed to set up root directory for postinst.'
fi

# set up /var/run fstab entry
PI_FSTAB=$PI_ROOT/etc/fstab
if ! grep -q 'tmpfs /var/run ' $PI_FSTAB >&/dev/null; then
  # replace the fstab. the default one has header that will cause
  # it to be wiped out on live boot.
  echo 'tmpfs /var/run tmpfs nosuid,nodev 0 0' >$PI_FSTAB
fi

# postinst hook
PI_SCRIPT=${PI_ROOT}${vyatta_sysconfdir}/install-image/postinst
if [ -e "$PI_SCRIPT" ]; then
  echo "running post-install script"
  $PI_SCRIPT $PI_ROOT
fi

# set up grub entry (if provided)
DEF_GRUB=${PI_ROOT}${vyatta_sysconfdir}/grub/default-union-grub-entry
if [ -e "$DEF_GRUB" ]; then
  old_grub_cfg=/live/image/boot/grub/grub.cfg
  new_grub_cfg=$TMP_DIR/grub.cfg
  sed -n '/^menuentry/q;p' $old_grub_cfg >$new_grub_cfg
  cat $DEF_GRUB >>$new_grub_cfg
  sed -n '/^menuentry/,${p}' $old_grub_cfg >>$new_grub_cfg
  sed -i 's/^set default=[0-9]\+$/set default=0/' $new_grub_cfg
  mv $new_grub_cfg $old_grub_cfg
fi

# done
exit 0