#!/bin/bash
# vim:set ft=sh sw=2 noet:

# 20230809 PeterG <pg_freesw {at} freesw.for.sabi.co.UK> 

printenv > /tmp/dhc

RTO_MIN='5ms'

if true
then
  disp() { case "$1" in ?*) printf "$2\n" "$1";; esac; }

: '				      	| text aligned to here'
  case "$reason" in
  'PREINIT') 
    disp "$reason"		       'reason			"%s"';;

  'BOUND'|'RENEW'|'REBIND'|'REBOOT')
    disp "$reason"		       'reason			"%s"'
    disp "$interface"		       'interface		"%s"'
    disp "$new_interface_mtu"	       'new_interface_mtu	"%s"'

    disp "$new_ip_address"	       'new_ip_address		"%s"'
    disp "$new_network_number"	       'new_network_number	"%s"'
    disp "$new_subnet_mask"	       'new_subnet_mask		"%s"'
    disp "$new_broadcast_address"      'new_broadcast_address	"%s"'
    disp "$alias_ip_address"	       'alias_ip_address	"%s"'
    disp "$alias_subnet_mask"	       'alias_subnet_mask	"%s"'

    disp "$old_ip_address"	       'old_ip_address		"%s"'
    disp "$old_network_number"	       'old_network_number	"%s"'
    disp "$old_broadcast_address"      'old_broadcast_address	"%s"'
    disp "$old_subnet_mask"	       'old_subnet_mask		"%s"'

    disp "$old_routers"		       'old_routers		"%s"'

    disp "$old_domain_name"	       'old_domain_name		"%s"'
    disp "$old_domain_name_servers"    'old_domain_name_servers	"%s"'

    disp "$METRIC"		       'METRIC			"%s"'
    disp "$GATEWAY"		       'GATEWAY			"%s"'
    disp "$GATEWAYDEV"		       'GATEWAYDEV		"%s"'
    disp "$DHCLIENT_IGNORE_GATEWAY"    'DHCLIENT_IGNORE_GATEWAY	"%s"'
    disp "$new_routers"		       'new_routers		"%s"'
    disp "$new_static_routes"	       'new_static_routes	"%s"'

    disp "$new_host_name"	       'new_host_name		"%s"'
    disp "$new_domain_name"	       'new_domain_name		"%s"'
    disp "$new_domain_name_servers"    'new_domain_name_servers	"%s"'

    disp "$PEERNIS"		       'PEERNIS			"%s"'
    disp "$new_nis_domain"	       'new_nis_domain		"%s"'
    disp "$new_nis_servers"	       'new_nis_servers		"%s"'

    disp "$PEERNTP"		       'PEERNTP			"%s"'
    disp "$new_ntp_servers"	       'new_ntp_servers		"%s"'
    disp "$new_time_offset"	       'new_time_offset		"%s"'
    disp "$DHCP_TIME_OFFSET_SETS_TIMEZONE" 'DHCP_TIME_OFFSET_SETS_TIMEZONE	"%s"'

    disp "$DHCLIENT_DELAY"	       'DHCLIENT_DELAY		"%s"';;

  'EXPIRE'|'FAIL'|'RELEASE'|'STOP')
    disp "$reason"		       'reason			"%s"'
    disp "$interface"		       'interface		"%s"'

    disp "$old_ip_address"	       'old_ip_address		"%s"'
    disp "$old_network_number"	       'old_network_number	"%s"'
    disp "$old_broadcast_address"      'old_broadcast_address	"%s"'
    disp "$old_subnet_mask"	       'old_subnet_mask		"%s"'

    disp "$old_routers"		       'old_routers		"%s"'

    disp "$old_domain_name"	       'old_domain_name		"%s"'
    disp "$old_domain_name_servers"    'old_domain_name_servers	"%s"';;
  esac
fi

: 'The things that this script sets are:

  * primary interface mtu, address, subnet, netmask, broadcast
  * secondary interface address, netmask
  * default route gateway, metric, device

  * /etc/localtime
  * /etc/ntp.conf
  * /etc/resolv.conf
  * /etc/yp.conf

  It also runs:

  * /etc/dhclient-${interface}-up-hooks or /etc/dhclient-up-hooks
  * /etc/dhclient-${interface}-down-hooks or /etc/dhclient-down-hooks
'

: '/etc/localtime:	$new_time_offset'
: '/etc/ntp.conf:	$new_ntp_servers'
: '/etc/resolv.conf	$new_domain_name, $new_domain_name_servers'
: '/etc/yp.conf:	$new_nis_name, $new_nis_servers'

