Align help text
[openresolv] / resolvconf.in
1 #!/bin/sh
2 # Copyright 2006 Gentoo Foundation
3 # Copyright 2007 Roy Marples
4 # All rights reserved
5
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions
8 # are met:
9 #     * Redistributions of source code must retain the above copyright
10 #       notice, this list of conditions and the following disclaimer.
11 #     * Redistributions in binary form must reproduce the above
12 #       copyright notice, this list of conditions and the following
13 #       disclaimer in the documentation and/or other materials provided
14 #       with the distribution.
15 #
16 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 argv0="$0"
29
30 PREFIX=
31 RESOLVCONF="${PREFIX}"/etc/resolvconf
32 UPDATED="${RESOLVCONF}"/update.d
33 VARDIR="${RESOLVCONF}"/run
34 IFACEDIR="${VARDIR}/interfaces"
35
36 error_exit() {
37         echo "$*" >&2
38         exit 1
39 }
40
41 usage() {
42         cat <<-EOF
43         Usage: ${argv0##*/} [options]
44
45         Inform the system about any DNS updates.
46
47         Options:
48           -a \$INTERFACE    Add DNS information to the specified interface
49                            (DNS supplied via stdin in resolv.conf format)
50           -d \$INTERFACE    Delete DNS information from the specified interface
51           -u               Run updates from our current DNS information
52           -l [\$PATTERN]    Show DNS information, optionally from interfaces
53                            that match the specified pattern
54           -i [\$PATTERN]    Show interfaces that have supplied DNS information
55                    optionally from interfaces that match the specified
56                    pattern
57           -v [\$PATTERN]    echo NEWDOMAIN, NEWSEARCH and NEWNS variables to
58                            the console
59           -s \$SVC \$CMD     Do \$CMD for the system service \$SVC
60           -h               Show this help cruft
61         EOF
62         [ -z "$@" ] && exit 0
63         echo
64         error_exit "$*"
65 }
66
67 echo_resolv() {
68         [ -n "$1" -a -e "${IFACEDIR}/$1" ] || return 1
69         echo "# resolv.conf for interface $1"
70         cat "${IFACEDIR}/$1"
71         echo
72 }
73
74 uniqify() {
75     local result=
76     while [ -n "$1" ]; do
77                 case " ${result} " in
78                         *" $1 "*) ;;
79                         *) result="${result} $1" ;;
80                 esac
81                 shift
82         done
83     echo "${result# *}"
84 }
85
86 if [ -n "$1" ]; then
87         CMD="$1"
88         shift
89 fi
90
91 # We do our service restarting here so that our subscribers don't have to know
92 # about the OS's init system.
93 if [ "x${CMD}" = "x-s" ]; then
94         if [ -n "$1" ]; then
95                 SERVICE="$1"
96                 shift
97         fi
98         [ -z "${SERVICE}" ] && usage "Service not specified"
99         if [ -n "$1" ]; then
100                 ACTION="$1"
101                 shift
102         fi
103         [ -z "${ACTION}" ] && usage "Action not specified"
104
105         # If restarting check if service is running or not if we can
106         if [ "x${ACTION}" = "xrestart" ]; then
107                 if [ -s /var/run/"${SERVICE}".pid ]; then
108                         kill -0 $(cat /var/run/"${SERVICE}".pid)
109                 elif [ -s /var/run/"${SERVICE}"/"${SERVICE}".pid ]; then
110                         kill -0 $(cat /var/run/"${SERVICE}".pid)
111                 elif [ -s /var/run/"${SERVICE}"/pid ]; then
112                         kill -0 $(cat /var/run/"${SERVICE}"/pid)
113                 else
114                         false
115                 fi
116                 # Service not running, so don't restart
117                 [ $? != 0 ] && exit 1
118         fi      
119         if [ -x /sbin/service ]; then
120                 service "${SERVICE}" "${ACTION}" "$@" 
121         elif [ -x /etc/init.d/"${SERVICE}" -a -x /sbin/runscript ]; then
122                 if [ "x${ACTION}" = "xrestart" ]; then
123                         /etc/init.d/"${SERVICE}" --quiet --nodeps conditionalrestart "$@"
124                 else
125                         /etc/init.d/"${SERVICE}" --quiet --nodeps "${ACTION}" "$@"
126                 fi
127         elif [ -x /etc/init.d/"${SERVICE}" ]; then
128                 /etc/init.d/"${SERVICE}" "${ACTION}" "$@"
129         elif [ -x /etc/rc.d/"${SERVICE}" ]; then
130                 /etc/rc.d/"${SERVICE}" "${ACTION}" "$@" 
131         elif [ -x /etc/rc.d/rc."${SERVICE}" ]; then
132                 /etc/rc.d/rc."${SERVICE}" "${ACTION}" "$@"
133         else
134                 error_exit "Don't know how to interact with services on this platform"
135         fi
136         exit $?
137 fi
138
139 if [ -n "$1" ]; then
140         IFACE="$1"
141         shift
142 fi
143
144 # -l is a Gentoo option that lists our resolv files
145 # optionally for a specific interface
146 if [ "x${CMD}" = "x-l" -o "x${CMD}" = "x-i" ]; then
147         [ -d "${IFACEDIR}" ] || exit 0
148         
149         # If we have an interface ordering list, then use that.
150         # It works by just using pathname expansion in the interface directory.
151         if [ -n "${IFACE}" ]; then
152                 LIST="${IFACE} $@"
153         elif [ -r "${RESOLVCONF}"/interface-order ]; then
154                 LIST="$(cat "${RESOLVCONF}"/interface-order)"
155         fi
156
157         # If we don't have a list then prefer lo, tunnels, ppp
158         # and then anything else.
159         if [ -z "${LIST}" ]; then
160                 LIST="lo lo[0-9]* tap[0-9]* tun[0-9]* vpn vpn[0-9]* ppp[0-9]* ippp[0-9]* *"
161         fi
162
163         cd "${IFACEDIR}"
164         for IFACE in $(uniqify ${LIST}); do
165                 # Only list interfaces which we really have
166                 [ -e "${IFACE}" ] || continue
167                 
168                 if [ "x${CMD}" = "x-i" ]; then
169                         printf "${IFACE} "
170                 else
171                         echo_resolv "${IFACE}"
172                 fi
173         done
174         [ "x${CMD}" = "x-i" ] && echo
175         exit 0
176 fi
177
178 if [ "x${CMD}" = "x-v" ]; then
179         NS=
180         DOMAIN=
181         SEARCH=
182         NEWSEARCH=
183         NEWNS=
184         NEWDOMAIN=
185         LINES="$("${argv0}" -l "${IFACE}" | sed -e "s/'/'\\\\''/g" -e "s/^/'/g" -e "s/$/'/g")"
186         eval set -- ${LINES}
187         for LINE in "$@"; do
188                 case "${LINE}" in
189                         "nameserver "*)
190                                 case "${LINE#* }" in
191                                         127.*) continue ;;
192                                 esac
193                                 NS="${NS}${LINE#* } "
194                                 ;;
195                         "domain "*)
196                                 [ -z "${SEARCH}" ] && DOMAIN="${LINE#* }"
197                                 ;;
198                         "search "*)
199                                 SEARCH="${LINE#* }"
200                                 DOMAIN=
201                                 ;;
202                         *)
203                                 if [ -z "${LINE}" ]; then
204                                         for N in ${NS}; do
205                                                 if [ -n "${DOMAIN}" ]; then
206                                                         NEWDOMAIN="${NEWDOMAIN} ${DOMAIN},${N}"
207                                                 elif [ -n "${SEARCH}" ]; then
208                                                         for S in ${SEARCH}; do
209                                                                 NEWSEARCH="${NEWSEARCH} ${S},${N}"
210                                                         done
211                                                 else
212                                                         NEWNS="${NEWNS} ${N}"
213                                                 fi
214                                         done
215                                         NS=
216                                         DOMAIN=
217                                         SEARCH=
218                                 fi
219                                 ;;
220                 esac
221         done
222
223         # Prefer DOMAIN nameservers over SEARCH nameservers
224         # if we are supplied both.
225         NEWDOMAIN="$(uniqify ${NEWDOMAIN})"
226         NEWSEARCH="$(uniqify ${NEWSEARCH})"
227         NEWNS="$(uniqify ${NEWNS})"
228         for S in ${NEWSEARCH}; do
229                 for DN in ${NEWDOMAIN}; do
230                         if [ "${S%,*}" = "${DN%,*}" ]; then
231                                 NEWSEARCH="$(echo "${NEWSEARCH}" | sed -e "s/${S}/${DN}/g")"
232                                 NEWDOMAIN="$(echo "${NEWDOMAIN}" | sed -e "s/${DN}//g")"
233                                 break
234                         fi
235                 done
236         done
237
238         echo "NEWDOMAIN='${NEWDOMAIN}'"
239         echo "NEWSEARCH='${NEWSEARCH}'"
240         echo "NEWNS='${NEWNS}'"
241         exit 0
242 fi
243
244 # Test that we have valid options
245 if [ "x${CMD}" = "x-a" -o "x${CMD}" = "x-d" ]; then
246         if [ -z "${IFACE}" ]; then
247                 usage "Interface not specified"
248         fi
249 elif [ "x${CMD}" != "x-u" ]; then
250         [ -n "x${CMD}" -a "x${CMD}" != "x-h" ] && usage "Unknown option ${CMD}"
251         usage
252 fi
253 if [ "x${CMD}" = "x-a" ]; then
254         for x in '/' \\ ' ' '*'; do
255                 case "${IFACE}" in
256                         *[${x}]*) error_exit "${x} not allowed in interface name" ;;
257                 esac
258         done
259         for x in '.' '-' '~'; do
260                 case "${IFACE}" in
261                         [${x}]*) error_exit "${x} not allowed at start of interface name" ;;
262                 esac
263         done
264         [ "x${CMD}" = "x-a" -a -t 0 ] && error_exit "No file given via stdin"
265         IFACERESOLV="${IFACEDIR}/${IFACE}"
266 fi
267
268 # Ensure that libdir exists
269 if [ ! -d "${IFACEDIR}" ]; then
270         if [ ! -d "${VARDIR}" ]; then
271                 if [ -L "${VARDIR}" ]; then
272                         DIR="$(readlink "${VARDIR}")"
273                         # Change to /etc as link maybe relative
274                         cd "${VARDIR%/*}"
275                         if ! mkdir -m 0755 -p "${DIR}"; then
276                                 error_exit "Failed to create needed directory ${DIR}"
277                         fi
278                 else
279                         if ! mkdir -m 0755 -p "${VARDIR}"; then
280                                 error_exit "Failed to create needed directory ${VARDIR}"
281                         fi
282                 fi
283         fi
284         mkdir -m 0755 -p "${IFACEDIR}" || \
285                 error_exit "Failed to create needed directory ${IFACEDIR}"
286 else
287         # Delete any existing information about the interface
288         if [ "x${CMD}" = "x-a" -o "x${CMD}" = "x-d" ]; then
289                 cd "${IFACEDIR}"
290                 for iface in ${IFACE}; do
291                         rm -f "${iface}" || exit $?
292                 done
293         fi
294 fi
295
296 if [ "x${CMD}" = "x-a" ]; then
297         # Create our resolv.conf file
298         cat >"${IFACEDIR}"/"${IFACE}" || exit $?
299 fi
300
301 retval=0
302 for x in "${UPDATED}"/*; do
303         if [ -e "${x}" ]; then
304                 "${x}" "${CMD}" "${IFACE}"
305                 retval=$((${retval} + $?))
306         fi
307 done
308
309 exit ${retval}
310
311 # vim: set ts=4 :