Sync usage with man page.
[netbsd-mini2440.git] / external / bsd / openresolv / dist / resolvconf.in
blobc0298b47ae587286b0fc96167341b83ab980c6cc
1 #!/bin/sh
2 # Copyright (c) 2007-2009 Roy Marples
3 # All rights reserved
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions
7 # are met:
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.
27 RESOLVCONF="$0"
28 SYSCONFDIR=@SYSCONFDIR@
29 LIBEXECDIR=@LIBEXECDIR@
30 VARDIR=@VARDIR@
31 # Support original resolvconf configuration layout
32 # as well as the openresolv config file
33 if [ -f "$SYSCONFDIR"/resolvconf.conf ]; then
34 . "$SYSCONFDIR"/resolvconf.conf
35 [ -n "$state_dir" ] && VARDIR="$state_dir"
36 elif [ -d "$SYSCONFDIR/resolvconf" ]; then
37 SYSCONFDIR="$SYSCONFDIR/resolvconf"
38 if [ -f "$SYSCONFDIR"/interface-order ]; then
39 interface_order="$(cat "$SYSCONFDIR"/interface-order)"
42 IFACEDIR="$VARDIR/interfaces"
43 METRICDIR="$VARDIR/metrics"
44 PRIVATEDIR="$VARDIR/private"
46 : ${dynamic_order:=tap[0-9]* tun[0-9]* vpn vpn[0-9]* ppp[0-9]* ippp[0-9]*}
47 : ${interface_order:=lo lo[0-9]*}
49 error_exit()
51 echo "$*" >&2
52 exit 1
55 usage()
57 cat <<-EOF
58 Usage: ${RESOLVCONF##*/} [options]
60 Inform the system about any DNS updates.
62 Options:
63 -a \$INTERFACE Add DNS information to the specified interface
64 (DNS supplied via stdin in resolv.conf format)
65 -m metric Give the added DNS information a metric
66 -p Mark the interface as private
67 -d \$INTERFACE Delete DNS information from the specified interface
68 -f Ignore non existant interfaces
69 -I Init the state dir
70 -u Run updates from our current DNS information
71 -l [\$PATTERN] Show DNS information, optionally from interfaces
72 that match the specified pattern
73 -i [\$PATTERN] Show interfaces that have supplied DNS information
74 optionally from interfaces that match the specified
75 pattern
76 -v [\$PATTERN] echo NEWDOMAIN, NEWSEARCH and NEWNS variables to
77 the console
78 -h Show this help cruft
79 EOF
80 [ -z "$1" ] && exit 0
81 echo
82 error_exit "$*"
85 echo_resolv()
87 local line=
88 [ -n "$1" -a -e "$IFACEDIR/$1" ] || return 1
89 echo "# resolv.conf from $1"
90 # Our variable maker works of the fact each resolv.conf per interface
91 # is separated by blank lines.
92 # So we remove them when echoing them.
93 while read line; do
94 [ -n "$line" ] && echo "$line"
95 done < "$IFACEDIR/$1"
96 echo
99 # Parse resolv.conf's and make variables
100 # for domain name servers, search name servers and global nameservers
101 parse_resolv()
103 local line= ns= ds= search= d= n= newns=
104 local new=true iface= private=false p=
106 echo "DOMAINS="
107 echo "SEARCH="
108 echo "NAMESERVERS="
110 while read line; do
111 case "$line" in
112 "# resolv.conf from "*)
113 if ${new}; then
114 iface="${line#\# resolv.conf from *}"
115 new=false
116 if [ -e "$PRIVATEDIR/$iface" ]; then
117 private=true
118 else
119 # Allow expansion
120 cd "$IFACEDIR"
121 private=false
122 for p in $private_interfaces; do
123 if [ "$p" = "$iface" ]; then
124 private=true
125 break
127 done
131 "nameserver "*)
132 case "${line#* }" in
133 127.*|0.0.0.0|255.255.255.255) continue;;
134 esac
135 ns="$ns${line#* } "
137 "domain "*|"search "*)
138 search="${line#* }"
141 [ -n "$line" ] && continue
142 if [ -n "$ns" -a -n "$search" ]; then
143 newns=
144 for n in $ns; do
145 newns="$newns${newns:+,}$n"
146 done
148 for d in $search; do
149 ds="$ds${ds:+ }$d:$newns"
150 done
151 echo "DOMAINS=\"\$DOMAINS $ds\""
153 echo "SEARCH=\"\$SEARCH $search\""
154 if ! $private; then
155 echo "NAMESERVERS=\"\$NAMESERVERS $ns\""
158 search=
159 new=true
161 esac
162 done
165 uniqify()
167 local result=
168 while [ -n "$1" ]; do
169 case " $result " in
170 *" $1 "*);;
171 *) result="$result $1";;
172 esac
173 shift
174 done
175 echo "${result# *}"
178 list_resolv()
180 [ -d "$IFACEDIR" ] || return 0
182 local report=false list= retval=0 cmd="$1"
183 shift
185 # If we have an interface ordering list, then use that.
186 # It works by just using pathname expansion in the interface directory.
187 if [ -n "$1" ]; then
188 list="$@"
189 $force || report=true
190 else
191 cd "$IFACEDIR"
192 for i in $interface_order; do
193 [ -e "$i" ] && list="$list $i"
194 done
195 for i in $dynamic_order; do
196 if [ -e "$i" -a ! -e "$METRICDIR/"*" $i" ]; then
197 list="$list $i"
199 done
200 if [ -d "$METRICDIR" ]; then
201 cd "$METRICDIR"
202 for i in *; do
203 list="$list ${i#* }"
204 done
206 list="$list *"
209 cd "$IFACEDIR"
210 for i in $(uniqify $list); do
211 # Only list interfaces which we really have
212 if ! [ -e "$i" ]; then
213 if $report; then
214 echo "No resolv.conf for interface $i" >&2
215 retval=$(($retval + 1))
217 continue
220 if [ "$cmd" = i -o "$cmd" = "-i" ]; then
221 printf "$i "
222 else
223 echo_resolv "$i"
225 done
226 [ "$cmd" = i -o "$cmd" = "-i" ] && echo
227 return $retval
230 make_vars()
232 eval "$(list_resolv -l "$@" | parse_resolv)"
234 # Ensure that we only list each domain once
235 newdomains=
236 for d in $DOMAINS; do
237 dn="${d%%:*}"
238 case " $newdomains" in
239 *" ${dn}:"*) continue;;
240 esac
241 newdomains="$newdomains${newdomains:+ }$dn:"
242 newns=
243 for nd in $DOMAINS; do
244 if [ "$dn" = "${nd%%:*}" ]; then
245 ns="${nd#*:}"
246 while [ -n "$ns" ]; do
247 case ",$newns," in
248 *,${ns%%,*},*) ;;
249 *) newns="$newns${newns:+,}${ns%%,*}";;
250 esac
251 [ "$ns" = "${ns#*,}" ] && break
252 ns="${ns#*,}"
253 done
255 done
256 newdomains="$newdomains$newns"
257 done
258 echo "DOMAINS='$newdomains'"
259 echo "SEARCH='$(uniqify $SEARCH)'"
260 echo "NAMESERVERS='$(uniqify $NAMESERVERS)'"
263 force=false
264 while getopts a:d:fhilm:puv OPT; do
265 case "$OPT" in
266 f) force=true;;
267 h) usage;;
268 m) IF_METRIC="$OPTARG";;
269 p) IF_PRIVATE=1;;
270 '?') ;;
271 *) cmd="$OPT"; iface="$OPTARG";;
272 esac
273 done
274 shift $(($OPTIND - 1))
275 args="$iface${iface:+ }$@"
277 # -I inits the state dir
278 if [ "$cmd" = I ]; then
279 if [ -d "$VARDIR" ]; then
280 rm -rf "$VARDIR"/*
282 exit $?
285 # -l lists our resolv files, optionally for a specific interface
286 if [ "$cmd" = l -o "$cmd" = i ]; then
287 list_resolv "$cmd" "$args"
288 exit $?
291 # Not normally needed, but subscribers should be able to run independently
292 if [ "$cmd" = v ]; then
293 make_vars "$iface"
294 exit $?
297 # Test that we have valid options
298 if [ "$cmd" = a -o "$cmd" = d ]; then
299 if [ -z "$iface" ]; then
300 usage "Interface not specified"
302 elif [ "$cmd" != u ]; then
303 [ -n "$cmd" -a "$cmd" != h ] && usage "Unknown option $cmd"
304 usage
306 if [ "$cmd" = a ]; then
307 for x in '/' \\ ' ' '*'; do
308 case "$iface" in
309 *[$x]*) error_exit "$x not allowed in interface name";;
310 esac
311 done
312 for x in '.' '-' '~'; do
313 case "$iface" in
314 [$x]*) error_exit \
315 "$x not allowed at start of interface name";;
316 esac
317 done
318 [ "$cmd" = a -a -t 0 ] && error_exit "No file given via stdin"
321 if [ ! -d "$IFACEDIR" ]; then
322 if [ ! -d "$VARDIR" ]; then
323 if [ -L "$VARDIR" ]; then
324 dir="$(readlink "$VARDIR")"
325 # link maybe relative
326 cd "${VARDIR%/*}"
327 if ! mkdir -m 0755 -p "$dir"; then
328 error_exit "Failed to create needed" \
329 "directory $dir"
331 else
332 if ! mkdir -m 0755 -p "$VARDIR"; then
333 error_exit "Failed to create needed" \
334 "directory $VARDIR"
338 mkdir -m 0755 -p "$IFACEDIR" || \
339 error_exit "Failed to create needed directory $IFACEDIR"
340 else
341 # Delete any existing information about the interface
342 if [ "$cmd" = d ]; then
343 cd "$IFACEDIR"
344 for i in $args; do
345 if [ "$cmd" = d -a ! -e "$i" ]; then
346 $force && continue
347 error_exit "No resolv.conf for" \
348 "interface $i"
350 rm -f "$i" "$METRICDIR/"*" $i" \
351 "$PRIVATEDIR/$i" || exit $?
352 done
356 if [ "$cmd" = a ]; then
357 # Read resolv.conf from stdin
358 resolv="$(cat)\n"
359 # If what we are given matches what we have, then do nothing
360 if [ -e "$IFACEDIR/$iface" ]; then
361 if [ "$(printf "$resolv")" = \
362 "$(cat "$IFACEDIR/$iface")" ]
363 then
364 exit 0
366 rm "$IFACEDIR/$iface"
368 printf "$resolv" >"$IFACEDIR/$iface" || exit $?
369 [ ! -d "$METRICDIR" ] && mkdir "$METRICDIR"
370 rm -f "$METRICDIR/"*" $iface"
371 if [ -n "$IF_METRIC" ]; then
372 # Pad metric to 6 characters, so 5 is less than 10
373 while [ ${#IF_METRIC} -le 6 ]; do
374 IF_METRIC="0$IF_METRIC"
375 done
376 echo " " >"$METRICDIR/$IF_METRIC $iface"
378 case "$IF_PRIVATE" in
379 [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
380 if [ ! -d "$PRIVATEDIR" ]; then
381 [ -e "$PRIVATEDIR" ] && rm "$PRIVATEDIR"
382 mkdir "$PRIVATEDIR"
384 [ -d "$PRIVATEDIR" ] && echo " " >"$PRIVATEDIR/$iface"
387 if [ -e "$PRIVATEDIR/$iface" ]; then
388 rm -f "$PRIVATEDIR/$iface"
391 esac
394 eval "$(make_vars)"
395 export RESOLVCONF DOMAINS SEARCH NAMESERVERS
396 : ${list_resolv:=list_resolv -l}
397 retval=0
398 for script in "$LIBEXECDIR"/*; do
399 if [ -f "$script" ]; then
400 if [ -x "$script" ]; then
401 "$script" "$cmd" "$iface"
402 else
403 (. "$script" "$cmd" "$fiace")
405 retval=$(($retval + $?))
407 done
408 exit $retval