2 # Copyright 2007-2009 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.
28 SYSCONFDIR=@SYSCONFDIR@
29 LIBEXECDIR=@LIBEXECDIR@
31 IFACEDIR="$VARDIR/interfaces"
32 METRICDIR="$VARDIR/metrics"
33 PRIVATEDIR="$VARDIR/private"
35 # Support original resolvconf configuration layout
36 # as well as the openresolv config file
37 if [ -f "$SYSCONFDIR"/resolvconf.conf ]; then
38 . "$SYSCONFDIR"/resolvconf.conf
39 elif [ -d "$SYSCONFDIR/resolvconf" ]; then
40 SYSCONFDIR="$SYSCONFDIR/resolvconf"
41 if [ -f "$SYSCONFDIR"/interface-order ]; then
42 interface_order="$(cat "$SYSCONFDIR"/interface-order)"
45 : ${dynamic_order:=tap[0-9]* tun[0-9]* vpn vpn[0-9]* ppp[0-9]* ippp[0-9]*}
46 : ${interface_order:=lo lo[0-9]*}
57 Usage: ${RESOLVCONF##*/} [options]
59 Inform the system about any DNS updates.
62 -a \$INTERFACE Add DNS information to the specified interface
63 (DNS supplied via stdin in resolv.conf format)
64 -m metric Give the added DNS information a metric
65 -p Mark the interface as private
66 -d \$INTERFACE Delete DNS information from the specified interface
67 -f Ignore non existant interfaces
68 -u Run updates from our current DNS information
69 -l [\$PATTERN] Show DNS information, optionally from interfaces
70 that match the specified pattern
71 -i [\$PATTERN] Show interfaces that have supplied DNS information
72 optionally from interfaces that match the specified
74 -v [\$PATTERN] echo NEWDOMAIN, NEWSEARCH and NEWNS variables to
76 -s \$SVC \$CMD Do \$CMD for the system service \$SVC
77 -h Show this help cruft
87 [ -n "$1" -a -e "$IFACEDIR/$1" ] || return 1
88 echo "# resolv.conf from $1"
89 # Our variable maker works of the fact each resolv.conf per interface
90 # is separated by blank lines.
91 # So we remove them when echoing them.
93 [ -n "$line" ] && echo "$line"
98 # Parse resolv.conf's and make variables
99 # for domain name servers, search name servers and global nameservers
102 local line= ns= ds= search= d= n= newns=
103 local new=true iface= private=false
111 "# resolv.conf from "*)
113 iface="${line#\# resolv.conf from *}"
115 case " $private_interfaces " in
120 if [ -e "$PRIVATEDIR/$iface" ]; then
131 127.*|0.0.0.0|255.255.255.255) continue;;
135 "domain "*|"search "*)
139 [ -n "$line" ] && continue
140 if [ -n "$ns" -a -n "$search" ]; then
143 newns="$newns${newns:+,}$n"
147 ds="$ds${ds:+ }$d:$newns"
149 echo "DOMAINS=\"\$DOMAINS $ds\""
151 echo "SEARCH=\"\$SEARCH $search\""
153 echo "NAMESERVERS=\"\$NAMESERVERS $ns\""
166 while [ -n "$1" ]; do
169 *) result="$result $1";;
178 [ -d "$IFACEDIR" ] || return 0
180 local report=false list= retval=0 cmd="$1"
183 # If we have an interface ordering list, then use that.
184 # It works by just using pathname expansion in the interface directory.
187 $force || report=true
190 for i in $interface_order; do
191 [ -e "$i" ] && list="$list $i"
193 for i in $dynamic_order; do
194 if [ -e "$i" -a ! -e "$METRICDIR/"*" $i" ]; then
198 if [ -d "$METRICDIR" ]; then
208 for i in $(uniqify $list); do
209 # Only list interfaces which we really have
210 if ! [ -e "$i" ]; then
212 echo "No resolv.conf for interface $i" >&2
213 retval=$(($retval + 1))
218 if [ "$cmd" = i -o "$cmd" = "-i" ]; then
224 [ "$cmd" = i -o "$cmd" = "-i" ] && echo
230 eval "$(list_resolv -l "$@" | parse_resolv)"
232 # Ensure that we only list each domain once
234 for d in $DOMAINS; do
236 case " $newdomains" in
237 *" ${dn}:"*) continue;;
239 newdomains="$newdomains${newdomains:+ }$dn:"
241 for nd in $DOMAINS; do
242 if [ "$dn" = "${nd%%:*}" ]; then
244 while [ -n "$ns" ]; do
247 *) newns="$newns${newns:+,}${ns%%,*}";;
249 [ "$ns" = "${ns#*,}" ] && break
254 newdomains="$newdomains$newns"
256 echo "DOMAINS='$newdomains'"
257 echo "SEARCH='$(uniqify $SEARCH)'"
258 echo "NAMESERVERS='$(uniqify $NAMESERVERS)'"
261 # We do our service restarting here so that our subscribers don't have to know
262 # about the OS's init system.
265 local service="$1" action="$2"
267 [ -z "$action" ] && usage "Action not specified"
270 # If restarting check if service is running or not if we can
271 if [ "$action" = restart ]; then
272 if [ -s /var/run/"$service".pid ]; then
273 kill -0 $(cat /var/run/"$service".pid) 2>/dev/null
274 elif [ -s /var/run/"$service"/"$service".pid ]; then
275 kill -0 $(cat /var/run/"$service"/"$service".pid) \
277 elif [ -s /var/run/"$service"/pid ]; then
278 kill -0 $(cat /var/run/"$service"/pid) 2>/dev/null
282 # Service not running, so don't restart
283 [ $? != 0 ] && exit 0
285 if [ -x /sbin/service ]; then
286 service "$service" "$action" "$@"
287 elif [ -x /etc/init.d/"$service" -a -x /sbin/runscript ]; then
288 if [ "$action" = "restart" ]; then
289 /etc/init.d/"$service" --quiet --nodeps \
290 conditionalrestart "$@"
292 /etc/init.d/"$service" --quiet --nodeps \
295 elif [ -x /etc/init.d/"$service" ]; then
296 /etc/init.d/"$service" "$action" "$@"
297 elif [ -x /etc/rc.d/"${service}" ]; then
298 /etc/rc.d/"$service" "$action" "$@"
299 elif [ -x /etc/rc.d/rc."$service" ]; then
300 /etc/rc.d/rc."$service" "$action" "$@"
302 error_exit "Don't know how to interact with services on" \
308 while getopts a:d:fhilm:ps:uv OPT; do
312 m) IF_METRIC="$OPTARG";;
314 s) cmd=s; service="$OPTARG";;
316 *) cmd="$OPT"; iface="$OPTARG";;
319 shift $(($OPTIND - 1))
320 args="$iface${iface:+ }$@"
322 if [ "$cmd" = s ]; then
323 service "$service" "$@"
327 # -l lists our resolv files, optionally for a specific interface
328 if [ "$cmd" = l -o "$cmd" = i ]; then
329 list_resolv "$cmd" "$args"
333 if [ "$cmd" = v ]; then
338 # Test that we have valid options
339 if [ "$cmd" = a -o "$cmd" = d ]; then
340 if [ -z "$iface" ]; then
341 usage "Interface not specified"
343 elif [ "$cmd" != u ]; then
344 [ -n "$cmd" -a "$cmd" != h ] && usage "Unknown option $cmd"
347 if [ "$cmd" = a ]; then
348 for x in '/' \\ ' ' '*'; do
350 *[$x]*) error_exit "$x not allowed in interface name";;
353 for x in '.' '-' '~'; do
356 "$x not allowed at start of interface name";;
359 [ "$cmd" = a -a -t 0 ] && error_exit "No file given via stdin"
362 if [ ! -d "$IFACEDIR" ]; then
363 if [ ! -d "$VARDIR" ]; then
364 if [ -L "$VARDIR" ]; then
365 dir="$(readlink "$VARDIR")"
366 # link maybe relative
368 if ! mkdir -m 0755 -p "$dir"; then
369 error_exit "Failed to create needed" \
373 if ! mkdir -m 0755 -p "$VARDIR"; then
374 error_exit "Failed to create needed" \
379 mkdir -m 0755 -p "$IFACEDIR" || \
380 error_exit "Failed to create needed directory $IFACEDIR"
382 # Delete any existing information about the interface
383 if [ "$cmd" = d ]; then
386 if [ "$cmd" = d -a ! -e "$i" ]; then
388 error_exit "No resolv.conf for" \
391 rm -f "$i" "$METRICDIR/"*" $i" \
392 "$PRIVATEDIR/$i" || exit $?
397 if [ "$cmd" = a ]; then
398 # Read resolv.conf from stdin
400 # If what we are given matches what we have, then do nothing
401 if [ -e "$IFACEDIR/$iface" ]; then
402 if [ "$(printf "$resolv")" = \
403 "$(cat "$IFACEDIR/$iface")" ]
407 rm "$IFACEDIR/$iface"
409 printf "$resolv" >"$IFACEDIR/$iface" || exit $?
410 [ ! -d "$METRICDIR" ] && mkdir "$METRICDIR"
411 rm -f "$METRICDIR/"*" $iface"
412 if [ -n "$IF_METRIC" ]; then
413 # Pad metric to 6 characters, so 5 is less than 10
414 while [ ${#IF_METRIC} -le 6 ]; do
415 IF_METRIC="0$IF_METRIC"
417 echo " " >"$METRICDIR/$IF_METRIC $iface"
419 case "$IF_PRIVATE" in
420 [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
421 if [ ! -d "$PRIVATEDIR" ]; then
422 [ -e "$PRIVATEDIR" ] && rm "$PRIVATEDIR"
425 [ -d "$PRIVATEDIR" ] && echo " " >"$PRIVATEDIR/$iface"
428 if [ -e "$PRIVATEDIR/$iface" ]; then
429 rm -f "$PRIVATEDIR/$iface"
437 for script in "$LIBEXECDIR"/*; do
438 [ -f "$script" ] || continue
439 ( . "$script" "$cmd" "$iface" )
440 retval=$(($retval + $?))