Rearrangement more or less sorted, back to trying to get it to compile.
[adns] / src / setup.c
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 */
23
24 #include <stdlib.h>
25 #include <errno.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29
30 #include <netdb.h>
31 #include <arpa/inet.h>
32
33 #include "internal.h"
34
35 static 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) {
41 adns__debug(ads,-1,"duplicate nameserver %s ignored",inet_ntoa(addr));
42 return;
43 }
44 }
45
46 if (ads->nservers>=MAXSERVERS) {
47 adns__diag(ads,-1,"too many nameservers, ignoring %s",inet_ntoa(addr));
48 return;
49 }
50
51 ss= ads->servers+ads->nservers;
52 ss->addr= addr;
53 ads->nservers++;
54 }
55
56 static 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
69 static 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 }
76 adns__debug(ads,-1,"using nameserver %s",inet_ntoa(ia));
77 addserver(ads,ia);
78 }
79
80 static void ccf_search(adns_state ads, const char *fn, int lno, const char *buf) {
81 if (!buf) return;
82 adns__diag(ads,-1,"warning - `search' ignored fixme");
83 }
84
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");
87 }
88
89 static void ccf_options(adns_state ads, const char *fn, int lno, const char *buf) {
90 if (!buf) return;
91 adns__diag(ads,-1,"warning - `options' ignored fixme");
92 }
93
94 static void ccf_clearnss(adns_state ads, const char *fn, int lno, const char *buf) {
95 ads->nservers= 0;
96 }
97
98 static 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
111 static 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) {
120 adns__debug(ads,-1,"configuration file `%s' does not exist",filename);
121 return;
122 }
123 adns__diag(ads,-1,"cannot open configuration file `%s': %s",
124 filename,strerror(errno));
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)) {
132 adns__diag(ads,-1,"%s:%d: line too long",filename,lno);
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) {
148 adns__diag(ads,-1,"%s:%d: unknown configuration directive `%.*s'",
149 filename,lno,q-p,p);
150 continue;
151 }
152 while (ctype_whitespace(*q)) q++;
153 ccip->fn(ads,filename,lno,q);
154 }
155 if (ferror(file)) {
156 adns__diag(ads,-1,"%s:%d: read error: %s",filename,lno,strerror(errno));
157 }
158 fclose(file);
159 }
160
161 static const char *instrum_getenv(adns_state ads, const char *envvar) {
162 const char *value;
163
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);
167 return value;
168 }
169
170 static void readconfigenv(adns_state ads, const char *envvar) {
171 const char *filename;
172
173 if (ads->iflags & adns_if_noenv) {
174 adns__debug(ads,-1,"not checking environment variable `%s'",envvar);
175 return;
176 }
177 filename= instrum_getenv(ads,envvar);
178 if (filename) readconfig(ads,filename);
179 }
180
181
182 int adns__setnonblock(adns_state ads, int fd) {
183 int r;
184
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
191 int adns_init(adns_state *ads_r, adns_initflags flags, FILE *diagfile) {
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;
198 ads->iflags= flags;
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;
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);
211
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);
216
217 readconfig(ads,"/etc/resolv.conf");
218 readconfigenv(ads,"RES_CONF");
219 readconfigenv(ads,"ADNS_RES_CONF");
220
221 ccf_options(ads,"RES_OPTIONS",-1,res_options);
222 ccf_options(ads,"ADNS_RES_OPTIONS",-1,adns_res_options);
223
224 ccf_search(ads,"LOCALDOMAIN",-1,instrum_getenv(ads,"LOCALDOMAIN"));
225 ccf_search(ads,"ADNS_LOCALDOMAIN",-1,instrum_getenv(ads,"ADNS_LOCALDOMAIN"));
226
227 if (!ads->nservers) {
228 struct in_addr ia;
229 if (ads->iflags & adns_if_debug)
230 fprintf(stderr,"adns: no nameservers, using localhost\n");
231 ia.s_addr= INADDR_LOOPBACK;
232 addserver(ads,ia);
233 }
234
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; }
238
239 r= adns__setnonblock(ads,ads->udpsocket);
240 if (r) { r= errno; goto x_closeudp; }
241
242 *ads_r= ads;
243 return 0;
244
245 x_closeudp:
246 close(ads->udpsocket);
247 x_free:
248 free(ads);
249 return r;
250 }
251
252 int adns_finish(adns_state ads) {
253 abort(); /* fixme */
254 }