#!/bin/bash
# Copyright 2006 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2

# Written by Roy Marples (uberlord@gentoo.org)
# Heavily based on Debian resolvconf by Thomas Hood

# Load our system functions (einfo, default path, etc)
argv0="$0"
if ! source /etc/init.d/functions.sh ; then
	echo "${argv0##*/}: Could not source /etc/init.d/functions.sh!" >&2
	exit 1
fi

error_exit() {
	eerror "$*"
	exit 1
}

VARDIR=/etc/resolvconf/run
ADDORDER="${VARDIR}/added_order"
IFACEDIR="${VARDIR}/interfaces"

usage() {
	cat <<-EOF
	Usage: ${argv0##*/} [options]

	Inform the system about any DNS updates.

	Options:
	  -a \$INTERFACE    Add DNS information to the specified interface
	                   (DNS supplied via stdin in resolv.conf format)
	  -d \$INTERFACE    Delete DNS information from the specified interface
	  -u               Run updates from our current DNS information
	  -l [\$PATTERN]    Show DNS information, optionally from interfaces
	                   that match the specified pattern
	  -i [\$PATTERN]    Show interfaces that have supplied DNS information
                   optionally from interfaces that match the specified
                   pattern
	  -v [\$PATTERN]    echo NEWDOMAIN, NEWSEARCH and NEWNS variables to
	  		   the console
	  -h               Show this help cruft
	EOF
	[[ -z $@ ]] && exit 0
	echo
	error_exit "$*"
}

echo_resolv() {
	[[ -z $1 || ! -e "${IFACEDIR}/$1" ]] && return
	echo "# resolv.conf for interface $1"
	grep "." "${IFACEDIR}/$1"
	echo
}

CMD="$1"
IFACE="$2"
shift ; shift

# -l is a Gentoo option that lists our resolv files
# optionally for a specific interface
if [[ ${CMD} == "-l" || ${CMD} == "-i" ]] ; then
	[[ ! -d ${IFACEDIR} ]] && exit 0
	
	# If we have an interface ordering list, then use that.
	# It works by just using pathname expansion in the interface directory.
	if [[ -n ${IFACE} ]] ; then
		LIST="${IFACE} $@"
	elif [[ -r /etc/resolvconf/interface-order ]] ; then
		LIST="$(< /etc/resolvconf/interface-order)"
	fi

	# If we don't have a list then prefer lo, tunnels, ppp
	# and then anything else.
	if [[ -z ${LIST} ]] ; then
		LIST="lo lo[0-9]* tap[0-9]* tun[0-9]* vpn vpn[0-9]* ppp[0-9]* ippp[0-9]* *"
	fi

	cd "${IFACEDIR}"
	shopt -s nullglob extglob
	for IFACE in $(uniqify ${LIST}) ; do
		# Only list interfaces which we really have
		[[ ! -e ${IFACE} ]] && continue
		
		if [[ ${CMD} == "-i" ]] ; then
			echo -n "${IFACE} "
		else
			echo_resolv "${IFACE}"
		fi
	done
	[[ ${CMD} == "-i" ]] && echo
	exit 0
fi

if [[ ${CMD} == "-v" ]] ; then
	NS=
	DOMAIN=
	SEARCH=
	NEWSEARCH=
	NEWNS=
	NEWDOMAIN=
	while read LINE ; do
		if [[ ${LINE} == "nameserver "* ]] ; then
			[[ ${LINE#* } == 127.* ]] && continue
			NS="${NS}${LINE#* } "
		elif [[ ${LINE} == "domain "* ]] ; then
			[[ -z ${SEARCH} ]] && DOMAIN="${LINE#* }"
		elif [[ ${LINE} == "search "* ]] ; then
			SEARCH="${LINE#* }"
			DOMAIN=
		elif [[ -z ${LINE} ]] ; then
			for N in ${NS} ; do
				if [[ -n ${DOMAIN} ]] ; then
					NEWDOMAIN="${NEWDOMAIN} ${DOMAIN},${N}"
				elif [[ -n ${SEARCH} ]] ; then
					for S in ${SEARCH} ; do
						NEWSEARCH="${NEWSEARCH} ${S},${N}"
					done
				else
					NEWNS="${NEWNS} ${N}"
				fi
			done
			NS=
			DOMAIN=
			SEARCH=
		fi
	done < <("${argv0}" -l "${IFACE}")

	# Prefer DOMAIN nameservers over SEARCH nameservers
	# if we are supplied both.
	NEWDOMAIN="$(uniqify ${NEWDOMAIN})"
	NEWSEARCH="$(uniqify ${NEWSEARCH})"
	NEWNS="$(uniqify ${NEWNS})"
	for S in ${NEWSEARCH} ; do
		for DN in ${NEWDOMAIN} ; do
			if [[ ${S%,*} == "${DN%,*}" ]] ; then
				NEWSEARCH="${NEWSEARCH//${S}/${DN}}"
				NEWDOMAIN="${NEWDOMAIN//${DN}/}"
				break
			fi
		done
	done

	echo "NEWDOMAIN='${NEWDOMAIN}'"
	echo "NEWSEARCH='${NEWSEARCH}'"
	echo "NEWNS='${NEWNS}'"
	exit 0
fi

# Only root can update resolv.conf
[[ ${EUID} != "0" ]] && error_exit "You must be root to run ${argv0##*/}"

# Test that we have valid options
if [[ ${CMD} == "-a" || ${CMD} == "-d" ]] ; then
	if [[ -z ${IFACE} ]] ; then
		usage "Interface not specified"
	fi
elif [[ ${CMD} != "-u" ]] ; then
	[[ -n ${CMD} && ${CMD} != "-h" ]] && usage "Unknown option ${CMD}"
	usage
fi
if [[ ${CMD} == "-a" ]] ; then
	q='\'
	for x in '/' '\' ' ' '*' ; do
		[[ ${IFACE/${q}${x}/} != "${IFACE}" ]] \
			&& error_exit "${x} not allowed in interface name"
	done
	for x in '.' '-' '~' ; do
		[[ ${IFACE#${x}} != "${IFACE}" ]] \
			&& error_exit "${x} not allowed at start of interface name"
	done
	[[ ${CMD} == "-a" && -t 0 ]] && error_exit "No file given via stdin"
	IFACERESOLV="${IFACEDIR}/${IFACE}"
fi

# Ensure that libdir exists
if [[ ! -d ${IFACEDIR} ]] ; then
	if [[ ! -d ${VARDIR} ]] ; then
		if [[ -L ${VARDIR} ]] ; then
			DIR="$(readlink -f "${VARDIR}")"
			[[ -z ${DIR} ]] && DIR="$(readlink "${VARDIR}")"
		fi
		# Change to /etc as link maybe relative
		cd "${VARDIR%/*}"
		mkdir -m 0755 -p "${DIR}" \
			|| error_exit "Failed to create needed directory ${DIR}"
	fi
	mkdir -m 0755 -p "${IFACEDIR}" | 
		error_exit "Failed to create needed directory ${IFACEDIR}"
else
	# Delete any existing information about the interface
	if [[ ${CMD} == "-a" || ${CMD} == "-d" ]] ; then
		cd "${IFACEDIR}"
		shopt -s nullglob extglob
		for IFACE in $(uniqify ${IFACE}) ; do
			rm -f "${IFACE}"
			if [[ -e ${ADDORDER} ]] ; then
				sed -i.old -e '/^'"${IFACE}"'$/ d' "${ADDORDER}"
				rm -f "${ADDORDER}.old"
			fi
		done
	fi
fi

if [[ ${CMD} == "-a" ]] ; then
	# Create our resolv.conf file
	RESOLV=
	while read LINE ; do
		RESOLV="${RESOLV}${LINE}\n"
	done
	echo -e "${RESOLV}" > "${IFACEDIR}/${IFACE}"

	# Add our interface to the back of the list
	echo "${IFACE}" >> "${ADDORDER}"
fi

for x in /etc/resolvconf/update.d/* ; do
	[[ -e ${x} ]] && "${x}" "${CMD}" "${IFACE}"
done

# vim: ts=4 :
