Annotation of embedaddon/bird/conf/cf-lex.l, revision 1.1.1.2
1.1 misho 1: /*
2: * BIRD -- Configuration Lexer
3: *
4: * (c) 1998--2000 Martin Mares <mj@ucw.cz>
5: *
6: * Can be freely distributed and used under the terms of the GNU GPL.
7: */
8:
9: /**
10: * DOC: Lexical analyzer
11: *
12: * The lexical analyzer used for configuration files and CLI commands
13: * is generated using the |flex| tool accompanied by a couple of
14: * functions maintaining the hash tables containing information about
15: * symbols and keywords.
16: *
17: * Each symbol is represented by a &symbol structure containing name
18: * of the symbol, its lexical scope, symbol class (%SYM_PROTO for a
19: * name of a protocol, %SYM_CONSTANT for a constant etc.) and class
20: * dependent data. When an unknown symbol is encountered, it's
21: * automatically added to the symbol table with class %SYM_VOID.
22: *
23: * The keyword tables are generated from the grammar templates
24: * using the |gen_keywords.m4| script.
25: */
26:
27: %{
28: #undef REJECT /* Avoid name clashes */
29:
30: #include <errno.h>
31: #include <stdlib.h>
32: #include <stdarg.h>
33: #include <stdint.h>
34: #include <unistd.h>
35: #include <libgen.h>
36: #include <glob.h>
37: #include <fcntl.h>
38: #include <sys/stat.h>
39: #include <sys/types.h>
40: #include <sys/stat.h>
41:
42: #define PARSER 1
43:
44: #include "nest/bird.h"
45: #include "nest/route.h"
46: #include "nest/protocol.h"
47: #include "filter/filter.h"
48: #include "conf/conf.h"
49: #include "conf/cf-parse.tab.h"
50: #include "lib/string.h"
1.1.1.2 ! misho 51: #include "lib/hash.h"
1.1 misho 52:
53: struct keyword {
54: byte *name;
55: int value;
56: struct keyword *next;
57: };
58:
59: #include "conf/keywords.h"
60:
1.1.1.2 ! misho 61: /* Could be defined by Bison in cf-parse.tab.h, inteferes with SYM hash */
! 62: #ifdef SYM
! 63: #undef SYM
! 64: #endif
! 65:
! 66:
! 67: static uint cf_hash(byte *c);
! 68:
! 69: #define KW_KEY(n) n->name
! 70: #define KW_NEXT(n) n->next
! 71: #define KW_EQ(a,b) !strcmp(a,b)
! 72: #define KW_FN(k) cf_hash(k)
! 73: #define KW_ORDER 8 /* Fixed */
! 74:
! 75: #define SYM_KEY(n) n->name, n->scope->active
! 76: #define SYM_NEXT(n) n->next
! 77: #define SYM_EQ(a,s1,b,s2) !strcmp(a,b) && s1 == s2
! 78: #define SYM_FN(k,s) cf_hash(k)
! 79: #define SYM_ORDER 6 /* Initial */
1.1 misho 80:
1.1.1.2 ! misho 81: #define SYM_REHASH sym_rehash
! 82: #define SYM_PARAMS /8, *1, 2, 2, 6, 20
! 83:
! 84:
! 85: HASH_DEFINE_REHASH_FN(SYM, struct symbol)
! 86:
! 87: HASH(struct keyword) kw_hash;
! 88:
! 89:
! 90: static struct sym_scope *conf_this_scope;
1.1 misho 91:
92: linpool *cfg_mem;
93:
94: int (*cf_read_hook)(byte *buf, unsigned int max, int fd);
95: struct include_file_stack *ifs;
96: static struct include_file_stack *ifs_head;
97:
98: #define MAX_INCLUDE_DEPTH 8
99:
100: #define YY_INPUT(buf,result,max) result = cf_read_hook(buf, max, ifs->fd);
101: #define YY_NO_UNPUT
102: #define YY_FATAL_ERROR(msg) cf_error(msg)
1.1.1.2 ! misho 103: #define YY_USER_ACTION ifs->chno += yyleng; ifs->toklen = yyleng;
1.1 misho 104:
105: static void cf_include(char *arg, int alen);
106: static int check_eof(void);
107:
108: %}
109:
110: %option noyywrap
111: %option noinput
112: %option nounput
113: %option noreject
114:
115: %x COMMENT CCOMM CLI
116:
117: ALPHA [a-zA-Z_]
118: DIGIT [0-9]
119: XIGIT [0-9a-fA-F]
120: ALNUM [a-zA-Z_0-9]
121: WHITE [ \t]
122: include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*;
123:
124: %%
125: {include} {
126: char *start, *end;
127:
128: if (!ifs->depth)
129: cf_error("Include not allowed in CLI");
130:
131: start = strchr(yytext, '"');
132: start++;
133:
134: end = strchr(start, '"');
135: *end = 0;
136:
137: if (start == end)
138: cf_error("Include with empty argument");
139:
140: cf_include(start, end-start);
141: }
142:
143: {DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+ {
144: ip4_addr a;
145: if (!ip4_pton(yytext, &a))
146: cf_error("Invalid IPv4 address %s", yytext);
147:
148: #ifdef IPV6
149: cf_lval.i32 = ip4_to_u32(a);
150: return RTRID;
151: #else
152: cf_lval.a = ipa_from_ip4(a);
153: return IPA;
154: #endif
155: }
156:
157: ({XIGIT}*::|({XIGIT}*:){3,})({XIGIT}*|{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+) {
158: #ifdef IPV6
159: if (ipa_pton(yytext, &cf_lval.a))
160: return IPA;
161: cf_error("Invalid IPv6 address %s", yytext);
162: #else
163: cf_error("This is an IPv4 router, therefore IPv6 addresses are not supported");
164: #endif
165: }
166:
167: 0x{XIGIT}+ {
168: char *e;
169: unsigned long int l;
170: errno = 0;
171: l = strtoul(yytext+2, &e, 16);
172: if (e && *e || errno == ERANGE || (unsigned long int)(unsigned int) l != l)
173: cf_error("Number out of range");
174: cf_lval.i = l;
175: return NUM;
176: }
177:
178: {DIGIT}+ {
179: char *e;
180: unsigned long int l;
181: errno = 0;
182: l = strtoul(yytext, &e, 10);
183: if (e && *e || errno == ERANGE || (unsigned long int)(unsigned int) l != l)
184: cf_error("Number out of range");
185: cf_lval.i = l;
186: return NUM;
187: }
188:
189: else: {
190: /* Hack to distinguish if..else from else: in case */
191: return ELSECOL;
192: }
193:
194: ({ALPHA}{ALNUM}*|[']({ALNUM}|[-]|[\.]|[:])*[']) {
195: if(*yytext == '\'') {
196: yytext[yyleng-1] = 0;
197: yytext++;
198: }
1.1.1.2 ! misho 199:
! 200: struct keyword *k = HASH_FIND(kw_hash, KW, yytext);
! 201: if (k)
! 202: {
! 203: if (k->value > 0)
! 204: return k->value;
! 205: else
1.1 misho 206: {
1.1.1.2 ! misho 207: cf_lval.i = -k->value;
! 208: return ENUM;
1.1 misho 209: }
1.1.1.2 ! misho 210: }
! 211:
! 212: cf_lval.s = cf_get_symbol(yytext);
1.1 misho 213: return SYM;
214: }
215:
216: <CLI>(.|\n) {
217: BEGIN(INITIAL);
218: return CLI_MARKER;
219: }
220:
221: \.\. {
222: return DDOT;
223: }
224:
225: [={}:;,.()+*/%<>~\[\]?!\|-] {
226: return yytext[0];
227: }
228:
229: ["][^"\n]*["] {
230: yytext[yyleng-1] = 0;
231: cf_lval.t = cfg_strdup(yytext+1);
232: return TEXT;
233: }
234:
235: ["][^"\n]*\n cf_error("Unterminated string");
236:
237: <INITIAL,COMMENT><<EOF>> { if (check_eof()) return END; }
238:
239: {WHITE}+
240:
1.1.1.2 ! misho 241: \n ifs->lino++; ifs->chno = 0;
1.1 misho 242:
243: # BEGIN(COMMENT);
244:
245: \/\* BEGIN(CCOMM);
246:
247: . cf_error("Unknown character");
248:
249: <COMMENT>\n {
250: ifs->lino++;
1.1.1.2 ! misho 251: ifs->chno = 0;
1.1 misho 252: BEGIN(INITIAL);
253: }
254:
255: <COMMENT>.
256:
257: <CCOMM>\*\/ BEGIN(INITIAL);
1.1.1.2 ! misho 258: <CCOMM>\n ifs->lino++; ifs->chno = 0;
1.1 misho 259: <CCOMM>\/\* cf_error("Comment nesting not supported");
260: <CCOMM><<EOF>> cf_error("Unterminated comment");
261: <CCOMM>.
262:
263: \!\= return NEQ;
264: \!\~ return NMA;
265: \<\= return LEQ;
266: \>\= return GEQ;
267: \&\& return AND;
268: \|\| return OR;
269:
270: \[\= return PO;
271: \=\] return PC;
272:
273: %%
274:
1.1.1.2 ! misho 275: static uint
1.1 misho 276: cf_hash(byte *c)
277: {
1.1.1.2 ! misho 278: uint h = 13 << 24;
1.1 misho 279:
280: while (*c)
1.1.1.2 ! misho 281: h = h + (h >> 2) + (h >> 5) + ((uint) *c++ << 24);
1.1 misho 282: return h;
283: }
284:
285:
286: /*
287: * IFS stack - it contains structures needed for recursive processing
288: * of include in config files. On the top of the stack is a structure
289: * for currently processed file. Other structures are either for
290: * active files interrupted because of include directive (these have
291: * fd and flex buffer) or for inactive files scheduled to be processed
292: * later (when parent requested including of several files by wildcard
293: * match - these do not have fd and flex buffer yet).
294: *
295: * FIXME: Most of these ifs and include functions are really sysdep/unix.
296: */
297:
298: static struct include_file_stack *
299: push_ifs(struct include_file_stack *old)
300: {
301: struct include_file_stack *ret;
302: ret = cfg_allocz(sizeof(struct include_file_stack));
303: ret->lino = 1;
304: ret->prev = old;
305: return ret;
306: }
307:
308: static struct include_file_stack *
309: pop_ifs(struct include_file_stack *old)
310: {
311: yy_delete_buffer(old->buffer);
312: close(old->fd);
313: return old->prev;
314: }
315:
316: static void
317: enter_ifs(struct include_file_stack *new)
318: {
319: if (!new->buffer)
320: {
321: new->fd = open(new->file_name, O_RDONLY);
322: if (new->fd < 0)
323: {
324: ifs = ifs->up;
325: cf_error("Unable to open included file %s: %m", new->file_name);
326: }
327:
328: new->buffer = yy_create_buffer(NULL, YY_BUF_SIZE);
329: }
330:
331: yy_switch_to_buffer(new->buffer);
332: }
333:
334: /**
335: * cf_lex_unwind - unwind lexer state during error
336: *
337: * cf_lex_unwind() frees the internal state on IFS stack when the lexical
338: * analyzer is terminated by cf_error().
339: */
340: void
341: cf_lex_unwind(void)
342: {
343: struct include_file_stack *n;
344:
345: for (n = ifs; n != ifs_head; n = n->prev)
346: {
347: /* Memory is freed automatically */
348: if (n->buffer)
349: yy_delete_buffer(n->buffer);
350: if (n->fd)
351: close(n->fd);
352: }
353:
354: ifs = ifs_head;
355: }
356:
357: static void
358: cf_include(char *arg, int alen)
359: {
360: struct include_file_stack *base_ifs = ifs;
361: int new_depth, rv, i;
362: char *patt;
363: glob_t g = {};
364:
365: new_depth = ifs->depth + 1;
366: if (new_depth > MAX_INCLUDE_DEPTH)
367: cf_error("Max include depth reached");
368:
369: /* expand arg to properly handle relative filenames */
370: if (*arg != '/')
371: {
372: int dlen = strlen(ifs->file_name);
373: char *dir = alloca(dlen + 1);
374: patt = alloca(dlen + alen + 2);
375: memcpy(dir, ifs->file_name, dlen + 1);
376: sprintf(patt, "%s/%s", dirname(dir), arg);
377: }
378: else
379: patt = arg;
380:
381: /* Skip globbing if there are no wildcards, mainly to get proper
382: response when the included config file is missing */
383: if (!strpbrk(arg, "?*["))
384: {
385: ifs = push_ifs(ifs);
386: ifs->file_name = cfg_strdup(patt);
387: ifs->depth = new_depth;
388: ifs->up = base_ifs;
389: enter_ifs(ifs);
390: return;
391: }
392:
393: /* Expand the pattern */
394: rv = glob(patt, GLOB_ERR | GLOB_NOESCAPE, NULL, &g);
395: if (rv == GLOB_ABORTED)
396: cf_error("Unable to match pattern %s: %m", patt);
397: if ((rv != 0) || (g.gl_pathc <= 0))
398: return;
399:
400: /*
401: * Now we put all found files to ifs stack in reverse order, they
402: * will be activated and processed in order as ifs stack is popped
403: * by pop_ifs() and enter_ifs() in check_eof().
404: */
405: for(i = g.gl_pathc - 1; i >= 0; i--)
406: {
407: char *fname = g.gl_pathv[i];
408: struct stat fs;
409:
410: if (stat(fname, &fs) < 0)
411: {
412: globfree(&g);
413: cf_error("Unable to stat included file %s: %m", fname);
414: }
415:
416: if (fs.st_mode & S_IFDIR)
417: continue;
418:
419: /* Prepare new stack item */
420: ifs = push_ifs(ifs);
421: ifs->file_name = cfg_strdup(fname);
422: ifs->depth = new_depth;
423: ifs->up = base_ifs;
424: }
425:
426: globfree(&g);
427: enter_ifs(ifs);
428: }
429:
430: static int
431: check_eof(void)
432: {
433: if (ifs == ifs_head)
434: {
435: /* EOF in main config file */
436: ifs->lino = 1; /* Why this? */
437: return 1;
438: }
439:
440: ifs = pop_ifs(ifs);
441: enter_ifs(ifs);
442: return 0;
443: }
444:
445: static struct symbol *
1.1.1.2 ! misho 446: cf_new_symbol(byte *c)
1.1 misho 447: {
1.1.1.2 ! misho 448: struct symbol *s;
! 449:
! 450: uint l = strlen(c);
1.1 misho 451: if (l > SYM_MAX_LEN)
452: cf_error("Symbol too long");
1.1.1.2 ! misho 453:
1.1 misho 454: s = cfg_alloc(sizeof(struct symbol) + l);
455: s->scope = conf_this_scope;
456: s->class = SYM_VOID;
457: s->def = NULL;
458: s->aux = 0;
459: strcpy(s->name, c);
460:
1.1.1.2 ! misho 461: if (!new_config->sym_hash.data)
! 462: HASH_INIT(new_config->sym_hash, new_config->pool, SYM_ORDER);
1.1 misho 463:
1.1.1.2 ! misho 464: HASH_INSERT2(new_config->sym_hash, SYM, new_config->pool, s);
1.1 misho 465:
1.1.1.2 ! misho 466: return s;
1.1 misho 467: }
468:
469: /**
470: * cf_find_symbol - find a symbol by name
471: * @cfg: specificed config
472: * @c: symbol name
473: *
474: * This functions searches the symbol table in the config @cfg for a symbol of
475: * given name. First it examines the current scope, then the second recent one
476: * and so on until it either finds the symbol and returns a pointer to its
477: * &symbol structure or reaches the end of the scope chain and returns %NULL to
478: * signify no match.
479: */
480: struct symbol *
481: cf_find_symbol(struct config *cfg, byte *c)
482: {
1.1.1.2 ! misho 483: struct symbol *s;
! 484:
! 485: if (cfg->sym_hash.data &&
! 486: (s = HASH_FIND(cfg->sym_hash, SYM, c, 1)))
! 487: return s;
! 488:
! 489: if (cfg->fallback &&
! 490: cfg->fallback->sym_hash.data &&
! 491: (s = HASH_FIND(cfg->fallback->sym_hash, SYM, c, 1)))
! 492: return s;
! 493:
! 494: return NULL;
1.1 misho 495: }
496:
497: /**
498: * cf_get_symbol - get a symbol by name
499: * @c: symbol name
500: *
501: * This functions searches the symbol table of the currently parsed config
502: * (@new_config) for a symbol of given name. It returns either the already
503: * existing symbol or a newly allocated undefined (%SYM_VOID) symbol if no
504: * existing symbol is found.
505: */
506: struct symbol *
507: cf_get_symbol(byte *c)
508: {
1.1.1.2 ! misho 509: return cf_find_symbol(new_config, c) ?: cf_new_symbol(c);
1.1 misho 510: }
511:
512: struct symbol *
513: cf_default_name(char *template, int *counter)
514: {
515: char buf[SYM_MAX_LEN];
516: struct symbol *s;
517: char *perc = strchr(template, '%');
518:
519: for(;;)
520: {
521: bsprintf(buf, template, ++(*counter));
1.1.1.2 ! misho 522: s = cf_get_symbol(buf);
1.1 misho 523: if (s->class == SYM_VOID)
524: return s;
525: if (!perc)
526: break;
527: }
528: cf_error("Unable to generate default name");
529: }
530:
531: /**
532: * cf_define_symbol - define meaning of a symbol
533: * @sym: symbol to be defined
534: * @type: symbol class to assign
535: * @def: class dependent data
536: *
537: * Defines new meaning of a symbol. If the symbol is an undefined
538: * one (%SYM_VOID), it's just re-defined to the new type. If it's defined
539: * in different scope, a new symbol in current scope is created and the
540: * meaning is assigned to it. If it's already defined in the current scope,
541: * an error is reported via cf_error().
542: *
543: * Result: Pointer to the newly defined symbol. If we are in the top-level
544: * scope, it's the same @sym as passed to the function.
545: */
546: struct symbol *
547: cf_define_symbol(struct symbol *sym, int type, void *def)
548: {
549: if (sym->class)
550: {
551: if (sym->scope == conf_this_scope)
552: cf_error("Symbol already defined");
1.1.1.2 ! misho 553: sym = cf_new_symbol(sym->name);
1.1 misho 554: }
555: sym->class = type;
556: sym->def = def;
557: return sym;
558: }
559:
560: static void
561: cf_lex_init_kh(void)
562: {
1.1.1.2 ! misho 563: HASH_INIT(kw_hash, &root_pool, KW_ORDER);
1.1 misho 564:
1.1.1.2 ! misho 565: struct keyword *k;
! 566: for (k=keyword_list; k->name; k++)
! 567: HASH_INSERT(kw_hash, KW, k);
1.1 misho 568: }
569:
570: /**
571: * cf_lex_init - initialize the lexer
572: * @is_cli: true if we're going to parse CLI command, false for configuration
573: * @c: configuration structure
574: *
575: * cf_lex_init() initializes the lexical analyzer and prepares it for
576: * parsing of a new input.
577: */
578: void
579: cf_lex_init(int is_cli, struct config *c)
580: {
1.1.1.2 ! misho 581: if (!kw_hash.data)
1.1 misho 582: cf_lex_init_kh();
583:
584: ifs_head = ifs = push_ifs(NULL);
585: if (!is_cli)
586: {
587: ifs->file_name = c->file_name;
588: ifs->fd = c->file_fd;
589: ifs->depth = 1;
590: }
591:
592: yyrestart(NULL);
593: ifs->buffer = YY_CURRENT_BUFFER;
594:
595: if (is_cli)
596: BEGIN(CLI);
597: else
598: BEGIN(INITIAL);
599:
600: conf_this_scope = cfg_allocz(sizeof(struct sym_scope));
601: conf_this_scope->active = 1;
602: }
603:
604: /**
605: * cf_push_scope - enter new scope
606: * @sym: symbol representing scope name
607: *
608: * If we want to enter a new scope to process declarations inside
609: * a nested block, we can just call cf_push_scope() to push a new
610: * scope onto the scope stack which will cause all new symbols to be
611: * defined in this scope and all existing symbols to be sought for
612: * in all scopes stored on the stack.
613: */
614: void
615: cf_push_scope(struct symbol *sym)
616: {
617: struct sym_scope *s = cfg_alloc(sizeof(struct sym_scope));
618:
619: s->next = conf_this_scope;
620: conf_this_scope = s;
621: s->active = 1;
622: s->name = sym;
623: }
624:
625: /**
626: * cf_pop_scope - leave a scope
627: *
628: * cf_pop_scope() pops the topmost scope from the scope stack,
629: * leaving all its symbols in the symbol table, but making them
630: * invisible to the rest of the config.
631: */
632: void
633: cf_pop_scope(void)
634: {
635: conf_this_scope->active = 0;
636: conf_this_scope = conf_this_scope->next;
637: ASSERT(conf_this_scope);
638: }
639:
640: /**
641: * cf_symbol_class_name - get name of a symbol class
642: * @sym: symbol
643: *
644: * This function returns a string representing the class
645: * of the given symbol.
646: */
647: char *
648: cf_symbol_class_name(struct symbol *sym)
649: {
650: if (cf_symbol_is_constant(sym))
651: return "constant";
652:
653: switch (sym->class)
654: {
655: case SYM_VOID:
656: return "undefined";
657: case SYM_PROTO:
658: return "protocol";
659: case SYM_TEMPLATE:
660: return "protocol template";
661: case SYM_FUNCTION:
662: return "function";
663: case SYM_FILTER:
664: return "filter";
665: case SYM_TABLE:
666: return "routing table";
667: case SYM_ROA:
668: return "ROA table";
669: default:
670: return "unknown type";
671: }
672: }
673:
674:
675: /**
676: * DOC: Parser
677: *
678: * Both the configuration and CLI commands are analyzed using a syntax
679: * driven parser generated by the |bison| tool from a grammar which
680: * is constructed from information gathered from grammar snippets by
681: * the |gen_parser.m4| script.
682: *
683: * Grammar snippets are files (usually with extension |.Y|) contributed
684: * by various BIRD modules in order to provide information about syntax of their
685: * configuration and their CLI commands. Each snipped consists of several
686: * sections, each of them starting with a special keyword: |CF_HDR| for
687: * a list of |#include| directives needed by the C code, |CF_DEFINES|
688: * for a list of C declarations, |CF_DECLS| for |bison| declarations
689: * including keyword definitions specified as |CF_KEYWORDS|, |CF_GRAMMAR|
690: * for the grammar rules, |CF_CODE| for auxiliary C code and finally
691: * |CF_END| at the end of the snippet.
692: *
693: * To create references between the snippets, it's possible to define
694: * multi-part rules by utilizing the |CF_ADDTO| macro which adds a new
695: * alternative to a multi-part rule.
696: *
697: * CLI commands are defined using a |CF_CLI| macro. Its parameters are:
698: * the list of keywords determining the command, the list of parameters,
699: * help text for the parameters and help text for the command.
700: *
701: * Values of |enum| filter types can be defined using |CF_ENUM| with
702: * the following parameters: name of filter type, prefix common for all
703: * literals of this type and names of all the possible values.
704: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>