#!/bin/bash
# Need bash because we use ${foo//bar/baz}
#
# Script to update the named options file
#
# Resolvconf may run us even if named is not running.
# If a bind package is installed then we go ahead and update
# the named configuration in case named is started later.
#
# Assumption: On entry, PWD contains the resolv.conf-type files
#
# Licensed under the GNU GPL.  See /usr/share/common-licenses/GPL.
#
# History
# June 2003 - June 2004: Written by Thomas Hood <jdthood@yahoo.co.uk>

set -e
PATH=/bin:/sbin

[ -x /usr/sbin/named ] || exit 0
[ -x /lib/resolvconf/list-records ] || exit 1
[ -f /etc/bind/named.conf.options ] || exit 0

OPTSFILE=named.options

RUNDIR=/var/run/bind
[ -d "$RUNDIR" ] || mkdir --parents --mode=0755 "$RUNDIR"

# Stores arguments (minus duplicates) in RSLT, separated by spaces
# Doesn't work properly if an argument itself contain whitespace
uniquify()
{
	RSLT=""
	while [ "$1" ] ; do
		for E in $RSLT ; do
			[ "$1" = "$E" ] && { shift ; continue 2 ; }
		done
		RSLT="${RSLT:+$RSLT }$1"
		shift
	done
}

RSLVCNFFILES="$(/lib/resolvconf/list-records | sed -e '/^lo/d')"
 
### Compile semicolon-separated list nameservers ###
NMSRVRS=""
if [ "$RSLVCNFFILES" ] ; then
	uniquify $(sed -n 's/^[[:space:]]*nameserver[[:space:]]\+//p' $RSLVCNFFILES)
	NMSRVRS="${RSLT// /; }; "
fi

# N.B.: After changing directory we no longer have access to the resolv.conf-type files
cd "$RUNDIR"

TMPFILE="${OPTSFILE}_new.$$"
clean_up()
{
	rm -f "${RUNDIR}/$TMPFILE"
}
trap clean_up EXIT
rm -f "$TMPFILE"

# We want to process named.conf.options such that the new forwarders 
# statement gets inserted but nothing else is corrupted in the process.
# We want to do this using only commands available in /bin and /sbin, i.e.,
# with sh, sed and/or grep.   Sed can be made to work -- with difficulty.
# Even so, the following script does not work properly if comment
# delimiters of one style of commenting appear inside another kind of
# comment.  (Named supports C, C++ and sh comment styles.)
# First, we do our best to delete all and only comments.
# Then we delete any existing forwarders statement, taking into account
# the fact that these can span several lines.  Then we add a new
# forwarders statement at the beginning of the options statement.
#
echo "// named.conf fragment automatically generated by $0" > "$TMPFILE"
echo "// DO NOT EDIT THIS FILE.  Instead edit /etc/bind/named.conf.options ." >> "$TMPFILE"
cat /etc/bind/named.conf.options | sed 's%\*/%\*/\
%g' | sed '\%/\*%{ :x ; s%\*/%\*/% ; t y ; N ; b x ; :y ; s%/\*.*\*/%% ; }' | sed 's%//.*%%' | sed 's/#.*//' | sed '/forwarders/{ :x ; s/}/}/ ; t y ; N ; b x ; :y ; s/}[[:space:]]*;/};/ ; t z ; N ; b y ; :z s/forwarders[[:space:]]*{[^}]*};// ; }' | sed 's/options[[:space:]]*{/options {\
	forwarders { '"${NMSRVRS}"'};/' | sed '/^[[:space:]]*$/{ d ; }' >> "$TMPFILE"

# bind version 8 does not create a "bind" group
chown root:bind "$TMPFILE" > /dev/null 2>&1 || :

if [ "$1" = "-i" ] ; then
	mv -f "$TMPFILE" "$OPTSFILE"
	exit 0
fi

# Reload named unless we know its options haven't changed
if [ -x /usr/bin/diff ] && [ -f "$OPTSFILE" ] && /usr/bin/diff -q "$OPTSFILE" "$TMPFILE" > /dev/null ; then
	# No change
	rm -f "$TMPFILE"
else
	mv -f "$TMPFILE" "$OPTSFILE"
	[ -x /etc/init.d/bind9 ] && /etc/init.d/bind9 reload > /dev/null 2>&1 || :
	[ -x /etc/init.d/bind  ] && /etc/init.d/bind reload > /dev/null 2>&1 || :
fi

