#!/bin/sh

# Copyright (C)2011 Laurence Tratt <http://tratt.net/laurie/>
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
# 
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.


main_server=echo.tratt.net
backup_server=reverb.tratt.net

function die {
    echo $1 >&2
    exit $2
}


ae=0
minimal=0
while getopts "m" f
do
    case "$f" in
        m)   minimal=1;;
        [?]) ae=1; break;;
    esac
done

if [ $ae -gt 0 ]; then
    die "Usage: zonerw [-m]" 1
fi

function is_host_down {
    ftp -o /dev/null http://$1/ > /dev/null 2> /dev/null
    if [ $? -ne 0 ]; then
        sleep 10
        ftp -o /dev/null http://$1/ > /dev/null 2> /dev/null
        if [ $? -ne 0 ]; then
            return 1
        fi
    fi
    return 0
}

is_host_down $main_server
if [ $? -eq 0 ]; then
    server=$main_server
else
    server=$backup_server
fi

i=3
while [ 1 ]; do
    ip=`host $server \
      | grep "has address" \
      | sed -E "s/^.*has address ([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}).*/\1/g"`
    if [[ $? -eq 0 && $ip != "" ]]; then
        break
    fi
    
    sleep 3
    i=$(($i - 1))
    if [ $i -eq 0 ]; then
        die "Can't find IP address for $server" 1
    fi
done

for zoneinp in `ls $HOME/var/nsd/zones/*.base`; do
    zonename=`cat $zoneinp | grep "\$ORIGIN" | head -n 1 | sed -E "s/[$]ORIGIN //g"`
    zoneoutp=/var/nsd/zones/`basename $zoneinp | sed -E "s/\.base//g"`
    if [ -f $zoneoutp ]; then
        if [ $minimal -eq 1 ]; then
            # In minimal mode, we don't update records unless the IP address
            # we're rewriting to has changed.
            oldip=`cat $zoneoutp | grep "@IP@" | head -n 1 \
              | sed -E "s/.* ([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}).*@IP@.*/\1/g"`
            if [[ $? -ne 0 || $oldip == "" ]]; then
                die "Can't find IP address for $server" 1
            fi
            if [ $oldip == $ip ]; then
                continue
            fi
        fi
    
        oldserial=`cat $zoneoutp | grep "@serial number@" \
          | sed -E "s/ *([0-9]+).*@serial number@.*/\1/g"` \
          || die "Can't parse old serial number" $?
        dateserial=`echo $oldserial | sed -E "s/([0-9]{8})[0-9]{2}/\1/g"` \
          || die "Can't parse old serial number" $?
        incserial=`echo $oldserial | sed -E "s/[0-9]{8}([0-9]{2})/\1/g"` \
          || die "Can't parse old serial number" $?
        # Strip leading zeros which confuse the shell arithmetic (which aren't
        # sure if they're octal numbers or not).
        incserial=`echo $incserial | sed -E "s/^0//g"`
        if [ $dateserial != `date +%Y%m%d` ]; then
            # If the old serial number was for a different day, start a new
            # serial number.
            serial=`date +%Y%m%d`01
        else
            if [ $incserial == "99" ]; then
                die "Serial number limit of 99 exceeded for today" 1
            fi
            serial=`date +%Y%m%d``printf %.2d $(($incserial+1))`
        fi
    else
        serial=`date +%Y%m%d`01
    fi
    t=`mktemp` || exit $?
    cat $zoneinp \
      | sed -E "s/( *)0000000000(.*)(@serial number@.*)/\1$serial\2\3/g ; s/(.*)0\.0\.0\.0(.*@IP@.*)/\1$ip\2/g" \
      > $t
    e=$?
    if [ $e -ne 0 ]; then
        rm $t
        exit $e
    fi

    mv -f $t $zoneoutp || die "Can't move $t to $zoneoutp" 1
done

supuner sudo /usr/sbin/nsdc -c /home/ltratt/etc/nsd.conf.reverb rebuild || exit $?
sudo /usr/sbin/nsdc -c /home/ltratt/etc/nsd.conf.reverb running \
  2> /dev/null > /dev/null
if [ $? -eq 0 ]; then
    supuner sudo /usr/sbin/nsdc -c /home/ltratt/etc/nsd.conf.reverb reload \
      || exit $?
else
    supuner sudo /usr/sbin/nsdc -c /home/ltratt/etc/nsd.conf.reverb start || exit $?
fi
