Commit 48ec367a authored by Ondrej Filip's avatar Ondrej Filip
Browse files

Configuration can include other files.

parent a9899527
Loading
Loading
Loading
Loading
+80 −9
Original line number Diff line number Diff line
@@ -63,19 +63,27 @@ struct sym_scope {
};
static struct sym_scope *conf_this_scope;

int conf_lino;
#define MAX_INCLUDE_DEPTH 5

static struct include_file_stack *ifs_head;
static int ifs_depth;

static int cf_hash(byte *c);
static struct symbol *cf_find_sym(byte *c, unsigned int h0);

linpool *cfg_mem;

int (*cf_read_hook)(byte *buf, unsigned int max);
int (*cf_read_hook)(byte *buf, unsigned int max, int fd);
int (*cf_open_hook)(char *filename);

#define YY_INPUT(buf,result,max) result = cf_read_hook(buf, max);
#define YY_INPUT(buf,result,max) result = cf_read_hook(buf, max, ifs->conf_fd);
#define YY_NO_UNPUT
#define YY_FATAL_ERROR(msg) cf_error(msg)

static void new_include(void);
static int check_eof(void);
static struct include_file_stack *new_stack(struct include_file_stack *old);

%}

%option noyywrap
@@ -90,8 +98,10 @@ DIGIT [0-9]
XIGIT [0-9a-fA-F]
ALNUM [a-zA-Z_0-9]
WHITE [ \t]
include   ^{WHITE}*include{WHITE}*\".*\"{WHITE}*;

%%
{include} { if(cf_open_hook) new_include(); }

