2 # Copyright 2007-2008 Roy Marples
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions
8 # * Redistributions of source code must retain the above copyright
9 # notice, this list of conditions and the following disclaimer.
10 # * Redistributions in binary form must reproduce the above
11 # copyright notice, this list of conditions and the following
12 # disclaimer in the documentation and/or other materials provided
13 # with the distribution.
15 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 RESOLVCONF="${PREFIX}"/etc/resolvconf
31 UPDATED="${RESOLVCONF}"/update.d
32 VARDIR="${RESOLVCONF}"/run
33 IFACEDIR="${VARDIR}/interfaces"
42 Usage: ${argv0##*/} [options]
44 Inform the system about any DNS updates.
47 -a \$INTERFACE Add DNS information to the specified interface
48 (DNS supplied via stdin in resolv.conf format)
49 -d \$INTERFACE Delete DNS information from the specified interface
50 -f Ignore non existant interfaces
51 -u Run updates from our current DNS information
52 -l [\$PATTERN] Show DNS information, optionally from interfaces
53 that match the specified pattern
54 -i [\$PATTERN] Show interfaces that have supplied DNS information
55 optionally from interfaces that match the specified
57 -v [\$PATTERN] echo NEWDOMAIN, NEWSEARCH and NEWNS variables to
59 -s \$SVC \$CMD Do \$CMD for the system service \$SVC
60 -h Show this help cruft
68 [ -n "$1" -a -e "${IFACEDIR}/$1" ] || return 1
69 echo "# resolv.conf for interface $1"
79 *) result="${result} $1";;
87 while getopts a:d:fhils:uv OPT; do
91 s) CMD=s; SERVICE="${OPTARG}";;
93 *) CMD="${OPT}"; IFACE="${OPTARG}";;
96 shift $((${OPTIND} - 1))
97 ARGS="${IFACE}${IFACE:+ }$@"
99 # We do our service restarting here so that our subscribers don't have to know
100 # about the OS's init system.
101 if [ "${CMD}" = "s" ]; then
106 [ -z "${ACTION}" ] && usage "Action not specified"
108 # If restarting check if service is running or not if we can
109 if [ "${ACTION}" = "restart" ]; then
110 if [ -s /var/run/"${SERVICE}".pid ]; then
111 kill -0 $(cat /var/run/"${SERVICE}".pid) 2>/dev/null
112 elif [ -s /var/run/"${SERVICE}"/"${SERVICE}".pid ]; then
113 kill -0 $(cat /var/run/"${SERVICE}".pid) 2>/dev/null
114 elif [ -s /var/run/"${SERVICE}"/pid ]; then
115 kill -0 $(cat /var/run/"${SERVICE}"/pid) 2>/dev/null
119 # Service not running, so don't restart
120 [ $? != 0 ] && exit 0
122 if [ -x /sbin/service ]; then
123 service "${SERVICE}" "${ACTION}" "$@"
124 elif [ -x /etc/init.d/"${SERVICE}" -a -x /sbin/runscript ]; then
125 if [ "${ACTION}" = "restart" ]; then
126 /etc/init.d/"${SERVICE}" --quiet --nodeps conditionalrestart "$@"
128 /etc/init.d/"${SERVICE}" --quiet --nodeps "${ACTION}" "$@"
130 elif [ -x /etc/init.d/"${SERVICE}" ]; then
131 /etc/init.d/"${SERVICE}" "${ACTION}" "$@"
132 elif [ -x /etc/rc.d/"${SERVICE}" ]; then
133 /etc/rc.d/"${SERVICE}" "${ACTION}" "$@"
134 elif [ -x /etc/rc.d/rc."${SERVICE}" ]; then
135 /etc/rc.d/rc."${SERVICE}" "${ACTION}" "$@"
137 error_exit "Don't know how to interact with services on this platform"
142 # -l lists our resolv files, optionally for a specific interface
143 if [ "${CMD}" = "l" -o "${CMD}" = "i" ]; then
144 [ -d "${IFACEDIR}" ] || exit 0
147 # If we have an interface ordering list, then use that.
148 # It works by just using pathname expansion in the interface directory.
149 if [ -n "${ARGS}" ]; then
151 ${FORCE} || REPORT=true
152 elif [ -r "${RESOLVCONF}"/interface-order ]; then
153 LIST="$(cat "${RESOLVCONF}"/interface-order)"
156 # If we don't have a list then prefer lo, tunnels, ppp
157 # and then anything else.
158 if [ -z "${LIST}" ]; then
159 LIST="lo lo[0-9]* tap[0-9]* tun[0-9]* vpn vpn[0-9]* ppp[0-9]* ippp[0-9]* *"
164 for IFACE in $(uniqify ${LIST}); do
165 # Only list interfaces which we really have
166 if ! [ -e "${IFACE}" ]; then
168 echo "No resolv.conf for interface ${IFACE}" >&2
169 RETVAL=$((${RETVAL} + 1))
174 if [ "${CMD}" = "i" ]; then
177 echo_resolv "${IFACE}"
180 [ "${CMD}" = "i" ] && echo
184 if [ "${CMD}" = "v" ]; then
191 LINES="$("${argv0}" -l "${IFACE}" |
192 sed -e "s/'/'\\\\''/g" -e "s/^/'/g" -e "s/$/'/g")"
200 NS="${NS}${LINE#* } "
203 [ -z "${SEARCH}" ] && DOMAIN="${LINE#* }"
210 if [ -z "${LINE}" ]; then
212 if [ -n "${DOMAIN}" ]; then
213 NEWDOMAIN="${NEWDOMAIN} ${DOMAIN},${N}"
214 elif [ -n "${SEARCH}" ]; then
215 for S in ${SEARCH}; do
216 NEWSEARCH="${NEWSEARCH} ${S},${N}"
219 NEWNS="${NEWNS} ${N}"
230 # Prefer DOMAIN nameservers over SEARCH nameservers
231 # if we are supplied both.
232 NEWDOMAIN="$(uniqify ${NEWDOMAIN})"
233 NEWSEARCH="$(uniqify ${NEWSEARCH})"
234 NEWNS="$(uniqify ${NEWNS})"
235 for S in ${NEWSEARCH}; do
236 for DN in ${NEWDOMAIN}; do
237 if [ "${S%,*}" = "${DN%,*}" ]; then
238 NEWSEARCH="$(echo "${NEWSEARCH}" |
239 sed -e "s/${S}/${DN}/g")"
240 NEWDOMAIN="$(echo "${NEWDOMAIN}" |
241 sed -e "s/${DN}//g")"
247 echo "NEWDOMAIN='${NEWDOMAIN}'"
248 echo "NEWSEARCH='${NEWSEARCH}'"
249 echo "NEWNS='${NEWNS}'"
253 # Test that we have valid options
254 if [ "${CMD}" = "a" -o "${CMD}" = "d" ]; then
255 if [ -z "${IFACE}" ]; then
256 usage "Interface not specified"
258 elif [ "${CMD}" != "u" ]; then
259 [ -n "${CMD}" -a "${CMD}" != "h" ] && usage "Unknown option ${CMD}"
262 if [ "${CMD}" = "a" ]; then
263 for x in '/' \\ ' ' '*'; do
265 *[${x}]*) error_exit "${x} not allowed in interface name";;
268 for x in '.' '-' '~'; do
270 [${x}]*) error_exit "${x} not allowed at start of interface name";;
273 [ "${CMD}" = "a" -a -t 0 ] && error_exit "No file given via stdin"
274 IFACERESOLV="${IFACEDIR}/${IFACE}"
277 # Ensure that libdir exists
278 if [ ! -d "${IFACEDIR}" ]; then
279 if [ ! -d "${VARDIR}" ]; then
280 if [ -L "${VARDIR}" ]; then
281 DIR="$(readlink "${VARDIR}")"
282 # Change to /etc as link maybe relative
284 if ! mkdir -m 0755 -p "${DIR}"; then
285 error_exit "Failed to create needed directory ${DIR}"
288 if ! mkdir -m 0755 -p "${VARDIR}"; then
289 error_exit "Failed to create needed directory ${VARDIR}"
293 mkdir -m 0755 -p "${IFACEDIR}" || \
294 error_exit "Failed to create needed directory ${IFACEDIR}"
296 # Delete any existing information about the interface
297 if [ "${CMD}" = "a" -o "${CMD}" = "d" ]; then
299 for iface in ${IFACE}; do
300 if [ "${CMD}" = "d" -a ! -e "${iface}" ]; then
302 error_exit "No resolv.conf for interface ${iface}"
304 rm -f "${iface}" || exit $?
309 if [ "${CMD}" = "a" ]; then
310 # Create our resolv.conf file
311 cat >"${IFACEDIR}"/"${IFACE}" || exit $?
315 for x in "${UPDATED}"/*; do
316 if [ -e "${x}" ]; then
317 "${x}" "${CMD}" "${IFACE}"
318 RETVAL=$((${RETVAL} + $?))