Reorder files for best compilation.
[adns] / src / setup.c
CommitLineData
e576be50 1/*
2 * setup.c
3 * - configuration file parsing
4 * - management of global state
5 */
6/*
7 * This file is part of adns, which is Copyright (C) 1997, 1998 Ian Jackson
8 *
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)
12 * any later version.
13 *
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.
18 *
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.
22 */
656b2da9 23
4353a5c4 24#include <stdlib.h>
25#include <errno.h>
26#include <string.h>
27#include <unistd.h>
28#include <fcntl.h>
656b2da9 29
4353a5c4 30#include <netdb.h>
31#include <arpa/inet.h>
32
33#include "internal.h"
34
656b2da9 35static void addserver(adns_state ads, struct in_addr addr) {
36 int i;
37 struct server *ss;
38
39 for (i=0; i<ads->nservers; i++) {
40 if (ads->servers[i].addr.s_addr == addr.s_addr) {
3955725c 41 adns__debug(ads,-1,0,"duplicate nameserver %s ignored",inet_ntoa(addr));
656b2da9 42 return;
43 }
44 }
45
46 if (ads->nservers>=MAXSERVERS) {
3955725c 47 adns__diag(ads,-1,0,"too many nameservers, ignoring %s",inet_ntoa(addr));
656b2da9 48 return;
49 }
50
51 ss= ads->servers+ads->nservers;
52 ss->addr= addr;
656b2da9 53 ads->nservers++;
54}
55
56static void configparseerr(adns_state ads, const char *fn, int lno,
57 const char *fmt, ...) {
58 va_list al;
59
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);
63 va_start(al,fmt);
64 vfprintf(stderr,fmt,al);
65 va_end(al);
66 fputc('\n',stderr);
67}
68
69static void ccf_nameserver(adns_state ads, const char *fn, int lno, const char *buf) {
70 struct in_addr ia;
71
72 if (!inet_aton(buf,&ia)) {
73 configparseerr(ads,fn,lno,"invalid nameserver address `%s'",buf);
74 return;
75 }
3955725c 76 adns__debug(ads,-1,0,"using nameserver %s",inet_ntoa(ia));
656b2da9 77 addserver(ads,ia);
78}
79
80static void ccf_search(adns_state ads, const char *fn, int lno, const char *buf) {
81 if (!buf) return;
3955725c 82 adns__diag(ads,-1,0,"warning - `search' ignored fixme");
656b2da9 83}
84
85static void ccf_sortlist(adns_state ads, const char *fn, int lno, const char *buf) {
3955725c 86 adns__diag(ads,-1,0,"warning - `sortlist' ignored fixme");
656b2da9 87}
88
89static void ccf_options(adns_state ads, const char *fn, int lno, const char *buf) {
90 if (!buf) return;
3955725c 91 adns__diag(ads,-1,0,"warning - `options' ignored fixme");
656b2da9 92}
93
94static void ccf_clearnss(adns_state ads, const char *fn, int lno, const char *buf) {
95 ads->nservers= 0;
96}
97
98static const struct configcommandinfo {
99 const char *name;
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 },
108 { 0 }
109};
110
656b2da9 111static void readconfig(adns_state ads, const char *filename) {
112 char linebuf[2000], *p, *q;
113 FILE *file;
114 int lno, l, c;
115 const struct configcommandinfo *ccip;
116
117 file= fopen(filename,"r");
118 if (!file) {
119 if (errno == ENOENT) {
3955725c 120 adns__debug(ads,-1,0,"configuration file `%s' does not exist",filename);
656b2da9 121 return;
122 }
3955725c 123 adns__diag(ads,-1,0,"cannot open configuration file `%s': %s",
4353a5c4 124 filename,strerror(errno));
656b2da9 125 return;
126 }
127
128 for (lno=1; fgets(linebuf,sizeof(linebuf),file); lno++) {
129 l= strlen(linebuf);
130 if (!l) continue;
131 if (linebuf[l-1] != '\n' && !feof(file)) {
3955725c 132 adns__diag(ads,-1,0,"%s:%d: line too long",filename,lno);
656b2da9 133 while ((c= getc(file)) != EOF && c != '\n') { }
134 if (c == EOF) break;
135 continue;
136 }
137 while (l>0 && ctype_whitespace(linebuf[l-1])) l--;
138 linebuf[l]= 0;
139 p= linebuf;
140 while (ctype_whitespace(*p)) p++;
141 if (*p == '#' || *p == '\n') continue;
142 q= p;
143 while (*q && !ctype_whitespace(*q)) q++;
144 for (ccip=configcommandinfos;
145 ccip->name && strncmp(ccip->name,p,q-p);
146 ccip++);
147 if (!ccip->name) {
3955725c 148 adns__diag(ads,-1,0,"%s:%d: unknown configuration directive `%.*s'",
4353a5c4 149 filename,lno,q-p,p);
656b2da9 150 continue;
151 }
152 while (ctype_whitespace(*q)) q++;
153 ccip->fn(ads,filename,lno,q);
154 }
155 if (ferror(file)) {
3955725c 156 adns__diag(ads,-1,0,"%s:%d: read error: %s",filename,lno,strerror(errno));
656b2da9 157 }
158 fclose(file);
159}
160
161static const char *instrum_getenv(adns_state ads, const char *envvar) {
162 const char *value;
163
164 value= getenv(envvar);
3955725c 165 if (!value) adns__debug(ads,-1,0,"environment variable %s not set",envvar);
166 else adns__debug(ads,-1,0,"environment variable %s set to `%s'",envvar,value);
656b2da9 167 return value;
168}
169
170static void readconfigenv(adns_state ads, const char *envvar) {
171 const char *filename;
172
173 if (ads->iflags & adns_if_noenv) {
3955725c 174 adns__debug(ads,-1,0,"not checking environment variable `%s'",envvar);
656b2da9 175 return;
176 }
177 filename= instrum_getenv(ads,envvar);
178 if (filename) readconfig(ads,filename);
179}
4353a5c4 180
181
182int adns__setnonblock(adns_state ads, int fd) {
183 int r;
656b2da9 184
4353a5c4 185 r= fcntl(fd,F_GETFL,0); if (r<0) return errno;
186 r |= O_NONBLOCK;
187 r= fcntl(fd,F_SETFL,r); if (r<0) return errno;
188 return 0;
189}
190
191int adns_init(adns_state *ads_r, adns_initflags flags, FILE *diagfile) {
656b2da9 192 adns_state ads;
193 const char *res_options, *adns_res_options;
194 struct protoent *proto;
195 int r;
196
197 ads= malloc(sizeof(*ads)); if (!ads) return errno;
656b2da9 198 ads->iflags= flags;
4353a5c4 199 ads->diagfile= diagfile ? diagfile : stderr;
200 LIST_INIT(ads->timew);
201 LIST_INIT(ads->childw);
202 LIST_INIT(ads->output);
203 ads->nextid= 0x311f;
204 ads->udpsocket= ads->tcpsocket= -1;
4353a5c4 205 adns__vbuf_init(&ads->tcpsend);
206 adns__vbuf_init(&ads->tcprecv);
207 ads->nservers= ads->tcpserver= 0;
208 ads->tcpstate= server_disconnected;
209 timerclear(&ads->tcptimeout);
656b2da9 210
211 res_options= instrum_getenv(ads,"RES_OPTIONS");
212 adns_res_options= instrum_getenv(ads,"ADNS_RES_OPTIONS");
213 ccf_options(ads,"RES_OPTIONS",-1,res_options);
214 ccf_options(ads,"ADNS_RES_OPTIONS",-1,adns_res_options);
215
216 readconfig(ads,"/etc/resolv.conf");
217 readconfigenv(ads,"RES_CONF");
218 readconfigenv(ads,"ADNS_RES_CONF");
219
220 ccf_options(ads,"RES_OPTIONS",-1,res_options);
221 ccf_options(ads,"ADNS_RES_OPTIONS",-1,adns_res_options);
222
223 ccf_search(ads,"LOCALDOMAIN",-1,instrum_getenv(ads,"LOCALDOMAIN"));
224 ccf_search(ads,"ADNS_LOCALDOMAIN",-1,instrum_getenv(ads,"ADNS_LOCALDOMAIN"));
225
226 if (!ads->nservers) {
227 struct in_addr ia;
228 if (ads->iflags & adns_if_debug)
229 fprintf(stderr,"adns: no nameservers, using localhost\n");
230 ia.s_addr= INADDR_LOOPBACK;
231 addserver(ads,ia);
232 }
233
234 proto= getprotobyname("udp"); if (!proto) { r= ENOPROTOOPT; goto x_free; }
235 ads->udpsocket= socket(AF_INET,SOCK_DGRAM,proto->p_proto);
8402e34c 236 if (ads->udpsocket<0) { r= errno; goto x_free; }
4bec51a4 237
94436798 238 r= adns__setnonblock(ads,ads->udpsocket);
239 if (r) { r= errno; goto x_closeudp; }
656b2da9 240
241 *ads_r= ads;
242 return 0;
243
94436798 244 x_closeudp:
245 close(ads->udpsocket);
656b2da9 246 x_free:
247 free(ads);
248 return r;
249}
250
9ec44266 251void adns_finish(adns_state ads) {
252 for (;;) {
253 if (ads->timew.head) adns_cancel(ads->timew.head);
254 else if (ads->childw.head) adns_cancel(ads->childw.head);
255 else if (ads->output.head) adns_cancel(ads->output.head);
256 else break;
257 }
258 close(ads->udpsocket);
259 if (ads->tcpsocket >= 0) close(ads->tcpsocket);
260 adns__vbuf_free(&ads->tcpsend);
261 adns__vbuf_free(&ads->tcprecv);
262 free(ads);
656b2da9 263}