#!/bin/bash
#
# $Id: testdhcp,v 1.16 2005/09/18 10:37:24 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 [try to] be automatically selected
# 
# Examples:
#     testdhcp eth1,192.168.3.7
#     testdhcp 192.168.3.*
#     testdhcp 10.*
#     testdhcp 192.168.1.[01][0-9]
#

[ -n "$DEBUGWHEREAMI" ] && set -o xtrace

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 -1 $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
