xref: /freebsd/contrib/openresolv/resolvconf.in (revision 9af6c78cd43b18e169f10802142c61638bd62bed)
1587392a5SHajimu UMEMOTO#!/bin/sh
2*9af6c78cSPedro F. Giffuni# Copyright (c) 2007-2019 Roy Marples
3587392a5SHajimu UMEMOTO# All rights reserved
4587392a5SHajimu UMEMOTO
5587392a5SHajimu UMEMOTO# Redistribution and use in source and binary forms, with or without
6587392a5SHajimu UMEMOTO# modification, are permitted provided that the following conditions
7587392a5SHajimu UMEMOTO# are met:
8587392a5SHajimu UMEMOTO#     * Redistributions of source code must retain the above copyright
9587392a5SHajimu UMEMOTO#       notice, this list of conditions and the following disclaimer.
10587392a5SHajimu UMEMOTO#     * Redistributions in binary form must reproduce the above
11587392a5SHajimu UMEMOTO#       copyright notice, this list of conditions and the following
12587392a5SHajimu UMEMOTO#       disclaimer in the documentation and/or other materials provided
13587392a5SHajimu UMEMOTO#       with the distribution.
14587392a5SHajimu UMEMOTO#
15587392a5SHajimu UMEMOTO# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16587392a5SHajimu UMEMOTO# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17587392a5SHajimu UMEMOTO# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18587392a5SHajimu UMEMOTO# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19587392a5SHajimu UMEMOTO# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20587392a5SHajimu UMEMOTO# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21587392a5SHajimu UMEMOTO# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22587392a5SHajimu UMEMOTO# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23587392a5SHajimu UMEMOTO# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24587392a5SHajimu UMEMOTO# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25587392a5SHajimu UMEMOTO# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26587392a5SHajimu UMEMOTO
27587392a5SHajimu UMEMOTORESOLVCONF="$0"
28*9af6c78cSPedro F. GiffuniOPENRESOLV_VERSION="3.9.2"
29587392a5SHajimu UMEMOTOSYSCONFDIR=@SYSCONFDIR@
30587392a5SHajimu UMEMOTOLIBEXECDIR=@LIBEXECDIR@
31587392a5SHajimu UMEMOTOVARDIR=@VARDIR@
323f2a60a1SPedro F. GiffuniRCDIR=@RCDIR@
333f2a60a1SPedro F. GiffuniRESTARTCMD=@RESTARTCMD@
34d7149f4eSGlen Barber
3587b2cfceSPedro F. Giffuniif [ "$1" = "--version" ]; then
3687b2cfceSPedro F. Giffuni	echo "openresolv $OPENRESOLV_VERSION"
3787b2cfceSPedro F. Giffuni	echo "Copyright (c) 2007-2016 Roy Marples"
3887b2cfceSPedro F. Giffuni	exit 0
3987b2cfceSPedro F. Giffunifi
4087b2cfceSPedro F. Giffuni
41d7149f4eSGlen Barber# Disregard dhcpcd setting
42d7149f4eSGlen Barberunset interface_order state_dir
43d7149f4eSGlen Barber
44d7149f4eSGlen Barber# If you change this, change the test in VFLAG and libc.in as well
45d7149f4eSGlen Barberlocal_nameservers="127.* 0.0.0.0 255.255.255.255 ::1"
46d7149f4eSGlen Barber
47d7149f4eSGlen Barberdynamic_order="tap[0-9]* tun[0-9]* vpn vpn[0-9]* ppp[0-9]* ippp[0-9]*"
48d7149f4eSGlen Barberinterface_order="lo lo[0-9]*"
49d7149f4eSGlen Barbername_server_blacklist="0.0.0.0"
50d7149f4eSGlen Barber
51587392a5SHajimu UMEMOTO# Support original resolvconf configuration layout
52587392a5SHajimu UMEMOTO# as well as the openresolv config file
53587392a5SHajimu UMEMOTOif [ -f "$SYSCONFDIR"/resolvconf.conf ]; then
54587392a5SHajimu UMEMOTO	. "$SYSCONFDIR"/resolvconf.conf
55587392a5SHajimu UMEMOTO	[ -n "$state_dir" ] && VARDIR="$state_dir"
56587392a5SHajimu UMEMOTOelif [ -d "$SYSCONFDIR/resolvconf" ]; then
57587392a5SHajimu UMEMOTO	SYSCONFDIR="$SYSCONFDIR/resolvconf"
58587392a5SHajimu UMEMOTO	if [ -f "$SYSCONFDIR"/interface-order ]; then
59587392a5SHajimu UMEMOTO		interface_order="$(cat "$SYSCONFDIR"/interface-order)"
60587392a5SHajimu UMEMOTO	fi
61587392a5SHajimu UMEMOTOfi
62587392a5SHajimu UMEMOTOIFACEDIR="$VARDIR/interfaces"
63587392a5SHajimu UMEMOTOMETRICDIR="$VARDIR/metrics"
64587392a5SHajimu UMEMOTOPRIVATEDIR="$VARDIR/private"
65d7149f4eSGlen BarberEXCLUSIVEDIR="$VARDIR/exclusive"
66d7149f4eSGlen BarberLOCKDIR="$VARDIR/lock"
67c364f334SPedro F. Giffuni_PWD="$PWD"
68587392a5SHajimu UMEMOTO
69d7149f4eSGlen Barberwarn()
70d7149f4eSGlen Barber{
71d7149f4eSGlen Barber	echo "$*" >&2
72d7149f4eSGlen Barber}
73587392a5SHajimu UMEMOTO
74587392a5SHajimu UMEMOTOerror_exit()
75587392a5SHajimu UMEMOTO{
76587392a5SHajimu UMEMOTO	echo "$*" >&2
77587392a5SHajimu UMEMOTO	exit 1
78587392a5SHajimu UMEMOTO}
79587392a5SHajimu UMEMOTO
80587392a5SHajimu UMEMOTOusage()
81587392a5SHajimu UMEMOTO{
82587392a5SHajimu UMEMOTO	cat <<-EOF
833f2a60a1SPedro F. Giffuni	Usage: ${RESOLVCONF##*/} [options] command [argument]
84587392a5SHajimu UMEMOTO
85587392a5SHajimu UMEMOTO	Inform the system about any DNS updates.
86587392a5SHajimu UMEMOTO
873f2a60a1SPedro F. Giffuni	Commands:
88587392a5SHajimu UMEMOTO	  -a \$INTERFACE    Add DNS information to the specified interface
89587392a5SHajimu UMEMOTO	                   (DNS supplied via stdin in resolv.conf format)
90587392a5SHajimu UMEMOTO	  -d \$INTERFACE    Delete DNS information from the specified interface
913f2a60a1SPedro F. Giffuni	  -h               Show this help cruft
92587392a5SHajimu UMEMOTO	  -i [\$PATTERN]    Show interfaces that have supplied DNS information
93587392a5SHajimu UMEMOTO                   optionally from interfaces that match the specified
94587392a5SHajimu UMEMOTO                   pattern
953f2a60a1SPedro F. Giffuni	  -l [\$PATTERN]    Show DNS information, optionally from interfaces
963f2a60a1SPedro F. Giffuni	                   that match the specified pattern
973f2a60a1SPedro F. Giffuni
983f2a60a1SPedro F. Giffuni	  -u               Run updates from our current DNS information
9987b2cfceSPedro F. Giffuni	  --version        Echo the ${RESOLVCONF##*/} version
1003f2a60a1SPedro F. Giffuni
1013f2a60a1SPedro F. Giffuni	Options:
1023f2a60a1SPedro F. Giffuni	  -f               Ignore non existent interfaces
1033f2a60a1SPedro F. Giffuni	  -m metric        Give the added DNS information a metric
1043f2a60a1SPedro F. Giffuni	  -p               Mark the interface as private
1053f2a60a1SPedro F. Giffuni	  -x               Mark the interface as exclusive
1063f2a60a1SPedro F. Giffuni
1073f2a60a1SPedro F. Giffuni	Subscriber and System Init Commands:
1083f2a60a1SPedro F. Giffuni	  -I               Init the state dir
1093f2a60a1SPedro F. Giffuni	  -r \$SERVICE      Restart the system service
1103f2a60a1SPedro F. Giffuni	                   (restarting a non-existent or non-running service
1113f2a60a1SPedro F. Giffuni	                    should have no output and return 0)
1123f2a60a1SPedro F. Giffuni	  -R               Show the system service restart command
113587392a5SHajimu UMEMOTO	  -v [\$PATTERN]    echo NEWDOMAIN, NEWSEARCH and NEWNS variables to
114587392a5SHajimu UMEMOTO	  		   the console
1153f2a60a1SPedro F. Giffuni	  -V [\$PATTERN]    Same as -v, but only uses configuration in
1163f2a60a1SPedro F. Giffuni	                   $SYSCONFDIR/resolvconf.conf
117587392a5SHajimu UMEMOTO	EOF
118587392a5SHajimu UMEMOTO	[ -z "$1" ] && exit 0
119587392a5SHajimu UMEMOTO	echo
120587392a5SHajimu UMEMOTO	error_exit "$*"
121587392a5SHajimu UMEMOTO}
122587392a5SHajimu UMEMOTO
123c364f334SPedro F. Giffuni# Strip any trailing dot from each name as a FQDN does not belong
124c364f334SPedro F. Giffuni# in resolv.conf(5)
125c364f334SPedro F. Giffuni# If you think otherwise, capture a DNS trace and you'll see libc
126c364f334SPedro F. Giffuni# will strip it regardless.
127c364f334SPedro F. Giffuni# This also solves setting up duplicate zones in our subscribers.
128*9af6c78cSPedro F. Giffuni# Also strip any comments denoted by #.
129*9af6c78cSPedro F. Giffuniresolv_strip()
130c364f334SPedro F. Giffuni{
131*9af6c78cSPedro F. Giffuni	space=
132*9af6c78cSPedro F. Giffuni	for word; do
133*9af6c78cSPedro F. Giffuni		case "$word" in
134*9af6c78cSPedro F. Giffuni		\#*) break;;
135*9af6c78cSPedro F. Giffuni		esac
136*9af6c78cSPedro F. Giffuni		printf "%s%s" "$space${word%.}"
137*9af6c78cSPedro F. Giffuni		space=" "
138c364f334SPedro F. Giffuni	done
139c364f334SPedro F. Giffuni	printf "\n"
140c364f334SPedro F. Giffuni}
141c364f334SPedro F. Giffuni
14287b2cfceSPedro F. Giffuniprivate_iface()
14387b2cfceSPedro F. Giffuni{
14487b2cfceSPedro F. Giffuni	# Allow expansion
14587b2cfceSPedro F. Giffuni	cd "$IFACEDIR"
14687b2cfceSPedro F. Giffuni
14787b2cfceSPedro F. Giffuni	# Public interfaces override private ones.
14887b2cfceSPedro F. Giffuni	for p in $public_interfaces; do
14987b2cfceSPedro F. Giffuni		case "$iface" in
15087b2cfceSPedro F. Giffuni		"$p"|"$p":*) return 1;;
15187b2cfceSPedro F. Giffuni		esac
15287b2cfceSPedro F. Giffuni	done
15387b2cfceSPedro F. Giffuni
15487b2cfceSPedro F. Giffuni	if [ -e "$PRIVATEDIR/$iface" ]; then
15587b2cfceSPedro F. Giffuni		return 0
15687b2cfceSPedro F. Giffuni	fi
15787b2cfceSPedro F. Giffuni
15887b2cfceSPedro F. Giffuni	for p in $private_interfaces; do
15987b2cfceSPedro F. Giffuni		case "$iface" in
16087b2cfceSPedro F. Giffuni		"$p"|"$p":*) return 0;;
16187b2cfceSPedro F. Giffuni		esac
16287b2cfceSPedro F. Giffuni	done
16387b2cfceSPedro F. Giffuni
16487b2cfceSPedro F. Giffuni	# Not a private interface
16587b2cfceSPedro F. Giffuni	return 1
16687b2cfceSPedro F. Giffuni}
16787b2cfceSPedro F. Giffuni
168587392a5SHajimu UMEMOTO# Parse resolv.conf's and make variables
169587392a5SHajimu UMEMOTO# for domain name servers, search name servers and global nameservers
170587392a5SHajimu UMEMOTOparse_resolv()
171587392a5SHajimu UMEMOTO{
172*9af6c78cSPedro F. Giffuni	domain=
173*9af6c78cSPedro F. Giffuni	new=true
174587392a5SHajimu UMEMOTO	newns=
175*9af6c78cSPedro F. Giffuni	ns=
176*9af6c78cSPedro F. Giffuni	private=false
177*9af6c78cSPedro F. Giffuni	search=
178587392a5SHajimu UMEMOTO
179d7149f4eSGlen Barber	while read -r line; do
180*9af6c78cSPedro F. Giffuni		stripped_line="$(resolv_strip ${line#* })"
181587392a5SHajimu UMEMOTO		case "$line" in
182587392a5SHajimu UMEMOTO		"# resolv.conf from "*)
183587392a5SHajimu UMEMOTO			if ${new}; then
184587392a5SHajimu UMEMOTO				iface="${line#\# resolv.conf from *}"
185587392a5SHajimu UMEMOTO				new=false
18687b2cfceSPedro F. Giffuni				if private_iface "$iface"; then
187587392a5SHajimu UMEMOTO					private=true
188587392a5SHajimu UMEMOTO				else
189587392a5SHajimu UMEMOTO					private=false
190587392a5SHajimu UMEMOTO				fi
191587392a5SHajimu UMEMOTO			fi
192587392a5SHajimu UMEMOTO			;;
193587392a5SHajimu UMEMOTO		"nameserver "*)
194d7149f4eSGlen Barber			islocal=false
195d7149f4eSGlen Barber			for l in $local_nameservers; do
196*9af6c78cSPedro F. Giffuni				case "$stripped_line" in
197d7149f4eSGlen Barber				$l)
198d7149f4eSGlen Barber					islocal=true
199d7149f4eSGlen Barber					break
200587392a5SHajimu UMEMOTO					;;
201587392a5SHajimu UMEMOTO				esac
202d7149f4eSGlen Barber			done
203*9af6c78cSPedro F. Giffuni			if $islocal; then
204*9af6c78cSPedro F. Giffuni				echo "LOCALNAMESERVERS=\"\$LOCALNAMESERVERS $stripped_line\""
205*9af6c78cSPedro F. Giffuni			else
206*9af6c78cSPedro F. Giffuni				ns="$ns$stripped_line "
207*9af6c78cSPedro F. Giffuni			fi
208587392a5SHajimu UMEMOTO			;;
209d7149f4eSGlen Barber		"domain "*)
210*9af6c78cSPedro F. Giffuni			search="$stripped_line"
211d7149f4eSGlen Barber			if [ -z "$domain" ]; then
212c364f334SPedro F. Giffuni				domain="$search"
213d7149f4eSGlen Barber				echo "DOMAIN=\"$domain\""
214d7149f4eSGlen Barber			fi
215d7149f4eSGlen Barber			;;
216d7149f4eSGlen Barber		"search "*)
217*9af6c78cSPedro F. Giffuni			search="$stripped_line"
218587392a5SHajimu UMEMOTO			;;
219587392a5SHajimu UMEMOTO		*)
220587392a5SHajimu UMEMOTO			[ -n "$line" ] && continue
221*9af6c78cSPedro F. Giffuni			if [ -n "$ns" ] && [ -n "$search" ]; then
222587392a5SHajimu UMEMOTO				newns=
223587392a5SHajimu UMEMOTO				for n in $ns; do
224587392a5SHajimu UMEMOTO					newns="$newns${newns:+,}$n"
225587392a5SHajimu UMEMOTO				done
226587392a5SHajimu UMEMOTO				ds=
227587392a5SHajimu UMEMOTO				for d in $search; do
228587392a5SHajimu UMEMOTO					ds="$ds${ds:+ }$d:$newns"
229587392a5SHajimu UMEMOTO				done
230587392a5SHajimu UMEMOTO				echo "DOMAINS=\"\$DOMAINS $ds\""
231587392a5SHajimu UMEMOTO			fi
232587392a5SHajimu UMEMOTO			echo "SEARCH=\"\$SEARCH $search\""
233587392a5SHajimu UMEMOTO			if ! $private; then
234587392a5SHajimu UMEMOTO				echo "NAMESERVERS=\"\$NAMESERVERS $ns\""
235587392a5SHajimu UMEMOTO			fi
236587392a5SHajimu UMEMOTO			ns=
237587392a5SHajimu UMEMOTO			search=
238587392a5SHajimu UMEMOTO			new=true
239587392a5SHajimu UMEMOTO			;;
240587392a5SHajimu UMEMOTO		esac
241587392a5SHajimu UMEMOTO	done
242587392a5SHajimu UMEMOTO}
243587392a5SHajimu UMEMOTO
244587392a5SHajimu UMEMOTOuniqify()
245587392a5SHajimu UMEMOTO{
246*9af6c78cSPedro F. Giffuni	result=
247587392a5SHajimu UMEMOTO	while [ -n "$1" ]; do
248587392a5SHajimu UMEMOTO		case " $result " in
249587392a5SHajimu UMEMOTO		*" $1 "*);;
250587392a5SHajimu UMEMOTO		*) result="$result $1";;
251587392a5SHajimu UMEMOTO		esac
252587392a5SHajimu UMEMOTO		shift
253587392a5SHajimu UMEMOTO	done
254587392a5SHajimu UMEMOTO	echo "${result# *}"
255587392a5SHajimu UMEMOTO}
256587392a5SHajimu UMEMOTO
257d7149f4eSGlen Barberdirname()
258d7149f4eSGlen Barber{
259*9af6c78cSPedro F. Giffuni	OIFS="$IFS"
260*9af6c78cSPedro F. Giffuni	IFS=/
261d7149f4eSGlen Barber	set -- $@
262d7149f4eSGlen Barber	IFS="$OIFS"
263d7149f4eSGlen Barber	if [ -n "$1" ]; then
264d7149f4eSGlen Barber		printf %s .
265d7149f4eSGlen Barber	else
266d7149f4eSGlen Barber		shift
267d7149f4eSGlen Barber	fi
268d7149f4eSGlen Barber	while [ -n "$2" ]; do
269d7149f4eSGlen Barber		printf "/%s" "$1"
270d7149f4eSGlen Barber		shift
271d7149f4eSGlen Barber	done
272d7149f4eSGlen Barber	printf "\n"
273d7149f4eSGlen Barber}
274d7149f4eSGlen Barber
275d7149f4eSGlen Barberconfig_mkdirs()
276d7149f4eSGlen Barber{
277*9af6c78cSPedro F. Giffuni	e=0
278d7149f4eSGlen Barber	for f; do
279d7149f4eSGlen Barber		[ -n "$f" ] || continue
280d7149f4eSGlen Barber		d="$(dirname "$f")"
281d7149f4eSGlen Barber		if [ ! -d "$d" ]; then
282d7149f4eSGlen Barber			if type install >/dev/null 2>&1; then
283d7149f4eSGlen Barber				install -d "$d" || e=$?
284d7149f4eSGlen Barber			else
285d7149f4eSGlen Barber				mkdir "$d" || e=$?
286d7149f4eSGlen Barber			fi
287d7149f4eSGlen Barber		fi
288d7149f4eSGlen Barber	done
289d7149f4eSGlen Barber	return $e
290d7149f4eSGlen Barber}
291d7149f4eSGlen Barber
2923f2a60a1SPedro F. Giffuni# With the advent of alternative init systems, it's possible to have
2933f2a60a1SPedro F. Giffuni# more than one installed. So we need to try and guess what one we're
2943f2a60a1SPedro F. Giffuni# using unless overriden by configure.
2953f2a60a1SPedro F. Giffuni# Note that restarting a service is a last resort - the subscribers
2963f2a60a1SPedro F. Giffuni# should make a reasonable attempt to reconfigre the service via some
2973f2a60a1SPedro F. Giffuni# method, normally SIGHUP.
2983f2a60a1SPedro F. Giffunidetect_init()
2993f2a60a1SPedro F. Giffuni{
3003f2a60a1SPedro F. Giffuni	[ -n "$RESTARTCMD" ] && return 0
3013f2a60a1SPedro F. Giffuni
3023f2a60a1SPedro F. Giffuni	# Detect the running init system.
3033f2a60a1SPedro F. Giffuni	# As systemd and OpenRC can be installed on top of legacy init
3043f2a60a1SPedro F. Giffuni	# systems we try to detect them first.
305*9af6c78cSPedro F. Giffuni	status="@STATUSARG@"
3063f2a60a1SPedro F. Giffuni	: ${status:=status}
307*9af6c78cSPedro F. Giffuni	if [ -x /bin/systemctl ] && [ -S /run/systemd/private ]; then
308*9af6c78cSPedro F. Giffuni		RESTARTCMD='
309*9af6c78cSPedro F. Giffuni			if /bin/systemctl --quiet is-active $1.service
3103f2a60a1SPedro F. Giffuni			then
311*9af6c78cSPedro F. Giffuni				/bin/systemctl restart $1.service
312*9af6c78cSPedro F. Giffuni			fi'
313*9af6c78cSPedro F. Giffuni	elif [ -x /usr/bin/systemctl ] && [ -S /run/systemd/private ]; then
314*9af6c78cSPedro F. Giffuni		RESTARTCMD='
315*9af6c78cSPedro F. Giffuni			if /usr/bin/systemctl --quiet is-active $1.service
316*9af6c78cSPedro F. Giffuni			then
317*9af6c78cSPedro F. Giffuni				/usr/bin/systemctl restart $1.service
318*9af6c78cSPedro F. Giffuni			fi'
319*9af6c78cSPedro F. Giffuni	elif [ -x /sbin/rc-service ] &&
320*9af6c78cSPedro F. Giffuni	     { [ -s /libexec/rc/init.d/softlevel ] ||
321*9af6c78cSPedro F. Giffuni	     [ -s /run/openrc/softlevel ]; }
322*9af6c78cSPedro F. Giffuni	then
323*9af6c78cSPedro F. Giffuni		RESTARTCMD='/sbin/rc-service -i $1 -- -Ds restart'
3243f2a60a1SPedro F. Giffuni	elif [ -x /usr/sbin/invoke-rc.d ]; then
3253f2a60a1SPedro F. Giffuni		RCDIR=/etc/init.d
326*9af6c78cSPedro F. Giffuni		RESTARTCMD='
327*9af6c78cSPedro F. Giffuni		   if /usr/sbin/invoke-rc.d --quiet $1 status >/dev/null 2>&1
328*9af6c78cSPedro F. Giffuni		   then
329*9af6c78cSPedro F. Giffuni			/usr/sbin/invoke-rc.d $1 restart
330*9af6c78cSPedro F. Giffuni		   fi'
3313f2a60a1SPedro F. Giffuni	elif [ -x /sbin/service ]; then
3323f2a60a1SPedro F. Giffuni		# Old RedHat
3333f2a60a1SPedro F. Giffuni		RCDIR=/etc/init.d
334*9af6c78cSPedro F. Giffuni		RESTARTCMD='
335*9af6c78cSPedro F. Giffuni			if /sbin/service $1; then
336*9af6c78cSPedro F. Giffuni				/sbin/service $1 restart
337*9af6c78cSPedro F. Giffuni			fi'
3383f2a60a1SPedro F. Giffuni	elif [ -x /usr/sbin/service ]; then
3393f2a60a1SPedro F. Giffuni		# Could be FreeBSD
340*9af6c78cSPedro F. Giffuni		RESTARTCMD="
341*9af6c78cSPedro F. Giffuni			if /usr/sbin/service \$1 $status >/dev/null 2>&1
342*9af6c78cSPedro F. Giffuni			then
343*9af6c78cSPedro F. Giffuni				/usr/sbin/service \$1 restart
3443f2a60a1SPedro F. Giffuni			fi"
3453f2a60a1SPedro F. Giffuni	elif [ -x /bin/sv ]; then
346*9af6c78cSPedro F. Giffuni		RESTARTCMD='/bin/sv status $1 >/dev/null 2>&1 &&
347*9af6c78cSPedro F. Giffuni			    /bin/sv try-restart $1'
3483f2a60a1SPedro F. Giffuni	elif [ -x /usr/bin/sv ]; then
349*9af6c78cSPedro F. Giffuni		RESTARTCMD='/usr/bin/sv status $1 >/dev/null 2>&1 &&
350*9af6c78cSPedro F. Giffuni			    /usr/bin/sv try-restart $1'
351*9af6c78cSPedro F. Giffuni	elif [ -e /etc/arch-release ] && [ -d /etc/rc.d ]; then
3523f2a60a1SPedro F. Giffuni		RCDIR=/etc/rc.d
353*9af6c78cSPedro F. Giffuni		RESTARTCMD='
354*9af6c78cSPedro F. Giffuni			if [ -e /var/run/daemons/$1 ]
355*9af6c78cSPedro F. Giffuni			then
356*9af6c78cSPedro F. Giffuni				/etc/rc.d/$1 restart
357*9af6c78cSPedro F. Giffuni			fi'
358*9af6c78cSPedro F. Giffuni	elif [ -e /etc/slackware-version ] && [ -d /etc/rc.d ]; then
359*9af6c78cSPedro F. Giffuni		RESTARTCMD='
360*9af6c78cSPedro F. Giffuni			if /etc/rc.d/rc.$1 status >/dev/null 2>&1
361*9af6c78cSPedro F. Giffuni			then
362*9af6c78cSPedro F. Giffuni				/etc/rc.d/rc.$1 restart
363*9af6c78cSPedro F. Giffuni			fi'
364*9af6c78cSPedro F. Giffuni	elif [ -e /etc/rc.d/rc.subr ] && [ -d /etc/rc.d ]; then
3653f2a60a1SPedro F. Giffuni		# OpenBSD
366*9af6c78cSPedro F. Giffuni		RESTARTCMD='
367*9af6c78cSPedro F. Giffuni			if /etc/rc.d/$1 check >/dev/null 2>&1
368*9af6c78cSPedro F. Giffuni			then
369*9af6c78cSPedro F. Giffuni				/etc/rc.d/$1 restart
370*9af6c78cSPedro F. Giffuni			fi'
3713f2a60a1SPedro F. Giffuni	else
3723f2a60a1SPedro F. Giffuni		for x in /etc/init.d/rc.d /etc/rc.d /etc/init.d; do
3733f2a60a1SPedro F. Giffuni			[ -d $x ] || continue
374*9af6c78cSPedro F. Giffuni			RESTARTCMD="
375*9af6c78cSPedro F. Giffuni				if $x/\$1 $status >/dev/null 2>&1
376*9af6c78cSPedro F. Giffuni				then
377*9af6c78cSPedro F. Giffuni					$x/\$1 restart
3783f2a60a1SPedro F. Giffuni				fi"
3793f2a60a1SPedro F. Giffuni			break
3803f2a60a1SPedro F. Giffuni		done
3813f2a60a1SPedro F. Giffuni	fi
3823f2a60a1SPedro F. Giffuni
3833f2a60a1SPedro F. Giffuni	if [ -z "$RESTARTCMD" ]; then
384*9af6c78cSPedro F. Giffuni		if [ "$_NOINIT_WARNED" != true ]; then
3853f2a60a1SPedro F. Giffuni			warn "could not detect a useable init system"
3863f2a60a1SPedro F. Giffuni			_NOINIT_WARNED=true
3873f2a60a1SPedro F. Giffuni		fi
3883f2a60a1SPedro F. Giffuni		return 1
3893f2a60a1SPedro F. Giffuni	fi
3903f2a60a1SPedro F. Giffuni	_NOINIT_WARNED=
3913f2a60a1SPedro F. Giffuni	return 0
3923f2a60a1SPedro F. Giffuni}
3933f2a60a1SPedro F. Giffuni
3943f2a60a1SPedro F. Giffuniecho_resolv()
3953f2a60a1SPedro F. Giffuni{
396*9af6c78cSPedro F. Giffuni	OIFS="$IFS"
3973f2a60a1SPedro F. Giffuni
398*9af6c78cSPedro F. Giffuni	[ -n "$1" ] && [ -f "$IFACEDIR/$1" ] || return 1
3993f2a60a1SPedro F. Giffuni	echo "# resolv.conf from $1"
4003f2a60a1SPedro F. Giffuni	# Our variable maker works of the fact each resolv.conf per interface
4013f2a60a1SPedro F. Giffuni	# is separated by blank lines.
4023f2a60a1SPedro F. Giffuni	# So we remove them when echoing them.
4033f2a60a1SPedro F. Giffuni	while read -r line; do
4043f2a60a1SPedro F. Giffuni		IFS="$OIFS"
4053f2a60a1SPedro F. Giffuni		if [ -n "$line" ]; then
4063f2a60a1SPedro F. Giffuni			# We need to set IFS here to preserve any whitespace
4073f2a60a1SPedro F. Giffuni			IFS=''
4083f2a60a1SPedro F. Giffuni			printf "%s\n" "$line"
4093f2a60a1SPedro F. Giffuni		fi
4103f2a60a1SPedro F. Giffuni	done < "$IFACEDIR/$1"
4113f2a60a1SPedro F. Giffuni	IFS="$OIFS"
4123f2a60a1SPedro F. Giffuni}
4133f2a60a1SPedro F. Giffuni
414587392a5SHajimu UMEMOTOlist_resolv()
415587392a5SHajimu UMEMOTO{
416587392a5SHajimu UMEMOTO	[ -d "$IFACEDIR" ] || return 0
417587392a5SHajimu UMEMOTO
418*9af6c78cSPedro F. Giffuni	cmd="$1"
419587392a5SHajimu UMEMOTO	shift
420*9af6c78cSPedro F. Giffuni	excl=false
421*9af6c78cSPedro F. Giffuni	list=
422*9af6c78cSPedro F. Giffuni	report=false
423*9af6c78cSPedro F. Giffuni	retval=0
424587392a5SHajimu UMEMOTO
425d7149f4eSGlen Barber	case "$IF_EXCLUSIVE" in
426d7149f4eSGlen Barber	[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
427*9af6c78cSPedro F. Giffuni		excl=true
428d7149f4eSGlen Barber		if [ -d "$EXCLUSIVEDIR" ]; then
429d7149f4eSGlen Barber			cd "$EXCLUSIVEDIR"
430d7149f4eSGlen Barber			for i in *; do
431d7149f4eSGlen Barber				if [ -f "$i" ]; then
432d7149f4eSGlen Barber					list="${i#* }"
433d7149f4eSGlen Barber					break
434d7149f4eSGlen Barber				fi
435d7149f4eSGlen Barber			done
436d7149f4eSGlen Barber		fi
43787b2cfceSPedro F. Giffuni		cd "$IFACEDIR"
43887b2cfceSPedro F. Giffuni		for i in $inclusive_interfaces; do
439*9af6c78cSPedro F. Giffuni			if [ -f "$i" ] && [ "$list" = "$i" ]; then
44087b2cfceSPedro F. Giffuni				list=
44187b2cfceSPedro F. Giffuni				excl=false
44287b2cfceSPedro F. Giffuni				break
44387b2cfceSPedro F. Giffuni			fi
44487b2cfceSPedro F. Giffuni		done
445d7149f4eSGlen Barber		;;
446d7149f4eSGlen Barber	esac
447d7149f4eSGlen Barber
448587392a5SHajimu UMEMOTO	# If we have an interface ordering list, then use that.
449587392a5SHajimu UMEMOTO	# It works by just using pathname expansion in the interface directory.
450587392a5SHajimu UMEMOTO	if [ -n "$1" ]; then
451d7149f4eSGlen Barber		list="$*"
452587392a5SHajimu UMEMOTO		$force || report=true
453d7149f4eSGlen Barber	elif ! $excl; then
454587392a5SHajimu UMEMOTO		cd "$IFACEDIR"
455587392a5SHajimu UMEMOTO		for i in $interface_order; do
456d7149f4eSGlen Barber			[ -f "$i" ] && list="$list $i"
457d7149f4eSGlen Barber			for ii in "$i":* "$i".*; do
458d7149f4eSGlen Barber				[ -f "$ii" ] && list="$list $ii"
459d7149f4eSGlen Barber			done
460587392a5SHajimu UMEMOTO		done
461587392a5SHajimu UMEMOTO		for i in $dynamic_order; do
462*9af6c78cSPedro F. Giffuni			if [ -e "$i" ] && ! [ -e "$METRICDIR/"*" $i" ]; then
463587392a5SHajimu UMEMOTO				list="$list $i"
464587392a5SHajimu UMEMOTO			fi
465d7149f4eSGlen Barber			for ii in "$i":* "$i".*; do
466*9af6c78cSPedro F. Giffuni				if [ -f "$ii" ] && ! [ -e "$METRICDIR/"*" $ii" ]
467*9af6c78cSPedro F. Giffuni				then
468d7149f4eSGlen Barber					list="$list $ii"
469d7149f4eSGlen Barber				fi
470d7149f4eSGlen Barber			done
471587392a5SHajimu UMEMOTO		done
472*9af6c78cSPedro F. Giffuni		# Interfaces have an implicit metric of 0 if not specified.
473*9af6c78cSPedro F. Giffuni		for i in *; do
474*9af6c78cSPedro F. Giffuni			if [ -f "$i" ] && ! [ -e "$METRICDIR/"*" $i" ]; then
475*9af6c78cSPedro F. Giffuni				list="$list $i"
476*9af6c78cSPedro F. Giffuni			fi
477*9af6c78cSPedro F. Giffuni		done
478587392a5SHajimu UMEMOTO		if [ -d "$METRICDIR" ]; then
479587392a5SHajimu UMEMOTO			cd "$METRICDIR"
480587392a5SHajimu UMEMOTO			for i in *; do
481d7149f4eSGlen Barber				[ -f "$i" ] && list="$list ${i#* }"
482587392a5SHajimu UMEMOTO			done
483587392a5SHajimu UMEMOTO		fi
484587392a5SHajimu UMEMOTO	fi
485587392a5SHajimu UMEMOTO
486587392a5SHajimu UMEMOTO	cd "$IFACEDIR"
487d7149f4eSGlen Barber	retval=1
488587392a5SHajimu UMEMOTO	for i in $(uniqify $list); do
489587392a5SHajimu UMEMOTO		# Only list interfaces which we really have
490d7149f4eSGlen Barber		if ! [ -f "$i" ]; then
491587392a5SHajimu UMEMOTO			if $report; then
492587392a5SHajimu UMEMOTO				echo "No resolv.conf for interface $i" >&2
493d7149f4eSGlen Barber				retval=2
494587392a5SHajimu UMEMOTO			fi
495587392a5SHajimu UMEMOTO			continue
496587392a5SHajimu UMEMOTO		fi
497587392a5SHajimu UMEMOTO
498*9af6c78cSPedro F. Giffuni		if [ "$cmd" = i ] || [ "$cmd" = "-i" ]; then
499d7149f4eSGlen Barber			printf %s "$i "
500587392a5SHajimu UMEMOTO		else
50187b2cfceSPedro F. Giffuni			echo_resolv "$i" && echo
502587392a5SHajimu UMEMOTO		fi
503*9af6c78cSPedro F. Giffuni		[ $? = 0 ] && [ "$retval" = 1 ] && retval=0
504587392a5SHajimu UMEMOTO	done
505*9af6c78cSPedro F. Giffuni	[ "$cmd" = i ] || [ "$cmd" = "-i" ] && echo
506587392a5SHajimu UMEMOTO	return $retval
507587392a5SHajimu UMEMOTO}
508587392a5SHajimu UMEMOTO
509*9af6c78cSPedro F. Giffunilist_remove()
510*9af6c78cSPedro F. Giffuni{
511d7149f4eSGlen Barber	[ -z "$2" ] && return 0
512d7149f4eSGlen Barber	eval list=\"\$$1\"
513d7149f4eSGlen Barber	shift
514*9af6c78cSPedro F. Giffuni	result=
515*9af6c78cSPedro F. Giffuni	retval=0
516d7149f4eSGlen Barber
517d7149f4eSGlen Barber	set -f
518d7149f4eSGlen Barber	for e; do
519d7149f4eSGlen Barber		found=false
520d7149f4eSGlen Barber		for l in $list; do
521d7149f4eSGlen Barber			case "$e" in
522d7149f4eSGlen Barber			$l) found=true;;
523d7149f4eSGlen Barber			esac
524d7149f4eSGlen Barber			$found && break
525d7149f4eSGlen Barber		done
526d7149f4eSGlen Barber		if $found; then
527d7149f4eSGlen Barber			retval=$(($retval + 1))
528d7149f4eSGlen Barber		else
529d7149f4eSGlen Barber			result="$result $e"
530d7149f4eSGlen Barber		fi
531d7149f4eSGlen Barber	done
532d7149f4eSGlen Barber	set +f
533d7149f4eSGlen Barber	echo "${result# *}"
534d7149f4eSGlen Barber	return $retval
535d7149f4eSGlen Barber}
536d7149f4eSGlen Barber
537d7149f4eSGlen Barberecho_prepend()
538d7149f4eSGlen Barber{
539d7149f4eSGlen Barber	echo "# Generated by resolvconf"
540d7149f4eSGlen Barber	if [ -n "$search_domains" ]; then
541d7149f4eSGlen Barber		echo "search $search_domains"
542d7149f4eSGlen Barber	fi
543d7149f4eSGlen Barber	for n in $name_servers; do
544d7149f4eSGlen Barber		echo "nameserver $n"
545d7149f4eSGlen Barber	done
546d7149f4eSGlen Barber	echo
547d7149f4eSGlen Barber}
548d7149f4eSGlen Barber
549d7149f4eSGlen Barberecho_append()
550d7149f4eSGlen Barber{
551d7149f4eSGlen Barber	echo "# Generated by resolvconf"
552d7149f4eSGlen Barber	if [ -n "$search_domains_append" ]; then
553d7149f4eSGlen Barber		echo "search $search_domains_append"
554d7149f4eSGlen Barber	fi
555d7149f4eSGlen Barber	for n in $name_servers_append; do
556d7149f4eSGlen Barber		echo "nameserver $n"
557d7149f4eSGlen Barber	done
558d7149f4eSGlen Barber	echo
559d7149f4eSGlen Barber}
560d7149f4eSGlen Barber
561d7149f4eSGlen Barberreplace()
562d7149f4eSGlen Barber{
563d7149f4eSGlen Barber	while read -r keyword value; do
564d7149f4eSGlen Barber		for r in $replace; do
565d7149f4eSGlen Barber			k="${r%%/*}"
566d7149f4eSGlen Barber			r="${r#*/}"
567d7149f4eSGlen Barber			f="${r%%/*}"
568d7149f4eSGlen Barber			r="${r#*/}"
569d7149f4eSGlen Barber			v="${r%%/*}"
570d7149f4eSGlen Barber			case "$keyword" in
571d7149f4eSGlen Barber			$k)
572d7149f4eSGlen Barber				case "$value" in
573d7149f4eSGlen Barber				$f) value="$v";;
574d7149f4eSGlen Barber				esac
575d7149f4eSGlen Barber				;;
576d7149f4eSGlen Barber			esac
577d7149f4eSGlen Barber		done
578d7149f4eSGlen Barber		val=
579d7149f4eSGlen Barber		for sub in $value; do
580d7149f4eSGlen Barber			for r in $replace_sub; do
581d7149f4eSGlen Barber				k="${r%%/*}"
582d7149f4eSGlen Barber				r="${r#*/}"
583d7149f4eSGlen Barber				f="${r%%/*}"
584d7149f4eSGlen Barber				r="${r#*/}"
585d7149f4eSGlen Barber				v="${r%%/*}"
586d7149f4eSGlen Barber				case "$keyword" in
587d7149f4eSGlen Barber				$k)
588d7149f4eSGlen Barber					case "$sub" in
589d7149f4eSGlen Barber					$f) sub="$v";;
590d7149f4eSGlen Barber					esac
591d7149f4eSGlen Barber					;;
592d7149f4eSGlen Barber				esac
593d7149f4eSGlen Barber			done
594d7149f4eSGlen Barber			val="$val${val:+ }$sub"
595d7149f4eSGlen Barber		done
596d7149f4eSGlen Barber		printf "%s %s\n" "$keyword" "$val"
597d7149f4eSGlen Barber	done
598d7149f4eSGlen Barber}
599d7149f4eSGlen Barber
600587392a5SHajimu UMEMOTOmake_vars()
601587392a5SHajimu UMEMOTO{
602d7149f4eSGlen Barber	# Clear variables
603d7149f4eSGlen Barber	DOMAIN=
604d7149f4eSGlen Barber	DOMAINS=
605d7149f4eSGlen Barber	SEARCH=
606d7149f4eSGlen Barber	NAMESERVERS=
607d7149f4eSGlen Barber	LOCALNAMESERVERS=
608d7149f4eSGlen Barber
609*9af6c78cSPedro F. Giffuni	if [ -n "${name_servers}${search_domains}" ]; then
610d7149f4eSGlen Barber		eval "$(echo_prepend | parse_resolv)"
611d7149f4eSGlen Barber	fi
612d7149f4eSGlen Barber	if [ -z "$VFLAG" ]; then
613d7149f4eSGlen Barber		IF_EXCLUSIVE=1
614d7149f4eSGlen Barber		list_resolv -i "$@" >/dev/null || IF_EXCLUSIVE=0
615d7149f4eSGlen Barber		eval "$(list_resolv -l "$@" | replace | parse_resolv)"
616d7149f4eSGlen Barber	fi
617*9af6c78cSPedro F. Giffuni	if [ -n "${name_servers_append}${search_domains_append}" ]; then
618d7149f4eSGlen Barber		eval "$(echo_append | parse_resolv)"
619d7149f4eSGlen Barber	fi
620587392a5SHajimu UMEMOTO
621587392a5SHajimu UMEMOTO	# Ensure that we only list each domain once
622*9af6c78cSPedro F. Giffuni	newdomains=
623587392a5SHajimu UMEMOTO	for d in $DOMAINS; do
624587392a5SHajimu UMEMOTO		dn="${d%%:*}"
625d7149f4eSGlen Barber		list_remove domain_blacklist "$dn" >/dev/null || continue
626587392a5SHajimu UMEMOTO		case " $newdomains" in
627587392a5SHajimu UMEMOTO		*" ${dn}:"*) continue;;
628587392a5SHajimu UMEMOTO		esac
629587392a5SHajimu UMEMOTO		newns=
630587392a5SHajimu UMEMOTO		for nd in $DOMAINS; do
631587392a5SHajimu UMEMOTO			if [ "$dn" = "${nd%%:*}" ]; then
632587392a5SHajimu UMEMOTO				ns="${nd#*:}"
633587392a5SHajimu UMEMOTO				while [ -n "$ns" ]; do
634587392a5SHajimu UMEMOTO					case ",$newns," in
635587392a5SHajimu UMEMOTO					*,${ns%%,*},*) ;;
636d7149f4eSGlen Barber					*) list_remove name_server_blacklist \
637d7149f4eSGlen Barber						"${ns%%,*}" >/dev/null \
638d7149f4eSGlen Barber					&& newns="$newns${newns:+,}${ns%%,*}";;
639587392a5SHajimu UMEMOTO					esac
640587392a5SHajimu UMEMOTO					[ "$ns" = "${ns#*,}" ] && break
641587392a5SHajimu UMEMOTO					ns="${ns#*,}"
642587392a5SHajimu UMEMOTO				done
643587392a5SHajimu UMEMOTO			fi
644587392a5SHajimu UMEMOTO		done
645d7149f4eSGlen Barber		if [ -n "$newns" ]; then
646d7149f4eSGlen Barber			newdomains="$newdomains${newdomains:+ }$dn:$newns"
647d7149f4eSGlen Barber		fi
648587392a5SHajimu UMEMOTO	done
649d7149f4eSGlen Barber	DOMAIN="$(list_remove domain_blacklist $DOMAIN)"
650d7149f4eSGlen Barber	SEARCH="$(uniqify $SEARCH)"
651d7149f4eSGlen Barber	SEARCH="$(list_remove domain_blacklist $SEARCH)"
652d7149f4eSGlen Barber	NAMESERVERS="$(uniqify $NAMESERVERS)"
653d7149f4eSGlen Barber	NAMESERVERS="$(list_remove name_server_blacklist $NAMESERVERS)"
654d7149f4eSGlen Barber	LOCALNAMESERVERS="$(uniqify $LOCALNAMESERVERS)"
655d7149f4eSGlen Barber	LOCALNAMESERVERS="$(list_remove name_server_blacklist $LOCALNAMESERVERS)"
656d7149f4eSGlen Barber	echo "DOMAIN='$DOMAIN'"
657d7149f4eSGlen Barber	echo "SEARCH='$SEARCH'"
658d7149f4eSGlen Barber	echo "NAMESERVERS='$NAMESERVERS'"
659d7149f4eSGlen Barber	echo "LOCALNAMESERVERS='$LOCALNAMESERVERS'"
660587392a5SHajimu UMEMOTO	echo "DOMAINS='$newdomains'"
661587392a5SHajimu UMEMOTO}
662587392a5SHajimu UMEMOTO
663587392a5SHajimu UMEMOTOforce=false
664d7149f4eSGlen BarberVFLAG=
6653f2a60a1SPedro F. Giffuniwhile getopts a:Dd:fhIilm:pRruvVx OPT; do
666587392a5SHajimu UMEMOTO	case "$OPT" in
667587392a5SHajimu UMEMOTO	f) force=true;;
668587392a5SHajimu UMEMOTO	h) usage;;
669587392a5SHajimu UMEMOTO	m) IF_METRIC="$OPTARG";;
670587392a5SHajimu UMEMOTO	p) IF_PRIVATE=1;;
671d7149f4eSGlen Barber	V)
672d7149f4eSGlen Barber		VFLAG=1
673d7149f4eSGlen Barber		if [ "$local_nameservers" = \
674d7149f4eSGlen Barber		    "127.* 0.0.0.0 255.255.255.255 ::1" ]
675d7149f4eSGlen Barber		then
676d7149f4eSGlen Barber			local_nameservers=
677d7149f4eSGlen Barber		fi
678d7149f4eSGlen Barber		;;
679d7149f4eSGlen Barber	x) IF_EXCLUSIVE=1;;
680587392a5SHajimu UMEMOTO	'?') ;;
681587392a5SHajimu UMEMOTO	*) cmd="$OPT"; iface="$OPTARG";;
682587392a5SHajimu UMEMOTO	esac
683587392a5SHajimu UMEMOTOdone
684587392a5SHajimu UMEMOTOshift $(($OPTIND - 1))
685d7149f4eSGlen Barberargs="$iface${iface:+ }$*"
686587392a5SHajimu UMEMOTO
687587392a5SHajimu UMEMOTO# -I inits the state dir
688587392a5SHajimu UMEMOTOif [ "$cmd" = I ]; then
689587392a5SHajimu UMEMOTO	if [ -d "$VARDIR" ]; then
690587392a5SHajimu UMEMOTO		rm -rf "$VARDIR"/*
691587392a5SHajimu UMEMOTO	fi
692587392a5SHajimu UMEMOTO	exit $?
693587392a5SHajimu UMEMOTOfi
694587392a5SHajimu UMEMOTO
695d7149f4eSGlen Barber# -D ensures that the listed config file base dirs exist
696d7149f4eSGlen Barberif [ "$cmd" = D ]; then
697d7149f4eSGlen Barber	config_mkdirs "$@"
698d7149f4eSGlen Barber	exit $?
699d7149f4eSGlen Barberfi
700d7149f4eSGlen Barber
701587392a5SHajimu UMEMOTO# -l lists our resolv files, optionally for a specific interface
702*9af6c78cSPedro F. Giffuniif [ "$cmd" = l ] || [ "$cmd" = i ]; then
703587392a5SHajimu UMEMOTO	list_resolv "$cmd" "$args"
704587392a5SHajimu UMEMOTO	exit $?
705587392a5SHajimu UMEMOTOfi
706587392a5SHajimu UMEMOTO
7073f2a60a1SPedro F. Giffuni# Restart a service or echo the command to restart a service
708*9af6c78cSPedro F. Giffuniif [ "$cmd" = r ] || [ "$cmd" = R ]; then
7093f2a60a1SPedro F. Giffuni	detect_init || exit 1
7103f2a60a1SPedro F. Giffuni	if [ "$cmd" = r ]; then
7113f2a60a1SPedro F. Giffuni		set -- $args
712*9af6c78cSPedro F. Giffuni		eval "$RESTARTCMD"
7133f2a60a1SPedro F. Giffuni	else
714*9af6c78cSPedro F. Giffuni		echo "$RESTARTCMD" |
715*9af6c78cSPedro F. Giffuni			sed -e '/^$/d' -e 's/^			//g'
7163f2a60a1SPedro F. Giffuni	fi
7173f2a60a1SPedro F. Giffuni	exit $?
7183f2a60a1SPedro F. Giffunifi
7193f2a60a1SPedro F. Giffuni
720587392a5SHajimu UMEMOTO# Not normally needed, but subscribers should be able to run independently
721*9af6c78cSPedro F. Giffuniif [ "$cmd" = v ] || [ -n "$VFLAG" ]; then
722587392a5SHajimu UMEMOTO	make_vars "$iface"
723587392a5SHajimu UMEMOTO	exit $?
724587392a5SHajimu UMEMOTOfi
725587392a5SHajimu UMEMOTO
726587392a5SHajimu UMEMOTO# Test that we have valid options
727*9af6c78cSPedro F. Giffuniif [ "$cmd" = a ] || [ "$cmd" = d ]; then
728587392a5SHajimu UMEMOTO	if [ -z "$iface" ]; then
729587392a5SHajimu UMEMOTO		usage "Interface not specified"
730587392a5SHajimu UMEMOTO	fi
731587392a5SHajimu UMEMOTOelif [ "$cmd" != u ]; then
732*9af6c78cSPedro F. Giffuni	[ -n "$cmd" ] && [ "$cmd" != h ] && usage "Unknown option $cmd"
733587392a5SHajimu UMEMOTO	usage
734587392a5SHajimu UMEMOTOfi
735d7149f4eSGlen Barber
736587392a5SHajimu UMEMOTOif [ "$cmd" = a ]; then
737587392a5SHajimu UMEMOTO	for x in '/' \\ ' ' '*'; do
738587392a5SHajimu UMEMOTO		case "$iface" in
739587392a5SHajimu UMEMOTO		*[$x]*) error_exit "$x not allowed in interface name";;
740587392a5SHajimu UMEMOTO		esac
741587392a5SHajimu UMEMOTO	done
742587392a5SHajimu UMEMOTO	for x in '.' '-' '~'; do
743587392a5SHajimu UMEMOTO		case "$iface" in
744587392a5SHajimu UMEMOTO		[$x]*) error_exit \
745587392a5SHajimu UMEMOTO			"$x not allowed at start of interface name";;
746587392a5SHajimu UMEMOTO		esac
747587392a5SHajimu UMEMOTO	done
748*9af6c78cSPedro F. Giffuni	[ "$cmd" = a ] && [ -t 0 ] && error_exit "No file given via stdin"
749587392a5SHajimu UMEMOTOfi
750587392a5SHajimu UMEMOTO
751587392a5SHajimu UMEMOTOif [ ! -d "$VARDIR" ]; then
752587392a5SHajimu UMEMOTO	if [ -L "$VARDIR" ]; then
753587392a5SHajimu UMEMOTO		dir="$(readlink "$VARDIR")"
754587392a5SHajimu UMEMOTO		# link maybe relative
755587392a5SHajimu UMEMOTO		cd "${VARDIR%/*}"
756587392a5SHajimu UMEMOTO		if ! mkdir -m 0755 -p "$dir"; then
757587392a5SHajimu UMEMOTO			error_exit "Failed to create needed" \
758587392a5SHajimu UMEMOTO				"directory $dir"
759587392a5SHajimu UMEMOTO		fi
760587392a5SHajimu UMEMOTO	else
761587392a5SHajimu UMEMOTO		if ! mkdir -m 0755 -p "$VARDIR"; then
762587392a5SHajimu UMEMOTO			error_exit "Failed to create needed" \
763587392a5SHajimu UMEMOTO				"directory $VARDIR"
764587392a5SHajimu UMEMOTO		fi
765587392a5SHajimu UMEMOTO	fi
766587392a5SHajimu UMEMOTOfi
767d7149f4eSGlen Barber
768d7149f4eSGlen Barberif [ ! -d "$IFACEDIR" ]; then
769587392a5SHajimu UMEMOTO	mkdir -m 0755 -p "$IFACEDIR" || \
770587392a5SHajimu UMEMOTO		error_exit "Failed to create needed directory $IFACEDIR"
771587392a5SHajimu UMEMOTO	if [ "$cmd" = d ]; then
772d7149f4eSGlen Barber		# Provide the same error messages as below
773d7149f4eSGlen Barber		if ! ${force}; then
774587392a5SHajimu UMEMOTO			cd "$IFACEDIR"
775587392a5SHajimu UMEMOTO			for i in $args; do
776d7149f4eSGlen Barber				warn "No resolv.conf for interface $i"
777587392a5SHajimu UMEMOTO			done
778587392a5SHajimu UMEMOTO		fi
779d7149f4eSGlen Barber		${force}
780d7149f4eSGlen Barber		exit $?
781d7149f4eSGlen Barber	fi
782587392a5SHajimu UMEMOTOfi
783587392a5SHajimu UMEMOTO
784d7149f4eSGlen Barber# An interface was added, changed, deleted or a general update was called.
785d7149f4eSGlen Barber# Due to exclusivity we need to ensure that this is an atomic operation.
786d7149f4eSGlen Barber# Our subscribers *may* need this as well if the init system is sub par.
787d7149f4eSGlen Barber# As such we spinlock at this point as best we can.
788d7149f4eSGlen Barber# We don't use flock(1) because it's not widely available and normally resides
789d7149f4eSGlen Barber# in /usr which we do our very best to operate without.
790d7149f4eSGlen Barber[ -w "$VARDIR" ] || error_exit "Cannot write to $LOCKDIR"
791d7149f4eSGlen Barber: ${lock_timeout:=10}
792d7149f4eSGlen Barberwhile true; do
793d7149f4eSGlen Barber	if mkdir "$LOCKDIR" 2>/dev/null; then
794d7149f4eSGlen Barber		trap 'rm -rf "$LOCKDIR";' EXIT
795d7149f4eSGlen Barber		trap 'rm -rf "$LOCKDIR"; exit 1' INT QUIT ABRT SEGV ALRM TERM
796d7149f4eSGlen Barber		echo $$ >"$LOCKDIR/pid"
797d7149f4eSGlen Barber		break
798d7149f4eSGlen Barber	fi
799d7149f4eSGlen Barber	pid=$(cat "$LOCKDIR/pid")
800d7149f4eSGlen Barber	if ! kill -0 "$pid"; then
801d7149f4eSGlen Barber		warn "clearing stale lock pid $pid"
802d7149f4eSGlen Barber		rm -rf "$LOCKDIR"
803d7149f4eSGlen Barber		continue
804d7149f4eSGlen Barber	fi
805d7149f4eSGlen Barber	lock_timeout=$(($lock_timeout - 1))
806d7149f4eSGlen Barber	if [ "$lock_timeout" -le 0 ]; then
807d7149f4eSGlen Barber		error_exit "timed out waiting for lock from pid $pid"
808d7149f4eSGlen Barber	fi
809d7149f4eSGlen Barber	sleep 1
810d7149f4eSGlen Barberdone
811d7149f4eSGlen Barber
812d7149f4eSGlen Barbercase "$cmd" in
813d7149f4eSGlen Barbera)
814587392a5SHajimu UMEMOTO	# Read resolv.conf from stdin
815a02aba5fSHiroki Sato	resolv="$(cat)"
816d7149f4eSGlen Barber	changed=false
817d7149f4eSGlen Barber	changedfile=false
818587392a5SHajimu UMEMOTO	# If what we are given matches what we have, then do nothing
819587392a5SHajimu UMEMOTO	if [ -e "$IFACEDIR/$iface" ]; then
820d7149f4eSGlen Barber		if [ "$(echo "$resolv")" != \
821587392a5SHajimu UMEMOTO			"$(cat "$IFACEDIR/$iface")" ]
822587392a5SHajimu UMEMOTO		then
823d7149f4eSGlen Barber			changed=true
824d7149f4eSGlen Barber			changedfile=true
825587392a5SHajimu UMEMOTO		fi
826d7149f4eSGlen Barber	else
827d7149f4eSGlen Barber		changed=true
828d7149f4eSGlen Barber		changedfile=true
829587392a5SHajimu UMEMOTO	fi
830d7149f4eSGlen Barber
831d7149f4eSGlen Barber	# Set metric and private before creating the interface resolv.conf file
832d7149f4eSGlen Barber	# to ensure that it will have the correct flags
833587392a5SHajimu UMEMOTO	[ ! -d "$METRICDIR" ] && mkdir "$METRICDIR"
834d7149f4eSGlen Barber	oldmetric="$METRICDIR/"*" $iface"
835d7149f4eSGlen Barber	newmetric=
836587392a5SHajimu UMEMOTO	if [ -n "$IF_METRIC" ]; then
837587392a5SHajimu UMEMOTO		# Pad metric to 6 characters, so 5 is less than 10
838587392a5SHajimu UMEMOTO		while [ ${#IF_METRIC} -le 6 ]; do
839587392a5SHajimu UMEMOTO			IF_METRIC="0$IF_METRIC"
840587392a5SHajimu UMEMOTO		done
841d7149f4eSGlen Barber		newmetric="$METRICDIR/$IF_METRIC $iface"
842587392a5SHajimu UMEMOTO	fi
843d7149f4eSGlen Barber	rm -f "$METRICDIR/"*" $iface"
844*9af6c78cSPedro F. Giffuni	[ "$oldmetric" != "$newmetric" ] &&
845*9af6c78cSPedro F. Giffuni	    [ "$oldmetric" != "$METRICDIR/* $iface" ] &&
846d7149f4eSGlen Barber		changed=true
847d7149f4eSGlen Barber	[ -n "$newmetric" ] && echo " " >"$newmetric"
848d7149f4eSGlen Barber
849587392a5SHajimu UMEMOTO	case "$IF_PRIVATE" in
850587392a5SHajimu UMEMOTO	[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
851587392a5SHajimu UMEMOTO		if [ ! -d "$PRIVATEDIR" ]; then
852587392a5SHajimu UMEMOTO			[ -e "$PRIVATEDIR" ] && rm "$PRIVATEDIR"
853587392a5SHajimu UMEMOTO			mkdir "$PRIVATEDIR"
854587392a5SHajimu UMEMOTO		fi
855d7149f4eSGlen Barber		[ -e "$PRIVATEDIR/$iface" ] || changed=true
856587392a5SHajimu UMEMOTO		[ -d "$PRIVATEDIR" ] && echo " " >"$PRIVATEDIR/$iface"
857587392a5SHajimu UMEMOTO		;;
858587392a5SHajimu UMEMOTO	*)
859587392a5SHajimu UMEMOTO		if [ -e "$PRIVATEDIR/$iface" ]; then
860587392a5SHajimu UMEMOTO			rm -f "$PRIVATEDIR/$iface"
861d7149f4eSGlen Barber			changed=true
862587392a5SHajimu UMEMOTO		fi
863587392a5SHajimu UMEMOTO		;;
864587392a5SHajimu UMEMOTO	esac
865d7149f4eSGlen Barber
866d7149f4eSGlen Barber	oldexcl=
867d7149f4eSGlen Barber	for x in "$EXCLUSIVEDIR/"*" $iface"; do
868d7149f4eSGlen Barber		if [ -f "$x" ]; then
869d7149f4eSGlen Barber			oldexcl="$x"
870d7149f4eSGlen Barber			break
871587392a5SHajimu UMEMOTO		fi
872d7149f4eSGlen Barber	done
873d7149f4eSGlen Barber	case "$IF_EXCLUSIVE" in
874d7149f4eSGlen Barber	[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
875d7149f4eSGlen Barber		if [ ! -d "$EXCLUSIVEDIR" ]; then
876d7149f4eSGlen Barber			[ -e "$EXCLUSIVEDIR" ] && rm "$EXCLUSIVEDIR"
877d7149f4eSGlen Barber			mkdir "$EXCLUSIVEDIR"
878d7149f4eSGlen Barber		fi
879d7149f4eSGlen Barber		cd "$EXCLUSIVEDIR"
880d7149f4eSGlen Barber		for x in *; do
881d7149f4eSGlen Barber			[ -f "$x" ] && break
882d7149f4eSGlen Barber		done
883d7149f4eSGlen Barber		if [ "${x#* }" != "$iface" ]; then
884d7149f4eSGlen Barber			if [ "$x" = "${x% *}" ]; then
885d7149f4eSGlen Barber				x=10000000
886d7149f4eSGlen Barber			else
887d7149f4eSGlen Barber				x="${x% *}"
888d7149f4eSGlen Barber			fi
889d7149f4eSGlen Barber			if [ "$x" = "0000000" ]; then
890d7149f4eSGlen Barber				warn "exclusive underflow"
891d7149f4eSGlen Barber			else
892d7149f4eSGlen Barber				x=$(($x - 1))
893d7149f4eSGlen Barber			fi
894d7149f4eSGlen Barber			if [ -d "$EXCLUSIVEDIR" ]; then
895d7149f4eSGlen Barber				echo " " >"$EXCLUSIVEDIR/$x $iface"
896d7149f4eSGlen Barber			fi
897d7149f4eSGlen Barber			changed=true
898d7149f4eSGlen Barber		fi
899d7149f4eSGlen Barber		;;
900d7149f4eSGlen Barber	*)
901d7149f4eSGlen Barber		if [ -f "$oldexcl" ]; then
902d7149f4eSGlen Barber			rm -f "$oldexcl"
903d7149f4eSGlen Barber			changed=true
904d7149f4eSGlen Barber		fi
905d7149f4eSGlen Barber		;;
906d7149f4eSGlen Barber	esac
907d7149f4eSGlen Barber
908d7149f4eSGlen Barber	if $changedfile; then
909d7149f4eSGlen Barber		printf "%s\n" "$resolv" >"$IFACEDIR/$iface" || exit $?
910d7149f4eSGlen Barber	elif ! $changed; then
911d7149f4eSGlen Barber		exit 0
912d7149f4eSGlen Barber	fi
913d7149f4eSGlen Barber	unset changed changedfile oldmetric newmetric x oldexcl
914d7149f4eSGlen Barber	;;
915d7149f4eSGlen Barber
916d7149f4eSGlen Barberd)
917d7149f4eSGlen Barber	# Delete any existing information about the interface
918d7149f4eSGlen Barber	cd "$IFACEDIR"
919d7149f4eSGlen Barber	changed=false
920d7149f4eSGlen Barber	for i in $args; do
921d7149f4eSGlen Barber		if [ -e "$i" ]; then
922d7149f4eSGlen Barber			changed=true
923d7149f4eSGlen Barber		elif ! ${force}; then
924d7149f4eSGlen Barber			warn "No resolv.conf for interface $i"
925d7149f4eSGlen Barber		fi
926d7149f4eSGlen Barber		rm -f "$i" "$METRICDIR/"*" $i" \
927d7149f4eSGlen Barber			"$PRIVATEDIR/$i" \
928d7149f4eSGlen Barber			"$EXCLUSIVEDIR/"*" $i" || exit $?
929d7149f4eSGlen Barber	done
930d7149f4eSGlen Barber	if ! ${changed}; then
931d7149f4eSGlen Barber		# Set the return code based on the forced flag
932d7149f4eSGlen Barber		${force}
933d7149f4eSGlen Barber		exit $?
934d7149f4eSGlen Barber	fi
935d7149f4eSGlen Barber	unset changed i
936d7149f4eSGlen Barber	;;
937d7149f4eSGlen Barberesac
938d7149f4eSGlen Barber
939d7149f4eSGlen Barbercase "${resolvconf:-YES}" in
940d7149f4eSGlen Barber[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) ;;
941d7149f4eSGlen Barber*) exit 0;;
942d7149f4eSGlen Barberesac
943587392a5SHajimu UMEMOTO
9443f2a60a1SPedro F. Giffuni# Try and detect a suitable init system for our scripts
9453f2a60a1SPedro F. Giffunidetect_init
9463f2a60a1SPedro F. Giffuniexport RESTARTCMD RCDIR _NOINIT_WARNED
9473f2a60a1SPedro F. Giffuni
948587392a5SHajimu UMEMOTOeval "$(make_vars)"
949587392a5SHajimu UMEMOTOexport RESOLVCONF DOMAINS SEARCH NAMESERVERS LOCALNAMESERVERS
950587392a5SHajimu UMEMOTO: ${list_resolv:=list_resolv -l}
951587392a5SHajimu UMEMOTOretval=0
952c364f334SPedro F. Giffuni
953c364f334SPedro F. Giffuni# Run scripts in the same directory resolvconf is run from
9543f2a60a1SPedro F. Giffuni# in case any scripts accidentally dump files in the wrong place.
955c364f334SPedro F. Giffunicd "$_PWD"
956587392a5SHajimu UMEMOTOfor script in "$LIBEXECDIR"/*; do
957587392a5SHajimu UMEMOTO	if [ -f "$script" ]; then
958d7149f4eSGlen Barber		eval script_enabled="\$${script##*/}"
959d7149f4eSGlen Barber		case "${script_enabled:-YES}" in
960d7149f4eSGlen Barber		[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) ;;
961d7149f4eSGlen Barber		*) continue;;
962d7149f4eSGlen Barber		esac
963587392a5SHajimu UMEMOTO		if [ -x "$script" ]; then
964587392a5SHajimu UMEMOTO			"$script" "$cmd" "$iface"
965587392a5SHajimu UMEMOTO		else
966d7149f4eSGlen Barber			(set -- "$cmd" "$iface"; . "$script")
967587392a5SHajimu UMEMOTO		fi
968587392a5SHajimu UMEMOTO		retval=$(($retval + $?))
969587392a5SHajimu UMEMOTO	fi
970587392a5SHajimu UMEMOTOdone
971587392a5SHajimu UMEMOTOexit $retval
972