#!/bin/bash

############################################################
#                                                          #
# lunar.init - a collection of init.d script functions     #
#                                                          #
############################################################
#                                                          #
# Copyrighted Auke Kok <koka@geo.vu.nl> 2002 under GPLv2   #
# Copyright 2009 by Stefan Wold under GPLv2                #
#                                                          #
############################################################

# we really need to do this:
trap ":" QUIT TSTP SEGV
export PATH=/usr/local/sbin:/sbin:/bin:/usr/sbin:/usr/bin

#
# work notes:
#
# Need to install status() and other return codes
# Need to rectify daemon-restart test and script deletion of /var/run/<prog>.pid
# Need to assess impact of the above changes elswehere
#
#
#
#

#
# for whoever called us, we would like to know the follofing data,
# so we may probe for changes, get and or set variables, etc.
#
# chkconfig:        [ the chkconfig style data for the symlinks ]
# config:           [ one or more config files to watch         ]
# description:      [ a multiline description for this script   ]
# short:            [ one liner to be displayed during start    ]
# pidfile:          [ the pidfile                               ]
# processname:      [ name of the process                       ]
# sigstop:          [ signal to stop (defaults to TERM)         ]
# sigreload:        [ signal to reload (defaults to HUP)        ]
#

#
# the functionality in here can be called in 2 ways. Either run the script
# itself by `$0 start`, or by calling the default_start (for instance)
# functions directly.
#
# the default actions available are: (`$0 <action>`)
#
# start|start_daemon	starts the process
# stop|killproc		kills the process
# restart		restarts it
# probe			probes (checks dates on configs) for a reload
# reload		reloads it
# status		check if it's alive
# <empty or invalid>	display default usage message
# install		install the required symlinks
# uninstall		remove the appropriate symlinks
#
# analog to that, you may also directly reference the functions:
#
# default_{start|stop|restart|probe|reload|status}
#

CHKCONFIG=$(grep '^# chkconfig:' "$0" | cut -d : -f 2-2)
CONFIGFILES=$(grep '^# config:' "$0" | cut -d : -f 2-2 | tr -d " ")
# DESCRIPTION=`grep '^# description: ' "$0" | cut -d : -f 2-2 | tr -d " "`
SHORT=$(grep '^# short:' "$0" | cut -d : -f 2-2 | tr -d " ")
PIDFILE=$(grep '^# pidfile:' "$0" | cut -d : -f 2-2 | tr -d " ")
PROCESS=$(grep '^# processname:' "$0" | cut -d : -f 2-2 | tr -d " ")
SIGSTOP=$(grep '^# sigstop:' "$0" | cut -d : -f 2-2 | tr -d " ")
SIGRELOAD=$(grep '^# sigreload:' "$0" | cut -d : -f 2-2 | tr -d " ")
RUNAS=$(grep '^# runas:' "$0" | cut -d : -f 2-2 | tr -d " ")

