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