#!/bin/ksh
#
#H# darkstat.sh
#H#
#H# Function: start or stop darkstat
#H# 
#H# Usage:    darkstat.sh [-v|--verbose] [-q|--quiet] [-f|--force] [-p|--port darkstat_port] [-i|--interface interface] 
#H#                       [start [darkstat_options]|stop|restart [darkstat_options]|status|daemon_help]
#H#
#H# Parameter
#H#   -v - verbose mode
#H#   -q - quiet mode
#H#   -f - force execution
#H#   -p - port for darkstat (default: 667)
#H#   -i - interface, default: interface used for the first default route in the output of "netstat -rn"
#H#
#H#   darkstat_options - additional options for starting the darkstat
#H#   daemon_help - list the usage help for the darkstat daemon
#H#
#H# To save the output also in a file use the start parameter:
#H#      --chroot <outputdir> --export <outputfile> --user <run_user>
#H#  e.g.
#H#      --chroot /var/tmp/jwm/data --export darkstat.data --user xtrnaw7
#H#
#H#  The user <run_user> must have write access to the directory <outputdir>
#H#
# History:  
#   25.10.2016 v1.0.0 /bs
#     initial release
#

# for debugging
#
#PREFIX="echo "
PREFIX=""

# define constants
#
__TRUE=0
__FALSE=1

# variables for the trap handler
#
INSIDE_DIE=${__FALSE}

# script name and directory
#
typeset -r SCRIPTNAME="${0##*/}"
typeset SCRIPTDIR="${0%/*}"
if [ "${SCRIPTNAME}"x = "${SCRIPTDIR}"x ] ; then
  SCRIPTDIR="$( whence ${SCRIPTNAME} )"
  SCRIPTDIR="${SCRIPTDIR%/*}"
fi  
REAL_SCRIPTDIR="$( cd -P ${SCRIPTDIR} ; pwd )"

LOGFILE="${LOGFILE:=/var/tmp/${SCRIPTNAME}.log}"

# define variables
#
FORCE=${FORCE:=${__FALSE}}
QUIET=${QUIET:=${__FALSE}}
VERBOSE=${VERBOSE:=${__FALSE}}

# default for the port used by darkstat
#
DARKSTAT_PORT="667"

# additional options for the darkstat
#
DARKSTAT_OPTIONS=""

DARKSTAT_INTERFACE="$( netstat -rn | grep "^0.0.0.0 " | head -1 | awk '{ print $NF};' )"

# ----------------------------------------------------------------------
# general functions
#
LogMsg () {
  [[ ${QUIET} = ${__TRUE} ]] && return

  typeset THISMSG="$*"
  
  if [ "$1"x = "-"x ] ; then
    shift
    THISMSG="$*"
  else
    THISMSG="[$( date +"%d.%m.%Y %H:%M" ) ${THISSCRIPT}] $*"
  fi
  
  echo "${THISMSG}"  
  [ "${LOGFILE}"x != ""x ] && echo "${THISMSG}" >>"${LOGFILE}"
}

# ----------------------------------------------------------------------
#
LogInfo () {
  [ ${VERBOSE} = ${__TRUE} ] && LogMsg "INFO: $*"
}

# ----------------------------------------------------------------------
#
LogError () {
  LogMsg "ERROR: $*"
}

# ----------------------------------------------------------------------
#
LogWarning () {
  LogMsg "WARNING: $*"
}

# ----------------------------------------------------------------------
#
function cleanup {

#  LogMsg "-"
#  LogMsg "-"
  
  return 0
}

