X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=secnet.git;a=blobdiff_plain;f=conffile.c;h=9c373c2cacc524d3304b26b554317f41656139ab;hp=746b6546bd47e39d2dfc1531946067851290e936;hb=ff05a229397c75142725f45cad191ce4a00625ce;hpb=2fe58dfd10216a37f1ece081f926971882de112e diff --git a/conffile.c b/conffile.c index 746b654..9c373c2 100644 --- a/conffile.c +++ b/conffile.c @@ -1,20 +1,17 @@ -/* - * $Log$ - */ - /* conffile.c - process the configuration file */ /* #define DUMP_PARSE_TREE */ +#include "secnet.h" #include -#include #include - -#include "secnet.h" #include "conffile.h" #include "conffile_internal.h" #include "util.h" -#include "modules.h" +#include "ipaddr.h" + +/* from modules.c */ +extern void init_builtin_modules(dict_t *dict); static struct cloc no_loc={"none",0}; @@ -75,8 +72,6 @@ static list_t *dict_ilookup(dict_t *dict, atom_t key) static void dict_iadd(dict_t *dict, atom_t key, list_t *val) { struct entry *e; - /* XXX May want to permit redefinition of keys in the future */ - /* (although it could be very confusing) */ if (dict_ilookup_primitive(dict, key)) { fatal("duplicate key \"%s\" in dictionary\n",key); } @@ -334,6 +329,9 @@ static list_t *process_invocation(dict_t *context, struct p_node *i) if (cl->type != t_closure) { cfgfatal(i->l->loc,"conffile","only closures can be invoked\n"); } + if (!cl->data.closure->apply) { + cfgfatal(i->l->loc,"conffile","this closure cannot be invoked\n"); + } args=process_ilist(context, i->r); return cl->data.closure->apply(cl->data.closure, i->loc, context, args); } @@ -381,6 +379,36 @@ static list_t *makelist(closure_t *self, struct cloc loc, return r; } +/* Take a list consisting of a closure and some other things. Apply the + closure to the other things, and return the resulting list */ +static list_t *map(closure_t *self, struct cloc loc, dict_t *context, + list_t *args) +{ + list_t *r=NULL, *al; + item_t *ci; + closure_t *cl; + list_t se; + + ci=list_elem(args,0); + if (ci && ci->type==t_closure) { + cl=ci->data.closure; + if (!cl->apply) { + cfgfatal(loc,"map","closure cannot be applied\n"); + } + for (al=args->next; al; al=al->next) { + /* Construct a single-element list */ + se.next=NULL; + se.item=al->item; + /* Invoke the closure, append its result to the output */ + r=list_append_list(r,cl->apply(cl,loc,context,&se)); + } + } else { + cfgfatal(loc,"map","you must supply a closure as the " + "first argument\n"); + } + return r; +} + /* Read a file and turn it into a string */ static list_t *readfile(closure_t *self, struct cloc loc, dict_t *context, list_t *args) @@ -459,6 +487,7 @@ static dict_t *process_config(struct p_node *c) add_closure(root,"makelist",makelist); add_closure(root,"readfile",readfile); + add_closure(root,"map",map); init_builtin_modules(root); @@ -522,10 +551,36 @@ list_t *list_new(void) return NULL; } +uint32_t list_length(list_t *a) +{ + uint32_t l=0; + list_t *i; + for (i=a; i; i=i->next) l++; + return l; +} + +list_t *list_copy(list_t *a) +{ + list_t *r, *i, *b, *l; + + if (!a) return NULL; + l=NULL; + r=NULL; + for (i=a; i; i=i->next) { + b=safe_malloc(sizeof(*b),"list_copy"); + if (l) l->next=b; else r=b; + l=b; + b->item=i->item; + b->next=NULL; + } + return r; +} + list_t *list_append_list(list_t *a, list_t *b) { list_t *i; + b=list_copy(b); if (!a) return b; for (i=a; i->next; i=i->next); i->next=b; @@ -656,91 +711,32 @@ bool_t dict_read_bool(dict_t *dict, string_t key, bool_t required, return r; } -static struct subnet string_to_subnet(item_t *i, string_t desc) +uint32_t string_to_word(string_t s, struct cloc loc, + struct flagstr *f, string_t desc) { - struct subnet s; - uint32_t a, b, c, d, n; - uint32_t match; - - /* i is not guaranteed to be a string */ - if (i->type!=t_string) { - cfgfatal(i->loc,desc,"expecting a string (subnet specification)\n"); - } - - /* We expect strings of the form "a.b.c.d[/n]", i.e. the dots are - NOT optional. The subnet mask is optional; if missing it is assumed - to be /32. */ - match=sscanf(i->data.string,"%u.%u.%u.%u/%u", &a, &b, &c, &d, &n); - if (match<4) { - cfgfatal(i->loc,desc,"\"%s\" is not a valid " - "subnet specification\n",i->data.string); - } - if (match<5) { - n=32; - } - if (a>255 || b>255 || c>255 || d>255 || n>32) { - cfgfatal(i->loc,desc,"\"%s\": range error\n",i->data.string); - } - s.prefix=(a<<24)|(b<<16)|(c<<8)|(d); - s.mask=(~0UL << (32-n)); - if (s.prefix & ~s.mask) { - cfgfatal(i->loc,desc,"\"%s\": prefix not fully contained " - "in mask\n",i->data.string); - } - return s; + struct flagstr *j; + for (j=f; j->name; j++) + if (strcmp(s,j->name)==0) + return j->value; + cfgfatal(loc,desc,"option \"%s\" not known\n",s); + return 0; } -uint32_t string_to_ipaddr(item_t *i, string_t desc) +uint32_t string_list_to_word(list_t *l, struct flagstr *f, string_t desc) { - uint32_t a, b, c, d; - uint32_t match; - - /* i is not guaranteed to be a string */ - if (i->type!=t_string) { - cfgfatal(i->loc,desc,"expecting a string (IP address)\n"); - } - - match=sscanf(i->data.string,"%u.%u.%u.%u", &a, &b, &c, &d); - if (match<4) { - cfgfatal(i->loc,desc,"\"%s\" is not a valid " - "IP address\n",i->data.string); - } - if (a>255 || b>255 || c>255 || d>255) { - cfgfatal(i->loc,desc,"\"%s\": range error\n",i->data.string); - } - return (a<<24)|(b<<16)|(c<<8)|(d); -} - -void dict_read_subnet_list(dict_t *dict, string_t key, bool_t required, - string_t desc, struct cloc loc, - struct subnet_list *sl) -{ - list_t *l, *li; - item_t *i; - uint32_t e=0; + list_t *i; + uint32_t r=0; + struct flagstr *j; - sl->entries=0; - sl->list=NULL; - l=dict_lookup(dict, key); - if (!l) { - if (!required) return; - cfgfatal(loc,desc,"required parameter \"%s\" not found\n",key); - } - /* Count the items in the list */ - for (li=l; li; li=li->next) e++; - if (e==0) return; - sl->entries=e; - sl->list=safe_malloc(sizeof(struct subnet)*e, "dict_read_subnet_list"); - e=0; - /* Fill in the list */ - for (li=l; li; li=li->next) { - i=li->item; - if (i->type!=t_string) { - cfgfatal(loc,desc,"parameter \"%s\": all elements must " - "be strings\n",key); + for (i=l; i; i=i->next) { + if (i->item->type!=t_string) { + cfgfatal(i->item->loc,desc,"all elements of list must be " + "strings\n"); } - sl->list[e++]=string_to_subnet(i,desc); + for (j=f; j->name; j++) + r|=string_to_word(i->item->data.string,i->item->loc,f,desc); } + return r; } dict_t *read_conffile(char *name)