Commit e3511e3c authored by Jan Včelák's avatar Jan Včelák 🚀

config scanner: separate includes structures

refs #2381
parent 18064177
......@@ -88,6 +88,10 @@ src/knot/conf/cf-lex.l
src/knot/conf/cf-parse.y
src/knot/conf/conf.c
src/knot/conf/conf.h
src/knot/conf/extra.c
src/knot/conf/extra.h
src/knot/conf/includes.c
src/knot/conf/includes.h
src/knot/conf/logconf.c
src/knot/conf/logconf.h
src/knot/ctl/knotc_main.c
......
......@@ -264,12 +264,16 @@ libknotd_la_SOURCES = \
knot/stat/stat.h \
knot/common.h \
knot/other/debug.h \
knot/conf/cf-parse.y \
knot/conf/cf-lex.l \
knot/conf/cf-parse.y \
knot/conf/conf.c \
knot/conf/conf.h \
knot/conf/extra.c \
knot/conf/extra.h \
knot/conf/includes.c \
knot/conf/includes.h \
knot/conf/logconf.c \
knot/conf/logconf.h \
knot/conf/conf.h \
knot/ctl/process.c \
knot/ctl/process.h \
knot/ctl/remote.c \
......
......@@ -16,6 +16,8 @@
#include "common/sockaddr.h"
#include "knot/conf/conf.h"
#include "knot/conf/includes.h"
#include "knot/conf/extra.h"
#include "common/log.h"
#include "libknotd_la-cf-parse.h" /* Automake generated header. */
......@@ -42,69 +44,6 @@ int hex2bin(const char* src, char *dst, size_t len) {
return 0;
}
/* Scanner extra data. */
#define MAX_INCLUSION_DEPTH 8
typedef struct {
char *names[MAX_INCLUSION_DEPTH];
int free_index;
} cf_includes_t;
typedef struct {
bool error;
cf_includes_t includes;
} cf_extra_t;
#define YY_USER_INIT yyextra = calloc(1, sizeof(cf_extra_t))
/* Functions to control scanner extra data. */
static bool names_stack_has_space(cf_extra_t *extra)
{
if (!extra)
return false;
return extra->includes.free_index < MAX_INCLUSION_DEPTH;
}
static void names_stack_push(cf_extra_t *extra, char *name)
{
if (!extra)
return;
extra->includes.names[extra->includes.free_index] = name;
extra->includes.free_index += 1;
}
static char *names_stack_pop(cf_extra_t *extra)
{
if (!extra || extra->includes.free_index == 0)
return NULL;
extra->includes.free_index -= 1;
return extra->includes.names[extra->includes.free_index];
}
/* Public interface to extra data in scanner. */
extern cf_extra_t *cf_get_extra(yyscan_t scanner);
void cf_set_error(yyscan_t scanner)
{
cf_extra_t *extra = cf_get_extra(scanner);
if (!extra)
return;
extra->error = true;
}
char *cf_current_filename(yyscan_t scanner)
{
cf_extra_t *extra = cf_get_extra(scanner);
return names_stack_pop(extra);
}
//#define YY_INPUT(buf,result,max) result = cf_read_hook(buf, max);
#define YY_NO_UNPUT
......@@ -119,7 +58,7 @@ char *cf_current_filename(yyscan_t scanner)
%option yylineno
%option prefix = "cf_"
%option outfile = "lex.yy.c"
%option extra-type = "cf_extra_t *"
%option extra-type = "conf_extra_t *"
%x include
......@@ -341,13 +280,11 @@ hmac-sha512 { lval.alg = KNOT_TSIG_ALG_HMAC_SHA512; return TSIG_ALGO_NAME; }
: /* Optional : in assignments. */;
<<EOF>> {
char *name = names_stack_pop(yyextra);
char *name = conf_includes_pop(yyextra->includes);
free(name);
yypop_buffer_state(yyscanner);
if (!YY_CURRENT_BUFFER) {
free(yyextra);
if (!YY_CURRENT_BUFFER)
return END;
}
}
<include>{BLANK}+
......@@ -359,22 +296,25 @@ hmac-sha512 { lval.alg = KNOT_TSIG_ALG_HMAC_SHA512; return TSIG_ALGO_NAME; }
return END;
}
if (!names_stack_has_space(yyextra)) {
// remove quotes
yytext += 1;
yyleng -= 2;
yytext[yyleng] = '\0';
if (!conf_includes_can_push(yyextra->includes)) {
cf_error(yyscanner, "includes nested too deeply");
return END;
}
char *filename = strndup(yytext + 1, yyleng - 2);
FILE *included = fopen(filename, "r");
FILE *included = fopen(yytext, "r");
if (!included) {
cf_error(yyscanner, "cannot open file '%s'", filename);
free(filename);
cf_error(yyscanner, "cannot open file '%s'", yytext);
return END;
}
conf_includes_push(yyextra->includes, yytext);
YY_BUFFER_STATE bs = yy_create_buffer(included, YY_BUF_SIZE, yyscanner);
yypush_buffer_state(bs, yyscanner);
names_stack_push(yyextra, filename);
}
<include>["][^"\n]*\n cf_error(yyscanner, "Unterminated string.");
......
......@@ -14,6 +14,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
......@@ -25,6 +26,7 @@
#include <urcu.h>
#include "knot/conf/conf.h"
#include "knot/conf/extra.h"
#include "knot/common.h"
#include "knot/ctl/remote.h"
......@@ -39,6 +41,7 @@ static const char *DEFAULT_CONFIG[] = {
#define DEFAULT_CONF_COUNT 1 /*!< \brief Number of default config paths. */
#define ERROR_BUFFER_SIZE 512 /*!< \brief Error buffer size. */
#define INCLUDES_MAX_DEPTH 8 /*!< \brief Max depth of config inclusion. */
/*
* Utilities.
......@@ -49,7 +52,8 @@ extern int cf_parse(void *scanner);
extern int cf_get_lineno(void *scanner);
extern void cf_set_error(void *scanner);
extern char *cf_get_text(void *scanner);
extern int cf_lex_init(void *scanner);
extern conf_extra_t *cf_get_extra(void *scanner);
extern int cf_lex_init_extra(void *, void *scanner);
extern void cf_set_in(FILE *f, void *scanner);
extern void cf_lex_destroy(void *scanner);
extern void switch_input(const char *str, void *scanner);
......@@ -68,14 +72,15 @@ static void cf_print_error(void *scanner, const char *msg)
text = cf_get_text(scanner);
}
char *filename = cf_current_filename(scanner);
conf_extra_t *extra = cf_get_extra(scanner);
char *filename = conf_includes_top(extra->includes);
if (!filename)
filename = new_config->filename;
log_server_error("Config error in '%s' (line %d token '%s') - %s\n",
filename, lineno, text, msg);
cf_set_error(scanner);
extra->error = true;
_parser_res = KNOT_EPARSEFAIL;
}
......@@ -444,10 +449,12 @@ static int conf_fparser(conf_t *conf)
_parser_res = KNOT_EOK;
new_config->filename = conf->filename;
void *sc = NULL;
cf_lex_init(&sc);
conf_extra_t *extra = conf_extra_init(conf->filename, INCLUDES_MAX_DEPTH);
cf_lex_init_extra(extra, &sc);
cf_set_in(f, sc);
cf_parse(sc);
cf_lex_destroy(sc);
conf_extra_free(extra);
ret = _parser_res;
fclose(f);
// }
......@@ -476,10 +483,12 @@ static int conf_strparser(conf_t *conf, const char *src)
char *oldfn = new_config->filename;
new_config->filename = "(stdin)";
void *sc = NULL;
cf_lex_init(&sc);
conf_extra_t *extra = conf_extra_init("", INCLUDES_MAX_DEPTH);
cf_lex_init_extra(extra, &sc);
switch_input(src, sc);
cf_parse(sc);
cf_lex_destroy(sc);
conf_extra_free(extra);
new_config->filename = oldfn;
ret = _parser_res;
// }
......
/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include "knot/conf/includes.h"
#include "knot/conf/extra.h"
conf_extra_t *conf_extra_init(const char *file, int includes_capacity)
{
conf_extra_t *extra = calloc(1, sizeof(conf_extra_t));
if (!extra)
return NULL;
conf_includes_t *includes = conf_includes_init(includes_capacity);
if (!includes) {
free(extra);
return NULL;
}
if (!conf_includes_push(includes, file)) {
free(extra);
return NULL;
}
extra->error = false;
extra->includes = includes;
return extra;
}
void conf_extra_free(conf_extra_t *extra)
{
if (!extra)
return;
conf_includes_free(extra->includes);
free(extra);
}
/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _KNOT_CONF_EXTRA_H_
#define _KNOT_CONF_EXTRA_H_
#include <stdbool.h>
#include "knot/conf/includes.h"
typedef struct {
bool error;
conf_includes_t *includes;
} conf_extra_t;
conf_extra_t *conf_extra_init(const char *file, int includes_capacity);
void conf_extra_free(conf_extra_t *extra);
#endif /* _KNOT_CONF_EXTRA_H_ */
/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include "knot/conf/includes.h"
struct conf_includes {
int free_index;
int capacity;
char *names[0];
};
conf_includes_t *conf_includes_init(int capacity)
{
if (capacity <= 0)
return NULL;
size_t size = sizeof(conf_includes_t) + (capacity * sizeof(char *));
conf_includes_t *result = calloc(1, size);
if (!result)
return NULL;
result->capacity = capacity;
return result;
}
void conf_includes_free(conf_includes_t *includes)
{
if (!includes)
return;
for (int i = 0; i < includes->free_index; i++)
free(includes->names[i]);
free(includes);
}
bool conf_includes_can_push(conf_includes_t *includes)
{
if (!includes)
return false;
return includes->free_index < includes->capacity;
}
bool conf_includes_push(conf_includes_t *includes, const char *filename)
{
if (!includes || !filename)
return false;
if (!conf_includes_can_push(includes))
return false;
includes->names[includes->free_index++] = strdup(filename);
return true;
}
char *conf_includes_top(conf_includes_t *includes)
{
if (!includes || includes->free_index == 0)
return NULL;
return includes->names[includes->free_index - 1];
}
char *conf_includes_pop(conf_includes_t *includes)
{
char *result = conf_includes_top(includes);
if (result)
includes->free_index -= 1;
return result;
}
/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _KNOT_CONF_INCLUDES_H_
#define _KNOT_CONF_INCLUDES_H_
#include <stdbool.h>
struct conf_includes;
typedef struct conf_includes conf_includes_t;
conf_includes_t *conf_includes_init(int capacity);
void conf_includes_free(conf_includes_t *includes);
bool conf_includes_can_push(conf_includes_t *includes);
bool conf_includes_push(conf_includes_t *includes, const char *filename);
char *conf_includes_top(conf_includes_t *includes);
char *conf_includes_pop(conf_includes_t *includes);
#endif /* _KNOT_CONF_INCLUDES_H_ */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment