#!/bin/bash

# Wrapper program, mainly for cleaning up after netscape leaves lock and core
# files. But it can be used to wrap any program.

# Functionality: when this script receives a signal 1, 2, 3 or 15; it will
# send that signal and then signals 1, 2, 3, 15 and 9 (except for the signal
# sent first) at 3 second intervals to the wrapped program, until it dies.
# Then it will clean up a lock file, if required, and a core file, if required
# -- see below.

# Author: John Latham, Dept. of Computer Science, University of Manchester, UK.
# Email jtl@cs.man.ac.uk

# Time-stamp: <September 23, 1999 00:54 jtl@todd.jtl>

# Usage: place this in a directory anywhere earlier in the PATH than the
# program you want it to wrap, and give it the same name. /usr/local/bin is an
# obvious place. Any other programs you also want it to wrap can simply each
# have a link to this file, of the same name as the wrapped program. This
# wrapper should find the real program to wrap from $0 and by manipulating
# $PATH to temporarily remove the place where this wrapper is put. The wrapped
# program must appear on the PATH, and no other copy of the wrapper may appear
# in the PATH (that would lead to recursive calls!)

# Set $TraceActions to True if you want this wrapper to report what it is
# doing to Standard output (if that is a tty) and also to the file $TraceFile
# (if that variable is not empty)
# This is set via $DefaultTraceActions, possibly overrriden by the environment
# variable $WRAPPER_TRACE

#DefaultTraceActions=True
DefaultTraceActions=False
TraceActions=${WRAPPER_TRACE:-$DefaultTraceActions}

# Set $DefaultTraceFile to the default name of the file you want this wrapper
# to trace actions to (if $TraceActions is True). This is in addition to traces
# being written on standard output (if it is a tty). The value of $TraceFile is
# set to $DefaultTraceFile, unless the environment variable $WRAPPER_TRACE_FILE
# is set; in which case that value is used. If $TraceFile is empty, then there
# will be no tracing to a file.

#DefaultTraceFile=`tty`
#DefaultTraceFile=/dev/console
DefaultTraceFile=""
TraceFile=${WRAPPER_TRACE_FILE:-$DefaultTraceFile}

# Set $TestForLockFile to be some test for the existence of a file (e.g. a
# lock file) which should be removed on exit; iff it was not existing on entry.
# This is ignored if it is empty.
# Set $RemoveLockFile to be a command which will remove the above file.
# Set $TestForCoreFile to be a test for a core file which must be removed on
# exit (even if it was there on entry). Ignored if empty.
# Set $RemoveCoreFile to be a command that removes the above core file.

case $0
in
  *netscape*) TestForLockFile="test -L $HOME/.netscape/lock"
              RemoveLockFile="rm -f $HOME/.netscape/lock"
              TestForCoreFile="strings core 2>&1|grep netscape > /dev/null"
              RemoveCoreFile="rm -f core" ;;
  *) TestForLockFile=""
     TestForCoreFile="" ;;
esac


function trace_action()
{
  if test "$TraceActions" = True
  then
    if test "$TraceFile" != ""
    then
      echo `/bin/date`:`hostname`:$USER:$0 $1 >> $TraceFile
    fi
    test -t 1 && echo $1
  fi
}


function error_report()
{
 test -t 2 && echo $1 >&2
}


function check_lock()
{
  if test "$LockToBeRemoved" = True
  then
#    $TestForLockFile && sleep 1
    if $TestForLockFile
    then
      trace_action "$ChildProgram left the lock file (now removed)"
      $RemoveLockFile
    else
      trace_action "$ChildProgram removed the lock file"
    fi
  fi
}


function check_core()
{
  if test "$TestForCoreFile" != ""
  then
    if eval $TestForCoreFile
    then
      trace_action "$ChildProgram left a core file (now removed)"
      $RemoveCoreFile
    else
      trace_action "$ChildProgram did not leave a core file"
    fi
  fi
}


function terminate()
{
  trap - $1

  trace_action "Received signal $1"
  trace_action "Sending signal $1 to $ChildProgram($ChildPid)"
  kill -$1 $ChildPid

  for Count in 1 2 3
  do
    test "`ps $ChildPid 2>&1 |grep $ChildPid`" != "" && sleep 1
  done

  for Signal in 1 2 3 15 9
  do
    if test $Signal != $1
    then
      test "`ps $ChildPid 2>&1 |grep $ChildPid`" != "" && sleep 1
      if test "`ps $ChildPid 2>&1 |grep $ChildPid`" != ""
      then
        trace_action "Sending signal $Signal to $ChildProgram($ChildPid)"
        kill -$Signal $ChildPid
      fi
    fi
  done

  check_lock
  check_core

  exit `expr 128 + $1`
}


trap "terminate 1" 1
trap "terminate 2" 2
trap "terminate 3" 3
trap "terminate 15" 15

case $TestForLockFile
in
  "") LockToBeRemoved=False ;;
  *)  LockToBeRemoved=True
      $TestForLockFile && LockToBeRemoved=False ;;
esac

case $0
in
 .*|/*) ThisProgramPath=$0 ;;
 *) ThisProgramPath=`which $0` ;;
esac

ThisDirectory=`dirname $ThisProgramPath`
ThisProgramName=`basename $ThisProgramPath`

OldPath=$PATH
RemovePattern=`echo $ThisDirectory | sed "s|\.|\\\\\.|g"`

export PATH=`echo $PATH | sed "s|:$RemovePattern:|:|g" \
                        | sed "s|^$RemovePattern:||g" \
                        | sed "s|:$RemovePattern\$||g"`
ChildProgram=`which $ThisProgramName` 2>/dev/null
case $ChildProgram
in
 *no" "*" "in*) ChildProgram="" ;;
esac

export PATH=$OldPath

if test "$ChildProgram" = ""
then
   error_report "Cannot find $ThisProgramName from wrapper"
else
  $ChildProgram $* &
  ChildPid=$!

  wait $ChildPid
  NormalExitStatus=$?

  check_lock
  check_core

  exit $NormalExitStatus
fi
