diff options
| author | 2020-02-11 16:45:42 +0000 | |
|---|---|---|
| committer | 2020-02-11 16:45:42 +0000 | |
| commit | ef60399ab18269e984457246f827e4a7d6e22d01 (patch) | |
| tree | c4fe61f9633f69a77b53fd22048449081c459cd2 /usr.sbin/bind/lib/isccfg/parser.c | |
| parent | add iwx to fw_update (diff) | |
| download | wireguard-openbsd-ef60399ab18269e984457246f827e4a7d6e22d01.tar.xz wireguard-openbsd-ef60399ab18269e984457246f827e4a7d6e22d01.zip | |
Finish moving of dig(1) to /usr/bin/dig by removing the sources in the
old location. dig(1) sources can be found in src/usr.bin/dig.
ok deraadt@
Diffstat (limited to 'usr.sbin/bind/lib/isccfg/parser.c')
| -rw-r--r-- | usr.sbin/bind/lib/isccfg/parser.c | 1296 |
1 files changed, 0 insertions, 1296 deletions
diff --git a/usr.sbin/bind/lib/isccfg/parser.c b/usr.sbin/bind/lib/isccfg/parser.c deleted file mode 100644 index 3471c609017..00000000000 --- a/usr.sbin/bind/lib/isccfg/parser.c +++ /dev/null @@ -1,1296 +0,0 @@ -/* - * Copyright (C) Internet Systems Consortium, Inc. ("ISC") - * - * Permission to use, copy, modify, and/or 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. - */ - -/*! \file */ - -#include <limits.h> -#include <stdlib.h> -#include <string.h> - -#include <isc/buffer.h> -#include <isc/formatcheck.h> -#include <isc/lex.h> -#include <isc/log.h> -#include <isc/net.h> -#include <isc/netaddr.h> -#include <isc/netscope.h> -#include <isc/sockaddr.h> -#include <isc/symtab.h> -#include <isc/util.h> - -#include <isccfg/cfg.h> -#include <isccfg/grammar.h> - -/*! - * Pass one of these flags to cfg_parser_error() to include the - * token text in log message. - */ -#define CFG_LOG_NEAR 0x00000001 /*%< Say "near <token>" */ -#define CFG_LOG_BEFORE 0x00000002 /*%< Say "before <token>" */ -#define CFG_LOG_NOPREP 0x00000004 /*%< Say just "<token>" */ - -isc_logcategory_t cfg_category = { "config", 0 }; -isc_logmodule_t cfg_module = { "isccfg/parser", 0 }; - -/* Shorthand */ -#define CAT &cfg_category -#define MOD &cfg_module - -#define MAP_SYM 1 /* Unique type for isc_symtab */ - -#define TOKEN_STRING(pctx) (pctx->token.value.as_textregion.base) - -#define CFG_LEXOPT_QSTRING (ISC_LEXOPT_QSTRING | ISC_LEXOPT_QSTRINGMULTILINE) - -/* 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 variables */ -cfg_rep_t cfg_rep_string; -cfg_rep_t cfg_rep_list; - -cfg_type_t cfg_type_qstring; -cfg_type_t cfg_type_ustring; -cfg_type_t cfg_type_sstring; -cfg_type_t cfg_type_token; -cfg_type_t cfg_type_unsupported; - -/* - * Forward declarations of static functions. - */ - -static isc_result_t -cfg_gettoken(cfg_parser_t *pctx, int options); - -static isc_result_t -cfg_peektoken(cfg_parser_t *pctx, int options); - -static void -cfg_ungettoken(cfg_parser_t *pctx); - -static isc_result_t -cfg_create_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **objp); - -static isc_result_t -cfg_parse_qstring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret); - -static isc_result_t -cfg_parse_astring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret); - -static isc_result_t -cfg_parse_sstring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret); - -static isc_result_t -cfg_parse_special(cfg_parser_t *pctx, int special); -/*%< Parse a required special character 'special'. */ - -static isc_result_t -cfg_create_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **objp); - -static isc_result_t -cfg_parse_listelt(cfg_parser_t *pctx, const cfg_type_t *elttype, - cfg_listelt_t **ret); - -static isc_result_t -cfg_parse_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret); - -static isc_result_t -cfg_parse_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret); - -static void -cfg_parser_error(cfg_parser_t *pctx, unsigned int flags, - const char *fmt, ...) ISC_FORMAT_PRINTF(3, 4); - -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); - -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_string = { "string", free_string }; -cfg_rep_t cfg_rep_map = { "map", free_map }; -cfg_rep_t cfg_rep_list = { "list", free_list }; - -/* - * Configuration type definitions. - */ - -/* Functions. */ - -static isc_result_t -cfg_parse_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - isc_result_t result; - - REQUIRE(pctx != NULL); - REQUIRE(type != NULL); - REQUIRE(ret != NULL && *ret == NULL); - - result = type->parse(pctx, type, ret); - if (result != ISC_R_SUCCESS) - return (result); - ENSURE(*ret != NULL); - return (ISC_R_SUCCESS); -} - -static isc_result_t -cfg_parse_special(cfg_parser_t *pctx, int special) { - isc_result_t result; - - REQUIRE(pctx != NULL); - - 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, &cfg_rep_list, - &cfg_type_qstring -}; - -isc_result_t -cfg_parser_create(isc_log_t *lctx, cfg_parser_t **ret) { - isc_result_t result; - cfg_parser_t *pctx; - isc_lexspecials_t specials; - - REQUIRE(ret != NULL && *ret == NULL); - - pctx = malloc(sizeof(*pctx)); - if (pctx == NULL) - return (ISC_R_NOMEMORY); - - result = isc_refcount_init(&pctx->references, 1); - if (result != ISC_R_SUCCESS) { - free(pctx); - return (result); - } - - pctx->lctx = lctx; - pctx->lexer = NULL; - pctx->seen_eof = ISC_FALSE; - pctx->ungotten = ISC_FALSE; - pctx->errors = 0; - pctx->open_files = NULL; - pctx->closed_files = NULL; - pctx->line = 0; - pctx->token.type = isc_tokentype_unknown; - pctx->flags = 0; - - memset(specials, 0, sizeof(specials)); - specials['{'] = 1; - specials['}'] = 1; - specials[';'] = 1; - specials['/'] = 1; - specials['"'] = 1; - specials['!'] = 1; - - CHECK(isc_lex_create(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); - free(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); -} - -/* - * 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: %s", - isc_result_totext(result)); - 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(pctx != NULL); - REQUIRE(filename != NULL); - REQUIRE(type != NULL); - REQUIRE(ret != NULL && *ret == NULL); - - CHECK(parser_openfile(pctx, filename)); - CHECK(parse2(pctx, type, ret)); - cleanup: - return (result); -} - -void -cfg_parser_destroy(cfg_parser_t **pctxp) { - cfg_parser_t *pctx; - unsigned int refs; - - REQUIRE(pctxp != NULL && *pctxp != NULL); - - pctx = *pctxp; - *pctxp = NULL; - - isc_refcount_decrement(&pctx->references, &refs); - if (refs == 0) { - 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); - free(pctx); - } -} - -/* - * 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 = malloc(len + 1); - if (obj->value.string.base == 0) { - free(obj); - return (ISC_R_NOMEMORY); - } - memmove(obj->value.string.base, contents, len); - obj->value.string.base[len] = '\0'; - - *ret = obj; - cleanup: - return (result); -} - -static isc_result_t -cfg_parse_qstring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - isc_result_t result; - - REQUIRE(pctx != NULL); - REQUIRE(ret != NULL && *ret == NULL); - - 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); -} - -static isc_result_t -cfg_parse_astring(cfg_parser_t *pctx, const cfg_type_t *type, - cfg_obj_t **ret) -{ - isc_result_t result; - - REQUIRE(pctx != NULL); - REQUIRE(ret != NULL && *ret == NULL); - - UNUSED(type); - - CHECK(cfg_getstringtoken(pctx)); - return (create_string(pctx, - TOKEN_STRING(pctx), - &cfg_type_qstring, - ret)); - cleanup: - return (result); -} - -static isc_result_t -cfg_parse_sstring(cfg_parser_t *pctx, const cfg_type_t *type, - cfg_obj_t **ret) -{ - isc_result_t result; - - REQUIRE(pctx != NULL); - REQUIRE(ret != NULL && *ret == NULL); - - UNUSED(type); - - CHECK(cfg_getstringtoken(pctx)); - return (create_string(pctx, - TOKEN_STRING(pctx), - &cfg_type_sstring, - ret)); - cleanup: - return (result); -} - -static void -free_string(cfg_parser_t *pctx, cfg_obj_t *obj) { - UNUSED(pctx); - free(obj->value.string.base); -} - -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, &cfg_rep_string, NULL -}; - -/* Unquoted string only */ -cfg_type_t cfg_type_ustring = { - "string", parse_ustring, &cfg_rep_string, NULL -}; - -/* Any string (quoted or unquoted); printed with quotes */ -cfg_type_t cfg_type_astring = { - "string", cfg_parse_astring, &cfg_rep_string, NULL -}; - -/* - * Any string (quoted or unquoted); printed with quotes. - * If CFG_PRINTER_XKEY is set when printing the string will be '?' out. - */ -cfg_type_t cfg_type_sstring = { - "string", cfg_parse_sstring, &cfg_rep_string, NULL -}; - -/* - * Booleans - */ - -/* - * Lists. - */ - -static isc_result_t -cfg_create_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **obj) { - isc_result_t result; - - REQUIRE(pctx != NULL); - REQUIRE(type != NULL); - REQUIRE(obj != NULL && *obj == NULL); - - 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) { - UNUSED(pctx); - cfg_listelt_t *elt; - - elt = malloc(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); - free(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); - } -} - -static 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; - - REQUIRE(pctx != NULL); - REQUIRE(elttype != NULL); - REQUIRE(ret != NULL && *ret == 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: - free(elt); - return (result); -} - -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)); -} - -/* - * Return the length of a list object. If obj is NULL or is not - * a list, return 0. - */ -unsigned int -cfg_list_length(const cfg_obj_t *obj, isc_boolean_t recurse) { - const cfg_listelt_t *elt; - unsigned int count = 0; - - if (obj == NULL || !cfg_obj_islist(obj)) - return (0U); - for (elt = cfg_list_first(obj); - elt != NULL; - elt = cfg_list_next(elt)) { - if (recurse && cfg_obj_islist(elt->obj)) { - count += cfg_list_length(elt->obj, recurse); - } else { - count++; - } - } - return (count); -} - -/* - * 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; - - REQUIRE(pctx != NULL); - REQUIRE(type != NULL); - REQUIRE(ret != NULL && *ret == NULL); - - CHECK(create_map(pctx, type, &obj)); - - obj->value.map.clausesets = clausesets; - - for (;;) { - 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. */ - - /* See if the clause already has a value; if not create one. */ - result = isc_symtab_lookup(obj->value.map.symtab, - clause->name, 0, &symval); - - /* Single-valued clause */ - if (result == ISC_R_NOTFOUND) { - CHECK(parse_symtab_elt(pctx, clause->name, - clause->type, - obj->value.map.symtab)); - 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_result_t result; - cfg_obj_t *obj = NULL; - isc_symvalue_t symval; - - CHECK(cfg_parse_obj(pctx, elttype, &obj)); - - 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; }" - */ -static isc_result_t -cfg_parse_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - isc_result_t result; - - REQUIRE(pctx != NULL); - REQUIRE(type != NULL); - REQUIRE(ret != NULL && *ret == NULL); - - 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; - - REQUIRE(pctx != NULL); - REQUIRE(nametype != NULL); - REQUIRE(type != NULL); - REQUIRE(ret != NULL && *ret == NULL); - - CHECK(cfg_parse_obj(pctx, nametype, &idobj)); - CHECK(cfg_parse_map(pctx, type, &mapobj)); - mapobj->value.map.id = idobj; - *ret = mapobj; - return (result); - cleanup: - CLEANUP_OBJ(idobj); - CLEANUP_OBJ(mapobj); - 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)); -} - -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 = malloc(r.length + 1); - if (obj->value.string.base == NULL) { - result = ISC_R_NOMEMORY; - goto cleanup; - } - obj->value.string.length = r.length; - memmove(obj->value.string.base, r.base, r.length); - obj->value.string.base[r.length] = '\0'; - *ret = obj; - return (result); - - cleanup: - if (obj != NULL) - free(obj); - return (result); -} - -cfg_type_t cfg_type_token = { - "token", parse_token, &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_rep_list, NULL -}; - -static isc_result_t -cfg_gettoken(cfg_parser_t *pctx, int options) { - isc_result_t result; - - REQUIRE(pctx != NULL); - - 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); -} - -static void -cfg_ungettoken(cfg_parser_t *pctx) { - REQUIRE(pctx != NULL); - - if (pctx->seen_eof) - return; - isc_lex_ungettoken(pctx->lexer, &pctx->token); - pctx->ungotten = ISC_TRUE; -} - -static isc_result_t -cfg_peektoken(cfg_parser_t *pctx, int options) { - isc_result_t result; - - REQUIRE(pctx != NULL); - - 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); -} - -static void -cfg_parser_error(cfg_parser_t *pctx, unsigned int flags, const char *fmt, ...) { - va_list args; - - REQUIRE(pctx != NULL); - REQUIRE(fmt != NULL); - - va_start(args, fmt); - parser_complain(pctx, ISC_FALSE, flags, fmt, args); - va_end(args); - pctx->errors++; -} - -#define MAX_LOG_TOKEN 30 /* How much of a token to quote in log messages. */ - -static isc_boolean_t -have_current_file(cfg_parser_t *pctx) { - cfg_listelt_t *elt; - if (pctx->open_files == NULL) - return (ISC_FALSE); - - elt = ISC_LIST_TAIL(pctx->open_files->value.list); - if (elt == NULL) - return (ISC_FALSE); - - return (ISC_TRUE); -} - -static char * -current_file(cfg_parser_t *pctx) { - static char none[] = "none"; - cfg_listelt_t *elt; - cfg_obj_t *fileobj; - - if (!have_current_file(pctx)) - return (none); - - elt = ISC_LIST_TAIL(pctx->open_files->value.list); - if (elt == NULL) /* shouldn't be possible, but... */ - 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[PATH_MAX + 100]; - static char message[2048]; - int level = ISC_LOG_ERROR; - const char *prep = ""; - size_t len; - - if (is_warning) - level = ISC_LOG_WARNING; - - where[0] = '\0'; - if (have_current_file(pctx)) - snprintf(where, sizeof(where), "%s:%u: ", - current_file(pctx), pctx->line); - - len = vsnprintf(message, sizeof(message), format, args); -#define ELIPSIS " ... " - if (len >= sizeof(message)) { - message[sizeof(message) - sizeof(ELIPSIS)] = 0; - strlcat(message, ELIPSIS, sizeof(message)); - } - - 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); -} - -static isc_result_t -cfg_create_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - isc_result_t result; - cfg_obj_t *obj; - - REQUIRE(pctx != NULL); - REQUIRE(type != NULL); - REQUIRE(ret != NULL && *ret == NULL); - - obj = malloc(sizeof(cfg_obj_t)); - if (obj == NULL) - return (ISC_R_NOMEMORY); - obj->type = type; - obj->file = current_file(pctx); - obj->line = pctx->line; - result = isc_refcount_init(&obj->references, 1); - if (result != ISC_R_SUCCESS) { - free(obj); - return (result); - } - *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(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) - free(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); -} - -/* - * Destroy 'obj', a configuration object created in 'pctx'. - */ -void -cfg_obj_destroy(cfg_parser_t *pctx, cfg_obj_t **objp) { - cfg_obj_t *obj; - unsigned int refs; - - REQUIRE(objp != NULL && *objp != NULL); - REQUIRE(pctx != NULL); - - obj = *objp; - - isc_refcount_decrement(&obj->references, &refs); - if (refs == 0) { - obj->type->rep->free(pctx, obj); - isc_refcount_destroy(&obj->references); - free(obj); - } - *objp = NULL; -} |
