Obtain a spinlock earlier due to exclusivity.
[openresolv] / resolvconf.in
1 #!/bin/sh
2 # Copyright (c) 2007-2015 Roy Marples
3 # All rights reserved
4
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.
14 #
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.
26
27 RESOLVCONF="$0"
28 SYSCONFDIR=@SYSCONFDIR@
29 LIBEXECDIR=@LIBEXECDIR@
30 VARDIR=@VARDIR@
31
32 # Disregard dhcpcd setting
33 unset interface_order state_dir
34
35 # If you change this, change the test in VFLAG and libc.in as well
36 local_nameservers="127.* 0.0.0.0 255.255.255.255 ::1"
37
38 dynamic_order="tap[0-9]* tun[0-9]* vpn vpn[0-9]* ppp[0-9]* ippp[0-9]*"
39 interface_order="lo lo[0-9]*"
40 name_server_blacklist="0.0.0.0"
41
42 # Support original resolvconf configuration layout
43 # as well as the openresolv config file
44 if [ -f "$SYSCONFDIR"/resolvconf.conf ]; then
45         . "$SYSCONFDIR"/resolvconf.conf
46         [ -n "$state_dir" ] && VARDIR="$state_dir"
47 elif [ -d "$SYSCONFDIR/resolvconf" ]; then
48         SYSCONFDIR="$SYSCONFDIR/resolvconf"
49         if [ -f "$SYSCONFDIR"/interface-order ]; then
50                 interface_order="$(cat "$SYSCONFDIR"/interface-order)"
51         fi
52 fi
53 TMPDIR="$VARDIR/tmp"
54 IFACEDIR="$VARDIR/interfaces"
55 METRICDIR="$VARDIR/metrics"
56 PRIVATEDIR="$VARDIR/private"
57 EXCLUSIVEDIR="$VARDIR/exclusive"
58 LOCKDIR="$VARDIR/lock"
59
60 warn()
61 {
62         echo "$*" >&2
63 }
64
65 error_exit()
66 {
67         echo "$*" >&2
68         exit 1
69 }
70
71 usage()
72 {
73         cat <<-EOF
74         Usage: ${RESOLVCONF##*/} [options]
75
76         Inform the system about any DNS updates.
77
78         Options:
79           -a \$INTERFACE    Add DNS information to the specified interface
80                            (DNS supplied via stdin in resolv.conf format)
81           -m metric        Give the added DNS information a metric
82           -p               Mark the interface as private
83           -x               Mark the interface as exclusive
84           -d \$INTERFACE    Delete DNS information from the specified interface
85           -f               Ignore non existant interfaces
86           -I               Init the state dir
87           -u               Run updates from our current DNS information
88           -l [\$PATTERN]    Show DNS information, optionally from interfaces
89                            that match the specified pattern
90           -i [\$PATTERN]    Show interfaces that have supplied DNS information
91                    optionally from interfaces that match the specified
92                    pattern
93           -v [\$PATTERN]    echo NEWDOMAIN, NEWSEARCH and NEWNS variables to
94                            the console
95           -h               Show this help cruft
96         EOF
97         [ -z "$1" ] && exit 0
98         echo
99         error_exit "$*"
100 }
101
102 echo_resolv()
103 {
104         local line= OIFS="$IFS"
105
106         [ -n "$1" -a -f "$IFACEDIR/$1" ] || return 1
107         echo "# resolv.conf from $1"
108         # Our variable maker works of the fact each resolv.conf per interface
109         # is separated by blank lines.
110         # So we remove them when echoing them.
111         while read -r line; do
112                 IFS="$OIFS"
113                 if [ -n "$line" ]; then
114                         # We need to set IFS here to preserve any whitespace
115                         IFS=''
116                         printf "%s\n" "$line"
117                 fi
118         done < "$IFACEDIR/$1"
119         echo
120         IFS="$OIFS"
121 }
122
123 # Parse resolv.conf's and make variables
124 # for domain name servers, search name servers and global nameservers
125 parse_resolv()
126 {
127         local line= ns= ds= search= d= n= newns=
128         local new=true iface= private=false p= domain= l= islocal=
129
130         newns=
131
132         while read -r line; do
133                 case "$line" in
134                 "# resolv.conf from "*)
135                         if ${new}; then
136                                 iface="${line#\# resolv.conf from *}"
137                                 new=false
138                                 if [ -e "$PRIVATEDIR/$iface" ]; then
139                                         private=true
140                                 else
141                                         # Allow expansion
142                                         cd "$IFACEDIR"
143                                         private=false
144                                         for p in $private_interfaces; do
145                                                 case "$iface" in
146                                                 "$p"|"$p":*) private=true; break;;
147                                                 esac
148                                         done
149                                 fi
150                         fi
151                         ;;
152                 "nameserver "*)
153                         islocal=false
154                         for l in $local_nameservers; do
155                                 case "${line#* }" in
156                                 $l)
157                                         islocal=true
158                                         echo "LOCALNAMESERVERS=\"\$LOCALNAMESERVERS ${line#* }\""
159                                         break
160                                         ;;
161                                 esac
162                         done
163                         $islocal || ns="$ns${line#* } "
164                         ;;
165                 "domain "*)
166                         if [ -z "$domain" ]; then
167                                 domain="${line#* }"
168                                 echo "DOMAIN=\"$domain\""
169                         fi
170                         search="${line#* }"
171                         ;;
172                 "search "*)
173                         search="${line#* }"
174                         ;;
175                 *)
176                         [ -n "$line" ] && continue
177                         if [ -n "$ns" -a -n "$search" ]; then
178                                 newns=
179                                 for n in $ns; do
180                                         newns="$newns${newns:+,}$n"
181                                 done
182                                 ds=
183                                 for d in $search; do
184                                         ds="$ds${ds:+ }$d:$newns"
185                                 done
186                                 echo "DOMAINS=\"\$DOMAINS $ds\""
187                         fi
188                         echo "SEARCH=\"\$SEARCH $search\""
189                         if ! $private; then
190                                 echo "NAMESERVERS=\"\$NAMESERVERS $ns\""
191                         fi
192                         ns=
193                         search=
194                         new=true
195                         ;;
196                 esac
197         done
198 }
199
200 uniqify()
201 {
202         local result=
203         while [ -n "$1" ]; do
204                 case " $result " in
205                 *" $1 "*);;
206                 *) result="$result $1";;
207                 esac
208                 shift
209         done
210         echo "${result# *}"
211 }
212
213 dirname()
214 {
215         local dir= OIFS="$IFS"
216         local IFS=/
217         set -- $@
218         IFS="$OIFS"
219         if [ -n "$1" ]; then
220                 printf %s .
221         else
222                 shift
223         fi
224         while [ -n "$2" ]; do
225                 printf "/%s" "$1"
226                 shift
227         done
228         printf "\n"
229 }
230
231 config_mkdirs()
232 {
233         local e=0 f d
234         for f; do
235                 [ -n "$f" ] || continue
236                 d="$(dirname "$f")"
237                 if [ ! -d "$d" ]; then
238                         if type install >/dev/null 2>&1; then
239                                 install -d "$d" || e=$?
240                         else
241                                 mkdir "$d" || e=$?
242                         fi
243                 fi
244         done
245         return $e
246 }
247
248 list_resolv()
249 {
250         [ -d "$IFACEDIR" ] || return 0
251
252         local report=false list= retval=0 cmd="$1" excl=
253         shift
254
255         if [ "$cmd" = "-x" ]; then
256                 IF_EXCLUSIVE=1
257                 shift
258         fi
259
260         case "$IF_EXCLUSIVE" in
261         [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
262                 if [ -d "$EXCLUSIVEDIR" ]; then
263                         cd "$EXCLUSIVEDIR"
264                         for i in *; do
265                                 if [ -f "$i" ]; then
266                                         list="${i#* }"
267                                         break
268                                 fi
269                         done
270                 fi
271                 excl=true
272                 ;;
273         *)
274                 excl=false
275                 ;;
276         esac
277
278         # If we have an interface ordering list, then use that.
279         # It works by just using pathname expansion in the interface directory.
280         if [ -n "$1" ]; then
281                 list="$*"
282                 $force || report=true
283         elif ! $excl; then
284                 cd "$IFACEDIR"
285                 for i in $interface_order; do
286                         [ -f "$i" ] && list="$list $i"
287                         for ii in "$i":* "$i".*; do
288                                 [ -f "$ii" ] && list="$list $ii"
289                         done
290                 done
291                 for i in $dynamic_order; do
292                         if [ -e "$i" -a ! -e "$METRICDIR/"*" $i" ]; then
293                                 list="$list $i"
294                         fi
295                         for ii in "$i":* "$i".*; do
296                                 if [ -f "$ii" -a ! -e "$METRICDIR/"*" $ii" ]; then
297                                         list="$list $ii"
298                                 fi
299                         done
300                 done
301                 if [ -d "$METRICDIR" ]; then
302                         cd "$METRICDIR"
303                         for i in *; do
304                                 [ -f "$i" ] && list="$list ${i#* }"
305                         done
306                 fi
307                 list="$list *"
308         fi
309
310         cd "$IFACEDIR"
311         retval=1
312         for i in $(uniqify $list); do
313                 # Only list interfaces which we really have
314                 if ! [ -f "$i" ]; then
315                         if $report; then
316                                 echo "No resolv.conf for interface $i" >&2
317                                 retval=2
318                         fi
319                         continue
320                 fi
321                 
322                 if [ "$cmd" = i -o "$cmd" = "-i" ]; then
323                         printf %s "$i "
324                 else
325                         echo_resolv "$i"
326                 fi
327                 [ $? = 0 -a "$retval" = 1 ] && retval=0
328         done
329         [ "$cmd" = i -o "$cmd" = "-i" ] && echo
330         return $retval
331 }
332
333 list_remove() {
334         local list= e= l= result= found= retval=0
335
336         [ -z "$2" ] && return 0
337         eval list=\"\$$1\"
338         shift
339
340         set -f
341         for e; do
342                 found=false
343                 for l in $list; do
344                         case "$e" in
345                         $l) found=true;;
346                         esac
347                         $found && break
348                 done
349                 if $found; then
350                         retval=$(($retval + 1))
351                 else
352                         result="$result $e"
353                 fi
354         done
355         set +f
356         echo "${result# *}"
357         return $retval
358 }
359
360 echo_prepend()
361 {
362         echo "# Generated by resolvconf"
363         if [ -n "$search_domains" ]; then
364                 echo "search $search_domains"
365         fi
366         for n in $name_servers; do
367                 echo "nameserver $n"
368         done
369         echo
370 }
371
372 echo_append()
373 {
374         echo "# Generated by resolvconf"
375         if [ -n "$search_domains_append" ]; then
376                 echo "search $search_domains_append"
377         fi
378         for n in $name_servers_append; do
379                 echo "nameserver $n"
380         done
381         echo
382 }
383
384 replace()
385 {
386         local r= k= f= v= val= sub=
387
388         while read -r keyword value; do
389                 for r in $replace; do
390                         k="${r%%/*}"
391                         r="${r#*/}"
392                         f="${r%%/*}"
393                         r="${r#*/}"
394                         v="${r%%/*}"
395                         case "$keyword" in
396                         $k)
397                                 case "$value" in
398                                 $f) value="$v";;
399                                 esac
400                                 ;;
401                         esac
402                 done
403                 val=
404                 for sub in $value; do
405                         for r in $replace_sub; do
406                                 k="${r%%/*}"
407                                 r="${r#*/}"
408                                 f="${r%%/*}"
409                                 r="${r#*/}"
410                                 v="${r%%/*}"
411                                 case "$keyword" in
412                                 $k)
413                                         case "$sub" in
414                                         $f) sub="$v";;
415                                         esac
416                                         ;;
417                                 esac
418                         done
419                         val="$val${val:+ }$sub"
420                 done
421                 printf "%s %s\n" "$keyword" "$val"
422         done
423 }
424
425 make_vars()
426 {
427         local newdomains= d= dn= newns= ns= x=
428
429         # Clear variables
430         DOMAIN=
431         DOMAINS=
432         SEARCH=
433         NAMESERVERS=
434         LOCALNAMESERVERS=
435         
436
437         if [ -n "$name_servers" -o -n "$search_domains" ]; then
438                 eval "$(echo_prepend | parse_resolv)"
439         fi
440         if [ -z "$VFLAG" ]; then
441                 list_resolv -x -l "$@" >/dev/null && x="-x"
442                 eval "$(list_resolv $x -l "$@" | replace | parse_resolv)"
443         fi
444         if [ -n "$name_servers_append" -o -n "$search_domains_append" ]; then
445                 eval "$(echo_append | parse_resolv)"
446         fi
447
448         # Ensure that we only list each domain once
449         for d in $DOMAINS; do
450                 dn="${d%%:*}"
451                 list_remove domain_blacklist "$dn" >/dev/null || continue
452                 case " $newdomains" in
453                 *" ${dn}:"*) continue;;
454                 esac
455                 newns=
456                 for nd in $DOMAINS; do
457                         if [ "$dn" = "${nd%%:*}" ]; then
458                                 ns="${nd#*:}"
459                                 while [ -n "$ns" ]; do
460                                         case ",$newns," in
461                                         *,${ns%%,*},*) ;;
462                                         *) list_remove name_server_blacklist \
463                                                 "${ns%%,*}" >/dev/null \
464                                         && newns="$newns${newns:+,}${ns%%,*}";;
465                                         esac
466                                         [ "$ns" = "${ns#*,}" ] && break
467                                         ns="${ns#*,}"
468                                 done
469                         fi
470                 done
471                 if [ -n "$newns" ]; then
472                         newdomains="$newdomains${newdomains:+ }$dn:$newns"
473                 fi
474         done
475         DOMAIN="$(list_remove domain_blacklist $DOMAIN)"
476         SEARCH="$(uniqify $SEARCH)"
477         SEARCH="$(list_remove domain_blacklist $SEARCH)"
478         NAMESERVERS="$(uniqify $NAMESERVERS)"
479         NAMESERVERS="$(list_remove name_server_blacklist $NAMESERVERS)"
480         LOCALNAMESERVERS="$(uniqify $LOCALNAMESERVERS)"
481         LOCALNAMESERVERS="$(list_remove name_server_blacklist $LOCALNAMESERVERS)"
482         echo "DOMAIN='$DOMAIN'"
483         echo "SEARCH='$SEARCH'"
484         echo "NAMESERVERS='$NAMESERVERS'"
485         echo "LOCALNAMESERVERS='$LOCALNAMESERVERS'"
486         echo "DOMAINS='$newdomains'"
487 }
488
489 force=false
490 VFLAG=
491 while getopts a:Dd:fhIilm:puvVx OPT; do
492         case "$OPT" in
493         f) force=true;;
494         h) usage;;
495         m) IF_METRIC="$OPTARG";;
496         p) IF_PRIVATE=1;;
497         V)
498                 VFLAG=1
499                 if [ "$local_nameservers" = \
500                     "127.* 0.0.0.0 255.255.255.255 ::1" ]
501                 then
502                         local_nameservers=
503                 fi
504                 ;;
505         x) IF_EXCLUSIVE=1;;
506         '?') ;;
507         *) cmd="$OPT"; iface="$OPTARG";;
508         esac
509 done
510 shift $(($OPTIND - 1))
511 args="$iface${iface:+ }$*"
512
513 # -I inits the state dir
514 if [ "$cmd" = I ]; then
515         if [ -d "$VARDIR" ]; then
516                 rm -rf "$VARDIR"/*
517         fi
518         exit $?
519 fi
520
521 # -D ensures that the listed config file base dirs exist
522 if [ "$cmd" = D ]; then
523         config_mkdirs "$@"
524         exit $?
525 fi
526
527 # -l lists our resolv files, optionally for a specific interface
528 if [ "$cmd" = l -o "$cmd" = i ]; then
529         list_resolv "$cmd" "$args"
530         exit $?
531 fi
532
533 # Not normally needed, but subscribers should be able to run independently
534 if [ "$cmd" = v -o -n "$VFLAG" ]; then
535         make_vars "$iface"
536         exit $?
537 fi
538
539 # Test that we have valid options
540 if [ "$cmd" = a -o "$cmd" = d ]; then
541         if [ -z "$iface" ]; then
542                 usage "Interface not specified"
543         fi
544 elif [ "$cmd" != u ]; then
545         [ -n "$cmd" -a "$cmd" != h ] && usage "Unknown option $cmd"
546         usage
547 fi
548
549 if [ "$cmd" = a ]; then
550         for x in '/' \\ ' ' '*'; do
551                 case "$iface" in
552                 *[$x]*) error_exit "$x not allowed in interface name";;
553                 esac
554         done
555         for x in '.' '-' '~'; do
556                 case "$iface" in
557                 [$x]*) error_exit \
558                         "$x not allowed at start of interface name";;
559                 esac
560         done
561         [ "$cmd" = a -a -t 0 ] && error_exit "No file given via stdin"
562 fi
563
564 if [ ! -d "$VARDIR" ]; then
565         if [ -L "$VARDIR" ]; then
566                 dir="$(readlink "$VARDIR")"
567                 # link maybe relative
568                 cd "${VARDIR%/*}"
569                 if ! mkdir -m 0755 -p "$dir"; then
570                         error_exit "Failed to create needed" \
571                                 "directory $dir"
572                 fi
573         else
574                 if ! mkdir -m 0755 -p "$VARDIR"; then
575                         error_exit "Failed to create needed" \
576                                 "directory $VARDIR"
577                 fi
578         fi
579 fi
580
581 if [ ! -d "$IFACEDIR" ]; then
582         mkdir -m 0755 -p "$IFACEDIR" || \
583                 error_exit "Failed to create needed directory $IFACEDIR"
584         if [ "$cmd" = d ]; then
585                 # Provide the same error messages as below
586                 if ! ${force}; then
587                         cd "$IFACEDIR"
588                         for i in $args; do
589                                 warn "No resolv.conf for interface $i"
590                         done
591                 fi
592                 ${force}
593                 exit $?
594         fi
595 else
596 fi
597
598 # An interface was added, changed, deleted or a general update was called.
599 # Due to exclusivity we need to ensure that this is an atomic operation.
600 # Our subscribers *may* need this as well if the init system is sub par.
601 # As such we spinlock at this point as best we can.
602 # We don't use flock(1) because it's not widely available and normally resides
603 # in /usr which we do our very best to operate without.
604 [ -w "$VARDIR" ] || error_exit "Cannot write to $LOCKDIR"
605 : ${lock_timeout:=10}
606 while true; do
607         if mkdir "$LOCKDIR" 2>/dev/null; then
608                 trap 'rm -rf "$LOCKDIR";' EXIT
609                 trap 'rm -rf "$LOCKDIR"; exit 1' INT QUIT ABRT SEGV ALRM TERM
610                 echo $$ >"$LOCKDIR/pid"
611                 break
612         fi
613         pid=$(cat "$LOCKDIR/pid")
614         if ! kill -0 "$pid"; then
615                 warn "clearing stale lock pid $pid"
616                 rm -rf "$LOCKDIR"
617                 continue
618         fi
619         lock_timeout=$(($lock_timeout - 1))
620         if [ "$lock_timeout" -le 0 ]; then
621                 error_exit "timed out waiting for lock from pid $pid"
622         fi
623         sleep 1
624 done
625
626 case "$cmd" in
627 a)
628         # Read resolv.conf from stdin
629         resolv="$(cat)"
630         changed=false
631         changedfile=false
632         # If what we are given matches what we have, then do nothing
633         if [ -e "$IFACEDIR/$iface" ]; then
634                 if [ "$(echo "$resolv")" != \
635                         "$(cat "$IFACEDIR/$iface")" ]
636                 then
637                         changed=true
638                         changedfile=true
639                 fi
640         else
641                 changed=true
642                 changedfile=true
643         fi
644
645         # Set metric and private before creating the interface resolv.conf file
646         # to ensure that it will have the correct flags
647         [ ! -d "$METRICDIR" ] && mkdir "$METRICDIR"
648         oldmetric="$METRICDIR/"*" $iface"
649         newmetric=
650         if [ -n "$IF_METRIC" ]; then
651                 # Pad metric to 6 characters, so 5 is less than 10
652                 while [ ${#IF_METRIC} -le 6 ]; do
653                         IF_METRIC="0$IF_METRIC"
654                 done
655                 newmetric="$METRICDIR/$IF_METRIC $iface"
656         fi
657         rm -f "$METRICDIR/"*" $iface"
658         [ "$oldmetric" != "$newmetric" -a \
659             "$oldmetric" != "$METRICDIR/* $iface" ] &&
660                 changed=true
661         [ -n "$newmetric" ] && echo " " >"$newmetric"
662
663         case "$IF_PRIVATE" in
664         [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
665                 if [ ! -d "$PRIVATEDIR" ]; then
666                         [ -e "$PRIVATEDIR" ] && rm "$PRIVATEDIR"
667                         mkdir "$PRIVATEDIR"
668                 fi
669                 [ -e "$PRIVATEDIR/$iface" ] || changed=true
670                 [ -d "$PRIVATEDIR" ] && echo " " >"$PRIVATEDIR/$iface"
671                 ;;
672         *)
673                 if [ -e "$PRIVATEDIR/$iface" ]; then
674                         rm -f "$PRIVATEDIR/$iface"
675                         changed=true
676                 fi
677                 ;;
678         esac
679
680         oldexcl=
681         for x in "$EXCLUSIVEDIR/"*" $iface"; do
682                 if [ -f "$x" ]; then
683                         oldexcl="$x"
684                         break
685                 fi
686         done
687         case "$IF_EXCLUSIVE" in
688         [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
689                 if [ ! -d "$EXCLUSIVEDIR" ]; then
690                         [ -e "$EXCLUSIVEDIR" ] && rm "$EXCLUSIVEDIR"
691                         mkdir "$EXCLUSIVEDIR"
692                 fi
693                 cd "$EXCLUSIVEDIR"
694                 for x in *; do
695                         [ -f "$x" ] && break
696                 done
697                 if [ "${x#* }" != "$iface" ]; then
698                         if [ "$x" = "${x% *}" ]; then
699                                 x=10000000
700                         else
701                                 x="${x% *}"
702                         fi
703                         if [ "$x" = "0000000" ]; then
704                                 warn "exclusive underflow"
705                         else
706                                 x=$(($x - 1))
707                         fi
708                         if [ -d "$EXCLUSIVEDIR" ]; then
709                                 echo " " >"$EXCLUSIVEDIR/$x $iface"
710                         fi
711                         changed=true
712                 fi
713                 ;;
714         *)
715                 if [ -f "$oldexcl" ]; then
716                         rm -f "$oldexcl"
717                         changed=true
718                 fi
719                 ;;
720         esac
721
722         if $changedfile; then
723                 printf %s "$resolv" >"$IFACEDIR/$iface" || exit $?
724         else
725                 exit 0
726         fi
727         unset changed changedfile oldmetric newmetric x oldexcl
728         ;;
729
730 d)
731         # Delete any existing information about the interface
732         cd "$IFACEDIR"
733         changed=false
734         for i in $args; do
735                 if [ -e "$i" ]; then
736                         changed=true
737                 elif ! ${force}; then
738                         warn "No resolv.conf for interface $i"
739                 fi
740                 rm -f "$i" "$METRICDIR/"*" $i" \
741                         "$PRIVATEDIR/$i" \
742                         "$EXCLUSIVEDIR/"*" $i" || exit $?
743         done
744         if ! ${changed}; then
745                 # Set the return code based on the forced flag
746                 ${force}
747                 exit $?
748         fi
749         unset changed i
750         ;;
751 esac
752
753 case "${resolvconf:-YES}" in
754 [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) ;;
755 *) exit 0;;
756 esac
757
758 eval "$(make_vars)"
759 export RESOLVCONF DOMAINS SEARCH NAMESERVERS LOCALNAMESERVERS
760 : ${list_resolv:=list_resolv -l}
761 retval=0
762 for script in "$LIBEXECDIR"/*; do
763         if [ -f "$script" ]; then
764                 eval script_enabled="\$${script##*/}"
765                 case "${script_enabled:-YES}" in
766                 [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) ;;
767                 *) continue;;
768                 esac
769                 if [ -x "$script" ]; then
770                         "$script" "$cmd" "$iface"
771                 else
772                         (set -- "$cmd" "$iface"; . "$script")
773                 fi
774                 retval=$(($retval + $?))
775         fi
776 done
777 exit $retval