Files

211 lines
4.9 KiB
C
Raw Permalink Normal View History

/* config_file.c - masterdont config file reading */
#include "config.h"
#include "config_file.h"
#include "zones.h"
#include "zinfo.h"
/* used during config file reading */
static struct config_read cread;
/* config syntax error */
static void config_err(char* str)
{
if(cread.include_depth == 0)
fprintf(stderr, "error: %s\n", str);
else fprintf(stderr, "error in %s %d: %s\n",
cread.fnames[cread.include_depth-1],
cread.lineno[cread.include_depth-1], str);
exit(1);
}
/* skip to end of line */
static void skip_to_eol(FILE* in)
{
int c;
while( (c=fgetc(in)) != EOF) {
if(c == '\n') {
cread.lineno[cread.include_depth-1]++;
return;
}
}
/* EOF is end of line too for ending a comment */
}
/* fill quoted string, remove ending quote */
static void fillup_quoted(FILE* in, char* buf, size_t sz, char q)
{
size_t pos = strlen(buf);
int c;
if(pos>0 && buf[pos-1] == q) {
buf[pos-1] = 0;
return;
}
while( (c=fgetc(in)) != EOF ) {
if(c == q) {
buf[pos] = 0;
return;
}
buf[pos++] = c;
if(pos >= sz) config_err("string too long");
}
config_err("no ending quote for string");
}
/* skip whitespace */
static char skip_white(FILE* in)
{
int c;
while( (c=fgetc(in)) != EOF ) {
if(c == ' ' || c == '\t' || c == '\r')
continue;
else if(c == '\n') {
cread.lineno[cread.include_depth-1]++;
continue;
}
return c;
}
return 0;
}
/* mini lexer and parser; grab one word from the input file, skip
* whitespace and comments. return 0 on EOF */
static char* read_token(FILE* in)
{
static char buf[10240];
buf[sizeof(buf)-1] = 0;
while(!feof(in)) {
buf[0] = skip_white(in);
if(feof(in)) return 0;
if(fscanf(in, "%10230s", buf+1) != 1) {
return 0;
}
if(buf[0] == '#') {
skip_to_eol(in);
continue;
} else if(buf[0] == '\"' || buf[0] == '\'') {
fillup_quoted(in, buf, sizeof(buf), buf[0]);
return buf+1;
}
return buf;
}
return 0;
}
struct config_file* config_file_create()
{
struct config_file* cfg = (struct config_file*)calloc(1, sizeof(*cfg));
if(!cfg) {
printf("out of memory\n");
exit(1);
}
cfg->port = DEFAULT_PORT;
return cfg;
}
void config_file_delete(struct config_file* cfg)
{
if(!cfg) return;
free(cfg);
}
/* open new include file */
static void config_open_include(const char* fname)
{
if(cread.include_depth >= MAX_INCLUDES)
config_err("too many include files");
cread.fnames[cread.include_depth] = strdup(fname);
if(!cread.fnames[cread.include_depth])
config_err("out of memory");
cread.fstack[cread.include_depth] = fopen(fname, "ra");
if(!cread.fstack[cread.include_depth]) {
perror(fname);
config_err("could not open config file");
}
cread.lineno[cread.include_depth] = 1;
cread.include_depth ++;
}
/* close include file */
static void config_close_include(void)
{
if(cread.include_depth == 0) config_err("unexpected end of file");
free(cread.fnames[cread.include_depth-1]);
fclose(cread.fstack[cread.include_depth-1]);
cread.fstack[cread.include_depth-1] = NULL;
cread.include_depth--;
}
void config_file_read(struct config_file* cfg, const char* fname,
struct zones_t* zones)
{
char* p;
char key[1024];
cread.cfg = cfg;
cread.zones = zones;
cread.include_depth = 0;
cread.zone_read = 0;
config_open_include(fname);
while(cread.include_depth > 0) {
p = read_token(cread.fstack[cread.include_depth-1]);
if(p == 0) {
config_close_include();
continue;
}
if(strcmp(p, "server:") == 0)
continue;
else if(strcmp(p, "zone:") == 0) {
if(cread.zone_read) config_file_add_zone(&cread);
cread.zone_read = 1;
cread.zone_linenr = cread.lineno[cread.include_depth-1];
cread.zone_name = NULL;
cread.zone_dir = NULL;
continue;
}
key[sizeof(key)-1]=0;
strncpy(key, p, sizeof(key)-1);
while((p=read_token(cread.fstack[cread.include_depth-1]))==0){
config_close_include();
if(cread.include_depth == 0)
config_err("unexpected end of file");
}
if(strcmp(key, "include:") == 0) {
config_open_include(p);
} else if(strcmp(key, "port:") == 0) {
cfg->port = atoi(p);
if(cfg->port == 0) config_err("invalid port number");
} else if(strcmp(key, "name:") == 0) {
free(cread.zone_name);
cread.zone_name = strdup(p);
if(!cread.zone_name) config_err("out of memory");
} else if(strcmp(key, "dir:") == 0) {
free(cread.zone_dir);
cread.zone_dir = strdup(p);
if(!cread.zone_dir) config_err("out of memory");
}
}
if(cread.zone_read) config_file_add_zone(&cread);
}
void config_file_add_zone(struct config_read* cr)
{
struct zone_entry_t* entry;
if(cr->zone_name == NULL) {
fprintf(stderr, "in zone declared on line %d\n",
cr->zone_linenr);
config_err("zone has no name");
}
if(cr->zone_dir == NULL) {
fprintf(stderr, "in zone declared on line %d\n",
cr->zone_linenr);
config_err("zone has no dir");
}
entry = zones_insert(cr->zones, cr->zone_name, LDNS_RR_CLASS_IN);
if(!entry) {
config_err("out of memory adding zone");
}
entry->zinfo->dir = cr->zone_dir;
free(cr->zone_name);
}