#!/bin/sh
# Copyright 2007 Roy Marples
# All rights reserved

# libc subscriber for resolvconf 

# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#     * Redistributions of source code must retain the above copyright
#       notice, this list of conditions and the following disclaimer.
#     * Redistributions in binary form must reproduce the above
#       copyright notice, this list of conditions and the following
#       disclaimer in the documentation and/or other materials provided
#       with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

PREFIX="/usr/local"
RESOLVCONF="${PREFIX}"/etc/resolvconf
RESOLVCONFS="$(resolvconf -l)"
BASE="${RESOLVCONF}/resolv.conf.d/base"

uniqify() {
    local result=
    while [ -n "$1" ]; do
		case " ${result} " in
			*" $1 "*);;
			*) result="${result} $1";;
		esac
		shift
	done
    echo "${result# *}"
}

OUR_NS=
if [ -e "${BASE}" ]; then
	OUR_NS="$(sed -n -e 's/^[[:space:]]*nameserver[[:space:]]*//p' "${BASE}")"
fi
OUR_NS="$(uniqify \
	${OUR_NS} \
	$(echo "${RESOLVCONFS}" \
	| sed -n -e 's/^[[:space:]]*nameserver[[:space:]]*//p') \
)"

# libc only allows for 3 nameservers
# truncate after 127 as well
i=0
NS=
LOCALH=false
for N in ${OUR_NS}; do
	i=$((${i} + 1))
	NS="${NS} ${N}"
	[ "${i}" = "3" ] && break
	case "${N}" in
		127.*) LOCALH=true; break;;
	esac
done

# This is nasty!
# If we have a local nameserver then assume they are intelligent enough
# to be forwarding domain requests to the correct nameserver and not search
# ones. This means we prefer search then domain, otherwise, we use them in
# the order given to us.
OUR_SEARCH=
if ${LOCALH}; then
	if [ -e "${BASE}" ]; then
		OUR_SEARCH="$(sed -n -e 's/^[[:space:]]*search[[:space:]]*//p' "${BASE}")"
	fi
	OUR_SEARCH="${OUR_SEARCH} $(echo "${RESOLVCONFS}" \
		| sed -n 's/^[[:space:]]*search[[:space:]]*//p')"
	if [ -e "${BASE}" ]; then
		OUR_SEARCH="${OUR_SEARCH} $(sed -n -e 's/^[[:space:]]*domain[[:space:]]*//p' "${BASE}")"
	fi
	OUR_SEARCH="${OUR_SEARCH} $( echo "${RESOLVCONFS}" \
		| sed -n -e 's/^[[:space:]]*domain[[:space:]]*//p')"
else
	if [ -e "${BASE}" ]; then
		OUR_SEARCH="$(sed -n -e 's/^[[:space:]]*search[[:space:]]*//p' \
			-e 's/^[[:space:]]*domain[[:space:]]*//p' "${BASE}")"
	fi
	OUR_SEARCH="${OUR_SEARCH} $(echo "${RESOLVCONFS}" \
		| sed -n -e 's/^[[:space:]]*search[[:space:]]*//p' \
			-e 's/^[[:space:]]*domain[[:space:]]*//p')"
fi

# libc only allows for 6 search domains 
i=0
SEARCH=
for S in $(uniqify ${OUR_SEARCH}); do
	i=$((${i} + 1))
	SEARCH="${SEARCH} ${S}"
	[ "${i}" = "6" ] && break
done
[ -n "${SEARCH}" ] && SEARCH="search${SEARCH}"

# Hold our new resolv.conf in a variable to save on temporary files
NEWCONF="# Generated by resolvconf\n"
[ -e "${RESOLVCONF}"/resolv.conf.d/head ] \
	&& NEWCONF="${NEWCONF}$(cat "${RESOLVCONF}"/resolv.conf.d/head)\n"
[ -n "${SEARCH}" ] && NEWCONF="${NEWCONF}${SEARCH}\n"
for N in ${NS}; do
	NEWCONF="${NEWCONF}nameserver ${N}\n"
done

# Now dump everything else from our resolvs
if [ -e "${BASE}" ]; then
	NEWCONF="${NEWCONF}$(sed -e '/^[[:space:]]*$/d' \
		-e '/^[[:space:]]*nameserver[[:space:]]*.*/d' \
		-e '/^[[:space:]]*search[[:space:]]*.*/d' \
		-e '/^[[:space:]]*domain[[:space:]]*.*/d' \
		"${BASE}")" 
fi

# We don't know we're using GNU sed, so we do it like this
NEWCONF="${NEWCONF}$(echo "${RESOLVCONFS}" | sed -e '/^[[:space:]]*$/d' \
	-e '/^[[:space:]]*#/d' \
	-e '/^[[:space:]]*nameserver[[:space:]]*.*/d' \
	-e '/^[[:space:]]*search[[:space:]]*.*/d' \
	-e '/^[[:space:]]*domain[[:space:]]*.*/d' \
	)"
[ -e "${RESOLVCONF}"/resolv.conf.d/tail ] \
	&& NEWCONF="${NEWCONF}$(cat "${RESOLVCONF}"/resolv.conf.d/tail)"

# Check if the file has actually changed or not
if [ -e "${RESOLVCONF}"/run/resolv.conf ]; then
	[ "$(cat "${RESOLVCONF}"/run/resolv.conf)" = "$(printf "${NEWCONF}")" ] && exit 0
fi

# Create our resolv.conf now
(umask 022; printf "${NEWCONF}" > "${RESOLVCONF}"/run/resolv.conf)

resolvconf -s nscd restart

# Notify users of the resolver
for x in "${REVOLVCONF}"/update-libc.d/*; do
	[ -e "${x}" ] && "${x}" "$@"
done

# vim: ts=4 :
