/contrib/openresolv/resolvconf.in
https://bitbucket.org/freebsd/freebsd-head/ · Autoconf · 421 lines · 348 code · 27 blank · 46 comment · 77 complexity · 0e07b53d3caff326ada990d2d6a583cd MD5 · raw file
- #!/bin/sh
- # Copyright (c) 2007-2009 Roy Marples
- # All rights reserved
- # 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.
- RESOLVCONF="$0"
- SYSCONFDIR=@SYSCONFDIR@
- LIBEXECDIR=@LIBEXECDIR@
- VARDIR=@VARDIR@
- # Support original resolvconf configuration layout
- # as well as the openresolv config file
- if [ -f "$SYSCONFDIR"/resolvconf.conf ]; then
- . "$SYSCONFDIR"/resolvconf.conf
- [ -n "$state_dir" ] && VARDIR="$state_dir"
- elif [ -d "$SYSCONFDIR/resolvconf" ]; then
- SYSCONFDIR="$SYSCONFDIR/resolvconf"
- if [ -f "$SYSCONFDIR"/interface-order ]; then
- interface_order="$(cat "$SYSCONFDIR"/interface-order)"
- fi
- fi
- IFACEDIR="$VARDIR/interfaces"
- METRICDIR="$VARDIR/metrics"
- PRIVATEDIR="$VARDIR/private"
- : ${dynamic_order:=tap[0-9]* tun[0-9]* vpn vpn[0-9]* ppp[0-9]* ippp[0-9]*}
- : ${interface_order:=lo lo[0-9]*}
- error_exit()
- {
- echo "$*" >&2
- exit 1
- }
- usage()
- {
- cat <<-EOF
- Usage: ${RESOLVCONF##*/} [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)
- -m metric Give the added DNS information a metric
- -p Mark the interface as private
- -d \$INTERFACE Delete DNS information from the specified interface
- -f Ignore non existant interfaces
- -I Init the state dir
- -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 "$1" ] && exit 0
- echo
- error_exit "$*"
- }
- echo_resolv()
- {
- local line=
- [ -n "$1" -a -e "$IFACEDIR/$1" ] || return 1
- echo "# resolv.conf from $1"
- # Our variable maker works of the fact each resolv.conf per interface
- # is separated by blank lines.
- # So we remove them when echoing them.
- while read line; do
- [ -n "$line" ] && echo "$line"
- done < "$IFACEDIR/$1"
- echo
- }
- # Parse resolv.conf's and make variables
- # for domain name servers, search name servers and global nameservers
- parse_resolv()
- {
- local line= ns= ds= search= d= n= newns=
- local new=true iface= private=false p=
- echo "DOMAINS="
- echo "SEARCH=\"$search_domains\""
- # let our subscribers know about global nameservers
- for n in $name_servers; do
- case "$n" in
- 127.*|0.0.0.0|255.255.255.255|::1) :;;
- *) newns="$newns${newns:+ }$n";;
- esac
- done
- echo "NAMESERVERS=\"$newns\""
- echo "LOCALNAMESERVERS="
- newns=
- while read line; do
- case "$line" in
- "# resolv.conf from "*)
- if ${new}; then
- iface="${line#\# resolv.conf from *}"
- new=false
- if [ -e "$PRIVATEDIR/$iface" ]; then
- private=true
- else
- # Allow expansion
- cd "$IFACEDIR"
- private=false
- for p in $private_interfaces; do
- if [ "$p" = "$iface" ]; then
- private=true
- break
- fi
- done
- fi
- fi
- ;;
- "nameserver "*)
- case "${line#* }" in
- 127.*|0.0.0.0|255.255.255.255|::1)
- echo "LOCALNAMESERVERS=\"\$LOCALNAMESERVERS ${line#* }\""
- continue
- ;;
- esac
- ns="$ns${line#* } "
- ;;
- "domain "*|"search "*)
- search="${line#* }"
- ;;
- *)
- [ -n "$line" ] && continue
- if [ -n "$ns" -a -n "$search" ]; then
- newns=
- for n in $ns; do
- newns="$newns${newns:+,}$n"
- done
- ds=
- for d in $search; do
- ds="$ds${ds:+ }$d:$newns"
- done
- echo "DOMAINS=\"\$DOMAINS $ds\""
- fi
- echo "SEARCH=\"\$SEARCH $search\""
- if ! $private; then
- echo "NAMESERVERS=\"\$NAMESERVERS $ns\""
- fi
- ns=
- search=
- new=true
- ;;
- esac
- done
- }
- uniqify()
- {
- local result=
- while [ -n "$1" ]; do
- case " $result " in
- *" $1 "*);;
- *) result="$result $1";;
- esac
- shift
- done
- echo "${result# *}"
- }
- list_resolv()
- {
- [ -d "$IFACEDIR" ] || return 0
- local report=false list= retval=0 cmd="$1"
- shift
- # If we have an interface ordering list, then use that.
- # It works by just using pathname expansion in the interface directory.
- if [ -n "$1" ]; then
- list="$@"
- $force || report=true
- else
- cd "$IFACEDIR"
- for i in $interface_order; do
- [ -e "$i" ] && list="$list $i"
- done
- for i in $dynamic_order; do
- if [ -e "$i" -a ! -e "$METRICDIR/"*" $i" ]; then
- list="$list $i"
- fi
- done
- if [ -d "$METRICDIR" ]; then
- cd "$METRICDIR"
- for i in *; do
- list="$list ${i#* }"
- done
- fi
- list="$list *"
- fi
- cd "$IFACEDIR"
- for i in $(uniqify $list); do
- # Only list interfaces which we really have
- if ! [ -e "$i" ]; then
- if $report; then
- echo "No resolv.conf for interface $i" >&2
- retval=$(($retval + 1))
- fi
- continue
- fi
-
- if [ "$cmd" = i -o "$cmd" = "-i" ]; then
- printf "$i "
- else
- echo_resolv "$i"
- fi
- done
- [ "$cmd" = i -o "$cmd" = "-i" ] && echo
- return $retval
- }
- make_vars()
- {
- eval "$(list_resolv -l "$@" | parse_resolv)"
- # Ensure that we only list each domain once
- newdomains=
- for d in $DOMAINS; do
- dn="${d%%:*}"
- case " $newdomains" in
- *" ${dn}:"*) continue;;
- esac
- newdomains="$newdomains${newdomains:+ }$dn:"
- newns=
- for nd in $DOMAINS; do
- if [ "$dn" = "${nd%%:*}" ]; then
- ns="${nd#*:}"
- while [ -n "$ns" ]; do
- case ",$newns," in
- *,${ns%%,*},*) ;;
- *) newns="$newns${newns:+,}${ns%%,*}";;
- esac
- [ "$ns" = "${ns#*,}" ] && break
- ns="${ns#*,}"
- done
- fi
- done
- newdomains="$newdomains$newns"
- done
- echo "DOMAINS='$newdomains'"
- echo "SEARCH='$(uniqify $SEARCH)'"
- echo "NAMESERVERS='$(uniqify $NAMESERVERS)'"
- echo "LOCALNAMESERVERS='$(uniqify $LOCALNAMESERVERS)'"
- }
- force=false
- while getopts a:d:fhIilm:puv OPT; do
- case "$OPT" in
- f) force=true;;
- h) usage;;
- m) IF_METRIC="$OPTARG";;
- p) IF_PRIVATE=1;;
- '?') ;;
- *) cmd="$OPT"; iface="$OPTARG";;
- esac
- done
- shift $(($OPTIND - 1))
- args="$iface${iface:+ }$@"
- # -I inits the state dir
- if [ "$cmd" = I ]; then
- if [ -d "$VARDIR" ]; then
- rm -rf "$VARDIR"/*
- fi
- exit $?
- fi
- # -l lists our resolv files, optionally for a specific interface
- if [ "$cmd" = l -o "$cmd" = i ]; then
- list_resolv "$cmd" "$args"
- exit $?
- fi
- # Not normally needed, but subscribers should be able to run independently
- if [ "$cmd" = v ]; then
- make_vars "$iface"
- exit $?
- fi
- # Test that we have valid options
- if [ "$cmd" = a -o "$cmd" = d ]; then
- if [ -z "$iface" ]; then
- usage "Interface not specified"
- fi
- elif [ "$cmd" != u ]; then
- [ -n "$cmd" -a "$cmd" != h ] && usage "Unknown option $cmd"
- usage
- fi
- if [ "$cmd" = a ]; then
- for x in '/' \\ ' ' '*'; do
- case "$iface" in
- *[$x]*) error_exit "$x not allowed in interface name";;
- esac
- done
- for x in '.' '-' '~'; do
- case "$iface" in
- [$x]*) error_exit \
- "$x not allowed at start of interface name";;
- esac
- done
- [ "$cmd" = a -a -t 0 ] && error_exit "No file given via stdin"
- fi
- if [ ! -d "$IFACEDIR" ]; then
- if [ ! -d "$VARDIR" ]; then
- if [ -L "$VARDIR" ]; then
- dir="$(readlink "$VARDIR")"
- # link maybe relative
- cd "${VARDIR%/*}"
- if ! mkdir -m 0755 -p "$dir"; then
- error_exit "Failed to create needed" \
- "directory $dir"
- fi
- else
- if ! mkdir -m 0755 -p "$VARDIR"; then
- error_exit "Failed to create needed" \
- "directory $VARDIR"
- fi
- fi
- fi
- mkdir -m 0755 -p "$IFACEDIR" || \
- error_exit "Failed to create needed directory $IFACEDIR"
- else
- # Delete any existing information about the interface
- if [ "$cmd" = d ]; then
- cd "$IFACEDIR"
- for i in $args; do
- if [ "$cmd" = d -a ! -e "$i" ]; then
- $force && continue
- error_exit "No resolv.conf for" \
- "interface $i"
- fi
- rm -f "$i" "$METRICDIR/"*" $i" \
- "$PRIVATEDIR/$i" || exit $?
- done
- fi
- fi
- if [ "$cmd" = a ]; then
- # Read resolv.conf from stdin
- resolv="$(cat)"
- # If what we are given matches what we have, then do nothing
- if [ -e "$IFACEDIR/$iface" ]; then
- if [ "$(echo "$resolv")" = \
- "$(cat "$IFACEDIR/$iface")" ]
- then
- exit 0
- fi
- rm "$IFACEDIR/$iface"
- fi
- echo "$resolv" >"$IFACEDIR/$iface" || exit $?
- [ ! -d "$METRICDIR" ] && mkdir "$METRICDIR"
- rm -f "$METRICDIR/"*" $iface"
- if [ -n "$IF_METRIC" ]; then
- # Pad metric to 6 characters, so 5 is less than 10
- while [ ${#IF_METRIC} -le 6 ]; do
- IF_METRIC="0$IF_METRIC"
- done
- echo " " >"$METRICDIR/$IF_METRIC $iface"
- fi
- case "$IF_PRIVATE" in
- [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
- if [ ! -d "$PRIVATEDIR" ]; then
- [ -e "$PRIVATEDIR" ] && rm "$PRIVATEDIR"
- mkdir "$PRIVATEDIR"
- fi
- [ -d "$PRIVATEDIR" ] && echo " " >"$PRIVATEDIR/$iface"
- ;;
- *)
- if [ -e "$PRIVATEDIR/$iface" ]; then
- rm -f "$PRIVATEDIR/$iface"
- fi
- ;;
- esac
- fi
- eval "$(make_vars)"
- export RESOLVCONF DOMAINS SEARCH NAMESERVERS LOCALNAMESERVERS
- : ${list_resolv:=list_resolv -l}
- retval=0
- for script in "$LIBEXECDIR"/*; do
- if [ -f "$script" ]; then
- if [ -x "$script" ]; then
- "$script" "$cmd" "$iface"
- else
- (. "$script" "$cmd" "$iface")
- fi
- retval=$(($retval + $?))
- fi
- done
- exit $retval