#!/bin/bash
# Begin $rc_base/init.d/functions - Run Level Control Functions
# Based on functions script from LFS-3.1 and earlier.
# Rewritten by Gerard Beekmans  - gerard@linuxfromscratch.org
# With code based on Matthias Benkmann's simpleinit-msb @
# http://winterdrache.de/linux/newboot/index.html
# Modified slightly for SourceMage GNU linux
# SGL-script-version=20020923

umask 022

export PATH="/bin:/usr/bin:/sbin:/usr/sbin"

KILLDELAY=3

COLUMNS=$(stty size)
COLUMNS=${COLUMNS##* }
COL=$[ $COLUMNS - 10 ]
WCOL=$[ $COLUMNS - 30 ]
SET_COL="builtin echo -en \\033[${COL}G"
SET_WCOL="builtin echo -en \\033[${WCOL}G"
CURS_UP="builtin echo -en \\033[A"

NORMAL="builtin echo -en \\033[0;39m"
SUCCESS="builtin echo -en \\033[1;32m"
WARNING="builtin echo -en \\033[1;33m"
FAILURE="builtin echo -en \\033[1;31m"
SCRIPTC="builtin echo -en \\033[1;37m"

# log the messages hack
echo() { 
if ! [[ -t 1 ]]; then
  builtin echo "$@"
else
  INITSTORE="$INITSTORE$(builtin echo "$@")"

  # correct for bash's insane strip trailing newline mumbo jumbo on command substitutions
  TRAILINGNL=$(( $(builtin echo "$@" | ( i=0; while read LINE; do i=$((++i)); done; builtin echo $i)) - $(builtin echo "$(builtin echo "$@")" | ( i=0; while read LINE; do i=$((++i)); done; builtin echo $i)) ))
  local i
  for ((i=0; i <= $TRAILINGNL; i++)); do
    INITSTORE="$INITSTORE
"
  done

  # if it's more than one line, dump the line out and save the last line that doesn't have a newline at the end yet.
  if [ "`builtin echo "$INITSTORE" | ( i=0; while read LINE; do i=$((++i)); done; builtin echo $i)`" -gt 1 ]; then
    print_status message
  fi
fi
}
export -f echo
export INITSTORE

print_error_msg()
{
  echo
  $FAILURE
  echo "You should not be reading this error message. It means"
  echo "that an unforseen error took place in $i,"
  echo "which exited with a return value of $error_value"
  echo
  echo "If you're able to track this error down to a bug in one"
  echo "of the files provided by SourceMage GNU Linux, please"
  echo "be so kind to inform us at http://www.sourcemage.org"
  $NORMAL
  echo
  echo
  echo "Press Enter to continue..."
  read
}

evaluate_retval()
{
  local exit_value=$?

  if [ $exit_value = 0 ] ; then
    print_status success
  else
    print_status failure
  fi

  return $exit_value
}

logger_func()
{
  [ -e /bin/logger ] && /bin/logger $* ||
  {
    [ -e /usr/bin/logger ] && /usr/bin/logger $*
  }
  true
}
export -f logger_func

print_status()
{
  if [ $# = 0 ] ; then
    echo "Usage: $0 {success|warning|failure|message}"
    return 1
  fi

  case "$1" in
    success) COLORCODE="$SUCCESS" ;;
    warning) COLORCODE="$WARNING" ;;
    failure) COLORCODE="$FAILURE" ;;
    message) ;; # null
  esac

  local SCRIPT="$(builtin echo $0 | sed -e 's!/.*/!!')"
  local SCRIPTW="$($SCRIPTC)$SCRIPT$($NORMAL)"

  local line
  builtin echo "$INITSTORE" | while read line; do
    [ -n "$line" -o "$1" != "message" ]         &&
    if [ -n "$SYSLOG_INIT" ]; then
      logger_func -p user.info -t init.d -- "$SCRIPT: $@: $line"
    fi                                          &&
    builtin echo -n  "$SCRIPTW"                 &&
    if [ ! "$1" = "message" ]; then
      builtin echo -n ": "   &&
      $COLORCODE             &&
      builtin echo -n "$@"   &&
      $NORMAL
    fi                                          &&
    if [ -n "$line" ]; then
      builtin echo -n  ": $line"
    fi
    if [ -n "$line" -o "$1" != "message" ]; then
      builtin echo -ne "\eE" # PARALLEL
     fi
  done
  if [ "$1" = "message" ]; then
    INITSTORE="$line"
  else
    INITSTORE=
  fi

}
export -f print_status