# ----------------------------------------------------------------------
# general exit routine
#      
die () {
  typeset THISRC=$1

  INSIDE_DIE=${__TRUE}

  trap "" EXIT

  cleanup

  if [ $# -ne 0 ] ; then
    shift
    if [ $# -ne 0 ] ; then
      if [ ${THISRC} = 0 ] ; then
        LogMsg "$*"
      else
        LogError "$*! RC=${THISRC}"
      fi
    fi      
  fi
  LogMsg "### ${SCRIPTNAME} ended at $( date )"
  exit ${THISRC}
}

# ----------------------------------------------------------------------
#
signal_handler() {
  trap "" exit
  
  if [ ${INSIDE_DIE} = ${__FALSE} ] ; then
    die 100 "Script aborted for unknown reason"
  fi  
}

  	
# ----------------------------------------------------------------------

show_darkstat_daemon_status() {
  LogMsg "The darkstat daemon is${1} running; the PID is ${DARKSTAT_PID}"
  LogMsg "-"
  LogMsg "-" "$( ps -f -p${DARKSTAT_PID} )"
  LogMsg "-"

  LogMsg "The DARKSTAT daemon is listening on these ports:"
  LogMsg "-" 
  LogMsg "-" "$( netstat -tlpn  | grep " ${DARKSTAT_PID}/" )"
  LogMsg "-"
}

# ----------------------------------------------------------------------
#
LogMsg "### ${SCRIPTNAME} started at $( date )"

# install the trap handler
#
trap "signal_handler" EXIT

# get the parameter
#
PARAMETER_OKAY=${__TRUE}
ACTION=""

while [ $# -ne 0 ] ; do
  case $1 in

    --help | -H | help |  "" )
       grep "^#H#" $0 | cut -c4-
       die 0
       ;;

    -v | --verbose )
       VERBOSE=${__TRUE}
       ;;

    +v | ++verbose )
       VERBOSE=${__FALSE}
       ;;

    -q | --quiet )
       QUIET=${__TRUE}
       ;;

    +q | ++quiet )
       QUIET=${__FALSE}
       ;;

    -f | --force )
       FORCE=${__TRUE}
       ;;

    +f | ++force )
       FORCE=${__FALSE}
       ;;

    -d | --debug )
       PREFIX="echo "
       ;;

    +d | ++debug )
       PREFIX=""
       ;;

    -p | --port )
       if [ $# -ge 2 ] ; then
         DARKSTAT_PORT="$2"
         shift
       else
         die 7 "Incomplete parameter -p found"
       fi
       ;;


    -i | --interface )
       if [ $# -ge 2 ] ; then
         DARKSTAT_INTERFACE="$2"
         shift
       else
         die 7 "Incomplete parameter -i found"
       fi
       ;;

    start )
       [ "${ACTION}"x != ""x ] && die 11 "Duplicate action parameter found"
       ACTION="start"
       shift 
       DARKSTAT_OPTIONS="$*"
       break
       ;;

    stop )
       [ "${ACTION}"x != ""x ] && die 11 "Duplicate action parameter found"
       ACTION="stop"
       shift 
       [ $# -ne 0 ] && die 8 "Invalid parameter found: $*"
       break
       ;;

    status )
       [ "${ACTION}"x != ""x ] && die 11 "Duplicate action parameter found"
       ACTION="status"
       shift 
       [ $# -ne 0 ] && die 8 "Invalid parameter found: $*"
       break
       ;;

    restart )
       [ "${ACTION}"x != ""x ] && die 11 "Duplicate action parameter found"
       ACTION="restart"
       shift 
       DARKSTAT_OPTIONS="$*"
       break
       ;;
 
    daemon_help   )
       [ "${ACTION}"x != ""x ] && die 11 "Duplicate action parameter found"
       ACTION="daemon_help"
       shift 
       [ $# -ne 0 ] && die 8 "Invalid parameter found: $*"
       break
       ;;
       
    * ) 
       LogError "Unknown parameter found: $1"
       PARAMETER_OKAY=${__TRUE}
       ;;
     
  esac
  shift
done
[ "${ACTION}"x = ""x ] && ACTION="status"

if [ ${PARAMETER_OKAY} != ${__TRUE} ] ; then
  grep "^#H#" $0 | cut -c4-
  die 2
