chiark / gitweb /
ecf92a2ee03ad57277309be91ccf973cfa746d25
[adns.git] / src / setup.c
1 /**/
2
3 #include "adns-internal.h"
4
5 static void vdebug(adns_state ads, const char *fmt, va_list al) {
6   if (!(ads->iflags & adns_if_debug)) return;
7   fputs("adns debug: ",stderr);
8   vfprintf(stderr,fmt,al);
9   fputc('\n',stderr);
10 }
11
12 void adns__debug(adns_state ads, const char *fmt, ...) {
13   va_list al;
14
15   va_start(al,fmt);
16   vdebug(ads,fmt,al);
17   va_end(al);
18 }
19
20 static void vdiag(adns_state ads, const char *fmt, va_list al) {
21   if (ads->iflags & adns_if_noerrprint) return;
22   fputs("adns: ",stderr);
23   vfprintf(stderr,fmt,al);
24   fputc('\n',stderr);
25 }
26
27 void adns__diag(adns_state ads, const char *fmt, ...) {
28   va_list al;
29
30   va_start(al,fmt);
31   vdiag(ads,fmt,al);
32   va_end(al);
33 }
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       debug(ads,"duplicate nameserver %s ignored",inet_ntoa(addr));
42       return;
43     }
44   }
45   
46   if (ads->nservers>=MAXSERVERS) {
47     diag(ads,"too many nameservers, ignoring %s",inet_ntoa(addr));
48     return;
49   }
50
51   ss= ads->servers+ads->nservers;
52   ss->addr= addr;
53   ss->state= server_disc;
54   ss->connw.head= ss->connw.tail= 0;
55   ads->nservers++;
56 }
57
58 static void configparseerr(adns_state ads, const char *fn, int lno,
59                            const char *fmt, ...) {
60   va_list al;
61   
62   if (ads->iflags & adns_if_noerrprint) return;
63   if (lno==-1) fprintf(stderr,"adns: %s: ",fn);
64   else fprintf(stderr,"adns: %s:%d: ",fn,lno);
65   va_start(al,fmt);
66   vfprintf(stderr,fmt,al);
67   va_end(al);
68   fputc('\n',stderr);
69 }
70
71 static void ccf_nameserver(adns_state ads, const char *fn, int lno, const char *buf) {
72   struct in_addr ia;
73   
74   if (!inet_aton(buf,&ia)) {
75     configparseerr(ads,fn,lno,"invalid nameserver address `%s'",buf);
76     return;
77   }
78   debug(ads,"using nameserver %s",inet_ntoa(ia));
79   addserver(ads,ia);
80 }
81
82 static void ccf_search(adns_state ads, const char *fn, int lno, const char *buf) {
83   if (!buf) return;
84   diag(ads,"warning - `search' ignored FIXME");
85 }
86
87 static void ccf_sortlist(adns_state ads, const char *fn, int lno, const char *buf) {
88   diag(ads,"warning - `sortlist' ignored FIXME");
89 }
90
91 static void ccf_options(adns_state ads, const char *fn, int lno, const char *buf) {
92   if (!buf) return;
93   diag(ads,"warning - `options' ignored FIXME");
94 }
95
96 static void ccf_clearnss(adns_state ads, const char *fn, int lno, const char *buf) {
97   ads->nservers= 0;
98 }
99
100 static const struct configcommandinfo {
101   const char *name;
102   void (*fn)(adns_state ads, const char *fn, int lno, const char *buf);
103 } configcommandinfos[]= {
104   { "nameserver",        ccf_nameserver  },
105   { "domain",            ccf_search      },
106   { "search",            ccf_search      },
107   { "sortlist",          ccf_sortlist    },
108   { "options",           ccf_options     },
109   { "clearnameservers",  ccf_clearnss    },
110   {  0                                   }
111 };
112
113 static int ctype_whitespace(int c) { return c==' ' || c=='\n' || c=='\t'; }
114 static int ctype_digit(int c) { return c>='0' && c<='9'; }
115
116 static void readconfig(adns_state ads, const char *filename) {
117   char linebuf[2000], *p, *q;
118   FILE *file;
119   int lno, l, c;
120   const struct configcommandinfo *ccip;
121
122   file= fopen(filename,"r");
123   if (!file) {
124     if (errno == ENOENT) {
125       debug(ads,"configuration file `%s' does not exist",filename);
126       return;
127     }
128     diag(ads,"cannot open configuration file `%s': %s",filename,strerror(errno));
129     return;
130   }
131
132   for (lno=1; fgets(linebuf,sizeof(linebuf),file); lno++) {
133     l= strlen(linebuf);
134     if (!l) continue;
135     if (linebuf[l-1] != '\n' && !feof(file)) {
136       diag(ads,"%s:%d: line too long",filename,lno);
137       while ((c= getc(file)) != EOF && c != '\n') { }
138       if (c == EOF) break;
139       continue;
140     }
141     while (l>0 && ctype_whitespace(linebuf[l-1])) l--;
142     linebuf[l]= 0;
143     p= linebuf;
144     while (ctype_whitespace(*p)) p++;
145     if (*p == '#' || *p == '\n') continue;
146     q= p;
147     while (*q && !ctype_whitespace(*q)) q++;
148     for (ccip=configcommandinfos;
149          ccip->name && strncmp(ccip->name,p,q-p);
150          ccip++);
151     if (!ccip->name) {
152       diag(ads,"%s:%d: unknown configuration directive `%.*s'",filename,lno,q-p,p);
153       continue;
154     }
155     while (ctype_whitespace(*q)) q++;
156     ccip->fn(ads,filename,lno,q);
157   }
158   if (ferror(file)) {
159     diag(ads,"%s:%d: read error: %s",filename,lno,strerror(errno));
160   }
161   fclose(file);
162 }
163
164 static const char *instrum_getenv(adns_state ads, const char *envvar) {
165   const char *value;
166
167   value= getenv(envvar);
168   if (!value) debug(ads,"environment variable %s not set",envvar);
169   else debug(ads,"environment variable %s set to `%s'",envvar,value);
170   return value;
171 }
172
173 static void readconfigenv(adns_state ads, const char *envvar) {
174   const char *filename;
175
176   if (ads->iflags & adns_if_noenv) {
177     debug(ads,"not checking environment variable `%s'",envvar);
178     return;
179   }
180   filename= instrum_getenv(ads,envvar);
181   if (filename) readconfig(ads,filename);
182 }
183   
184 int adns_init(adns_state *ads_r, adns_initflags flags) {
185   adns_state ads;
186   const char *res_options, *adns_res_options;
187   struct protoent *proto;
188   int r;
189   
190   ads= malloc(sizeof(*ads)); if (!ads) return errno;
191   ads->tosend.head= ads->tosend.tail= 0;
192   ads->timew.head= ads->timew.tail= 0;
193   ads->childw.head= ads->childw.tail= 0;
194   ads->output.head= ads->output.tail= 0;
195   ads->nextid= 0x311f;
196   ads->udpsocket= -1;
197   ads->qbufavail= 0;
198   ads->qbuf= 0;
199   ads->tcpbufavail= ads->tcpbufused= ads->tcpbufdone= 0;
200   ads->tcpbuf= 0;
201   ads->iflags= flags;
202   ads->nservers= 0;
203   ads->iflags= flags;
204
205   res_options= instrum_getenv(ads,"RES_OPTIONS");
206   adns_res_options= instrum_getenv(ads,"ADNS_RES_OPTIONS");
207   ccf_options(ads,"RES_OPTIONS",-1,res_options);
208   ccf_options(ads,"ADNS_RES_OPTIONS",-1,adns_res_options);
209
210   readconfig(ads,"/etc/resolv.conf");
211   readconfigenv(ads,"RES_CONF");
212   readconfigenv(ads,"ADNS_RES_CONF");
213
214   ccf_options(ads,"RES_OPTIONS",-1,res_options);
215   ccf_options(ads,"ADNS_RES_OPTIONS",-1,adns_res_options);
216
217   ccf_search(ads,"LOCALDOMAIN",-1,instrum_getenv(ads,"LOCALDOMAIN"));
218   ccf_search(ads,"ADNS_LOCALDOMAIN",-1,instrum_getenv(ads,"ADNS_LOCALDOMAIN"));
219
220   if (!ads->nservers) {
221     struct in_addr ia;
222     if (ads->iflags & adns_if_debug)
223       fprintf(stderr,"adns: no nameservers, using localhost\n");
224     ia.s_addr= INADDR_LOOPBACK;
225     addserver(ads,ia);
226   }
227
228   proto= getprotobyname("udp"); if (!proto) { r= ENOPROTOOPT; goto x_free; }
229   ads->udpsocket= socket(AF_INET,SOCK_DGRAM,proto->p_proto);
230   if (!ads->udpsocket) { r= errno; goto x_closeudp; }
231   
232   *ads_r= ads;
233   return 0;
234
235  x_closeudp:
236   close(ads->udpsocket);
237  x_free:
238   free(ads);
239   return r;
240 }
241
242 int adns_finish(adns_state ads) {
243   abort(); /* FIXME */
244 }