Configuration can include other files.
This commit is contained in:
parent
a98995273b
commit
48ec367aab
10 changed files with 145 additions and 25 deletions
|
@ -63,19 +63,27 @@ struct sym_scope {
|
||||||
};
|
};
|
||||||
static struct sym_scope *conf_this_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 int cf_hash(byte *c);
|
||||||
static struct symbol *cf_find_sym(byte *c, unsigned int h0);
|
static struct symbol *cf_find_sym(byte *c, unsigned int h0);
|
||||||
|
|
||||||
linpool *cfg_mem;
|
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_NO_UNPUT
|
||||||
#define YY_FATAL_ERROR(msg) cf_error(msg)
|
#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
|
%option noyywrap
|
||||||
|
@ -90,8 +98,10 @@ DIGIT [0-9]
|
||||||
XIGIT [0-9a-fA-F]
|
XIGIT [0-9a-fA-F]
|
||||||
ALNUM [a-zA-Z_0-9]
|
ALNUM [a-zA-Z_0-9]
|
||||||
WHITE [ \t]
|
WHITE [ \t]
|
||||||
|
include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*;
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
{include} { if(cf_open_hook) new_include(); }
|
||||||
|
|
||||||
{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+ {
|
{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+ {
|
||||||
#ifdef IPV6
|
#ifdef IPV6
|
||||||
|
@ -188,11 +198,11 @@ else: {
|
||||||
|
|
||||||
["][^"\n]*\n cf_error("Unterminated string");
|
["][^"\n]*\n cf_error("Unterminated string");
|
||||||
|
|
||||||
<INITIAL,COMMENT><<EOF>> return END;
|
<INITIAL,COMMENT><<EOF>> { if(check_eof()) return END; }
|
||||||
|
|
||||||
{WHITE}+
|
{WHITE}+
|
||||||
|
|
||||||
\n conf_lino++;
|
\n ifs->conf_lino++;
|
||||||
|
|
||||||
# BEGIN(COMMENT);
|
# BEGIN(COMMENT);
|
||||||
|
|
||||||
|
@ -201,14 +211,14 @@ else: {
|
||||||
. cf_error("Unknown character");
|
. cf_error("Unknown character");
|
||||||
|
|
||||||
<COMMENT>\n {
|
<COMMENT>\n {
|
||||||
conf_lino++;
|
ifs->conf_lino++;
|
||||||
BEGIN(INITIAL);
|
BEGIN(INITIAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
<COMMENT>.
|
<COMMENT>.
|
||||||
|
|
||||||
<CCOMM>\*\/ BEGIN(INITIAL);
|
<CCOMM>\*\/ BEGIN(INITIAL);
|
||||||
<CCOMM>\n conf_lino++;
|
<CCOMM>\n ifs->conf_lino++;
|
||||||
<CCOMM>\/\* cf_error("Comment nesting not supported");
|
<CCOMM>\/\* cf_error("Comment nesting not supported");
|
||||||
<CCOMM><<EOF>> cf_error("Unterminated comment");
|
<CCOMM><<EOF>> cf_error("Unterminated comment");
|
||||||
<CCOMM>.
|
<CCOMM>.
|
||||||
|
@ -234,6 +244,50 @@ cf_hash(byte *c)
|
||||||
return h;
|
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 *
|
static struct symbol *
|
||||||
cf_new_sym(byte *c, unsigned int h)
|
cf_new_sym(byte *c, unsigned int h)
|
||||||
{
|
{
|
||||||
|
@ -359,6 +413,16 @@ cf_lex_init_kh(void)
|
||||||
kw_hash_inited = 1;
|
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
|
* cf_lex_init - initialize the lexer
|
||||||
* @is_cli: true if we're going to parse CLI command, false for configuration
|
* @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.
|
* parsing of a new input.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
cf_lex_init(int is_cli)
|
cf_lex_init(int is_cli, struct config *c)
|
||||||
{
|
{
|
||||||
if (!kw_hash_inited)
|
if (!kw_hash_inited)
|
||||||
cf_lex_init_kh();
|
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);
|
yyrestart(NULL);
|
||||||
if (is_cli)
|
if (is_cli)
|
||||||
BEGIN(CLI);
|
BEGIN(CLI);
|
||||||
|
|
|
@ -108,7 +108,7 @@ config_parse(struct config *c)
|
||||||
cfg_mem = c->mem;
|
cfg_mem = c->mem;
|
||||||
if (setjmp(conf_jmpbuf))
|
if (setjmp(conf_jmpbuf))
|
||||||
return 0;
|
return 0;
|
||||||
cf_lex_init(0);
|
cf_lex_init(0, c);
|
||||||
sysdep_preconfig(c);
|
sysdep_preconfig(c);
|
||||||
protos_preconfig(c);
|
protos_preconfig(c);
|
||||||
rt_preconfig(c);
|
rt_preconfig(c);
|
||||||
|
@ -138,7 +138,7 @@ cli_parse(struct config *c)
|
||||||
cfg_mem = c->mem;
|
cfg_mem = c->mem;
|
||||||
if (setjmp(conf_jmpbuf))
|
if (setjmp(conf_jmpbuf))
|
||||||
return 0;
|
return 0;
|
||||||
cf_lex_init(1);
|
cf_lex_init(1, c);
|
||||||
cf_parse();
|
cf_parse();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -355,7 +355,8 @@ cf_error(char *msg, ...)
|
||||||
if (bvsnprintf(buf, sizeof(buf), msg, args) < 0)
|
if (bvsnprintf(buf, sizeof(buf), msg, args) < 0)
|
||||||
strcpy(buf, "<bug: error message too long>");
|
strcpy(buf, "<bug: error message too long>");
|
||||||
new_config->err_msg = cfg_strdup(buf);
|
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);
|
longjmp(conf_jmpbuf, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
23
conf/conf.h
23
conf/conf.h
|
@ -12,6 +12,8 @@
|
||||||
#include "lib/resource.h"
|
#include "lib/resource.h"
|
||||||
#include "lib/timer.h"
|
#include "lib/timer.h"
|
||||||
|
|
||||||
|
#define BIRD_FNAME_MAX 255 /* Would be better to use some UNIX define */
|
||||||
|
|
||||||
/* Configuration structure */
|
/* Configuration structure */
|
||||||
|
|
||||||
struct config {
|
struct config {
|
||||||
|
@ -38,7 +40,9 @@ struct config {
|
||||||
int cli_debug; /* Tracing of CLI connections and commands */
|
int cli_debug; /* Tracing of CLI connections and commands */
|
||||||
char *err_msg; /* Parser error message */
|
char *err_msg; /* Parser error message */
|
||||||
int err_lino; /* Line containing error */
|
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_hash; /* Lexer: symbol hash table */
|
||||||
struct symbol **sym_fallback; /* Lexer: fallback symbol hash table */
|
struct symbol **sym_fallback; /* Lexer: fallback symbol hash table */
|
||||||
int obstacle_count; /* Number of items blocking freeing of this config */
|
int obstacle_count; /* Number of items blocking freeing of this config */
|
||||||
|
@ -83,7 +87,8 @@ char *cfg_strdup(char *c);
|
||||||
|
|
||||||
/* Lexer */
|
/* 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 {
|
||||||
struct symbol *next;
|
struct symbol *next;
|
||||||
|
@ -106,10 +111,20 @@ struct symbol {
|
||||||
|
|
||||||
#define SYM_VARIABLE 0x100 /* 0x100-0x1ff are variable types */
|
#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);
|
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_find_symbol(byte *c);
|
||||||
struct symbol *cf_default_name(char *template, int *counter);
|
struct symbol *cf_default_name(char *template, int *counter);
|
||||||
struct symbol *cf_define_symbol(struct symbol *symbol, int type, void *def);
|
struct symbol *cf_define_symbol(struct symbol *symbol, int type, void *def);
|
||||||
|
|
|
@ -25,6 +25,8 @@
|
||||||
#filter sink { reject; }
|
#filter sink { reject; }
|
||||||
#filter okay { accept; }
|
#filter okay { accept; }
|
||||||
|
|
||||||
|
#include "filters.conf";
|
||||||
|
|
||||||
# Define another routing table
|
# Define another routing table
|
||||||
#table testable;
|
#table testable;
|
||||||
|
|
||||||
|
|
|
@ -259,6 +259,9 @@ protocol rip {
|
||||||
<sect>Global options
|
<sect>Global options
|
||||||
|
|
||||||
<p><descrip>
|
<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>
|
<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/{
|
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,
|
error, trace }/ etc.) into selected destination (a file specified as a filename string,
|
||||||
|
|
|
@ -19,7 +19,7 @@ f_new_inst(void)
|
||||||
ret = cfg_alloc(sizeof(struct f_inst));
|
ret = cfg_alloc(sizeof(struct f_inst));
|
||||||
ret->code = ret->aux = 0;
|
ret->code = ret->aux = 0;
|
||||||
ret->arg1 = ret->arg2 = ret->next = NULL;
|
ret->arg1 = ret->arg2 = ret->next = NULL;
|
||||||
ret->lineno = conf_lino;
|
ret->lineno = ifs->conf_lino;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -329,6 +329,9 @@ string s;
|
||||||
test_undef(3);
|
test_undef(3);
|
||||||
test_undef(2);
|
test_undef(2);
|
||||||
|
|
||||||
|
print "Testing include";
|
||||||
|
include "test.conf.inc";
|
||||||
|
|
||||||
print "done";
|
print "done";
|
||||||
quitbird;
|
quitbird;
|
||||||
# print "*** FAIL: this is unreachable";
|
# print "*** FAIL: this is unreachable";
|
||||||
|
|
6
filter/test.conf.inc
Normal file
6
filter/test.conf.inc
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
print "Entering include";
|
||||||
|
print "Should be 2: ", 1+1;
|
||||||
|
print "Leaving include";
|
||||||
|
|
||||||
|
|
|
@ -251,6 +251,7 @@ cli_command(struct cli *c)
|
||||||
bzero(&f, sizeof(f));
|
bzero(&f, sizeof(f));
|
||||||
f.mem = c->parser_pool;
|
f.mem = c->parser_pool;
|
||||||
cf_read_hook = cli_cmd_read_hook;
|
cf_read_hook = cli_cmd_read_hook;
|
||||||
|
cf_open_hook = NULL;
|
||||||
cli_rh_pos = c->rx_buf;
|
cli_rh_pos = c->rx_buf;
|
||||||
cli_rh_len = strlen(c->rx_buf);
|
cli_rh_len = strlen(c->rx_buf);
|
||||||
cli_rh_trick_flag = 0;
|
cli_rh_trick_flag = 0;
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <libgen.h>
|
||||||
|
|
||||||
#include "nest/bird.h"
|
#include "nest/bird.h"
|
||||||
#include "lib/lists.h"
|
#include "lib/lists.h"
|
||||||
|
@ -150,18 +151,34 @@ read_iproute_table(char *file, char *prefix, int max)
|
||||||
#endif // PATH_IPROUTE_DIR
|
#endif // PATH_IPROUTE_DIR
|
||||||
|
|
||||||
|
|
||||||
static int conf_fd;
|
|
||||||
static char *config_name = PATH_CONFIG;
|
static char *config_name = PATH_CONFIG;
|
||||||
|
|
||||||
static int
|
static int
|
||||||
cf_read(byte *dest, unsigned int len)
|
cf_read(byte *dest, unsigned int len, int fd)
|
||||||
{
|
{
|
||||||
int l = read(conf_fd, dest, len);
|
int l = read(fd, dest, len);
|
||||||
if (l < 0)
|
if (l < 0)
|
||||||
cf_error("Read error");
|
cf_error("Read error");
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
cf_open(char *filename)
|
||||||
|
{
|
||||||
|
char full_name[BIRD_FNAME_MAX];
|
||||||
|
char *cur = filename;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (*filename != '/') {
|
||||||
|
snprintf(full_name, sizeof(full_name), "%s/%s", dirname(config_name), filename);
|
||||||
|
cur = full_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret = open(cur, O_RDONLY)) == -1)
|
||||||
|
cf_error("Unable to open included configuration file: %s", cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
sysdep_preconfig(struct config *c)
|
sysdep_preconfig(struct config *c)
|
||||||
{
|
{
|
||||||
|
@ -189,12 +206,13 @@ unix_read_config(struct config **cp, char *name)
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
*cp = conf;
|
*cp = conf;
|
||||||
conf_fd = open(name, O_RDONLY);
|
conf->file_fd = open(name, O_RDONLY);
|
||||||
if (conf_fd < 0)
|
if (conf->file_fd < 0)
|
||||||
return 0;
|
return 0;
|
||||||
cf_read_hook = cf_read;
|
cf_read_hook = cf_read;
|
||||||
|
cf_open_hook = cf_open;
|
||||||
ret = config_parse(conf);
|
ret = config_parse(conf);
|
||||||
close(conf_fd);
|
close(conf->file_fd);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,7 +224,7 @@ read_config(void)
|
||||||
if (!unix_read_config(&conf, config_name))
|
if (!unix_read_config(&conf, config_name))
|
||||||
{
|
{
|
||||||
if (conf->err_msg)
|
if (conf->err_msg)
|
||||||
die("%s, line %d: %s", config_name, conf->err_lino, conf->err_msg);
|
die("%s, line %d: %s", conf->err_file_name, conf->err_lino, conf->err_msg);
|
||||||
else
|
else
|
||||||
die("Unable to open configuration file %s: %m", config_name);
|
die("Unable to open configuration file %s: %m", config_name);
|
||||||
}
|
}
|
||||||
|
@ -222,7 +240,7 @@ async_config(void)
|
||||||
if (!unix_read_config(&conf, config_name))
|
if (!unix_read_config(&conf, config_name))
|
||||||
{
|
{
|
||||||
if (conf->err_msg)
|
if (conf->err_msg)
|
||||||
log(L_ERR "%s, line %d: %s", config_name, conf->err_lino, conf->err_msg);
|
log(L_ERR "%s, line %d: %s", conf->err_file_name, conf->err_lino, conf->err_msg);
|
||||||
else
|
else
|
||||||
log(L_ERR "Unable to open configuration file %s: %m", config_name);
|
log(L_ERR "Unable to open configuration file %s: %m", config_name);
|
||||||
config_free(conf);
|
config_free(conf);
|
||||||
|
|
Loading…
Reference in a new issue