mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-30 14:07:59 +00:00
the values of the notify and dialup options may now be of either boolean or
string types; added cfg_obj_is*() functions for determining the type of a configuration object; reordered some functions in parser.c
This commit is contained in:
@@ -15,7 +15,7 @@
|
||||
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id: cfg.h,v 1.11 2001/02/22 23:59:28 bwelling Exp $ */
|
||||
/* $Id: cfg.h,v 1.12 2001/02/23 00:15:55 gson Exp $ */
|
||||
|
||||
#ifndef DNS_CFG_H
|
||||
#define DNS_CFG_H 1
|
||||
@@ -138,6 +138,19 @@ cfg_parser_destroy(cfg_parser_t **pctxp);
|
||||
* Destroy a configuration parser.
|
||||
*/
|
||||
|
||||
isc_boolean_t
|
||||
cfg_obj_isvoid(cfg_obj_t *obj);
|
||||
/*
|
||||
* Return true iff 'obj' is of void type (e.g., an optional
|
||||
* value not specified).
|
||||
*/
|
||||
|
||||
isc_boolean_t
|
||||
cfg_obj_ismap(cfg_obj_t *obj);
|
||||
/*
|
||||
* Return true iff 'obj' is of a map type.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
cfg_map_get(cfg_obj_t *mapobj, const char* name, cfg_obj_t **obj);
|
||||
/*
|
||||
@@ -167,6 +180,12 @@ cfg_map_getname(cfg_obj_t *mapobj);
|
||||
* or NULL if the map object does not have a name.
|
||||
*/
|
||||
|
||||
isc_boolean_t
|
||||
cfg_obj_istuple(cfg_obj_t *obj);
|
||||
/*
|
||||
* Return true iff 'obj' is of a map type.
|
||||
*/
|
||||
|
||||
cfg_obj_t *
|
||||
cfg_tuple_get(cfg_obj_t *tupleobj, const char* name);
|
||||
/*
|
||||
@@ -179,6 +198,12 @@ cfg_tuple_get(cfg_obj_t *tupleobj, const char* name);
|
||||
* fields of said tuple type.
|
||||
*/
|
||||
|
||||
isc_boolean_t
|
||||
cfg_obj_isuint32(cfg_obj_t *obj);
|
||||
/*
|
||||
* Return true iff 'obj' is of integer type.
|
||||
*/
|
||||
|
||||
isc_uint32_t
|
||||
cfg_obj_asuint32(cfg_obj_t *obj);
|
||||
/*
|
||||
@@ -191,6 +216,12 @@ cfg_obj_asuint32(cfg_obj_t *obj);
|
||||
* A 32-bit unsigned integer.
|
||||
*/
|
||||
|
||||
isc_boolean_t
|
||||
cfg_obj_isstring(cfg_obj_t *obj);
|
||||
/*
|
||||
* Return true iff 'obj' is of string type.
|
||||
*/
|
||||
|
||||
char *
|
||||
cfg_obj_asstring(cfg_obj_t *obj);
|
||||
/*
|
||||
@@ -204,6 +235,12 @@ cfg_obj_asstring(cfg_obj_t *obj);
|
||||
* A pointer to a null terminated string.
|
||||
*/
|
||||
|
||||
isc_boolean_t
|
||||
cfg_obj_isboolean(cfg_obj_t *obj);
|
||||
/*
|
||||
* Return true iff 'obj' is of a boolean type.
|
||||
*/
|
||||
|
||||
isc_boolean_t
|
||||
cfg_obj_asboolean(cfg_obj_t *obj);
|
||||
/*
|
||||
@@ -216,6 +253,12 @@ cfg_obj_asboolean(cfg_obj_t *obj);
|
||||
* A boolean value.
|
||||
*/
|
||||
|
||||
isc_boolean_t
|
||||
cfg_obj_issockaddr(cfg_obj_t *obj);
|
||||
/*
|
||||
* Return true iff 'obj' is of sockaddr type.
|
||||
*/
|
||||
|
||||
isc_sockaddr_t *
|
||||
cfg_obj_assockaddr(cfg_obj_t *obj);
|
||||
/*
|
||||
@@ -229,6 +272,12 @@ cfg_obj_assockaddr(cfg_obj_t *obj);
|
||||
* if necessary.
|
||||
*/
|
||||
|
||||
isc_boolean_t
|
||||
cfg_obj_islist(cfg_obj_t *obj);
|
||||
/*
|
||||
* Return true iff 'obj' is of list type.
|
||||
*/
|
||||
|
||||
cfg_listelt_t *
|
||||
cfg_list_first(cfg_obj_t *obj);
|
||||
/*
|
||||
|
@@ -15,7 +15,7 @@
|
||||
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id: parser.c,v 1.19 2001/02/22 23:59:27 bwelling Exp $ */
|
||||
/* $Id: parser.c,v 1.20 2001/02/23 00:15:53 gson Exp $ */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
@@ -387,6 +387,7 @@ cfg_rep_t cfg_rep_void = { "void", free_noop };
|
||||
*/
|
||||
|
||||
static cfg_type_t cfg_type_boolean;
|
||||
static cfg_type_t cfg_type_boolean_or_ustring;
|
||||
static cfg_type_t cfg_type_uint32;
|
||||
static cfg_type_t cfg_type_qstring;
|
||||
static cfg_type_t cfg_type_astring;
|
||||
@@ -429,7 +430,7 @@ static cfg_type_t cfg_type_server_key_kludge;
|
||||
static cfg_type_t cfg_type_optional_facility;
|
||||
static cfg_type_t cfg_type_logseverity;
|
||||
static cfg_type_t cfg_type_lwres;
|
||||
|
||||
static cfg_type_t cfg_type_boolean_or_ustring;
|
||||
|
||||
/*
|
||||
* Configuration type definitions.
|
||||
@@ -837,9 +838,9 @@ static cfg_clausedef_t
|
||||
zone_clauses[] = {
|
||||
{ "allow-query", &cfg_type_bracketed_aml, 0 },
|
||||
{ "allow-transfer", &cfg_type_bracketed_aml, 0 },
|
||||
{ "notify", &cfg_type_ustring, 0 },
|
||||
{ "notify", &cfg_type_boolean_or_ustring, 0 },
|
||||
{ "also-notify", &cfg_type_portiplist, 0 },
|
||||
{ "dialup", &cfg_type_ustring, 0 },
|
||||
{ "dialup", &cfg_type_boolean_or_ustring, 0 },
|
||||
{ "forward", &cfg_type_ustring, 0 },
|
||||
{ "forwarders", &cfg_type_portiplist, 0 },
|
||||
{ "maintain-ixfr-base", &cfg_type_boolean, 0 },
|
||||
@@ -1134,6 +1135,12 @@ free_tuple(cfg_parser_t *pctx, cfg_obj_t *obj) {
|
||||
nfields * sizeof(cfg_obj_t *));
|
||||
}
|
||||
|
||||
isc_boolean_t
|
||||
cfg_obj_istuple(cfg_obj_t *obj) {
|
||||
REQUIRE(obj != NULL);
|
||||
return (ISC_TF(obj->type->rep == &cfg_rep_tuple));
|
||||
}
|
||||
|
||||
cfg_obj_t *
|
||||
cfg_tuple_get(cfg_obj_t *tupleobj, const char* name) {
|
||||
unsigned int i;
|
||||
@@ -1368,31 +1375,6 @@ cfg_parser_destroy(cfg_parser_t **pctxp) {
|
||||
*pctxp = NULL;
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
cfg_map_get(cfg_obj_t *mapobj, const char* name, cfg_obj_t **obj) {
|
||||
isc_result_t result;
|
||||
isc_symvalue_t val;
|
||||
cfg_map_t *map;
|
||||
|
||||
REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map);
|
||||
REQUIRE(name != NULL);
|
||||
REQUIRE(obj != NULL && *obj == NULL);
|
||||
|
||||
map = &mapobj->value.map;
|
||||
|
||||
result = isc_symtab_lookup(map->symtab, name, MAP_SYM, &val);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (result);
|
||||
*obj = val.as_pointer;
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
cfg_obj_t *
|
||||
cfg_map_getname(cfg_obj_t *mapobj) {
|
||||
REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map);
|
||||
return (mapobj->value.map.id);
|
||||
}
|
||||
|
||||
/*
|
||||
* void
|
||||
*/
|
||||
@@ -1407,6 +1389,13 @@ print_void(cfg_printer_t *pctx, cfg_obj_t *obj) {
|
||||
UNUSED(pctx);
|
||||
UNUSED(obj);
|
||||
}
|
||||
|
||||
isc_boolean_t
|
||||
cfg_obj_isvoid(cfg_obj_t *obj) {
|
||||
REQUIRE(obj != NULL);
|
||||
return (ISC_TF(obj->type->rep == &cfg_rep_void));
|
||||
}
|
||||
|
||||
static cfg_type_t cfg_type_void = {
|
||||
"void", parse_void, print_void, &cfg_rep_void, NULL };
|
||||
|
||||
@@ -1451,6 +1440,12 @@ print_uint32(cfg_printer_t *pctx, cfg_obj_t *obj) {
|
||||
print_uint(pctx, obj->value.uint32);
|
||||
}
|
||||
|
||||
isc_boolean_t
|
||||
cfg_obj_isuint32(cfg_obj_t *obj) {
|
||||
REQUIRE(obj != NULL);
|
||||
return (ISC_TF(obj->type->rep == &cfg_rep_uint32));
|
||||
}
|
||||
|
||||
isc_uint32_t
|
||||
cfg_obj_asuint32(cfg_obj_t *obj) {
|
||||
REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_uint32);
|
||||
@@ -1592,24 +1587,30 @@ free_string(cfg_parser_t *pctx, cfg_obj_t *obj) {
|
||||
obj->value.string.length + 1);
|
||||
}
|
||||
|
||||
isc_boolean_t
|
||||
cfg_obj_isstring(cfg_obj_t *obj) {
|
||||
REQUIRE(obj != NULL);
|
||||
return (ISC_TF(obj->type->rep == &cfg_rep_string));
|
||||
}
|
||||
|
||||
char *
|
||||
cfg_obj_asstring(cfg_obj_t *obj) {
|
||||
REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_string);
|
||||
return (obj->value.string.base);
|
||||
}
|
||||
|
||||
isc_boolean_t
|
||||
cfg_obj_isboolean(cfg_obj_t *obj) {
|
||||
REQUIRE(obj != NULL);
|
||||
return (ISC_TF(obj->type->rep == &cfg_rep_boolean));
|
||||
}
|
||||
|
||||
isc_boolean_t
|
||||
cfg_obj_asboolean(cfg_obj_t *obj) {
|
||||
REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_boolean);
|
||||
return (obj->value.boolean);
|
||||
}
|
||||
|
||||
isc_sockaddr_t *
|
||||
cfg_obj_assockaddr(cfg_obj_t *obj) {
|
||||
REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_sockaddr);
|
||||
return (&obj->value.sockaddr);
|
||||
}
|
||||
|
||||
/* Quoted string only */
|
||||
static cfg_type_t cfg_type_qstring = {
|
||||
"qstring", parse_qstring, print_qstring, &cfg_rep_string, NULL };
|
||||
@@ -1634,7 +1635,9 @@ static cfg_type_t cfg_type_size = {
|
||||
* boolean
|
||||
*/
|
||||
static isc_result_t
|
||||
parse_boolean(cfg_parser_t *pctx, cfg_type_t *type, cfg_obj_t **ret) {
|
||||
parse_boolean_like(cfg_parser_t *pctx, cfg_type_t *type,
|
||||
cfg_obj_t **ret, isc_boolean_t accept_string)
|
||||
{
|
||||
isc_result_t result;
|
||||
isc_boolean_t value;
|
||||
cfg_obj_t *obj = NULL;
|
||||
@@ -1645,7 +1648,7 @@ parse_boolean(cfg_parser_t *pctx, cfg_type_t *type, cfg_obj_t **ret) {
|
||||
return (result);
|
||||
|
||||
if (pctx->token.type != isc_tokentype_string)
|
||||
goto bad_boolean;
|
||||
goto no_string;
|
||||
|
||||
if ((strcasecmp(pctx->token.value.as_pointer, "true") == 0) ||
|
||||
(strcasecmp(pctx->token.value.as_pointer, "yes") == 0) ||
|
||||
@@ -1665,6 +1668,12 @@ parse_boolean(cfg_parser_t *pctx, cfg_type_t *type, cfg_obj_t **ret) {
|
||||
return (result);
|
||||
|
||||
bad_boolean:
|
||||
if (accept_string)
|
||||
return (create_string(pctx,
|
||||
pctx->token.value.as_pointer,
|
||||
&cfg_type_ustring,
|
||||
ret));
|
||||
no_string:
|
||||
parser_error(pctx, LOG_NEAR, "boolean expected");
|
||||
return (ISC_R_UNEXPECTEDTOKEN);
|
||||
|
||||
@@ -1672,6 +1681,18 @@ parse_boolean(cfg_parser_t *pctx, cfg_type_t *type, cfg_obj_t **ret) {
|
||||
return (result);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
parse_boolean(cfg_parser_t *pctx, cfg_type_t *type, cfg_obj_t **ret) {
|
||||
return (parse_boolean_like(pctx, type, ret, ISC_FALSE));
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
parse_boolean_or_ustring(cfg_parser_t *pctx, cfg_type_t *type,
|
||||
cfg_obj_t **ret)
|
||||
{
|
||||
return (parse_boolean_like(pctx, type, ret, ISC_TRUE));
|
||||
}
|
||||
|
||||
static void
|
||||
print_boolean(cfg_printer_t *pctx, cfg_obj_t *obj) {
|
||||
if (obj->value.boolean)
|
||||
@@ -1683,9 +1704,14 @@ print_boolean(cfg_printer_t *pctx, cfg_obj_t *obj) {
|
||||
static cfg_type_t cfg_type_boolean = {
|
||||
"boolean", parse_boolean, print_boolean, &cfg_rep_boolean, NULL };
|
||||
|
||||
static cfg_type_t cfg_type_boolean_or_ustring = {
|
||||
"boolean_or_string", parse_boolean_or_ustring, NULL, NULL, NULL };
|
||||
|
||||
static keyword_type_t key_kw = { "key", &cfg_type_astring };
|
||||
static cfg_type_t cfg_type_optional_keyref = {
|
||||
"optional_keyref", parse_optional_keyvalue, print_optional_keyvalue, &cfg_rep_string, &key_kw };
|
||||
"optional_keyref", parse_optional_keyvalue, print_optional_keyvalue,
|
||||
&cfg_rep_string, &key_kw
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
@@ -1859,6 +1885,12 @@ print_spacelist(cfg_printer_t *pctx, cfg_obj_t *obj) {
|
||||
}
|
||||
}
|
||||
|
||||
isc_boolean_t
|
||||
cfg_obj_islist(cfg_obj_t *obj) {
|
||||
REQUIRE(obj != NULL);
|
||||
return (ISC_TF(obj->type->rep == &cfg_rep_list));
|
||||
}
|
||||
|
||||
cfg_listelt_t *
|
||||
cfg_list_first(cfg_obj_t *obj) {
|
||||
REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_list);
|
||||
@@ -1881,6 +1913,240 @@ cfg_listelt_value(cfg_listelt_t *elt) {
|
||||
* Maps.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Parse a map body. That's something like
|
||||
*
|
||||
* "foo 1; bar { glub; }; zap true; zap false;"
|
||||
*
|
||||
* i.e., a sequence of option names followed by values and
|
||||
* terminated by semicolons. Used for the top level of
|
||||
* the named.conf syntax, as well as for the body of the
|
||||
* options, view, zone, and other statements.
|
||||
*/
|
||||
static isc_result_t
|
||||
parse_mapbody(cfg_parser_t *pctx, cfg_type_t *type, cfg_obj_t **ret)
|
||||
{
|
||||
cfg_clausedef_t **clausesets = type->of;
|
||||
isc_result_t result;
|
||||
cfg_clausedef_t **clauseset;
|
||||
cfg_clausedef_t *clause;
|
||||
cfg_obj_t *value = NULL;
|
||||
cfg_obj_t *obj = NULL;
|
||||
cfg_obj_t *eltobj = NULL;
|
||||
cfg_obj_t *includename = NULL;
|
||||
isc_symvalue_t symval;
|
||||
cfg_list_t *list = NULL;
|
||||
|
||||
CHECK(create_map(pctx, type, &obj));
|
||||
|
||||
obj->value.map.clausesets = clausesets;
|
||||
|
||||
for (;;) {
|
||||
cfg_listelt_t *elt;
|
||||
|
||||
redo:
|
||||
/*
|
||||
* Parse the option name and see if it is known.
|
||||
*/
|
||||
CHECK(cfg_gettoken(pctx, 0));
|
||||
|
||||
if (pctx->token.type != isc_tokentype_string) {
|
||||
cfg_ungettoken(pctx);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* We accept "include" statements wherever a map body
|
||||
* clause can occur.
|
||||
*/
|
||||
if (strcasecmp(pctx->token.value.as_pointer, "include") == 0) {
|
||||
/*
|
||||
* Turn the file name into a temporary configuration
|
||||
* object just so that it is not overwritten by the
|
||||
* semicolon token.
|
||||
*/
|
||||
CHECK(parse(pctx, &cfg_type_qstring, &includename));
|
||||
CHECK(parse_semicolon(pctx));
|
||||
CHECK(parser_openfile(pctx, includename->
|
||||
value.string.base));
|
||||
cfg_obj_destroy(pctx, &includename);
|
||||
goto redo;
|
||||
}
|
||||
|
||||
clause = NULL;
|
||||
for (clauseset = clausesets; *clauseset != NULL; clauseset++) {
|
||||
for (clause = *clauseset;
|
||||
clause->name != NULL;
|
||||
clause++) {
|
||||
if (strcasecmp(pctx->token.value.as_pointer,
|
||||
clause->name) == 0)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
done:
|
||||
if (clause == NULL || clause->name == NULL) {
|
||||
parser_error(pctx, LOG_NOPREP, "unknown option");
|
||||
/*
|
||||
* Try to recover by parsing this option as an unknown
|
||||
* option and discarding it.
|
||||
*/
|
||||
CHECK(parse(pctx, &cfg_type_unsupported, &eltobj));
|
||||
cfg_obj_destroy(pctx, &eltobj);
|
||||
CHECK(parse_semicolon(pctx));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Clause is known. */
|
||||
|
||||
/* Issue warnings if appropriate */
|
||||
if ((clause->flags & CFG_CLAUSEFLAG_OBSOLETE) != 0)
|
||||
parser_warning(pctx, 0, "option '%s' is obsolete",
|
||||
clause->name);
|
||||
if ((clause->flags & CFG_CLAUSEFLAG_NOTIMP) != 0)
|
||||
parser_warning(pctx, 0, "option '%s' is "
|
||||
"not implemented",
|
||||
clause->name);
|
||||
if ((clause->flags & CFG_CLAUSEFLAG_NYI) != 0)
|
||||
parser_warning(pctx, 0, "option '%s' is "
|
||||
"not yet implemented", clause->name);
|
||||
/*
|
||||
* Don't log options with CFG_CLAUSEFLAG_NEWDEFAULT
|
||||
* set here - we need to log the *lack* of such an option,
|
||||
* not its presence.
|
||||
*/
|
||||
|
||||
/* See if the clause already has a value; if not create one. */
|
||||
result = isc_symtab_lookup(obj->value.map.symtab,
|
||||
clause->name, 0, &symval);
|
||||
|
||||
if ((clause->flags & CFG_CLAUSEFLAG_MULTI) != 0) {
|
||||
/* Multivalued clause */
|
||||
cfg_obj_t *listobj = NULL;
|
||||
if (result == ISC_R_NOTFOUND) {
|
||||
CHECK(create_list(pctx,
|
||||
&cfg_type_implicitlist,
|
||||
&listobj));
|
||||
symval.as_pointer = listobj;
|
||||
result = isc_symtab_define(obj->value.
|
||||
map.symtab,
|
||||
clause->name,
|
||||
1, symval,
|
||||
isc_symexists_reject);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
isc_mem_put(pctx->mctx, list,
|
||||
sizeof(cfg_list_t));
|
||||
goto cleanup;
|
||||
}
|
||||
} else if (result == ISC_R_SUCCESS) {
|
||||
listobj = symval.as_pointer;
|
||||
} else {
|
||||
parser_error(pctx, LOG_NEAR,
|
||||
"isc_symtab_define() failed",
|
||||
clause->name);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
elt = NULL;
|
||||
CHECK(parse_list_elt(pctx, clause->type, &elt));
|
||||
CHECK(parse_semicolon(pctx));
|
||||
|
||||
ISC_LIST_APPEND(listobj->value.list, elt, link);
|
||||
} else {
|
||||
/* Single-valued clause */
|
||||
if (result == ISC_R_NOTFOUND) {
|
||||
isc_boolean_t callback =
|
||||
ISC_TF((clause->flags &
|
||||
CFG_CLAUSEFLAG_CALLBACK) != 0);
|
||||
CHECK(parse_symtab_elt(pctx, clause->name,
|
||||
clause->type,
|
||||
obj->value.map.symtab,
|
||||
callback));
|
||||
CHECK(parse_semicolon(pctx));
|
||||
} else if (result == ISC_R_SUCCESS) {
|
||||
parser_error(pctx, LOG_NEAR, "'%s' redefined",
|
||||
clause->name);
|
||||
goto cleanup;
|
||||
} else {
|
||||
parser_error(pctx, LOG_NEAR,
|
||||
"isc_symtab_define() failed");
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
*ret = obj;
|
||||
return (ISC_R_SUCCESS);
|
||||
|
||||
cleanup:
|
||||
CLEANUP_OBJ(value);
|
||||
CLEANUP_OBJ(obj);
|
||||
CLEANUP_OBJ(eltobj);
|
||||
CLEANUP_OBJ(includename);
|
||||
return (result);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
parse_symtab_elt(cfg_parser_t *pctx, const char *name,
|
||||
cfg_type_t *elttype, isc_symtab_t *symtab,
|
||||
isc_boolean_t callback)
|
||||
{
|
||||
isc_result_t result;
|
||||
cfg_obj_t *obj = NULL;
|
||||
isc_symvalue_t symval;
|
||||
|
||||
CHECK(parse(pctx, elttype, &obj));
|
||||
|
||||
if (callback && pctx->callback != NULL)
|
||||
CHECK(pctx->callback(name, obj, pctx->callbackarg));
|
||||
|
||||
symval.as_pointer = obj;
|
||||
CHECK(isc_symtab_define(symtab, name,
|
||||
1, symval,
|
||||
isc_symexists_reject));
|
||||
obj = NULL;
|
||||
return (ISC_R_SUCCESS);
|
||||
|
||||
cleanup:
|
||||
CLEANUP_OBJ(obj);
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse a map; e.g., "{ foo 1; bar { glub; }; zap true; zap false; }"
|
||||
*/
|
||||
static isc_result_t
|
||||
parse_map(cfg_parser_t *pctx, cfg_type_t *type, cfg_obj_t **ret)
|
||||
{
|
||||
isc_result_t result;
|
||||
CHECK(parse_special(pctx, '{'));
|
||||
CHECK(parse_mapbody(pctx, type, ret));
|
||||
CHECK(parse_special(pctx, '}'));
|
||||
cleanup:
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse a named map; e.g., "name { foo 1; }". Used for the "key", "server",
|
||||
* and "channel" statements.
|
||||
*/
|
||||
static isc_result_t
|
||||
parse_named_map(cfg_parser_t *pctx, cfg_type_t *type, cfg_obj_t **ret)
|
||||
{
|
||||
isc_result_t result;
|
||||
cfg_obj_t *idobj = NULL;
|
||||
cfg_obj_t *mapobj = NULL;
|
||||
|
||||
CHECK(parse_astring(pctx, NULL, &idobj));
|
||||
CHECK(parse_map(pctx, type, &mapobj));
|
||||
mapobj->value.map.id = idobj;
|
||||
idobj = NULL;
|
||||
*ret = mapobj;
|
||||
cleanup:
|
||||
CLEANUP_OBJ(idobj);
|
||||
return (result);
|
||||
}
|
||||
|
||||
static void
|
||||
print_mapbody(cfg_printer_t *pctx, cfg_obj_t *obj) {
|
||||
isc_result_t result = ISC_R_SUCCESS;
|
||||
@@ -1944,6 +2210,38 @@ print_map(cfg_printer_t *pctx, cfg_obj_t *obj) {
|
||||
print_close(pctx);
|
||||
}
|
||||
|
||||
isc_boolean_t
|
||||
cfg_obj_ismap(cfg_obj_t *obj) {
|
||||
REQUIRE(obj != NULL);
|
||||
return (ISC_TF(obj->type->rep == &cfg_rep_map));
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
cfg_map_get(cfg_obj_t *mapobj, const char* name, cfg_obj_t **obj) {
|
||||
isc_result_t result;
|
||||
isc_symvalue_t val;
|
||||
cfg_map_t *map;
|
||||
|
||||
REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map);
|
||||
REQUIRE(name != NULL);
|
||||
REQUIRE(obj != NULL && *obj == NULL);
|
||||
|
||||
map = &mapobj->value.map;
|
||||
|
||||
result = isc_symtab_lookup(map->symtab, name, MAP_SYM, &val);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (result);
|
||||
*obj = val.as_pointer;
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
cfg_obj_t *
|
||||
cfg_map_getname(cfg_obj_t *mapobj) {
|
||||
REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map);
|
||||
return (mapobj->value.map.id);
|
||||
}
|
||||
|
||||
|
||||
/* Parse an arbitrary token, storing its raw text representation. */
|
||||
static isc_result_t
|
||||
parse_token(cfg_parser_t *pctx, cfg_type_t *type, cfg_obj_t **ret) {
|
||||
@@ -2529,6 +2827,18 @@ print_sockaddr(cfg_printer_t *pctx, cfg_obj_t *obj) {
|
||||
}
|
||||
}
|
||||
|
||||
isc_boolean_t
|
||||
cfg_obj_issockaddr(cfg_obj_t *obj) {
|
||||
REQUIRE(obj != NULL);
|
||||
return (ISC_TF(obj->type->rep == &cfg_rep_sockaddr));
|
||||
}
|
||||
|
||||
isc_sockaddr_t *
|
||||
cfg_obj_assockaddr(cfg_obj_t *obj) {
|
||||
REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_sockaddr);
|
||||
return (&obj->value.sockaddr);
|
||||
}
|
||||
|
||||
/* An IPv4/IPv6 address with optional port, "*" accepted as wildcard. */
|
||||
static cfg_type_t cfg_type_sockaddr4wild = {
|
||||
"sockaddr4wild", parse_sockaddr4wild, print_sockaddr,
|
||||
@@ -2726,241 +3036,6 @@ cfg_type_t cfg_type_rndcconf = {
|
||||
rndcconf_clausesets
|
||||
};
|
||||
|
||||
/*
|
||||
* Parse a map body. That's something like
|
||||
*
|
||||
* "foo 1; bar { glub; }; zap true; zap false;"
|
||||
*
|
||||
* i.e., a sequence of option names followed by values and
|
||||
* terminated by semicolons. Used for the top level of
|
||||
* the named.conf syntax, as well as for the body of the
|
||||
* options, view, zone, and other statements.
|
||||
*/
|
||||
static isc_result_t
|
||||
parse_mapbody(cfg_parser_t *pctx, cfg_type_t *type, cfg_obj_t **ret)
|
||||
{
|
||||
cfg_clausedef_t **clausesets = type->of;
|
||||
isc_result_t result;
|
||||
cfg_clausedef_t **clauseset;
|
||||
cfg_clausedef_t *clause;
|
||||
cfg_obj_t *value = NULL;
|
||||
cfg_obj_t *obj = NULL;
|
||||
cfg_obj_t *eltobj = NULL;
|
||||
cfg_obj_t *includename = NULL;
|
||||
isc_symvalue_t symval;
|
||||
cfg_list_t *list = NULL;
|
||||
|
||||
CHECK(create_map(pctx, type, &obj));
|
||||
|
||||
obj->value.map.clausesets = clausesets;
|
||||
|
||||
for (;;) {
|
||||
cfg_listelt_t *elt;
|
||||
|
||||
redo:
|
||||
/*
|
||||
* Parse the option name and see if it is known.
|
||||
*/
|
||||
CHECK(cfg_gettoken(pctx, 0));
|
||||
|
||||
if (pctx->token.type != isc_tokentype_string) {
|
||||
cfg_ungettoken(pctx);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* We accept "include" statements wherever a map body
|
||||
* clause can occur.
|
||||
*/
|
||||
if (strcasecmp(pctx->token.value.as_pointer, "include") == 0) {
|
||||
/*
|
||||
* Turn the file name into a temporary configuration
|
||||
* object just so that it is not overwritten by the
|
||||
* semicolon token.
|
||||
*/
|
||||
CHECK(parse(pctx, &cfg_type_qstring, &includename));
|
||||
CHECK(parse_semicolon(pctx));
|
||||
CHECK(parser_openfile(pctx, includename->
|
||||
value.string.base));
|
||||
cfg_obj_destroy(pctx, &includename);
|
||||
goto redo;
|
||||
}
|
||||
|
||||
clause = NULL;
|
||||
for (clauseset = clausesets; *clauseset != NULL; clauseset++) {
|
||||
for (clause = *clauseset;
|
||||
clause->name != NULL;
|
||||
clause++) {
|
||||
if (strcasecmp(pctx->token.value.as_pointer,
|
||||
clause->name) == 0)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
done:
|
||||
if (clause == NULL || clause->name == NULL) {
|
||||
parser_error(pctx, LOG_NOPREP, "unknown option");
|
||||
/*
|
||||
* Try to recover by parsing this option as an unknown
|
||||
* option and discarding it.
|
||||
*/
|
||||
CHECK(parse(pctx, &cfg_type_unsupported, &eltobj));
|
||||
cfg_obj_destroy(pctx, &eltobj);
|
||||
CHECK(parse_semicolon(pctx));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Clause is known. */
|
||||
|
||||
/* Issue warnings if appropriate */
|
||||
if ((clause->flags & CFG_CLAUSEFLAG_OBSOLETE) != 0)
|
||||
parser_warning(pctx, 0, "option '%s' is obsolete",
|
||||
clause->name);
|
||||
if ((clause->flags & CFG_CLAUSEFLAG_NOTIMP) != 0)
|
||||
parser_warning(pctx, 0, "option '%s' is "
|
||||
"not implemented",
|
||||
clause->name);
|
||||
if ((clause->flags & CFG_CLAUSEFLAG_NYI) != 0)
|
||||
parser_warning(pctx, 0, "option '%s' is "
|
||||
"not yet implemented", clause->name);
|
||||
/*
|
||||
* Don't log options with CFG_CLAUSEFLAG_NEWDEFAULT
|
||||
* set here - we need to log the *lack* of such an option,
|
||||
* not its presence.
|
||||
*/
|
||||
|
||||
/* See if the clause already has a value; if not create one. */
|
||||
result = isc_symtab_lookup(obj->value.map.symtab,
|
||||
clause->name, 0, &symval);
|
||||
|
||||
if ((clause->flags & CFG_CLAUSEFLAG_MULTI) != 0) {
|
||||
/* Multivalued clause */
|
||||
cfg_obj_t *listobj = NULL;
|
||||
if (result == ISC_R_NOTFOUND) {
|
||||
CHECK(create_list(pctx,
|
||||
&cfg_type_implicitlist,
|
||||
&listobj));
|
||||
symval.as_pointer = listobj;
|
||||
result = isc_symtab_define(obj->value.
|
||||
map.symtab,
|
||||
clause->name,
|
||||
1, symval,
|
||||
isc_symexists_reject);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
isc_mem_put(pctx->mctx, list,
|
||||
sizeof(cfg_list_t));
|
||||
goto cleanup;
|
||||
}
|
||||
} else if (result == ISC_R_SUCCESS) {
|
||||
listobj = symval.as_pointer;
|
||||
} else {
|
||||
parser_error(pctx, LOG_NEAR,
|
||||
"isc_symtab_define() failed",
|
||||
clause->name);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
elt = NULL;
|
||||
CHECK(parse_list_elt(pctx, clause->type, &elt));
|
||||
CHECK(parse_semicolon(pctx));
|
||||
|
||||
ISC_LIST_APPEND(listobj->value.list, elt, link);
|
||||
} else {
|
||||
/* Single-valued clause */
|
||||
if (result == ISC_R_NOTFOUND) {
|
||||
isc_boolean_t callback =
|
||||
ISC_TF((clause->flags &
|
||||
CFG_CLAUSEFLAG_CALLBACK) != 0);
|
||||
CHECK(parse_symtab_elt(pctx, clause->name,
|
||||
clause->type,
|
||||
obj->value.map.symtab,
|
||||
callback));
|
||||
CHECK(parse_semicolon(pctx));
|
||||
} else if (result == ISC_R_SUCCESS) {
|
||||
parser_error(pctx, LOG_NEAR, "'%s' redefined",
|
||||
clause->name);
|
||||
goto cleanup;
|
||||
} else {
|
||||
parser_error(pctx, LOG_NEAR,
|
||||
"isc_symtab_define() failed");
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
*ret = obj;
|
||||
return (ISC_R_SUCCESS);
|
||||
|
||||
cleanup:
|
||||
CLEANUP_OBJ(value);
|
||||
CLEANUP_OBJ(obj);
|
||||
CLEANUP_OBJ(eltobj);
|
||||
CLEANUP_OBJ(includename);
|
||||
return (result);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
parse_symtab_elt(cfg_parser_t *pctx, const char *name,
|
||||
cfg_type_t *elttype, isc_symtab_t *symtab,
|
||||
isc_boolean_t callback)
|
||||
{
|
||||
isc_result_t result;
|
||||
cfg_obj_t *obj = NULL;
|
||||
isc_symvalue_t symval;
|
||||
|
||||
CHECK(parse(pctx, elttype, &obj));
|
||||
|
||||
if (callback && pctx->callback != NULL)
|
||||
CHECK(pctx->callback(name, obj, pctx->callbackarg));
|
||||
|
||||
symval.as_pointer = obj;
|
||||
CHECK(isc_symtab_define(symtab, name,
|
||||
1, symval,
|
||||
isc_symexists_reject));
|
||||
obj = NULL;
|
||||
return (ISC_R_SUCCESS);
|
||||
|
||||
cleanup:
|
||||
CLEANUP_OBJ(obj);
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse a map; e.g., "{ foo 1; bar { glub; }; zap true; zap false; }"
|
||||
*/
|
||||
static isc_result_t
|
||||
parse_map(cfg_parser_t *pctx, cfg_type_t *type, cfg_obj_t **ret)
|
||||
{
|
||||
isc_result_t result;
|
||||
CHECK(parse_special(pctx, '{'));
|
||||
CHECK(parse_mapbody(pctx, type, ret));
|
||||
CHECK(parse_special(pctx, '}'));
|
||||
cleanup:
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse a named map; e.g., "name { foo 1; }". Used for the "key", "server",
|
||||
* and "channel" statements.
|
||||
*/
|
||||
static isc_result_t
|
||||
parse_named_map(cfg_parser_t *pctx, cfg_type_t *type, cfg_obj_t **ret)
|
||||
{
|
||||
isc_result_t result;
|
||||
cfg_obj_t *idobj = NULL;
|
||||
cfg_obj_t *mapobj = NULL;
|
||||
|
||||
CHECK(parse_astring(pctx, NULL, &idobj));
|
||||
CHECK(parse_map(pctx, type, &mapobj));
|
||||
mapobj->value.map.id = idobj;
|
||||
idobj = NULL;
|
||||
*ret = mapobj;
|
||||
cleanup:
|
||||
CLEANUP_OBJ(idobj);
|
||||
return (result);
|
||||
}
|
||||
|
||||
|
||||
static isc_result_t
|
||||
cfg_gettoken(cfg_parser_t *pctx, int options) {
|
||||
isc_result_t result;
|
||||
|
Reference in New Issue
Block a user