#!/bin/sh
# Wireless Leiden config-update script for FreeBSD 8.0 (nanobsd)
# Based on the 'API' of Jasper
# Rick van der Zwet
# XXX: TODO, some proper error checking for fetch


# Slow connection = no connection
export HTTP_TIMEOUT=10


check_access() {
  # Direct Access - External
  BASEURL="http://wirelessleiden.nl/config/"
  fetch -o /dev/null -q $BASEURL > /dev/null && return
  echo "# WARN: Fetch via external $BASEURL failed"

  # Direct Access - Internal IP 
  BASEURL="http://172.16.4.46/wleiden/config/"
  # Connectivity check
  fetch -o /dev/null -q $BASEURL > /dev/null && return
  echo "# WARN: Fetch via internal $BASEURL failed"
  
  # Direct Access - External DNS
  BASEURL="http://132.229.112.21/wleiden/config/"
  fetch -o /dev/null -q $BASEURL > /dev/null && return
  echo "# CRIT: Fetch via external $BASEURL failed"

  exit 1
}
check_access


# Default config to fetch
CONFIG=`hostname -s`

# Determine it's statup and running location and some other hints
# Skip named.conf as it not planned in current release
FILES="authorized_keys dhcpd.conf dnsmasq.conf motd rc.conf.local resolv.conf pf.hybrid.conf.local wleiden.yaml"
file_details() {
  POST_CMD=""
  FILE_HINT=""

  case "$1" in 
  'authorized_keys')
     STARTUP_LOC="/cfg/ssh/${FILE}"
     RUNNING_LOC="/etc/ssh/${FILE}"
   ;;
  'dhcpd.conf')
     STARTUP_LOC="/cfg/local/${FILE}"
     RUNNING_LOC="/usr/local/etc/${FILE}"
     POST_CMD="service isc-dhcpd restart"
   ;;
  'dnsmasq.conf')
     STARTUP_LOC="/cfg/local/${FILE}"
     RUNNING_LOC="/usr/local/etc/${FILE}"
     POST_CMD="service dnsmasq restart"
   ;;
   'motd')
     STARTUP_LOC="/cfg/${FILE}"
     RUNNING_LOC="/etc/${FILE}"
     POST_CMD="/etc/rc.d/motd onestart"
   ;;
  'named.conf')
     STARTUP_LOC="/cfg/namedb/${FILE}"
     RUNNING_LOC="/etc/namedb/${FILE}"
     POST_CMD="service named restart"
   ;;
  'rc.conf.local')
     STARTUP_LOC="/cfg/${FILE}"
     RUNNING_LOC="/etc/${FILE}"
     FILE_HINT="Restart interfaces with: nohup service netif restart"
   ;;
   'resolv.conf')
     STARTUP_LOC="/cfg/${FILE}"
     RUNNING_LOC="/etc/${FILE}"
     FILE_HINT="To get the ordering right run: nameserver-shuffle"
   ;;
   'pf.hybrid.conf.local')
     STARTUP_LOC="/cfg/${FILE}"
     RUNNING_LOC="/etc/${FILE}"
     POST_CMD="service pf reload"
   ;;
   'wleiden.yaml')
     STARTUP_LOC="/cfg/local/${FILE}"
     RUNNING_LOC="/usr/local/etc/${FILE}"
   ;;
  esac
}

usage() {
	(
	echo "Usage: $0 [-bpn] [-c <config>] [-m <all|startup|testing|running>]"
	echo "	-b          = batch mode, no user input"
	echo "	-c <config> = default configuration to fetch"
	echo "	-d          = do not run the POST_CMD commands [default]"
        echo "  -p          = run the POST_CMD commands to activate the services right-away"
	echo "	-n          = do not mount config partition"
	echo "	-m all      = copy config files to running & config partition [default]"
	echo "	-m startup  = copy config files to config partition"
	echo "	-m testing  = do not copy config files"
	echo "	-m running  = copy config files to running partition"
	echo "	-m hack     = copy running files to config partition"
	) 1>&2
	exit 2
}

# Argument parsing using getopts
USE_API=1		# Whether or not to use the webinterface
OPT_MOUNT=1
OPT_RUNNING=1
OPT_STARTUP=1
OPT_HACK=0		# Hack for people without configuration managment and testing
OPT_BATCH=0
OPT_POSTCMD=false

parse_options() {
  while getopts "bc:nm:dp" OPT; do
  	case "$OPT" in
  	b) OPT_BATCH=1;;
  	c) CONFIG="${OPTARG}";;
	d) OPT_POSTCMD=false;;
  	n) OPT_MOUNT=0;;
  	m) case "$OPTARG" in
  	   all) true;;
  	   live) OPT_STARTUP=0;;	
  	   startup) OPT_RUNNING=0;;		
  	   testing) OPT_RUNNING=0; OPT_STARTUP=0; OPT_MOUNT=0;;		
  	   hack) OPT_RUNNING=0; OPT_STARTUP=0; OPT_HACK=1; USE_API=0;;		
  	   *) usage;;
  	   esac;;
  	h) usage;;
	p) OPT_POSTCMD=true;;
  	\?) usage;;
  	esac
  done
  # Allow to override automatic mounting, in case of external mount 'managment'
  if [ "$1" = "-n" ]; then
  	OPT_MOUNT=0
  fi
  
  if [ "${OPT_RUNNING}" -eq 1 ]; then
    echo "# INFO: Storing new config files in running configuration"
  fi
  
  if [ "${OPT_STARTUP}" -eq 1 ]; then
    echo "# INFO: Storing new config files in startup configuration"
  fi
  
  if [ "${OPT_HACK}" -eq 1 ]; then
    echo "# WARN: Copy running configuration to startup configuration"
    echo "# WARN: Please do mind to document/mention this changes somewhere"
  fi

  if /bin/df / | grep -q "^/dev/md[0-9]"; then
    OPT_MOUNT=0
    echo "# WARN: Mount operations disabled as we are running in a md(4) image"
  fi

  # New line before the real work gets started
  echo "" 
}