ip_dotted_decimal()
{
  B3="`expr "$1" : '\([0-9]*\)\.[0-9]*\.[0-9]*\.[0-9]*'`"
  B2="`expr "$1" : '[0-9]*\.\([0-9]*\)\.[0-9]*\.[0-9]*'`"
  B1="`expr "$1" : '[0-9]*\.[0-9]*\.\([0-9]*\)\.[0-9]*'`"
  B0="`expr "$1" : '[0-9]*\.[0-9]*\.[0-9]*\.\([0-9]*\)'`"

  echo "`expr $B0 + $B1 \* 256 + $B2 \* 65536 + $B3 \* 16777216`"
}

previous_push()
{
  F="$1"
  N=0

  while
    S=`printf '_%03d' "$N"`
    test -e "$F$S"
  do N=`expr "$N" + 1`
  done

  if mv "$F" "$F$S"
  then
    cp "$F$S" "$F"
    echo "$F$S"
  fi
}

previous_pop()
{
  F="$1"
  N=0

  while
    S=`printf '_%03d' "$N"`
    test -e "$F$S"
  do N=`expr "$N" + 1`
  done

  case "$N" in
  '0') : ;;
  *)
    N=`expr "$N" - 1`
    S=`printf '_%03d' "$N"`
    mv "$F$S" "$F";;
  esac
}

if ! test -x /bin/ipcalc
then
  old_subnet_prfx="$old_subnet_mask"
  new_subnet_prfx="$new_subnet_mask"
else
  case "$old_ip_address;$old_subnet_mask" in ?*';'?*)
    old_subnet_prfx=`/bin/ipcalc -p "$old_ip_address" "$old_subnet_mask"`
    old_subnet_prfx=`expr "$old_subnet_prfx" : 'PREFIX=\([0-9]*\)'`;;
  esac

  case "$new_ip_address;$new_subnet_mask" in ?*';'?*)
    new_subnet_prfx=`/bin/ipcalc -p "$new_ip_address" "$new_subnet_mask"`
    new_subnet_prfx=`expr "$new_subnet_prfx" : 'PREFIX=\([0-9]*\)'`;;
  esac
fi

LOGF='local7'
TSTAMP="`date -R`"

k_release=$(uname -r)
k_relmaj=$(echo $release | cut -f1 -d'.')
k_relmin=$(echo $release | cut -f2 -d'.')

case "$new_ip_address" in ?*)
  new_ip_address_d=`ip_dotted_decimal "$new_ip_address"`
  new_ip_address_x=`printf "%08x" "$new_ip_address_d"`;;
esac

case "$new_interface_mtu" in
?*)	new_mtu="$new_interface_mtu";;
'')
	case "$interface" in
	'w'*)	new_mtu='576';;
	*)	new_mtu='1472';;
	esac;;
esac

case "$reason" in
'PREINIT')
  : 'DHCP start preparation'

  case "$DHCLIENT_DELAY" in ?*) sleep "$DHCLIENT_DELAY";; esac;;

'ARPCHECK'|'ARPSEND')
  : 'DHCP check ARP'
  case "$interface#$new_ip_address" in ?*'#'?*) 
    arping -q -f -c 2 -w 3 -D -I ${interface} ${new_ip_address};;
  esac;;

'BOUND'|'RENEW'|'REBIND'|'REBOOT')

  case "$new_mtu" in ?*)
    ip link set mtu "$new_mtu" dev "$interface";;
  esac

  case "$old_routers" in
  "$new_routers") : 'No change';;
  ?*)
    for old_router in $old_routers
    do ip route delete 0/0 via "$old_router"
    done;;
  esac

  case "$old_network_number" in
  '') old_address_prfx='32';;
  ?*) old_address_prfx="$old_subnet_prfx";;
  esac

  case "$old_ip_address" in
  "$new_ip_address") : 'No change';;
  ?*)
    ip address delete "$old_ip_address"/"$old_address_prfx" \
      dev "$interface";;
  esac

  case "$new_network_number" in
  '') new_address_prfx='32';;
  ?*) new_address_prfx="$new_subnet_prfx";;
  esac

  case "$new_ip_address" in ?*)
    ip address add "$new_ip_address"/"$new_address_prfx" \
      dev "$interface";;
  esac

  case "$new_routers" in
  ?*)
    for new_router in $new_routers
    do
      case "$METRIC" in
      '') ip route add 0/0 via "$new_router" rto_min "$RTO_MIN";;
      ?*) ip route add 0/0 via "$new_router" rto_min "$RTO_MIN" metric "$METRIC";;
      esac
    done;;
  esac

  case "$new_host_name" in ?*)
    hostname "$new_host_name"
    if test -f '/etc/sysconfig/network'
    then
      PREVIOUS="`previous_push '/etc/sysconfig/network'`"
      echo "# dhclient-script $TSTAMP
