Respect MANPREFIX
[openresolv] / resolvconf
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           -h               Show this help cruft
60         EOF
61         [ -z "$@" ] && exit 0
62         echo
63         error_exit "$*"
64 }
65
66 echo_resolv() {
67         [ -n "$1" -a -e "${IFACEDIR}/$1" ] || return 1
68         echo "# resolv.conf for interface $1"
69         grep "." "${IFACEDIR}/$1"
70         echo
71 }
72
73 uniqify() {
74     local result=
75     while [ -n "$1" ]; do
76                 case " ${result} " in
77                         *" $1 "*) ;;
78                         *) result="${result} $1" ;;
79                 esac
80                 shift
81         done
82     echo "${result# *}"
83 }
84
85 if [ -n "$1" ]; then
86         CMD="$1"
87         shift
88 fi
89 if [ -n "$1" ]; then
90         IFACE="$1"
91         shift
92 fi
93
94 # -l is a Gentoo option that lists our resolv files
95 # optionally for a specific interface
96 if [ "x${CMD}" = "x-l" -o "x${CMD}" = "x-i" ]; then
97         [ -d "${IFACEDIR}" ] || exit 0
98         
99         # If we have an interface ordering list, then use that.
100         # It works by just using pathname expansion in the interface directory.
101         if [ -n "${IFACE}" ]; then
102                 LIST="${IFACE} $@"
103         elif [ -r "${RESOLVCONF}"/interface-order ]; then
104                 LIST="$(cat "${RESOLVCONF}"/interface-order)"
105         fi
106
107         # If we don't have a list then prefer lo, tunnels, ppp
108         # and then anything else.
109         if [ -z "${LIST}" ]; then
110                 LIST="lo lo[0-9]* tap[0-9]* tun[0-9]* vpn vpn[0-9]* ppp[0-9]* ippp[0-9]* *"
111         fi
112
113         cd "${IFACEDIR}"
114         for IFACE in $(uniqify ${LIST}); do
115                 # Only list interfaces which we really have
116                 [ -e "${IFACE}" ] || continue
117                 
118                 if [ "x${CMD}" = "x-i" ]; then
119                         printf "${IFACE} "
120                 else
121                         echo_resolv "${IFACE}"
122                 fi
123         done
124         [ "x${CMD}" = "x-i" ] && echo
125         exit 0
126 fi
127
128 if [ "x${CMD}" = "x-v" ]; then
129         NS=
130         DOMAIN=
131         SEARCH=
132         NEWSEARCH=
133         NEWNS=
134         NEWDOMAIN=
135         LINES="$("${argv0}" -l "${IFACE}" | sed -e "s/'/'\\\\''/g" -e "s/^/'/g" -e "s/$/'/g")"
136         eval set -- ${LINES}
137         for LINE in "$@"; do
138                 case "${LINE}" in
139                         "nameserver "*)
140                                 case "${LINE#* }" in
141                                         127.*) continue ;;
142                                 esac
143                                 NS="${NS}${LINE#* } "
144                                 ;;
145                         "domain "*)
146                                 [ -z "${SEARCH}" ] && DOMAIN="${LINE#* }"
147                                 ;;
148                         "search "*)
149                                 SEARCH="${LINE#* }"
150                                 DOMAIN=
151                                 ;;
152                         *)
153                                 if [ -z "${LINE}" ]; then
154                                         for N in ${NS}; do
155                                                 if [ -n "${DOMAIN}" ]; then
156                                                         NEWDOMAIN="${NEWDOMAIN} ${DOMAIN},${N}"
157                                                 elif [ -n "${SEARCH}" ]; then
158                                                         for S in ${SEARCH}; do
159                                                                 NEWSEARCH="${NEWSEARCH} ${S},${N}"
160                                                         done
161                                                 else
162                                                         NEWNS="${NEWNS} ${N}"
163                                                 fi
164                                         done
165                                         NS=
166                                         DOMAIN=
167                                         SEARCH=
168                                 fi
169                                 ;;
170                 esac
171         done
172
173         # Prefer DOMAIN nameservers over SEARCH nameservers
174         # if we are supplied both.
175         NEWDOMAIN="$(uniqify ${NEWDOMAIN})"
176         NEWSEARCH="$(uniqify ${NEWSEARCH})"
177         NEWNS="$(uniqify ${NEWNS})"
178         for S in ${NEWSEARCH}; do
179                 for DN in ${NEWDOMAIN}; do
180                         if [ "${S%,*}" = "${DN%,*}" ]; then
181                                 NEWSEARCH="$(echo "${NEWSEARCH}" | sed -e "s/${S}/${DN}/g")"
182                                 NEWDOMAIN="$(echo "${NEWDOMAIN}" | sed -e "s/${DN}//g")"
183                                 break
184                         fi
185                 done
186         done
187
188         echo "NEWDOMAIN='${NEWDOMAIN}'"
189         echo "NEWSEARCH='${NEWSEARCH}'"
190         echo "NEWNS='${NEWNS}'"
191         exit 0
192 fi
193
194 # Test that we have valid options
195 if [ "x${CMD}" = "x-a" -o "x${CMD}" = "x-d" ]; then
196         if [ -z "${IFACE}" ]; then
197                 usage "Interface not specified"
198         fi
199 elif [ "x${CMD}" != "x-u" ]; then
200         [ -n "x${CMD}" -a "x${CMD}" != "x-h" ] && usage "Unknown option ${CMD}"
201         usage
202 fi
203 if [ "x${CMD}" = "x-a" ]; then
204         for x in '/' \\ ' ' '*'; do
205                 case "${IFACE}" in
206                         *[${x}]*) error_exit "${x} not allowed in interface name" ;;
207                 esac
208         done
209         for x in '.' '-' '~'; do
210                 case "${IFACE}" in
211                         [${x}]*) error_exit "${x} not allowed at start of interface name" ;;
212                 esac
213         done
214         [ "x${CMD}" = "x-a" -a -t 0 ] && error_exit "No file given via stdin"
215         IFACERESOLV="${IFACEDIR}/${IFACE}"
216 fi
217
218 # Ensure that libdir exists
219 if [ ! -d "${IFACEDIR}" ]; then
220         if [ ! -d "${VARDIR}" ]; then
221                 if [ -L "${VARDIR}" ]; then
222                         DIR="$(readlink "${VARDIR}")"
223                         # Change to /etc as link maybe relative
224                         cd "${VARDIR%/*}"
225                         if ! mkdir -m 0755 -p "${DIR}"; then
226                                 error_exit "Failed to create needed directory ${DIR}"
227                         fi
228                 else
229                         if ! mkdir -m 0755 -p "${VARDIR}"; then
230                                 error_exit "Failed to create needed directory ${VARDIR}"
231                         fi
232                 fi
233         fi
234         mkdir -m 0755 -p "${IFACEDIR}" || \
235                 error_exit "Failed to create needed directory ${IFACEDIR}"
236 else
237         # Delete any existing information about the interface
238         if [ "x${CMD}" = "x-a" -o "x${CMD}" = "x-d" ]; then
239                 cd "${IFACEDIR}"
240                 for iface in ${IFACE}; do
241                         rm -f "${iface}" || exit $?
242                 done
243         fi
244 fi
245
246 if [ "x${CMD}" = "x-a" ]; then
247         # Create our resolv.conf file
248         cat >"${IFACEDIR}"/"${IFACE}" || exit $?
249 fi
250
251 retval=0
252 for x in "${UPDATED}"/*; do
253         if [ -e "${x}" ]; then
254                 "${x}" "${CMD}" "${IFACE}"
255                 retval=$((${retval} + $?))
256         fi
257 done
258
259 exit ${retval}
260
261 # vim: set ts=4 :