#!/bin/bash
#
# $Id: testdhcp,v 1.13 2004/02/21 09:42:45 andrew Exp $
#
# by Andrew McMillan, Catalyst IT Ltd, (c) 2001 licensed
# for use under the GPL version 2
#
# This script tests whether we are at a specific DHCP-assigned IP address.
# DHCP IP address assignment should be done if it hasn't already.
#
###############################################
# NOTE:  This script is something of a work in progress.  I can't have experience
# with all possible DHCP clients, so if you need help getting it working with what
# you happen to use, feel free to call upon me.
###############################################
#
# Parameters: [<interface>,](start|stop|restart|<IP address pattern>)
#
# <interface> 	Interface to test.  If omitted, use INTERFACE variable (from detect.conf)
#
# start        	Start dhcp client (use before testing IP address).
# stop		Stop dhcp client (use when you do not want to leave the client running)
# restart       Restart dhcp client
# <IP address>  IP address to test for.  You may use bash pattern matching
#		characters for subnet testing.
#
# Environment variables:
#
# INTERFACE	Default interface name to use if not specified
# DEBUGWHEREAMI Turn on debugging output (0 for debug msgs, 1 for execution tracing)
# PUMPPATH	Path to pump
# DHCLIENTPATH  Path to dhclient
# DHCPCDPATH    Path to dhcpcd
# DHCPMETHOD    Which dhcpclient method to use (pump, dhclient, dhclient3 or dhcpcd).  
#		If unspecified, it will be automatically selected
# 
# Examples:
#     testdhcp eth1,192.168.3.7
#     testdhcp 192.168.3.*
#     testdhcp 10.*
#     testdhcp 192.168.1.[01][0-9]

STATEDIR=${STATEDIR:-"/var/lib/whereami"}
WHEREAMILOCK=$LOCKDIR/whereami.started
PUMPPATH=${PUMPPATH:-/sbin/pump}
DHCLIENTPATH=${DHCLIENTPATH:-/sbin/dhclient}
DHCLIENT=`basename $DHCLIENTPATH`
DHCPCDPATH=${DHCPCDPATH:-/sbin/dhcpcd}

debug()
{
    [ -n "$DEBUGWHEREAMI" ] && echo $@
}

# Run DHCP action - pump
# pump <command>
pump()
{
    # We prefer this one at the moment, and it is the Debian (and RH) default
    # Also consider: It might be advisable to set a timeout in your /etc/pump.conf

    STATEFILE=$STATEDIR/dhclient.$INTERFACE
    case $1 in
      start)
	# Prod the DHCP server for a new address
	$PUMPPATH --interface $INTERFACE
	# Get the status into a file.
	if ! $PUMPPATH --interface $INTERFACE --status >$STATEFILE; then
	  # OK, looks like it's got it's knickers knotted and we need to nuke it and try again..
	  killall $PUMPPATH
	  sleep 1
	  $PUMPPATH --interface $INTERFACE
	  $PUMPPATH --interface $INTERFACE --status >$STATEFILE
	fi
	;;
      stop)
        killall $PUMPPATH
	;;
      test)
	if [ ! -s $STATEFILE -o ! -f $WHEREAMILOCK -o $STATEFILE -ot $WHEREAMILOCK ]; then
	  echo testdhcp: pump was not started
	  return 1
	fi
        DHCP_ADDRESS=`grep "IP: " $STATEFILE | tr -d " " | cut -f2 -d:`
	;;
    esac
}

dhclient()
{
    # ISC dhcp version 2.
    # Use the -e flag to make sure that dhclient only runs in the background if it
    # has a lease.  Thus we know if we see dhclient in the background, that the
    # interface has got an IP address from a DHCP server.
    # Also consider: It might be advisable to set a timeout in your /etc/dhclient.conf

    STATEFILE=$STATEDIR/dhclient.$INTERFACE
    [ -z "$DEBUGWHEREAMI" ] && QUIETFLAG=-q
    case $1 in
      start)
	if $DHCLIENTPATH $QUIETFLAG -e $INTERFACE; then
	  # dhclient started and got a lease
	  return 0
        else
	  # no address - disable interface
	  ifconfig $INTERFACE down
	  return 1
	fi
	;;
      stop)
	dhcli_pid="`ps ax | grep $DHCLIENT | grep $INTERFACE | cut -c-5`"
	[ -n "$dhcli_pid" ] && kill $dhcli_pid
	ifconfig $INTERFACE down
	rm -f $STATEFILE
	;;

      test)
	# if dhclient is running, we have an IP address
	if ps ax | grep $DHCLIENT | grep -q $INTERFACE ; then
	  DHCP_ADDRESS="`/sbin/ifconfig $INTERFACE | head -2 | tail -1 | cut -d: -f2 | cut -d\  -f1`"
	  [ -n "$DHCP_ADDRESS" ] && return 0 || return 1
	else
	  return 1
	fi
	;;
    esac
}

