diff options
Diffstat (limited to 'usr.sbin/bind/lib/isccfg/parser.c')
| -rw-r--r-- | usr.sbin/bind/lib/isccfg/parser.c | 851 |
1 files changed, 698 insertions, 153 deletions
diff --git a/usr.sbin/bind/lib/isccfg/parser.c b/usr.sbin/bind/lib/isccfg/parser.c index 5ddbed7868b..f82b3d91dd2 100644 --- a/usr.sbin/bind/lib/isccfg/parser.c +++ b/usr.sbin/bind/lib/isccfg/parser.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2016 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000-2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,12 +15,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $ISC: parser.c,v 1.112.18.11 2006/02/28 03:10:49 marka Exp $ */ - /*! \file */ #include <config.h> +#include <stdlib.h> + #include <isc/buffer.h> #include <isc/dir.h> #include <isc/formatcheck.h> @@ -29,12 +29,12 @@ #include <isc/mem.h> #include <isc/net.h> #include <isc/netaddr.h> +#include <isc/netscope.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 <isc/util.h> #include <isccfg/cfg.h> #include <isccfg/grammar.h> @@ -50,7 +50,7 @@ /* Check a return value. */ #define CHECK(op) \ - do { result = (op); \ + do { result = (op); \ if (result != ISC_R_SUCCESS) goto cleanup; \ } while (0) @@ -112,16 +112,17 @@ parser_complain(cfg_parser_t *pctx, isc_boolean_t is_warning, * 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 }; +LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_uint32 = { "uint32", free_noop }; +LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_uint64 = { "uint64", free_noop }; +LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_string = { "string", free_string }; +LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_boolean = { "boolean", free_noop }; +LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_map = { "map", free_map }; +LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_list = { "list", free_list }; +LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_tuple = { "tuple", free_tuple }; +LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_sockaddr = { "sockaddr", free_noop }; +LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_netprefix = { "netprefix", free_noop }; +LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_void = { "void", free_noop }; +LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_fixedpoint = { "fixedpoint", free_noop }; /* * Configuration type definitions. @@ -137,11 +138,17 @@ static cfg_type_t cfg_type_implicitlist = { void cfg_print_obj(cfg_printer_t *pctx, const cfg_obj_t *obj) { + REQUIRE(pctx != NULL); + REQUIRE(obj != NULL); + obj->type->print(pctx, obj); } void cfg_print_chars(cfg_printer_t *pctx, const char *text, int len) { + REQUIRE(pctx != NULL); + REQUIRE(text != NULL); + pctx->f(pctx->closure, text, len); } @@ -170,11 +177,15 @@ print_close(cfg_printer_t *pctx) { 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); + + REQUIRE(pctx != NULL); + REQUIRE(type != NULL); + REQUIRE(ret != NULL && *ret == NULL); + result = type->parse(pctx, type, ret); if (result != ISC_R_SUCCESS) return (result); - INSIST(*ret != NULL); + ENSURE(*ret != NULL); return (ISC_R_SUCCESS); } @@ -183,16 +194,31 @@ cfg_print(const cfg_obj_t *obj, void (*f)(void *closure, const char *text, int textlen), void *closure) { + REQUIRE(obj != NULL); + REQUIRE(f != NULL); + + cfg_printx(obj, 0, f, closure); +} + +void +cfg_printx(const cfg_obj_t *obj, unsigned int flags, + void (*f)(void *closure, const char *text, int textlen), + void *closure) +{ cfg_printer_t pctx; + + REQUIRE(obj != NULL); + REQUIRE(f != NULL); + pctx.f = f; pctx.closure = closure; pctx.indent = 0; + pctx.flags = flags; 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; @@ -202,6 +228,10 @@ cfg_create_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { unsigned int nfields = 0; int i; + REQUIRE(pctx != NULL); + REQUIRE(type != NULL); + REQUIRE(ret != NULL && *ret == NULL); + for (f = fields; f->name != NULL; f++) nfields++; @@ -232,6 +262,10 @@ cfg_parse_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) cfg_obj_t *obj = NULL; unsigned int i; + REQUIRE(pctx != NULL); + REQUIRE(type != NULL); + REQUIRE(ret != NULL && *ret == NULL); + 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])); @@ -247,16 +281,22 @@ cfg_parse_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) 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 *fields; const cfg_tuplefielddef_t *f; isc_boolean_t need_space = ISC_FALSE; + REQUIRE(pctx != NULL); + REQUIRE(obj != NULL); + + fields = obj->type->of; + 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); + if (need_space && fieldobj->type->rep != &cfg_rep_void) + cfg_print_cstr(pctx, " "); cfg_print_obj(pctx, fieldobj); - need_space = ISC_TF(fieldobj->type->print != cfg_print_void); + need_space = ISC_TF(need_space || + fieldobj->type->print != cfg_print_void); } } @@ -266,9 +306,14 @@ cfg_doc_tuple(cfg_printer_t *pctx, const cfg_type_t *type) { const cfg_tuplefielddef_t *f; isc_boolean_t need_space = ISC_FALSE; + REQUIRE(pctx != NULL); + REQUIRE(type != NULL); + + fields = type->of; + for (f = fields; f->name != NULL; f++) { if (need_space) - cfg_print_chars(pctx, " ", 1); + cfg_print_cstr(pctx, " "); cfg_doc_obj(pctx, f->type); need_space = ISC_TF(f->type->print != cfg_print_void); } @@ -303,8 +348,9 @@ 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); + REQUIRE(name != NULL); fields = tupleobj->type->of; for (f = fields, i = 0; f->name != NULL; f++, i++) { @@ -317,7 +363,10 @@ cfg_tuple_get(const cfg_obj_t *tupleobj, const char* name) { isc_result_t cfg_parse_special(cfg_parser_t *pctx, int special) { - isc_result_t result; + 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) @@ -338,7 +387,8 @@ cfg_parse_special(cfg_parser_t *pctx, int special) { */ static isc_result_t parse_semicolon(cfg_parser_t *pctx) { - isc_result_t result; + isc_result_t result; + CHECK(cfg_gettoken(pctx, 0)); if (pctx->token.type == isc_tokentype_special && pctx->token.value.as_char == ';') @@ -355,7 +405,8 @@ parse_semicolon(cfg_parser_t *pctx) { */ static isc_result_t parse_eof(cfg_parser_t *pctx) { - isc_result_t result; + isc_result_t result; + CHECK(cfg_gettoken(pctx, 0)); if (pctx->token.type == isc_tokentype_eof) @@ -387,7 +438,15 @@ cfg_parser_create(isc_mem_t *mctx, isc_log_t *lctx, cfg_parser_t **ret) { if (pctx == NULL) return (ISC_R_NOMEMORY); - pctx->mctx = mctx; + pctx->mctx = NULL; + isc_mem_attach(mctx, &pctx->mctx); + + result = isc_refcount_init(&pctx->references, 1); + if (result != ISC_R_SUCCESS) { + isc_mem_putanddetach(&pctx->mctx, pctx, sizeof(*pctx)); + return (result); + } + pctx->lctx = lctx; pctx->lexer = NULL; pctx->seen_eof = ISC_FALSE; @@ -400,6 +459,7 @@ cfg_parser_create(isc_mem_t *mctx, isc_log_t *lctx, cfg_parser_t **ret) { pctx->callback = NULL; pctx->callbackarg = NULL; pctx->token.type = isc_tokentype_unknown; + pctx->flags = 0; memset(specials, 0, sizeof(specials)); specials['{'] = 1; @@ -427,7 +487,7 @@ cfg_parser_create(isc_mem_t *mctx, isc_log_t *lctx, cfg_parser_t **ret) { isc_lex_destroy(&pctx->lexer); CLEANUP_OBJ(pctx->open_files); CLEANUP_OBJ(pctx->closed_files); - isc_mem_put(mctx, pctx, sizeof(*pctx)); + isc_mem_putanddetach(&pctx->mctx, pctx, sizeof(*pctx)); return (result); } @@ -460,6 +520,8 @@ cfg_parser_setcallback(cfg_parser_t *pctx, cfg_parsecallback_t callback, void *arg) { + REQUIRE(pctx != NULL); + pctx->callback = callback; pctx->callbackarg = arg; } @@ -504,7 +566,10 @@ cfg_parse_file(cfg_parser_t *pctx, const char *filename, { 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)); @@ -518,26 +583,48 @@ 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(pctx != NULL); + REQUIRE(type != NULL); REQUIRE(buffer != NULL); - CHECK(isc_lex_openbuffer(pctx->lexer, buffer)); + REQUIRE(ret != NULL && *ret == NULL); + + CHECK(isc_lex_openbuffer(pctx->lexer, buffer)); CHECK(parse2(pctx, type, ret)); cleanup: return (result); } void +cfg_parser_attach(cfg_parser_t *src, cfg_parser_t **dest) { + REQUIRE(src != NULL); + REQUIRE(dest != NULL && *dest == NULL); + + isc_refcount_increment(&src->references, NULL); + *dest = src; +} + +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)); + 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); + isc_mem_putanddetach(&pctx->mctx, pctx, sizeof(*pctx)); + } } /* @@ -545,18 +632,30 @@ cfg_parser_destroy(cfg_parser_t **pctxp) { */ isc_result_t cfg_parse_void(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { + REQUIRE(pctx != NULL); + REQUIRE(ret != NULL && *ret == NULL); + UNUSED(type); + return (cfg_create_obj(pctx, &cfg_type_void, ret)); } void cfg_print_void(cfg_printer_t *pctx, const cfg_obj_t *obj) { + + REQUIRE(pctx != NULL); + REQUIRE(obj != NULL); + UNUSED(pctx); UNUSED(obj); } void cfg_doc_void(cfg_printer_t *pctx, const cfg_type_t *type) { + + REQUIRE(pctx != NULL); + REQUIRE(type != NULL); + UNUSED(pctx); UNUSED(type); } @@ -567,18 +666,101 @@ cfg_obj_isvoid(const cfg_obj_t *obj) { return (ISC_TF(obj->type->rep == &cfg_rep_void)); } -cfg_type_t cfg_type_void = { +LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_void = { "void", cfg_parse_void, cfg_print_void, cfg_doc_void, &cfg_rep_void, NULL }; +/* + * Fixed point + */ +isc_result_t +cfg_parse_fixedpoint(cfg_parser_t *pctx, const cfg_type_t *type, + cfg_obj_t **ret) +{ + isc_result_t result; + cfg_obj_t *obj = NULL; + size_t n1, n2, n3, l; + const char *p; + + REQUIRE(pctx != NULL); + REQUIRE(ret != NULL && *ret == NULL); + + UNUSED(type); + + CHECK(cfg_gettoken(pctx, 0)); + if (pctx->token.type != isc_tokentype_string) { + cfg_parser_error(pctx, CFG_LOG_NEAR, + "expected fixed point number"); + return (ISC_R_UNEXPECTEDTOKEN); + } + + + p = TOKEN_STRING(pctx); + l = strlen(p); + n1 = strspn(p, "0123456789"); + n2 = strspn(p + n1, "."); + n3 = strspn(p + n1 + n2, "0123456789"); + + if ((n1 + n2 + n3 != l) || (n1 + n3 == 0) || + n1 > 5 || n2 > 1 || n3 > 2) { + cfg_parser_error(pctx, CFG_LOG_NEAR, + "expected fixed point number"); + return (ISC_R_UNEXPECTEDTOKEN); + } + + CHECK(cfg_create_obj(pctx, &cfg_type_fixedpoint, &obj)); + + obj->value.uint32 = strtoul(p, NULL, 10) * 100; + switch (n3) { + case 2: + obj->value.uint32 += strtoul(p + n1 + n2, NULL, 10); + break; + case 1: + obj->value.uint32 += strtoul(p + n1 + n2, NULL, 10) * 10; + break; + } + *ret = obj; + + cleanup: + return (result); +} + +void +cfg_print_fixedpoint(cfg_printer_t *pctx, const cfg_obj_t *obj) { + char buf[64]; + int n; + + REQUIRE(pctx != NULL); + REQUIRE(obj != NULL); + + n = snprintf(buf, sizeof(buf), "%u.%02u", + obj->value.uint32/100, obj->value.uint32%100); + INSIST(n > 0 && (size_t)n < sizeof(buf)); + cfg_print_chars(pctx, buf, strlen(buf)); +} + +isc_uint32_t +cfg_obj_asfixedpoint(const cfg_obj_t *obj) { + REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_fixedpoint); + return (obj->value.uint32); +} + +LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_fixedpoint = { + "fixedpoint", cfg_parse_fixedpoint, cfg_print_fixedpoint, + cfg_doc_terminal, &cfg_rep_fixedpoint, 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; + isc_result_t result; cfg_obj_t *obj = NULL; + + REQUIRE(pctx != NULL); + REQUIRE(ret != NULL && *ret == NULL); + UNUSED(type); CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER)); @@ -603,6 +785,7 @@ cfg_print_cstr(cfg_printer_t *pctx, const char *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); } @@ -624,7 +807,7 @@ cfg_obj_asuint32(const cfg_obj_t *obj) { return (obj->value.uint32); } -cfg_type_t cfg_type_uint32 = { +LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_uint32 = { "integer", cfg_parse_uint32, cfg_print_uint32, cfg_doc_terminal, &cfg_rep_uint32, NULL }; @@ -648,12 +831,13 @@ cfg_obj_asuint64(const cfg_obj_t *obj) { 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 = { +LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_uint64 = { "64_bit_integer", NULL, cfg_print_uint64, cfg_doc_terminal, &cfg_rep_uint64, NULL }; @@ -680,7 +864,7 @@ create_string(cfg_parser_t *pctx, const char *contents, const cfg_type_t *type, isc_mem_put(pctx->mctx, obj, sizeof(*obj)); return (ISC_R_NOMEMORY); } - memcpy(obj->value.string.base, contents, len); + memmove(obj->value.string.base, contents, len); obj->value.string.base[len] = '\0'; *ret = obj; @@ -690,7 +874,11 @@ create_string(cfg_parser_t *pctx, const char *contents, const cfg_type_t *type, isc_result_t cfg_parse_qstring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - isc_result_t result; + isc_result_t result; + + REQUIRE(pctx != NULL); + REQUIRE(ret != NULL && *ret == NULL); + UNUSED(type); CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING)); @@ -698,17 +886,16 @@ cfg_parse_qstring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 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)); + 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; + isc_result_t result; + UNUSED(type); CHECK(cfg_gettoken(pctx, 0)); @@ -728,7 +915,11 @@ isc_result_t cfg_parse_astring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - isc_result_t result; + isc_result_t result; + + REQUIRE(pctx != NULL); + REQUIRE(ret != NULL && *ret == NULL); + UNUSED(type); CHECK(cfg_getstringtoken(pctx)); @@ -740,9 +931,33 @@ cfg_parse_astring(cfg_parser_t *pctx, const cfg_type_t *type, return (result); } +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); +} + isc_boolean_t cfg_is_enum(const char *s, const char *const *enums) { const char * const *p; + + REQUIRE(s != NULL); + REQUIRE(enums != NULL); + for (p = enums; *p != NULL; p++) { if (strcasecmp(*p, s) == 0) return (ISC_TRUE); @@ -753,6 +968,7 @@ cfg_is_enum(const char *s, const char *const *enums) { 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); @@ -761,20 +977,28 @@ check_enum(cfg_parser_t *pctx, cfg_obj_t *obj, const char *const *enums) { isc_result_t cfg_parse_enum(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - isc_result_t result; + isc_result_t result; cfg_obj_t *obj = NULL; + + REQUIRE(pctx != NULL); + REQUIRE(type != NULL); + REQUIRE(ret != NULL && *ret == NULL); + CHECK(parse_ustring(pctx, NULL, &obj)); CHECK(check_enum(pctx, obj, type->of)); *ret = obj; return (ISC_R_SUCCESS); cleanup: - CLEANUP_OBJ(obj); + CLEANUP_OBJ(obj); return (result); } void cfg_doc_enum(cfg_printer_t *pctx, const cfg_type_t *type) { const char * const *p; + REQUIRE(pctx != NULL); + REQUIRE(type != NULL); + cfg_print_chars(pctx, "( ", 2); for (p = type->of; *p != NULL; p++) { cfg_print_cstr(pctx, *p); @@ -786,6 +1010,9 @@ cfg_doc_enum(cfg_printer_t *pctx, const cfg_type_t *type) { void cfg_print_ustring(cfg_printer_t *pctx, const cfg_obj_t *obj) { + REQUIRE(pctx != NULL); + REQUIRE(obj != NULL); + cfg_print_chars(pctx, obj->value.string.base, obj->value.string.length); } @@ -797,6 +1024,18 @@ print_qstring(cfg_printer_t *pctx, const cfg_obj_t *obj) { } static void +print_sstring(cfg_printer_t *pctx, const cfg_obj_t *obj) { + cfg_print_chars(pctx, "\"", 1); + if ((pctx->flags & CFG_PRINTER_XKEY) != 0) { + unsigned int len = obj->value.string.length; + while (len-- > 0) + cfg_print_chars(pctx, "?", 1); + } else + 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); @@ -815,24 +1054,33 @@ cfg_obj_asstring(const cfg_obj_t *obj) { } /* Quoted string only */ -cfg_type_t cfg_type_qstring = { +LIBISCCFG_EXTERNAL_DATA 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 = { +LIBISCCFG_EXTERNAL_DATA 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 = { +LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_astring = { "string", cfg_parse_astring, print_qstring, cfg_doc_terminal, &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. + */ +LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_sstring = { + "string", cfg_parse_sstring, print_sstring, cfg_doc_terminal, + &cfg_rep_string, NULL +}; + +/* * Booleans */ @@ -848,12 +1096,16 @@ cfg_obj_asboolean(const cfg_obj_t *obj) { 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 +cfg_parse_boolean(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - isc_result_t result; + isc_result_t result; isc_boolean_t value; cfg_obj_t *obj = NULL; + + REQUIRE(pctx != NULL); + REQUIRE(ret != NULL && ret != NULL); + UNUSED(type); result = cfg_gettoken(pctx, 0); @@ -888,16 +1140,19 @@ parse_boolean(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) return (result); } -static void -print_boolean(cfg_printer_t *pctx, const cfg_obj_t *obj) { +void +cfg_print_boolean(cfg_printer_t *pctx, const cfg_obj_t *obj) { + REQUIRE(pctx != NULL); + REQUIRE(obj != NULL); + 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, +LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_boolean = { + "boolean", cfg_parse_boolean, cfg_print_boolean, cfg_doc_terminal, &cfg_rep_boolean, NULL }; @@ -908,6 +1163,11 @@ cfg_type_t cfg_type_boolean = { 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: @@ -917,6 +1177,7 @@ cfg_create_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **obj) { 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); @@ -952,6 +1213,10 @@ cfg_parse_listelt(cfg_parser_t *pctx, const cfg_type_t *elttype, 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); @@ -1021,6 +1286,11 @@ cfg_parse_bracketed_list(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(parse_list(pctx, type, ret)); CHECK(cfg_parse_special(pctx, '}')); @@ -1030,6 +1300,9 @@ cfg_parse_bracketed_list(cfg_parser_t *pctx, const cfg_type_t *type, void cfg_print_bracketed_list(cfg_printer_t *pctx, const cfg_obj_t *obj) { + REQUIRE(pctx != NULL); + REQUIRE(obj != NULL); + print_open(pctx); print_list(pctx, obj); print_close(pctx); @@ -1037,6 +1310,9 @@ cfg_print_bracketed_list(cfg_printer_t *pctx, const cfg_obj_t *obj) { void cfg_doc_bracketed_list(cfg_printer_t *pctx, const cfg_type_t *type) { + REQUIRE(pctx != NULL); + REQUIRE(type != NULL); + cfg_print_chars(pctx, "{ ", 2); cfg_doc_obj(pctx, type->of); cfg_print_chars(pctx, "; ... }", 7); @@ -1055,6 +1331,10 @@ cfg_parse_spacelist(cfg_parser_t *pctx, const cfg_type_t *listtype, const cfg_type_t *listof = listtype->of; isc_result_t result; + REQUIRE(pctx != NULL); + REQUIRE(listtype != NULL); + REQUIRE(ret != NULL && *ret == NULL); + CHECK(cfg_create_list(pctx, listtype, &listobj)); for (;;) { @@ -1080,6 +1360,9 @@ 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; + REQUIRE(pctx != NULL); + REQUIRE(obj != NULL); + for (elt = ISC_LIST_HEAD(*list); elt != NULL; elt = ISC_LIST_NEXT(elt, link)) { @@ -1109,7 +1392,30 @@ cfg_list_next(const cfg_listelt_t *elt) { return (ISC_LIST_NEXT(elt, link)); } -const cfg_obj_t * +/* + * 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); +} + +cfg_obj_t * cfg_listelt_value(const cfg_listelt_t *elt) { REQUIRE(elt != NULL); return (elt->obj); @@ -1143,6 +1449,10 @@ cfg_parse_mapbody(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) isc_symvalue_t symval; cfg_list_t *list = NULL; + REQUIRE(pctx != NULL); + REQUIRE(type != NULL); + REQUIRE(ret != NULL && *ret == NULL); + CHECK(create_map(pctx, type, &obj)); obj->value.map.clausesets = clausesets; @@ -1214,6 +1524,15 @@ cfg_parse_mapbody(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) if ((clause->flags & CFG_CLAUSEFLAG_NYI) != 0) cfg_parser_warning(pctx, 0, "option '%s' is " "not implemented", clause->name); + + if ((clause->flags & CFG_CLAUSEFLAG_NOTCONFIGURED) != 0) { + cfg_parser_warning(pctx, 0, "option '%s' was not " + "enabled at compile time", + clause->name); + result = ISC_R_FAILURE; + goto cleanup; + } + /* * Don't log options with CFG_CLAUSEFLAG_NEWDEFAULT * set here - we need to log the *lack* of such an option, @@ -1304,7 +1623,7 @@ parse_symtab_elt(cfg_parser_t *pctx, const char *name, if (callback && pctx->callback != NULL) CHECK(pctx->callback(name, obj, pctx->callbackarg)); - + symval.as_pointer = obj; CHECK(isc_symtab_define(symtab, name, 1, symval, @@ -1322,6 +1641,11 @@ parse_symtab_elt(cfg_parser_t *pctx, const char *name, 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, '}')); @@ -1333,25 +1657,31 @@ cfg_parse_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { * 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) +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; - idobj = NULL; *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; }". + * Parse a map identified by a string name. E.g., "name { foo 1; }". * Used for the "key" and "channel" statements. */ isc_result_t @@ -1383,6 +1713,9 @@ cfg_print_mapbody(cfg_printer_t *pctx, const cfg_obj_t *obj) { const cfg_clausedef_t * const *clauseset; + REQUIRE(pctx != NULL); + REQUIRE(obj != NULL); + for (clauseset = obj->value.map.clausesets; *clauseset != NULL; clauseset++) @@ -1396,10 +1729,10 @@ cfg_print_mapbody(cfg_printer_t *pctx, const cfg_obj_t *obj) { 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) { + cfg_obj_t *symobj = symval.as_pointer; + if (symobj->type == &cfg_type_implicitlist) { /* Multivalued. */ - cfg_list_t *list = &obj->value.list; + cfg_list_t *list = &symobj->value.list; cfg_listelt_t *elt; for (elt = ISC_LIST_HEAD(*list); elt != NULL; @@ -1415,7 +1748,7 @@ cfg_print_mapbody(cfg_printer_t *pctx, const cfg_obj_t *obj) { print_indent(pctx); cfg_print_cstr(pctx, clause->name); cfg_print_chars(pctx, " ", 1); - cfg_print_obj(pctx, obj); + cfg_print_obj(pctx, symobj); cfg_print_chars(pctx, ";\n", 2); } } else if (result == ISC_R_NOTFOUND) { @@ -1427,11 +1760,45 @@ cfg_print_mapbody(cfg_printer_t *pctx, const cfg_obj_t *obj) { } } +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" }, + { CFG_CLAUSEFLAG_TESTONLY, "test only" }, + { CFG_CLAUSEFLAG_NOTCONFIGURED, "not configured" }, + { CFG_CLAUSEFLAG_MULTI, "may occur multiple times" }, + { CFG_CLAUSEFLAG_EXPERIMENTAL, "experimental" }, + { 0, NULL } +}; + +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_cstr(pctx, " // "); + else + cfg_print_cstr(pctx, ", "); + cfg_print_cstr(pctx, p->text); + first = ISC_FALSE; + } + } +} + void cfg_doc_mapbody(cfg_printer_t *pctx, const cfg_type_t *type) { const cfg_clausedef_t * const *clauseset; const cfg_clausedef_t *clause; - + + REQUIRE(pctx != NULL); + REQUIRE(type != NULL); + for (clauseset = type->of; *clauseset != NULL; clauseset++) { for (clause = *clauseset; clause->name != NULL; @@ -1439,26 +1806,18 @@ cfg_doc_mapbody(cfg_printer_t *pctx, const cfg_type_t *type) { 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); + cfg_print_cstr(pctx, ";"); + print_clause_flags(pctx, clause->flags); + cfg_print_cstr(pctx, "\n\n"); } } } -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) { + REQUIRE(pctx != NULL); + REQUIRE(obj != NULL); + if (obj->value.map.id != NULL) { cfg_print_obj(pctx, obj->value.map.id); cfg_print_chars(pctx, " ", 1); @@ -1468,27 +1827,14 @@ cfg_print_map(cfg_printer_t *pctx, const cfg_obj_t *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; - + + REQUIRE(pctx != NULL); + REQUIRE(type != NULL); + if (type->parse == cfg_parse_named_map) { cfg_doc_obj(pctx, &cfg_type_astring); cfg_print_chars(pctx, " ", 1); @@ -1499,9 +1845,9 @@ cfg_doc_map(cfg_printer_t *pctx, const cfg_type_t *type) { 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; @@ -1530,13 +1876,13 @@ 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); @@ -1550,12 +1896,21 @@ cfg_map_getname(const cfg_obj_t *mapobj) { return (mapobj->value.map.id); } +unsigned int +cfg_map_count(const cfg_obj_t *mapobj) { + const cfg_map_t *map; + + REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map); + + map = &mapobj->value.map; + return (isc_symtab_count(map->symtab)); +} /* 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_result_t result; isc_region_t r; UNUSED(type); @@ -1576,7 +1931,7 @@ parse_token(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { goto cleanup; } obj->value.string.length = r.length; - memcpy(obj->value.string.base, r.base, r.length); + memmove(obj->value.string.base, r.base, r.length); obj->value.string.base[r.length] = '\0'; *ret = obj; return (result); @@ -1587,7 +1942,7 @@ parse_token(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { return (result); } -cfg_type_t cfg_type_token = { +LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_token = { "token", parse_token, cfg_print_ustring, cfg_doc_terminal, &cfg_rep_string, NULL }; @@ -1636,7 +1991,7 @@ parse_unsupported(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { return (result); } -cfg_type_t cfg_type_unsupported = { +LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_unsupported = { "unsupported", parse_unsupported, cfg_print_spacelist, cfg_doc_terminal, &cfg_rep_list, NULL }; @@ -1646,7 +2001,7 @@ cfg_type_t cfg_type_unsupported = { * * 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 + * "*" 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. */ @@ -1682,9 +2037,9 @@ token_addr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na) { char buf[64]; int i; - strlcpy(buf, s, sizeof(buf)); + strcpy(buf, s); for (i = 0; i < 3; i++) { - strlcat(buf, ".0", sizeof(buf)); + strcat(buf, ".0"); if (inet_pton(AF_INET, buf, &in4a) == 1) { isc_netaddr_fromin(na, &in4a); return (ISC_R_SUCCESS); @@ -1697,7 +2052,7 @@ token_addr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na) { char *d; /* zone delimiter */ isc_uint32_t zone = 0; /* scope zone ID */ - strlcpy(buf, s, sizeof(buf)); + strcpy(buf, s); d = strchr(buf, '%'); if (d != NULL) *d = '\0'; @@ -1733,6 +2088,9 @@ cfg_parse_rawaddr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na) { const char *wild = ""; const char *prefix = ""; + REQUIRE(pctx != NULL); + REQUIRE(na != NULL); + CHECK(cfg_gettoken(pctx, 0)); result = token_addr(pctx, flags, na); if (result == ISC_R_UNEXPECTEDTOKEN) { @@ -1761,6 +2119,9 @@ isc_boolean_t cfg_lookingat_netaddr(cfg_parser_t *pctx, unsigned int flags) { isc_result_t result; isc_netaddr_t na_dummy; + + REQUIRE(pctx != NULL); + result = token_addr(pctx, flags, &na_dummy); return (ISC_TF(result == ISC_R_SUCCESS)); } @@ -1769,6 +2130,9 @@ isc_result_t cfg_parse_rawport(cfg_parser_t *pctx, unsigned int flags, in_port_t *port) { isc_result_t result; + REQUIRE(pctx != NULL); + REQUIRE(port != NULL); + CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER)); if ((flags & CFG_ADDR_WILDOK) != 0 && @@ -1799,12 +2163,40 @@ cfg_print_rawaddr(cfg_printer_t *pctx, const isc_netaddr_t *na) { char text[128]; isc_buffer_t buf; + REQUIRE(pctx != NULL); + REQUIRE(na != NULL); + 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)); } +isc_result_t +cfg_parse_dscp(cfg_parser_t *pctx, isc_dscp_t *dscp) { + isc_result_t result; + + REQUIRE(pctx != NULL); + REQUIRE(dscp != NULL); + + 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); + } + if (pctx->token.value.as_ulong > 63U) { + cfg_parser_error(pctx, CFG_LOG_NEAR, + "dscp out of range"); + return (ISC_R_RANGE); + } + *dscp = (isc_dscp_t)(pctx->token.value.as_ulong); + return (ISC_R_SUCCESS); + cleanup: + return (result); +} + /* netaddr */ static unsigned int netaddr_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK; @@ -1844,39 +2236,40 @@ cfg_doc_netaddr(cfg_printer_t *pctx, const cfg_type_t *type) { if (n != 0) cfg_print_chars(pctx, " | ", 3); cfg_print_cstr(pctx, "<ipv6_address>"); - n++; + n++; } if (*flagp & CFG_ADDR_WILDOK) { if (n != 0) cfg_print_chars(pctx, " | ", 3); cfg_print_chars(pctx, "*", 1); n++; + POST(n); } if (*flagp != CFG_ADDR_V4OK && *flagp != CFG_ADDR_V6OK) cfg_print_chars(pctx, " )", 2); } -cfg_type_t cfg_type_netaddr = { +LIBISCCFG_EXTERNAL_DATA 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 = { +LIBISCCFG_EXTERNAL_DATA 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 = { +LIBISCCFG_EXTERNAL_DATA 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 = { +LIBISCCFG_EXTERNAL_DATA 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 = { +LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_netaddr6wild = { "netaddr6wild", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr, &cfg_rep_sockaddr, &netaddr6wild_flags }; @@ -1890,7 +2283,11 @@ cfg_parse_netprefix(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t *obj = NULL; isc_result_t result; isc_netaddr_t netaddr; - unsigned int addrlen, prefixlen; + unsigned int addrlen = 0, prefixlen; + + REQUIRE(pctx != NULL); + REQUIRE(ret != NULL && *ret == NULL); + UNUSED(type); CHECK(cfg_parse_rawaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V4PREFIXOK | @@ -1903,7 +2300,6 @@ cfg_parse_netprefix(cfg_parser_t *pctx, const cfg_type_t *type, addrlen = 128; break; default: - addrlen = 0; INSIST(0); break; } @@ -1953,13 +2349,17 @@ cfg_obj_isnetprefix(const cfg_obj_t *obj) { void cfg_obj_asnetprefix(const cfg_obj_t *obj, isc_netaddr_t *netaddr, - unsigned int *prefixlen) { + unsigned int *prefixlen) +{ REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_netprefix); + REQUIRE(netaddr != NULL); + REQUIRE(prefixlen != NULL); + *netaddr = obj->value.netprefix.address; *prefixlen = obj->value.netprefix.prefixlen; } -cfg_type_t cfg_type_netprefix = { +LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_netprefix = { "netprefix", cfg_parse_netprefix, print_netprefix, cfg_doc_terminal, &cfg_rep_netprefix, NULL }; @@ -1971,17 +2371,43 @@ parse_sockaddrsub(cfg_parser_t *pctx, const cfg_type_t *type, isc_result_t result; isc_netaddr_t netaddr; in_port_t port = 0; + isc_dscp_t dscp = -1; cfg_obj_t *obj = NULL; + int have_port = 0, have_dscp = 0; 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)); + for (;;) { + CHECK(cfg_peektoken(pctx, 0)); + if (pctx->token.type == isc_tokentype_string) { + if (strcasecmp(TOKEN_STRING(pctx), "port") == 0) { + CHECK(cfg_gettoken(pctx, 0)); /* read "port" */ + CHECK(cfg_parse_rawport(pctx, flags, &port)); + ++have_port; + } else if ((flags & CFG_ADDR_DSCPOK) != 0 && + strcasecmp(TOKEN_STRING(pctx), "dscp") == 0) + { + CHECK(cfg_gettoken(pctx, 0)); /* read "dscp" */ + CHECK(cfg_parse_dscp(pctx, &dscp)); + ++have_dscp; + } else + break; + } else + break; + } + if (have_port > 1) { + cfg_parser_error(pctx, 0, "expected at most one port"); + result = ISC_R_UNEXPECTEDTOKEN; + goto cleanup; + } + + if (have_dscp > 1) { + cfg_parser_error(pctx, 0, "expected at most one dscp"); + result = ISC_R_UNEXPECTEDTOKEN; + goto cleanup; } isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, port); + obj->value.sockaddrdscp.dscp = dscp; *ret = obj; return (ISC_R_SUCCESS); @@ -1991,14 +2417,28 @@ parse_sockaddrsub(cfg_parser_t *pctx, const cfg_type_t *type, } static unsigned int sockaddr_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK; -cfg_type_t cfg_type_sockaddr = { +LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_sockaddr = { "sockaddr", cfg_parse_sockaddr, cfg_print_sockaddr, cfg_doc_sockaddr, &cfg_rep_sockaddr, &sockaddr_flags }; +static unsigned int sockaddrdscp_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK | + CFG_ADDR_DSCPOK; +LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_sockaddrdscp = { + "sockaddr", cfg_parse_sockaddr, cfg_print_sockaddr, cfg_doc_sockaddr, + &cfg_rep_sockaddr, &sockaddrdscp_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; + const unsigned int *flagp; + + REQUIRE(pctx != NULL); + REQUIRE(type != NULL); + REQUIRE(ret != NULL && *ret == NULL); + + flagp = type->of; + return (parse_sockaddrsub(pctx, &cfg_type_sockaddr, *flagp, ret)); } @@ -2008,6 +2448,9 @@ cfg_print_sockaddr(cfg_printer_t *pctx, const cfg_obj_t *obj) { in_port_t port; char buf[ISC_NETADDR_FORMATSIZE]; + REQUIRE(pctx != NULL); + REQUIRE(obj != NULL); + isc_netaddr_fromsockaddr(&netaddr, &obj->value.sockaddr); isc_netaddr_format(&netaddr, buf, sizeof(buf)); cfg_print_cstr(pctx, buf); @@ -2016,12 +2459,20 @@ cfg_print_sockaddr(cfg_printer_t *pctx, const cfg_obj_t *obj) { cfg_print_chars(pctx, " port ", 6); cfg_print_rawuint(pctx, port); } + if (obj->value.sockaddrdscp.dscp != -1) { + cfg_print_chars(pctx, " dscp ", 6); + cfg_print_rawuint(pctx, obj->value.sockaddrdscp.dscp); + } } void cfg_doc_sockaddr(cfg_printer_t *pctx, const cfg_type_t *type) { const unsigned int *flagp = type->of; int n = 0; + + REQUIRE(pctx != NULL); + REQUIRE(type != NULL); + cfg_print_chars(pctx, "( ", 2); if (*flagp & CFG_ADDR_V4OK) { cfg_print_cstr(pctx, "<ipv4_address>"); @@ -2031,13 +2482,14 @@ cfg_doc_sockaddr(cfg_printer_t *pctx, const cfg_type_t *type) { if (n != 0) cfg_print_chars(pctx, " | ", 3); cfg_print_cstr(pctx, "<ipv6_address>"); - n++; + n++; } if (*flagp & CFG_ADDR_WILDOK) { if (n != 0) cfg_print_chars(pctx, " | ", 3); cfg_print_chars(pctx, "*", 1); n++; + POST(n); } cfg_print_chars(pctx, " ) ", 3); if (*flagp & CFG_ADDR_WILDOK) { @@ -2045,6 +2497,9 @@ cfg_doc_sockaddr(cfg_printer_t *pctx, const cfg_type_t *type) { } else { cfg_print_cstr(pctx, "[ port <integer> ]"); } + if ((*flagp & CFG_ADDR_DSCPOK) != 0) { + cfg_print_cstr(pctx, " [ dscp <integer> ]"); + } } isc_boolean_t @@ -2059,10 +2514,18 @@ cfg_obj_assockaddr(const cfg_obj_t *obj) { return (&obj->value.sockaddr); } +isc_dscp_t +cfg_obj_getdscp(const cfg_obj_t *obj) { + REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_sockaddr); + return (obj->value.sockaddrdscp.dscp); +} + 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); @@ -2119,6 +2582,8 @@ cfg_gettoken(cfg_parser_t *pctx, int options) { void cfg_ungettoken(cfg_parser_t *pctx) { + REQUIRE(pctx != NULL); + if (pctx->seen_eof) return; isc_lex_ungettoken(pctx->lexer, &pctx->token); @@ -2128,6 +2593,9 @@ cfg_ungettoken(cfg_parser_t *pctx) { 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: @@ -2157,6 +2625,10 @@ cfg_getstringtoken(cfg_parser_t *pctx) { 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); @@ -2166,6 +2638,10 @@ cfg_parser_error(cfg_parser_t *pctx, unsigned int flags, const char *fmt, ...) { void cfg_parser_warning(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_TRUE, flags, fmt, args); va_end(args); @@ -2174,16 +2650,30 @@ cfg_parser_warning(cfg_parser_t *pctx, unsigned int flags, const char *fmt, ...) #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 (pctx->open_files == NULL) + if (!have_current_file(pctx)) return (none); + elt = ISC_LIST_TAIL(pctx->open_files->value.list); - if (elt == NULL) + if (elt == NULL) /* shouldn't be possible, but... */ return (none); fileobj = elt->obj; @@ -2206,13 +2696,16 @@ parser_complain(cfg_parser_t *pctx, isc_boolean_t is_warning, if (is_warning) level = ISC_LOG_WARNING; - snprintf(where, sizeof(where), "%s:%u: ", - current_file(pctx), pctx->line); + 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); - if (len == -1 || len >= sizeof(message)) - FATAL_ERROR(__FILE__, __LINE__, - "error message would overflow"); +#define ELIPSIS " ... " + if (len >= sizeof(message)) + strcpy(message + sizeof(message) - sizeof(ELIPSIS) - 1, + ELIPSIS); if ((flags & (CFG_LOG_NEAR|CFG_LOG_BEFORE|CFG_LOG_NOPREP)) != 0) { isc_region_t r; @@ -2256,43 +2749,63 @@ cfg_obj_log(const cfg_obj_t *obj, isc_log_t *lctx, int level, va_list ap; char msgbuf[2048]; + REQUIRE(obj != NULL); + REQUIRE(fmt != NULL); + 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); + if (obj->file != NULL) { + isc_log_write(lctx, CAT, MOD, level, + "%s:%u: %s", obj->file, obj->line, msgbuf); + } else { + isc_log_write(lctx, CAT, MOD, level, "%s", msgbuf); + } } const char * cfg_obj_file(const cfg_obj_t *obj) { + REQUIRE(obj != NULL); + return (obj->file); } unsigned int cfg_obj_line(const cfg_obj_t *obj) { + REQUIRE(obj != NULL); + return (obj->line); } 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 = 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; + result = isc_refcount_init(&obj->references, 1); + if (result != ISC_R_SUCCESS) { + isc_mem_put(pctx->mctx, obj, sizeof(cfg_obj_t)); + return (result); + } *ret = obj; return (ISC_R_SUCCESS); } + static void map_symtabitem_destroy(char *key, unsigned int type, isc_symvalue_t symval, void *userarg) @@ -2337,6 +2850,10 @@ free_map(cfg_parser_t *pctx, cfg_obj_t *obj) { isc_boolean_t cfg_obj_istype(const cfg_obj_t *obj, const cfg_type_t *type) { + + REQUIRE(obj != NULL); + REQUIRE(type != NULL); + return (ISC_TF(obj->type == type)); } @@ -2345,12 +2862,32 @@ cfg_obj_istype(const cfg_obj_t *obj, const cfg_type_t *type) { */ 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)); + 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); + isc_mem_put(pctx->mctx, obj, sizeof(cfg_obj_t)); + } *objp = NULL; } +void +cfg_obj_attach(cfg_obj_t *src, cfg_obj_t **dest) { + REQUIRE(src != NULL); + REQUIRE(dest != NULL && *dest == NULL); + + isc_refcount_increment(&src->references, NULL); + *dest = src; +} + static void free_noop(cfg_parser_t *pctx, cfg_obj_t *obj) { UNUSED(pctx); @@ -2359,11 +2896,17 @@ free_noop(cfg_parser_t *pctx, cfg_obj_t *obj) { void cfg_doc_obj(cfg_printer_t *pctx, const cfg_type_t *type) { + REQUIRE(pctx != NULL); + REQUIRE(type != NULL); + type->doc(pctx, type); } void cfg_doc_terminal(cfg_printer_t *pctx, const cfg_type_t *type) { + REQUIRE(pctx != NULL); + REQUIRE(type != NULL); + cfg_print_chars(pctx, "<", 1); cfg_print_cstr(pctx, type->name); cfg_print_chars(pctx, ">", 1); @@ -2375,8 +2918,10 @@ cfg_print_grammar(const cfg_type_t *type, void *closure) { cfg_printer_t pctx; + pctx.f = f; pctx.closure = closure; pctx.indent = 0; + pctx.flags = 0; cfg_doc_obj(&pctx, type); } |
