-x marks the resolv.conf as exclusive.
authorRoy Marples <roy@marples.name>
Mon, 27 Apr 2015 12:06:27 +0000 (12:06 +0000)
committerRoy Marples <roy@marples.name>
Mon, 27 Apr 2015 12:06:27 +0000 (12:06 +0000)
Only the latest exclusive resolv.conf will be processed.
Fixes [e1e6078045].

resolvconf.8.in
resolvconf.in

index 7de953c3b8ef7d79b77ee51857f95c1713c02ec5..10dcf5dd73992f6a869f1495ffcd4a9c1f92323f 100644 (file)
@@ -22,7 +22,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd March 10, 2014
+.Dd April 27, 2014
 .Dt RESOLVCONF 8
 .Os
 .Sh NAME
 .Nm
 .Op Fl m Ar metric
 .Op Fl p
+.Op Fl x
 .Fl a Ar interface Ns Op Ar .protocol
 .No < Ns Pa file
 .Nm
 .Op Fl f
 .Fl d Ar interface Ns Op Ar .protocol
 .Nm
+.Op Fl x
 .Fl il Ar pattern
 .Nm
 .Fl u
@@ -106,6 +108,12 @@ for how to configure
 .Nm
 to use a local name server.
 .Pp
+.Nm
+can mark an interfaces
+.Pa resolv.conf
+as exclusive.
+Only the latest exclusive interface is used for processing, otherwise all are.
+.Pp
 When an interface goes down, it should then call
 .Nm
 with
@@ -164,6 +172,10 @@ to update all its subscribers.
 .Nm
 does not update the subscribers when adding a resolv.conf that matches
 what it already has for that interface.
+.It Fl x
+Mark the interface
+.Pa resolv.conf
+as exclusive when adding, otherwise only use the latest exclusive interface.
 .El
 .Pp
 .Nm
@@ -244,6 +256,10 @@ for the metric.
 Marks the interface
 .Pa resolv.conf
 as private.
+.It Va IF_EXCLUSIVE
+Marks the interface
+.Pa resolv.conf
+as exclusive.
 .El
 .Sh FILES
 .Bl -ohang
index d1ac8ce5ac38a64d7b38d677a524138e5c4dcd92..81ef88e8af1dcdbe79ccc86b672c0210e1b5b5d5 100644 (file)
@@ -54,6 +54,7 @@ TMPDIR="$VARDIR/tmp"
 IFACEDIR="$VARDIR/interfaces"
 METRICDIR="$VARDIR/metrics"
 PRIVATEDIR="$VARDIR/private"
+EXCLUSIVEDIR="$VARDIR/exclusive"
 LOCKDIR="$VARDIR/lock"
 
 warn()
@@ -79,6 +80,7 @@ usage()
                           (DNS supplied via stdin in resolv.conf format)
          -m metric        Give the added DNS information a metric
          -p               Mark the interface as private
+         -x               Mark the interface as exclusive
          -d \$INTERFACE    Delete DNS information from the specified interface
          -f               Ignore non existant interfaces
          -I               Init the state dir
