summaryrefslogtreecommitdiffstats
path: root/usr.sbin/bind/lib/isccfg/parser.c
diff options
context:
space:
mode:
authorflorian <florian@openbsd.org>2020-02-11 16:45:42 +0000
committerflorian <florian@openbsd.org>2020-02-11 16:45:42 +0000
commitef60399ab18269e984457246f827e4a7d6e22d01 (patch)
treec4fe61f9633f69a77b53fd22048449081c459cd2 /usr.sbin/bind/lib/isccfg/parser.c
parentadd iwx to fw_update (diff)
downloadwireguard-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.c1296
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;
-}