fi

# ----------------------------------------------------------------------

THISRC=${__FALSE}

CUR_USER_ID="$( id -u )"
CUR_USER_NAME="$( id -un )"
CUR_GROUP_ID="$( id -g )"
CUR_GROUP_NAME="$( id -gn )"

[ "${CUR_USER_ID}"x != "0"x ] && die 101 "This script must be executed by root only"

if [ "${DARKSTAT_INTERFACE}"x = ""x ] ; then
  die 102 "No network interface to use found"
fi  

DARKSTAT_PID_FILE="/tmp/darkstat.${DARKSTAT_PORT}_${DARKSTAT_INTERFACE}.pid"

if [ "${JWM_DIR}"x != ""x ] ; then
  LogMsg "Using the directory based on the the environment variable JWM_DIR (\"${JWM_DIR}\") "
  DARKSTAT_BASE_DIR="${JWM_DIR}"
else
  DARKSTAT_BASE_DIR="$( cd $( dirname $0 )/.. 2>/dev/null && pwd  || echo ${PWD} )"
  LogMsg "Environment variable JWM_DIR not set - using the directory based on the script directory ($( dirname $0 )) "
fi

if [ "${DARKSTAT_EXPORT_FILE}"x = ""x ] ; then
  DARKSTAT_EXPORT_FILE="darkstat_data_$( date +"%d_%m_%Y_%H_%M" ).data"
elif [ "${DARKSTAT_EXPORT_FILE}"x = "none"x ] ; then
  DARKSTAT_EXPORT_FILE=""
fi

LogMsg "The darkstat base directory is ${DARKSTAT_BASE_DIR}"
LogMsg "The interface used by darkstart is ${DARKSTAT_INTERFACE}"

[ ! -d "${DARKSTAT_BASE_DIR}" ] && die 9 "The directory \"${DARKSTAT_BASE_DIR}\" does not exist"
cd "${DARKSTAT_BASE_DIR}" || die 10 "Can not change to the directory \"${DARKSTAT_BASE_DIR}\" "

if [ -x "./sbin/darkstat" ] ; then
  DARKSTAT_BINARY="./sbin/darkstat"
else  
  die 11 "The darkstat binary (either darkstat or busybox) does not exist or is not executable"
fi

LogInfo "The darkstat binary to use is \"${DARKSTAT_BINARY} ${DARKSTAT_FUNCTION}\" "

if [ -r "${DARKSTAT_PID_FILE}" ] ; then
  DARKSTAT_PID="$( cat  "${DARKSTAT_PID_FILE}" )"
  [ "${DARKSTAT_PID}"x != ""x ] && ps -p "${DARKSTAT_PID}" 2>/dev/null 1>/dev/null || DARKSTAT_PID=""
fi

if [ "${DARKSTAT_PID}"x = ""x ] ; then
  DARKSTAT_PID="$( ps -ef | grep -v grep | grep "${DARKSTAT_BINARY} -i ${DARKSTAT_INTERFACE} " | head -1 |awk '{ print $2 };' )"
fi

