 #!/bin/ksh
#
### Simple korn shell script template
###

#H# ???
#H#
#H# Function: ???
#H# 
#H# Usage:    ??? [-v|--verbose] [-q|--quiet] [-f|--force] [-y|--yes] [-n|--no]  [start|stop|restart|status]
#H#
#H# Parameter:
#H#   -v - verbose mode
#H#   -q - quiet mode
#H#   -f - force execution
#H#   -y - answer yes to all questions
#H#   -n - answer no to all questions
#H#


### LSB Style tags (remove the initial ### to activate)
### 
### ### BEGIN INIT INFO
### # Provides: foo
### # Required-Start: bar
### # Default-Start: 2 3 4 5
### # Default-Stop: 0 1 6
### # Description: Foo init script
### ### END INIT INFO

### chkconfig tags for start/stop scripts (remove the initial ### to activate)
###
### For example: # chkconfig: 2345 20 80
###
### # chkconfig: <startlevellist> <startpriority> <endpriority>
### # description: <multi-line description of service>

### see man chkconfig for other supported tags

#
# History:  
#   28.04.2016 v1.0.0 /bs
#     initial release
#
#   24.10.2016 v1.1.0 /bs
#     added the functions DebugShell, executeCommandAndLog, LogOnly
#     added the variables $RUNNING_IN_TERMINAL_SESSION, REAL_SCRIPTDIR, REAL_SCRIPTNAME
#
#   01.03.2017 v1.2.0 /bs
#     added logrotate 
#
#   12.03.2017 v1.3.0 /bs
#     added the functions AskUser, isNumber
#     added the parameter --yes and --noo
#

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

# define constants
#
__TRUE=0
__FALSE=1

APPLICATION_NAME="MyApplication"


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

# current hostname
#
CUR_HOST="$( hostname )"
CUR_SHORT_HOST="${CUR_HOST%%.*}"


# 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 )"
REAL_SCRIPTNAME="${REAL_SCRIPTDIR}/${SCRIPTNAME}"

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

CUR_USER_ID="$( id -u )"
CUR_USER_NAME="$( id -un )"

CUR_GROUP_ID="$( id -g )"
CUR_GROUP_NAME="$( id -gn )"


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

# variables for AskUser
#

# do not print the user input
__NOECHO=${__FALSE}

# use /dev/tty instead of STDIN and STDOU
__USE_TTY=${__FALSE}

# allow a debug shell in ask user
#
__DEBUG_SHELL_IN_ASKUSER=${__TRUE}

# answer all questions with Yes (if "y") or No (if "n") else ask the user
#
__USER_RESPONSE_IS=""


# check tty
#
tty -s && RUNNING_IN_TERMINAL_SESSION=${__TRUE} || RUNNING_IN_TERMINAL_SESSION=${__FALSE}

# values for the function Read_APPL_PARAMS_entries
#
RCM_SERVICE=""
RCM_FUNCTION=""

# ----------------------------------------------------------------------
# internal functions
#
# create up to 10 backups of one or more file
#
# Usage:   RotateLog [file1 [... [file#]]]
#
function RotateLog {
  typeset THISRC=${__FALSE}
  typeset THIS_LOGFILES="${LOGFILE}"
  typeset THIS_LOGFILE=""
  typeset i
  
  [ $# -ne 0 ] && THIS_LOGFILES="$*"
  if [ "${THIS_LOGFILES}"x != ""x ] ; then
    for THIS_LOGFILE in "${THIS_LOGFILES}" ; do
      for i in 8 7 6 5 4 3 2 1 0  ; do
        [ -r "${THIS_LOGFILE}.${i}" ] && mv "${THIS_LOGFILE}.${i}" "${THIS_LOGFILE}.$(( i + 1 ))"
      done
      [ -r "${THIS_LOGFILE}" ] && mv "${THIS_LOGFILE}" "${THIS_LOGFILE}.0"
    done
    THISRC=${__TRUE}
  fi

  return ${THISRC}
}

# ----------------------------------------------------------------------
# redirect STDOUT and STDERR of the script and all commands executed by
# the script to a file if called in an background session
#
if [ ${RUNNING_IN_TERMINAL_SESSION} = ${__FALSE} ] ; then
  STDOUT_FILE="/var/tmp/${SCRIPTNAME}.STDOUT_STDERRR"
  RotateLog "${STDOUT_FILE}"
  
  echo "${SCRIPTNAME} -- Running in a detached session ... STDOUT/STDERR will be in ${STDOUT_FILE}" >&2
  echo "${SCRIPTNAME} -- Running in a detached session ... STDOUT/STDERR will be in ${STDOUT_FILE}" >/dev/tty
 
  exec 3>&1
  exec 4>&2
  exec 1>>"${STDOUT_FILE}"  2>&1
fi

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

  typeset THISMSG=""

  [ ${ROTATE_LOG} = ${__TRUE} ] && RotateLog
  ROTATE_LOG=${__FALSE}
  
  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}"
}

