#!/bin/sh
#
# Copyright (c) 2000-2017 University of Utah and the Flux Group.
# 
# {{{EMULAB-LICENSE
# 
# This file is part of the Emulab network testbed software.
# 
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
# 
# This file is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public
# License for more details.
# 
# You should have received a copy of the GNU Affero General Public License
# along with this file.  If not, see <http://www.gnu.org/licenses/>.
# 
# }}}
#
. /etc/emulab/paths.sh

update_emulab_state() {
    #
    # Remember our server IP, real hostname, router IP, etc.
    #
    echo $new_dhcp_server_identifier > $BOOTDIR/bossip
    echo $new_host_name > $BOOTDIR/realname
    echo $new_routers > $BOOTDIR/routerip
    echo $new_ip_address > $BOOTDIR/myip
    echo $new_subnet_mask > $BOOTDIR/mynetmask
    echo $new_domain_name > $BOOTDIR/mydomain
    if [ -n "$interface" ]; then
	echo $interface > $BOOTDIR/controlif
    fi

    #
    # For Xen-based vnodes we record the vnode name where the scripts expect it.
    # XXX this works because only Xen-based vnodes DHCP.
    #
    case "$new_host_name" in
	pcvm*)
	    echo $new_host_name > $BOOTDIR/vmname
	    ;;
    esac   

    #
    # If this is a newnode boot, boss (inner or outer) will have returned with
    # no hostname.  We don't need to record anything in this case, so skip it.
    #
    if [ x"$new_host_name" = x ]; then
	return
    fi

    #
    # We have observed problems where changing the speed/duplex of a link
    # leaves DNS a little wonky.  So we whack on it til it responds so that
    # the sethostname script won't fail.
    #
    if [ "$new_network_number" = "10.200.1.0" ]; then
	for i in 0 1 2; do
            if `$BINDIR/tmcc bossinfo >/dev/null 2>&1`; then
		break
	    fi
            echo "`date`: ${interface}: waiting for DNS.." >>$LOGDIR/dhclient-exit.log 2>&1
            sleep $i
	done
    fi

    #
    # resolvconf on Linux also breaks DNS momentarily via dhclient exit
    # hook, or something.  On Ubuntu 16, resolvconf is setup to run via
    # dhclient enter hook (the hook redefines make_resolv_conf, which
    # dhclient-script eventually executes prior to the exit hook execution).
    # For whatever reason, though, sometimes when our exit hook (this
    # script) runs, /etc/resolv.conf is a dangling symlink.  I was not able
    # to find the source of the asynch behavior, so I can't say for sure.
    # But sethostname.dhclient is an immediate casualty, because it calls
    # tmcc bossinfo(), and the tmcc binary attempts to use res_init and read
    # the resolver and use that as boss.  If there is no /etc/resolv.conf
    # (or it is a broken symlink into /run, as it is on resolvconf systems
    # before resolvconf runs for the first time on boot), res_init will
    # return localhost, and there is no way for us in tmcc to know that is
    # inappropriate (taking the res_init resolver might not be the best
    # choice, but we do not dare to add a special-case rejection of
    # localhost in tmcc... you never know what crazy proxy schemes might
    # arise in the future).
    #
    if [ -x /sbin/resolvconf ]; then
	rcwaittime=0
	while [ ! -f `readlink -f /etc/resolv.conf` -a $rcwaittime -lt 5 ]; do
            echo "`date`: waiting for /etc/resolv.conf to exist..." >>$LOGDIR/dhclient-exit.log 2>&1
            sleep 1
            rcwaittime=`expr $rcwaittime + 1`
	done
	if [ ! -f `readlink -f /etc/resolv.conf` ]; then
            echo "*** WARNING: /etc/resolv.conf does not exist; this will likely cause problems!" >>$LOGDIR/dhclient-exit.log 2>&1
	fi
    fi

    #
    # See if the Testbed configuration software wants to change the hostname.
    #
    $BINDIR/sethostname.dhclient >>$LOGDIR/dhclient.log 2>&1

    #
    # Let the ifup-wait-emulab-cnet.service systemd service know that
    # the control net is up.
    #
    touch /var/run/cnet
}

echo "`date`: ${interface}: ${reason}" >>$LOGDIR/dhclient-exit.log 2>&1

#
# Only update our state for an up interface in the right protocol state.
#
if [ ! $if_up ]
then
    # do nothing if the interface isn't coming up
    echo "`date`: ${interface}: ${reason}: interface not up, ignoring" >>$LOGDIR/dhclient-exit.log 2>&1
    true
elif [ x$reason != xREBOOT -a x$reason != xBOUND -a x$reason != xRENEW -a x$reason != xREBIND ]
then
    # do nothing
    echo "`date`: ${interface}: ${reason}: ignoring" >>$LOGDIR/dhclient-enter.log 2>&1
    true
else
    update_emulab_state
fi

echo "`date`: ${interface}: ${reason}: done" >>$LOGDIR/dhclient-exit.log 2>&1
