diff --git a/Knot.files b/Knot.files index c4c386e0ec2dbc2b517126013ed1f583e3540ce0..1cd5fb5d7ef96d4e74242ff18eac1442f1ead900 100644 --- a/Knot.files +++ b/Knot.files @@ -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 diff --git a/src/Makefile.am b/src/Makefile.am index e4e2c019f8813c256289d385066770f133a1ccfa..c5899000491739c83a4e74316d73a442d675ee1f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 \ diff --git a/src/knot/conf/cf-lex.l b/src/knot/conf/cf-lex.l index dc940a60a52244b97715f16ff8b164d9c4d7335e..a94dc20168a2e03ede976d9dc80f77ea8454abb3 100644 --- a/src/knot/conf/cf-lex.l +++ b/src/knot/conf/cf-lex.l @@ -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."); diff --git a/src/knot/conf/conf.c b/src/knot/conf/conf.c index edf676cbeef1d0f1ba614f6e31628ce5b9d78deb..a1e41612b2469b27608361435b65f7ef7b1c86ae 100644 --- a/src/knot/conf/conf.c +++ b/src/knot/conf/conf.c @@ -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; // } diff --git a/src/knot/conf/extra.c b/src/knot/conf/extra.c new file mode 100644 index 0000000000000000000000000000000000000000..a01117a4637af697d50576aa876b217235f165d5 --- /dev/null +++ b/src/knot/conf/extra.c @@ -0,0 +1,54 @@ +/* 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); +} diff --git a/src/knot/conf/extra.h b/src/knot/conf/extra.h new file mode 100644 index 0000000000000000000000000000000000000000..23108355a9ae59601787e33c69cb86cc507ba5f6 --- /dev/null +++ b/src/knot/conf/extra.h @@ -0,0 +1,31 @@ +/* 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_ */ diff --git a/src/knot/conf/includes.c b/src/knot/conf/includes.c new file mode 100644 index 0000000000000000000000000000000000000000..522502607ec510bab44607b05bfbb23fcf819e37 --- /dev/null +++ b/src/knot/conf/includes.c @@ -0,0 +1,89 @@ +/* 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; +} diff --git a/src/knot/conf/includes.h b/src/knot/conf/includes.h new file mode 100644 index 0000000000000000000000000000000000000000..9e1b4f78c2032f567f4b84b40544a63523413e5b --- /dev/null +++ b/src/knot/conf/includes.h @@ -0,0 +1,32 @@ +/* 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_ */