3 * - configuration file parsing
4 * - management of global state
7 * This file is part of adns, which is Copyright (C) 1997, 1998 Ian Jackson
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2, or (at your option)
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31 #include <arpa/inet.h>
35 static void addserver(adns_state ads, struct in_addr addr) {
39 for (i=0; i<ads->nservers; i++) {
40 if (ads->servers[i].addr.s_addr == addr.s_addr) {
41 adns__debug(ads,-1,"duplicate nameserver %s ignored",inet_ntoa(addr));
46 if (ads->nservers>=MAXSERVERS) {
47 adns__diag(ads,-1,"too many nameservers, ignoring %s",inet_ntoa(addr));
51 ss= ads->servers+ads->nservers;
56 static void configparseerr(adns_state ads, const char *fn, int lno,
57 const char *fmt, ...) {
60 if (ads->iflags & adns_if_noerrprint) return;
61 if (lno==-1) fprintf(stderr,"adns: %s: ",fn);
62 else fprintf(stderr,"adns: %s:%d: ",fn,lno);
64 vfprintf(stderr,fmt,al);
69 static void ccf_nameserver(adns_state ads, const char *fn, int lno, const char *buf) {
72 if (!inet_aton(buf,&ia)) {
73 configparseerr(ads,fn,lno,"invalid nameserver address `%s'",buf);
76 adns__debug(ads,-1,"using nameserver %s",inet_ntoa(ia));
80 static void ccf_search(adns_state ads, const char *fn, int lno, const char *buf) {
82 adns__diag(ads,-1,"warning - `search' ignored fixme");
85 static void ccf_sortlist(adns_state ads, const char *fn, int lno, const char *buf) {
86 adns__diag(ads,-1,"warning - `sortlist' ignored fixme");
89 static void ccf_options(adns_state ads, const char *fn, int lno, const char *buf) {
91 adns__diag(ads,-1,"warning - `options' ignored fixme");
94 static void ccf_clearnss(adns_state ads, const char *fn, int lno, const char *buf) {
98 static const struct configcommandinfo {
100 void (*fn)(adns_state ads, const char *fn, int lno, const char *buf);
101 } configcommandinfos[]= {
102 { "nameserver", ccf_nameserver },
103 { "domain", ccf_search },
104 { "search", ccf_search },
105 { "sortlist", ccf_sortlist },
106 { "options", ccf_options },
107 { "clearnameservers", ccf_clearnss },
111 static void readconfig(adns_state ads, const char *filename) {
112 char linebuf[2000], *p, *q;
115 const struct configcommandinfo *ccip;
117 file= fopen(filename,"r");
119 if (errno == ENOENT) {
120 adns__debug(ads,-1,"configuration file `%s' does not exist",filename);
123 adns__diag(ads,-1,"cannot open configuration file `%s': %s",
124 filename,strerror(errno));
128 for (lno=1; fgets(linebuf,sizeof(linebuf),file); lno++) {
131 if (linebuf[l-1] != '\n' && !feof(file)) {
132 adns__diag(ads,-1,"%s:%d: line too long",filename,lno);
133 while ((c= getc(file)) != EOF && c != '\n') { }
137 while (l>0 && ctype_whitespace(linebuf[l-1])) l--;
140 while (ctype_whitespace(*p)) p++;
141 if (*p == '#' || *p == '\n') continue;
143 while (*q && !ctype_whitespace(*q)) q++;
144 for (ccip=configcommandinfos;
145 ccip->name && strncmp(ccip->name,p,q-p);
148 adns__diag(ads,-1,"%s:%d: unknown configuration directive `%.*s'",
152 while (ctype_whitespace(*q)) q++;
153 ccip->fn(ads,filename,lno,q);
156 adns__diag(ads,-1,"%s:%d: read error: %s",filename,lno,strerror(errno));
161 static const char *instrum_getenv(adns_state ads, const char *envvar) {
164 value= getenv(envvar);
165 if (!value) adns__debug(ads,-1,"environment variable %s not set",envvar);
166 else adns__debug(ads,-1,"environment variable %s set to `%s'",envvar,value);
170 static void readconfigenv(adns_state ads, const char *envvar) {
171 const char *filename;
173 if (ads->iflags & adns_if_noenv) {
174 adns__debug(ads,-1,"not checking environment variable `%s'",envvar);
177 filename= instrum_getenv(ads,envvar);
178 if (filename) readconfig(ads,filename);
182 int adns__setnonblock(adns_state ads, int fd) {
185 r= fcntl(fd,F_GETFL,0); if (r<0) return errno;
187 r= fcntl(fd,F_SETFL,r); if (r<0) return errno;
191 int adns_init(adns_state *ads_r, adns_initflags flags, FILE *diagfile) {
193 const char *res_options, *adns_res_options;
194 struct protoent *proto;
197 ads= malloc(sizeof(*ads)); if (!ads) return errno;
199 ads->diagfile= diagfile ? diagfile : stderr;
200 LIST_INIT(ads->timew);
201 LIST_INIT(ads->childw);
202 LIST_INIT(ads->output);
204 ads->udpsocket= ads->tcpsocket= -1;
205 adns__vbuf_init(&ads->rqbuf);
206 adns__vbuf_init(&ads->tcpsend);
207 adns__vbuf_init(&ads->tcprecv);
208 ads->nservers= ads->tcpserver= 0;
209 ads->tcpstate= server_disconnected;
210 timerclear(&ads->tcptimeout);
212 res_options= instrum_getenv(ads,"RES_OPTIONS");
213 adns_res_options= instrum_getenv(ads,"ADNS_RES_OPTIONS");
214 ccf_options(ads,"RES_OPTIONS",-1,res_options);
215 ccf_options(ads,"ADNS_RES_OPTIONS",-1,adns_res_options);
217 readconfig(ads,"/etc/resolv.conf");
218 readconfigenv(ads,"RES_CONF");
219 readconfigenv(ads,"ADNS_RES_CONF");
221 ccf_options(ads,"RES_OPTIONS",-1,res_options);
222 ccf_options(ads,"ADNS_RES_OPTIONS",-1,adns_res_options);
224 ccf_search(ads,"LOCALDOMAIN",-1,instrum_getenv(ads,"LOCALDOMAIN"));
225 ccf_search(ads,"ADNS_LOCALDOMAIN",-1,instrum_getenv(ads,"ADNS_LOCALDOMAIN"));
227 if (!ads->nservers) {
229 if (ads->iflags & adns_if_debug)
230 fprintf(stderr,"adns: no nameservers, using localhost\n");
231 ia.s_addr= INADDR_LOOPBACK;
235 proto= getprotobyname("udp"); if (!proto) { r= ENOPROTOOPT; goto x_free; }
236 ads->udpsocket= socket(AF_INET,SOCK_DGRAM,proto->p_proto);
237 if (ads->udpsocket<0) { r= errno; goto x_free; }
239 r= adns__setnonblock(ads,ads->udpsocket);
240 if (r) { r= errno; goto x_closeudp; }
246 close(ads->udpsocket);
252 int adns_finish(adns_state ads) {