@@ -247,15 +249,38 @@ list_resolv()
 {
        [ -d "$IFACEDIR" ] || return 0
 
-       local report=false list= retval=0 cmd="$1"
+       local report=false list= retval=0 cmd="$1" excl=
        shift
 
+       if [ "$cmd" = "-x" ]; then
+               IF_EXCLUSIVE=1
+               shift
+       fi
+
+       case "$IF_EXCLUSIVE" in
+       [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
+               if [ -d "$EXCLUSIVEDIR" ]; then
+                       cd "$EXCLUSIVEDIR"
+                       for i in *; do
+                               if [ -f "$i" ]; then
+                                       list="${i#* }"
+                                       break
+                               fi
+                       done
+               fi
+               excl=true
+               ;;
+       *)
+               excl=false
+               ;;
+       esac
+
        # 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
+       elif ! $excl; then
                cd "$IFACEDIR"
                for i in $interface_order; do
                        [ -f "$i" ] && list="$list $i"
@@ -283,12 +308,13 @@ list_resolv()
        fi
 
        cd "$IFACEDIR"
+       retval=1
        for i in $(uniqify $list); do
                # Only list interfaces which we really have
                if ! [ -f "$i" ]; then
                        if $report; then
                                echo "No resolv.conf for interface $i" >&2
-                               retval=$(($retval + 1))
+                               retval=2
                        fi
                        continue
                fi
@@ -298,6 +324,7 @@ list_resolv()
                else
                        echo_resolv "$i"
                fi
+               [ $? = 0 -a "$retval" = 1 ] && retval=0
        done
        [ "$cmd" = i -o "$cmd" = "-i" ] && echo
        return $retval
@@ -397,7 +424,7 @@ replace()
 
 make_vars()
 {
-       local newdomains= d= dn= newns= ns=
+       local newdomains= d= dn= newns= ns= x=
 
        # Clear variables
        DOMAIN=
@@ -405,12 +432,14 @@ make_vars()
        SEARCH=
        NAMESERVERS=
        LOCALNAMESERVERS=
+       
 
        if [ -n "$name_servers" -o -n "$search_domains" ]; then
                eval "$(echo_prepend | parse_resolv)"
        fi
        if [ -z "$VFLAG" ]; then
-               eval "$(list_resolv -l "$@" | replace | parse_resolv)"
+               list_resolv -x -l "$@" >/dev/null && x="-x"
+               eval "$(list_resolv $x -l "$@" | replace | parse_resolv)"
        fi
        if [ -n "$name_servers_append" -o -n "$search_domains_append" ]; then
                eval "$(echo_append | parse_resolv)"
@@ -459,7 +488,7 @@ make_vars()
 
 force=false
 VFLAG=
-while getopts a:Dd:fhIilm:puvV OPT; do
+while getopts a:Dd:fhIilm:puvVx OPT; do
        case "$OPT" in
        f) force=true;;
        h) usage;;
@@ -473,6 +502,7 @@ while getopts a:Dd:fhIilm:puvV OPT; do
                        local_nameservers=
                fi
                ;;
+       x) IF_EXCLUSIVE=1;;
        '?') ;;
        *) cmd="$OPT"; iface="$OPTARG";;
        esac
@@ -574,7 +604,8 @@ else
                                warn "No resolv.conf for interface $i"
                        fi
                        rm -f "$i" "$METRICDIR/"*" $i" \
-                               "$PRIVATEDIR/$i" || exit $?
+                               "$PRIVATEDIR/$i" \
+                               "$EXCLUSIVEDIR/"*" $i" || exit $?
                done
                if ! ${changed}; then
                        # Set the return code based on the forced flag
@@ -601,6 +632,7 @@ if [ "$cmd" = a ]; then
                changed=true
                changedfile=true
        fi
+
        # Set metric and private before creating the interface resolv.conf file
        # to ensure that it will have the correct flags
        [ ! -d "$METRICDIR" ] && mkdir "$METRICDIR"
@@ -618,6 +650,7 @@ if [ "$cmd" = a ]; then
            "$oldmetric" != "$METRICDIR/* $iface" ] &&
                changed=true
        [ -n "$newmetric" ] && echo " " >"$newmetric"
+
        case "$IF_PRIVATE" in
        [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
                if [ ! -d "$PRIVATEDIR" ]; then
@@ -634,6 +667,49 @@ if [ "$cmd" = a ]; then
                fi
                ;;
        esac
+
+       oldexcl=
+       for x in "$EXCLUSIVEDIR/"*" $iface"; do
+               if [ -f "$x" ]; then
+                       oldexcl="$x"
+                       break
+               fi
+       done
+       case "$IF_EXCLUSIVE" in
+       [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
+               if [ ! -d "$EXCLUSIVEDIR" ]; then
+                       [ -e "$EXCLUSIVEDIR" ] && rm "$EXCLUSIVEDIR"
+                       mkdir "$EXCLUSIVEDIR"
+               fi
+               cd "$EXCLUSIVEDIR"
+               for x in *; do
+                       [ -f "$x" ] && break
+               done
+               if [ "${x#* }" != "$iface" ]; then
+                       if [ "$x" = "${x% *}" ]; then
+                               x=10000000
+                       else
+                               x="${x% *}"
+                       fi
+                       if [ "$x" = "0000000" ]; then
+                               warn "exclusive underflow"
+                       else
+                               x=$(($x - 1))
+                       fi
+                       if [ -d "$EXCLUSIVEDIR" ]; then
+                               echo " " >"$EXCLUSIVEDIR/$x $iface"
+                       fi
+                       changed=true
+               fi
+               ;;
+       *)
+               if [ -f "$oldexcl" ]; then
+                       rm -f "$oldexcl"
+                       changed=true
+               fi
+               ;;
+       esac
+
        if $changedfile; then
                # Ensure that creating the file is an atomic operation
                if [ ! -d "$TMPDIR" ]; then