From 36369543b62cd8922a096f7877036ec8497bc5a9 Mon Sep 17 00:00:00 2001 From: ian Date: Sun, 22 Nov 1998 19:06:32 +0000 Subject: [PATCH] Allow configuration entirely by text file. --- src/adns.h | 7 +- src/general.c | 17 ++-- src/internal.h | 1 + src/setup.c | 255 ++++++++++++++++++++++++++++++++++++++----------- 4 files changed, 215 insertions(+), 65 deletions(-) diff --git a/src/adns.h b/src/adns.h index 6a9e1b3..da30694 100644 --- a/src/adns.h +++ b/src/adns.h @@ -235,8 +235,11 @@ typedef struct { * If no (appropriate) requests are outstanding adns_query and adns_wait return ESRCH; */ -/* fixme: separate parsing from instantiation */ -int adns_init(adns_state *newstate_r, adns_initflags flags, FILE *diagfile/*0=>stderr*/); +int adns_init(adns_state *newstate_r, adns_initflags flags, + FILE *diagfile /*0=>stderr*/); + +int adns_init_strcfg(adns_state *newstate_r, adns_initflags flags, + FILE *diagfile /*0=>discard*/, const char *configtext); int adns_synchronous(adns_state ads, const char *owner, diff --git a/src/general.c b/src/general.c index fbab698..45aec68 100644 --- a/src/general.c +++ b/src/general.c @@ -34,33 +34,36 @@ void adns__vdiag(adns_state ads, const char *pfx, adns_initflags prevent, int serv, adns_query qu, const char *fmt, va_list al) { const char *bef, *aft; vbuf vb; - if (!(ads->iflags & adns_if_debug) && (!prevent || (ads->iflags & prevent))) return; + + if (!ads->diagfile || + (!(ads->iflags & adns_if_debug) && (!prevent || (ads->iflags & prevent)))) + return; - fprintf(stderr,"adns%s: ",pfx); + fprintf(ads->diagfile,"adns%s: ",pfx); - vfprintf(stderr,fmt,al); + vfprintf(ads->diagfile,fmt,al); bef= " ("; aft= "\n"; if (qu && qu->query_dgram) { adns__vbuf_init(&vb); - fprintf(stderr,"%sQNAME=%s, QTYPE=%s", + fprintf(ads->diagfile,"%sQNAME=%s, QTYPE=%s", bef, adns__diag_domain(qu->ads,-1,0, &vb, qu->query_dgram,qu->query_dglen,DNS_HDRSIZE), qu->typei ? qu->typei->rrtname : ""); if (qu->typei && qu->typei->fmtname) - fprintf(stderr,"(%s)",qu->typei->fmtname); + fprintf(ads->diagfile,"(%s)",qu->typei->fmtname); bef=", "; aft=")\n"; } if (serv>=0) { - fprintf(stderr,"%sNS=%s",bef,inet_ntoa(ads->servers[serv].addr)); + fprintf(ads->diagfile,"%sNS=%s",bef,inet_ntoa(ads->servers[serv].addr)); bef=", "; aft=")\n"; } - fputs(aft,stderr); + fputs(aft,ads->diagfile); } void adns__debug(adns_state ads, int serv, adns_query qu, const char *fmt, ...) { diff --git a/src/internal.h b/src/internal.h index 672e3a9..27d0258 100644 --- a/src/internal.h +++ b/src/internal.h @@ -239,6 +239,7 @@ struct adns__query { struct adns__state { adns_initflags iflags; FILE *diagfile; + int configerrno; struct { adns_query head, tail; } timew, childw, output; int nextid, udpsocket, tcpsocket; vbuf tcpsend, tcprecv; diff --git a/src/setup.c b/src/setup.c index 72c72d4..c0f584b 100644 --- a/src/setup.c +++ b/src/setup.c @@ -32,6 +32,8 @@ #include "internal.h" +static void readconfig(adns_state ads, const char *filename); + static void addserver(adns_state ads, struct in_addr addr) { int i; struct server *ss; @@ -53,17 +55,23 @@ static void addserver(adns_state ads, struct in_addr addr) { ads->nservers++; } +static void saveerr(adns_state ads, int en) { + if (!ads->configerrno) ads->configerrno= en; +} + static void configparseerr(adns_state ads, const char *fn, int lno, const char *fmt, ...) { va_list al; - - if (ads->iflags & adns_if_noerrprint) return; - if (lno==-1) fprintf(stderr,"adns: %s: ",fn); - else fprintf(stderr,"adns: %s:%d: ",fn,lno); + + saveerr(ads,EINVAL); + if (!ads->diagfile || (ads->iflags & adns_if_noerrprint)) return; + + if (lno==-1) fprintf(ads->diagfile,"adns: %s: ",fn); + else fprintf(ads->diagfile,"adns: %s:%d: ",fn,lno); va_start(al,fmt); - vfprintf(stderr,fmt,al); + vfprintf(ads->diagfile,fmt,al); va_end(al); - fputc('\n',stderr); + fputc('\n',ads->diagfile); } static void ccf_nameserver(adns_state ads, const char *fn, int lno, const char *buf) { @@ -95,6 +103,14 @@ static void ccf_clearnss(adns_state ads, const char *fn, int lno, const char *bu ads->nservers= 0; } +static void ccf_include(adns_state ads, const char *fn, int lno, const char *buf) { + if (!*buf) { + configparseerr(ads,fn,lno,"`include' directive with no filename"); + return; + } + readconfig(ads,buf); +} + static const struct configcommandinfo { const char *name; void (*fn)(adns_state ads, const char *fn, int lno, const char *buf); @@ -105,44 +121,109 @@ static const struct configcommandinfo { { "sortlist", ccf_sortlist }, { "options", ccf_options }, { "clearnameservers", ccf_clearnss }, + { "include", ccf_include }, { 0 } }; -static void readconfig(adns_state ads, const char *filename) { - char linebuf[2000], *p, *q; +typedef union { FILE *file; - int lno, l, c; - const struct configcommandinfo *ccip; + const char *text; +} getline_ctx; - file= fopen(filename,"r"); - if (!file) { - if (errno == ENOENT) { - adns__debug(ads,-1,0,"configuration file `%s' does not exist",filename); - return; +static int gl_file(adns_state ads, getline_ctx *src_io, const char *filename, + int lno, char *buf, int buflen) { + FILE *file= src_io->file; + int c, i; + char *p; + + p= buf; + buflen--; + i= 0; + + for (;;) { /* loop over chars */ + if (i == buflen) { + adns__diag(ads,-1,0,"%s:%d: line too long, ignored",filename,lno); + goto x_badline; + } + c= getc(file); + if (!c) { + adns__diag(ads,-1,0,"%s:%d: line contains nul, ignored",filename,lno); + goto x_badline; + } else if (c == '\n') { + break; + } else if (c == EOF) { + if (ferror(file)) { + saveerr(ads,errno); + adns__diag(ads,-1,0,"%s:%d: read error: %s",filename,lno,strerror(errno)); + return -1; + } + if (!i) return -1; + break; + } else { + *p++= c; + i++; } - adns__diag(ads,-1,0,"cannot open configuration file `%s': %s", - filename,strerror(errno)); - return; } - for (lno=1; fgets(linebuf,sizeof(linebuf),file); lno++) { - l= strlen(linebuf); - if (!l) continue; - if (linebuf[l-1] != '\n' && !feof(file)) { - adns__diag(ads,-1,0,"%s:%d: line too long",filename,lno); - while ((c= getc(file)) != EOF && c != '\n') { } - if (c == EOF) break; - continue; - } + *p++= 0; + return i; + + x_badline: + saveerr(ads,EINVAL); + while ((c= getc(file)) != EOF && c != '\n'); + return -2; +} + +static int gl_text(adns_state ads, getline_ctx *src_io, const char *filename, + int lno, char *buf, int buflen) { + const char *cp= src_io->text, *nn; + int l; + + if (!cp) return -1; + + nn= strchr(cp,'\n'); + + l= nn ? nn-cp : strlen(cp); + src_io->text= nn ? nn+1 : 0; + + if (l >= buflen) { + adns__diag(ads,-1,0,"%s:%d: line too long, ignored",filename,lno); + saveerr(ads,EINVAL); + return -2; + } + + memcpy(buf,cp,l); + buf[l]= 0; + return l; +} + +static void readconfiggeneric(adns_state ads, const char *filename, + int (*getline)(adns_state ads, getline_ctx*, + const char *filename, int lno, + char *buf, int buflen), + /* Returns >=0 for success, -1 for EOF or error + * (error will have been reported), or -2 for + * bad line was encountered, try again. + */ + getline_ctx gl_ctx) { + char linebuf[2000], *p, *q; + int lno, l, dirl; + const struct configcommandinfo *ccip; + + for (lno=1; + (l= getline(ads,&gl_ctx, filename,lno, linebuf,sizeof(linebuf))) != -1; + lno++) { + if (l == -2) continue; while (l>0 && ctype_whitespace(linebuf[l-1])) l--; linebuf[l]= 0; p= linebuf; while (ctype_whitespace(*p)) p++; - if (*p == '#' || *p == '\n') continue; + if (*p == '#' || !*p) continue; q= p; while (*q && !ctype_whitespace(*q)) q++; + dirl= q-p; for (ccip=configcommandinfos; - ccip->name && strncmp(ccip->name,p,q-p); + ccip->name && !(strlen(ccip->name)==dirl && !memcmp(ccip->name,p,q-p)); ccip++); if (!ccip->name) { adns__diag(ads,-1,0,"%s:%d: unknown configuration directive `%.*s'", @@ -152,10 +233,6 @@ static void readconfig(adns_state ads, const char *filename) { while (ctype_whitespace(*q)) q++; ccip->fn(ads,filename,lno,q); } - if (ferror(file)) { - adns__diag(ads,-1,0,"%s:%d: read error: %s",filename,lno,strerror(errno)); - } - fclose(file); } static const char *instrum_getenv(adns_state ads, const char *envvar) { @@ -167,6 +244,33 @@ static const char *instrum_getenv(adns_state ads, const char *envvar) { return value; } +static void readconfig(adns_state ads, const char *filename) { + getline_ctx gl_ctx; + + gl_ctx.file= fopen(filename,"r"); + if (!gl_ctx.file) { + if (errno == ENOENT) { + adns__debug(ads,-1,0,"configuration file `%s' does not exist",filename); + return; + } + saveerr(ads,errno); + adns__diag(ads,-1,0,"cannot open configuration file `%s': %s", + filename,strerror(errno)); + return; + } + + readconfiggeneric(ads,filename,gl_file,gl_ctx); + + fclose(gl_ctx.file); +} + +static void readconfigtext(adns_state ads, const char *text, const char *showname) { + getline_ctx gl_ctx; + + gl_ctx.text= text; + readconfiggeneric(ads,showname,gl_text,gl_ctx); +} + static void readconfigenv(adns_state ads, const char *envvar) { const char *filename; @@ -188,15 +292,13 @@ int adns__setnonblock(adns_state ads, int fd) { return 0; } -int adns_init(adns_state *ads_r, adns_initflags flags, FILE *diagfile) { +static int init_begin(adns_state *ads_r, adns_initflags flags, FILE *diagfile) { adns_state ads; - const char *res_options, *adns_res_options; - struct protoent *proto; - int r; ads= malloc(sizeof(*ads)); if (!ads) return errno; + ads->iflags= flags; - ads->diagfile= diagfile ? diagfile : stderr; + ads->diagfile= diagfile; LIST_INIT(ads->timew); LIST_INIT(ads->childw); LIST_INIT(ads->output); @@ -208,25 +310,18 @@ int adns_init(adns_state *ads_r, adns_initflags flags, FILE *diagfile) { ads->tcpstate= server_disconnected; timerclear(&ads->tcptimeout); - res_options= instrum_getenv(ads,"RES_OPTIONS"); - adns_res_options= instrum_getenv(ads,"ADNS_RES_OPTIONS"); - ccf_options(ads,"RES_OPTIONS",-1,res_options); - ccf_options(ads,"ADNS_RES_OPTIONS",-1,adns_res_options); - - readconfig(ads,"/etc/resolv.conf"); - readconfigenv(ads,"RES_CONF"); - readconfigenv(ads,"ADNS_RES_CONF"); - - ccf_options(ads,"RES_OPTIONS",-1,res_options); - ccf_options(ads,"ADNS_RES_OPTIONS",-1,adns_res_options); - - ccf_search(ads,"LOCALDOMAIN",-1,instrum_getenv(ads,"LOCALDOMAIN")); - ccf_search(ads,"ADNS_LOCALDOMAIN",-1,instrum_getenv(ads,"ADNS_LOCALDOMAIN")); + *ads_r= ads; + return 0; +} +static int init_finish(adns_state ads) { + struct in_addr ia; + struct protoent *proto; + int r; + if (!ads->nservers) { - struct in_addr ia; - if (ads->iflags & adns_if_debug) - fprintf(stderr,"adns: no nameservers, using localhost\n"); + if (ads->diagfile && ads->iflags & adns_if_debug) + fprintf(ads->diagfile,"adns: no nameservers, using localhost\n"); ia.s_addr= INADDR_LOOPBACK; addserver(ads,ia); } @@ -238,7 +333,6 @@ int adns_init(adns_state *ads_r, adns_initflags flags, FILE *diagfile) { r= adns__setnonblock(ads,ads->udpsocket); if (r) { r= errno; goto x_closeudp; } - *ads_r= ads; return 0; x_closeudp: @@ -248,6 +342,55 @@ int adns_init(adns_state *ads_r, adns_initflags flags, FILE *diagfile) { return r; } +int adns_init(adns_state *ads_r, adns_initflags flags, FILE *diagfile) { + adns_state ads; + const char *res_options, *adns_res_options; + int r; + + r= init_begin(&ads, flags, diagfile ? diagfile : stderr); + if (r) return r; + + res_options= instrum_getenv(ads,"RES_OPTIONS"); + adns_res_options= instrum_getenv(ads,"ADNS_RES_OPTIONS"); + ccf_options(ads,"RES_OPTIONS",-1,res_options); + ccf_options(ads,"ADNS_RES_OPTIONS",-1,adns_res_options); + + readconfig(ads,"/etc/resolv.conf"); + readconfigenv(ads,"RES_CONF"); + readconfigenv(ads,"ADNS_RES_CONF"); + + ccf_options(ads,"RES_OPTIONS",-1,res_options); + ccf_options(ads,"ADNS_RES_OPTIONS",-1,adns_res_options); + + ccf_search(ads,"LOCALDOMAIN",-1,instrum_getenv(ads,"LOCALDOMAIN")); + ccf_search(ads,"ADNS_LOCALDOMAIN",-1,instrum_getenv(ads,"ADNS_LOCALDOMAIN")); + + r= init_finish(ads); + if (r) return r; + + *ads_r= ads; + return 0; +} + +int adns_init_strcfg(adns_state *ads_r, adns_initflags flags, + FILE *diagfile, const char *configtext) { + adns_state ads; + int r; + + r= init_begin(&ads, flags, diagfile); if (r) return r; + + readconfigtext(ads,configtext,""); + if (ads->configerrno) { + r= ads->configerrno; + free(ads); + return r; + } + + r= init_finish(ads); if (r) return r; + *ads_r= ads; + return 0; +} + void adns_finish(adns_state ads) { for (;;) { if (ads->timew.head) adns_cancel(ads->timew.head); -- 2.30.2