#!/bin/sh
#
BASEDIR=`dirname $0`
. ${BASEDIR}/common.inc.sh

NANOBSD="$NANO_SRC/tools/tools/nanobsd/nanobsd.sh"

usage() {
cat <<EOF
# Usage $0 <arguments>
#
# Wrapper around nanobsd.sh with autodetection of already processed steps to
# provide some failsafe net, which avoids building world and/or kernel by
# default.
#
# Rick van der Zwet <rick@wirelessleiden.nl>
#
# Arguments:
# build                         - Build NanoBSD parts which are not build yet
# build force kernel            - Build NanoBSD and force rebuilding the kernel
# build force world             - Build NanoBSD and force rebuilding world
# edit				- Manually edit the image
# config [for <node>]           - Configure image to be used for <node>
# rebuild                       - Rebuild NanoBSD (aka force rebuilding all)
# deploy on <node> [and reboot] - Deploy the image on node and reboot if needed
# ports update 			- Update the packages from ports 
# ports force rebuild		- Forcefully rebuilding all required packages
EOF
}


deploy_image() {
  # Find object directory 
  img=${OBJDIR}/_.disk.image

  if [ ! -r "$img" ]; then
    p_err Source $img does not exists
    exit 1
  fi

  prompt_timeout=5
  p_warn "Going to DEPLOY $img to $host: (and 9.X-RELEASE) to 10.X-RELEASE"
  p_warn "You will need to type the root password at least twice, consider using a key"
  $do_reboot && p_warn "AND will REBOOT the $host"


  p_warn "Press CTRL+C in $prompt_timeout seconds to CANCEL"
  # sleep $prompt_timeout

  echo "# Trying to connect to $host"
  release=`ssh $host 'uname -r'` || exit 1

  # Release update cycle depends on the release we are coming from
  echo "# Host has FreeBSD Release: $release"
  if echo $release | grep -q '^[1234567]\.*-RELEASE'; then
    p_err "$release not supported for upgrade"
    exit 1
  elif echo $release | grep -q '^8\.*-RELEASE'; then
    # Hack to make sure we update the fstab the right way when converting from
    # 8.X-RELEASE to 9.X-RELEASE. ad0 naming changed to ada0, secondly an
    # specific update script had to be called.
    command="/tmp/update$$"
    cat > $command <<'EOF'
# Write new image
echo "FreeBSD Release : `uname -r`"
echo "Active Partition: `df -H / | tail -1`"
if [ "`uname -r`" = "9.0-RELEASE" ]; then 
  echo "Error not valid update cycle!"
  exit 1
else
  if df / | grep -q '1a ' ; then
    echo  "New Partition   : /dev/ad0s2a"
    echo /tools/updatep2

    # Quirck to fix partitions
    # mount -uwo noatime /dev/ad0s2a
    # sed -i "" "s/ada0s1/ada0s2/" /mnt/conf/base/etc/fstab /mnt/etc/fstab
    # umount 
  else
    echo  "New Partition   : /dev/ad0s1a"
    echo /tools/updatep1
  fi
fi
EOF
    cat $command | ssh $host "cat > $command" || exit 1
    cat $img | ssh $host "sh $command" || exit 1
  else
    cat $img | ssh $host /tools/update || exit 1
  fi

  if $do_reboot; then
    echo "# Reboot requested, press CTRL+C in $prompt_timeout seconds to cancel"
    sleep $prompt_timeout
    ssh $host reboot || exit 1
  fi
}

config_image() {
  node_name=${1:+"-b -c $1"}

  img=$OBJDIR/_.disk.full

  mnt=`mktemp -d -t $(basename $0)`
  md=`mdconfig -a -t vnode -f $img`
  
  # Clean up when done
  trap "umount $mnt/dev; umount $mnt/cfg; umount $mnt; mdconfig -d -u $md; rm -d $mnt" 0
  trap "exit 1" 1 2 3 15

  # Root filesystem
  mount /dev/${md}s1a $mnt || exit 1

  # /dev/null in chroot
  mount -t devfs devfs ${mnt}/dev || exit 1
  
  # Config files lives at /cfg  location
  mount /dev/${md}s3 $mnt/cfg || exit 1
  
  # Try to fetch and store config
  chroot $mnt /tools/wl-config -d -n -m startup $node_name || exit 1
}

edit_image() {
  img=$OBJDIR/_.disk.full

  mnt=`mktemp -d -t $(basename $0)`
  md=`mdconfig -a -t vnode -f $img`
  
  # Clean up when done
  trap "umount $mnt/dev; umount $mnt/cfg; umount $mnt; mdconfig -d -u $md; rm -d $mnt" 0
  trap "exit 1" 1 2 3 15

  # Root filesystem
  mount /dev/${md}s1a $mnt || exit 1

  # /dev/null in chroot
  mount -t devfs devfs ${mnt}/dev || exit 1
  
  # Config files lives at /cfg  location
  mount /dev/${md}s3 $mnt/cfg || exit 1

  # Nasty hack to set custom prompt
  prompt='set prompt = "image# "'
  echo $prompt >> $mnt/root/.cshrc
  
  p_info "Type exit when done"
  chroot $mnt /bin/csh
  p_info "Any changes are made permanent on image $img"
  
  # Unset prompt again
  sed -I '' "/^$prompt$/d" $mnt/root/.cshrc
}


build_image() {
  p_info Forcefully building kernel: $FORCE_KERNEL
  p_info Forcefully building world : $FORCE_WORLD
  
  NANOBSD_EXTRA=${NANOBSD_EXTRA:-''}
  
  if [ ! -r "${NANOBSD}" ]; then
    p_err ${NANOBSD} does not exists
    exit 1
  fi
  
  if [ ! -x "${NANOBSD}" ]; then
    NANOBSD="sh ${NANOBSD}"
  fi
  
  # Find object directory 
  OBJDIR="/usr/obj/nanobsd.${NANO_NAME}"
  
  if [ -d "${OBJDIR}" ]; then
    NANOBSD_FLAGS=""
    
    # Detect succesfull buildworld
    tail -10 ${OBJDIR}/_.bw | grep 'World build completed'
    if [ $? -eq 0 -a ${FORCE_WORLD} = "no" ]; then
       p_info NO building of world
       NANOBSD_FLAGS="${NANOBSD_FLAGS} -w"
    fi  
  
    # Detect succesfull buildkernel
    tail -10 ${OBJDIR}/_.bk | grep 'Kernel build for .* completed'
    if [ $? -eq 0 -a ${FORCE_KERNEL} = "no" ]; then
       p_info NO building of kernel
       NANOBSD_FLAGS="${NANOBSD_FLAGS} -k"
    fi  
  
  else
    p_warn Nothing yet, starting fresh
    NANOBSD_FLAGS=""
  fi
  
  # Provide verbose output by default
  COMMAND="${NANOBSD} ${NANOBSD_FLAGS} -c ${NANO_CFG_FILE} -v ${NANOBSD_EXTRA}"
  f_time ${COMMAND}
  RETVAL=$?
  
  # Verify on build failures
  tail -10 ${OBJDIR}/_.bw | grep 'World build completed'
  if [ $? -eq 1 ]; then
    p_err Building world FAILED, check ${OBJDIR}/_.bw
  fi
  tail -10 ${OBJDIR}/_.bk | grep 'Kernel build for .* completed'
  if [ $? -eq 1 ]; then
    p_err Building kernel FAILED, check ${OBJDIR}/_.bk
  fi  
  if [ $RETVAL -ne 0 ]; then
    p_err "Errors in building NanoBSD Image ($RETVAL)"
  fi
  p_info End time: `date`
  exit ${RETVAL}
}

#
# Argument parsing
#
FORCE_KERNEL=${FORCE_KERNEL:-"no"}
FORCE_WORLD=${FORCE_WORLD:-"no"}
if [ -z "$1" ]; then
  usage; exit 1
elif [ "$1" = "build" ]; then
  if [ -z "$2" ]; then
  elif [ "$2" = "force" ]; then
    if [ "$3" = "kernel" ]; then
      FORCE_KERNEL="yes"
    elif [ "$3" = "world" ]; then
      FORCE_WORLD="yes"
    else
      echo "Argument Error - '$3'"; exit 128
    fi
  else
    echo "Argument Error - '$2'"; exit 128
  fi
  build_image
elif [ "$1" = "rebuild" ]; then
  FORCE_KERNEL="yes"
  FORCE_WORLD="yes"
  build_image
elif [ "$1" = "deploy" -a "$2" = "on" ]; then
  if [ -z "$3" ]; then
      echo "Argument Error - '$3'"; exit 128
  fi
  host=$3
  do_reboot=false
  if [ -n "$4" -o -n "$5" ]; then
    if [ "$4" = "and" -a "$5" = "reboot" ]; then
      do_reboot=true
    else
      echo "Argument Error - '$4 $5'"; exit 128
    fi
  fi
  deploy_image
elif [ "$1" = "ports" ]; then
  if [ "$2" = "update" ]; then
    # Fetch the latest details and provide listing of packages to be updated
    portsnap fetch update || exit 1

    # HACK: install our own ports _inside_ the normal ports dir
    cp -fR $WL_PORTSDIR/* $PORTSDIR || exit 1

    # Make sure portmaster is present to update all ports
    portmaster --version 1>/dev/null 2>/dev/null || make -C /usr/ports/ports-mgmt/portmaster BATCH=yes install clean || exit 1

    # Update via portmaster
    CMD="env `echo $PKG_MAKE_ARGS` portmaster --no-confirm --update-if-newer -t -y -d -G  `echo $PACKAGE_LIST`"
    echo "# Going to run port upgrade cycle: $CMD"; $CMD || exit 1

    . ${BASEDIR}/package-build.sh
  elif [ "$2" = "force" -a "$3" = "rebuild" ]; then
    export FORCE_REBUILD=1
    . ${BASEDIR}/package-build.sh
  else
    shift 1
    echo "Arguments Error - '$*'"; exit 128
  fi
elif [ "$1" = "config" ]; then
  if [ "$2" = "for" ]; then
    if [ -n "$3" ]; then
      node_name=$3
    else
      echo "Arguments Error - '$*'"; exit 128
    fi
  else
    echo "Arguments Error - '$*'"; exit 128
  fi
  config_image $node_name
elif [ "$1" = "edit" ]; then
  edit_image
else
  echo "Argument Error - '$1'"; exit 128
fi