# ----------------------------------------------------------------------
#
function LogOnly {
  LogMsg "$*" >/dev/null
}

# ----------------------------------------------------------------------
#
function LogInfo {
  [ ${VERBOSE} = ${__TRUE} ] && LogMsg "INFO: $*" >&2
}

# ----------------------------------------------------------------------
#
function LogError {
  LogMsg "ERROR: $*" >&2
}

# ----------------------------------------------------------------------
#
function LogWarning  {
  LogMsg "WARNING: $*"
}

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

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

# --------------------------------------
# executeCommandAndLog
#
# execute a command and write STDERR and STDOUT also to the logfile
#
# usage: executeCommandAndLog command parameter
#
# returns: the RC of the executed command (even if a logfile is used!)
#
function executeCommandAndLog {
  set +e
  typeset THISRC=0

  LogInfo "### Executing \"$@\" " || LogOnly "### Executing \"$@\" "

  if [ "${LOGFILE}"x != ""x -a -f "${LOGFILE}" ] ; then
    # The following trick is from
    # http://www.unix.com/unix-dummies-questions-answers/13018-exit-status-command-pipe-line.html#post47559
    exec 5>&1
    tee -a "${LOGFILE}" >&5 |&
    exec >&p
    eval "$*" 2>&1
    THISRC=$?
    exec >&- >&5
    wait

    LogInfo "### The RC is ${THISRC}" || LogOnly  "### The RC is ${THISRC}"

  else
    eval "$@"
    THISRC=$?
  fi

  return ${THISRC}
}

# --------------------------------------
# DebugShell
#
# Open a simple debug shell
#
# Usage: DebugShell
#
# returns: ${__TRUE}
#
# Input is always read from /dev/tty; output always goes to /dev/tty
#
function DebugShell {
	
  if [ ${RUNNING_IN_TERMINAL_SESSION} != ${__TRUE} ] ; then
    LogError "DebugShell can only be used in interactive sessions"
    return ${__FALSE}
  fi
  
  "typeset" THISRC=${__TRUE}

  "typeset" USER_INPUT=""

  while "true" ; do
    "printf" "\n ------------------------------------------------------------------------------- \n"
    "printf" "${SCRIPTNAME} - debug shell - enter a command to execute (\"exit\" to leave the shell)\n"
    "printf" "( functions = list all defined functions )\n"
    "printf" ">> "
    "read" USER_INPUT

    case "${USER_INPUT}" in
      "exit" )
        "break";
        ;;

      "functions" | "func" | "funcs" )
        "typeset" -f | grep "\{$"
        ;;

      "" )
        :
        ;;

      * )
        "eval" ${USER_INPUT}
        ;;
    esac
  done </dev/tty >/dev/tty 2>&1

  "return" ${THISRC}
}

# ----------------------------------------------------------------------
# show the script usage
#
function show_script_usage {
  typeset THISRC=${__FALSE}

  grep "^#H#" "${REAL_SCRIPTNAME}" | cut -c4-

  return ${THISRC}
}

# ----------------------------------------------------------------------
# general exit routine
#      
function 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

  if [ "${LOGFILE}"x != ""x -a -f "${LOGFILE}" ] ; then
    LogMsg "### The logfile used was ${LOGFILE}"
  fi

  LogMsg "### ${SCRIPTNAME} ended at $( date )"
  
  exit ${THISRC}
}

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

