2 # Copyright 2007-2008 Roy Marples
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions
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.
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.
28 SYSCONFDIR=@SYSCONFDIR@
29 VARDIR=@VARBASE@/run/resolvconf
30 IFACEDIR="${VARDIR}/interfaces"
31 METRICDIR="${VARDIR}/metrics"
42 Usage: ${ARGV0##*/} [options]
44 Inform the system about any DNS updates.
47 -a \$INTERFACE Add DNS information to the specified interface
48 (DNS supplied via stdin in resolv.conf format)
49 -m metric Give the added DNS information a metric
50 -d \$INTERFACE Delete DNS information from the specified interface
51 -f Ignore non existant interfaces
52 -u Run updates from our current DNS information
53 -l [\$PATTERN] Show DNS information, optionally from interfaces
54 that match the specified pattern
55 -i [\$PATTERN] Show interfaces that have supplied DNS information
56 optionally from interfaces that match the specified
58 -v [\$PATTERN] echo NEWDOMAIN, NEWSEARCH and NEWNS variables to
60 -s \$SVC \$CMD Do \$CMD for the system service \$SVC
61 -h Show this help cruft
71 [ -n "$1" -a -e "${IFACEDIR}/$1" ] || return 1
72 echo "# resolv.conf from $1"
73 # Our variable maker works of the fact each resolv.conf per interface
74 # is separated by blank lines.
75 # So we remove them when echoing them.
77 [ -n "${LINE}" ] && echo "${LINE}"
78 done < "${IFACEDIR}/$1"
82 # Parse resolv.conf's and make variables
83 # for domain name servers, search name servers and global nameservers
86 local LINE= NS= DOMAIN= SEARCH= N= NEWDOMAIN= NEWSEARCH= NEWNS=
101 [ -z "${SEARCH}" ] && DOMAIN="${LINE#* }"
108 if [ -z "${LINE}" ]; then
110 if [ -n "${DOMAIN}" ]; then
111 echo "NEWDOMAIN=\"\${NEWDOMAIN} ${DOMAIN},${N}\""
112 elif [ -n "${SEARCH}" ]; then
113 for S in ${SEARCH}; do
114 echo "NEWSEARCH=\"\${NEWSEARCH} ${S},${N}\""
117 echo "NEWNS=\"\${NEWNS} ${N}\""
132 while [ -n "$1" ]; do
133 case " ${result} " in
135 *) result="${result} $1";;
143 while getopts a:d:fhilm:s:uv OPT; do
147 m) IF_METRIC="${OPTARG}";;
148 s) CMD=s; SERVICE="${OPTARG}";;
150 *) CMD="${OPT}"; IFACE="${OPTARG}";;
153 shift $((${OPTIND} - 1))
154 ARGS="${IFACE}${IFACE:+ }$@"
156 # We do our service restarting here so that our subscribers don't have to know
157 # about the OS's init system.
158 if [ "${CMD}" = "s" ]; then
163 [ -z "${ACTION}" ] && usage "Action not specified"
165 # If restarting check if service is running or not if we can
166 if [ "${ACTION}" = "restart" ]; then
167 if [ -s /var/run/"${SERVICE}".pid ]; then
168 kill -0 $(cat /var/run/"${SERVICE}".pid) 2>/dev/null
169 elif [ -s /var/run/"${SERVICE}"/"${SERVICE}".pid ]; then
170 kill -0 $(cat /var/run/"${SERVICE}"/"${SERVICE}".pid) 2>/dev/null
171 elif [ -s /var/run/"${SERVICE}"/pid ]; then
172 kill -0 $(cat /var/run/"${SERVICE}"/pid) 2>/dev/null
176 # Service not running, so don't restart
177 [ $? != 0 ] && exit 0
179 if [ -x /sbin/service ]; then
180 service "${SERVICE}" "${ACTION}" "$@"
181 elif [ -x /etc/init.d/"${SERVICE}" -a -x /sbin/runscript ]; then
182 if [ "${ACTION}" = "restart" ]; then
183 /etc/init.d/"${SERVICE}" --quiet --nodeps conditionalrestart "$@"
185 /etc/init.d/"${SERVICE}" --quiet --nodeps "${ACTION}" "$@"
187 elif [ -x /etc/init.d/"${SERVICE}" ]; then
188 /etc/init.d/"${SERVICE}" "${ACTION}" "$@"
189 elif [ -x /etc/rc.d/"${SERVICE}" ]; then
190 /etc/rc.d/"${SERVICE}" "${ACTION}" "$@"
191 elif [ -x /etc/rc.d/rc."${SERVICE}" ]; then
192 /etc/rc.d/rc."${SERVICE}" "${ACTION}" "$@"
194 error_exit "Don't know how to interact with services on this platform"
199 # -l lists our resolv files, optionally for a specific interface
200 if [ "${CMD}" = "l" -o "${CMD}" = "i" ]; then
201 [ -d "${IFACEDIR}" ] || exit 0
204 # If we have an interface ordering list, then use that.
205 # It works by just using pathname expansion in the interface directory.
206 if [ -n "${ARGS}" ]; then
208 ${FORCE} || REPORT=true
209 elif [ -r "${SYSCONFDIR}"/interface-order ]; then
210 LIST="lo lo[0-9]* $(cat "${SYSCONFDIR}"/interface-order) *"
212 # If we don't have a list then prefer lo, metrics, tunnels, ppp
213 # and then anything else.
214 if [ -z "${LIST}" ]; then
218 LIST="${LIST} ${METRIC#* }"
220 LIST="${LIST} tap[0-9]* tun[0-9]* vpn vpn[0-9]* ppp[0-9]* ippp[0-9]* *"
225 for IFACE in $(uniqify ${LIST}); do
226 # Only list interfaces which we really have
227 if ! [ -e "${IFACE}" ]; then
229 echo "No resolv.conf for interface ${IFACE}" >&2
230 RETVAL=$((${RETVAL} + 1))
235 if [ "${CMD}" = "i" ]; then
238 echo_resolv "${IFACE}"
241 [ "${CMD}" = "i" ] && echo
245 if [ "${CMD}" = "v" ]; then
246 eval "$("${ARGV0}" -l "${IFACE}" | parse_resolv)"
248 # Prefer DOMAIN nameservers over SEARCH nameservers
249 # if we are supplied both, but put them in the SEARCH list
250 NEWDOMAIN="$(uniqify ${NEWDOMAIN})"
251 NEWSEARCH="$(uniqify ${NEWSEARCH})"
252 NEWNS="$(uniqify ${NEWNS})"
255 for S in ${NEWSEARCH}; do
256 for DN in ${NEWDOMAIN}; do
257 if [ "${S%,*}" = "${DN%,*}" ]; then
262 _NEWSEARCH="${_NEWSEARCH}${_NEWSEARCH:+ }${S}"
264 for DN in ${NEWDOMAIN}; do
265 for S in ${_NEWSEARCH}; do
266 if [ "${S%,*}" = "${DN%,*}" ]; then
271 if [ -n "${DN}" ]; then
272 _NEWDOMAIN="${_NEWDOMAIN}${_NEWDOMAIN:+ }${DN}"
276 echo "NEWDOMAIN='${_NEWDOMAIN}'"
277 echo "NEWSEARCH='${_NEWSEARCH}'"
278 echo "NEWNS='${NEWNS}'"
282 # Test that we have valid options
283 if [ "${CMD}" = "a" -o "${CMD}" = "d" ]; then
284 if [ -z "${IFACE}" ]; then
285 usage "Interface not specified"
287 elif [ "${CMD}" != "u" ]; then
288 [ -n "${CMD}" -a "${CMD}" != "h" ] && usage "Unknown option ${CMD}"
291 if [ "${CMD}" = "a" ]; then
292 for x in '/' \\ ' ' '*'; do
294 *[${x}]*) error_exit "${x} not allowed in interface name";;
297 for x in '.' '-' '~'; do
299 [${x}]*) error_exit "${x} not allowed at start of interface name";;
302 [ "${CMD}" = "a" -a -t 0 ] && error_exit "No file given via stdin"
303 IFACERESOLV="${IFACEDIR}/${IFACE}"
306 # Ensure that libdir exists
307 if [ ! -d "${IFACEDIR}" ]; then
308 if [ ! -d "${VARDIR}" ]; then
309 if [ -L "${VARDIR}" ]; then
310 DIR="$(readlink "${VARDIR}")"
311 # Change to /etc as link maybe relative
313 if ! mkdir -m 0755 -p "${DIR}"; then
314 error_exit "Failed to create needed directory ${DIR}"
317 if ! mkdir -m 0755 -p "${VARDIR}"; then
318 error_exit "Failed to create needed directory ${VARDIR}"
322 mkdir -m 0755 -p "${IFACEDIR}" || \
323 error_exit "Failed to create needed directory ${IFACEDIR}"
325 # Delete any existing information about the interface
326 if [ "${CMD}" = "d" ]; then
328 for ARG in ${ARGS}; do
329 if [ "${CMD}" = "d" -a ! -e "${ARG}" ]; then
331 error_exit "No resolv.conf for interface ${ARG}"
333 rm -f "${ARG}" "${METRICDIR}/"*" ${ARG}" || exit $?
338 if [ "${CMD}" = "a" ]; then
339 # Read resolv.conf from stdin
341 # If what we are given matches what we have, then do nothing
342 if [ -e "${IFACEDIR}/${IFACE}" ]; then
343 if [ "$(printf "${RESOLV}")" = "$(cat "${IFACEDIR}/${IFACE}")" ]
347 rm "${IFACEDIR}/${IFACE}"
349 printf "${RESOLV}" >"${IFACEDIR}/${IFACE}" || exit $?
350 rm -f "${METRICDIR}/"*" ${IFACE}"
351 if [ ! -d "${METRICDIR}" ]; then
354 rm -f "${METRICDIR}/"*" ${IFACE}"
355 # Pad metric to 6 characters, so 5 is less than 10
356 # All interfaces will get a default metric of 0
357 while [ ${#IF_METRIC} -le 6 ]; do
358 IF_METRIC="0${IF_METRIC}"
360 echo " " >"${METRICDIR}/${IF_METRIC} ${IFACE}"
364 for SCRIPT in "${SYSCONFDIR}"/update.d/*; do
365 if [ -e "${SCRIPT}" ]; then
366 "${SCRIPT}" "${CMD}" "${IFACE}"
367 RETVAL=$((${RETVAL} + $?))