case ${ACTION} in
   
  start )
    if [ "${DARKSTAT_PID}"x != ""x ] ; then
      show_darkstat_daemon_status " already"
      THISRC=${__FALSE}
    else  
      LogMsg "Starting the darkstat daemon ..."
      LogMsg "The port to use for the darkstat daemon is ${DARKSTAT_PORT}"
      
      CUR_OUTPUT="$( ifconfig ${DARKSTAT_INTERFACE} 2>&1 )"
      if [ $? -ne 0 ] ; then
        LogMsg "-" "${CUR_OUTPUT}"
        die 105 "Interface ${DARKSTAT_INTERFACE} not valid."
      fi
      
      if [ "${DARKSTAT_OPTIONS}"x != ""x ] ; then
        LogMsg "The additional options to use for the darkstat daemon are \"${DARKSTAT_OPTIONS}\" "
        if [[ ${DARKSTAT_OPTIONS} == *--no-daemon* ]] ; then
          die 50 "You can not use this script to start the darkstat daemon in the foreground"
        fi
      fi    

      [ -r "${DARKSTAT_PID_FILE}" ] && rm "${DARKSTAT_PID_FILE}" 2>/dev/null
      CUR_OUTPUT="$( set -x  ; "${DARKSTAT_BINARY}"  -p "${DARKSTAT_PORT}" -i "${DARKSTAT_INTERFACE}" --pidfile "${DARKSTAT_PID_FILE}" ${DARKSTAT_OPTIONS} 2>&1 )"
      DARKSTAT_PID="$( cat "${DARKSTAT_PID_FILE}" 2>/dev/null )"
      
      if [ "${DARKSTAT_PID}"x != ""x ] ; then
        ps -p  "${DARKSTAT_PID}" 2>/dev/null 1>/dev/null && THISRC=${__TRUE} || THISRC=${__FALSE}
      else
        THISRC=${__FALSE}
      fi

      LogMsg "-" "${CUR_OUTPUT}"
      if [ ${THISRC} -ne ${__TRUE} ] ; then
        LogMsg "Failed to start the darkstat daemon -- please check the messages for the cause of the error"
        THISRC=${__FALSE}
      else
        LogMsg "darkstat daemon started; the PID is ${DARKSTAT_PID} "
        LogMsg "Use http://localhost:${DARKSTAT_PORT} or http://${HOSTNAME}:${DARKSTAT_PORT} to access the darkstat in your Webbrowser"
        THISRC=${__TRUE}
      fi
    fi  
    ;;

  stop )
    if [ "${DARKSTAT_PID}"x = ""x ] ; then
      LogMsg "The darkstat daemon is NOT running (well, it may be running but it was not started by this script)"
     THISRC=${__FALSE}
    else
      THISRC=${__TRUE}
      LogMsg "The darkstat daemon is running; the PID is ${DARKSTAT_PID}"
              
      LogMsg "Stopping the darkstat daemon ..."
      kill "${DARKSTAT_PID}"
      sleep 1
      ps -p "${DARKSTAT_PID}" 2>/dev/null 1>/dev/null
      if [ $? -eq 0 ] ; then
        LogMsg "The darkstat daemon is still running -- now using \"kill -9  ${DARKSTAT_PID} \" ..."
        kill -9 "${DARKSTAT_PID}"
        ps -p "${DARKSTAT_PID}" 2>/dev/null 1>/dev/null
        if [ $? -eq 0 ] ; then
          LogMsg "The darkstat daemon is still running -- please kill the process ${DARKSTAT_PID} manually"
          THISRC=${__FALSE}        
        fi
      fi

      if [ ${THISRC} -eq ${__TRUE} ] ; then
        [ -r "${DARKSTAT_PID_FILE}" ] && rm -f  "${DARKSTAT_PID_FILE}" 2>/dev/null      
      fi  
    fi        
    ;;

  restart )
    "${REAL_SCRIPTDIR}/${SCRIPTNAME}" stop && "${REAL_SCRIPTDIR}/${SCRIPTNAME}" start ${DARKSTAT_OPTIONS}
    THISRC=$?
    ;;

  status )  
    if [ "${DARKSTAT_PID}"x != ""x ] ; then
      show_darkstat_daemon_status
      THISRC=${__TRUE}
    else
      LogMsg "The darkstat daemon is NOT running (well, it may be running but it was not started by this script)"
      THISRC=${__FALSE}
    fi
    ;;

  daemon_help )
    LogMsg "Additional parameter supported by the darkstat daemon are:"    
    LogMsg "-" "$( "${DARKSTAT_BINARY}" --help )"
    ;;
    
  esac
  
# ----------------------------------------------------------------------
#

# ----------------------------------------------------------------------
#

die ${THISRC}

# ----------------------------------------------------------------------
#