# ----------------------------------------------------------------------
# read APPL_PARAMS from RCM
#
# APPL_PARAMS not used for this service
#
Read_APPL_PARAMS_entries() {
  typeset THISRC=${__TRUE}

  typeset RCM_INCLUDE_FILE="/usr/db/RCM/Utility/shAPI_env"
  typeset RCM_HOSTID_FILE="/var/db/var/hostid"

  typeset RCM_HOSTID="$( cat "${RCM_HOSTID_FILE}" 2>/dev/null )"
  typeset RCM_DO_QUERY="/usr/db/RCM/Utility/dbquery"
  
  if [ "${RCM_INCLUDE_FILE}"x != ""x ] ; then
    if [ -r "${RCM_INCLUDE_FILE}" ] ; then
      . "${RCM_INCLUDE_FILE}"
    fi
  fi

  if  [ ! -x "${RCM_DO_QUERY}" ] ; then
    LogError "${RCM_DO_QUERY} not found or not executable"
    THISRC=${__FALSE}
  fi
  
  if [ "${RCM_HOSTID}"x = ""x ] ; then
    LogError 201 "Can not read the file ${RCM_HOSTID_FILE}"
    THISRC=${__FALSE}
  fi

  if [ "${RCM_SERVICE}"x = ""x ] ; then
    LogError "Variable RCM_SERVICE is not set"
    THISRC=${__FALSE}
  fi

  if [ "${RCM_FUNCTION}"x = ""x ] ; then
    LogError "Variable RCM_FUNCTION is not set"
    THISRC=${__FALSE}
  fi
  
  if [ ${THISRC} = ${__TRUE} ] ; then

    THISRC=${__FALSE}

# read the APPL_PARAMS from the RCM
#
    DBQUERY_CMD="${RCM_DO_QUERY} --where \"{ hostid => '${RCM_HOSTID}', service => '${RCM_SERVICE}', function => '${RCM_FUNCTION}' }\" \
              --key appl_params_by_hostid_svc_func --fields=parameter,value "

    LogMsg "Executing "
    LogMsg "-"  "${DBQUERY_CMD}"

    eval ${DBQUERY_CMD} | tr -d '"' | sort | while read THIS_KEY THIS_VALUE ; do
      [ "${THIS_KEY}"x = ""x ] && continue

      THISRC=${__TRUE}
      LogMsg "Key found: \"${THIS_KEY}\" = \"${THIS_VALUE}\" "

      case ${THIS_KEY} in

        SAS_USER )
          LogMsg "Found the SAS user ${THIS_VALUE}"
          SAS_USER="${THIS_VALUE}"
          ;;  

        * )
          LogMsg "Unknown entry found in APPL_PARAMS: ${THIS_KEY} : ${THIS_VALUE}"
          ;;   

      esac
    done

  fi

  [ ${THISRC} != ${__TRUE} ] && LogWarning "No config found in the RCM"

  return ${THISRC}
}


# --------------------------------------
# isNumber
#
# check if a value is an integer
#
# usage: isNumber testValue
#
# returns: ${__TRUE} - testValue is a number else not
#
function isNumber {
  typeset THISRC=${__FALSE}

# old code:
#  typeset TESTVAR="$(echo "$1" | sed 's/[0-9]*//g' )"
#  [ "${TESTVAR}"x = ""x ] && return ${__TRUE} || return ${__FALSE}

  [[ $1 == +([0-9]) ]] && THISRC=${__TRUE} || THISRC=${__FALSE}

  return ${THISRC}
}

# --------------------------------------
# AskUser
#
# Ask the user (or use defaults depending on the parameter -n and -y)
#
# Usage: AskUser "message"
#
# returns: ${__TRUE} - user input is yes
#          ${__FALSE} - user input is no
#          USER_INPUT contains the user input
#
# Notes: "all" is interpreted as yes for this and all other questions
#        "none" is interpreted as no for this and all other questions
#
# If __NOECHO is ${__TRUE} the user input is not written to STDOUT
# __NOECHO is set to ${__FALSE} again in this function
#
# If __USE_TTY is ${__TRUE} the prompt is written to /dev/tty and the
# user input is read from /dev/tty . This is useful if STDOUT is redirected
# to a file.
#
# "shell" opens the DebugShell; set __DEBUG_SHELL_IN_ASKUSER to ${__FALSE}
# to disable the DebugShell in AskUser
#