{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+ {
#ifdef IPV6
@@ -188,11 +198,11 @@ else: {

["][^"\n]*\n	cf_error("Unterminated string");

<INITIAL,COMMENT><<EOF>>	return END;
<INITIAL,COMMENT><<EOF>>	{ if(check_eof()) return END; }

{WHITE}+

\n	conf_lino++;
\n	ifs->conf_lino++;

#	BEGIN(COMMENT);

@@ -201,14 +211,14 @@ else: {
.	cf_error("Unknown character");

<COMMENT>\n {
  conf_lino++;
  ifs->conf_lino++;
  BEGIN(INITIAL);
}

<COMMENT>.

<CCOMM>\*\/	BEGIN(INITIAL);
<CCOMM>\n	conf_lino++;
<CCOMM>\n	ifs->conf_lino++;
<CCOMM>\/\*	cf_error("Comment nesting not supported");
<CCOMM><<EOF>>	cf_error("Unterminated comment");
<CCOMM>.
@@ -234,6 +244,50 @@ cf_hash(byte *c)
  return h;
}

/* Open included file with properly swapped buffers */
static void
new_include(void)
{
  char *fname, *p = NULL;

  if ((fname = strchr(yytext, '"')) != NULL) {

    if ((p = strchr(++fname, '"')) != NULL) *p = '\0';

    if (ifs_depth >= MAX_INCLUDE_DEPTH)
      cf_error("Max include depth reached.");

    /* Save current stack */
    ifs->stack = YY_CURRENT_BUFFER;
    /* Prepare new stack */
    ifs->next = new_stack(ifs);
    ifs = ifs->next;
    strcpy(ifs->conf_fname, fname); /* XXX: strlcpy should be here */
    ifs->conf_fd = cf_open_hook(fname);

    yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
  }
}

static int
check_eof(void)
{
	if (ifs == ifs_head) {
		/* EOF in main config file */
		ifs->conf_lino = 1;
		return 1;
	}

	ifs_depth--;
	close(ifs->conf_fd);
	ifs = ifs->prev;
	ifs->next = NULL;
	
	yy_delete_buffer(YY_CURRENT_BUFFER);
	yy_switch_to_buffer(ifs->stack);
	return 0;
}

static struct symbol *
cf_new_sym(byte *c, unsigned int h)
{
@@ -359,6 +413,16 @@ cf_lex_init_kh(void)
  kw_hash_inited = 1;
}

static struct include_file_stack *
new_stack(struct include_file_stack *old)
{
  struct include_file_stack *ret;
  ret = cfg_allocz(sizeof(struct include_file_stack));
  ret->conf_lino = 1;
  ret->prev = old;
  return ret;
}

/**
 * cf_lex_init - initialize the lexer
 * @is_cli: true if we're going to parse CLI command, false for configuration
@@ -367,11 +431,18 @@ cf_lex_init_kh(void)
 * parsing of a new input.
 */
void
cf_lex_init(int is_cli)
cf_lex_init(int is_cli, struct config *c)
{
  if (!kw_hash_inited)
    cf_lex_init_kh();
  conf_lino = 1;
  ifs_head = new_stack(NULL);
  ifs = ifs_head;
  ifs_depth = 0;
  if (!is_cli) {
    ifs->conf_fd = c->file_fd;
    ifs_depth = 1;
    strcpy(ifs->conf_fname, c->file_name);
  }
  yyrestart(NULL);
  if (is_cli)
    BEGIN(CLI);
+4 −3
Original line number Diff line number Diff line
@@ -108,7 +108,7 @@ config_parse(struct config *c)
  cfg_mem = c->mem;
  if (setjmp(conf_jmpbuf))
    return 0;
  cf_lex_init(0);
  cf_lex_init(0, c);
  sysdep_preconfig(c);
  protos_preconfig(c);
  rt_preconfig(c);
@@ -138,7 +138,7 @@ cli_parse(struct config *c)
  cfg_mem = c->mem;
  if (setjmp(conf_jmpbuf))
    return 0;
  cf_lex_init(1);
  cf_lex_init(1, c);
  cf_parse();
  return 1;
}
@@ -355,7 +355,8 @@ cf_error(char *msg, ...)
  if (bvsnprintf(buf, sizeof(buf), msg, args) < 0)
    strcpy(buf, "<bug: error message too long>");
  new_config->err_msg = cfg_strdup(buf);
  new_config->err_lino = conf_lino;
  new_config->err_lino = ifs->conf_lino;
  new_config->err_file_name = ifs->conf_fname;
  longjmp(conf_jmpbuf, 1);
}

+19 −4
Original line number Diff line number Diff line
@@ -12,6 +12,8 @@
#include "lib/resource.h"
#include "lib/timer.h"

#define BIRD_FNAME_MAX 255	/* Would be better to use some UNIX define */

/* Configuration structure */

struct config {
@@ -38,7 +40,9 @@ struct config {
  int cli_debug;			/* Tracing of CLI connections and commands */
  char *err_msg;			/* Parser error message */
  int err_lino;				/* Line containing error */
  char *file_name;			/* Name of configuration file */
  char *err_file_name;			/* File name containing error */
  char *file_name;			/* Name of main configuration file */
  int file_fd;				/* File descriptor of main configuration file */
  struct symbol **sym_hash;		/* Lexer: symbol hash table */
  struct symbol **sym_fallback;		/* Lexer: fallback symbol hash table */
  int obstacle_count;			/* Number of items blocking freeing of this config */
@@ -83,7 +87,8 @@ char *cfg_strdup(char *c);

/* Lexer */

extern int (*cf_read_hook)(byte *buf, unsigned int max);
extern int (*cf_read_hook)(byte *buf, unsigned int max, int fd);
extern int (*cf_open_hook)(char *filename);

struct symbol {
  struct symbol *next;
@@ -106,10 +111,20 @@ struct symbol {

#define SYM_VARIABLE 0x100	/* 0x100-0x1ff are variable types */

extern int conf_lino;
struct include_file_stack {
        void	*stack; /* Internal lexer state */
        unsigned int    conf_lino; /* Current file lineno (at include) */
        char            conf_fname[BIRD_FNAME_MAX]; /* Current file name */
        int             conf_fd; /* Current file descriptor */
        struct include_file_stack *prev;
        struct include_file_stack *next;
};

struct include_file_stack *ifs;


int cf_lex(void);
void cf_lex_init(int is_cli);
void cf_lex_init(int is_cli, struct config *c);
struct symbol *cf_find_symbol(byte *c);
struct symbol *cf_default_name(char *template, int *counter);
struct symbol *cf_define_symbol(struct symbol *symbol, int type, void *def);
+2 −0
Original line number Diff line number Diff line
@@ -25,6 +25,8 @@
#filter sink { reject; }
#filter okay { accept; }

#include "filters.conf";

# Define another routing table
#table testable;

+3 −0
Original line number Diff line number Diff line
@@ -259,6 +259,9 @@ protocol rip {
<sect>Global options

<p><descrip>
	<tag>include "<m/filename/"</tag> 
	This statement causes inclusion of a new file. The maximal depth is set to 5.

	<tag>log "<m/filename/"|syslog [name <m/name/]|stderr all|{ <m/list of classes/ }</tag> 
	Set logging of messages having the given class (either <cf/all/ or <cf/{
	error, trace }/ etc.) into selected destination (a file specified as a filename string,
Loading