xref: /netbsd-src/external/bsd/openresolv/dist/resolvconf.in (revision 59c22029c4938f7f5a598754771a670ab2ba89b8)
1793621c9Sroy#!/bin/sh
2*59c22029Sroy# Copyright (c) 2007-2023 Roy Marples
3793621c9Sroy# All rights reserved
4793621c9Sroy
5793621c9Sroy# Redistribution and use in source and binary forms, with or without
6793621c9Sroy# modification, are permitted provided that the following conditions
7793621c9Sroy# are met:
8793621c9Sroy#     * Redistributions of source code must retain the above copyright
9793621c9Sroy#       notice, this list of conditions and the following disclaimer.
10793621c9Sroy#     * Redistributions in binary form must reproduce the above
11793621c9Sroy#       copyright notice, this list of conditions and the following
12793621c9Sroy#       disclaimer in the documentation and/or other materials provided
13793621c9Sroy#       with the distribution.
14793621c9Sroy#
15793621c9Sroy# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16793621c9Sroy# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17793621c9Sroy# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18793621c9Sroy# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19793621c9Sroy# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20793621c9Sroy# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21793621c9Sroy# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22793621c9Sroy# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23793621c9Sroy# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24793621c9Sroy# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25793621c9Sroy# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26793621c9Sroy
27793621c9SroyRESOLVCONF="$0"
28*59c22029SroyOPENRESOLV_VERSION="3.13.2"
29793621c9SroySYSCONFDIR=@SYSCONFDIR@
30793621c9SroyLIBEXECDIR=@LIBEXECDIR@
31793621c9SroyVARDIR=@VARDIR@
329d6c0475SroyRCDIR=@RCDIR@
339d6c0475SroyRESTARTCMD=@RESTARTCMD@
34c3da4b2aSroy
35292189d7Sroyif [ "$1" = "--version" ]; then
36292189d7Sroy	echo "openresolv $OPENRESOLV_VERSION"
379cbb0fe2Sroy	echo "Copyright (c) 2007-2020 Roy Marples"
38292189d7Sroy	exit 0
39292189d7Sroyfi
40292189d7Sroy
41c3da4b2aSroy# Disregard dhcpcd setting
42e9917e6eSroyunset interface_order state_dir
43c3da4b2aSroy
44075ee3c1Sroy# If you change this, change the test in VFLAG and libc.in as well
45075ee3c1Sroylocal_nameservers="127.* 0.0.0.0 255.255.255.255 ::1"
46075ee3c1Sroy
479cbb0fe2Sroydynamic_order="tap[0-9]* tun[0-9]* vpn vpn[0-9]* wg[0-9]* ppp[0-9]* ippp[0-9]*"
48075ee3c1Sroyinterface_order="lo lo[0-9]*"
49075ee3c1Sroyname_server_blacklist="0.0.0.0"
50075ee3c1Sroy
51793621c9Sroy# Support original resolvconf configuration layout
52793621c9Sroy# as well as the openresolv config file
53793621c9Sroyif [ -f "$SYSCONFDIR"/resolvconf.conf ]; then
54793621c9Sroy	. "$SYSCONFDIR"/resolvconf.conf
55793621c9Sroy	[ -n "$state_dir" ] && VARDIR="$state_dir"
56793621c9Sroyelif [ -d "$SYSCONFDIR/resolvconf" ]; then
57793621c9Sroy	SYSCONFDIR="$SYSCONFDIR/resolvconf"
58793621c9Sroy	if [ -f "$SYSCONFDIR"/interface-order ]; then
59793621c9Sroy		interface_order="$(cat "$SYSCONFDIR"/interface-order)"
60793621c9Sroy	fi
61793621c9Sroyfi
629cbb0fe2Sroy
63793621c9SroyIFACEDIR="$VARDIR/interfaces"
64793621c9SroyMETRICDIR="$VARDIR/metrics"
65793621c9SroyPRIVATEDIR="$VARDIR/private"
664ac8d7d2SroyEXCLUSIVEDIR="$VARDIR/exclusive"
670949b2edSroyDEPRECATEDDIR="$VARDIR/deprecated"
68075ee3c1SroyLOCKDIR="$VARDIR/lock"
692644931fSroy_PWD="$PWD"
70793621c9Sroy
71075ee3c1Sroywarn()
72075ee3c1Sroy{
73075ee3c1Sroy	echo "$*" >&2
74075ee3c1Sroy}
75793621c9Sroy
76793621c9Sroyerror_exit()
77793621c9Sroy{
78793621c9Sroy	echo "$*" >&2
79793621c9Sroy	exit 1
80793621c9Sroy}
81793621c9Sroy
82793621c9Sroyusage()
83793621c9Sroy{
84793621c9Sroy	cat <<-EOF
859d6c0475Sroy	Usage: ${RESOLVCONF##*/} [options] command [argument]
86793621c9Sroy
87793621c9Sroy	Inform the system about any DNS updates.
88793621c9Sroy
899d6c0475Sroy	Commands:
90793621c9Sroy	  -a \$INTERFACE    Add DNS information to the specified interface
91793621c9Sroy	                   (DNS supplied via stdin in resolv.conf format)
920949b2edSroy	  -C \$PATTERN      Deprecate DNS information for matched interfaces
930949b2edSroy	  -c \$PATTERN      Configure DNS information for matched interfaces
94793621c9Sroy	  -d \$INTERFACE    Delete DNS information from the specified interface
959d6c0475Sroy	  -h               Show this help cruft
96793621c9Sroy	  -i [\$PATTERN]    Show interfaces that have supplied DNS information
97793621c9Sroy                   optionally from interfaces that match the specified
98793621c9Sroy                   pattern
999d6c0475Sroy	  -l [\$PATTERN]    Show DNS information, optionally from interfaces
1009d6c0475Sroy	                   that match the specified pattern
1019d6c0475Sroy
1029d6c0475Sroy	  -u               Run updates from our current DNS information
103292189d7Sroy	  --version        Echo the ${RESOLVCONF##*/} version
1049d6c0475Sroy
1059d6c0475Sroy	Options:
106292189d7Sroy	  -f               Ignore non existent interfaces
1079d6c0475Sroy	  -m metric        Give the added DNS information a metric
1089d6c0475Sroy	  -p               Mark the interface as private
1099d6c0475Sroy	  -x               Mark the interface as exclusive
1109d6c0475Sroy
1119d6c0475Sroy	Subscriber and System Init Commands:
1129d6c0475Sroy	  -I               Init the state dir
1139d6c0475Sroy	  -r \$SERVICE      Restart the system service
1149d6c0475Sroy	                   (restarting a non-existent or non-running service
1159d6c0475Sroy	                    should have no output and return 0)
1169d6c0475Sroy	  -R               Show the system service restart command
117793621c9Sroy	  -v [\$PATTERN]    echo NEWDOMAIN, NEWSEARCH and NEWNS variables to
118793621c9Sroy	  		   the console
1199d6c0475Sroy	  -V [\$PATTERN]    Same as -v, but only uses configuration in
1209d6c0475Sroy	                   $SYSCONFDIR/resolvconf.conf
121793621c9Sroy	EOF
122793621c9Sroy	[ -z "$1" ] && exit 0
123793621c9Sroy	echo
124793621c9Sroy	error_exit "$*"
125793621c9Sroy}
126793621c9Sroy
1272644931fSroy# Strip any trailing dot from each name as a FQDN does not belong
1282644931fSroy# in resolv.conf(5)
1292644931fSroy# If you think otherwise, capture a DNS trace and you'll see libc
1302644931fSroy# will strip it regardless.
1312644931fSroy# This also solves setting up duplicate zones in our subscribers.
132e37204c6Sroy# Also strip any comments denoted by #.
133e37204c6Sroyresolv_strip()
1342644931fSroy{
135e37204c6Sroy	space=
136e37204c6Sroy	for word; do
137e37204c6Sroy		case "$word" in
138e37204c6Sroy		\#*) break;;
139e37204c6Sroy		esac
140e37204c6Sroy		printf "%s%s" "$space${word%.}"
141e37204c6Sroy		space=" "
1422644931fSroy	done
1432644931fSroy	printf "\n"
1442644931fSroy}
1452644931fSroy
146292189d7Sroyprivate_iface()
147292189d7Sroy{
148292189d7Sroy	# Allow expansion
149292189d7Sroy	cd "$IFACEDIR"
150292189d7Sroy
151292189d7Sroy	# Public interfaces override private ones.
152292189d7Sroy	for p in $public_interfaces; do
153292189d7Sroy		case "$iface" in
154292189d7Sroy		"$p"|"$p":*) return 1;;
155292189d7Sroy		esac
156292189d7Sroy	done
157292189d7Sroy
158292189d7Sroy	if [ -e "$PRIVATEDIR/$iface" ]; then
159292189d7Sroy		return 0
160292189d7Sroy	fi
161292189d7Sroy
162292189d7Sroy	for p in $private_interfaces; do
163292189d7Sroy		case "$iface" in
164292189d7Sroy		"$p"|"$p":*) return 0;;
165292189d7Sroy		esac
166292189d7Sroy	done
167292189d7Sroy
168292189d7Sroy	# Not a private interface
169292189d7Sroy	return 1
170292189d7Sroy}
171292189d7Sroy
172793621c9Sroy# Parse resolv.conf's and make variables
173793621c9Sroy# for domain name servers, search name servers and global nameservers
174793621c9Sroyparse_resolv()
175793621c9Sroy{
176e37204c6Sroy	domain=
177e37204c6Sroy	new=true
178d8775c93Sroy	newns=
179e37204c6Sroy	ns=
180e37204c6Sroy	private=false
181e37204c6Sroy	search=
182793621c9Sroy
18302c18234Sroy	while read -r line; do
184e37204c6Sroy		stripped_line="$(resolv_strip ${line#* })"
185793621c9Sroy		case "$line" in
186793621c9Sroy		"# resolv.conf from "*)
187793621c9Sroy			if ${new}; then
188793621c9Sroy				iface="${line#\# resolv.conf from *}"
189793621c9Sroy				new=false
190292189d7Sroy				if private_iface "$iface"; then
191793621c9Sroy					private=true
192793621c9Sroy				else
193793621c9Sroy					private=false
1945bcbb70cSroy				fi
195793621c9Sroy			fi
196793621c9Sroy			;;
197793621c9Sroy		"nameserver "*)
198075ee3c1Sroy			islocal=false
199075ee3c1Sroy			for l in $local_nameservers; do
200e37204c6Sroy				case "$stripped_line" in
201075ee3c1Sroy				$l)
202075ee3c1Sroy					islocal=true
203075ee3c1Sroy					break
204d8775c93Sroy					;;
205793621c9Sroy				esac
206075ee3c1Sroy			done
207e37204c6Sroy			if $islocal; then
208e37204c6Sroy				echo "LOCALNAMESERVERS=\"\$LOCALNAMESERVERS $stripped_line\""
209e37204c6Sroy			else
210e37204c6Sroy				ns="$ns$stripped_line "
211e37204c6Sroy			fi
212793621c9Sroy			;;
21302c18234Sroy		"domain "*)
214e37204c6Sroy			search="$stripped_line"
21502c18234Sroy			if [ -z "$domain" ]; then
2162644931fSroy				domain="$search"
21702c18234Sroy				echo "DOMAIN=\"$domain\""
21802c18234Sroy			fi
21902c18234Sroy			;;
22002c18234Sroy		"search "*)
221e37204c6Sroy			search="$stripped_line"
222793621c9Sroy			;;
223793621c9Sroy		*)
224793621c9Sroy			[ -n "$line" ] && continue
225d7a1218eSkre			if [ -n "$ns" ] && [ -n "$search" ]; then
226793621c9Sroy				newns=
227793621c9Sroy				for n in $ns; do
228793621c9Sroy					newns="$newns${newns:+,}$n"
229793621c9Sroy				done
230793621c9Sroy				ds=
231793621c9Sroy				for d in $search; do
232793621c9Sroy					ds="$ds${ds:+ }$d:$newns"
233793621c9Sroy				done
234793621c9Sroy				echo "DOMAINS=\"\$DOMAINS $ds\""
235793621c9Sroy			fi
236793621c9Sroy			echo "SEARCH=\"\$SEARCH $search\""
237793621c9Sroy			if ! $private; then
238793621c9Sroy				echo "NAMESERVERS=\"\$NAMESERVERS $ns\""
239793621c9Sroy			fi
240793621c9Sroy			ns=
241793621c9Sroy			search=
242793621c9Sroy			new=true
243793621c9Sroy			;;
244793621c9Sroy		esac
245793621c9Sroy	done
246793621c9Sroy}
247793621c9Sroy
248793621c9Sroyuniqify()
249793621c9Sroy{
250e37204c6Sroy	result=
251793621c9Sroy	while [ -n "$1" ]; do
252793621c9Sroy		case " $result " in
253793621c9Sroy		*" $1 "*);;
254793621c9Sroy		*) result="$result $1";;
255793621c9Sroy		esac
256793621c9Sroy		shift
257793621c9Sroy	done
258793621c9Sroy	echo "${result# *}"
259793621c9Sroy}
260793621c9Sroy
26102c18234Sroydirname()
26202c18234Sroy{
263e37204c6Sroy	OIFS="$IFS"
264e37204c6Sroy	IFS=/
26502c18234Sroy	set -- $@
26602c18234Sroy	IFS="$OIFS"
26702c18234Sroy	if [ -n "$1" ]; then
26802c18234Sroy		printf %s .
26902c18234Sroy	else
27002c18234Sroy		shift
27102c18234Sroy	fi
27202c18234Sroy	while [ -n "$2" ]; do
27302c18234Sroy		printf "/%s" "$1"
27402c18234Sroy		shift
27502c18234Sroy	done
27602c18234Sroy	printf "\n"
27702c18234Sroy}
27802c18234Sroy
27902c18234Sroyconfig_mkdirs()
28002c18234Sroy{
28102c18234Sroy	for f; do
28202c18234Sroy		[ -n "$f" ] || continue
28302c18234Sroy		d="$(dirname "$f")"
28402c18234Sroy		if [ ! -d "$d" ]; then
2850949b2edSroy			mkdir -p "$d" || return $?
28602c18234Sroy		fi
28702c18234Sroy	done
2880949b2edSroy	return 0
28902c18234Sroy}
29002c18234Sroy
2919d6c0475Sroy# With the advent of alternative init systems, it's possible to have
2929d6c0475Sroy# more than one installed. So we need to try and guess what one we're
293*59c22029Sroy# using unless overridden by configure.
2949d6c0475Sroy# Note that restarting a service is a last resort - the subscribers
295*59c22029Sroy# should make a reasonable attempt to reconfigure the service via some
2969d6c0475Sroy# method, normally SIGHUP.
2979d6c0475Sroydetect_init()
2989d6c0475Sroy{
2999d6c0475Sroy	[ -n "$RESTARTCMD" ] && return 0
3009d6c0475Sroy
3019d6c0475Sroy	# Detect the running init system.
3029d6c0475Sroy	# As systemd and OpenRC can be installed on top of legacy init
3039d6c0475Sroy	# systems we try to detect them first.
304e37204c6Sroy	status="@STATUSARG@"
3059d6c0475Sroy	: ${status:=status}
306d7a1218eSkre	if [ -x /bin/systemctl ] && [ -S /run/systemd/private ]; then
307d7a1218eSkre		RESTARTCMD='
308d7a1218eSkre			if /bin/systemctl --quiet is-active $1.service
3099d6c0475Sroy			then
310d7a1218eSkre				/bin/systemctl restart $1.service
311d7a1218eSkre			fi'
312d7a1218eSkre	elif [ -x /usr/bin/systemctl ] && [ -S /run/systemd/private ]; then
313d7a1218eSkre		RESTARTCMD='
314d7a1218eSkre			if /usr/bin/systemctl --quiet is-active $1.service
315d7a1218eSkre			then
316d7a1218eSkre				/usr/bin/systemctl restart $1.service
317d7a1218eSkre			fi'
318e37204c6Sroy	elif [ -x /sbin/rc-service ] &&
319e37204c6Sroy	     { [ -s /libexec/rc/init.d/softlevel ] ||
320e37204c6Sroy	     [ -s /run/openrc/softlevel ]; }
321d7a1218eSkre	then
322d7a1218eSkre		RESTARTCMD='/sbin/rc-service -i $1 -- -Ds restart'
3239d6c0475Sroy	elif [ -x /usr/sbin/invoke-rc.d ]; then
3249d6c0475Sroy		RCDIR=/etc/init.d
325d7a1218eSkre		RESTARTCMD='
326d7a1218eSkre		   if /usr/sbin/invoke-rc.d --quiet $1 status >/dev/null 2>&1
327d7a1218eSkre		   then
328d7a1218eSkre			/usr/sbin/invoke-rc.d $1 restart
329d7a1218eSkre		   fi'
330*59c22029Sroy	elif [ -x /usr/bin/s6-rc ] && [ -x /usr/bin/s6-svc ]; then
331*59c22029Sroy		RESTARTCMD='
332*59c22029Sroy		   if s6-rc -a list | grep -qFx $1-srv
333*59c22029Sroy		   then
334*59c22029Sroy			s6-svc -r /run/service/$1-srv
335*59c22029Sroy		   fi'
3369d6c0475Sroy	elif [ -x /sbin/service ]; then
3379d6c0475Sroy		# Old RedHat
3389d6c0475Sroy		RCDIR=/etc/init.d
339d7a1218eSkre		RESTARTCMD='
340d7a1218eSkre			if /sbin/service $1; then
341d7a1218eSkre				/sbin/service $1 restart
342d7a1218eSkre			fi'
3439d6c0475Sroy	elif [ -x /usr/sbin/service ]; then
3449d6c0475Sroy		# Could be FreeBSD
3454113b4f7Skre		RESTARTCMD="
3464113b4f7Skre			if /usr/sbin/service \$1 $status >/dev/null 2>&1
347d7a1218eSkre			then
3484113b4f7Skre				/usr/sbin/service \$1 restart
3494113b4f7Skre			fi"
3509d6c0475Sroy	elif [ -x /bin/sv ]; then
351d7a1218eSkre		RESTARTCMD='/bin/sv status $1 >/dev/null 2>&1 &&
352d7a1218eSkre			    /bin/sv try-restart $1'
3539d6c0475Sroy	elif [ -x /usr/bin/sv ]; then
354d7a1218eSkre		RESTARTCMD='/usr/bin/sv status $1 >/dev/null 2>&1 &&
355d7a1218eSkre			    /usr/bin/sv try-restart $1'
356d7a1218eSkre	elif [ -e /etc/arch-release ] && [ -d /etc/rc.d ]; then
3579d6c0475Sroy		RCDIR=/etc/rc.d
358d7a1218eSkre		RESTARTCMD='
359d7a1218eSkre			if [ -e /var/run/daemons/$1 ]
360d7a1218eSkre			then
361d7a1218eSkre				/etc/rc.d/$1 restart
362d7a1218eSkre			fi'
363d7a1218eSkre	elif [ -e /etc/slackware-version ] && [ -d /etc/rc.d ]; then
364d7a1218eSkre		RESTARTCMD='
365d7a1218eSkre			if /etc/rc.d/rc.$1 status >/dev/null 2>&1
366d7a1218eSkre			then
367d7a1218eSkre				/etc/rc.d/rc.$1 restart
368d7a1218eSkre			fi'
369d7a1218eSkre	elif [ -e /etc/rc.d/rc.subr ] && [ -d /etc/rc.d ]; then
3709d6c0475Sroy		# OpenBSD
371d7a1218eSkre		RESTARTCMD='
372d7a1218eSkre			if /etc/rc.d/$1 check >/dev/null 2>&1
373d7a1218eSkre			then
374d7a1218eSkre				/etc/rc.d/$1 restart
375d7a1218eSkre			fi'
376*59c22029Sroy	elif [ -d /etc/dinit.d ] && command -v dinitctl >/dev/null 2>&1; then
377*59c22029Sroy		RESTARTCMD='dinitctl --quiet restart --ignore-unstarted $1'
3789d6c0475Sroy	else
3799d6c0475Sroy		for x in /etc/init.d/rc.d /etc/rc.d /etc/init.d; do
3809d6c0475Sroy			[ -d $x ] || continue
381d7a1218eSkre			RESTARTCMD="
382d7a1218eSkre				if $x/\$1 $status >/dev/null 2>&1
383d7a1218eSkre				then
384d7a1218eSkre					$x/\$1 restart
3859d6c0475Sroy				fi"
3869d6c0475Sroy			break
3879d6c0475Sroy		done
3889d6c0475Sroy	fi
3899d6c0475Sroy
3909d6c0475Sroy	if [ -z "$RESTARTCMD" ]; then
391d7a1218eSkre		if [ "$_NOINIT_WARNED" != true ]; then
3929d6c0475Sroy			warn "could not detect a useable init system"
3939d6c0475Sroy			_NOINIT_WARNED=true
3949d6c0475Sroy		fi
3959d6c0475Sroy		return 1
3969d6c0475Sroy	fi
3979d6c0475Sroy	_NOINIT_WARNED=
3989d6c0475Sroy	return 0
3999d6c0475Sroy}
4009d6c0475Sroy
4019d6c0475Sroyecho_resolv()
4029d6c0475Sroy{
403e37204c6Sroy	OIFS="$IFS"
4049d6c0475Sroy
405d7a1218eSkre	[ -n "$1" ] && [ -f "$IFACEDIR/$1" ] || return 1
4069d6c0475Sroy	echo "# resolv.conf from $1"
4079d6c0475Sroy	# Our variable maker works of the fact each resolv.conf per interface
4089d6c0475Sroy	# is separated by blank lines.
4099d6c0475Sroy	# So we remove them when echoing them.
4109d6c0475Sroy	while read -r line; do
4119d6c0475Sroy		IFS="$OIFS"
4129d6c0475Sroy		if [ -n "$line" ]; then
4139d6c0475Sroy			# We need to set IFS here to preserve any whitespace
4149d6c0475Sroy			IFS=''
4159d6c0475Sroy			printf "%s\n" "$line"
4169d6c0475Sroy		fi
4179d6c0475Sroy	done < "$IFACEDIR/$1"
4189d6c0475Sroy	IFS="$OIFS"
4199d6c0475Sroy}
4209d6c0475Sroy
4210949b2edSroydeprecated_interface()
4220949b2edSroy{
4230949b2edSroy	[ -d "$DEPRECATEDDIR" ] || return 1
4240949b2edSroy
4250949b2edSroy	cd "$DEPRECATEDDIR"
4260949b2edSroy	for da; do
4270949b2edSroy		for daf in *; do
4280949b2edSroy			[ -f "$daf" ] || continue
4290949b2edSroy			case "$da" in
4300949b2edSroy			$daf) return 0;;
4310949b2edSroy			esac
4320949b2edSroy		done
4330949b2edSroy	done
4340949b2edSroy	return 1
4350949b2edSroy}
4360949b2edSroy
437793621c9Sroylist_resolv()
438793621c9Sroy{
439793621c9Sroy	[ -d "$IFACEDIR" ] || return 0
440793621c9Sroy
441e37204c6Sroy	cmd="$1"
442793621c9Sroy	shift
443*59c22029Sroy	pattern_specified="$1"
444*59c22029Sroy
445e37204c6Sroy	excl=false
446e37204c6Sroy	list=
447e37204c6Sroy	report=false
448e37204c6Sroy	retval=0
449793621c9Sroy
4504ac8d7d2Sroy	case "$IF_EXCLUSIVE" in
4514ac8d7d2Sroy	[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
452e37204c6Sroy		excl=true
4534ac8d7d2Sroy		if [ -d "$EXCLUSIVEDIR" ]; then
4544ac8d7d2Sroy			cd "$EXCLUSIVEDIR"
4554ac8d7d2Sroy			for i in *; do
4564ac8d7d2Sroy				if [ -f "$i" ]; then
4574ac8d7d2Sroy					list="${i#* }"
4584ac8d7d2Sroy					break
4594ac8d7d2Sroy				fi
4604ac8d7d2Sroy			done
4614ac8d7d2Sroy		fi
462292189d7Sroy		cd "$IFACEDIR"
463292189d7Sroy		for i in $inclusive_interfaces; do
464d7a1218eSkre			if [ -f "$i" ] && [ "$list" = "$i" ]; then
465292189d7Sroy				list=
466292189d7Sroy				excl=false
467292189d7Sroy				break
468292189d7Sroy			fi
469292189d7Sroy		done
4704ac8d7d2Sroy		;;
4714ac8d7d2Sroy	esac
4724ac8d7d2Sroy
473793621c9Sroy	# If we have an interface ordering list, then use that.
474793621c9Sroy	# It works by just using pathname expansion in the interface directory.
475*59c22029Sroy	if [ -n "$pattern_specified" ]; then
476d8775c93Sroy		list="$*"
477793621c9Sroy		$force || report=true
4784ac8d7d2Sroy	elif ! $excl; then
479793621c9Sroy		cd "$IFACEDIR"
4800949b2edSroy
481793621c9Sroy		for i in $interface_order; do
4824ac8d7d2Sroy			[ -f "$i" ] && list="$list $i"
4834ac8d7d2Sroy			for ii in "$i":* "$i".*; do
4844ac8d7d2Sroy				[ -f "$ii" ] && list="$list $ii"
485327a6ebcSroy			done
486793621c9Sroy		done
4870949b2edSroy
488793621c9Sroy		for i in $dynamic_order; do
489d7a1218eSkre			if [ -e "$i" ] && ! [ -e "$METRICDIR/"*" $i" ]; then
490793621c9Sroy				list="$list $i"
491793621c9Sroy			fi
4924ac8d7d2Sroy			for ii in "$i":* "$i".*; do
493d7a1218eSkre				if [ -f "$ii" ] && ! [ -e "$METRICDIR/"*" $ii" ]
494d7a1218eSkre				then
495327a6ebcSroy					list="$list $ii"
496327a6ebcSroy				fi
497327a6ebcSroy			done
498793621c9Sroy		done
4990949b2edSroy
500e37204c6Sroy		# Interfaces have an implicit metric of 0 if not specified.
501e37204c6Sroy		for i in *; do
502e37204c6Sroy			if [ -f "$i" ] && ! [ -e "$METRICDIR/"*" $i" ]; then
503e37204c6Sroy				list="$list $i"
504e37204c6Sroy			fi
505e37204c6Sroy		done
5060949b2edSroy
507793621c9Sroy		if [ -d "$METRICDIR" ]; then
508793621c9Sroy			cd "$METRICDIR"
509793621c9Sroy			for i in *; do
5104ac8d7d2Sroy				[ -f "$i" ] && list="$list ${i#* }"
511793621c9Sroy			done
512793621c9Sroy		fi
5130949b2edSroy
5140949b2edSroy		# Move deprecated interfaces to the back
5150949b2edSroy		active=
5160949b2edSroy		deprecated=
5170949b2edSroy		for i in $list; do
5180949b2edSroy			if deprecated_interface "$i"; then
5190949b2edSroy				deprecated="$deprecated $i"
5200949b2edSroy			else
5210949b2edSroy				active="$active $i"
5220949b2edSroy			fi
5230949b2edSroy		done
5240949b2edSroy		list="$active $deprecated"
525793621c9Sroy	fi
526793621c9Sroy
527793621c9Sroy	cd "$IFACEDIR"
528*59c22029Sroy	if $excl || [ -n "$pattern_specified" ]; then
5294ac8d7d2Sroy		retval=1
530*59c22029Sroy	else
531*59c22029Sroy		retval=0
532*59c22029Sroy	fi
533793621c9Sroy	for i in $(uniqify $list); do
534793621c9Sroy		# Only list interfaces which we really have
5354ac8d7d2Sroy		if ! [ -f "$i" ]; then
536793621c9Sroy			if $report; then
537793621c9Sroy				echo "No resolv.conf for interface $i" >&2
5384ac8d7d2Sroy				retval=2
539793621c9Sroy			fi
540793621c9Sroy			continue
541793621c9Sroy		fi
542793621c9Sroy
5439cbb0fe2Sroy		if ! $ALLIFACES; then
5449cbb0fe2Sroy			if [ -n "$allow_interfaces" ]; then
5459cbb0fe2Sroy				x=false
5469cbb0fe2Sroy				for j in $allow_interfaces; do
5479cbb0fe2Sroy					if [ "$i" = "$j" ]; then
5489cbb0fe2Sroy						x=true
5499cbb0fe2Sroy					fi
5509cbb0fe2Sroy				done
5519cbb0fe2Sroy				$x || continue
5529cbb0fe2Sroy			fi
5539cbb0fe2Sroy			for j in $deny_interfaces; do
5549cbb0fe2Sroy				if [ "$i" = "$j" ]; then
5559cbb0fe2Sroy					continue 2
5569cbb0fe2Sroy				fi
5579cbb0fe2Sroy			done
5589cbb0fe2Sroy		fi
5599cbb0fe2Sroy
560d7a1218eSkre		if [ "$cmd" = i ] || [ "$cmd" = "-i" ]; then
56102c18234Sroy			printf %s "$i "
562793621c9Sroy		else
563292189d7Sroy			echo_resolv "$i" && echo
564793621c9Sroy		fi
565d7a1218eSkre		[ $? = 0 ] && [ "$retval" = 1 ] && retval=0
566793621c9Sroy	done
567d7a1218eSkre	[ "$cmd" = i ] || [ "$cmd" = "-i" ] && echo
568793621c9Sroy	return $retval
569793621c9Sroy}
570793621c9Sroy
571e37204c6Sroylist_remove()
572e37204c6Sroy{
573333b3001Sroy	[ -z "$2" ] && return 0
574333b3001Sroy	eval list=\"\$$1\"
575333b3001Sroy	shift
576e37204c6Sroy	result=
577e37204c6Sroy	retval=0
578333b3001Sroy
579333b3001Sroy	set -f
580333b3001Sroy	for e; do
581333b3001Sroy		found=false
582333b3001Sroy		for l in $list; do
583333b3001Sroy			case "$e" in
584333b3001Sroy			$l) found=true;;
585333b3001Sroy			esac
586333b3001Sroy			$found && break
587333b3001Sroy		done
588333b3001Sroy		if $found; then
589333b3001Sroy			retval=$(($retval + 1))
590333b3001Sroy		else
591333b3001Sroy			result="$result $e"
592333b3001Sroy		fi
593333b3001Sroy	done
594333b3001Sroy	set +f
595333b3001Sroy	echo "${result# *}"
596333b3001Sroy	return $retval
597333b3001Sroy}
598333b3001Sroy
599e9917e6eSroyecho_prepend()
600e9917e6eSroy{
601e9917e6eSroy	echo "# Generated by resolvconf"
602e9917e6eSroy	if [ -n "$search_domains" ]; then
603e9917e6eSroy		echo "search $search_domains"
604e9917e6eSroy	fi
605e9917e6eSroy	for n in $name_servers; do
606e9917e6eSroy		echo "nameserver $n"
607e9917e6eSroy	done
608e9917e6eSroy	echo
609e9917e6eSroy}
610e9917e6eSroy
611e9917e6eSroyecho_append()
612e9917e6eSroy{
613e9917e6eSroy	echo "# Generated by resolvconf"
614e9917e6eSroy	if [ -n "$search_domains_append" ]; then
615e9917e6eSroy		echo "search $search_domains_append"
616e9917e6eSroy	fi
617e9917e6eSroy	for n in $name_servers_append; do
618e9917e6eSroy		echo "nameserver $n"
619e9917e6eSroy	done
620e9917e6eSroy	echo
621e9917e6eSroy}
622e9917e6eSroy
623548d7cc4Sroyreplace()
624548d7cc4Sroy{
625548d7cc4Sroy	while read -r keyword value; do
626548d7cc4Sroy		for r in $replace; do
627548d7cc4Sroy			k="${r%%/*}"
628548d7cc4Sroy			r="${r#*/}"
629548d7cc4Sroy			f="${r%%/*}"
630548d7cc4Sroy			r="${r#*/}"
631548d7cc4Sroy			v="${r%%/*}"
632548d7cc4Sroy			case "$keyword" in
633548d7cc4Sroy			$k)
634548d7cc4Sroy				case "$value" in
635548d7cc4Sroy				$f) value="$v";;
636548d7cc4Sroy				esac
637548d7cc4Sroy				;;
638548d7cc4Sroy			esac
639548d7cc4Sroy		done
640548d7cc4Sroy		val=
641548d7cc4Sroy		for sub in $value; do
642548d7cc4Sroy			for r in $replace_sub; do
643548d7cc4Sroy				k="${r%%/*}"
644548d7cc4Sroy				r="${r#*/}"
645548d7cc4Sroy				f="${r%%/*}"
646548d7cc4Sroy				r="${r#*/}"
647548d7cc4Sroy				v="${r%%/*}"
648548d7cc4Sroy				case "$keyword" in
649548d7cc4Sroy				$k)
650548d7cc4Sroy					case "$sub" in
651548d7cc4Sroy					$f) sub="$v";;
652548d7cc4Sroy					esac
653548d7cc4Sroy					;;
654548d7cc4Sroy				esac
655548d7cc4Sroy			done
656548d7cc4Sroy			val="$val${val:+ }$sub"
657548d7cc4Sroy		done
658548d7cc4Sroy		printf "%s %s\n" "$keyword" "$val"
659548d7cc4Sroy	done
660548d7cc4Sroy}
661548d7cc4Sroy
662793621c9Sroymake_vars()
663793621c9Sroy{
664e9917e6eSroy	# Clear variables
665e9917e6eSroy	DOMAIN=
666e9917e6eSroy	DOMAINS=
667e9917e6eSroy	SEARCH=
668e9917e6eSroy	NAMESERVERS=
669e9917e6eSroy	LOCALNAMESERVERS=
670e9917e6eSroy
671d7a1218eSkre	if [ -n "${name_servers}${search_domains}" ]; then
672e9917e6eSroy		eval "$(echo_prepend | parse_resolv)"
673e9917e6eSroy	fi
674075ee3c1Sroy	if [ -z "$VFLAG" ]; then
6754ac8d7d2Sroy		IF_EXCLUSIVE=1
6764ac8d7d2Sroy		list_resolv -i "$@" >/dev/null || IF_EXCLUSIVE=0
677548d7cc4Sroy		eval "$(list_resolv -l "$@" | replace | parse_resolv)"
678075ee3c1Sroy	fi
679871fbadaSryoon	if [ -n "${name_servers_append}${search_domains_append}" ]; then
680e9917e6eSroy		eval "$(echo_append | parse_resolv)"
681e9917e6eSroy	fi
682793621c9Sroy
683793621c9Sroy	# Ensure that we only list each domain once
684e37204c6Sroy	newdomains=
685793621c9Sroy	for d in $DOMAINS; do
686793621c9Sroy		dn="${d%%:*}"
687333b3001Sroy		list_remove domain_blacklist "$dn" >/dev/null || continue
688793621c9Sroy		case " $newdomains" in
689793621c9Sroy		*" ${dn}:"*) continue;;
690793621c9Sroy		esac
691793621c9Sroy		newns=
692793621c9Sroy		for nd in $DOMAINS; do
693793621c9Sroy			if [ "$dn" = "${nd%%:*}" ]; then
694793621c9Sroy				ns="${nd#*:}"
695793621c9Sroy				while [ -n "$ns" ]; do
696793621c9Sroy					case ",$newns," in
697793621c9Sroy					*,${ns%%,*},*) ;;
698333b3001Sroy					*) list_remove name_server_blacklist \
699075ee3c1Sroy						"${ns%%,*}" >/dev/null \
700333b3001Sroy					&& newns="$newns${newns:+,}${ns%%,*}";;
701793621c9Sroy					esac
702793621c9Sroy					[ "$ns" = "${ns#*,}" ] && break
703793621c9Sroy					ns="${ns#*,}"
704793621c9Sroy				done
705793621c9Sroy			fi
706793621c9Sroy		done
707333b3001Sroy		if [ -n "$newns" ]; then
708333b3001Sroy			newdomains="$newdomains${newdomains:+ }$dn:$newns"
709333b3001Sroy		fi
710793621c9Sroy	done
711333b3001Sroy	DOMAIN="$(list_remove domain_blacklist $DOMAIN)"
712333b3001Sroy	SEARCH="$(uniqify $SEARCH)"
713333b3001Sroy	SEARCH="$(list_remove domain_blacklist $SEARCH)"
714333b3001Sroy	NAMESERVERS="$(uniqify $NAMESERVERS)"
715333b3001Sroy	NAMESERVERS="$(list_remove name_server_blacklist $NAMESERVERS)"
716333b3001Sroy	LOCALNAMESERVERS="$(uniqify $LOCALNAMESERVERS)"
717333b3001Sroy	LOCALNAMESERVERS="$(list_remove name_server_blacklist $LOCALNAMESERVERS)"
71802c18234Sroy	echo "DOMAIN='$DOMAIN'"
719333b3001Sroy	echo "SEARCH='$SEARCH'"
720333b3001Sroy	echo "NAMESERVERS='$NAMESERVERS'"
721333b3001Sroy	echo "LOCALNAMESERVERS='$LOCALNAMESERVERS'"
72202c18234Sroy	echo "DOMAINS='$newdomains'"
723793621c9Sroy}
724793621c9Sroy
725793621c9Sroyforce=false
726075ee3c1SroyVFLAG=
7270949b2edSroywhile getopts a:C:c:Dd:fhIilm:pRruvVx OPT; do
728793621c9Sroy	case "$OPT" in
729793621c9Sroy	f) force=true;;
730793621c9Sroy	h) usage;;
731793621c9Sroy	m) IF_METRIC="$OPTARG";;
732793621c9Sroy	p) IF_PRIVATE=1;;
733075ee3c1Sroy	V)
734075ee3c1Sroy		VFLAG=1
735075ee3c1Sroy		if [ "$local_nameservers" = \
736075ee3c1Sroy		    "127.* 0.0.0.0 255.255.255.255 ::1" ]
737075ee3c1Sroy		then
738075ee3c1Sroy			local_nameservers=
739075ee3c1Sroy		fi
740075ee3c1Sroy		;;
7414ac8d7d2Sroy	x) IF_EXCLUSIVE=1;;
7420949b2edSroy	'?') exit 1;;
743793621c9Sroy	*) cmd="$OPT"; iface="$OPTARG";;
744793621c9Sroy	esac
745793621c9Sroydone
746793621c9Sroyshift $(($OPTIND - 1))
747d8775c93Sroyargs="$iface${iface:+ }$*"
748793621c9Sroy
749793621c9Sroy# -I inits the state dir
750793621c9Sroyif [ "$cmd" = I ]; then
751793621c9Sroy	if [ -d "$VARDIR" ]; then
752793621c9Sroy		rm -rf "$VARDIR"/*
753793621c9Sroy	fi
754793621c9Sroy	exit $?
755793621c9Sroyfi
756793621c9Sroy
75702c18234Sroy# -D ensures that the listed config file base dirs exist
75802c18234Sroyif [ "$cmd" = D ]; then
75902c18234Sroy	config_mkdirs "$@"
76002c18234Sroy	exit $?
76102c18234Sroyfi
76202c18234Sroy
763793621c9Sroy# -l lists our resolv files, optionally for a specific interface
764d7a1218eSkreif [ "$cmd" = l ] || [ "$cmd" = i ]; then
7659cbb0fe2Sroy	ALLIFACES=true
766793621c9Sroy	list_resolv "$cmd" "$args"
767793621c9Sroy	exit $?
768793621c9Sroyfi
7699cbb0fe2SroyALLIFACES=false
770793621c9Sroy
7719d6c0475Sroy# Restart a service or echo the command to restart a service
772d7a1218eSkreif [ "$cmd" = r ] || [ "$cmd" = R ]; then
7739d6c0475Sroy	detect_init || exit 1
7749d6c0475Sroy	if [ "$cmd" = r ]; then
7759d6c0475Sroy		set -- $args
7764113b4f7Skre		eval "$RESTARTCMD"
7779d6c0475Sroy	else
778e37204c6Sroy		echo "$RESTARTCMD" |
779e37204c6Sroy			sed -e '/^$/d' -e 's/^			//g'
7809d6c0475Sroy	fi
7819d6c0475Sroy	exit $?
7829d6c0475Sroyfi
7839d6c0475Sroy
784793621c9Sroy# Not normally needed, but subscribers should be able to run independently
785d7a1218eSkreif [ "$cmd" = v ] || [ -n "$VFLAG" ]; then
786793621c9Sroy	make_vars "$iface"
787793621c9Sroy	exit $?
788793621c9Sroyfi
789793621c9Sroy
790793621c9Sroy# Test that we have valid options
7910949b2edSroycase "$cmd" in
7920949b2edSroya|d|C|c)
793793621c9Sroy	if [ -z "$iface" ]; then
7940949b2edSroy		error_exit "Interface not specified"
795793621c9Sroy	fi
7960949b2edSroy	;;
7970949b2edSroyu)	;;
7980949b2edSroy*)
7990949b2edSroy	if [ -n "$cmd" ] && [ "$cmd" != h ]; then
8000949b2edSroy		error_exit "Unknown option $cmd"
8010949b2edSroy	fi
802793621c9Sroy	usage
8030949b2edSroy	;;
8040949b2edSroyesac
805075ee3c1Sroy
806793621c9Sroyif [ "$cmd" = a ]; then
807793621c9Sroy	for x in '/' \\ ' ' '*'; do
808793621c9Sroy		case "$iface" in
809793621c9Sroy		*[$x]*) error_exit "$x not allowed in interface name";;
810793621c9Sroy		esac
811793621c9Sroy	done
812793621c9Sroy	for x in '.' '-' '~'; do
813793621c9Sroy		case "$iface" in
814793621c9Sroy		[$x]*) error_exit \
815793621c9Sroy			"$x not allowed at start of interface name";;
816793621c9Sroy		esac
817793621c9Sroy	done
818d7a1218eSkre	[ "$cmd" = a ] && [ -t 0 ] && error_exit "No file given via stdin"
819793621c9Sroyfi
820793621c9Sroy
821793621c9Sroyif [ ! -d "$VARDIR" ]; then
822793621c9Sroy	if [ -L "$VARDIR" ]; then
823793621c9Sroy		dir="$(readlink "$VARDIR")"
824793621c9Sroy		# link maybe relative
825793621c9Sroy		cd "${VARDIR%/*}"
826793621c9Sroy		if ! mkdir -m 0755 -p "$dir"; then
827793621c9Sroy			error_exit "Failed to create needed" \
828793621c9Sroy				"directory $dir"
829793621c9Sroy		fi
830793621c9Sroy	else
831793621c9Sroy		if ! mkdir -m 0755 -p "$VARDIR"; then
832793621c9Sroy			error_exit "Failed to create needed" \
833793621c9Sroy				"directory $VARDIR"
834793621c9Sroy		fi
835793621c9Sroy	fi
836793621c9Sroyfi
837075ee3c1Sroy
838075ee3c1Sroyif [ ! -d "$IFACEDIR" ]; then
839793621c9Sroy	mkdir -m 0755 -p "$IFACEDIR" || \
840793621c9Sroy		error_exit "Failed to create needed directory $IFACEDIR"
841548d7cc4Sroy	if [ "$cmd" = d ]; then
842548d7cc4Sroy		# Provide the same error messages as below
843548d7cc4Sroy		if ! ${force}; then
844548d7cc4Sroy			cd "$IFACEDIR"
845548d7cc4Sroy			for i in $args; do
846548d7cc4Sroy				warn "No resolv.conf for interface $i"
847548d7cc4Sroy			done
848548d7cc4Sroy		fi
849548d7cc4Sroy		${force}
850548d7cc4Sroy		exit $?
851548d7cc4Sroy	fi
852793621c9Sroyfi
853793621c9Sroy
8544ac8d7d2Sroy# An interface was added, changed, deleted or a general update was called.
8554ac8d7d2Sroy# Due to exclusivity we need to ensure that this is an atomic operation.
8564ac8d7d2Sroy# Our subscribers *may* need this as well if the init system is sub par.
8574ac8d7d2Sroy# As such we spinlock at this point as best we can.
8584ac8d7d2Sroy# We don't use flock(1) because it's not widely available and normally resides
8594ac8d7d2Sroy# in /usr which we do our very best to operate without.
8604ac8d7d2Sroy[ -w "$VARDIR" ] || error_exit "Cannot write to $LOCKDIR"
8614ac8d7d2Sroy: ${lock_timeout:=10}
8620949b2edSroy: ${clear_nopids:=5}
8630949b2edSroyhave_pid=false
8640949b2edSroyhad_pid=false
8654ac8d7d2Sroywhile true; do
8664ac8d7d2Sroy	if mkdir "$LOCKDIR" 2>/dev/null; then
8674ac8d7d2Sroy		trap 'rm -rf "$LOCKDIR";' EXIT
8684ac8d7d2Sroy		trap 'rm -rf "$LOCKDIR"; exit 1' INT QUIT ABRT SEGV ALRM TERM
8694ac8d7d2Sroy		echo $$ >"$LOCKDIR/pid"
8704ac8d7d2Sroy		break
8714ac8d7d2Sroy	fi
8720949b2edSroy	pid=$(cat "$LOCKDIR/pid" 2>/dev/null)
8730949b2edSroy	if [ "$pid" -gt 0 ] 2>/dev/null; then
8740949b2edSroy		have_pid=true
8750949b2edSroy		had_pid=true
8760949b2edSroy	else
8770949b2edSroy		have_pid=false
8780949b2edSroy		clear_nopids=$(($clear_nopids - 1))
8790949b2edSroy		if [ "$clear_nopids" -le 0 ]; then
8800949b2edSroy			warn "not seen a pid, clearing lock directory"
8810949b2edSroy			rm -rf "$LOCKDIR"
8820949b2edSroy		else
8830949b2edSroy			lock_timeout=$(($lock_timeout - 1))
8840949b2edSroy			sleep 1
8850949b2edSroy		fi
8860949b2edSroy		continue
8870949b2edSroy	fi
8880949b2edSroy	if $have_pid && ! kill -0 "$pid"; then
8894ac8d7d2Sroy		warn "clearing stale lock pid $pid"
8904ac8d7d2Sroy		rm -rf "$LOCKDIR"
8914ac8d7d2Sroy		continue
8924ac8d7d2Sroy	fi
8934ac8d7d2Sroy	lock_timeout=$(($lock_timeout - 1))
8944ac8d7d2Sroy	if [ "$lock_timeout" -le 0 ]; then
8950949b2edSroy		if $have_pid; then
8964ac8d7d2Sroy			error_exit "timed out waiting for lock from pid $pid"
8970949b2edSroy		else
8980949b2edSroy			if $had_pid; then
8990949b2edSroy				error_exit "timed out waiting for lock" \
9000949b2edSroy					"from some pids"
9010949b2edSroy			else
9020949b2edSroy				error_exit "timed out waiting for lock"
9030949b2edSroy			fi
9040949b2edSroy		fi
9054ac8d7d2Sroy	fi
9064ac8d7d2Sroy	sleep 1
9074ac8d7d2Sroydone
9080949b2edSroyunset have_pid had_pid clear_nopids
9094ac8d7d2Sroy
9104ac8d7d2Sroycase "$cmd" in
9114ac8d7d2Sroya)
912793621c9Sroy	# Read resolv.conf from stdin
913d8775c93Sroy	resolv="$(cat)"
91402c18234Sroy	changed=false
915075ee3c1Sroy	changedfile=false
916793621c9Sroy	# If what we are given matches what we have, then do nothing
917793621c9Sroy	if [ -e "$IFACEDIR/$iface" ]; then
91802c18234Sroy		if [ "$(echo "$resolv")" != \
919793621c9Sroy			"$(cat "$IFACEDIR/$iface")" ]
920793621c9Sroy		then
92102c18234Sroy			changed=true
922075ee3c1Sroy			changedfile=true
923793621c9Sroy		fi
92402c18234Sroy	else
92502c18234Sroy		changed=true
926075ee3c1Sroy		changedfile=true
92702c18234Sroy	fi
9284ac8d7d2Sroy
929075ee3c1Sroy	# Set metric and private before creating the interface resolv.conf file
930075ee3c1Sroy	# to ensure that it will have the correct flags
931793621c9Sroy	[ ! -d "$METRICDIR" ] && mkdir "$METRICDIR"
93202c18234Sroy	oldmetric="$METRICDIR/"*" $iface"
93302c18234Sroy	newmetric=
934793621c9Sroy	if [ -n "$IF_METRIC" ]; then
935793621c9Sroy		# Pad metric to 6 characters, so 5 is less than 10
936793621c9Sroy		while [ ${#IF_METRIC} -le 6 ]; do
937793621c9Sroy			IF_METRIC="0$IF_METRIC"
938793621c9Sroy		done
93902c18234Sroy		newmetric="$METRICDIR/$IF_METRIC $iface"
940793621c9Sroy	fi
94102c18234Sroy	rm -f "$METRICDIR/"*" $iface"
942d7a1218eSkre	[ "$oldmetric" != "$newmetric" ] &&
943d7a1218eSkre	    [ "$oldmetric" != "$METRICDIR/* $iface" ] &&
94402c18234Sroy		changed=true
94502c18234Sroy	[ -n "$newmetric" ] && echo " " >"$newmetric"
9464ac8d7d2Sroy
947793621c9Sroy	case "$IF_PRIVATE" in
948793621c9Sroy	[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
949793621c9Sroy		if [ ! -d "$PRIVATEDIR" ]; then
950793621c9Sroy			[ -e "$PRIVATEDIR" ] && rm "$PRIVATEDIR"
951793621c9Sroy			mkdir "$PRIVATEDIR"
952793621c9Sroy		fi
95302c18234Sroy		[ -e "$PRIVATEDIR/$iface" ] || changed=true
954793621c9Sroy		[ -d "$PRIVATEDIR" ] && echo " " >"$PRIVATEDIR/$iface"
955793621c9Sroy		;;
956793621c9Sroy	*)
957793621c9Sroy		if [ -e "$PRIVATEDIR/$iface" ]; then
958793621c9Sroy			rm -f "$PRIVATEDIR/$iface"
95902c18234Sroy			changed=true
960793621c9Sroy		fi
961793621c9Sroy		;;
962793621c9Sroy	esac
9634ac8d7d2Sroy
9644ac8d7d2Sroy	oldexcl=
9654ac8d7d2Sroy	for x in "$EXCLUSIVEDIR/"*" $iface"; do
9664ac8d7d2Sroy		if [ -f "$x" ]; then
9674ac8d7d2Sroy			oldexcl="$x"
9684ac8d7d2Sroy			break
9694ac8d7d2Sroy		fi
9704ac8d7d2Sroy	done
9714ac8d7d2Sroy	case "$IF_EXCLUSIVE" in
9724ac8d7d2Sroy	[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
9734ac8d7d2Sroy		if [ ! -d "$EXCLUSIVEDIR" ]; then
9744ac8d7d2Sroy			[ -e "$EXCLUSIVEDIR" ] && rm "$EXCLUSIVEDIR"
9754ac8d7d2Sroy			mkdir "$EXCLUSIVEDIR"
9764ac8d7d2Sroy		fi
9774ac8d7d2Sroy		cd "$EXCLUSIVEDIR"
9784ac8d7d2Sroy		for x in *; do
9794ac8d7d2Sroy			[ -f "$x" ] && break
9804ac8d7d2Sroy		done
9814ac8d7d2Sroy		if [ "${x#* }" != "$iface" ]; then
9824ac8d7d2Sroy			if [ "$x" = "${x% *}" ]; then
9834ac8d7d2Sroy				x=10000000
9844ac8d7d2Sroy			else
9854ac8d7d2Sroy				x="${x% *}"
9864ac8d7d2Sroy			fi
9874ac8d7d2Sroy			if [ "$x" = "0000000" ]; then
9884ac8d7d2Sroy				warn "exclusive underflow"
9894ac8d7d2Sroy			else
9904ac8d7d2Sroy				x=$(($x - 1))
9914ac8d7d2Sroy			fi
9924ac8d7d2Sroy			if [ -d "$EXCLUSIVEDIR" ]; then
9934ac8d7d2Sroy				echo " " >"$EXCLUSIVEDIR/$x $iface"
9944ac8d7d2Sroy			fi
9954ac8d7d2Sroy			changed=true
9964ac8d7d2Sroy		fi
9974ac8d7d2Sroy		;;
9984ac8d7d2Sroy	*)
9994ac8d7d2Sroy		if [ -f "$oldexcl" ]; then
10004ac8d7d2Sroy			rm -f "$oldexcl"
10014ac8d7d2Sroy			changed=true
10024ac8d7d2Sroy		fi
10034ac8d7d2Sroy		;;
10044ac8d7d2Sroy	esac
10054ac8d7d2Sroy
1006075ee3c1Sroy	if $changedfile; then
10074ac8d7d2Sroy		printf "%s\n" "$resolv" >"$IFACEDIR/$iface" || exit $?
10084ac8d7d2Sroy	elif ! $changed; then
10094ac8d7d2Sroy		exit 0
1010075ee3c1Sroy	fi
10114ac8d7d2Sroy	unset changed changedfile oldmetric newmetric x oldexcl
10124ac8d7d2Sroy	;;
10134ac8d7d2Sroy
10144ac8d7d2Sroyd)
10154ac8d7d2Sroy	# Delete any existing information about the interface
10164ac8d7d2Sroy	cd "$IFACEDIR"
10174ac8d7d2Sroy	changed=false
10184ac8d7d2Sroy	for i in $args; do
10194ac8d7d2Sroy		if [ -e "$i" ]; then
10204ac8d7d2Sroy			changed=true
10214ac8d7d2Sroy		elif ! ${force}; then
10224ac8d7d2Sroy			warn "No resolv.conf for interface $i"
1023075ee3c1Sroy		fi
10244ac8d7d2Sroy		rm -f "$i" "$METRICDIR/"*" $i" \
10254ac8d7d2Sroy			"$PRIVATEDIR/$i" \
10264ac8d7d2Sroy			"$EXCLUSIVEDIR/"*" $i" || exit $?
10274ac8d7d2Sroy	done
10280949b2edSroy
10290949b2edSroy	if ! $changed; then
10304ac8d7d2Sroy		# Set the return code based on the forced flag
10310949b2edSroy		$force
10324ac8d7d2Sroy		exit $?
1033793621c9Sroy	fi
10344ac8d7d2Sroy	unset changed i
10354ac8d7d2Sroy	;;
10360949b2edSroy
10370949b2edSroyC)
10380949b2edSroy	# Mark interface as deprecated
10390949b2edSroy	[ ! -d "$DEPRECATEDDIR" ] && mkdir "$DEPRECATEDDIR"
10400949b2edSroy	cd "$DEPRECATEDDIR"
10410949b2edSroy	changed=false
10420949b2edSroy	for i in $args; do
10430949b2edSroy		if [ ! -e "$i" ]; then
10440949b2edSroy			changed=true
10450949b2edSroy			echo " " >"$i" || exit $?
10460949b2edSroy		fi
10470949b2edSroy	done
10480949b2edSroy	$changed || exit 0
10490949b2edSroy	unset changed i
10500949b2edSroy	;;
10510949b2edSroy
10520949b2edSroyc)
10530949b2edSroy	# Mark interface as active
10540949b2edSroy	if [ -d "$DEPRECATEDDIR" ]; then
10550949b2edSroy		cd "$DEPRECATEDDIR"
10560949b2edSroy		changed=false
10570949b2edSroy		for i in $args; do
10580949b2edSroy			if [ -e "$i" ]; then
10590949b2edSroy				changed=true
10600949b2edSroy				rm "$i" || exit $?
10610949b2edSroy			fi
10620949b2edSroy		done
10630949b2edSroy		$changed || exit 0
10640949b2edSroy		unset changed i
10650949b2edSroy	fi
10660949b2edSroy	;;
10674ac8d7d2Sroyesac
1068793621c9Sroy
1069075ee3c1Sroycase "${resolvconf:-YES}" in
1070075ee3c1Sroy[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) ;;
1071075ee3c1Sroy*) exit 0;;
1072075ee3c1Sroyesac
1073075ee3c1Sroy
10749d6c0475Sroy# Try and detect a suitable init system for our scripts
10759d6c0475Sroydetect_init
10769d6c0475Sroyexport RESTARTCMD RCDIR _NOINIT_WARNED
10779d6c0475Sroy
1078793621c9Sroyeval "$(make_vars)"
1079d8775c93Sroyexport RESOLVCONF DOMAINS SEARCH NAMESERVERS LOCALNAMESERVERS
1080793621c9Sroy: ${list_resolv:=list_resolv -l}
1081793621c9Sroyretval=0
10822644931fSroy
10832644931fSroy# Run scripts in the same directory resolvconf is run from
1084292189d7Sroy# in case any scripts accidentally dump files in the wrong place.
10852644931fSroycd "$_PWD"
1086793621c9Sroyfor script in "$LIBEXECDIR"/*; do
10875bcbb70cSroy	if [ -f "$script" ]; then
1088075ee3c1Sroy		eval script_enabled="\$${script##*/}"
1089075ee3c1Sroy		case "${script_enabled:-YES}" in
1090075ee3c1Sroy		[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) ;;
1091075ee3c1Sroy		*) continue;;
1092075ee3c1Sroy		esac
10935bcbb70cSroy		if [ -x "$script" ]; then
10945bcbb70cSroy			"$script" "$cmd" "$iface"
10955bcbb70cSroy		else
1096d8775c93Sroy			(set -- "$cmd" "$iface"; . "$script")
10975bcbb70cSroy		fi
1098793621c9Sroy		retval=$(($retval + $?))
10995bcbb70cSroy	fi
1100793621c9Sroydone
1101793621c9Sroyexit $retval
1102