function AskUser {
  typeset THISRC=""

  if [ "${__USE_TTY}"x = "${__TRUE}"x ] ; then
    typeset mySTDIN="</dev/tty"
    typeset mySTDOUT=">/dev/tty"
  else
    typeset mySTDIN=""
    typeset mySTDOUT=""
  fi

  case ${__USER_RESPONSE_IS} in

   "y" ) USER_INPUT="y" ; THISRC=${__TRUE}
         ;;

   "n" ) USER_INPUT="n" ; THISRC=${__FALSE}
         ;;

     * ) while true ; do
           [ $# -ne 0 ] && eval printf "\"$* \"" ${mySTDOUT}
           if [ ${__NOECHO} = ${__TRUE} ] ; then
             __STTY_SETTINGS="$( stty -g )"
             stty -echo
           fi

           eval read USER_INPUT ${mySTDIN}
           if [ "${USER_INPUT}"x = "shell"x -a ${__DEBUG_SHELL_IN_ASKUSER} = ${__TRUE} ] ; then
             DebugShell
           else
             [ "${USER_INPUT}"x = "#last"x ] && USER_INPUT="${LAST_USER_INPUT}"
             break
           fi
         done

         if [ ${__NOECHO} = ${__TRUE} ] ; then
           stty ${__STTY_SETTINGS}
           __STTY_SETTINGS=""
         fi

         case ${USER_INPUT} in

           "y" | "Y" | "yes" | "Yes") THISRC=${__TRUE}  ;;

           "n" | "N" | "no" | "No" ) THISRC=${__FALSE} ;;

           "all" ) __USER_RESPONSE_IS="y"  ; THISRC=${__TRUE}  ;;

           "none" )  __USER_RESPONSE_IS="n" ;  THISRC=${__FALSE} ;;

           * )  THISRC=${__FALSE} ;;

        esac
        ;;
  esac
  [ "${USER_INPUT}"x != ""x ] && LAST_USER_INPUT="${USER_INPUT}"

  __NOECHO=${__FALSE}
  return ${THISRC}
}

# ----------------------------------------------------------------------
# start the application
#
function start_application {
  typeset THISRC=${__FALSE}

  LogMsg "Starting the ${APPLICATION_NAME} ..."
    
  return ${THISRC}
}

# ----------------------------------------------------------------------
# stop the application
#
function stop_application {
  typeset THISRC=${__FALSE}

  LogMsg "Stopping the ${APPLICATION_NAME} ..."
  
  return ${THISRC}
}

# ----------------------------------------------------------------------
# get the status of the application
#
function status_application {
  typeset THISRC=${__FALSE}

  LogMsg "Retrieving the status of the ${APPLICATION_NAME} ..."
  
  return ${THISRC}
}


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

if [ "${LOGFILE}"x != ""x -a -f "${LOGFILE}" ] ; then
  LogMsg "### The logfile used is ${LOGFILE}"
fi

# install the trap handler
#
trap "signal_handler" EXIT

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

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

    -h | --help | -H | help |  "" )
       show_script_usage    
       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 )
       DebugShell 
       ;;

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

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

    -d:* | --debug:** )
       PREFIX="${1#*:}"
       LogMsg "The debug prefix used is: \"${PREFIX}\" "
       ;;

    +y | ++yes | +n | ++no )
       __USER_RESPONSE_IS=""
       ;;
   
    -y | --yes )
       __USER_RESPONSE_IS="y"
       ;;
       
    -n | --no )
       __USER_RESPONSE_IS="n"
       ;;
       
    start )
       [ "${ACTION}"x != ""x ] && die 201 "Duplicate action parameter found: ${ACTION} and $1"
       ACTION="start"
       ;;

    stop )
       [ "${ACTION}"x != ""x ] && die 201 "Duplicate action parameter found: ${ACTION} and $1"
       ACTION="stop"
       ;;

    status )
       [ "${ACTION}"x != ""x ] && die 201 "Duplicate action parameter found: ${ACTION} and $1"
       ACTION="status"
       ;;

    restart )
       [ "${ACTION}"x != ""x ] && die 201 "Duplicate action parameter found: ${ACTION} and $1"
       ACTION="restart"
       ;;
       
    * ) 
       LogError "Unknown parameter found: $1"
       PARAMETER_OKAY=${__TRUE}
       ;;
     
  esac
  shift
done
[ "${ACTION}"x = ""x ] && ACTION="status"

if [ ${PARAMETER_OKAY} != ${__TRUE} ] ; then
  show_script_usage
  die 2
fi

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

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

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



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

case ${ACTION} in

  start )
    start_application
    ;;

  stop )
    stop_application
    ;;
    
  restart )
    stop_application && start_application
    ;;

  status )
    status_application
    ;;

esac
    
# ----------------------------------------------------------------------
#
THISRC=${__TRUE}
#


# ----------------------------------------------------------------------
#
die ${THISRC}

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