diff options
Diffstat (limited to 'contrib/bind9/lib/isccfg/parser.c')
-rw-r--r-- | contrib/bind9/lib/isccfg/parser.c | 2382 |
1 files changed, 0 insertions, 2382 deletions
diff --git a/contrib/bind9/lib/isccfg/parser.c b/contrib/bind9/lib/isccfg/parser.c deleted file mode 100644 index 19a51a6..0000000 --- a/contrib/bind9/lib/isccfg/parser.c +++ /dev/null @@ -1,2382 +0,0 @@ -/* - * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") - * Copyright (C) 2000-2003 Internet Software Consortium. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH - * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, - * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE - * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - -/* $Id: parser.c,v 1.112.18.11 2006/02/28 03:10:49 marka Exp $ */ - -/*! \file */ - -#include <config.h> - -#include <isc/buffer.h> -#include <isc/dir.h> -#include <isc/formatcheck.h> -#include <isc/lex.h> -#include <isc/log.h> -#include <isc/mem.h> -#include <isc/net.h> -#include <isc/netaddr.h> -#include <isc/print.h> -#include <isc/string.h> -#include <isc/sockaddr.h> -#include <isc/netscope.h> -#include <isc/util.h> -#include <isc/symtab.h> - -#include <isccfg/cfg.h> -#include <isccfg/grammar.h> -#include <isccfg/log.h> - -/* Shorthand */ -#define CAT CFG_LOGCATEGORY_CONFIG -#define MOD CFG_LOGMODULE_PARSER - -#define MAP_SYM 1 /* Unique type for isc_symtab */ - -#define TOKEN_STRING(pctx) (pctx->token.value.as_textregion.base) - -/* Check a return value. */ -#define CHECK(op) \ - do { result = (op); \ - if (result != ISC_R_SUCCESS) goto cleanup; \ - } while (0) - -/* Clean up a configuration object if non-NULL. */ -#define CLEANUP_OBJ(obj) \ - do { if ((obj) != NULL) cfg_obj_destroy(pctx, &(obj)); } while (0) - - -/* - * Forward declarations of static functions. - */ - -static void -free_tuple(cfg_parser_t *pctx, cfg_obj_t *obj); - -static isc_result_t -parse_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret); - -static void -print_list(cfg_printer_t *pctx, const cfg_obj_t *obj); - -static void -free_list(cfg_parser_t *pctx, cfg_obj_t *obj); - -static isc_result_t -create_listelt(cfg_parser_t *pctx, cfg_listelt_t **eltp); - -static isc_result_t -create_string(cfg_parser_t *pctx, const char *contents, const cfg_type_t *type, - cfg_obj_t **ret); - -static void -free_string(cfg_parser_t *pctx, cfg_obj_t *obj); - -static isc_result_t -create_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **objp); - -static void -free_map(cfg_parser_t *pctx, cfg_obj_t *obj); - -static isc_result_t -parse_symtab_elt(cfg_parser_t *pctx, const char *name, - cfg_type_t *elttype, isc_symtab_t *symtab, - isc_boolean_t callback); - -static void -free_noop(cfg_parser_t *pctx, cfg_obj_t *obj); - -static isc_result_t -cfg_getstringtoken(cfg_parser_t *pctx); - -static void -parser_complain(cfg_parser_t *pctx, isc_boolean_t is_warning, - unsigned int flags, const char *format, va_list args); - -/* - * Data representations. These correspond to members of the - * "value" union in struct cfg_obj (except "void", which does - * not need a union member). - */ - -cfg_rep_t cfg_rep_uint32 = { "uint32", free_noop }; -cfg_rep_t cfg_rep_uint64 = { "uint64", free_noop }; -cfg_rep_t cfg_rep_string = { "string", free_string }; -cfg_rep_t cfg_rep_boolean = { "boolean", free_noop }; -cfg_rep_t cfg_rep_map = { "map", free_map }; -cfg_rep_t cfg_rep_list = { "list", free_list }; -cfg_rep_t cfg_rep_tuple = { "tuple", free_tuple }; -cfg_rep_t cfg_rep_sockaddr = { "sockaddr", free_noop }; -cfg_rep_t cfg_rep_netprefix = { "netprefix", free_noop }; -cfg_rep_t cfg_rep_void = { "void", free_noop }; - -/* - * Configuration type definitions. - */ - -/*% - * An implicit list. These are formed by clauses that occur multiple times. - */ -static cfg_type_t cfg_type_implicitlist = { - "implicitlist", NULL, print_list, NULL, &cfg_rep_list, NULL }; - -/* Functions. */ - -void -cfg_print_obj(cfg_printer_t *pctx, const cfg_obj_t *obj) { - obj->type->print(pctx, obj); -} - -void -cfg_print_chars(cfg_printer_t *pctx, const char *text, int len) { - pctx->f(pctx->closure, text, len); -} - -static void -print_open(cfg_printer_t *pctx) { - cfg_print_chars(pctx, "{\n", 2); - pctx->indent++; -} - -static void -print_indent(cfg_printer_t *pctx) { - int indent = pctx->indent; - while (indent > 0) { - cfg_print_chars(pctx, "\t", 1); - indent--; - } -} - -static void -print_close(cfg_printer_t *pctx) { - pctx->indent--; - print_indent(pctx); - cfg_print_chars(pctx, "}", 1); -} - -isc_result_t -cfg_parse_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - isc_result_t result; - INSIST(ret != NULL && *ret == NULL); - result = type->parse(pctx, type, ret); - if (result != ISC_R_SUCCESS) - return (result); - INSIST(*ret != NULL); - return (ISC_R_SUCCESS); -} - -void -cfg_print(const cfg_obj_t *obj, - void (*f)(void *closure, const char *text, int textlen), - void *closure) -{ - cfg_printer_t pctx; - pctx.f = f; - pctx.closure = closure; - pctx.indent = 0; - obj->type->print(&pctx, obj); -} - - -/* Tuples. */ - -isc_result_t -cfg_create_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - isc_result_t result; - const cfg_tuplefielddef_t *fields = type->of; - const cfg_tuplefielddef_t *f; - cfg_obj_t *obj = NULL; - unsigned int nfields = 0; - int i; - - for (f = fields; f->name != NULL; f++) - nfields++; - - CHECK(cfg_create_obj(pctx, type, &obj)); - obj->value.tuple = isc_mem_get(pctx->mctx, - nfields * sizeof(cfg_obj_t *)); - if (obj->value.tuple == NULL) { - result = ISC_R_NOMEMORY; - goto cleanup; - } - for (f = fields, i = 0; f->name != NULL; f++, i++) - obj->value.tuple[i] = NULL; - *ret = obj; - return (ISC_R_SUCCESS); - - cleanup: - if (obj != NULL) - isc_mem_put(pctx->mctx, obj, sizeof(*obj)); - return (result); -} - -isc_result_t -cfg_parse_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) -{ - isc_result_t result; - const cfg_tuplefielddef_t *fields = type->of; - const cfg_tuplefielddef_t *f; - cfg_obj_t *obj = NULL; - unsigned int i; - - CHECK(cfg_create_tuple(pctx, type, &obj)); - for (f = fields, i = 0; f->name != NULL; f++, i++) - CHECK(cfg_parse_obj(pctx, f->type, &obj->value.tuple[i])); - - *ret = obj; - return (ISC_R_SUCCESS); - - cleanup: - CLEANUP_OBJ(obj); - return (result); -} - -void -cfg_print_tuple(cfg_printer_t *pctx, const cfg_obj_t *obj) { - unsigned int i; - const cfg_tuplefielddef_t *fields = obj->type->of; - const cfg_tuplefielddef_t *f; - isc_boolean_t need_space = ISC_FALSE; - - for (f = fields, i = 0; f->name != NULL; f++, i++) { - const cfg_obj_t *fieldobj = obj->value.tuple[i]; - if (need_space) - cfg_print_chars(pctx, " ", 1); - cfg_print_obj(pctx, fieldobj); - need_space = ISC_TF(fieldobj->type->print != cfg_print_void); - } -} - -void -cfg_doc_tuple(cfg_printer_t *pctx, const cfg_type_t *type) { - const cfg_tuplefielddef_t *fields = type->of; - const cfg_tuplefielddef_t *f; - isc_boolean_t need_space = ISC_FALSE; - - for (f = fields; f->name != NULL; f++) { - if (need_space) - cfg_print_chars(pctx, " ", 1); - cfg_doc_obj(pctx, f->type); - need_space = ISC_TF(f->type->print != cfg_print_void); - } -} - -static void -free_tuple(cfg_parser_t *pctx, cfg_obj_t *obj) { - unsigned int i; - const cfg_tuplefielddef_t *fields = obj->type->of; - const cfg_tuplefielddef_t *f; - unsigned int nfields = 0; - - if (obj->value.tuple == NULL) - return; - - for (f = fields, i = 0; f->name != NULL; f++, i++) { - CLEANUP_OBJ(obj->value.tuple[i]); - nfields++; - } - isc_mem_put(pctx->mctx, obj->value.tuple, - nfields * sizeof(cfg_obj_t *)); -} - -isc_boolean_t -cfg_obj_istuple(const cfg_obj_t *obj) { - REQUIRE(obj != NULL); - return (ISC_TF(obj->type->rep == &cfg_rep_tuple)); -} - -const cfg_obj_t * -cfg_tuple_get(const cfg_obj_t *tupleobj, const char* name) { - unsigned int i; - const cfg_tuplefielddef_t *fields; - const cfg_tuplefielddef_t *f; - - REQUIRE(tupleobj != NULL && tupleobj->type->rep == &cfg_rep_tuple); - - fields = tupleobj->type->of; - for (f = fields, i = 0; f->name != NULL; f++, i++) { - if (strcmp(f->name, name) == 0) - return (tupleobj->value.tuple[i]); - } - INSIST(0); - return (NULL); -} - -isc_result_t -cfg_parse_special(cfg_parser_t *pctx, int special) { - isc_result_t result; - CHECK(cfg_gettoken(pctx, 0)); - if (pctx->token.type == isc_tokentype_special && - pctx->token.value.as_char == special) - return (ISC_R_SUCCESS); - - cfg_parser_error(pctx, CFG_LOG_NEAR, "'%c' expected", special); - return (ISC_R_UNEXPECTEDTOKEN); - cleanup: - return (result); -} - -/* - * Parse a required semicolon. If it is not there, log - * an error and increment the error count but continue - * parsing. Since the next token is pushed back, - * care must be taken to make sure it is eventually - * consumed or an infinite loop may result. - */ -static isc_result_t -parse_semicolon(cfg_parser_t *pctx) { - isc_result_t result; - CHECK(cfg_gettoken(pctx, 0)); - if (pctx->token.type == isc_tokentype_special && - pctx->token.value.as_char == ';') - return (ISC_R_SUCCESS); - - cfg_parser_error(pctx, CFG_LOG_BEFORE, "missing ';'"); - cfg_ungettoken(pctx); - cleanup: - return (result); -} - -/* - * Parse EOF, logging and returning an error if not there. - */ -static isc_result_t -parse_eof(cfg_parser_t *pctx) { - isc_result_t result; - CHECK(cfg_gettoken(pctx, 0)); - - if (pctx->token.type == isc_tokentype_eof) - return (ISC_R_SUCCESS); - - cfg_parser_error(pctx, CFG_LOG_NEAR, "syntax error"); - return (ISC_R_UNEXPECTEDTOKEN); - cleanup: - return (result); -} - -/* A list of files, used internally for pctx->files. */ - -static cfg_type_t cfg_type_filelist = { - "filelist", NULL, print_list, NULL, &cfg_rep_list, - &cfg_type_qstring -}; - -isc_result_t -cfg_parser_create(isc_mem_t *mctx, isc_log_t *lctx, cfg_parser_t **ret) { - isc_result_t result; - cfg_parser_t *pctx; - isc_lexspecials_t specials; - - REQUIRE(mctx != NULL); - REQUIRE(ret != NULL && *ret == NULL); - - pctx = isc_mem_get(mctx, sizeof(*pctx)); - if (pctx == NULL) - return (ISC_R_NOMEMORY); - - pctx->mctx = mctx; - pctx->lctx = lctx; - pctx->lexer = NULL; - pctx->seen_eof = ISC_FALSE; - pctx->ungotten = ISC_FALSE; - pctx->errors = 0; - pctx->warnings = 0; - pctx->open_files = NULL; - pctx->closed_files = NULL; - pctx->line = 0; - pctx->callback = NULL; - pctx->callbackarg = NULL; - pctx->token.type = isc_tokentype_unknown; - - memset(specials, 0, sizeof(specials)); - specials['{'] = 1; - specials['}'] = 1; - specials[';'] = 1; - specials['/'] = 1; - specials['"'] = 1; - specials['!'] = 1; - - CHECK(isc_lex_create(pctx->mctx, 1024, &pctx->lexer)); - - isc_lex_setspecials(pctx->lexer, specials); - isc_lex_setcomments(pctx->lexer, (ISC_LEXCOMMENT_C | - ISC_LEXCOMMENT_CPLUSPLUS | - ISC_LEXCOMMENT_SHELL)); - - CHECK(cfg_create_list(pctx, &cfg_type_filelist, &pctx->open_files)); - CHECK(cfg_create_list(pctx, &cfg_type_filelist, &pctx->closed_files)); - - *ret = pctx; - return (ISC_R_SUCCESS); - - cleanup: - if (pctx->lexer != NULL) - isc_lex_destroy(&pctx->lexer); - CLEANUP_OBJ(pctx->open_files); - CLEANUP_OBJ(pctx->closed_files); - isc_mem_put(mctx, pctx, sizeof(*pctx)); - return (result); -} - -static isc_result_t -parser_openfile(cfg_parser_t *pctx, const char *filename) { - isc_result_t result; - cfg_listelt_t *elt = NULL; - cfg_obj_t *stringobj = NULL; - - result = isc_lex_openfile(pctx->lexer, filename); - if (result != ISC_R_SUCCESS) { - cfg_parser_error(pctx, 0, "open: %s: %s", - filename, isc_result_totext(result)); - goto cleanup; - } - - CHECK(create_string(pctx, filename, &cfg_type_qstring, &stringobj)); - CHECK(create_listelt(pctx, &elt)); - elt->obj = stringobj; - ISC_LIST_APPEND(pctx->open_files->value.list, elt, link); - - return (ISC_R_SUCCESS); - cleanup: - CLEANUP_OBJ(stringobj); - return (result); -} - -void -cfg_parser_setcallback(cfg_parser_t *pctx, - cfg_parsecallback_t callback, - void *arg) -{ - pctx->callback = callback; - pctx->callbackarg = arg; -} - -/* - * Parse a configuration using a pctx where a lexer has already - * been set up with a source. - */ -static isc_result_t -parse2(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - isc_result_t result; - cfg_obj_t *obj = NULL; - - result = cfg_parse_obj(pctx, type, &obj); - - if (pctx->errors != 0) { - /* Errors have been logged. */ - if (result == ISC_R_SUCCESS) - result = ISC_R_FAILURE; - goto cleanup; - } - - if (result != ISC_R_SUCCESS) { - /* Parsing failed but no errors have been logged. */ - cfg_parser_error(pctx, 0, "parsing failed"); - goto cleanup; - } - - CHECK(parse_eof(pctx)); - - *ret = obj; - return (ISC_R_SUCCESS); - - cleanup: - CLEANUP_OBJ(obj); - return (result); -} - -isc_result_t -cfg_parse_file(cfg_parser_t *pctx, const char *filename, - const cfg_type_t *type, cfg_obj_t **ret) -{ - isc_result_t result; - - REQUIRE(filename != NULL); - - CHECK(parser_openfile(pctx, filename)); - CHECK(parse2(pctx, type, ret)); - cleanup: - return (result); -} - - -isc_result_t -cfg_parse_buffer(cfg_parser_t *pctx, isc_buffer_t *buffer, - const cfg_type_t *type, cfg_obj_t **ret) -{ - isc_result_t result; - REQUIRE(buffer != NULL); - CHECK(isc_lex_openbuffer(pctx->lexer, buffer)); - CHECK(parse2(pctx, type, ret)); - cleanup: - return (result); -} - -void -cfg_parser_destroy(cfg_parser_t **pctxp) { - cfg_parser_t *pctx = *pctxp; - isc_lex_destroy(&pctx->lexer); - /* - * Cleaning up open_files does not - * close the files; that was already done - * by closing the lexer. - */ - CLEANUP_OBJ(pctx->open_files); - CLEANUP_OBJ(pctx->closed_files); - isc_mem_put(pctx->mctx, pctx, sizeof(*pctx)); - *pctxp = NULL; -} - -/* - * void - */ -isc_result_t -cfg_parse_void(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - UNUSED(type); - return (cfg_create_obj(pctx, &cfg_type_void, ret)); -} - -void -cfg_print_void(cfg_printer_t *pctx, const cfg_obj_t *obj) { - UNUSED(pctx); - UNUSED(obj); -} - -void -cfg_doc_void(cfg_printer_t *pctx, const cfg_type_t *type) { - UNUSED(pctx); - UNUSED(type); -} - -isc_boolean_t -cfg_obj_isvoid(const cfg_obj_t *obj) { - REQUIRE(obj != NULL); - return (ISC_TF(obj->type->rep == &cfg_rep_void)); -} - -cfg_type_t cfg_type_void = { - "void", cfg_parse_void, cfg_print_void, cfg_doc_void, &cfg_rep_void, - NULL }; - - -/* - * uint32 - */ -isc_result_t -cfg_parse_uint32(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - isc_result_t result; - cfg_obj_t *obj = NULL; - UNUSED(type); - - CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER)); - if (pctx->token.type != isc_tokentype_number) { - cfg_parser_error(pctx, CFG_LOG_NEAR, "expected number"); - return (ISC_R_UNEXPECTEDTOKEN); - } - - CHECK(cfg_create_obj(pctx, &cfg_type_uint32, &obj)); - - obj->value.uint32 = pctx->token.value.as_ulong; - *ret = obj; - cleanup: - return (result); -} - -void -cfg_print_cstr(cfg_printer_t *pctx, const char *s) { - cfg_print_chars(pctx, s, strlen(s)); -} - -void -cfg_print_rawuint(cfg_printer_t *pctx, unsigned int u) { - char buf[32]; - snprintf(buf, sizeof(buf), "%u", u); - cfg_print_cstr(pctx, buf); -} - -void -cfg_print_uint32(cfg_printer_t *pctx, const cfg_obj_t *obj) { - cfg_print_rawuint(pctx, obj->value.uint32); -} - -isc_boolean_t -cfg_obj_isuint32(const cfg_obj_t *obj) { - REQUIRE(obj != NULL); - return (ISC_TF(obj->type->rep == &cfg_rep_uint32)); -} - -isc_uint32_t -cfg_obj_asuint32(const cfg_obj_t *obj) { - REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_uint32); - return (obj->value.uint32); -} - -cfg_type_t cfg_type_uint32 = { - "integer", cfg_parse_uint32, cfg_print_uint32, cfg_doc_terminal, - &cfg_rep_uint32, NULL -}; - - -/* - * uint64 - */ -isc_boolean_t -cfg_obj_isuint64(const cfg_obj_t *obj) { - REQUIRE(obj != NULL); - return (ISC_TF(obj->type->rep == &cfg_rep_uint64)); -} - -isc_uint64_t -cfg_obj_asuint64(const cfg_obj_t *obj) { - REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_uint64); - return (obj->value.uint64); -} - -void -cfg_print_uint64(cfg_printer_t *pctx, const cfg_obj_t *obj) { - char buf[32]; - snprintf(buf, sizeof(buf), "%" ISC_PRINT_QUADFORMAT "u", - obj->value.uint64); - cfg_print_cstr(pctx, buf); -} - -cfg_type_t cfg_type_uint64 = { - "64_bit_integer", NULL, cfg_print_uint64, cfg_doc_terminal, - &cfg_rep_uint64, NULL -}; - -/* - * qstring (quoted string), ustring (unquoted string), astring - * (any string) - */ - -/* Create a string object from a null-terminated C string. */ -static isc_result_t -create_string(cfg_parser_t *pctx, const char *contents, const cfg_type_t *type, - cfg_obj_t **ret) -{ - isc_result_t result; - cfg_obj_t *obj = NULL; - int len; - - CHECK(cfg_create_obj(pctx, type, &obj)); - len = strlen(contents); - obj->value.string.length = len; - obj->value.string.base = isc_mem_get(pctx->mctx, len + 1); - if (obj->value.string.base == 0) { - isc_mem_put(pctx->mctx, obj, sizeof(*obj)); - return (ISC_R_NOMEMORY); - } - memcpy(obj->value.string.base, contents, len); - obj->value.string.base[len] = '\0'; - - *ret = obj; - cleanup: - return (result); -} - -isc_result_t -cfg_parse_qstring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - isc_result_t result; - UNUSED(type); - - CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING)); - if (pctx->token.type != isc_tokentype_qstring) { - cfg_parser_error(pctx, CFG_LOG_NEAR, "expected quoted string"); - return (ISC_R_UNEXPECTEDTOKEN); - } - return (create_string(pctx, - TOKEN_STRING(pctx), - &cfg_type_qstring, - ret)); - cleanup: - return (result); -} - -static isc_result_t -parse_ustring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - isc_result_t result; - UNUSED(type); - - CHECK(cfg_gettoken(pctx, 0)); - if (pctx->token.type != isc_tokentype_string) { - cfg_parser_error(pctx, CFG_LOG_NEAR, "expected unquoted string"); - return (ISC_R_UNEXPECTEDTOKEN); - } - return (create_string(pctx, - TOKEN_STRING(pctx), - &cfg_type_ustring, - ret)); - cleanup: - return (result); -} - -isc_result_t -cfg_parse_astring(cfg_parser_t *pctx, const cfg_type_t *type, - cfg_obj_t **ret) -{ - isc_result_t result; - UNUSED(type); - - CHECK(cfg_getstringtoken(pctx)); - return (create_string(pctx, - TOKEN_STRING(pctx), - &cfg_type_qstring, - ret)); - cleanup: - return (result); -} - -isc_boolean_t -cfg_is_enum(const char *s, const char *const *enums) { - const char * const *p; - for (p = enums; *p != NULL; p++) { - if (strcasecmp(*p, s) == 0) - return (ISC_TRUE); - } - return (ISC_FALSE); -} - -static isc_result_t -check_enum(cfg_parser_t *pctx, cfg_obj_t *obj, const char *const *enums) { - const char *s = obj->value.string.base; - if (cfg_is_enum(s, enums)) - return (ISC_R_SUCCESS); - cfg_parser_error(pctx, 0, "'%s' unexpected", s); - return (ISC_R_UNEXPECTEDTOKEN); -} - -isc_result_t -cfg_parse_enum(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - isc_result_t result; - cfg_obj_t *obj = NULL; - CHECK(parse_ustring(pctx, NULL, &obj)); - CHECK(check_enum(pctx, obj, type->of)); - *ret = obj; - return (ISC_R_SUCCESS); - cleanup: - CLEANUP_OBJ(obj); - return (result); -} - -void -cfg_doc_enum(cfg_printer_t *pctx, const cfg_type_t *type) { - const char * const *p; - cfg_print_chars(pctx, "( ", 2); - for (p = type->of; *p != NULL; p++) { - cfg_print_cstr(pctx, *p); - if (p[1] != NULL) - cfg_print_chars(pctx, " | ", 3); - } - cfg_print_chars(pctx, " )", 2); -} - -void -cfg_print_ustring(cfg_printer_t *pctx, const cfg_obj_t *obj) { - cfg_print_chars(pctx, obj->value.string.base, obj->value.string.length); -} - -static void -print_qstring(cfg_printer_t *pctx, const cfg_obj_t *obj) { - cfg_print_chars(pctx, "\"", 1); - cfg_print_ustring(pctx, obj); - cfg_print_chars(pctx, "\"", 1); -} - -static void -free_string(cfg_parser_t *pctx, cfg_obj_t *obj) { - isc_mem_put(pctx->mctx, obj->value.string.base, - obj->value.string.length + 1); -} - -isc_boolean_t -cfg_obj_isstring(const cfg_obj_t *obj) { - REQUIRE(obj != NULL); - return (ISC_TF(obj->type->rep == &cfg_rep_string)); -} - -const char * -cfg_obj_asstring(const cfg_obj_t *obj) { - REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_string); - return (obj->value.string.base); -} - -/* Quoted string only */ -cfg_type_t cfg_type_qstring = { - "quoted_string", cfg_parse_qstring, print_qstring, cfg_doc_terminal, - &cfg_rep_string, NULL -}; - -/* Unquoted string only */ -cfg_type_t cfg_type_ustring = { - "string", parse_ustring, cfg_print_ustring, cfg_doc_terminal, - &cfg_rep_string, NULL -}; - -/* Any string (quoted or unquoted); printed with quotes */ -cfg_type_t cfg_type_astring = { - "string", cfg_parse_astring, print_qstring, cfg_doc_terminal, - &cfg_rep_string, NULL -}; - -/* - * Booleans - */ - -isc_boolean_t -cfg_obj_isboolean(const cfg_obj_t *obj) { - REQUIRE(obj != NULL); - return (ISC_TF(obj->type->rep == &cfg_rep_boolean)); -} - -isc_boolean_t -cfg_obj_asboolean(const cfg_obj_t *obj) { - REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_boolean); - return (obj->value.boolean); -} - -static isc_result_t -parse_boolean(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) -{ - isc_result_t result; - isc_boolean_t value; - cfg_obj_t *obj = NULL; - UNUSED(type); - - result = cfg_gettoken(pctx, 0); - if (result != ISC_R_SUCCESS) - return (result); - - if (pctx->token.type != isc_tokentype_string) - goto bad_boolean; - - if ((strcasecmp(TOKEN_STRING(pctx), "true") == 0) || - (strcasecmp(TOKEN_STRING(pctx), "yes") == 0) || - (strcmp(TOKEN_STRING(pctx), "1") == 0)) { - value = ISC_TRUE; - } else if ((strcasecmp(TOKEN_STRING(pctx), "false") == 0) || - (strcasecmp(TOKEN_STRING(pctx), "no") == 0) || - (strcmp(TOKEN_STRING(pctx), "0") == 0)) { - value = ISC_FALSE; - } else { - goto bad_boolean; - } - - CHECK(cfg_create_obj(pctx, &cfg_type_boolean, &obj)); - obj->value.boolean = value; - *ret = obj; - return (result); - - bad_boolean: - cfg_parser_error(pctx, CFG_LOG_NEAR, "boolean expected"); - return (ISC_R_UNEXPECTEDTOKEN); - - cleanup: - return (result); -} - -static void -print_boolean(cfg_printer_t *pctx, const cfg_obj_t *obj) { - if (obj->value.boolean) - cfg_print_chars(pctx, "yes", 3); - else - cfg_print_chars(pctx, "no", 2); -} - -cfg_type_t cfg_type_boolean = { - "boolean", parse_boolean, print_boolean, cfg_doc_terminal, - &cfg_rep_boolean, NULL -}; - -/* - * Lists. - */ - -isc_result_t -cfg_create_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **obj) { - isc_result_t result; - CHECK(cfg_create_obj(pctx, type, obj)); - ISC_LIST_INIT((*obj)->value.list); - cleanup: - return (result); -} - -static isc_result_t -create_listelt(cfg_parser_t *pctx, cfg_listelt_t **eltp) { - cfg_listelt_t *elt; - elt = isc_mem_get(pctx->mctx, sizeof(*elt)); - if (elt == NULL) - return (ISC_R_NOMEMORY); - elt->obj = NULL; - ISC_LINK_INIT(elt, link); - *eltp = elt; - return (ISC_R_SUCCESS); -} - -static void -free_list_elt(cfg_parser_t *pctx, cfg_listelt_t *elt) { - cfg_obj_destroy(pctx, &elt->obj); - isc_mem_put(pctx->mctx, elt, sizeof(*elt)); -} - -static void -free_list(cfg_parser_t *pctx, cfg_obj_t *obj) { - cfg_listelt_t *elt, *next; - for (elt = ISC_LIST_HEAD(obj->value.list); - elt != NULL; - elt = next) - { - next = ISC_LIST_NEXT(elt, link); - free_list_elt(pctx, elt); - } -} - -isc_result_t -cfg_parse_listelt(cfg_parser_t *pctx, const cfg_type_t *elttype, - cfg_listelt_t **ret) -{ - isc_result_t result; - cfg_listelt_t *elt = NULL; - cfg_obj_t *value = NULL; - - CHECK(create_listelt(pctx, &elt)); - - result = cfg_parse_obj(pctx, elttype, &value); - if (result != ISC_R_SUCCESS) - goto cleanup; - - elt->obj = value; - - *ret = elt; - return (ISC_R_SUCCESS); - - cleanup: - isc_mem_put(pctx->mctx, elt, sizeof(*elt)); - return (result); -} - -/* - * Parse a homogeneous list whose elements are of type 'elttype' - * and where each element is terminated by a semicolon. - */ -static isc_result_t -parse_list(cfg_parser_t *pctx, const cfg_type_t *listtype, cfg_obj_t **ret) -{ - cfg_obj_t *listobj = NULL; - const cfg_type_t *listof = listtype->of; - isc_result_t result; - cfg_listelt_t *elt = NULL; - - CHECK(cfg_create_list(pctx, listtype, &listobj)); - - for (;;) { - CHECK(cfg_peektoken(pctx, 0)); - if (pctx->token.type == isc_tokentype_special && - pctx->token.value.as_char == /*{*/ '}') - break; - CHECK(cfg_parse_listelt(pctx, listof, &elt)); - CHECK(parse_semicolon(pctx)); - ISC_LIST_APPEND(listobj->value.list, elt, link); - elt = NULL; - } - *ret = listobj; - return (ISC_R_SUCCESS); - - cleanup: - if (elt != NULL) - free_list_elt(pctx, elt); - CLEANUP_OBJ(listobj); - return (result); -} - -static void -print_list(cfg_printer_t *pctx, const cfg_obj_t *obj) { - const cfg_list_t *list = &obj->value.list; - const cfg_listelt_t *elt; - - for (elt = ISC_LIST_HEAD(*list); - elt != NULL; - elt = ISC_LIST_NEXT(elt, link)) { - print_indent(pctx); - cfg_print_obj(pctx, elt->obj); - cfg_print_chars(pctx, ";\n", 2); - } -} - -isc_result_t -cfg_parse_bracketed_list(cfg_parser_t *pctx, const cfg_type_t *type, - cfg_obj_t **ret) -{ - isc_result_t result; - CHECK(cfg_parse_special(pctx, '{')); - CHECK(parse_list(pctx, type, ret)); - CHECK(cfg_parse_special(pctx, '}')); - cleanup: - return (result); -} - -void -cfg_print_bracketed_list(cfg_printer_t *pctx, const cfg_obj_t *obj) { - print_open(pctx); - print_list(pctx, obj); - print_close(pctx); -} - -void -cfg_doc_bracketed_list(cfg_printer_t *pctx, const cfg_type_t *type) { - cfg_print_chars(pctx, "{ ", 2); - cfg_doc_obj(pctx, type->of); - cfg_print_chars(pctx, "; ... }", 7); -} - -/* - * Parse a homogeneous list whose elements are of type 'elttype' - * and where elements are separated by space. The list ends - * before the first semicolon. - */ -isc_result_t -cfg_parse_spacelist(cfg_parser_t *pctx, const cfg_type_t *listtype, - cfg_obj_t **ret) -{ - cfg_obj_t *listobj = NULL; - const cfg_type_t *listof = listtype->of; - isc_result_t result; - - CHECK(cfg_create_list(pctx, listtype, &listobj)); - - for (;;) { - cfg_listelt_t *elt = NULL; - - CHECK(cfg_peektoken(pctx, 0)); - if (pctx->token.type == isc_tokentype_special && - pctx->token.value.as_char == ';') - break; - CHECK(cfg_parse_listelt(pctx, listof, &elt)); - ISC_LIST_APPEND(listobj->value.list, elt, link); - } - *ret = listobj; - return (ISC_R_SUCCESS); - - cleanup: - CLEANUP_OBJ(listobj); - return (result); -} - -void -cfg_print_spacelist(cfg_printer_t *pctx, const cfg_obj_t *obj) { - const cfg_list_t *list = &obj->value.list; - const cfg_listelt_t *elt; - - for (elt = ISC_LIST_HEAD(*list); - elt != NULL; - elt = ISC_LIST_NEXT(elt, link)) { - cfg_print_obj(pctx, elt->obj); - if (ISC_LIST_NEXT(elt, link) != NULL) - cfg_print_chars(pctx, " ", 1); - } -} - -isc_boolean_t -cfg_obj_islist(const cfg_obj_t *obj) { - REQUIRE(obj != NULL); - return (ISC_TF(obj->type->rep == &cfg_rep_list)); -} - -const cfg_listelt_t * -cfg_list_first(const cfg_obj_t *obj) { - REQUIRE(obj == NULL || obj->type->rep == &cfg_rep_list); - if (obj == NULL) - return (NULL); - return (ISC_LIST_HEAD(obj->value.list)); -} - -const cfg_listelt_t * -cfg_list_next(const cfg_listelt_t *elt) { - REQUIRE(elt != NULL); - return (ISC_LIST_NEXT(elt, link)); -} - -const cfg_obj_t * -cfg_listelt_value(const cfg_listelt_t *elt) { - REQUIRE(elt != NULL); - return (elt->obj); -} - -/* - * Maps. - */ - -/* - * Parse a map body. That's something like - * - * "foo 1; bar { glub; }; zap true; zap false;" - * - * i.e., a sequence of option names followed by values and - * terminated by semicolons. Used for the top level of - * the named.conf syntax, as well as for the body of the - * options, view, zone, and other statements. - */ -isc_result_t -cfg_parse_mapbody(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) -{ - const cfg_clausedef_t * const *clausesets = type->of; - isc_result_t result; - const cfg_clausedef_t * const *clauseset; - const cfg_clausedef_t *clause; - cfg_obj_t *value = NULL; - cfg_obj_t *obj = NULL; - cfg_obj_t *eltobj = NULL; - cfg_obj_t *includename = NULL; - isc_symvalue_t symval; - cfg_list_t *list = NULL; - - CHECK(create_map(pctx, type, &obj)); - - obj->value.map.clausesets = clausesets; - - for (;;) { - cfg_listelt_t *elt; - - redo: - /* - * Parse the option name and see if it is known. - */ - CHECK(cfg_gettoken(pctx, 0)); - - if (pctx->token.type != isc_tokentype_string) { - cfg_ungettoken(pctx); - break; - } - - /* - * We accept "include" statements wherever a map body - * clause can occur. - */ - if (strcasecmp(TOKEN_STRING(pctx), "include") == 0) { - /* - * Turn the file name into a temporary configuration - * object just so that it is not overwritten by the - * semicolon token. - */ - CHECK(cfg_parse_obj(pctx, &cfg_type_qstring, &includename)); - CHECK(parse_semicolon(pctx)); - CHECK(parser_openfile(pctx, includename-> - value.string.base)); - cfg_obj_destroy(pctx, &includename); - goto redo; - } - - clause = NULL; - for (clauseset = clausesets; *clauseset != NULL; clauseset++) { - for (clause = *clauseset; - clause->name != NULL; - clause++) { - if (strcasecmp(TOKEN_STRING(pctx), - clause->name) == 0) - goto done; - } - } - done: - if (clause == NULL || clause->name == NULL) { - cfg_parser_error(pctx, CFG_LOG_NOPREP, "unknown option"); - /* - * Try to recover by parsing this option as an unknown - * option and discarding it. - */ - CHECK(cfg_parse_obj(pctx, &cfg_type_unsupported, &eltobj)); - cfg_obj_destroy(pctx, &eltobj); - CHECK(parse_semicolon(pctx)); - continue; - } - - /* Clause is known. */ - - /* Issue warnings if appropriate */ - if ((clause->flags & CFG_CLAUSEFLAG_OBSOLETE) != 0) - cfg_parser_warning(pctx, 0, "option '%s' is obsolete", - clause->name); - if ((clause->flags & CFG_CLAUSEFLAG_NOTIMP) != 0) - cfg_parser_warning(pctx, 0, "option '%s' is " - "not implemented", clause->name); - if ((clause->flags & CFG_CLAUSEFLAG_NYI) != 0) - cfg_parser_warning(pctx, 0, "option '%s' is " - "not implemented", clause->name); - /* - * Don't log options with CFG_CLAUSEFLAG_NEWDEFAULT - * set here - we need to log the *lack* of such an option, - * not its presence. - */ - - /* See if the clause already has a value; if not create one. */ - result = isc_symtab_lookup(obj->value.map.symtab, - clause->name, 0, &symval); - - if ((clause->flags & CFG_CLAUSEFLAG_MULTI) != 0) { - /* Multivalued clause */ - cfg_obj_t *listobj = NULL; - if (result == ISC_R_NOTFOUND) { - CHECK(cfg_create_list(pctx, - &cfg_type_implicitlist, - &listobj)); - symval.as_pointer = listobj; - result = isc_symtab_define(obj->value. - map.symtab, - clause->name, - 1, symval, - isc_symexists_reject); - if (result != ISC_R_SUCCESS) { - cfg_parser_error(pctx, CFG_LOG_NEAR, - "isc_symtab_define(%s) " - "failed", clause->name); - isc_mem_put(pctx->mctx, list, - sizeof(cfg_list_t)); - goto cleanup; - } - } else { - INSIST(result == ISC_R_SUCCESS); - listobj = symval.as_pointer; - } - - elt = NULL; - CHECK(cfg_parse_listelt(pctx, clause->type, &elt)); - CHECK(parse_semicolon(pctx)); - - ISC_LIST_APPEND(listobj->value.list, elt, link); - } else { - /* Single-valued clause */ - if (result == ISC_R_NOTFOUND) { - isc_boolean_t callback = - ISC_TF((clause->flags & - CFG_CLAUSEFLAG_CALLBACK) != 0); - CHECK(parse_symtab_elt(pctx, clause->name, - clause->type, - obj->value.map.symtab, - callback)); - CHECK(parse_semicolon(pctx)); - } else if (result == ISC_R_SUCCESS) { - cfg_parser_error(pctx, CFG_LOG_NEAR, "'%s' redefined", - clause->name); - result = ISC_R_EXISTS; - goto cleanup; - } else { - cfg_parser_error(pctx, CFG_LOG_NEAR, - "isc_symtab_define() failed"); - goto cleanup; - } - } - } - - - *ret = obj; - return (ISC_R_SUCCESS); - - cleanup: - CLEANUP_OBJ(value); - CLEANUP_OBJ(obj); - CLEANUP_OBJ(eltobj); - CLEANUP_OBJ(includename); - return (result); -} - -static isc_result_t -parse_symtab_elt(cfg_parser_t *pctx, const char *name, - cfg_type_t *elttype, isc_symtab_t *symtab, - isc_boolean_t callback) -{ - isc_result_t result; - cfg_obj_t *obj = NULL; - isc_symvalue_t symval; - - CHECK(cfg_parse_obj(pctx, elttype, &obj)); - - if (callback && pctx->callback != NULL) - CHECK(pctx->callback(name, obj, pctx->callbackarg)); - - symval.as_pointer = obj; - CHECK(isc_symtab_define(symtab, name, - 1, symval, - isc_symexists_reject)); - return (ISC_R_SUCCESS); - - cleanup: - CLEANUP_OBJ(obj); - return (result); -} - -/* - * Parse a map; e.g., "{ foo 1; bar { glub; }; zap true; zap false; }" - */ -isc_result_t -cfg_parse_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - isc_result_t result; - CHECK(cfg_parse_special(pctx, '{')); - CHECK(cfg_parse_mapbody(pctx, type, ret)); - CHECK(cfg_parse_special(pctx, '}')); - cleanup: - return (result); -} - -/* - * Subroutine for cfg_parse_named_map() and cfg_parse_addressed_map(). - */ -static isc_result_t -parse_any_named_map(cfg_parser_t *pctx, cfg_type_t *nametype, const cfg_type_t *type, - cfg_obj_t **ret) -{ - isc_result_t result; - cfg_obj_t *idobj = NULL; - cfg_obj_t *mapobj = NULL; - - CHECK(cfg_parse_obj(pctx, nametype, &idobj)); - CHECK(cfg_parse_map(pctx, type, &mapobj)); - mapobj->value.map.id = idobj; - idobj = NULL; - *ret = mapobj; - cleanup: - CLEANUP_OBJ(idobj); - return (result); -} - -/* - * Parse a map identified by a string name. E.g., "name { foo 1; }". - * Used for the "key" and "channel" statements. - */ -isc_result_t -cfg_parse_named_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - return (parse_any_named_map(pctx, &cfg_type_astring, type, ret)); -} - -/* - * Parse a map identified by a network address. - * Used to be used for the "server" statement. - */ -isc_result_t -cfg_parse_addressed_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - return (parse_any_named_map(pctx, &cfg_type_netaddr, type, ret)); -} - -/* - * Parse a map identified by a network prefix. - * Used for the "server" statement. - */ -isc_result_t -cfg_parse_netprefix_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - return (parse_any_named_map(pctx, &cfg_type_netprefix, type, ret)); -} - -void -cfg_print_mapbody(cfg_printer_t *pctx, const cfg_obj_t *obj) { - isc_result_t result = ISC_R_SUCCESS; - - const cfg_clausedef_t * const *clauseset; - - for (clauseset = obj->value.map.clausesets; - *clauseset != NULL; - clauseset++) - { - isc_symvalue_t symval; - const cfg_clausedef_t *clause; - - for (clause = *clauseset; - clause->name != NULL; - clause++) { - result = isc_symtab_lookup(obj->value.map.symtab, - clause->name, 0, &symval); - if (result == ISC_R_SUCCESS) { - cfg_obj_t *obj = symval.as_pointer; - if (obj->type == &cfg_type_implicitlist) { - /* Multivalued. */ - cfg_list_t *list = &obj->value.list; - cfg_listelt_t *elt; - for (elt = ISC_LIST_HEAD(*list); - elt != NULL; - elt = ISC_LIST_NEXT(elt, link)) { - print_indent(pctx); - cfg_print_cstr(pctx, clause->name); - cfg_print_chars(pctx, " ", 1); - cfg_print_obj(pctx, elt->obj); - cfg_print_chars(pctx, ";\n", 2); - } - } else { - /* Single-valued. */ - print_indent(pctx); - cfg_print_cstr(pctx, clause->name); - cfg_print_chars(pctx, " ", 1); - cfg_print_obj(pctx, obj); - cfg_print_chars(pctx, ";\n", 2); - } - } else if (result == ISC_R_NOTFOUND) { - ; /* do nothing */ - } else { - INSIST(0); - } - } - } -} - -void -cfg_doc_mapbody(cfg_printer_t *pctx, const cfg_type_t *type) { - const cfg_clausedef_t * const *clauseset; - const cfg_clausedef_t *clause; - - for (clauseset = type->of; *clauseset != NULL; clauseset++) { - for (clause = *clauseset; - clause->name != NULL; - clause++) { - cfg_print_cstr(pctx, clause->name); - cfg_print_chars(pctx, " ", 1); - cfg_doc_obj(pctx, clause->type); - cfg_print_chars(pctx, ";", 1); - /* XXX print flags here? */ - cfg_print_chars(pctx, "\n\n", 2); - } - } -} - -static struct flagtext { - unsigned int flag; - const char *text; -} flagtexts[] = { - { CFG_CLAUSEFLAG_NOTIMP, "not implemented" }, - { CFG_CLAUSEFLAG_NYI, "not yet implemented" }, - { CFG_CLAUSEFLAG_OBSOLETE, "obsolete" }, - { CFG_CLAUSEFLAG_NEWDEFAULT, "default changed" }, - { 0, NULL } -}; - -void -cfg_print_map(cfg_printer_t *pctx, const cfg_obj_t *obj) { - if (obj->value.map.id != NULL) { - cfg_print_obj(pctx, obj->value.map.id); - cfg_print_chars(pctx, " ", 1); - } - print_open(pctx); - cfg_print_mapbody(pctx, obj); - print_close(pctx); -} - -static void -print_clause_flags(cfg_printer_t *pctx, unsigned int flags) { - struct flagtext *p; - isc_boolean_t first = ISC_TRUE; - for (p = flagtexts; p->flag != 0; p++) { - if ((flags & p->flag) != 0) { - if (first) - cfg_print_chars(pctx, " // ", 4); - else - cfg_print_chars(pctx, ", ", 2); - cfg_print_cstr(pctx, p->text); - first = ISC_FALSE; - } - } -} - -void -cfg_doc_map(cfg_printer_t *pctx, const cfg_type_t *type) { - const cfg_clausedef_t * const *clauseset; - const cfg_clausedef_t *clause; - - if (type->parse == cfg_parse_named_map) { - cfg_doc_obj(pctx, &cfg_type_astring); - cfg_print_chars(pctx, " ", 1); - } else if (type->parse == cfg_parse_addressed_map) { - cfg_doc_obj(pctx, &cfg_type_netaddr); - cfg_print_chars(pctx, " ", 1); - } else if (type->parse == cfg_parse_netprefix_map) { - cfg_doc_obj(pctx, &cfg_type_netprefix); - cfg_print_chars(pctx, " ", 1); - } - - print_open(pctx); - - for (clauseset = type->of; *clauseset != NULL; clauseset++) { - for (clause = *clauseset; - clause->name != NULL; - clause++) { - print_indent(pctx); - cfg_print_cstr(pctx, clause->name); - if (clause->type->print != cfg_print_void) - cfg_print_chars(pctx, " ", 1); - cfg_doc_obj(pctx, clause->type); - cfg_print_chars(pctx, ";", 1); - print_clause_flags(pctx, clause->flags); - cfg_print_chars(pctx, "\n", 1); - } - } - print_close(pctx); -} - -isc_boolean_t -cfg_obj_ismap(const cfg_obj_t *obj) { - REQUIRE(obj != NULL); - return (ISC_TF(obj->type->rep == &cfg_rep_map)); -} - -isc_result_t -cfg_map_get(const cfg_obj_t *mapobj, const char* name, const cfg_obj_t **obj) { - isc_result_t result; - isc_symvalue_t val; - const cfg_map_t *map; - - REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map); - REQUIRE(name != NULL); - REQUIRE(obj != NULL && *obj == NULL); - - map = &mapobj->value.map; - - result = isc_symtab_lookup(map->symtab, name, MAP_SYM, &val); - if (result != ISC_R_SUCCESS) - return (result); - *obj = val.as_pointer; - return (ISC_R_SUCCESS); -} - -const cfg_obj_t * -cfg_map_getname(const cfg_obj_t *mapobj) { - REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map); - return (mapobj->value.map.id); -} - - -/* Parse an arbitrary token, storing its raw text representation. */ -static isc_result_t -parse_token(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - cfg_obj_t *obj = NULL; - isc_result_t result; - isc_region_t r; - - UNUSED(type); - - CHECK(cfg_create_obj(pctx, &cfg_type_token, &obj)); - CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING)); - if (pctx->token.type == isc_tokentype_eof) { - cfg_ungettoken(pctx); - result = ISC_R_EOF; - goto cleanup; - } - - isc_lex_getlasttokentext(pctx->lexer, &pctx->token, &r); - - obj->value.string.base = isc_mem_get(pctx->mctx, r.length + 1); - if (obj->value.string.base == NULL) { - result = ISC_R_NOMEMORY; - goto cleanup; - } - obj->value.string.length = r.length; - memcpy(obj->value.string.base, r.base, r.length); - obj->value.string.base[r.length] = '\0'; - *ret = obj; - return (result); - - cleanup: - if (obj != NULL) - isc_mem_put(pctx->mctx, obj, sizeof(*obj)); - return (result); -} - -cfg_type_t cfg_type_token = { - "token", parse_token, cfg_print_ustring, cfg_doc_terminal, - &cfg_rep_string, NULL -}; - -/* - * An unsupported option. This is just a list of tokens with balanced braces - * ending in a semicolon. - */ - -static isc_result_t -parse_unsupported(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - cfg_obj_t *listobj = NULL; - isc_result_t result; - int braces = 0; - - CHECK(cfg_create_list(pctx, type, &listobj)); - - for (;;) { - cfg_listelt_t *elt = NULL; - - CHECK(cfg_peektoken(pctx, 0)); - if (pctx->token.type == isc_tokentype_special) { - if (pctx->token.value.as_char == '{') - braces++; - else if (pctx->token.value.as_char == '}') - braces--; - else if (pctx->token.value.as_char == ';') - if (braces == 0) - break; - } - if (pctx->token.type == isc_tokentype_eof || braces < 0) { - cfg_parser_error(pctx, CFG_LOG_NEAR, "unexpected token"); - result = ISC_R_UNEXPECTEDTOKEN; - goto cleanup; - } - - CHECK(cfg_parse_listelt(pctx, &cfg_type_token, &elt)); - ISC_LIST_APPEND(listobj->value.list, elt, link); - } - INSIST(braces == 0); - *ret = listobj; - return (ISC_R_SUCCESS); - - cleanup: - CLEANUP_OBJ(listobj); - return (result); -} - -cfg_type_t cfg_type_unsupported = { - "unsupported", parse_unsupported, cfg_print_spacelist, cfg_doc_terminal, - &cfg_rep_list, NULL -}; - -/* - * Try interpreting the current token as a network address. - * - * If CFG_ADDR_WILDOK is set in flags, "*" can be used as a wildcard - * and at least one of CFG_ADDR_V4OK and CFG_ADDR_V6OK must also be set. The - * "*" is interpreted as the IPv4 wildcard address if CFG_ADDR_V4OK is - * set (including the case where CFG_ADDR_V4OK and CFG_ADDR_V6OK are both set), - * and the IPv6 wildcard address otherwise. - */ -static isc_result_t -token_addr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na) { - char *s; - struct in_addr in4a; - struct in6_addr in6a; - - if (pctx->token.type != isc_tokentype_string) - return (ISC_R_UNEXPECTEDTOKEN); - - s = TOKEN_STRING(pctx); - if ((flags & CFG_ADDR_WILDOK) != 0 && strcmp(s, "*") == 0) { - if ((flags & CFG_ADDR_V4OK) != 0) { - isc_netaddr_any(na); - return (ISC_R_SUCCESS); - } else if ((flags & CFG_ADDR_V6OK) != 0) { - isc_netaddr_any6(na); - return (ISC_R_SUCCESS); - } else { - INSIST(0); - } - } else { - if ((flags & (CFG_ADDR_V4OK | CFG_ADDR_V4PREFIXOK)) != 0) { - if (inet_pton(AF_INET, s, &in4a) == 1) { - isc_netaddr_fromin(na, &in4a); - return (ISC_R_SUCCESS); - } - } - if ((flags & CFG_ADDR_V4PREFIXOK) != 0 && - strlen(s) <= 15U) { - char buf[64]; - int i; - - strcpy(buf, s); - for (i = 0; i < 3; i++) { - strcat(buf, ".0"); - if (inet_pton(AF_INET, buf, &in4a) == 1) { - isc_netaddr_fromin(na, &in4a); - return (ISC_R_SUCCESS); - } - } - } - if ((flags & CFG_ADDR_V6OK) != 0 && - strlen(s) <= 127U) { - char buf[128]; /* see lib/bind9/getaddresses.c */ - char *d; /* zone delimiter */ - isc_uint32_t zone = 0; /* scope zone ID */ - - strcpy(buf, s); - d = strchr(buf, '%'); - if (d != NULL) - *d = '\0'; - - if (inet_pton(AF_INET6, buf, &in6a) == 1) { - if (d != NULL) { -#ifdef ISC_PLATFORM_HAVESCOPEID - isc_result_t result; - - result = isc_netscope_pton(AF_INET6, - d + 1, - &in6a, - &zone); - if (result != ISC_R_SUCCESS) - return (result); -#else - return (ISC_R_BADADDRESSFORM); -#endif - } - - isc_netaddr_fromin6(na, &in6a); - isc_netaddr_setzone(na, zone); - return (ISC_R_SUCCESS); - } - } - } - return (ISC_R_UNEXPECTEDTOKEN); -} - -isc_result_t -cfg_parse_rawaddr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na) { - isc_result_t result; - const char *wild = ""; - const char *prefix = ""; - - CHECK(cfg_gettoken(pctx, 0)); - result = token_addr(pctx, flags, na); - if (result == ISC_R_UNEXPECTEDTOKEN) { - if ((flags & CFG_ADDR_WILDOK) != 0) - wild = " or '*'"; - if ((flags & CFG_ADDR_V4PREFIXOK) != 0) - wild = " or IPv4 prefix"; - if ((flags & CFG_ADDR_MASK) == CFG_ADDR_V4OK) - cfg_parser_error(pctx, CFG_LOG_NEAR, - "expected IPv4 address%s%s", - prefix, wild); - else if ((flags & CFG_ADDR_MASK) == CFG_ADDR_V6OK) - cfg_parser_error(pctx, CFG_LOG_NEAR, - "expected IPv6 address%s%s", - prefix, wild); - else - cfg_parser_error(pctx, CFG_LOG_NEAR, - "expected IP address%s%s", - prefix, wild); - } - cleanup: - return (result); -} - -isc_boolean_t -cfg_lookingat_netaddr(cfg_parser_t *pctx, unsigned int flags) { - isc_result_t result; - isc_netaddr_t na_dummy; - result = token_addr(pctx, flags, &na_dummy); - return (ISC_TF(result == ISC_R_SUCCESS)); -} - -isc_result_t -cfg_parse_rawport(cfg_parser_t *pctx, unsigned int flags, in_port_t *port) { - isc_result_t result; - - CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER)); - - if ((flags & CFG_ADDR_WILDOK) != 0 && - pctx->token.type == isc_tokentype_string && - strcmp(TOKEN_STRING(pctx), "*") == 0) { - *port = 0; - return (ISC_R_SUCCESS); - } - if (pctx->token.type != isc_tokentype_number) { - cfg_parser_error(pctx, CFG_LOG_NEAR, - "expected port number or '*'"); - return (ISC_R_UNEXPECTEDTOKEN); - } - if (pctx->token.value.as_ulong >= 65536U) { - cfg_parser_error(pctx, CFG_LOG_NEAR, - "port number out of range"); - return (ISC_R_UNEXPECTEDTOKEN); - } - *port = (in_port_t)(pctx->token.value.as_ulong); - return (ISC_R_SUCCESS); - cleanup: - return (result); -} - -void -cfg_print_rawaddr(cfg_printer_t *pctx, const isc_netaddr_t *na) { - isc_result_t result; - char text[128]; - isc_buffer_t buf; - - isc_buffer_init(&buf, text, sizeof(text)); - result = isc_netaddr_totext(na, &buf); - RUNTIME_CHECK(result == ISC_R_SUCCESS); - cfg_print_chars(pctx, isc_buffer_base(&buf), isc_buffer_usedlength(&buf)); -} - -/* netaddr */ - -static unsigned int netaddr_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK; -static unsigned int netaddr4_flags = CFG_ADDR_V4OK; -static unsigned int netaddr4wild_flags = CFG_ADDR_V4OK | CFG_ADDR_WILDOK; -static unsigned int netaddr6_flags = CFG_ADDR_V6OK; -static unsigned int netaddr6wild_flags = CFG_ADDR_V6OK | CFG_ADDR_WILDOK; - -static isc_result_t -parse_netaddr(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - isc_result_t result; - cfg_obj_t *obj = NULL; - isc_netaddr_t netaddr; - unsigned int flags = *(const unsigned int *)type->of; - - CHECK(cfg_create_obj(pctx, type, &obj)); - CHECK(cfg_parse_rawaddr(pctx, flags, &netaddr)); - isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, 0); - *ret = obj; - return (ISC_R_SUCCESS); - cleanup: - CLEANUP_OBJ(obj); - return (result); -} - -static void -cfg_doc_netaddr(cfg_printer_t *pctx, const cfg_type_t *type) { - const unsigned int *flagp = type->of; - int n = 0; - if (*flagp != CFG_ADDR_V4OK && *flagp != CFG_ADDR_V6OK) - cfg_print_chars(pctx, "( ", 2); - if (*flagp & CFG_ADDR_V4OK) { - cfg_print_cstr(pctx, "<ipv4_address>"); - n++; - } - if (*flagp & CFG_ADDR_V6OK) { - if (n != 0) - cfg_print_chars(pctx, " | ", 3); - cfg_print_cstr(pctx, "<ipv6_address>"); - n++; - } - if (*flagp & CFG_ADDR_WILDOK) { - if (n != 0) - cfg_print_chars(pctx, " | ", 3); - cfg_print_chars(pctx, "*", 1); - n++; - } - if (*flagp != CFG_ADDR_V4OK && *flagp != CFG_ADDR_V6OK) - cfg_print_chars(pctx, " )", 2); -} - -cfg_type_t cfg_type_netaddr = { - "netaddr", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr, - &cfg_rep_sockaddr, &netaddr_flags -}; - -cfg_type_t cfg_type_netaddr4 = { - "netaddr4", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr, - &cfg_rep_sockaddr, &netaddr4_flags -}; - -cfg_type_t cfg_type_netaddr4wild = { - "netaddr4wild", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr, - &cfg_rep_sockaddr, &netaddr4wild_flags -}; - -cfg_type_t cfg_type_netaddr6 = { - "netaddr6", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr, - &cfg_rep_sockaddr, &netaddr6_flags -}; - -cfg_type_t cfg_type_netaddr6wild = { - "netaddr6wild", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr, - &cfg_rep_sockaddr, &netaddr6wild_flags -}; - -/* netprefix */ - -isc_result_t -cfg_parse_netprefix(cfg_parser_t *pctx, const cfg_type_t *type, - cfg_obj_t **ret) -{ - cfg_obj_t *obj = NULL; - isc_result_t result; - isc_netaddr_t netaddr; - unsigned int addrlen, prefixlen; - UNUSED(type); - - CHECK(cfg_parse_rawaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V4PREFIXOK | - CFG_ADDR_V6OK, &netaddr)); - switch (netaddr.family) { - case AF_INET: - addrlen = 32; - break; - case AF_INET6: - addrlen = 128; - break; - default: - addrlen = 0; - INSIST(0); - break; - } - CHECK(cfg_peektoken(pctx, 0)); - if (pctx->token.type == isc_tokentype_special && - pctx->token.value.as_char == '/') { - CHECK(cfg_gettoken(pctx, 0)); /* read "/" */ - CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER)); - if (pctx->token.type != isc_tokentype_number) { - cfg_parser_error(pctx, CFG_LOG_NEAR, - "expected prefix length"); - return (ISC_R_UNEXPECTEDTOKEN); - } - prefixlen = pctx->token.value.as_ulong; - if (prefixlen > addrlen) { - cfg_parser_error(pctx, CFG_LOG_NOPREP, - "invalid prefix length"); - return (ISC_R_RANGE); - } - } else { - prefixlen = addrlen; - } - CHECK(cfg_create_obj(pctx, &cfg_type_netprefix, &obj)); - obj->value.netprefix.address = netaddr; - obj->value.netprefix.prefixlen = prefixlen; - *ret = obj; - return (ISC_R_SUCCESS); - cleanup: - cfg_parser_error(pctx, CFG_LOG_NEAR, "expected network prefix"); - return (result); -} - -static void -print_netprefix(cfg_printer_t *pctx, const cfg_obj_t *obj) { - const cfg_netprefix_t *p = &obj->value.netprefix; - - cfg_print_rawaddr(pctx, &p->address); - cfg_print_chars(pctx, "/", 1); - cfg_print_rawuint(pctx, p->prefixlen); -} - -isc_boolean_t -cfg_obj_isnetprefix(const cfg_obj_t *obj) { - REQUIRE(obj != NULL); - return (ISC_TF(obj->type->rep == &cfg_rep_netprefix)); -} - -void -cfg_obj_asnetprefix(const cfg_obj_t *obj, isc_netaddr_t *netaddr, - unsigned int *prefixlen) { - REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_netprefix); - *netaddr = obj->value.netprefix.address; - *prefixlen = obj->value.netprefix.prefixlen; -} - -cfg_type_t cfg_type_netprefix = { - "netprefix", cfg_parse_netprefix, print_netprefix, cfg_doc_terminal, - &cfg_rep_netprefix, NULL -}; - -static isc_result_t -parse_sockaddrsub(cfg_parser_t *pctx, const cfg_type_t *type, - int flags, cfg_obj_t **ret) -{ - isc_result_t result; - isc_netaddr_t netaddr; - in_port_t port = 0; - cfg_obj_t *obj = NULL; - - CHECK(cfg_create_obj(pctx, type, &obj)); - CHECK(cfg_parse_rawaddr(pctx, flags, &netaddr)); - CHECK(cfg_peektoken(pctx, 0)); - if (pctx->token.type == isc_tokentype_string && - strcasecmp(TOKEN_STRING(pctx), "port") == 0) { - CHECK(cfg_gettoken(pctx, 0)); /* read "port" */ - CHECK(cfg_parse_rawport(pctx, flags, &port)); - } - isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, port); - *ret = obj; - return (ISC_R_SUCCESS); - - cleanup: - CLEANUP_OBJ(obj); - return (result); -} - -static unsigned int sockaddr_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK; -cfg_type_t cfg_type_sockaddr = { - "sockaddr", cfg_parse_sockaddr, cfg_print_sockaddr, cfg_doc_sockaddr, - &cfg_rep_sockaddr, &sockaddr_flags -}; - -isc_result_t -cfg_parse_sockaddr(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - const unsigned int *flagp = type->of; - return (parse_sockaddrsub(pctx, &cfg_type_sockaddr, *flagp, ret)); -} - -void -cfg_print_sockaddr(cfg_printer_t *pctx, const cfg_obj_t *obj) { - isc_netaddr_t netaddr; - in_port_t port; - char buf[ISC_NETADDR_FORMATSIZE]; - - isc_netaddr_fromsockaddr(&netaddr, &obj->value.sockaddr); - isc_netaddr_format(&netaddr, buf, sizeof(buf)); - cfg_print_cstr(pctx, buf); - port = isc_sockaddr_getport(&obj->value.sockaddr); - if (port != 0) { - cfg_print_chars(pctx, " port ", 6); - cfg_print_rawuint(pctx, port); - } -} - -void -cfg_doc_sockaddr(cfg_printer_t *pctx, const cfg_type_t *type) { - const unsigned int *flagp = type->of; - int n = 0; - cfg_print_chars(pctx, "( ", 2); - if (*flagp & CFG_ADDR_V4OK) { - cfg_print_cstr(pctx, "<ipv4_address>"); - n++; - } - if (*flagp & CFG_ADDR_V6OK) { - if (n != 0) - cfg_print_chars(pctx, " | ", 3); - cfg_print_cstr(pctx, "<ipv6_address>"); - n++; - } - if (*flagp & CFG_ADDR_WILDOK) { - if (n != 0) - cfg_print_chars(pctx, " | ", 3); - cfg_print_chars(pctx, "*", 1); - n++; - } - cfg_print_chars(pctx, " ) ", 3); - if (*flagp & CFG_ADDR_WILDOK) { - cfg_print_cstr(pctx, "[ port ( <integer> | * ) ]"); - } else { - cfg_print_cstr(pctx, "[ port <integer> ]"); - } -} - -isc_boolean_t -cfg_obj_issockaddr(const cfg_obj_t *obj) { - REQUIRE(obj != NULL); - return (ISC_TF(obj->type->rep == &cfg_rep_sockaddr)); -} - -const isc_sockaddr_t * -cfg_obj_assockaddr(const cfg_obj_t *obj) { - REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_sockaddr); - return (&obj->value.sockaddr); -} - -isc_result_t -cfg_gettoken(cfg_parser_t *pctx, int options) { - isc_result_t result; - - if (pctx->seen_eof) - return (ISC_R_SUCCESS); - - options |= (ISC_LEXOPT_EOF | ISC_LEXOPT_NOMORE); - - redo: - pctx->token.type = isc_tokentype_unknown; - result = isc_lex_gettoken(pctx->lexer, options, &pctx->token); - pctx->ungotten = ISC_FALSE; - pctx->line = isc_lex_getsourceline(pctx->lexer); - - switch (result) { - case ISC_R_SUCCESS: - if (pctx->token.type == isc_tokentype_eof) { - result = isc_lex_close(pctx->lexer); - INSIST(result == ISC_R_NOMORE || - result == ISC_R_SUCCESS); - - if (isc_lex_getsourcename(pctx->lexer) != NULL) { - /* - * Closed an included file, not the main file. - */ - cfg_listelt_t *elt; - elt = ISC_LIST_TAIL(pctx->open_files-> - value.list); - INSIST(elt != NULL); - ISC_LIST_UNLINK(pctx->open_files-> - value.list, elt, link); - ISC_LIST_APPEND(pctx->closed_files-> - value.list, elt, link); - goto redo; - } - pctx->seen_eof = ISC_TRUE; - } - break; - - case ISC_R_NOSPACE: - /* More understandable than "ran out of space". */ - cfg_parser_error(pctx, CFG_LOG_NEAR, "token too big"); - break; - - case ISC_R_IOERROR: - cfg_parser_error(pctx, 0, "%s", - isc_result_totext(result)); - break; - - default: - cfg_parser_error(pctx, CFG_LOG_NEAR, "%s", - isc_result_totext(result)); - break; - } - return (result); -} - -void -cfg_ungettoken(cfg_parser_t *pctx) { - if (pctx->seen_eof) - return; - isc_lex_ungettoken(pctx->lexer, &pctx->token); - pctx->ungotten = ISC_TRUE; -} - -isc_result_t -cfg_peektoken(cfg_parser_t *pctx, int options) { - isc_result_t result; - CHECK(cfg_gettoken(pctx, options)); - cfg_ungettoken(pctx); - cleanup: - return (result); -} - -/* - * Get a string token, accepting both the quoted and the unquoted form. - * Log an error if the next token is not a string. - */ -static isc_result_t -cfg_getstringtoken(cfg_parser_t *pctx) { - isc_result_t result; - - result = cfg_gettoken(pctx, CFG_LEXOPT_QSTRING); - if (result != ISC_R_SUCCESS) - return (result); - - if (pctx->token.type != isc_tokentype_string && - pctx->token.type != isc_tokentype_qstring) { - cfg_parser_error(pctx, CFG_LOG_NEAR, "expected string"); - return (ISC_R_UNEXPECTEDTOKEN); - } - return (ISC_R_SUCCESS); -} - -void -cfg_parser_error(cfg_parser_t *pctx, unsigned int flags, const char *fmt, ...) { - va_list args; - va_start(args, fmt); - parser_complain(pctx, ISC_FALSE, flags, fmt, args); - va_end(args); - pctx->errors++; -} - -void -cfg_parser_warning(cfg_parser_t *pctx, unsigned int flags, const char *fmt, ...) { - va_list args; - va_start(args, fmt); - parser_complain(pctx, ISC_TRUE, flags, fmt, args); - va_end(args); - pctx->warnings++; -} - -#define MAX_LOG_TOKEN 30 /* How much of a token to quote in log messages. */ - -static char * -current_file(cfg_parser_t *pctx) { - static char none[] = "none"; - cfg_listelt_t *elt; - cfg_obj_t *fileobj; - - if (pctx->open_files == NULL) - return (none); - elt = ISC_LIST_TAIL(pctx->open_files->value.list); - if (elt == NULL) - return (none); - - fileobj = elt->obj; - INSIST(fileobj->type == &cfg_type_qstring); - return (fileobj->value.string.base); -} - -static void -parser_complain(cfg_parser_t *pctx, isc_boolean_t is_warning, - unsigned int flags, const char *format, - va_list args) -{ - char tokenbuf[MAX_LOG_TOKEN + 10]; - static char where[ISC_DIR_PATHMAX + 100]; - static char message[2048]; - int level = ISC_LOG_ERROR; - const char *prep = ""; - size_t len; - - if (is_warning) - level = ISC_LOG_WARNING; - - snprintf(where, sizeof(where), "%s:%u: ", - current_file(pctx), pctx->line); - - len = vsnprintf(message, sizeof(message), format, args); - if (len >= sizeof(message)) - FATAL_ERROR(__FILE__, __LINE__, - "error message would overflow"); - - if ((flags & (CFG_LOG_NEAR|CFG_LOG_BEFORE|CFG_LOG_NOPREP)) != 0) { - isc_region_t r; - - if (pctx->ungotten) - (void)cfg_gettoken(pctx, 0); - - if (pctx->token.type == isc_tokentype_eof) { - snprintf(tokenbuf, sizeof(tokenbuf), "end of file"); - } else if (pctx->token.type == isc_tokentype_unknown) { - flags = 0; - tokenbuf[0] = '\0'; - } else { - isc_lex_getlasttokentext(pctx->lexer, - &pctx->token, &r); - if (r.length > MAX_LOG_TOKEN) - snprintf(tokenbuf, sizeof(tokenbuf), - "'%.*s...'", MAX_LOG_TOKEN, r.base); - else - snprintf(tokenbuf, sizeof(tokenbuf), - "'%.*s'", (int)r.length, r.base); - } - - /* Choose a preposition. */ - if (flags & CFG_LOG_NEAR) - prep = " near "; - else if (flags & CFG_LOG_BEFORE) - prep = " before "; - else - prep = " "; - } else { - tokenbuf[0] = '\0'; - } - isc_log_write(pctx->lctx, CAT, MOD, level, - "%s%s%s%s", where, message, prep, tokenbuf); -} - -void -cfg_obj_log(const cfg_obj_t *obj, isc_log_t *lctx, int level, - const char *fmt, ...) { - va_list ap; - char msgbuf[2048]; - - if (! isc_log_wouldlog(lctx, level)) - return; - - va_start(ap, fmt); - - vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap); - isc_log_write(lctx, CAT, MOD, level, - "%s:%u: %s", - obj->file == NULL ? "<unknown file>" : obj->file, - obj->line, msgbuf); - va_end(ap); -} - -const char * -cfg_obj_file(const cfg_obj_t *obj) { - return (obj->file); -} - -unsigned int -cfg_obj_line(const cfg_obj_t *obj) { - return (obj->line); -} - -isc_result_t -cfg_create_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - cfg_obj_t *obj; - - obj = isc_mem_get(pctx->mctx, sizeof(cfg_obj_t)); - if (obj == NULL) - return (ISC_R_NOMEMORY); - obj->type = type; - obj->file = current_file(pctx); - obj->line = pctx->line; - *ret = obj; - return (ISC_R_SUCCESS); -} - -static void -map_symtabitem_destroy(char *key, unsigned int type, - isc_symvalue_t symval, void *userarg) -{ - cfg_obj_t *obj = symval.as_pointer; - cfg_parser_t *pctx = (cfg_parser_t *)userarg; - - UNUSED(key); - UNUSED(type); - - cfg_obj_destroy(pctx, &obj); -} - - -static isc_result_t -create_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - isc_result_t result; - isc_symtab_t *symtab = NULL; - cfg_obj_t *obj = NULL; - - CHECK(cfg_create_obj(pctx, type, &obj)); - CHECK(isc_symtab_create(pctx->mctx, 5, /* XXX */ - map_symtabitem_destroy, - pctx, ISC_FALSE, &symtab)); - obj->value.map.symtab = symtab; - obj->value.map.id = NULL; - - *ret = obj; - return (ISC_R_SUCCESS); - - cleanup: - if (obj != NULL) - isc_mem_put(pctx->mctx, obj, sizeof(*obj)); - return (result); -} - -static void -free_map(cfg_parser_t *pctx, cfg_obj_t *obj) { - CLEANUP_OBJ(obj->value.map.id); - isc_symtab_destroy(&obj->value.map.symtab); -} - -isc_boolean_t -cfg_obj_istype(const cfg_obj_t *obj, const cfg_type_t *type) { - return (ISC_TF(obj->type == type)); -} - -/* - * Destroy 'obj', a configuration object created in 'pctx'. - */ -void -cfg_obj_destroy(cfg_parser_t *pctx, cfg_obj_t **objp) { - cfg_obj_t *obj = *objp; - obj->type->rep->free(pctx, obj); - isc_mem_put(pctx->mctx, obj, sizeof(cfg_obj_t)); - *objp = NULL; -} - -static void -free_noop(cfg_parser_t *pctx, cfg_obj_t *obj) { - UNUSED(pctx); - UNUSED(obj); -} - -void -cfg_doc_obj(cfg_printer_t *pctx, const cfg_type_t *type) { - type->doc(pctx, type); -} - -void -cfg_doc_terminal(cfg_printer_t *pctx, const cfg_type_t *type) { - cfg_print_chars(pctx, "<", 1); - cfg_print_cstr(pctx, type->name); - cfg_print_chars(pctx, ">", 1); -} - -void -cfg_print_grammar(const cfg_type_t *type, - void (*f)(void *closure, const char *text, int textlen), - void *closure) -{ - cfg_printer_t pctx; - pctx.f = f; - pctx.closure = closure; - pctx.indent = 0; - cfg_doc_obj(&pctx, type); -} |