Initial commit from resolvconf-gentoo-1.4
[openresolv] / bin / resolvconf
1 #!/bin/sh
2 # Copyright 2006 Gentoo Foundation
3 # Distributed under the terms of the GNU General Public License v2
4
5 # Written by Roy Marples (uberlord@gentoo.org)
6 # Heavily based on Debian resolvconf by Thomas Hood
7
8 argv0="$0"
9
10 VARDIR=/etc/resolvconf/run
11 IFACEDIR="${VARDIR}/interfaces"
12
13 error_exit() {
14         echo "$*" >&2
15         exit 1
16 }
17
18 usage() {
19         cat <<-EOF
20         Usage: ${argv0##*/} [options]
21
22         Inform the system about any DNS updates.
23
24         Options:
25           -a \$INTERFACE    Add DNS information to the specified interface
26                            (DNS supplied via stdin in resolv.conf format)
27           -d \$INTERFACE    Delete DNS information from the specified interface
28           -u               Run updates from our current DNS information
29           -l [\$PATTERN]    Show DNS information, optionally from interfaces
30                            that match the specified pattern
31           -i [\$PATTERN]    Show interfaces that have supplied DNS information
32                    optionally from interfaces that match the specified
33                    pattern
34           -v [\$PATTERN]    echo NEWDOMAIN, NEWSEARCH and NEWNS variables to
35                            the console
36           -h               Show this help cruft
37         EOF
38         [ -z "$@" ] && exit 0
39         echo
40         error_exit "$*"
41 }
42
43 echo_resolv() {
44         [ -n "$1" -a -e "${IFACEDIR}/$1" ] || return 1
45         echo "# resolv.conf for interface $1"
46         grep "." "${IFACEDIR}/$1"
47         echo
48 }
49
50 uniqify() {
51     local result=
52     while [ -n "$1" ] ; do
53                 case " ${result} " in
54                         *" $1 "*) ;;
55                         *) result="${result} $1" ;;
56                 esac
57                 shift
58         done
59     echo "${result# *}"
60 }
61
62 if [ -n "$1" ] ; then
63         CMD="$1"
64         shift
65 fi
66 if [ -n "$1" ] ; then
67         IFACE="$1"
68         shift
69 fi
70
71 # -l is a Gentoo option that lists our resolv files
72 # optionally for a specific interface
73 if [ "x${CMD}" = "x-l" -o "x${CMD}" = "x-i" ] ; then
74         [ ! -d "${IFACEDIR}" ] && exit 0
75         
76         # If we have an interface ordering list, then use that.
77         # It works by just using pathname expansion in the interface directory.
78         if [ -n "${IFACE}" ] ; then
79                 LIST="${IFACE} $@"
80         elif [ -r /etc/resolvconf/interface-order ] ; then
81                 LIST="$(cat /etc/resolvconf/interface-order)"
82         fi
83
84         # If we don't have a list then prefer lo, tunnels, ppp
85         # and then anything else.
86         if [ -z "${LIST}" ] ; then
87                 LIST="lo lo[0-9]* tap[0-9]* tun[0-9]* vpn vpn[0-9]* ppp[0-9]* ippp[0-9]* *"
88         fi
89
90         cd "${IFACEDIR}"
91         for IFACE in $(uniqify ${LIST}) ; do
92                 # Only list interfaces which we really have
93                 [ -e "${IFACE}" ] || continue
94                 
95                 if [ "x${CMD}" = "x-i" ] ; then
96                         printf "${IFACE} "
97                 else
98                         echo_resolv "${IFACE}"
99                 fi
100         done
101         [ "x${CMD}" = "x-i" ] && echo
102         exit 0
103 fi
104
105 if [ "x${CMD}" = "x-v" ] ; then
106         NS=
107         DOMAIN=
108         SEARCH=
109         NEWSEARCH=
110         NEWNS=
111         NEWDOMAIN=
112         LINES="$("${argv0}" -l "${IFACE}" | sed -e "s/'/'\\\\''/g" -e "s/^/'/g" -e "s/$/'/g")"
113         eval set -- ${LINES}
114         for LINE in "$@" ; do
115                 case "${LINE}" in
116                         "nameserver "*)
117                                 case "${LINE#* }" in
118                                         127.*) continue ;;
119                                 esac
120                                 NS="${NS}${LINE#* } "
121                                 ;;
122                         "domain "*)
123                                 [ -z "${SEARCH}" ] && DOMAIN="${LINE#* }"
124                                 ;;
125                         "search "*)
126                                 SEARCH="${LINE#* }"
127                                 DOMAIN=
128                                 ;;
129                         *)
130                                 if [ -z "${LINE}" ] ; then
131                                         for N in ${NS} ; do
132                                                 if [ -n "${DOMAIN}" ] ; then
133                                                         NEWDOMAIN="${NEWDOMAIN} ${DOMAIN},${N}"
134                                                 elif [ -n "${SEARCH}" ] ; then
135                                                         for S in ${SEARCH} ; do
136                                                                 NEWSEARCH="${NEWSEARCH} ${S},${N}"
137                                                         done
138                                                 else
139                                                         NEWNS="${NEWNS} ${N}"
140                                                 fi
141                                         done
142                                         NS=
143                                         DOMAIN=
144                                         SEARCH=
145                                 fi
146                                 ;;
147                 esac
148         done
149
150         # Prefer DOMAIN nameservers over SEARCH nameservers
151         # if we are supplied both.
152         NEWDOMAIN="$(uniqify ${NEWDOMAIN})"
153         NEWSEARCH="$(uniqify ${NEWSEARCH})"
154         NEWNS="$(uniqify ${NEWNS})"
155         for S in ${NEWSEARCH} ; do
156                 for DN in ${NEWDOMAIN} ; do
157                         if [ "${S%,*}" = "${DN%,*}" ] ; then
158                                 NEWSEARCH="$(echo "${NEWSEARCH}" | sed -e "s/${S}/${DN}/g")"
159                                 NEWDOMAIN="$(echo "${NEWDOMAIN}" | sed -e "s/${DN}//g")"
160                                 break
161                         fi
162                 done
163         done
164
165         echo "NEWDOMAIN='${NEWDOMAIN}'"
166         echo "NEWSEARCH='${NEWSEARCH}'"
167         echo "NEWNS='${NEWNS}'"
168         exit 0
169 fi
170
171 # Only root can update resolv.conf
172 if ! touch "${VARDIR}"/.test ; then
173         error_exit "You must be root to run ${argv0##*/}"
174 fi
175 rm "${VARDIR}"/.test
176
177 # Test that we have valid options
178 if [ "x${CMD}" = "x-a" -o "x${CMD}" = "x-d" ] ; then
179         if [ -z "${IFACE}" ] ; then
180                 usage "Interface not specified"
181         fi
182 elif [ "x${CMD}" != "x-u" ] ; then
183         [ -n "x${CMD}" -a "x${CMD}" != "x-h" ] && usage "Unknown option ${CMD}"
184         usage
185 fi
186 if [ "x${CMD}" = "x-a" ] ; then
187         q='\'
188         for x in '/' '\' ' ' '*' ; do
189                 case "${IFACE}" in
190                         *[${x}]*) error_exit "${x} not allowed in interface name" ;;
191                 esac
192         done
193         for x in '.' '-' '~' ; do
194                 case "${IFACE}" in
195                         [${x}]*) error_exit "${x} not allowed at start of interface name" ;;
196                 esac
197         done
198         [ "x${CMD}" = "x-a" -a -t 0 ] && error_exit "No file given via stdin"
199         IFACERESOLV="${IFACEDIR}/${IFACE}"
200 fi
201
202 # Ensure that libdir exists
203 if [ ! -d "${IFACEDIR}" ] ; then
204         if [ ! -d "${VARDIR}" ] ; then
205                 if [ -L "${VARDIR}" ] ; then
206                         DIR="$(readlink -f "${VARDIR}")"
207                         [ -z "${DIR}" ] && DIR="$(readlink "${VARDIR}")"
208                 fi
209                 # Change to /etc as link maybe relative
210                 cd "${VARDIR%/*}"
211                 mkdir -m 0755 -p "${DIR}" \
212                         || error_exit "Failed to create needed directory ${DIR}"
213         fi
214         mkdir -m 0755 -p "${IFACEDIR}" || \
215                 error_exit "Failed to create needed directory ${IFACEDIR}"
216 else
217         # Delete any existing information about the interface
218         if [ "x${CMD}" = "x-a" -o "x${CMD}" = "x-d" ] ; then
219                 cd "${IFACEDIR}"
220                 for iface in ${IFACE} ; do
221                         rm -f "${iface}"
222                 done
223         fi
224 fi
225
226 if [ "x${CMD}" = "x-a" ] ; then
227         # Create our resolv.conf file
228         cat >"${IFACEDIR}"/"${IFACE}"
229 fi
230
231 for x in /etc/resolvconf/update.d/* ; do
232         [ -e "${x}" ] && "${x}" "${CMD}" "${IFACE}"
233 done
234
235 # vim: set ts=4 :