Import release 0.1.10
[secnet] / conffile.c
1 /*
2 * $Log$
3 */
4
5 /* conffile.c - process the configuration file */
6
7 /* #define DUMP_PARSE_TREE */
8
9 #include "secnet.h"
10 #include <stdio.h>
11 #include <string.h>
12 #include "conffile.h"
13 #include "conffile_internal.h"
14 #include "util.h"
15 #include "ipaddr.h"
16
17 /* from modules.c */
18 extern void init_builtin_modules(dict_t *dict);
19
20 static struct cloc no_loc={"none",0};
21
22 struct atomlist {
23 struct atomlist *next;
24 atom_t a;
25 };
26
27 struct entry {
28 struct entry *next;
29 atom_t key;
30 list_t *val;
31 };
32
33 struct searchlist {
34 struct dict *d;
35 struct searchlist *next;
36 };
37
38 struct dict {
39 struct dict *parent;
40 struct searchlist *search;
41 struct entry *entries;
42 uint32_t size;
43 };
44
45 static struct atomlist *atoms=NULL;
46
47 static void process_alist(dict_t *context, struct p_node *c);
48 static list_t *process_invocation(dict_t *context, struct p_node *i);
49
50 static list_t *dict_ilookup_primitive(dict_t *dict, atom_t key)
51 {
52 struct entry *i;
53 for (i=dict->entries; i; i=i->next) {
54 if (key==i->key) return i->val;
55 }
56 return NULL;
57 }
58
59 static list_t *dict_ilookup(dict_t *dict, atom_t key)
60 {
61 dict_t *d;
62 list_t *v;
63
64 v=dict_ilookup_primitive(dict, key);
65 if (v) return v;
66 /* Check dictionaries in search path */
67 /* XXX */
68 /* Check lexical parents */
69 for (d=dict; d; d=d->parent) {
70 v=dict_ilookup_primitive(d, key);
71 if (v) return v;
72 }
73 return NULL;
74 }
75
76 static void dict_iadd(dict_t *dict, atom_t key, list_t *val)
77 {
78 struct entry *e;
79 /* XXX May want to permit redefinition of keys in the future */
80 /* (although it could be very confusing) */
81 if (dict_ilookup_primitive(dict, key)) {
82 fatal("duplicate key \"%s\" in dictionary\n",key);
83 }
84 e=safe_malloc(sizeof(*e),"dict_add");
85 e->next=dict->entries;
86 e->key=key;
87 e->val=val;
88 dict->entries=e;
89 dict->size++;
90 }
91
92 /***** Functions beyond this point are private to the config system *****/
93
94 static dict_t *dict_new(dict_t *parent)
95 {
96 dict_t *d;
97
98 d=safe_malloc(sizeof(*d),"dict_new");
99 d->parent=parent;
100 d->search=NULL;
101 d->entries=NULL;
102 d->size=0;
103 return d;
104 }
105
106 static struct p_node *node_copy(struct p_node *n)
107 {
108 struct p_node *r;
109 r=safe_malloc(sizeof(*r),"node_copy");
110 *r=*n;
111 return r;
112 }
113
114 static struct p_node *list_reverse(struct p_node *list)
115 {
116 struct p_node *rl=NULL, *i, *n;
117
118 for (i=list; i; i=i->r) {
119 n=node_copy(i);
120 n->r=rl;
121 rl=n;
122 }
123 return rl;
124 }
125
126 /* Since we use left-recursion in the parser for efficiency, sequences
127 end up "backwards" in the parse tree. Rather than have complicated
128 code for, eg. processing assignments in the right order, we reverse
129 these sequences here. */
130 static void ptree_mangle(struct p_node *t)
131 {
132 if (!t) return;
133 ptree_mangle(t->l);
134 ptree_mangle(t->r);
135 switch (t->type) {
136 case T_DICT:
137 /* ASSERT !t->l || t->l->type==T_ALIST */
138 /* ASSERT !t->r || t->r->type==T_LISTITEM */
139 t->l=list_reverse(t->l);
140 t->r=list_reverse(t->r);
141 break;
142 case T_ASSIGNMENT:
143 /* ASSERT t->l->type==T_KEY */
144 /* ASSERT t->r->type==T_LISTITEM */
145 t->r=list_reverse(t->r);
146 break;
147 case T_ABSPATH:
148 case T_RELPATH:
149 /* ASSERT t->l==NULL */
150 /* ASSERT t->r->type==T_PATHELEM */
151 t->r=list_reverse(t->r);
152 break;
153 case T_EXEC:
154 /* ASSERT t->l */
155 /* ASSERT t->r->type==T_LISTITEM */
156 t->r=list_reverse(t->r);
157 break;
158 }
159 }
160
161 #ifdef DUMP_PARSE_TREE
162 /* Convert a node type to a string, for parse tree dump */
163 static string_t ntype(uint32_t type)
164 {
165 switch(type) {
166 case T_STRING: return "T_STRING";
167 case T_NUMBER: return "T_NUMBER";
168 case T_KEY: return "T_KEY";
169 case T_ASSIGNMENT: return "T_ASSIGNMENT";
170 case T_LISTITEM: return "T_LISTITEM";
171 case T_EXEC: return "T_EXEC";
172 case T_PATHELEM: return "T_PATHELEM";
173 case T_ABSPATH: return "T_ABSPATH";
174 case T_RELPATH: return "T_RELPATH";
175 case T_DICT: return "T_DICT";
176 case T_ALIST: return "T_ALIST";
177 case T_ERROR: return "T_ERROR";
178 }
179 return "**unknown**";
180 }
181
182 static void ptree_indent(uint32_t amount)
183 {
184 uint32_t i;
185 for (i=0; i<amount; i++) printf(" . ");
186 }
187
188 static void ptree_dump(struct p_node *n, uint32_t d)
189 {
190 if (!n) {
191 printf("NULL\n");
192 return;
193 }
194
195 if (n->type<10) {
196 switch(n->type) {
197 case T_STRING: printf("T_STRING: \"%s\" (%s line %d)\n",
198 n->data.string,n->loc.file,n->loc.line); break;
199 case T_NUMBER: printf("T_NUMBER: %d (%s line %d)\n",
200 n->data.number, n->loc.file,n->loc.line); break;
201 case T_KEY: printf("T_KEY: %s (%s line %d)\n",
202 n->data.key, n->loc.file,n->loc.line); break;
203 default: printf("**unknown primitive type**\n"); break;
204 }
205 } else {
206 printf("%s: (%s line %d)\n",ntype(n->type),n->loc.file,n->loc.line);
207 ptree_indent(d);
208 printf(" |-"); ptree_dump(n->l, d+1);
209 ptree_indent(d);
210 printf(" +-"); ptree_dump(n->r, d+1);
211 }
212 }
213
214 #endif /* DUMP_PARSE_TREE */
215
216 static dict_t *dict_find_root(dict_t *d)
217 {
218 dict_t *i;
219
220 for (i=d; i->parent; i=i->parent);
221 return i;
222 }
223
224 static list_t *dict_lookup_path(dict_t *context, struct p_node *p)
225 {
226 dict_t *i;
227 list_t *l;
228
229 /* ASSERT p->type==T_PATHELEM */
230 /* ASSERT p->l->type==T_KEY */
231 l=dict_ilookup(context, p->l->data.key);
232 if (!l) {
233 cfgfatal(p->loc,"conffile","can't find key %s\n",
234 p->l->data.key);
235 }
236
237 while (p->r) {
238 if (l->item->type != t_dict) {
239 cfgfatal(p->loc,"conffile","path element \"%s\" "
240 "is not a dictionary\n",p->l->data.key);
241 }
242 i=l->item->data.dict; /* First thing in list */
243
244 p=p->r;
245 l=dict_ilookup_primitive(i, p->l->data.key);
246 if (!l) {
247 cfgfatal(p->loc,"conffile","can't find key %s\n",
248 p->l->data.key);
249 }
250 }
251 return l;
252 }
253
254 static item_t *new_item(enum types type, struct cloc loc)
255 {
256 item_t *i;
257
258 i=safe_malloc(sizeof(*i),"new_item");
259 i->type=type;
260 i->loc=loc;
261 return i;
262 }
263
264 static list_t *process_item(dict_t *context, struct p_node *i)
265 {
266 item_t *item=NULL;
267
268 switch (i->type) {
269 case T_STRING:
270 item=new_item(t_string, i->loc);
271 item->data.string=i->data.string; /* XXX maybe strcpy */
272 break;
273 case T_NUMBER:
274 item=new_item(t_number, i->loc);
275 item->data.number=i->data.number;
276 break;
277 case T_ABSPATH:
278 context=dict_find_root(context);
279 /* falls through */
280 case T_RELPATH:
281 return dict_lookup_path(context, i->r);
282 /* returns immediately */
283 break;
284 case T_DICT:
285 item=new_item(t_dict, i->loc);
286 item->data.dict=dict_new(context);
287 /* XXX dict_add_searchpath(context,process_ilist(context, i->r)); */
288 process_alist(item->data.dict, i->l);
289 break;
290 case T_EXEC:
291 return process_invocation(context, i);
292 /* returns immediately */
293 break;
294 default:
295 #ifdef DUMP_PARSE_TREE
296 ptree_dump(i,0);
297 fatal("process_item: invalid node type for a list item (%s)\n",
298 ntype(i->type));
299 #else
300 fatal("process_item: list item has invalid node type %d - recompile "
301 "with DUMP_PARSE_TREE defined in conffile.c for more "
302 "detailed debug output",i->type);
303 #endif /* DUMP_PARSE_TREE */
304 break;
305 }
306 return list_append(NULL,item);
307 }
308
309 static list_t *process_ilist(dict_t *context, struct p_node *l)
310 {
311 struct p_node *i;
312 list_t *r;
313
314 /* ASSERT l->type==T_LISTITEM */
315
316 r=list_new();
317
318 for (i=l; i; i=i->r) {
319 r=list_append_list(r,process_item(context,i->l));
320 }
321 return r;
322 }
323
324 static list_t *process_invocation(dict_t *context, struct p_node *i)
325 {
326 list_t *cll;
327 item_t *cl;
328 list_t *args;
329
330 /* ASSERT i->type==T_EXEC */
331 /* ASSERT i->r->type==T_LISTITEM */
332 /* XXX it might be null too */
333 cll=process_item(context,i->l);
334 cl=cll->item;
335 if (cl->type != t_closure) {
336 cfgfatal(i->l->loc,"conffile","only closures can be invoked\n");
337 }
338 if (!cl->data.closure->apply) {
339 cfgfatal(i->l->loc,"conffile","this closure cannot be invoked\n");
340 }
341 args=process_ilist(context, i->r);
342 return cl->data.closure->apply(cl->data.closure, i->loc, context, args);
343 }
344
345 static void process_alist(dict_t *context, struct p_node *c)
346 {
347 struct p_node *i;
348 atom_t k;
349 list_t *l;
350
351 if (!c) return; /* NULL assignment lists are valid (empty dictionary) */
352
353 /* ASSERT c->type==T_ALIST */
354 if (c->type!=T_ALIST) {
355 fatal("invalid node type in assignment list\n");
356 }
357
358 for (i=c; i; i=i->r) {
359 /* ASSERT i->l && i->l->type==T_ASSIGNMENT */
360 /* ASSERT i->l->l->type==T_KEY */
361 /* ASSERT i->l->r->type==T_LISTITEM */
362 k=i->l->l->data.key;
363 l=process_ilist(context, i->l->r);
364 dict_iadd(context, k, l);
365 }
366 }
367
368 /* Take a list of items; turn any dictionaries in this list into lists */
369 static list_t *makelist(closure_t *self, struct cloc loc,
370 dict_t *context, list_t *args)
371 {
372 list_t *r=NULL, *i;
373 struct entry *e;
374
375 for (i=args; i; i=i->next) {
376 if (i->item->type==t_dict) {
377 /* Convert */
378 for (e=i->item->data.dict->entries; e; e=e->next) {
379 r=list_append_list(r, e->val);
380 }
381 } else {
382 r=list_append_list(r, list_append(NULL,i->item));
383 }
384 }
385 return r;
386 }
387
388 /* Take a list consisting of a closure and some other things. Apply the
389 closure to the other things, and return the resulting list */
390 static list_t *map(closure_t *self, struct cloc loc, dict_t *context,
391 list_t *args)
392 {
393 list_t *r=NULL, *al;
394 item_t *ci;
395 closure_t *cl;
396 list_t se;
397
398 ci=list_elem(args,0);
399 if (ci && ci->type==t_closure) {
400 cl=ci->data.closure;
401 if (!cl->apply) {
402 cfgfatal(loc,"map","closure cannot be applied\n");
403 }
404 for (al=args->next; al; al=al->next) {
405 /* Construct a single-element list */
406 se.next=NULL;
407 se.item=al->item;
408 /* Invoke the closure, append its result to the output */
409 r=list_append_list(r,cl->apply(cl,loc,context,&se));
410 }
411 } else {
412 cfgfatal(loc,"map","you must supply a closure as the "
413 "first argument\n");
414 }
415 return r;
416 }
417
418 /* Read a file and turn it into a string */
419 static list_t *readfile(closure_t *self, struct cloc loc,
420 dict_t *context, list_t *args)
421 {
422 FILE *f;
423 string_t filename;
424 long length;
425 item_t *r;
426
427 r=list_elem(args,0);
428 if (!r) {
429 cfgfatal(loc,"readfile","you must supply a filename\n");
430 }
431 if (r->type!=t_string) {
432 cfgfatal(loc,"readfile","filename must be a string\n");
433 }
434 filename=r->data.string;
435 f=fopen(filename,"rb");
436 if (!f) {
437 fatal_perror("readfile (%s:%d): cannot open file \"%s\"",
438 loc.file,loc.line, filename);
439 }
440 if (fseek(f, 0, SEEK_END)!=0) {
441 fatal_perror("readfile (%s:%d): fseek(SEEK_END)",loc.file,loc.line);
442 }
443 length=ftell(f);
444 if (length<0) {
445 fatal_perror("readfile (%s:%d): ftell()",loc.file,loc.line);
446 }
447 if (fseek(f, 0, SEEK_SET)!=0) {
448 fatal_perror("readfile (%s:%d): fseek(SEEK_SET)",loc.file,loc.line);
449 }
450 r=new_item(t_string,loc);
451 r->data.string=safe_malloc(length+1,"readfile");
452 if (fread(r->data.string,length,1,f)!=1) {
453 fatal("readfile (%s:%d): fread: could not read all of file\n",
454 loc.file,loc.line);
455 }
456 r->data.string[length]=0;
457 if (fclose(f)!=0) {
458 fatal_perror("readfile (%s:%d): fclose",loc.file,loc.line);
459 }
460 return list_append(NULL,r);
461 }
462
463 static dict_t *process_config(struct p_node *c)
464 {
465 dict_t *root;
466 dict_t *context;
467 item_t *i;
468 list_t *false;
469 list_t *true;
470
471 root=dict_new(NULL);
472 context=root;
473
474 /* Predefined keys for boolean values */
475 i=new_item(t_bool,no_loc);
476 i->data.bool=False;
477 false=list_append(NULL,i);
478 i=new_item(t_bool,no_loc);
479 i->data.bool=True;
480 true=list_append(NULL,i);
481 dict_add(root,"false",false);
482 dict_add(root,"False",false);
483 dict_add(root,"FALSE",false);
484 dict_add(root,"no",false);
485 dict_add(root,"No",false);
486 dict_add(root,"NO",false);
487 dict_add(root,"true",true);
488 dict_add(root,"True",true);
489 dict_add(root,"TRUE",true);
490 dict_add(root,"yes",true);
491 dict_add(root,"Yes",true);
492 dict_add(root,"YES",true);
493
494 add_closure(root,"makelist",makelist);
495 add_closure(root,"readfile",readfile);
496 add_closure(root,"map",map);
497
498 init_builtin_modules(root);
499
500 process_alist(context, c);
501
502 return root;
503 }
504
505 /***** Externally accessible functions */
506
507 atom_t intern(string_t s)
508 {
509 struct atomlist *i;
510
511 for (i=atoms; i; i=i->next) {
512 if (strcmp(i->a, s)==0) break;
513 }
514
515 if (!i) {
516 /* Did't find it; create a new one */
517 i=safe_malloc(sizeof(*i),"intern: alloc list entry");
518 i->a=safe_strdup(s,"intern: alloc string");
519 i->next=atoms;
520 atoms=i;
521 }
522 return i->a;
523 }
524
525 list_t *dict_lookup(dict_t *dict, string_t key)
526 {
527 return dict_ilookup(dict, intern(key));
528 }
529
530 list_t *dict_lookup_primitive(dict_t *dict, string_t key)
531 {
532 return dict_ilookup_primitive(dict, intern(key));
533 }
534
535 void dict_add(dict_t *dict, string_t key, list_t *val)
536 {
537 dict_iadd(dict,intern(key),val);
538 }
539
540 string_t *dict_keys(dict_t *dict)
541 {
542 atom_t *r, *j;
543 struct entry *i;
544 r=safe_malloc(sizeof(*r)*(dict->size+1),"dict_keys");
545 for (i=dict->entries, j=r; i; i=i->next, j++) {
546 *j=i->key;
547 }
548 *j=NULL;
549 return r;
550 }
551
552
553 /* List-related functions */
554
555 list_t *list_new(void)
556 {
557 return NULL;
558 }
559
560 uint32_t list_length(list_t *a)
561 {
562 uint32_t l=0;
563 list_t *i;
564 for (i=a; i; i=i->next) l++;
565 return l;
566 }
567
568 list_t *list_copy(list_t *a)
569 {
570 list_t *r, *i, *b, *l;
571
572 if (!a) return NULL;
573 l=NULL;
574 r=NULL;
575 for (i=a; i; i=i->next) {
576 b=safe_malloc(sizeof(*b),"list_copy");
577 if (l) l->next=b; else r=b;
578 l=b;
579 b->item=i->item;
580 b->next=NULL;
581 }
582 return r;
583 }
584
585 list_t *list_append_list(list_t *a, list_t *b)
586 {
587 list_t *i;
588
589 b=list_copy(b);
590 if (!a) return b;
591 for (i=a; i->next; i=i->next);
592 i->next=b;
593 return a;
594 }
595
596 list_t *list_append(list_t *list, item_t *item)
597 {
598 list_t *l;
599
600 l=safe_malloc(sizeof(*l),"list_append");
601 l->item=item;
602 l->next=NULL;
603
604 return list_append_list(list,l);
605 }
606
607 item_t *list_elem(list_t *l, uint32_t index)
608 {
609 if (!l) return NULL;
610 if (index==0) return l->item;
611 return list_elem(l->next, index-1);
612 }
613
614 list_t *new_closure(closure_t *cl)
615 {
616 item_t *i;
617
618 i=new_item(t_closure,no_loc);
619 i->data.closure=cl;
620 return list_append(NULL,i);
621 }
622
623 void add_closure(dict_t *dict, string_t name, apply_fn apply)
624 {
625 closure_t *c;
626 c=safe_malloc(sizeof(*c),"add_closure");
627 c->description=name;
628 c->apply=apply;
629 c->interface=NULL;
630
631 dict_add(dict,name,new_closure(c));
632 }
633
634 void *find_cl_if(dict_t *dict, string_t name, uint32_t type,
635 bool_t fail_if_invalid, string_t desc, struct cloc loc)
636 {
637 list_t *l;
638 item_t *i;
639 closure_t *cl;
640
641 l=dict_lookup(dict,name);
642 if (!l) {
643 if (!fail_if_invalid) return NULL;
644 cfgfatal(loc,desc,"closure \"%s\" not found\n",name);
645 }
646 i=list_elem(l,0);
647 if (i->type!=t_closure) {
648 if (!fail_if_invalid) return NULL;
649 cfgfatal(loc,desc,"\"%s\" must be a closure\n",name);
650 }
651 cl=i->data.closure;
652 if (cl->type!=type) {
653 if (!fail_if_invalid) return NULL;
654 cfgfatal(loc,desc,"\"%s\" is the wrong type of closure\n",name);
655 }
656 return cl->interface;
657 }
658
659 /* Convenience functions for modules reading configuration dictionaries */
660 item_t *dict_find_item(dict_t *dict, string_t key, bool_t required,
661 string_t desc, struct cloc loc)
662 {
663 list_t *l;
664 item_t *i;
665
666 l=dict_lookup(dict,key);
667 if (!l) {
668 if (!required) return NULL;
669 cfgfatal(loc,desc,"required parameter \"%s\" not found\n",key);
670 }
671 i=list_elem(l,0);
672 return i;
673 }
674
675 string_t dict_read_string(dict_t *dict, string_t key, bool_t required,
676 string_t desc, struct cloc loc)
677 {
678 item_t *i;
679 string_t r;
680
681 i=dict_find_item(dict,key,required,desc,loc);
682 if (!i) return NULL;
683 if (i->type!=t_string) {
684 cfgfatal(loc,desc,"\"%s\" must be a string\n",key);
685 }
686 r=i->data.string;
687 return r;
688 }
689
690 uint32_t dict_read_number(dict_t *dict, string_t key, bool_t required,
691 string_t desc, struct cloc loc, uint32_t def)
692 {
693 item_t *i;
694 uint32_t r;
695
696 i=dict_find_item(dict,key,required,desc,loc);
697 if (!i) return def;
698 if (i->type!=t_number) {
699 cfgfatal(loc,desc,"\"%s\" must be a number\n",key);
700 }
701 r=i->data.number;
702 return r;
703 }
704
705 bool_t dict_read_bool(dict_t *dict, string_t key, bool_t required,
706 string_t desc, struct cloc loc, bool_t def)
707 {
708 item_t *i;
709 bool_t r;
710
711 i=dict_find_item(dict,key,required,desc,loc);
712 if (!i) return def;
713 if (i->type!=t_bool) {
714 cfgfatal(loc,desc,"\"%s\" must be a boolean\n",key);
715 }
716 r=i->data.bool;
717 return r;
718 }
719
720 static struct subnet string_to_subnet(item_t *i, string_t desc)
721 {
722 struct subnet s;
723 uint32_t a, b, c, d, n;
724 uint32_t match;
725
726 /* i is not guaranteed to be a string */
727 if (i->type!=t_string) {
728 cfgfatal(i->loc,desc,"expecting a string (subnet specification)\n");
729 }
730
731 if (strcmp(i->data.string,"default")==0) {
732 s.prefix=0;
733 s.mask=0;
734 s.len=0;
735 return s;
736 }
737
738 /* We expect strings of the form "a.b.c.d[/n]", i.e. the dots are
739 NOT optional. The subnet mask is optional; if missing it is assumed
740 to be /32. */
741 match=sscanf(i->data.string,"%u.%u.%u.%u/%u", &a, &b, &c, &d, &n);
742 if (match<4) {
743 cfgfatal(i->loc,desc,"\"%s\" is not a valid "
744 "subnet specification\n",i->data.string);
745 }
746 if (match<5) {
747 n=32;
748 }
749 if (a>255 || b>255 || c>255 || d>255 || n>32) {
750 cfgfatal(i->loc,desc,"\"%s\": range error\n",i->data.string);
751 }
752 s.prefix=(a<<24)|(b<<16)|(c<<8)|(d);
753 s.mask=n?(~0UL << (32-n)):0;
754 s.len=n;
755 if (s.prefix & ~s.mask) {
756 cfgfatal(i->loc,desc,"\"%s\": prefix not fully contained "
757 "in mask\n",i->data.string);
758 }
759 return s;
760 }
761
762 uint32_t string_to_ipaddr(item_t *i, string_t desc)
763 {
764 uint32_t a, b, c, d;
765 uint32_t match;
766
767 /* i is not guaranteed to be a string */
768 if (i->type!=t_string) {
769 cfgfatal(i->loc,desc,"expecting a string (IP address)\n");
770 }
771
772 match=sscanf(i->data.string,"%u.%u.%u.%u", &a, &b, &c, &d);
773 if (match<4) {
774 cfgfatal(i->loc,desc,"\"%s\" is not a valid "
775 "IP address\n",i->data.string);
776 }
777 if (a>255 || b>255 || c>255 || d>255) {
778 cfgfatal(i->loc,desc,"\"%s\": range error\n",i->data.string);
779 }
780 return (a<<24)|(b<<16)|(c<<8)|(d);
781 }
782
783 void dict_read_subnet_list(dict_t *dict, string_t key, bool_t required,
784 string_t desc, struct cloc loc,
785 struct subnet_list *sl)
786 {
787 list_t *l, *li;
788 item_t *i;
789 uint32_t e=0;
790
791 sl->entries=0;
792 sl->list=NULL;
793 l=dict_lookup(dict, key);
794 if (!l) {
795 if (!required) return;
796 cfgfatal(loc,desc,"required parameter \"%s\" not found\n",key);
797 }
798 /* Count the items in the list */
799 e=list_length(l);
800 if (e==0) return;
801 sl->entries=e;
802 sl->list=safe_malloc(sizeof(struct subnet)*e, "dict_read_subnet_list");
803 e=0;
804 /* Fill in the list */
805 for (li=l; li; li=li->next) {
806 i=li->item;
807 if (i->type!=t_string) {
808 cfgfatal(loc,desc,"parameter \"%s\": all elements must "
809 "be strings\n",key);
810 }
811 sl->list[e++]=string_to_subnet(i,desc);
812 }
813 }
814
815 uint32_t string_to_word(string_t s, struct cloc loc,
816 struct flagstr *f, string_t desc)
817 {
818 struct flagstr *j;
819 for (j=f; j->name; j++)
820 if (strcmp(s,j->name)==0)
821 return j->value;
822 cfgfatal(loc,desc,"option \"%s\" not known\n",s);
823 return 0;
824 }
825
826 uint32_t string_list_to_word(list_t *l, struct flagstr *f, string_t desc)
827 {
828 list_t *i;
829 uint32_t r=0;
830 struct flagstr *j;
831
832 for (i=l; i; i=i->next) {
833 if (i->item->type!=t_string) {
834 cfgfatal(i->item->loc,desc,"all elements of list must be "
835 "strings\n");
836 }
837 for (j=f; j->name; j++)
838 r|=string_to_word(i->item->data.string,i->item->loc,f,desc);
839 }
840 return r;
841 }
842
843 dict_t *read_conffile(char *name)
844 {
845 FILE *conffile;
846 struct p_node *config;
847
848 if (strcmp(name,"-")==0) {
849 conffile=stdin;
850 } else {
851 conffile=fopen(name,"r");
852 if (!conffile)
853 fatal_perror("Cannot open configuration file \"%s\"",name);
854 }
855 config_lineno=1;
856 config_file=name;
857 config=parse_conffile(conffile);
858 fclose(conffile);
859
860 #ifdef DUMP_PARSE_TREE
861 printf("*** config file parse tree BEFORE MANGLE\n");
862 ptree_dump(config,0);
863 #endif /* DUMP_PARSE_TREE */
864 /* The root of the configuration is a T_ALIST, which needs reversing
865 before we mangle because it isn't the child of a T_DICT. */
866 config=list_reverse(config);
867 ptree_mangle(config);
868 #ifdef DUMP_PARSE_TREE
869 printf("\n\n*** config file parse tree AFTER MANGLE\n");
870 ptree_dump(config,0);
871 #endif /* DUMP_PARSE_TREE */
872 return process_config(config);
873 }