# test validity of input
config_validator() {
  INPUT="$1"
  `grep -q "^${INPUT}\$" ${TMPDIR}/node_list.txt`
  if [ $? -eq 0 ]; then
    return 0
  else 
     echo "WARNING: Input '${INPUT}' is not valid, some hints..."
     grep -i "${INPUT}" ${TMPDIR}/node_list.txt
     return 1
  fi  
}



select_node() {
  # List of all available nodes
  fetch -q -o ${TMPDIR}/node_list.txt ${BASEURL} || exit 1
  
  if [ ${OPT_BATCH} -eq 1 ]; then
    config_validator "${CONFIG}"
   if [ $? -eq 1 ]; then
     echo "ERROR: Please provide valid config" 1>&2
     exit 1
   fi
  else
    # Provide Nodelist and feedback
    cat ${TMPDIR}/node_list.txt | column
    echo '       THIS script adds the config from GENESIS to this operating system'
    echo '       make sure you know what you are doing, if not press control-C'
    echo '       ENTER CONFIG NAME  ......(and press enter)'

    # Have the user to select the right node
    INVALID_CONFIG=1
    while [ ${INVALID_CONFIG} -eq 1 ]; do
      # Ask for node name, play around with prev option
      echo -n "Name [${CONFIG}]: "
      read INPUT
      if [ -z "${INPUT}" ]; then
        INPUT=${CONFIG}
      else
        CONFIG=${INPUT}
      fi
    
      config_validator "${INPUT}"
      if [ $? -eq 0 ]; then
         INVALID_CONFIG=0
      fi  
    done
  fi
}




# Copy file, saving some bits if no change needed
copy_file() {
  SOURCE=$1
  TARGET=$2
  diff -I '^FreeBSD ' -I '^# Generated at ' ${TARGET} ${SOURCE} 2>/dev/null
  if [ $? -ne 0 ]; then
    mkdir -p `dirname ${TARGET}` || exit 1
    cp ${SOURCE} ${TARGET} || exit 1
    return $?
  fi
  return 1
}

# Main function
main() {
  TMPDIR=`mktemp -d -t $(basename $0)`
  # Clear out tempdir when done
  if [ ${OPT_MOUNT} -eq 1 ]; then
  	trap "rm -Rf ${TMPDIR}; umount /cfg; mount -ro noatime /; exit" 0 1 2 3 15
  else
  	trap "rm -Rf ${TMPDIR}; exit" 0 1 2 3 15
  
  fi
  
  # Mount if requested
  if [ ${OPT_MOUNT} -eq 1 ]; then
  	mount -uwo noatime /
  	mount /cfg
  fi

  # Select node from web-interface
  if [ ${USE_API} -eq 1 ]; then
  	select_node
  fi
  
  # Worker, place all files in required directory
  for FILE in ${FILES}; do
    if [ ${USE_API} -eq 1 ]; then
      # Fetch needed file
      FRESH_LOC=${TMPDIR}/${FILE}
      fetch -q -o ${FRESH_LOC} ${BASEURL}/${CONFIG}/${FILE} || exit 1
    fi
  
    # Needed file details, like locations and hints
    file_details ${FILE}
  
    echo "# INFO: Working on file: '${FILE}'"
    # Copy file boot location
    if [ ${OPT_STARTUP} -eq 1 ]; then
      copy_file ${FRESH_LOC} ${STARTUP_LOC}
    fi
  
    # Copy file running location
    if [ ${OPT_RUNNING} -eq 1 ]; then
      copy_file ${FRESH_LOC} ${RUNNING_LOC}
      if [ $? -eq 0 ]; then
        echo "# INFO: '${FILE}' changed"  
        if [ -n "${POST_CMD}" ]; then
          if $OPT_POSTCMD; then
            echo "## Running post_cmd: $POST_CMD"
            $POST_CMD
          else
            echo "## To activate run the post_cmd: $POST_CMD"
          fi
        fi
        if [ -n "${FILE_HINT}" ]; then
          echo "# INFO: ${FILE_HINT}"
          echo ""
        fi
      fi
    fi
  
    # Direct copy
    if [ ${OPT_HACK} -eq 1 ]; then
      # No checking, just dumb try to copy mode
      cp -v ${RUNNING_LOC} ${STARTUP_LOC}
    fi
  done
  
  exit 0
}

parse_options $*
main
