#!/bin/sh
#
# Usage:
#   timeout [-d] <MAXTIME> <SLEEPTIME> <COMMAND> [<OPT> ...]
#
# Descripton:
#   timeout was written to make sure a command will be stopped, if 
#   it exceeds a specified time limit.
#
#   timeout will start the command <COMMAND> with the options [<OPT> ...].
#   timeout makes sure that, if <COMMAND> runs longer than <MAXTIME> seconds,
#   it will be killed with signal -15. If this does not help signal -9 is used.
#   timeout checks if <COMMAND> is running every <SLEEPTIME> seconds.
#
# Debug:
#   In Debugmode <CHECKMSG> will be displayed each time the check is running.
#   When the <COMMAND> has ended within <MAXTIME> the string <OKAYMSG> is 
#   displayed. When the command has to be killed the string <KILLMSG>
#   will be displayed.
# 
# Example Test Calls:
#   timeout -d 10 2 sleep 5
#     Debug timeout:  calling: ./timeout -bg -d 30969 10 2 sleep 5
#     Debug timeout:  Checking for timeout
#     Debug timeout:  Checking for timeout
#     Debug timeout:  Checking for timeout
#     Debug timeout:  Command terminated normally
#
#   timeout -d 5 2 sleep 10
#     Debug timeout:  calling: ./timeout -bg -d 30887 5 2 sleep 10
#     Debug timeout:  Checking for timeout
#     Debug timeout:  Checking for timeout
#     Debug timeout:  Checking for timeout
#     Debug timeout:  Command expired and had to be killed
#     Terminated
# 

debug()
{
  [ "$DEBUG" ] && echo "Debug timeout:  $*" >&2
}

DEBUG=""
BACKGROUND=""
OPTS="1"
while [ "$OPTS" ]; do
  if [ "$1" = "-d" ]; then
    DEBUG="$1"
    shift
  elif [ "$1" = "-bg" ]; then
    BACKGROUND="$1"
    shift
  else
    OPTS=""
  fi
done

CHECKMSG="Checking for timeout"
OKAYMSG="Command terminated normally"
KILLMSG="Command expired and had to be killed"

if [ "$BACKGROUND" ]; then
  PIDP="$1"; MAXTIME="$2"; SLEEPTIME="$3"
  shift 3
  T=0; NINE=""; while :; do
    sleep $SLEEPTIME
    let T=T+$SLEEPTIME

    debug "$CHECKMSG"

    PID=`ps -f | awk '{print $2, $3}'` # -f is used to be compatible to HPUX
    PID=`echo "$PID"| grep "$PIDP$" | grep -v "^$$"| awk '{print $2}'`

    if [ ! "$PID" ]; then
      debug "$OKAYMSG"
      exit 0
    elif [ $T -ge $MAXTIME ]; then
      debug "$KILLMSG"
      kill $NINE $PID
      NINE="-9"
      sleep 3
      exit 0
    fi
  done
fi

if [ $# -lt 3 ]; then
  echo "usage: timeout <MAXTIME> <SLEEPTIME> <COMMAND> [<OPT> ...]"
  exit 1
fi

debug "calling: $0 -bg $DEBUG $$ $@"
$0 -bg $DEBUG "$$" "$@" &
shift 2
"$@" 