get_data() {
  # define these
  LINKNAME=${0##*/}
  BASENAME=${LINKNAME#*[SK][0-9][0-9]}

  # attempt to get these right:
  if [ ! -z $PROCESS ]; then
    if [ "${PROCESS:0:1}" = "/" ]; then
      PROCESS_FULL=$PROCESS
      PROCESS_BASE=$(basename $PROCESS)
    else
      if ! which 2>/dev/null; then
        PROCESS_FULL=$(which $PROCESS)
        PROCESS_BASE=$(basename $PROCESS)
      else
        PROCESS=
      fi
    fi
    [ -z $PIDFILE ] && PIDFILE=/var/run/$PROCESS_BASE.pid
    [ -z $SHORT ] && SHORT=$BASENAME
    [ -z $SIGSTOP ] && SIGSTOP=TERM
    [ -z $SIGRELOAD ] && SIGRELOAD=HUP
  fi

  # VITAL INFO: SERVPID
  if [ -f "$PIDFILE" ]; then
    if [ -d "/proc/$(cat $PIDFILE)" ]; then
      SERVPID=$(cat "$PIDFILE")
    fi
  fi
}

# define the output string colors and text
ESC=$(echo -en "\033")
RESULT_OK="${ESC}[\061;32m${ESC}[70G[\040\040\040OK\040\040\040]${ESC}[m"
RESULT_FAIL="${ESC}[\061;31m${ESC}[70G[\040FAILED\040]${ESC}[m"
RESULT_WARN="${ESC}[\061;33m${ESC}[70G[\040\040WARN\040\040]${ESC}[m"
JUNK="]]]]]]"

# Handy
pgrep() {
  if [ -n "$SERVPID" ]; then
    # we will kill the daemon:
    if [ -d /proc/$SERVPID ]; then
      return 0
    else
      return 1
    fi
  else
    # where is the new daemon???
    if [ -f "$PIDFILE" ]; then
      if [ -d "/proc/$(cat $PIDFILE)" ]; then
        return 0
      else
        return 255
      fi
    else
      # sleep 1
      # second chance:
      if [ -f "$PIDFILE" ]; then
        if [ -d "/proc/$(cat $PIDFILE)" ]; then
          return 0
        else
          return 255
        fi
      else
        return 255
      fi
    fi
  fi
}

pkill() {
  if [ -z "$SERVPID" ]; then
    return 255
  else
    if kill -$SIGSTOP $SERVPID >&/dev/null; then
      if [ -f $PIDFILE ]; then
        rm -f $PIDFILE
      fi
      return 0
    else
      return 255
    fi
  fi
}

prload() {
  if [ ! -f $PIDFILE ]; then
    return 255
  else
    if kill -$SIGRELOAD $SERVPID >&/dev/null; then
      return 0
    else
      return 255
    fi
  fi
}

mkpid() {
  if [ ! -e $PIDFILE ]; then
    echo -n "[PID] "
    /bin/pgrep -o -P 1 "^$PROCESS_BASE$" >$PIDFILE && return 0 || return 255
  else
    return
  fi
}

pidok() {
  if [ -e $PIDFILE ]; then
    if pgrep; then
      return 0
    else
      return 255
    fi
  else
    return 255
  fi
}

log_success_msg() {
  echo -e "$1 $RESULT_OK"
}

log_failure_msg() {
  echo -e "$1 $RESULT_FAIL"
}

log_warning_msg() {
  echo -e "$1 $RESULT_WARN"
}

start_process() {
  if [ ! -z "$RUNAS" ]; then
    /bin/su $RUNAS -c "$PROCESS_FULL $ARGS" &&
      return 0 || return 255
  else
    $PROCESS_FULL $ARGS &&
      return 0 || return 255
  fi
}

# the main functions are defined as default_ so you may call these
# directly from a script too
default_start() {
  get_data
  # start the daemon
  echo -n "Starting $SHORT: "
  # check to see if it's not already running
  if ! pgrep; then
    # sanity check:
    if [ -f $PIDFILE ]; then
      rm -f $PIDFILE
    fi
    # start it up ourselves
    if start_process; then
      # starup succeeded, now check if it really is running
      if pgrep; then
        echo -e $RESULT_OK
      else
        # here's the broken daemon case
        mkpid
        if pgrep; then
          echo -e $RESULT_OK
        else
          # startup failed on our side
          echo -e $RESULT_FAIL
        fi
      fi
    fi
  else
    # it's already running idiot
    echo -n "already running"
    echo -e $RESULT_WARN
  fi
}

default_stop() {
  get_data
  # stop the daemon
  echo -n "Stopping $SHORT: "
  if pgrep; then
    pkill
    for COUNT in 1 2 3 4 5; do
      pgrep && pkill
      pgrep && echo -n "." && sleep 1
      if ! pgrep; then
        # killed OK
        [ -e $PIDFILE ] && rm $PIDFILE
        echo -e $RESULT_OK
        break
      fi
    done
    if pgrep; then
      # FAILED!
      mkpid
      echo -e "kill failed$RESULT_FAIL"
    fi
  else
    echo -e "not running $RESULT_WARN"
  fi
}

default_restart() {
  get_data
  # restart ourselves
  $0 stop && $0 start
}

default_probe() {
  get_data
  # see if we need to reload it based on the configs
  if [ -e $PIDFILE ]; then
    # is it really there?
    if pidok; then
      # test date of config files against PID dile
      NEEDRELOAD="false"
      for CONFIGFILE in $CONFIGFILES; do
        [ $CONFIGFILE -nt $PIDFILE ] && NEEDRELOAD="true"
      done
      if [ "X$NEEDRELOAD" == "Xtrue" ]; then
        # we need to reload
        $0 reload
      else
        # no need to reload
        echo "Reload of $SHORT not needed"
      fi
    else
      # our process died!
      [ -e $PIDFILE ] && rm $PIDFILE
      echo "Reload of $SHORT failed: process died!"
    fi
  else
    # no pid file???
    echo "Reload of $SHORT failed: cannot find process"
  fi
}

default_reload() {
  get_data
  # reload it
  echo -n "Reloading $SHORT: "
  if [ -e $PIDFILE ]; then
    # we have a pid file
    prload
    # test existence
    if pidok; then
      # still running then
      touch $PIDFILE
      echo -e $RESULT_OK
    else
      # something went wrong
      if pgrep; then
        # changed PID
        mkpid
        echo -e $RESULT_OK
      else
        # it died
        [ -e $PIDFILE ] && rm $PIDFILE
        echo -e "process died!$RESULT_FAIL"
      fi
    fi
  else
    # no pid file???
    echo -e "cannot find process$RESULT_FAIL"
  fi
}

default_status() {
  get_data
  # check if it is running
  echo -n "Checking $SHORT: "
  if pidok; then
    # we have a pid file and it's okay
    echo -e "$RESULT_OK"
  else
    # something went wrong
    if pgrep; then
      # changed PID
      mkpid
      echo -e "Was reloaded$RESULT_OK"
    else
      # it died
      [ -e $PIDFILE ] && rm $PIDFILE
      echo -e "process died!$RESULT_FAIL"
    fi
  fi
}

default_install() {
  get_data
  # make the links for this file go to the right places
  LEVELS=$(echo $CHKCONFIG | cut -d ' ' -f 1)
  LSTART=$(echo $CHKCONFIG | cut -d ' ' -f 2)
  LSTOP=$(echo $CHKCONFIG | cut -d ' ' -f 3)
  ls /etc/rc?.d/???$BASENAME >/dev/null 2>&1 &&
    echo "Warning: some links already exist!"
  for LEVEL in 0 1 2 3 4 5 6; do
    echo $LEVELS | grep -q $LEVEL && {
      # make start link
      echo ln -s ../init.d/$BASENAME /etc/rc$LEVEL.d/S$LSTART$BASENAME
      ln -s ../init.d/$BASENAME /etc/rc$LEVEL.d/S$LSTART$BASENAME || true
    } || {
      # make stop link
      echo ln -s ../init.d/$BASENAME /etc/rc$LEVEL.d/K$LSTOP$BASENAME
      ln -s ../init.d/$BASENAME /etc/rc$LEVEL.d/K$LSTOP$BASENAME || true
    }
  done
}

default_uninstall() {
  get_data
  # remove the links for this script
  LEVELS=$(echo $CHKCONFIG | cut -d ' ' -f 1)
  LSTART=$(echo $CHKCONFIG | cut -d ' ' -f 2)
  LSTOP=$(echo $CHKCONFIG | cut -d ' ' -f 3)
  for LEVEL in 0 1 2 3 4 5 6; do
    echo $LEVELS | grep -q $LEVEL && {
      # remove start link
      echo rm /etc/rc$LEVEL.d/S$LSTART$BASENAME
      rm /etc/rc$LEVEL.d/S$LSTART$BASENAME || true
    } || {
      # remove stop link
      echo rm /etc/rc$LEVEL.d/K$LSTOP$BASENAME
      rm /etc/rc$LEVEL.d/K$LSTOP$BASENAME || true
      # if ANYONE can explain why that || true is NEEDED
      # tell me PLEASE!!!
    }
  done
  ls /etc/rc?.d/???$BASENAME >/dev/null 2>&1 &&
    echo "Warning: some links still exist!"
}

default_usage() {
  # default usage message
  echo "usage: $0 {start|stop|restart|reload|status}"
}

# default when no action passed
[ -z $1 ] && ACTION=usage || ACTION=$1

# and run the code
if set | grep -q "^$ACTION ()"; then
  # do the custom function
  $ACTION $@
else
  get_data
  # these are always available:
  case $ACTION in
    install)
      default_install
      return
      ;;
    uninstall)
      default_uninstall
      return
      ;;
  esac
  # double check these:
  if [ -z $PROCESS ]; then
    echo -e "Processname is not defined!$RESULT_FAIL"
    exit 1
  fi
  if [ ! -x $PROCESS_FULL ]; then
    echo -e "The executable $PROCESS_BASE does not exist!$RESULT_FAIL"
    exit 1
  fi
  # do the builtin function
  case $ACTION in
    start | start_daemon) default_start ;;
    stop | killproc) default_stop ;;
    restart) default_restart ;;
    probe) default_probe ;;
    reload) default_reload ;;
    status) default_status ;;
    *) default_usage ;;
  esac
fi