NETWORKING=yes
HOSTNAME=$new_host_name" > '/etc/sysconfig/network'
    elif test -f '/etc/hostname'
    then
      PREVIOUS="`previous_push '/etc/hostname'`"
      echo "$new_host_name" > '/etc/hostname'
    fi;;
  esac

  case "$PEERDNS" in ''|[Yy]*)
    case "$reason;$new_domain_name;$new_domain_name_servers" in
    "RENEW;$old_domain_name;$old_domain_name_servers") : ;;

    *';'?*';'?*) 
      PREVIOUS="`previous_push '/etc/resolv.conf'`"
      (
	echo "; dhclient-script $TSTAMP"
	echo "options no-check-names attempts:3 timeout:4 ndots:1"
	echo "search $new_domain_name"
	for new_domain_name_server in $new_domain_name_servers
	do echo "nameserver $new_domain_name_server"
	done
      ) > '/etc/resolv.conf'
      chmod a+r '/etc/resolv.conf'

      : service nscd condrestart
    esac;;
  esac

  case "$PEERNTP" in ''|[Yy]*)
    case "reason;$new_ntp_servers" in
    "RENEW;$old_ntp_servers") : ;;

    *';'?*) 
      PREVIOUS="`previous_push '/etc/ntp.conf'`"
      (
	echo "# dhclient-script $TSTAMP"
	for new_ntp_server in $new_ntp_servers
	do echo "server $new_ntp_server"
	done

	if test -n "$PREVIOUS" -a -e "$PREVIOUS"
	then
	  echo "
# dhclient-script previous content follows
"
	  cat "$PREVIOUS"
	else
	  echo "
restrict default 	kod nomodify notrap nopeer noquery
restrict -6 default 	kod nomodify notrap nopeer noquery

restrict		127.0.0.1
restrict -6 		::1

driftfile		/var/etc/ntp/ntp.drift
statsdir		/var/log/ntpstats/

statistics		loopstats peerstats clockstats
filegen			loopstats file loopstats type day enable
filegen			peerstats file peerstats type day enable
filegen			clockstats file clockstats type day enable

enable			kernel monitor ntp stats
disable			auth bclient"
	fi
      ) > '/etc/ntp.conf'

      service ntpd condrestart
    esac;;
  esac

  case "$DHCP_TIME_OFFSET_SETS_TIMEZONE" in ''|[Yy]*)
    case "$reason;$new_time_offset" in
    "RENEW;$old_time_offset") : ;;

    *';'?*) 
      PREVIOUS="`previous_push '/etc/localtime'`"
      (
	new_hours_offset="`expr $new_time_offset / 3600`"
	case "$new_hours_offset" in [0-9]*)
	  new_hours_offset="+$new_hours_offset";;
	esac
	cat "/usr/share/zoneinfo/Etc/GMT$new_hours_offset"
      ) > '/etc/localtime'
      chmod a+r '/etc/localtime'
    esac;;
  esac
  ;;

'TIMEOUT')
  : 'DHCP timeout';;

'EXPIRE'|'FAIL'|'RELEASE'|'STOP')
  if test -f '/etc/sysconfig/network'
  then
    previous_pop '/etc/sysconfig/network'
    . /etc/sysconfig/network
  elif test -f '/etc/hostname'
  then
    previous_pop '/etc/hostname'
    HOSTNAME="`cat '/etc/hostname'`"
  fi
  case "$HOSTNAME" in ?*) hostname "$HOSTNAME";; esac

  case "$PEERDNS" in ''|[Yy]*)
    previous_pop '/etc/resolv.conf';;
  esac

  case "$PEERNTP" in ''|[Yy]*)
    previous_pop '/etc/ntp.conf';;
  esac

  case "$DHCP_TIME_OFFSET_SETS_TIMEZONE" in ''|[Yy]*)
    previous_pop '/etc/localtime';;
  esac

  case "$old_routers" in ?*)
    for old_router in $old_routers
    do ip route delete 0/0 via "$old_router"
    done;;
  esac

  case "$old_network_number" in
  '') old_address_prfx='32';;
  ?*) old_address_prfx="$old_subnet_prfx";;
  esac

  case "$old_ip_address" in ?*)
    ip address delete "$old_ip_address"/"$old_address_prfx" \
      dev "$interface";;
  esac;;
esac

exit $?
