summaryrefslogtreecommitdiffstats
path: root/usr.sbin/bind/lib/isccfg/parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/bind/lib/isccfg/parser.c')
-rw-r--r--usr.sbin/bind/lib/isccfg/parser.c851
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);
}