getpids()
{
  local base=${1##*/}
  pidlist=$(builtin echo $(for i in $(pidof -o $$ -o $PPID -o '%PPID' -x $base); do awk -v i=$i '!/\/etc\/init[.]d/ {print i}' < /proc/$i/cmdline; done))
}

loadproc()
{
  if [ $# = 0 ] ; then
    echo "Usage: loadproc {program}"
    exit 1
  fi

  getpids $1

  if [ -z "$pidlist" ] ; then
    ( unset -f echo ; "$@" ; )
    evaluate_retval
  else
    $SET_WCOL
    print_status warning running
  fi
}

killproc()
{
  if [ $# = 0 ] ; then
    echo "Usage: killproc {program} [signal]"
    exit 1
  fi

  if [ -z "$2" ] ; then
    signal=TERM
    fallback=KILL
  else
    signal=${2##-}
    signal=${signal##SIG}
    fallback=""
  fi

  getpids $1

  if [ -n "$pidlist" ] ; then
    failure=0
    for pid in $pidlist ; do
      kill -$signal $pid 2>/dev/null

      for ((i=0; $i<5000; i=$i+1)) ; do : ; done

      for ((i=0; $i<$KILLDELAY; i=$i+1)) ; do
        kill -0 $pid 2>/dev/null || break
        sleep 1
      done

      if [ -n "$fallback" ] ; then kill -$fallback $pid 2>/dev/null ; fi

      for ((i=0; $i<$KILLDELAY; i=$i+1)) ; do
        kill -0 $pid 2>/dev/null || break
        sleep 1
      done

      kill -0 $pid 2>/dev/null && failure=1
    done

    base=${1##*/}
    if [ $failure = 0 ] ; then rm -f /var/run/$base.pid ; fi

    (exit $failure)
    evaluate_retval
  else
    $SET_WCOL
    print_status warning not_running
    exit 0
  fi
}

reloadproc()
{
  if [ $# = 0 ] ; then
    echo "Usage: reloadproc {program} [signal]"
    exit 1
  fi

  if [ -z "$2" ] ; then
    signal=HUP
  else
    signal=${2##-}
    signal=${signal##SIG}

  fi

  getpids $1

  if [ -n "$pidlist" ] ; then
    failure=0

    for pid in $pidlist ; do
      kill -$signal $pid || failure=1
    done

    (exit $failure)
    evaluate_retval
  else
    $SET_WCOL
    print_status warning not_running
  fi
}

statusproc()
{
  if [ $# = 0 ] ; then
    echo "Usage: statusproc {program}"
    exit 1
  fi

  local base=${1##*/}
  getpids $1

  if [ -n "$pidlist" ] ; then
    echo "$base is running with Process ID(s) $pidlist"
  else
    if [ -s /var/run/$base.pid ] ; then
      echo "$1 is not running but /var/run/$base.pid exists"
      return 1
    else
      echo "$1 is not running"
    fi
  fi
}

required_executable()
{
  test -x $1 || {
    $FAILURE
    echo "Required program $1 doesn't appear to be installed"
    $NORMAL
    exit 5
  }
}

optional_executable()
{
  test -x $1 || {
    $WARNING
    echo "Optional program $1 doesn't appear to be installed"
    $NORMAL
    return 1
  }
  return 0
}

# End $rc_base/init.d/functions