dhclient3()
{
    # ISC dhcp version 3.
    # We drop a file in /etc/dhcp3/dhclient-exit-hooks.d/whereami, that
    # saves the DHCP state in /var/run/whereami/dhclient3.<interface>.
    # We also call whereami with --hint dhclient3 on state changes, so
    # we only need to look at the dhclient state

    # we know if we see dhclient in the background, that the
    # interface has got an IP address from a DHCP server.
    # Also consider: It might be advisable to set a timeout in your /etc/dhclient.conf

    STATEFILE=$STATEDIR/dhclient3.$INTERFACE
    [ -z "$DEBUGWHEREAMI" ] && QUIETFLAG=-q

    case $1 in
      start)
        $DHCLIENTPATH $QUIETFLAG $INTERFACE
      ;;

      stop)
        dhcli_pid="`ps ax | grep $DHCLIENT | grep $INTERFACE | cut -c-5`"
        [ -n "$dhcli_pid" ] && kill $dhcli_pid
        ifconfig $INTERFACE down
        rm -f $STATEFILE
      ;;
      
      test)
        DHCP_ADDRESS="`grep new_ip_address= $STATEFILE | cut -f2 -d=`"
        [ -n "$DHCP_ADDRESS" ]
      ;;
    esac
}

dhcpcd()
{

    INFOFILE="/var/lib/dhcpc/dhcpcd-$INTERFACE.info"
    PIDFILE="/var/run/dhcpcd-$INTERFACE.pid"
    case $1 in
      start)
	# Prod the DHCP server for a new address
	if $DHCPCDPATH -n "$INTERFACE"; then
	  # dhcpcd started and got a lease
	  return 0
        else
	  # no address - clear interface
	  ifconfig "$INTERFACE" 0.0.0.0
	  return 1
	fi
	;;
      stop)
        if [ -s "$PIDFILE" ] && kill -0 "`cat "$PIDFILE"`" ;then
          $DHCPCDPATH -k "$INTERFACE" > /dev/null
	fi
	;;
      test)
	if [ ! -s "$INFOFILE" -o ! -s "$PIDFILE" ]; then
	  debug testdhcp: dhcpcd was not started
	  return 1
	fi
        DHCP_ADDRESS="`grep '^IPADDR=' $INFOFILE| cut -f2 -d=`"
	;;
    esac
      
}


# Turn on execution tracing, for debugging...
[ "$DEBUGWHEREAMI" = "1" ] && set -o xtrace

case $1 in
  *,*)
    INTERFACE=${1/,*}
    IP_ADDRESS=${1/*,}
    ;;
  *)
    # Use INTERFACE variable; default to eth0 if not set
    INTERFACE=${INTERFACE:-eth0}
    IP_ADDRESS="$1"
    ;;
esac

mkdir -p $STATEDIR

if [ -z "$DHCPMETHOD" ]; then
  if [ -x "$PUMPPATH" ]; then
    DHCPMETHOD=pump
  elif [ -x "$DHCLIENTPATH" ]; then
     $DHCLIENTPATH --version 2>&1 | grep -i -q "DHCP Client V3\|dhclient-V3" &&
        DHCPMETHOD=dhclient3 || DHCPMETHOD=dhclient
  elif [ -x "$DHCPCDPATH" ]; then
     DHCPMETHOD=dhcpcd
  else
    logger -p user.error -t whereami -i "testdhcp: No suitable DHCP client found!"
    debug "testdhcp: No suitable DHCP client found!"
    exit 1
  fi
fi

case $IP_ADDRESS in
  '*.*.*.*')
    ACTION=restart
    ;;
  start|stop|restart)
    ACTION=$IP_ADDRESS
    ;;
  *)
    ACTION=test
    ;;
esac

debug testdhcp method:$DHCPMETHOD interface:$INTERFACE action:$ACTION IP:$IP_ADDRESS

if [ $ACTION = restart ];then
  $DHCPMETHOD stop
  $DHCPMETHOD start
else
  $DHCPMETHOD $ACTION
fi
STATUS=$?

if [ $ACTION = test -a $STATUS = 0 ] ;then
    # echo "DHCP=$DHCP_ADDRESS"
    [ "${DHCP_ADDRESS/#$IP_ADDRESS/FOUND}" = "FOUND" ] && exit 0
    # echo "Sorry $IP_ADDRESS not found"
    exit 2
fi

exit $STATUS
