Save the initial working directory and change to it just before running
[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 IFACEDIR="$VARDIR/interfaces"
54 METRICDIR="$VARDIR/metrics"
55 PRIVATEDIR="$VARDIR/private"
56 EXCLUSIVEDIR="$VARDIR/exclusive"
57 LOCKDIR="$VARDIR/lock"
58 _PWD="$PWD"
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         case "$IF_EXCLUSIVE" in
256         [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
257                 if [ -d "$EXCLUSIVEDIR" ]; then
258                         cd "$EXCLUSIVEDIR"
259                         for i in *; do
260                                 if [ -f "$i" ]; then
261                                         list="${i#* }"
262                                         break
263                                 fi
264                         done
265                 fi
266                 excl=true
267                 ;;
268         *)
269                 excl=false
270                 ;;
271         esac
272
273         # If we have an interface ordering list, then use that.
274         # It works by just using pathname expansion in the interface directory.
275         if [ -n "$1" ]; then
276                 list="$*"
277                 $force || report=true
278         elif ! $excl; then
279                 cd "$IFACEDIR"
280                 for i in $interface_order; do
281                         [ -f "$i" ] && list="$list $i"
282                         for ii in "$i":* "$i".*; do
283                                 [ -f "$ii" ] && list="$list $ii"
284                         done
285                 done
286                 for i in $dynamic_order; do
287                         if [ -e "$i" -a ! -e "$METRICDIR/"*" $i" ]; then
288                                 list="$list $i"
289                         fi
290                         for ii in "$i":* "$i".*; do
291                                 if [ -f "$ii" -a ! -e "$METRICDIR/"*" $ii" ]; then
292                                         list="$list $ii"
293                                 fi
294                         done
295                 done
296                 if [ -d "$METRICDIR" ]; then
297                         cd "$METRICDIR"
298                         for i in *; do
299                                 [ -f "$i" ] && list="$list ${i#* }"
300                         done
301                 fi
302                 list="$list *"
303         fi
304
305         cd "$IFACEDIR"
306         retval=1
307         for i in $(uniqify $list); do
308                 # Only list interfaces which we really have
309                 if ! [ -f "$i" ]; then
310                         if $report; then
311                                 echo "No resolv.conf for interface $i" >&2
312                                 retval=2
313                         fi
314                         continue
315                 fi
316                 
317                 if [ "$cmd" = i -o "$cmd" = "-i" ]; then
318                         printf %s "$i "
319                 else
320                         echo_resolv "$i"
321                 fi
322                 [ $? = 0 -a "$retval" = 1 ] && retval=0
323         done
324         [ "$cmd" = i -o "$cmd" = "-i" ] && echo
325         return $retval
326 }
327
328 list_remove() {
329         local list= e= l= result= found= retval=0
330
331         [ -z "$2" ] && return 0
332         eval list=\"\$$1\"
333         shift
334
335         set -f
336         for e; do
337                 found=false
338                 for l in $list; do
339                         case "$e" in
340                         $l) found=true;;
341                         esac
342                         $found && break
343                 done
344                 if $found; then
345                         retval=$(($retval + 1))
346                 else
347                         result="$result $e"
348                 fi
349         done
350         set +f
351         echo "${result# *}"
352         return $retval
353 }
354
355 echo_prepend()
356 {
357         echo "# Generated by resolvconf"
358         if [ -n "$search_domains" ]; then
359                 echo "search $search_domains"
360         fi
361         for n in $name_servers; do
362                 echo "nameserver $n"
363         done
364         echo
365 }
366
367 echo_append()
368 {
369         echo "# Generated by resolvconf"
370         if [ -n "$search_domains_append" ]; then
371                 echo "search $search_domains_append"
372         fi
373         for n in $name_servers_append; do
374                 echo "nameserver $n"
375         done
376         echo
377 }
378
379 replace()
380 {
381         local r= k= f= v= val= sub=
382
383         while read -r keyword value; do
384                 for r in $replace; do
385                         k="${r%%/*}"
386                         r="${r#*/}"
387                         f="${r%%/*}"
388                         r="${r#*/}"
389                         v="${r%%/*}"
390                         case "$keyword" in
391                         $k)
392                                 case "$value" in
393                                 $f) value="$v";;
394                                 esac
395                                 ;;
396                         esac
397                 done
398                 val=
399                 for sub in $value; do
400                         for r in $replace_sub; do
401                                 k="${r%%/*}"
402                                 r="${r#*/}"
403                                 f="${r%%/*}"
404                                 r="${r#*/}"
405                                 v="${r%%/*}"
406                                 case "$keyword" in
407                                 $k)
408                                         case "$sub" in
409                                         $f) sub="$v";;
410                                         esac
411                                         ;;
412                                 esac
413                         done
414                         val="$val${val:+ }$sub"
415                 done
416                 printf "%s %s\n" "$keyword" "$val"
417         done
418 }
419
420 make_vars()
421 {
422         local newdomains= d= dn= newns= ns=
423
424         # Clear variables
425         DOMAIN=
426         DOMAINS=
427         SEARCH=
428         NAMESERVERS=
429         LOCALNAMESERVERS=
430         
431         if [ -n "$name_servers" -o -n "$search_domains" ]; then
432                 eval "$(echo_prepend | parse_resolv)"
433         fi
434         if [ -z "$VFLAG" ]; then
435                 IF_EXCLUSIVE=1
436                 list_resolv -i "$@" >/dev/null || IF_EXCLUSIVE=0
437                 eval "$(list_resolv -l "$@" | replace | parse_resolv)"
438         fi
439         if [ -n "$name_servers_append" -o -n "$search_domains_append" ]; then
440                 eval "$(echo_append | parse_resolv)"
441         fi
442
443         # Ensure that we only list each domain once
444         for d in $DOMAINS; do
445                 dn="${d%%:*}"
446                 list_remove domain_blacklist "$dn" >/dev/null || continue
447                 case " $newdomains" in
448                 *" ${dn}:"*) continue;;
449                 esac
450                 newns=
451                 for nd in $DOMAINS; do
452                         if [ "$dn" = "${nd%%:*}" ]; then
453                                 ns="${nd#*:}"
454                                 while [ -n "$ns" ]; do
455                                         case ",$newns," in
456                                         *,${ns%%,*},*) ;;
457                                         *) list_remove name_server_blacklist \
458                                                 "${ns%%,*}" >/dev/null \
459                                         && newns="$newns${newns:+,}${ns%%,*}";;
460                                         esac
461                                         [ "$ns" = "${ns#*,}" ] && break
462                                         ns="${ns#*,}"
463                                 done
464                         fi
465                 done
466                 if [ -n "$newns" ]; then
467                         newdomains="$newdomains${newdomains:+ }$dn:$newns"
468                 fi
469         done
470         DOMAIN="$(list_remove domain_blacklist $DOMAIN)"
471         SEARCH="$(uniqify $SEARCH)"
472         SEARCH="$(list_remove domain_blacklist $SEARCH)"
473         NAMESERVERS="$(uniqify $NAMESERVERS)"
474         NAMESERVERS="$(list_remove name_server_blacklist $NAMESERVERS)"
475         LOCALNAMESERVERS="$(uniqify $LOCALNAMESERVERS)"
476         LOCALNAMESERVERS="$(list_remove name_server_blacklist $LOCALNAMESERVERS)"
477         echo "DOMAIN='$DOMAIN'"
478         echo "SEARCH='$SEARCH'"
479         echo "NAMESERVERS='$NAMESERVERS'"
480         echo "LOCALNAMESERVERS='$LOCALNAMESERVERS'"
481         echo "DOMAINS='$newdomains'"
482 }
483
484 force=false
485 VFLAG=
486 while getopts a:Dd:fhIilm:puvVx OPT; do
487         case "$OPT" in
488         f) force=true;;
489         h) usage;;
490         m) IF_METRIC="$OPTARG";;
491         p) IF_PRIVATE=1;;
492         V)
493                 VFLAG=1
494                 if [ "$local_nameservers" = \
495                     "127.* 0.0.0.0 255.255.255.255 ::1" ]
496                 then
497                         local_nameservers=
498                 fi
499                 ;;
500         x) IF_EXCLUSIVE=1;;
501         '?') ;;
502         *) cmd="$OPT"; iface="$OPTARG";;
503         esac
504 done
505 shift $(($OPTIND - 1))
506 args="$iface${iface:+ }$*"
507
508 # -I inits the state dir
509 if [ "$cmd" = I ]; then
510         if [ -d "$VARDIR" ]; then
511                 rm -rf "$VARDIR"/*
512         fi
513         exit $?
514 fi
515
516 # -D ensures that the listed config file base dirs exist
517 if [ "$cmd" = D ]; then
518         config_mkdirs "$@"
519         exit $?
520 fi
521
522 # -l lists our resolv files, optionally for a specific interface
523 if [ "$cmd" = l -o "$cmd" = i ]; then
524         list_resolv "$cmd" "$args"
525         exit $?
526 fi
527
528 # Not normally needed, but subscribers should be able to run independently
529 if [ "$cmd" = v -o -n "$VFLAG" ]; then
530         make_vars "$iface"
531         exit $?
532 fi
533
534 # Test that we have valid options
535 if [ "$cmd" = a -o "$cmd" = d ]; then
536         if [ -z "$iface" ]; then
537                 usage "Interface not specified"
538         fi
539 elif [ "$cmd" != u ]; then
540         [ -n "$cmd" -a "$cmd" != h ] && usage "Unknown option $cmd"
541         usage
542 fi
543
544 if [ "$cmd" = a ]; then
545         for x in '/' \\ ' ' '*'; do
546                 case "$iface" in
547                 *[$x]*) error_exit "$x not allowed in interface name";;
548                 esac
549         done
550         for x in '.' '-' '~'; do
551                 case "$iface" in
552                 [$x]*) error_exit \
553                         "$x not allowed at start of interface name";;
554                 esac
555         done
556         [ "$cmd" = a -a -t 0 ] && error_exit "No file given via stdin"
557 fi
558
559 if [ ! -d "$VARDIR" ]; then
560         if [ -L "$VARDIR" ]; then
561                 dir="$(readlink "$VARDIR")"
562                 # link maybe relative
563                 cd "${VARDIR%/*}"
564                 if ! mkdir -m 0755 -p "$dir"; then
565                         error_exit "Failed to create needed" \
566                                 "directory $dir"
567                 fi
568         else
569                 if ! mkdir -m 0755 -p "$VARDIR"; then
570                         error_exit "Failed to create needed" \
571                                 "directory $VARDIR"
572                 fi
573         fi
574 fi
575
576 if [ ! -d "$IFACEDIR" ]; then
577         mkdir -m 0755 -p "$IFACEDIR" || \
578                 error_exit "Failed to create needed directory $IFACEDIR"
579         if [ "$cmd" = d ]; then
580                 # Provide the same error messages as below
581                 if ! ${force}; then
582                         cd "$IFACEDIR"
583                         for i in $args; do
584                                 warn "No resolv.conf for interface $i"
585                         done
586                 fi
587                 ${force}
588                 exit $?
589         fi
590 fi
591
592 # An interface was added, changed, deleted or a general update was called.
593 # Due to exclusivity we need to ensure that this is an atomic operation.
594 # Our subscribers *may* need this as well if the init system is sub par.
595 # As such we spinlock at this point as best we can.
596 # We don't use flock(1) because it's not widely available and normally resides
597 # in /usr which we do our very best to operate without.
598 [ -w "$VARDIR" ] || error_exit "Cannot write to $LOCKDIR"
599 : ${lock_timeout:=10}
600 while true; do
601         if mkdir "$LOCKDIR" 2>/dev/null; then
602                 trap 'rm -rf "$LOCKDIR";' EXIT
603                 trap 'rm -rf "$LOCKDIR"; exit 1' INT QUIT ABRT SEGV ALRM TERM
604                 echo $$ >"$LOCKDIR/pid"
605                 break
606         fi
607         pid=$(cat "$LOCKDIR/pid")
608         if ! kill -0 "$pid"; then
609                 warn "clearing stale lock pid $pid"
610                 rm -rf "$LOCKDIR"
611                 continue
612         fi
613         lock_timeout=$(($lock_timeout - 1))
614         if [ "$lock_timeout" -le 0 ]; then
615                 error_exit "timed out waiting for lock from pid $pid"
616         fi
617         sleep 1
618 done
619
620 case "$cmd" in
621 a)
622         # Read resolv.conf from stdin
623         resolv="$(cat)"
624         changed=false
625         changedfile=false
626         # If what we are given matches what we have, then do nothing
627         if [ -e "$IFACEDIR/$iface" ]; then
628                 if [ "$(echo "$resolv")" != \
629                         "$(cat "$IFACEDIR/$iface")" ]
630                 then
631                         changed=true
632                         changedfile=true
633                 fi
634         else
635                 changed=true
636                 changedfile=true
637         fi
638
639         # Set metric and private before creating the interface resolv.conf file
640         # to ensure that it will have the correct flags
641         [ ! -d "$METRICDIR" ] && mkdir "$METRICDIR"
642         oldmetric="$METRICDIR/"*" $iface"
643         newmetric=
644         if [ -n "$IF_METRIC" ]; then
645                 # Pad metric to 6 characters, so 5 is less than 10
646                 while [ ${#IF_METRIC} -le 6 ]; do
647                         IF_METRIC="0$IF_METRIC"
648                 done
649                 newmetric="$METRICDIR/$IF_METRIC $iface"
650         fi
651         rm -f "$METRICDIR/"*" $iface"
652         [ "$oldmetric" != "$newmetric" -a \
653             "$oldmetric" != "$METRICDIR/* $iface" ] &&
654                 changed=true
655         [ -n "$newmetric" ] && echo " " >"$newmetric"
656
657         case "$IF_PRIVATE" in
658         [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
659                 if [ ! -d "$PRIVATEDIR" ]; then
660                         [ -e "$PRIVATEDIR" ] && rm "$PRIVATEDIR"
661                         mkdir "$PRIVATEDIR"
662                 fi
663                 [ -e "$PRIVATEDIR/$iface" ] || changed=true
664                 [ -d "$PRIVATEDIR" ] && echo " " >"$PRIVATEDIR/$iface"
665                 ;;
666         *)
667                 if [ -e "$PRIVATEDIR/$iface" ]; then
668                         rm -f "$PRIVATEDIR/$iface"
669                         changed=true
670                 fi
671                 ;;
672         esac
673
674         oldexcl=
675         for x in "$EXCLUSIVEDIR/"*" $iface"; do
676                 if [ -f "$x" ]; then
677                         oldexcl="$x"
678                         break
679                 fi
680         done
681         case "$IF_EXCLUSIVE" in
682         [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
683                 if [ ! -d "$EXCLUSIVEDIR" ]; then
684                         [ -e "$EXCLUSIVEDIR" ] && rm "$EXCLUSIVEDIR"
685                         mkdir "$EXCLUSIVEDIR"
686                 fi
687                 cd "$EXCLUSIVEDIR"
688                 for x in *; do
689                         [ -f "$x" ] && break
690                 done
691                 if [ "${x#* }" != "$iface" ]; then
692                         if [ "$x" = "${x% *}" ]; then
693                                 x=10000000
694                         else
695                                 x="${x% *}"
696                         fi
697                         if [ "$x" = "0000000" ]; then
698                                 warn "exclusive underflow"
699                         else
700                                 x=$(($x - 1))
701                         fi
702                         if [ -d "$EXCLUSIVEDIR" ]; then
703                                 echo " " >"$EXCLUSIVEDIR/$x $iface"
704                         fi
705                         changed=true
706                 fi
707                 ;;
708         *)
709                 if [ -f "$oldexcl" ]; then
710                         rm -f "$oldexcl"
711                         changed=true
712                 fi
713                 ;;
714         esac
715
716         if $changedfile; then
717                 printf "%s\n" "$resolv" >"$IFACEDIR/$iface" || exit $?
718         elif ! $changed; then
719                 exit 0
720         fi
721         unset changed changedfile oldmetric newmetric x oldexcl
722         ;;
723
724 d)
725         # Delete any existing information about the interface
726         cd "$IFACEDIR"
727         changed=false
728         for i in $args; do
729                 if [ -e "$i" ]; then
730                         changed=true
731                 elif ! ${force}; then
732                         warn "No resolv.conf for interface $i"
733                 fi
734                 rm -f "$i" "$METRICDIR/"*" $i" \
735                         "$PRIVATEDIR/$i" \
736                         "$EXCLUSIVEDIR/"*" $i" || exit $?
737         done
738         if ! ${changed}; then
739                 # Set the return code based on the forced flag
740                 ${force}
741                 exit $?
742         fi
743         unset changed i
744         ;;
745 esac
746
747 case "${resolvconf:-YES}" in
748 [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) ;;
749 *) exit 0;;
750 esac
751
752 eval "$(make_vars)"
753 export RESOLVCONF DOMAINS SEARCH NAMESERVERS LOCALNAMESERVERS
754 : ${list_resolv:=list_resolv -l}
755 retval=0
756
757 # Run scripts in the same directory resolvconf is run from
758 # in case any scripts accidently dump files in the wrong place.
759 cd "$_PWD"
760 for script in "$LIBEXECDIR"/*; do
761         if [ -f "$script" ]; then
762                 eval script_enabled="\$${script##*/}"
763                 case "${script_enabled:-YES}" in
764                 [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) ;;
765                 *) continue;;
766                 esac
767                 if [ -x "$script" ]; then
768                         "$script" "$cmd" "$iface"
769                 else
770                         (set -- "$cmd" "$iface"; . "$script")
771                 fi
772                 retval=$(($retval + $?))
773         fi
774 done
775 exit $retval