diff options
Diffstat (limited to 'usr.sbin/bind/lib/isccfg/parser.c')
| -rw-r--r-- | usr.sbin/bind/lib/isccfg/parser.c | 2695 |
1 files changed, 506 insertions, 2189 deletions
diff --git a/usr.sbin/bind/lib/isccfg/parser.c b/usr.sbin/bind/lib/isccfg/parser.c index c93af6f7d44..76aa71625b0 100644 --- a/usr.sbin/bind/lib/isccfg/parser.c +++ b/usr.sbin/bind/lib/isccfg/parser.c @@ -1,21 +1,21 @@ /* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000-2003 Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * - * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM - * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL - * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, - * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING - * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION - * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. */ -/* $ISC: parser.c,v 1.70.2.22 2003/09/19 13:41:36 marka Exp $ */ +/* $ISC: parser.c,v 1.70.2.20.2.18 2004/05/15 03:46:13 jinmei Exp $ */ #include <config.h> @@ -30,52 +30,21 @@ #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 <isccfg/cfg.h> +#include <isccfg/grammar.h> #include <isccfg/log.h> /* Shorthand */ #define CAT CFG_LOGCATEGORY_CONFIG #define MOD CFG_LOGMODULE_PARSER -#define QSTRING (ISC_LEXOPT_QSTRING | ISC_LEXOPT_QSTRINGMULTILINE) - -/* - * Pass one of these flags to parser_error() to include the - * token text in log message. - */ -#define LOG_NEAR 0x00000001 /* Say "near <token>" */ -#define LOG_BEFORE 0x00000002 /* Say "before <token>" */ -#define LOG_NOPREP 0x00000004 /* Say just "<token>" */ - #define MAP_SYM 1 /* Unique type for isc_symtab */ -/* Clause may occur multiple times (e.g., "zone") */ -#define CFG_CLAUSEFLAG_MULTI 0x00000001 -/* Clause is obsolete */ -#define CFG_CLAUSEFLAG_OBSOLETE 0x00000002 -/* Clause is not implemented, and may never be */ -#define CFG_CLAUSEFLAG_NOTIMP 0x00000004 -/* Clause is not implemented yet */ -#define CFG_CLAUSEFLAG_NYI 0x00000008 -/* Default value has changed since earlier release */ -#define CFG_CLAUSEFLAG_NEWDEFAULT 0x00000010 -/* - * Clause needs to be interpreted during parsing - * by calling a callback function, like the - * "directory" option. - */ -#define CFG_CLAUSEFLAG_CALLBACK 0x00000020 - -/* - * Flags defining whether to accept certain types of network addresses. - */ -#define V4OK 0x00000001 -#define V4PREFIXOK 0x00000002 -#define V6OK 0x00000004 -#define WILDOK 0x00000008 +#define TOKEN_STRING(pctx) (pctx->token.value.as_textregion.base) /* Check a return value. */ #define CHECK(op) \ @@ -88,231 +57,12 @@ do { if ((obj) != NULL) cfg_obj_destroy(pctx, &(obj)); } while (0) -typedef struct cfg_clausedef cfg_clausedef_t; -typedef struct cfg_tuplefielddef cfg_tuplefielddef_t; -typedef struct cfg_printer cfg_printer_t; -typedef ISC_LIST(cfg_listelt_t) cfg_list_t; -typedef struct cfg_map cfg_map_t; -typedef struct cfg_rep cfg_rep_t; - -/* - * Function types for configuration object methods - */ - -typedef isc_result_t (*cfg_parsefunc_t)(cfg_parser_t *, const cfg_type_t *type, - cfg_obj_t **); -typedef void (*cfg_printfunc_t)(cfg_printer_t *, cfg_obj_t *); -typedef void (*cfg_freefunc_t)(cfg_parser_t *, cfg_obj_t *); - - -/* - * Structure definitions - */ - -/* The parser object. */ -struct cfg_parser { - isc_mem_t * mctx; - isc_log_t * lctx; - isc_lex_t * lexer; - unsigned int errors; - unsigned int warnings; - isc_token_t token; - - /* We are at the end of all input. */ - isc_boolean_t seen_eof; - - /* The current token has been pushed back. */ - isc_boolean_t ungotten; - - /* - * The stack of currently active files, represented - * as a configuration list of configuration strings. - * The head is the top-level file, subsequent elements - * (if any) are the nested include files, and the - * last element is the file currently being parsed. - */ - cfg_obj_t * open_files; - - /* - * Names of files that we have parsed and closed - * and were previously on the open_file list. - * We keep these objects around after closing - * the files because the file names may still be - * referenced from other configuration objects - * for use in reporting semantic errors after - * parsing is complete. - */ - cfg_obj_t * closed_files; - - /* - * Current line number. We maintain our own - * copy of this so that it is available even - * when a file has just been closed. - */ - unsigned int line; - - cfg_parsecallback_t callback; - void *callbackarg; -}; - -/* - * A configuration printer object. This is an abstract - * interface to a destination to which text can be printed - * by calling the function 'f'. - */ -struct cfg_printer { - void (*f)(void *closure, const char *text, int textlen); - void *closure; - int indent; -}; - -/* A clause definition. */ - -struct cfg_clausedef { - const char *name; - cfg_type_t *type; - unsigned int flags; -}; - -/* A tuple field definition. */ - -struct cfg_tuplefielddef { - const char *name; - cfg_type_t *type; - unsigned int flags; -}; - -/* A configuration object type definition. */ -struct cfg_type { - const char *name; /* For debugging purposes only */ - cfg_parsefunc_t parse; - cfg_printfunc_t print; - cfg_rep_t * rep; /* Data representation */ - const void * of; /* For meta-types */ -}; - -/* A keyword-type definition, for things like "port <integer>". */ - -typedef struct { - const char *name; - const cfg_type_t *type; -} keyword_type_t; - -struct cfg_map { - cfg_obj_t *id; /* Used for 'named maps' like keys, zones, &c */ - const cfg_clausedef_t * const *clausesets; /* The clauses that - can occur in this map; - used for printing */ - isc_symtab_t *symtab; -}; - -typedef struct cfg_netprefix cfg_netprefix_t; - -struct cfg_netprefix { - isc_netaddr_t address; /* IP4/IP6 */ - unsigned int prefixlen; -}; - -/* - * A configuration data representation. - */ -struct cfg_rep { - const char * name; /* For debugging only */ - cfg_freefunc_t free; /* How to free this kind of data. */ -}; - -/* - * A configuration object. This is the main building block - * of the configuration parse tree. - */ - -struct cfg_obj { - const cfg_type_t *type; - union { - isc_uint32_t uint32; - isc_uint64_t uint64; - isc_textregion_t string; /* null terminated, too */ - isc_boolean_t boolean; - cfg_map_t map; - cfg_list_t list; - cfg_obj_t ** tuple; - isc_sockaddr_t sockaddr; - cfg_netprefix_t netprefix; - } value; - char * file; - unsigned int line; -}; - - -/* A list element. */ - -struct cfg_listelt { - cfg_obj_t *obj; - ISC_LINK(cfg_listelt_t) link; -}; - /* * Forward declarations of static functions. */ -static isc_result_t -create_cfgobj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **objp); - -static isc_result_t -create_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **objp); - -static isc_result_t -create_listelt(cfg_parser_t *pctx, cfg_listelt_t **eltp); - -static void -free_list(cfg_parser_t *pctx, cfg_obj_t *obj); - -static isc_result_t -create_string(cfg_parser_t *pctx, const char *contents, const cfg_type_t *type, - cfg_obj_t **ret); - static void -free_string(cfg_parser_t *pctx, cfg_obj_t *obj); - -static isc_result_t -create_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **objp); - -static isc_result_t -create_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **objp); - -static void -free_map(cfg_parser_t *pctx, cfg_obj_t *obj); - -static isc_result_t -get_addr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na); - -static void -print(cfg_printer_t *pctx, const char *text, int len); - -static void -print_void(cfg_printer_t *pctx, cfg_obj_t *obj); - -static isc_result_t -parse_enum_or_other(cfg_parser_t *pctx, const cfg_type_t *enumtype, - const cfg_type_t *othertype, cfg_obj_t **ret); - -static isc_result_t -parse_mapbody(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret); - -static void -print_mapbody(cfg_printer_t *pctx, cfg_obj_t *obj); - -static isc_result_t -parse_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret); - -static void -print_map(cfg_printer_t *pctx, cfg_obj_t *obj); - -static isc_result_t -parse_named_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret); - -static isc_result_t -parse_addressed_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret); +free_tuple(cfg_parser_t *pctx, cfg_obj_t *obj); static isc_result_t parse_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret); @@ -320,41 +70,24 @@ parse_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret); static void print_list(cfg_printer_t *pctx, cfg_obj_t *obj); -static isc_result_t -parse_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret); - -static void -print_tuple(cfg_printer_t *pctx, cfg_obj_t *obj); - -static void -free_tuple(cfg_parser_t *pctx, cfg_obj_t *obj); - -static isc_result_t -parse_spacelist(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret); - -static void -print_spacelist(cfg_printer_t *pctx, cfg_obj_t *obj); - static void -print_sockaddr(cfg_printer_t *pctx, cfg_obj_t *obj); +free_list(cfg_parser_t *pctx, cfg_obj_t *obj); static isc_result_t -parse_addrmatchelt(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret); +create_listelt(cfg_parser_t *pctx, cfg_listelt_t **eltp); static isc_result_t -parse_bracketed_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret); +create_string(cfg_parser_t *pctx, const char *contents, const cfg_type_t *type, + cfg_obj_t **ret); static void -print_bracketed_list(cfg_printer_t *pctx, cfg_obj_t *obj); - -static isc_result_t -parse_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret); +free_string(cfg_parser_t *pctx, cfg_obj_t *obj); static isc_result_t -parse_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret); +create_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **objp); static void -print_keyvalue(cfg_printer_t *pctx, cfg_obj_t *obj); +free_map(cfg_parser_t *pctx, cfg_obj_t *obj); static isc_result_t parse_symtab_elt(cfg_parser_t *pctx, const char *name, @@ -365,38 +98,12 @@ static void free_noop(cfg_parser_t *pctx, cfg_obj_t *obj); static isc_result_t -cfg_gettoken(cfg_parser_t *pctx, int options); - -static void -cfg_ungettoken(cfg_parser_t *pctx); - -static isc_result_t -cfg_peektoken(cfg_parser_t *pctx, int options); - -static isc_result_t cfg_getstringtoken(cfg_parser_t *pctx); static void -parser_error(cfg_parser_t *pctx, unsigned int flags, - const char *fmt, ...) ISC_FORMAT_PRINTF(3, 4); - -static void -parser_warning(cfg_parser_t *pctx, unsigned int flags, - const char *fmt, ...) ISC_FORMAT_PRINTF(3, 4); - -static void parser_complain(cfg_parser_t *pctx, isc_boolean_t is_warning, unsigned int flags, const char *format, va_list args); -static void -print_uint32(cfg_printer_t *pctx, cfg_obj_t *obj); - -static void -print_ustring(cfg_printer_t *pctx, cfg_obj_t *obj); - -static isc_result_t -parse_enum(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret); - /* * Data representations. These correspond to members of the * "value" union in struct cfg_obj (except "void", which does @@ -415,734 +122,30 @@ cfg_rep_t cfg_rep_netprefix = { "netprefix", free_noop }; cfg_rep_t cfg_rep_void = { "void", free_noop }; /* - * Forward declarations of configuration type definitions. - * Additional types are declared publicly in cfg.h. - */ - -static cfg_type_t cfg_type_boolean; -static cfg_type_t cfg_type_uint32; -static cfg_type_t cfg_type_qstring; -static cfg_type_t cfg_type_astring; -static cfg_type_t cfg_type_ustring; -static cfg_type_t cfg_type_optional_port; -static cfg_type_t cfg_type_bracketed_aml; -static cfg_type_t cfg_type_acl; -static cfg_type_t cfg_type_portiplist; -static cfg_type_t cfg_type_bracketed_sockaddrlist; -static cfg_type_t cfg_type_sockaddr; -static cfg_type_t cfg_type_netaddr; -static cfg_type_t cfg_type_optional_keyref; -static cfg_type_t cfg_type_options; -static cfg_type_t cfg_type_view; -static cfg_type_t cfg_type_viewopts; -static cfg_type_t cfg_type_key; -static cfg_type_t cfg_type_server; -static cfg_type_t cfg_type_controls; -static cfg_type_t cfg_type_bracketed_sockaddrkeylist; -static cfg_type_t cfg_type_querysource4; -static cfg_type_t cfg_type_querysource6; -static cfg_type_t cfg_type_querysource; -static cfg_type_t cfg_type_sockaddr4wild; -static cfg_type_t cfg_type_sockaddr6wild; -static cfg_type_t cfg_type_sockaddr; -static cfg_type_t cfg_type_netprefix; -static cfg_type_t cfg_type_zone; -static cfg_type_t cfg_type_zoneopts; -static cfg_type_t cfg_type_logging; -static cfg_type_t cfg_type_optional_facility; -static cfg_type_t cfg_type_void; -static cfg_type_t cfg_type_optional_class; -static cfg_type_t cfg_type_destinationlist; -static cfg_type_t cfg_type_size; -static cfg_type_t cfg_type_sizenodefault; -static cfg_type_t cfg_type_negated; -static cfg_type_t cfg_type_addrmatchelt; -static cfg_type_t cfg_type_unsupported; -static cfg_type_t cfg_type_token; -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_logfile; -static cfg_type_t cfg_type_lwres; -static cfg_type_t cfg_type_controls_sockaddr; -static cfg_type_t cfg_type_notifytype; -static cfg_type_t cfg_type_dialuptype; - -/* * Configuration type definitions. */ -/* tkey-dhkey */ - -static cfg_tuplefielddef_t tkey_dhkey_fields[] = { - { "name", &cfg_type_qstring, 0 }, - { "keyid", &cfg_type_uint32, 0 }, - { NULL, NULL, 0 } -}; - -static cfg_type_t cfg_type_tkey_dhkey = { - "tkey-dhkey", parse_tuple, print_tuple, &cfg_rep_tuple, - tkey_dhkey_fields -}; - -/* listen-on */ - -static cfg_tuplefielddef_t listenon_fields[] = { - { "port", &cfg_type_optional_port, 0 }, - { "acl", &cfg_type_bracketed_aml, 0 }, - { NULL, NULL, 0 } -}; -static cfg_type_t cfg_type_listenon = { - "listenon", parse_tuple, print_tuple, &cfg_rep_tuple, listenon_fields }; - -/* acl */ - -static cfg_tuplefielddef_t acl_fields[] = { - { "name", &cfg_type_astring, 0 }, - { "value", &cfg_type_bracketed_aml, 0 }, - { NULL, NULL, 0 } -}; - -static cfg_type_t cfg_type_acl = { - "acl", parse_tuple, print_tuple, &cfg_rep_tuple, acl_fields }; - - -/* - * "sockaddrkeylist", a list of socket addresses with optional keys - * and an optional default port, as used in the masters option. - * E.g., - * "port 1234 { 10.0.0.1 key foo; 1::2 port 69; }" - */ - -static cfg_tuplefielddef_t sockaddrkey_fields[] = { - { "sockaddr", &cfg_type_sockaddr, 0 }, - { "key", &cfg_type_optional_keyref, 0 }, - { NULL, NULL, 0 }, -}; - -static cfg_type_t cfg_type_sockaddrkey = { - "sockaddrkey", parse_tuple, print_tuple, &cfg_rep_tuple, - sockaddrkey_fields -}; - -static cfg_type_t cfg_type_bracketed_sockaddrkeylist = { - "bracketed_sockaddrkeylist", parse_bracketed_list, - print_bracketed_list, &cfg_rep_list, &cfg_type_sockaddrkey -}; - -static cfg_tuplefielddef_t sockaddrkeylist_fields[] = { - { "port", &cfg_type_optional_port, 0 }, - { "addresses", &cfg_type_bracketed_sockaddrkeylist, 0 }, - { NULL, NULL, 0 } -}; -static cfg_type_t cfg_type_sockaddrkeylist = { - "sockaddrkeylist", parse_tuple, print_tuple, &cfg_rep_tuple, - sockaddrkeylist_fields -}; - -/* - * A list of socket addresses with an optional default port, - * as used in the also-notify option. E.g., - * "port 1234 { 10.0.0.1; 1::2 port 69; }" - */ -static cfg_tuplefielddef_t portiplist_fields[] = { - { "port", &cfg_type_optional_port, 0 }, - { "addresses", &cfg_type_bracketed_sockaddrlist, 0 }, - { NULL, NULL, 0 } -}; -static cfg_type_t cfg_type_portiplist = { - "portiplist", parse_tuple, print_tuple, &cfg_rep_tuple, - portiplist_fields -}; - -/* - * A public key, as in the "pubkey" statement. - */ -static cfg_tuplefielddef_t pubkey_fields[] = { - { "flags", &cfg_type_uint32, 0 }, - { "protocol", &cfg_type_uint32, 0 }, - { "algorithm", &cfg_type_uint32, 0 }, - { "key", &cfg_type_qstring, 0 }, - { NULL, NULL, 0 } -}; -static cfg_type_t cfg_type_pubkey = { - "pubkey", parse_tuple, print_tuple, &cfg_rep_tuple, pubkey_fields }; - - -/* - * A list of RR types, used in grant statements. - * Note that the old parser allows quotes around the RR type names. - */ -static cfg_type_t cfg_type_rrtypelist = { - "rrtypelist", parse_spacelist, print_spacelist, &cfg_rep_list, - &cfg_type_astring -}; - -static const char *mode_enums[] = { "grant", "deny", NULL }; -static cfg_type_t cfg_type_mode = { - "mode", parse_enum, print_ustring, &cfg_rep_string, - &mode_enums -}; - -static const char *matchtype_enums[] = { - "name", "subdomain", "wildcard", "self", NULL }; -static cfg_type_t cfg_type_matchtype = { - "matchtype", parse_enum, print_ustring, &cfg_rep_string, - &matchtype_enums -}; - -/* - * A grant statement, used in the update policy. - */ -static cfg_tuplefielddef_t grant_fields[] = { - { "mode", &cfg_type_mode, 0 }, - { "identity", &cfg_type_astring, 0 }, /* domain name */ - { "matchtype", &cfg_type_matchtype, 0 }, - { "name", &cfg_type_astring, 0 }, /* domain name */ - { "types", &cfg_type_rrtypelist, 0 }, - { NULL, NULL, 0 } -}; -static cfg_type_t cfg_type_grant = { - "grant", parse_tuple, print_tuple, &cfg_rep_tuple, grant_fields }; - -static cfg_type_t cfg_type_updatepolicy = { - "update_policy", parse_bracketed_list, print_bracketed_list, - &cfg_rep_list, &cfg_type_grant -}; - -/* - * A view statement. - */ -static cfg_tuplefielddef_t view_fields[] = { - { "name", &cfg_type_astring, 0 }, - { "class", &cfg_type_optional_class, 0 }, - { "options", &cfg_type_viewopts, 0 }, - { NULL, NULL, 0 } -}; -static cfg_type_t cfg_type_view = { - "view", parse_tuple, print_tuple, &cfg_rep_tuple, view_fields }; - -/* - * A zone statement. - */ -static cfg_tuplefielddef_t zone_fields[] = { - { "name", &cfg_type_astring, 0 }, - { "class", &cfg_type_optional_class, 0 }, - { "options", &cfg_type_zoneopts, 0 }, - { NULL, NULL, 0 } -}; -static cfg_type_t cfg_type_zone = { - "zone", parse_tuple, print_tuple, &cfg_rep_tuple, zone_fields }; - -/* - * A "category" clause in the "logging" statement. - */ -static cfg_tuplefielddef_t category_fields[] = { - { "name", &cfg_type_astring, 0 }, - { "destinations", &cfg_type_destinationlist,0 }, - { NULL, NULL, 0 } -}; -static cfg_type_t cfg_type_category = { - "category", parse_tuple, print_tuple, &cfg_rep_tuple, category_fields }; - - -/* - * A trusted key, as used in the "trusted-keys" statement. - */ -static cfg_tuplefielddef_t trustedkey_fields[] = { - { "name", &cfg_type_astring, 0 }, - { "flags", &cfg_type_uint32, 0 }, - { "protocol", &cfg_type_uint32, 0 }, - { "algorithm", &cfg_type_uint32, 0 }, - { "key", &cfg_type_qstring, 0 }, - { NULL, NULL, 0 } -}; -static cfg_type_t cfg_type_trustedkey = { - "trustedkey", parse_tuple, print_tuple, &cfg_rep_tuple, - trustedkey_fields -}; - - -static keyword_type_t wild_class_kw = { "class", &cfg_type_ustring }; - -static cfg_type_t cfg_type_optional_wild_class = { - "optional_wild_class", parse_optional_keyvalue, - print_keyvalue, &cfg_rep_string, &wild_class_kw -}; - -static keyword_type_t wild_type_kw = { "type", &cfg_type_ustring }; - -static cfg_type_t cfg_type_optional_wild_type = { - "optional_wild_type", parse_optional_keyvalue, - print_keyvalue, &cfg_rep_string, &wild_type_kw -}; - -static keyword_type_t wild_name_kw = { "name", &cfg_type_qstring }; - -static cfg_type_t cfg_type_optional_wild_name = { - "optional_wild_name", parse_optional_keyvalue, - print_keyvalue, &cfg_rep_string, &wild_name_kw -}; - -/* - * An rrset ordering element. - */ -static cfg_tuplefielddef_t rrsetorderingelement_fields[] = { - { "class", &cfg_type_optional_wild_class, 0 }, - { "type", &cfg_type_optional_wild_type, 0 }, - { "name", &cfg_type_optional_wild_name, 0 }, - { "order", &cfg_type_ustring, 0 }, /* must be literal "order" */ - { "ordering", &cfg_type_ustring, 0 }, - { NULL, NULL, 0 } -}; -static cfg_type_t cfg_type_rrsetorderingelement = { - "rrsetorderingelement", parse_tuple, print_tuple, &cfg_rep_tuple, - rrsetorderingelement_fields -}; - -/* - * A global or view "check-names" option. Note that the zone - * "check-names" option has a different syntax. - */ -static cfg_tuplefielddef_t checknames_fields[] = { - { "type", &cfg_type_ustring, 0 }, - { "mode", &cfg_type_ustring, 0 }, - { NULL, NULL, 0 } -}; -static cfg_type_t cfg_type_checknames = { - "checknames", parse_tuple, print_tuple, &cfg_rep_tuple, - checknames_fields -}; - -static cfg_type_t cfg_type_bracketed_sockaddrlist = { - "bracketed_sockaddrlist", parse_bracketed_list, print_bracketed_list, - &cfg_rep_list, &cfg_type_sockaddr -}; - -static cfg_type_t cfg_type_rrsetorder = { - "rrsetorder", parse_bracketed_list, print_bracketed_list, - &cfg_rep_list, &cfg_type_rrsetorderingelement -}; - -static keyword_type_t port_kw = { "port", &cfg_type_uint32 }; - -static cfg_type_t cfg_type_optional_port = { - "optional_port", parse_optional_keyvalue, print_keyvalue, - &cfg_rep_uint32, &port_kw -}; - -/* A list of keys, as in the "key" clause of the controls statement. */ -static cfg_type_t cfg_type_keylist = { - "keylist", parse_bracketed_list, print_bracketed_list, &cfg_rep_list, - &cfg_type_astring -}; - -static cfg_type_t cfg_type_trustedkeys = { - "trusted-keys", parse_bracketed_list, print_bracketed_list, &cfg_rep_list, - &cfg_type_trustedkey -}; - /* * An implicit list. These are formed by clauses that occur multiple times. */ static cfg_type_t cfg_type_implicitlist = { - "implicitlist", NULL, print_list, &cfg_rep_list, NULL }; - -static const char *forwardtype_enums[] = { "first", "only", NULL }; -static cfg_type_t cfg_type_forwardtype = { - "forwardtype", parse_enum, print_ustring, &cfg_rep_string, - &forwardtype_enums -}; - -static const char *zonetype_enums[] = { - "master", "slave", "stub", "hint", "forward", "delegation-only", NULL }; -static cfg_type_t cfg_type_zonetype = { - "zonetype", parse_enum, print_ustring, &cfg_rep_string, - &zonetype_enums -}; - -static const char *loglevel_enums[] = { - "critical", "error", "warning", "notice", "info", "dynamic", NULL }; -static cfg_type_t cfg_type_loglevel = { - "loglevel", parse_enum, print_ustring, &cfg_rep_string, - &loglevel_enums -}; - -static const char *transferformat_enums[] = { - "many-answers", "one-answer", NULL }; -static cfg_type_t cfg_type_transferformat = { - "transferformat", parse_enum, print_ustring, &cfg_rep_string, - &transferformat_enums -}; - -/* - * Clauses that can be found within the top level of the named.conf - * file only. - */ -static cfg_clausedef_t -namedconf_clauses[] = { - { "options", &cfg_type_options, 0 }, - { "controls", &cfg_type_controls, CFG_CLAUSEFLAG_MULTI }, - { "acl", &cfg_type_acl, CFG_CLAUSEFLAG_MULTI }, - { "logging", &cfg_type_logging, 0 }, - { "view", &cfg_type_view, CFG_CLAUSEFLAG_MULTI }, - { "lwres", &cfg_type_lwres, CFG_CLAUSEFLAG_MULTI }, - { NULL, NULL, 0 } -}; - -/* - * Clauses that can occur at the top level or in the view - * statement, but not in the options block. - */ -static cfg_clausedef_t -namedconf_or_view_clauses[] = { - { "key", &cfg_type_key, CFG_CLAUSEFLAG_MULTI }, - { "zone", &cfg_type_zone, CFG_CLAUSEFLAG_MULTI }, - { "server", &cfg_type_server, CFG_CLAUSEFLAG_MULTI }, -#ifdef ISC_RFC2535 - { "trusted-keys", &cfg_type_trustedkeys, CFG_CLAUSEFLAG_MULTI }, -#else - { "trusted-keys", &cfg_type_trustedkeys, - CFG_CLAUSEFLAG_MULTI|CFG_CLAUSEFLAG_OBSOLETE }, -#endif - { NULL, NULL, 0 } -}; - -/* - * Clauses that can be found within the 'options' statement. - */ -static cfg_clausedef_t -options_clauses[] = { - { "blackhole", &cfg_type_bracketed_aml, 0 }, - { "coresize", &cfg_type_size, 0 }, - { "datasize", &cfg_type_size, 0 }, - { "deallocate-on-exit", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, - { "directory", &cfg_type_qstring, CFG_CLAUSEFLAG_CALLBACK }, - { "dump-file", &cfg_type_qstring, 0 }, - { "fake-iquery", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, - { "files", &cfg_type_size, 0 }, - { "has-old-clients", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, - { "heartbeat-interval", &cfg_type_uint32, 0 }, - { "host-statistics", &cfg_type_boolean, CFG_CLAUSEFLAG_NOTIMP }, - { "interface-interval", &cfg_type_uint32, 0 }, - { "listen-on", &cfg_type_listenon, CFG_CLAUSEFLAG_MULTI }, - { "listen-on-v6", &cfg_type_listenon, CFG_CLAUSEFLAG_MULTI }, - { "match-mapped-addresses", &cfg_type_boolean, 0 }, - { "memstatistics-file", &cfg_type_qstring, CFG_CLAUSEFLAG_NOTIMP }, - { "multiple-cnames", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, - { "named-xfer", &cfg_type_qstring, CFG_CLAUSEFLAG_OBSOLETE }, - { "pid-file", &cfg_type_qstring, 0 }, - { "port", &cfg_type_uint32, 0 }, - { "random-device", &cfg_type_qstring, 0 }, - { "recursive-clients", &cfg_type_uint32, 0 }, - { "rrset-order", &cfg_type_rrsetorder, CFG_CLAUSEFLAG_NOTIMP }, - { "serial-queries", &cfg_type_uint32, CFG_CLAUSEFLAG_OBSOLETE }, - { "serial-query-rate", &cfg_type_uint32, 0 }, - { "stacksize", &cfg_type_size, 0 }, - { "statistics-file", &cfg_type_qstring, 0 }, - { "statistics-interval", &cfg_type_uint32, CFG_CLAUSEFLAG_NYI }, - { "tcp-clients", &cfg_type_uint32, 0 }, - { "tkey-dhkey", &cfg_type_tkey_dhkey, 0 }, - { "tkey-gssapi-credential", &cfg_type_qstring, 0 }, - { "tkey-domain", &cfg_type_qstring, 0 }, - { "transfers-per-ns", &cfg_type_uint32, 0 }, - { "transfers-in", &cfg_type_uint32, 0 }, - { "transfers-out", &cfg_type_uint32, 0 }, - { "treat-cr-as-space", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, - { "use-id-pool", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, - { "use-ixfr", &cfg_type_boolean, 0 }, - { "version", &cfg_type_qstring, 0 }, - { NULL, NULL, 0 } -}; - - -static cfg_type_t cfg_type_namelist = { - "namelist", parse_bracketed_list, print_bracketed_list, - &cfg_rep_list, &cfg_type_qstring }; - -static keyword_type_t exclude_kw = { "exclude", &cfg_type_namelist }; - -static cfg_type_t cfg_type_optional_exclude = { - "optional_exclude", parse_optional_keyvalue, print_keyvalue, - &cfg_rep_list, &exclude_kw }; - -/* - * Clauses that can be found within the 'view' statement, - * with defaults in the 'options' statement. - */ - -static cfg_clausedef_t -view_clauses[] = { - { "allow-recursion", &cfg_type_bracketed_aml, 0 }, - { "allow-v6-synthesis", &cfg_type_bracketed_aml, 0 }, - { "sortlist", &cfg_type_bracketed_aml, 0 }, - { "topology", &cfg_type_bracketed_aml, CFG_CLAUSEFLAG_NOTIMP }, - { "auth-nxdomain", &cfg_type_boolean, CFG_CLAUSEFLAG_NEWDEFAULT }, - { "minimal-responses", &cfg_type_boolean, 0 }, - { "recursion", &cfg_type_boolean, 0 }, - { "provide-ixfr", &cfg_type_boolean, 0 }, - { "request-ixfr", &cfg_type_boolean, 0 }, - { "fetch-glue", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, - { "rfc2308-type1", &cfg_type_boolean, CFG_CLAUSEFLAG_NYI }, - { "additional-from-auth", &cfg_type_boolean, 0 }, - { "additional-from-cache", &cfg_type_boolean, 0 }, - /* - * Note that the query-source option syntax is different - * from the other -source options. - */ - { "query-source", &cfg_type_querysource4, 0 }, - { "query-source-v6", &cfg_type_querysource6, 0 }, - { "cleaning-interval", &cfg_type_uint32, 0 }, - { "min-roots", &cfg_type_uint32, CFG_CLAUSEFLAG_NOTIMP }, - { "lame-ttl", &cfg_type_uint32, 0 }, - { "max-ncache-ttl", &cfg_type_uint32, 0 }, - { "max-cache-ttl", &cfg_type_uint32, 0 }, - { "transfer-format", &cfg_type_transferformat, 0 }, - { "max-cache-size", &cfg_type_sizenodefault, 0 }, - { "check-names", &cfg_type_checknames, - CFG_CLAUSEFLAG_MULTI | CFG_CLAUSEFLAG_NOTIMP }, - { "cache-file", &cfg_type_qstring, 0 }, - { "root-delegation-only", &cfg_type_optional_exclude, 0 }, - { NULL, NULL, 0 } -}; - -/* - * Clauses that can be found within the 'view' statement only. - */ -static cfg_clausedef_t -view_only_clauses[] = { - { "match-clients", &cfg_type_bracketed_aml, 0 }, - { "match-destinations", &cfg_type_bracketed_aml, 0 }, - { "match-recursive-only", &cfg_type_boolean, 0 }, - { NULL, NULL, 0 } -}; - -/* - * Clauses that can be found in a 'zone' statement, - * with defaults in the 'view' or 'options' statement. - */ -static cfg_clausedef_t -zone_clauses[] = { - { "allow-query", &cfg_type_bracketed_aml, 0 }, - { "allow-transfer", &cfg_type_bracketed_aml, 0 }, - { "allow-update-forwarding", &cfg_type_bracketed_aml, 0 }, - { "allow-notify", &cfg_type_bracketed_aml, 0 }, - { "notify", &cfg_type_notifytype, 0 }, - { "notify-source", &cfg_type_sockaddr4wild, 0 }, - { "notify-source-v6", &cfg_type_sockaddr6wild, 0 }, - { "also-notify", &cfg_type_portiplist, 0 }, - { "dialup", &cfg_type_dialuptype, 0 }, - { "forward", &cfg_type_forwardtype, 0 }, - { "forwarders", &cfg_type_portiplist, 0 }, - { "maintain-ixfr-base", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, - { "max-ixfr-log-size", &cfg_type_size, CFG_CLAUSEFLAG_OBSOLETE }, - { "transfer-source", &cfg_type_sockaddr4wild, 0 }, - { "transfer-source-v6", &cfg_type_sockaddr6wild, 0 }, - { "max-transfer-time-in", &cfg_type_uint32, 0 }, - { "max-transfer-time-out", &cfg_type_uint32, 0 }, - { "max-transfer-idle-in", &cfg_type_uint32, 0 }, - { "max-transfer-idle-out", &cfg_type_uint32, 0 }, - { "max-retry-time", &cfg_type_uint32, 0 }, - { "min-retry-time", &cfg_type_uint32, 0 }, - { "max-refresh-time", &cfg_type_uint32, 0 }, - { "min-refresh-time", &cfg_type_uint32, 0 }, - { "sig-validity-interval", &cfg_type_uint32, 0 }, - { "zone-statistics", &cfg_type_boolean, 0 }, - { NULL, NULL, 0 } -}; - -/* - * Clauses that can be found in a 'zone' statement - * only. - */ -static cfg_clausedef_t -zone_only_clauses[] = { - { "type", &cfg_type_zonetype, 0 }, - { "allow-update", &cfg_type_bracketed_aml, 0 }, - { "file", &cfg_type_qstring, 0 }, - { "ixfr-base", &cfg_type_qstring, CFG_CLAUSEFLAG_OBSOLETE }, - { "ixfr-tmp-file", &cfg_type_qstring, CFG_CLAUSEFLAG_OBSOLETE }, - { "masters", &cfg_type_sockaddrkeylist, 0 }, - { "pubkey", &cfg_type_pubkey, - CFG_CLAUSEFLAG_MULTI | CFG_CLAUSEFLAG_OBSOLETE }, - { "update-policy", &cfg_type_updatepolicy, 0 }, - { "database", &cfg_type_astring, 0 }, - { "delegation-only", &cfg_type_boolean, 0 }, - /* - * Note that the format of the check-names option is different between - * the zone options and the global/view options. Ugh. - */ - { "check-names", &cfg_type_ustring, CFG_CLAUSEFLAG_NOTIMP }, - { NULL, NULL, 0 } -}; - - -/* The top-level named.conf syntax. */ - -static cfg_clausedef_t * -namedconf_clausesets[] = { - namedconf_clauses, - namedconf_or_view_clauses, - NULL -}; - -LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_namedconf = { - "namedconf", parse_mapbody, print_mapbody, &cfg_rep_map, - namedconf_clausesets -}; - -/* The "options" statement syntax. */ - -static cfg_clausedef_t * -options_clausesets[] = { - options_clauses, - view_clauses, - zone_clauses, - NULL -}; -static cfg_type_t cfg_type_options = { - "options", parse_map, print_map, &cfg_rep_map, options_clausesets }; - -/* The "view" statement syntax. */ - -static cfg_clausedef_t * -view_clausesets[] = { - view_only_clauses, - namedconf_or_view_clauses, - view_clauses, - zone_clauses, - NULL -}; -static cfg_type_t cfg_type_viewopts = { - "view", parse_map, print_map, &cfg_rep_map, view_clausesets }; - -/* The "zone" statement syntax. */ - -static cfg_clausedef_t * -zone_clausesets[] = { - zone_only_clauses, - zone_clauses, - NULL -}; -static cfg_type_t cfg_type_zoneopts = { - "zoneopts", parse_map, print_map, &cfg_rep_map, zone_clausesets }; - -/* - * Clauses that can be found within the 'key' statement. - */ -static cfg_clausedef_t -key_clauses[] = { - { "algorithm", &cfg_type_astring, 0 }, - { "secret", &cfg_type_astring, 0 }, - { NULL, NULL, 0 } -}; - -static cfg_clausedef_t * -key_clausesets[] = { - key_clauses, - NULL -}; -static cfg_type_t cfg_type_key = { - "key", parse_named_map, print_map, &cfg_rep_map, key_clausesets }; - - -/* - * Clauses that can be found in a 'server' statement. - */ -static cfg_clausedef_t -server_clauses[] = { - { "bogus", &cfg_type_boolean, 0 }, - { "provide-ixfr", &cfg_type_boolean, 0 }, - { "request-ixfr", &cfg_type_boolean, 0 }, - { "support-ixfr", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, - { "transfers", &cfg_type_uint32, 0 }, - { "transfer-format", &cfg_type_transferformat, 0 }, - { "keys", &cfg_type_server_key_kludge, 0 }, - { "edns", &cfg_type_boolean, 0 }, - { NULL, NULL, 0 } -}; -static cfg_clausedef_t * -server_clausesets[] = { - server_clauses, - NULL -}; -static cfg_type_t cfg_type_server = { - "server", parse_addressed_map, print_map, &cfg_rep_map, - server_clausesets -}; - - -/* - * Clauses that can be found in a 'channel' clause in the - * 'logging' statement. - * - * These have some additional constraints that need to be - * checked after parsing: - * - There must exactly one of file/syslog/null/stderr - * - */ -static cfg_clausedef_t -channel_clauses[] = { - /* Destinations. We no longer require these to be first. */ - { "file", &cfg_type_logfile, 0 }, - { "syslog", &cfg_type_optional_facility, 0 }, - { "null", &cfg_type_void, 0 }, - { "stderr", &cfg_type_void, 0 }, - /* Options. We now accept these for the null channel, too. */ - { "severity", &cfg_type_logseverity, 0 }, - { "print-time", &cfg_type_boolean, 0 }, - { "print-severity", &cfg_type_boolean, 0 }, - { "print-category", &cfg_type_boolean, 0 }, - { NULL, NULL, 0 } -}; -static cfg_clausedef_t * -channel_clausesets[] = { - channel_clauses, - NULL -}; -static cfg_type_t cfg_type_channel = { - "channel", parse_named_map, print_map, - &cfg_rep_map, channel_clausesets -}; - -/* A list of log destination, used in the "category" clause. */ -static cfg_type_t cfg_type_destinationlist = { - "destinationlist", parse_bracketed_list, print_bracketed_list, - &cfg_rep_list, &cfg_type_astring }; - -/* - * Clauses that can be found in a 'logging' statement. - */ -static cfg_clausedef_t -logging_clauses[] = { - { "channel", &cfg_type_channel, CFG_CLAUSEFLAG_MULTI }, - { "category", &cfg_type_category, CFG_CLAUSEFLAG_MULTI }, - { NULL, NULL, 0 } -}; -static cfg_clausedef_t * -logging_clausesets[] = { - logging_clauses, - NULL -}; -static cfg_type_t cfg_type_logging = { - "logging", parse_map, print_map, &cfg_rep_map, logging_clausesets }; - + "implicitlist", NULL, print_list, NULL, &cfg_rep_list, NULL }; /* Functions. */ -static void -print_obj(cfg_printer_t *pctx, cfg_obj_t *obj) { +void +cfg_print_obj(cfg_printer_t *pctx, cfg_obj_t *obj) { obj->type->print(pctx, obj); } -static void -print(cfg_printer_t *pctx, const char *text, int len) { +void +cfg_print_chars(cfg_printer_t *pctx, const char *text, int len) { pctx->f(pctx->closure, text, len); } static void print_open(cfg_printer_t *pctx) { - print(pctx, "{\n", 2); + cfg_print_chars(pctx, "{\n", 2); pctx->indent++; } @@ -1150,7 +153,7 @@ static void print_indent(cfg_printer_t *pctx) { int indent = pctx->indent; while (indent > 0) { - print(pctx, "\t", 1); + cfg_print_chars(pctx, "\t", 1); indent--; } } @@ -1159,11 +162,11 @@ static void print_close(cfg_printer_t *pctx) { pctx->indent--; print_indent(pctx); - print(pctx, "}", 1); + cfg_print_chars(pctx, "}", 1); } -static isc_result_t -parse(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { +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); result = type->parse(pctx, type, ret); @@ -1188,8 +191,8 @@ cfg_print(cfg_obj_t *obj, /* Tuples. */ -static isc_result_t -create_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { +isc_result_t +cfg_create_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { isc_result_t result; const cfg_tuplefielddef_t *fields = type->of; const cfg_tuplefielddef_t *f; @@ -1200,7 +203,7 @@ create_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { for (f = fields; f->name != NULL; f++) nfields++; - CHECK(create_cfgobj(pctx, type, &obj)); + CHECK(cfg_create_obj(pctx, type, &obj)); obj->value.tuple = isc_mem_get(pctx->mctx, nfields * sizeof(cfg_obj_t *)); if (obj->value.tuple == NULL) { @@ -1218,8 +221,8 @@ create_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { return (result); } -static isc_result_t -parse_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) +isc_result_t +cfg_parse_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { isc_result_t result; const cfg_tuplefielddef_t *fields = type->of; @@ -1227,9 +230,9 @@ parse_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) cfg_obj_t *obj = NULL; unsigned int i; - CHECK(create_tuple(pctx, type, &obj)); + CHECK(cfg_create_tuple(pctx, type, &obj)); for (f = fields, i = 0; f->name != NULL; f++, i++) - CHECK(parse(pctx, f->type, &obj->value.tuple[i])); + CHECK(cfg_parse_obj(pctx, f->type, &obj->value.tuple[i])); *ret = obj; return (ISC_R_SUCCESS); @@ -1239,8 +242,8 @@ parse_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) return (result); } -static void -print_tuple(cfg_printer_t *pctx, cfg_obj_t *obj) { +void +cfg_print_tuple(cfg_printer_t *pctx, cfg_obj_t *obj) { unsigned int i; const cfg_tuplefielddef_t *fields = obj->type->of; const cfg_tuplefielddef_t *f; @@ -1249,9 +252,23 @@ print_tuple(cfg_printer_t *pctx, cfg_obj_t *obj) { for (f = fields, i = 0; f->name != NULL; f++, i++) { cfg_obj_t *fieldobj = obj->value.tuple[i]; if (need_space) - print(pctx, " ", 1); - print_obj(pctx, fieldobj); - need_space = ISC_TF(fieldobj->type->print != print_void); + cfg_print_chars(pctx, " ", 1); + cfg_print_obj(pctx, fieldobj); + need_space = ISC_TF(fieldobj->type->print != cfg_print_void); + } +} + +void +cfg_doc_tuple(cfg_printer_t *pctx, const cfg_type_t *type) { + const cfg_tuplefielddef_t *fields = type->of; + const cfg_tuplefielddef_t *f; + isc_boolean_t need_space = ISC_FALSE; + + for (f = fields; f->name != NULL; f++) { + if (need_space) + cfg_print_chars(pctx, " ", 1); + cfg_doc_obj(pctx, f->type); + need_space = ISC_TF(f->type->print != cfg_print_void); } } @@ -1296,18 +313,15 @@ cfg_tuple_get(cfg_obj_t *tupleobj, const char* name) { return (NULL); } -/* - * Parse a required special character. - */ -static isc_result_t -parse_special(cfg_parser_t *pctx, int special) { +isc_result_t +cfg_parse_special(cfg_parser_t *pctx, int special) { isc_result_t result; CHECK(cfg_gettoken(pctx, 0)); if (pctx->token.type == isc_tokentype_special && pctx->token.value.as_char == special) return (ISC_R_SUCCESS); - parser_error(pctx, LOG_NEAR, "'%c' expected", special); + cfg_parser_error(pctx, CFG_LOG_NEAR, "'%c' expected", special); return (ISC_R_UNEXPECTEDTOKEN); cleanup: return (result); @@ -1328,7 +342,7 @@ parse_semicolon(cfg_parser_t *pctx) { pctx->token.value.as_char == ';') return (ISC_R_SUCCESS); - parser_error(pctx, LOG_BEFORE, "missing ';'"); + cfg_parser_error(pctx, CFG_LOG_BEFORE, "missing ';'"); cfg_ungettoken(pctx); cleanup: return (result); @@ -1345,22 +359,21 @@ parse_eof(cfg_parser_t *pctx) { if (pctx->token.type == isc_tokentype_eof) return (ISC_R_SUCCESS); - parser_error(pctx, LOG_NEAR, "syntax error"); + cfg_parser_error(pctx, CFG_LOG_NEAR, "syntax error"); return (ISC_R_UNEXPECTEDTOKEN); cleanup: - return(result); + return (result); } /* A list of files, used internally for pctx->files. */ static cfg_type_t cfg_type_filelist = { - "filelist", NULL, print_list, &cfg_rep_list, + "filelist", NULL, print_list, NULL, &cfg_rep_list, &cfg_type_qstring }; isc_result_t -cfg_parser_create(isc_mem_t *mctx, isc_log_t *lctx, cfg_parser_t **ret) -{ +cfg_parser_create(isc_mem_t *mctx, isc_log_t *lctx, cfg_parser_t **ret) { isc_result_t result; cfg_parser_t *pctx; isc_lexspecials_t specials; @@ -1401,8 +414,8 @@ cfg_parser_create(isc_mem_t *mctx, isc_log_t *lctx, cfg_parser_t **ret) ISC_LEXCOMMENT_CPLUSPLUS | ISC_LEXCOMMENT_SHELL)); - CHECK(create_list(pctx, &cfg_type_filelist, &pctx->open_files)); - CHECK(create_list(pctx, &cfg_type_filelist, &pctx->closed_files)); + CHECK(cfg_create_list(pctx, &cfg_type_filelist, &pctx->open_files)); + CHECK(cfg_create_list(pctx, &cfg_type_filelist, &pctx->closed_files)); *ret = pctx; return (ISC_R_SUCCESS); @@ -1424,7 +437,7 @@ parser_openfile(cfg_parser_t *pctx, const char *filename) { result = isc_lex_openfile(pctx->lexer, filename); if (result != ISC_R_SUCCESS) { - parser_error(pctx, 0, "open: %s: %s", + cfg_parser_error(pctx, 0, "open: %s: %s", filename, isc_result_totext(result)); goto cleanup; } @@ -1458,7 +471,7 @@ parse2(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { isc_result_t result; cfg_obj_t *obj = NULL; - result = parse(pctx, type, &obj); + result = cfg_parse_obj(pctx, type, &obj); if (pctx->errors != 0) { /* Errors have been logged. */ @@ -1469,7 +482,7 @@ parse2(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { if (result != ISC_R_SUCCESS) { /* Parsing failed but no errors have been logged. */ - parser_error(pctx, 0, "parsing failed"); + cfg_parser_error(pctx, 0, "parsing failed"); goto cleanup; } @@ -1528,44 +541,51 @@ cfg_parser_destroy(cfg_parser_t **pctxp) { /* * void */ -static isc_result_t -parse_void(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { +isc_result_t +cfg_parse_void(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { UNUSED(type); - return (create_cfgobj(pctx, &cfg_type_void, ret)); + return (cfg_create_obj(pctx, &cfg_type_void, ret)); } -static void -print_void(cfg_printer_t *pctx, cfg_obj_t *obj) { +void +cfg_print_void(cfg_printer_t *pctx, cfg_obj_t *obj) { UNUSED(pctx); UNUSED(obj); } +void +cfg_doc_void(cfg_printer_t *pctx, const cfg_type_t *type) { + UNUSED(pctx); + UNUSED(type); +} + 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 }; +cfg_type_t cfg_type_void = { + "void", cfg_parse_void, cfg_print_void, cfg_doc_void, &cfg_rep_void, + NULL }; /* * uint32 */ -static isc_result_t -parse_uint32(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { +isc_result_t +cfg_parse_uint32(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { isc_result_t result; cfg_obj_t *obj = NULL; UNUSED(type); CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER)); if (pctx->token.type != isc_tokentype_number) { - parser_error(pctx, LOG_NEAR, "expected number"); + cfg_parser_error(pctx, CFG_LOG_NEAR, "expected number"); return (ISC_R_UNEXPECTEDTOKEN); } - CHECK(create_cfgobj(pctx, &cfg_type_uint32, &obj)); + CHECK(cfg_create_obj(pctx, &cfg_type_uint32, &obj)); obj->value.uint32 = pctx->token.value.as_ulong; *ret = obj; @@ -1573,21 +593,21 @@ parse_uint32(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { return (result); } -static void -print_cstr(cfg_printer_t *pctx, const char *s) { - print(pctx, s, strlen(s)); +void +cfg_print_cstr(cfg_printer_t *pctx, const char *s) { + cfg_print_chars(pctx, s, strlen(s)); } -static void -print_uint(cfg_printer_t *pctx, unsigned int u) { +void +cfg_print_rawuint(cfg_printer_t *pctx, unsigned int u) { char buf[32]; snprintf(buf, sizeof(buf), "%u", u); - print_cstr(pctx, buf); + cfg_print_cstr(pctx, buf); } -static void -print_uint32(cfg_printer_t *pctx, cfg_obj_t *obj) { - print_uint(pctx, obj->value.uint32); +void +cfg_print_uint32(cfg_printer_t *pctx, cfg_obj_t *obj) { + cfg_print_rawuint(pctx, obj->value.uint32); } isc_boolean_t @@ -1602,8 +622,10 @@ cfg_obj_asuint32(cfg_obj_t *obj) { return (obj->value.uint32); } -static cfg_type_t cfg_type_uint32 = { - "integer", parse_uint32, print_uint32, &cfg_rep_uint32, NULL }; +cfg_type_t cfg_type_uint32 = { + "integer", cfg_parse_uint32, cfg_print_uint32, cfg_doc_terminal, + &cfg_rep_uint32, NULL +}; /* @@ -1621,162 +643,22 @@ cfg_obj_asuint64(cfg_obj_t *obj) { return (obj->value.uint64); } -static isc_result_t -parse_unitstring(char *str, isc_resourcevalue_t *valuep) { - char *endp; - unsigned int len; - isc_uint64_t value; - isc_uint64_t unit; - - value = isc_string_touint64(str, &endp, 10); - if (*endp == 0) { - *valuep = value; - return (ISC_R_SUCCESS); - } - - len = strlen(str); - if (len < 2 || endp[1] != '\0') - return (ISC_R_FAILURE); - - switch (str[len - 1]) { - case 'k': - case 'K': - unit = 1024; - break; - case 'm': - case 'M': - unit = 1024 * 1024; - break; - case 'g': - case 'G': - unit = 1024 * 1024 * 1024; - break; - default: - return (ISC_R_FAILURE); - } - if (value > ISC_UINT64_MAX / unit) - return (ISC_R_FAILURE); - *valuep = value * unit; - return (ISC_R_SUCCESS); -} - -static void -print_uint64(cfg_printer_t *pctx, cfg_obj_t *obj) { +void +cfg_print_uint64(cfg_printer_t *pctx, cfg_obj_t *obj) { char buf[32]; snprintf(buf, sizeof(buf), "%" ISC_PRINT_QUADFORMAT "u", obj->value.uint64); - print_cstr(pctx, buf); -} - -static cfg_type_t cfg_type_uint64 = { - "64_bit_integer", NULL, print_uint64, &cfg_rep_uint64, NULL }; - -static isc_result_t -parse_sizeval(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - isc_result_t result; - cfg_obj_t *obj = NULL; - isc_uint64_t val; - - UNUSED(type); - - CHECK(cfg_gettoken(pctx, 0)); - if (pctx->token.type != isc_tokentype_string) { - result = ISC_R_UNEXPECTEDTOKEN; - goto cleanup; - } - CHECK(parse_unitstring(pctx->token.value.as_pointer, &val)); - - CHECK(create_cfgobj(pctx, &cfg_type_uint64, &obj)); - obj->value.uint64 = val; - *ret = obj; - return (ISC_R_SUCCESS); - - cleanup: - parser_error(pctx, LOG_NEAR, "expected integer and optional unit"); - return (result); + cfg_print_cstr(pctx, buf); } -/* - * A size value (number + optional unit). - */ -static cfg_type_t cfg_type_sizeval = { - "sizeval", parse_sizeval, print_uint64, &cfg_rep_uint64, NULL }; - -/* - * A size, "unlimited", or "default". - */ - -static isc_result_t -parse_size(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - return (parse_enum_or_other(pctx, type, &cfg_type_sizeval, ret)); -} - -static const char *size_enums[] = { "unlimited", "default", NULL }; -static cfg_type_t cfg_type_size = { - "size", parse_size, print_ustring, &cfg_rep_string, size_enums +cfg_type_t cfg_type_uint64 = { + "64_bit_integer", NULL, cfg_print_uint64, cfg_doc_terminal, + &cfg_rep_uint64, NULL }; /* - * A size or "unlimited", but not "default". - */ -static const char *sizenodefault_enums[] = { "unlimited", NULL }; -static cfg_type_t cfg_type_sizenodefault = { - "size_no_default", parse_size, print_ustring, &cfg_rep_string, - sizenodefault_enums -}; - -/* - * optional_keyvalue - */ -static isc_result_t -parse_maybe_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, - isc_boolean_t optional, cfg_obj_t **ret) -{ - isc_result_t result; - cfg_obj_t *obj = NULL; - const keyword_type_t *kw = type->of; - - CHECK(cfg_peektoken(pctx, 0)); - if (pctx->token.type == isc_tokentype_string && - strcasecmp(pctx->token.value.as_pointer, kw->name) == 0) { - CHECK(cfg_gettoken(pctx, 0)); - CHECK(kw->type->parse(pctx, kw->type, &obj)); - obj->type = type; /* XXX kludge */ - } else { - if (optional) { - CHECK(parse_void(pctx, NULL, &obj)); - } else { - parser_error(pctx, LOG_NEAR, "expected '%s'", - kw->name); - result = ISC_R_UNEXPECTEDTOKEN; - goto cleanup; - } - } - *ret = obj; - cleanup: - return (result); -} - -static isc_result_t -parse_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - return (parse_maybe_optional_keyvalue(pctx, type, ISC_FALSE, ret)); -} - -static isc_result_t -parse_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - return (parse_maybe_optional_keyvalue(pctx, type, ISC_TRUE, ret)); -} - -static void -print_keyvalue(cfg_printer_t *pctx, cfg_obj_t *obj) { - const keyword_type_t *kw = obj->type->of; - print_cstr(pctx, kw->name); - print(pctx, " ", 1); - kw->type->print(pctx, obj); -} - -/* - * qstring, ustring, astring + * qstring (quoted string), ustring (unquoted string), astring + * (any string) */ /* Create a string object from a null-terminated C string. */ @@ -1788,7 +670,7 @@ create_string(cfg_parser_t *pctx, const char *contents, const cfg_type_t *type, cfg_obj_t *obj = NULL; int len; - CHECK(create_cfgobj(pctx, type, &obj)); + CHECK(cfg_create_obj(pctx, type, &obj)); len = strlen(contents); obj->value.string.length = len; obj->value.string.base = isc_mem_get(pctx->mctx, len + 1); @@ -1804,18 +686,18 @@ create_string(cfg_parser_t *pctx, const char *contents, const cfg_type_t *type, return (result); } -static isc_result_t -parse_qstring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { +isc_result_t +cfg_parse_qstring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { isc_result_t result; UNUSED(type); - CHECK(cfg_gettoken(pctx, QSTRING)); + CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING)); if (pctx->token.type != isc_tokentype_qstring) { - parser_error(pctx, LOG_NEAR, "expected quoted string"); + cfg_parser_error(pctx, CFG_LOG_NEAR, "expected quoted string"); return (ISC_R_UNEXPECTEDTOKEN); } return (create_string(pctx, - pctx->token.value.as_pointer, + TOKEN_STRING(pctx), &cfg_type_qstring, ret)); cleanup: @@ -1829,33 +711,33 @@ parse_ustring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { CHECK(cfg_gettoken(pctx, 0)); if (pctx->token.type != isc_tokentype_string) { - parser_error(pctx, LOG_NEAR, "expected unquoted string"); + cfg_parser_error(pctx, CFG_LOG_NEAR, "expected unquoted string"); return (ISC_R_UNEXPECTEDTOKEN); } return (create_string(pctx, - pctx->token.value.as_pointer, + TOKEN_STRING(pctx), &cfg_type_ustring, ret)); cleanup: return (result); } -static isc_result_t -parse_astring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { +isc_result_t +cfg_parse_astring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { isc_result_t result; UNUSED(type); CHECK(cfg_getstringtoken(pctx)); return (create_string(pctx, - pctx->token.value.as_pointer, + TOKEN_STRING(pctx), &cfg_type_qstring, ret)); cleanup: return (result); } -static isc_boolean_t -is_enum(const char *s, const char *const *enums) { +isc_boolean_t +cfg_is_enum(const char *s, const char *const *enums) { const char * const *p; for (p = enums; *p != NULL; p++) { if (strcasecmp(*p, s) == 0) @@ -1867,14 +749,14 @@ 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 (is_enum(s, enums)) + if (cfg_is_enum(s, enums)) return (ISC_R_SUCCESS); - parser_error(pctx, 0, "'%s' unexpected", s); + cfg_parser_error(pctx, 0, "'%s' unexpected", s); return (ISC_R_UNEXPECTEDTOKEN); } -static isc_result_t -parse_enum(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { +isc_result_t +cfg_parse_enum(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { isc_result_t result; cfg_obj_t *obj = NULL; CHECK(parse_ustring(pctx, NULL, &obj)); @@ -1886,36 +768,28 @@ parse_enum(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { return (result); } -static isc_result_t -parse_enum_or_other(cfg_parser_t *pctx, const cfg_type_t *enumtype, - const cfg_type_t *othertype, cfg_obj_t **ret) -{ - isc_result_t result; - CHECK(cfg_peektoken(pctx, 0)); - if (pctx->token.type == isc_tokentype_string && - is_enum(pctx->token.value.as_pointer, enumtype->of)) { - CHECK(parse_enum(pctx, enumtype, ret)); - } else { - CHECK(parse(pctx, othertype, ret)); +void +cfg_doc_enum(cfg_printer_t *pctx, const cfg_type_t *type) { + const char * const *p; + cfg_print_chars(pctx, "( ", 2); + for (p = type->of; *p != NULL; p++) { + cfg_print_cstr(pctx, *p); + if (p[1] != NULL) + cfg_print_chars(pctx, " | ", 3); } - cleanup: - return (result); + cfg_print_chars(pctx, " )", 2); } - -/* - * Print a string object. - */ -static void -print_ustring(cfg_printer_t *pctx, cfg_obj_t *obj) { - print(pctx, obj->value.string.base, obj->value.string.length); +void +cfg_print_ustring(cfg_printer_t *pctx, cfg_obj_t *obj) { + cfg_print_chars(pctx, obj->value.string.base, obj->value.string.length); } static void print_qstring(cfg_printer_t *pctx, cfg_obj_t *obj) { - print(pctx, "\"", 1); - print_ustring(pctx, obj); - print(pctx, "\"", 1); + cfg_print_chars(pctx, "\"", 1); + cfg_print_ustring(pctx, obj); + cfg_print_chars(pctx, "\"", 1); } static void @@ -1936,6 +810,28 @@ cfg_obj_asstring(cfg_obj_t *obj) { return (obj->value.string.base); } +/* Quoted string only */ +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 = { + "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 = { + "string", cfg_parse_astring, print_qstring, cfg_doc_terminal, + &cfg_rep_string, NULL +}; + +/* + * Booleans + */ + isc_boolean_t cfg_obj_isboolean(cfg_obj_t *obj) { REQUIRE(obj != NULL); @@ -1948,22 +844,6 @@ cfg_obj_asboolean(cfg_obj_t *obj) { return (obj->value.boolean); } -/* Quoted string only */ -static cfg_type_t cfg_type_qstring = { - "quoted_string", parse_qstring, print_qstring, &cfg_rep_string, NULL }; - -/* Unquoted string only */ -static cfg_type_t cfg_type_ustring = { - "string", parse_ustring, print_ustring, &cfg_rep_string, NULL }; - -/* Any string (quoted or unquoted); printed with quotes */ -static cfg_type_t cfg_type_astring = { - "string", parse_astring, print_qstring, &cfg_rep_string, NULL }; - - -/* - * boolean - */ static isc_result_t parse_boolean(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { @@ -1979,25 +859,25 @@ parse_boolean(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) if (pctx->token.type != isc_tokentype_string) goto bad_boolean; - if ((strcasecmp(pctx->token.value.as_pointer, "true") == 0) || - (strcasecmp(pctx->token.value.as_pointer, "yes") == 0) || - (strcmp(pctx->token.value.as_pointer, "1") == 0)) { + if ((strcasecmp(TOKEN_STRING(pctx), "true") == 0) || + (strcasecmp(TOKEN_STRING(pctx), "yes") == 0) || + (strcmp(TOKEN_STRING(pctx), "1") == 0)) { value = ISC_TRUE; - } else if ((strcasecmp(pctx->token.value.as_pointer, "false") == 0) || - (strcasecmp(pctx->token.value.as_pointer, "no") == 0) || - (strcmp(pctx->token.value.as_pointer, "0") == 0)) { + } else if ((strcasecmp(TOKEN_STRING(pctx), "false") == 0) || + (strcasecmp(TOKEN_STRING(pctx), "no") == 0) || + (strcmp(TOKEN_STRING(pctx), "0") == 0)) { value = ISC_FALSE; } else { goto bad_boolean; } - CHECK(create_cfgobj(pctx, &cfg_type_boolean, &obj)); + CHECK(cfg_create_obj(pctx, &cfg_type_boolean, &obj)); obj->value.boolean = value; *ret = obj; return (result); bad_boolean: - parser_error(pctx, LOG_NEAR, "boolean expected"); + cfg_parser_error(pctx, CFG_LOG_NEAR, "boolean expected"); return (ISC_R_UNEXPECTEDTOKEN); cleanup: @@ -2007,56 +887,24 @@ parse_boolean(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) static void print_boolean(cfg_printer_t *pctx, cfg_obj_t *obj) { if (obj->value.boolean) - print(pctx, "yes", 3); + cfg_print_chars(pctx, "yes", 3); else - print(pctx, "no", 2); + cfg_print_chars(pctx, "no", 2); } -static cfg_type_t cfg_type_boolean = { - "boolean", parse_boolean, print_boolean, &cfg_rep_boolean, NULL }; - -static const char *dialup_enums[] = { - "notify", "notify-passive", "refresh", "passive", NULL }; -static isc_result_t -parse_dialup_type(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret)); -} -static cfg_type_t cfg_type_dialuptype = { - "dialuptype", parse_dialup_type, print_ustring, - &cfg_rep_string, dialup_enums +cfg_type_t cfg_type_boolean = { + "boolean", parse_boolean, print_boolean, cfg_doc_terminal, + &cfg_rep_boolean, NULL }; -static const char *notify_enums[] = { "explicit", NULL }; -static isc_result_t -parse_notify_type(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret)); -} -static cfg_type_t cfg_type_notifytype = { - "notifytype", parse_notify_type, print_ustring, - &cfg_rep_string, notify_enums, -}; - -static keyword_type_t key_kw = { "key", &cfg_type_astring }; - -LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_keyref = { - "keyref", parse_keyvalue, print_keyvalue, - &cfg_rep_string, &key_kw -}; - -static cfg_type_t cfg_type_optional_keyref = { - "optional_keyref", parse_optional_keyvalue, print_keyvalue, - &cfg_rep_string, &key_kw -}; - - /* * Lists. */ -static isc_result_t -create_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **obj) { +isc_result_t +cfg_create_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **obj) { isc_result_t result; - CHECK(create_cfgobj(pctx, type, obj)); + CHECK(cfg_create_obj(pctx, type, obj)); ISC_LIST_INIT((*obj)->value.list); cleanup: return (result); @@ -2092,9 +940,9 @@ free_list(cfg_parser_t *pctx, cfg_obj_t *obj) { } } -static isc_result_t -parse_list_elt(cfg_parser_t *pctx, const cfg_type_t *elttype, - cfg_listelt_t **ret) +isc_result_t +cfg_parse_listelt(cfg_parser_t *pctx, const cfg_type_t *elttype, + cfg_listelt_t **ret) { isc_result_t result; cfg_listelt_t *elt = NULL; @@ -2102,7 +950,7 @@ parse_list_elt(cfg_parser_t *pctx, const cfg_type_t *elttype, CHECK(create_listelt(pctx, &elt)); - result = parse(pctx, elttype, &value); + result = cfg_parse_obj(pctx, elttype, &value); if (result != ISC_R_SUCCESS) goto cleanup; @@ -2128,14 +976,14 @@ parse_list(cfg_parser_t *pctx, const cfg_type_t *listtype, cfg_obj_t **ret) isc_result_t result; cfg_listelt_t *elt = NULL; - CHECK(create_list(pctx, listtype, &listobj)); + CHECK(cfg_create_list(pctx, listtype, &listobj)); for (;;) { CHECK(cfg_peektoken(pctx, 0)); if (pctx->token.type == isc_tokentype_special && pctx->token.value.as_char == /*{*/ '}') break; - CHECK(parse_list_elt(pctx, listof, &elt)); + CHECK(cfg_parse_listelt(pctx, listof, &elt)); CHECK(parse_semicolon(pctx)); ISC_LIST_APPEND(listobj->value.list, elt, link); elt = NULL; @@ -2159,42 +1007,51 @@ print_list(cfg_printer_t *pctx, cfg_obj_t *obj) { elt != NULL; elt = ISC_LIST_NEXT(elt, link)) { print_indent(pctx); - print_obj(pctx, elt->obj); - print(pctx, ";\n", 2); + cfg_print_obj(pctx, elt->obj); + cfg_print_chars(pctx, ";\n", 2); } } -static isc_result_t -parse_bracketed_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) +isc_result_t +cfg_parse_bracketed_list(cfg_parser_t *pctx, const cfg_type_t *type, + cfg_obj_t **ret) { isc_result_t result; - CHECK(parse_special(pctx, '{')); + CHECK(cfg_parse_special(pctx, '{')); CHECK(parse_list(pctx, type, ret)); - CHECK(parse_special(pctx, '}')); + CHECK(cfg_parse_special(pctx, '}')); cleanup: return (result); } -static void -print_bracketed_list(cfg_printer_t *pctx, cfg_obj_t *obj) { +void +cfg_print_bracketed_list(cfg_printer_t *pctx, cfg_obj_t *obj) { print_open(pctx); print_list(pctx, obj); print_close(pctx); } +void +cfg_doc_bracketed_list(cfg_printer_t *pctx, const cfg_type_t *type) { + cfg_print_chars(pctx, "{ ", 2); + cfg_doc_obj(pctx, type->of); + cfg_print_chars(pctx, "; ... }", 7); +} + /* * Parse a homogeneous list whose elements are of type 'elttype' * and where elements are separated by space. The list ends * before the first semicolon. */ -static isc_result_t -parse_spacelist(cfg_parser_t *pctx, const cfg_type_t *listtype, cfg_obj_t **ret) +isc_result_t +cfg_parse_spacelist(cfg_parser_t *pctx, const cfg_type_t *listtype, + cfg_obj_t **ret) { cfg_obj_t *listobj = NULL; const cfg_type_t *listof = listtype->of; isc_result_t result; - CHECK(create_list(pctx, listtype, &listobj)); + CHECK(cfg_create_list(pctx, listtype, &listobj)); for (;;) { cfg_listelt_t *elt = NULL; @@ -2203,7 +1060,7 @@ parse_spacelist(cfg_parser_t *pctx, const cfg_type_t *listtype, cfg_obj_t **ret) if (pctx->token.type == isc_tokentype_special && pctx->token.value.as_char == ';') break; - CHECK(parse_list_elt(pctx, listof, &elt)); + CHECK(cfg_parse_listelt(pctx, listof, &elt)); ISC_LIST_APPEND(listobj->value.list, elt, link); } *ret = listobj; @@ -2214,20 +1071,21 @@ parse_spacelist(cfg_parser_t *pctx, const cfg_type_t *listtype, cfg_obj_t **ret) return (result); } -static void -print_spacelist(cfg_printer_t *pctx, cfg_obj_t *obj) { +void +cfg_print_spacelist(cfg_printer_t *pctx, cfg_obj_t *obj) { cfg_list_t *list = &obj->value.list; cfg_listelt_t *elt; for (elt = ISC_LIST_HEAD(*list); elt != NULL; elt = ISC_LIST_NEXT(elt, link)) { - print_obj(pctx, elt->obj); + cfg_print_obj(pctx, elt->obj); if (ISC_LIST_NEXT(elt, link) != NULL) - print(pctx, " ", 1); + cfg_print_chars(pctx, " ", 1); } } + isc_boolean_t cfg_obj_islist(cfg_obj_t *obj) { REQUIRE(obj != NULL); @@ -2268,8 +1126,8 @@ cfg_listelt_value(cfg_listelt_t *elt) { * 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, const cfg_type_t *type, cfg_obj_t **ret) +isc_result_t +cfg_parse_mapbody(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { const cfg_clausedef_t * const *clausesets = type->of; isc_result_t result; @@ -2304,13 +1162,13 @@ parse_mapbody(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) * We accept "include" statements wherever a map body * clause can occur. */ - if (strcasecmp(pctx->token.value.as_pointer, "include") == 0) { + if (strcasecmp(TOKEN_STRING(pctx), "include") == 0) { /* * Turn the file name into a temporary configuration * object just so that it is not overwritten by the * semicolon token. */ - CHECK(parse(pctx, &cfg_type_qstring, &includename)); + CHECK(cfg_parse_obj(pctx, &cfg_type_qstring, &includename)); CHECK(parse_semicolon(pctx)); CHECK(parser_openfile(pctx, includename-> value.string.base)); @@ -2323,35 +1181,35 @@ parse_mapbody(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) for (clause = *clauseset; clause->name != NULL; clause++) { - if (strcasecmp(pctx->token.value.as_pointer, + if (strcasecmp(TOKEN_STRING(pctx), clause->name) == 0) goto done; } } done: if (clause == NULL || clause->name == NULL) { - parser_error(pctx, LOG_NOPREP, "unknown option"); + cfg_parser_error(pctx, CFG_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; + CHECK(cfg_parse_obj(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", + cfg_parser_warning(pctx, 0, "option '%s' is obsolete", clause->name); if ((clause->flags & CFG_CLAUSEFLAG_NOTIMP) != 0) - parser_warning(pctx, 0, "option '%s' is " + cfg_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 " + cfg_parser_warning(pctx, 0, "option '%s' is " "not implemented", clause->name); /* * Don't log options with CFG_CLAUSEFLAG_NEWDEFAULT @@ -2367,7 +1225,7 @@ parse_mapbody(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) /* Multivalued clause */ cfg_obj_t *listobj = NULL; if (result == ISC_R_NOTFOUND) { - CHECK(create_list(pctx, + CHECK(cfg_create_list(pctx, &cfg_type_implicitlist, &listobj)); symval.as_pointer = listobj; @@ -2377,7 +1235,7 @@ parse_mapbody(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) 1, symval, isc_symexists_reject); if (result != ISC_R_SUCCESS) { - parser_error(pctx, LOG_NEAR, + cfg_parser_error(pctx, CFG_LOG_NEAR, "isc_symtab_define(%s) " "failed", clause->name); isc_mem_put(pctx->mctx, list, @@ -2390,7 +1248,7 @@ parse_mapbody(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) } elt = NULL; - CHECK(parse_list_elt(pctx, clause->type, &elt)); + CHECK(cfg_parse_listelt(pctx, clause->type, &elt)); CHECK(parse_semicolon(pctx)); ISC_LIST_APPEND(listobj->value.list, elt, link); @@ -2406,12 +1264,12 @@ parse_mapbody(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) callback)); CHECK(parse_semicolon(pctx)); } else if (result == ISC_R_SUCCESS) { - parser_error(pctx, LOG_NEAR, "'%s' redefined", + cfg_parser_error(pctx, CFG_LOG_NEAR, "'%s' redefined", clause->name); result = ISC_R_EXISTS; goto cleanup; } else { - parser_error(pctx, LOG_NEAR, + cfg_parser_error(pctx, CFG_LOG_NEAR, "isc_symtab_define() failed"); goto cleanup; } @@ -2439,7 +1297,7 @@ parse_symtab_elt(cfg_parser_t *pctx, const char *name, cfg_obj_t *obj = NULL; isc_symvalue_t symval; - CHECK(parse(pctx, elttype, &obj)); + CHECK(cfg_parse_obj(pctx, elttype, &obj)); if (callback && pctx->callback != NULL) CHECK(pctx->callback(name, obj, pctx->callbackarg)); @@ -2458,19 +1316,18 @@ parse_symtab_elt(cfg_parser_t *pctx, const char *name, /* * Parse a map; e.g., "{ foo 1; bar { glub; }; zap true; zap false; }" */ -static isc_result_t -parse_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) -{ +isc_result_t +cfg_parse_map(cfg_parser_t *pctx, const 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, '}')); + CHECK(cfg_parse_special(pctx, '{')); + CHECK(cfg_parse_mapbody(pctx, type, ret)); + CHECK(cfg_parse_special(pctx, '}')); cleanup: return (result); } /* - * Subroutine for parse_named_map() and parse_addressed_map(). + * 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, @@ -2480,8 +1337,8 @@ parse_any_named_map(cfg_parser_t *pctx, cfg_type_t *nametype, const cfg_type_t * cfg_obj_t *idobj = NULL; cfg_obj_t *mapobj = NULL; - CHECK(parse(pctx, nametype, &idobj)); - CHECK(parse_map(pctx, type, &mapobj)); + CHECK(cfg_parse_obj(pctx, nametype, &idobj)); + CHECK(cfg_parse_map(pctx, type, &mapobj)); mapobj->value.map.id = idobj; idobj = NULL; *ret = mapobj; @@ -2494,8 +1351,8 @@ parse_any_named_map(cfg_parser_t *pctx, cfg_type_t *nametype, const cfg_type_t * * Parse a map identified by a string name. E.g., "name { foo 1; }". * Used for the "key" and "channel" statements. */ -static isc_result_t -parse_named_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { +isc_result_t +cfg_parse_named_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { return (parse_any_named_map(pctx, &cfg_type_astring, type, ret)); } @@ -2503,13 +1360,13 @@ parse_named_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { * Parse a map identified by a network address. * Used for the "server" statement. */ -static isc_result_t -parse_addressed_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { +isc_result_t +cfg_parse_addressed_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { return (parse_any_named_map(pctx, &cfg_type_netaddr, type, ret)); } -static void -print_mapbody(cfg_printer_t *pctx, cfg_obj_t *obj) { +void +cfg_print_mapbody(cfg_printer_t *pctx, cfg_obj_t *obj) { isc_result_t result = ISC_R_SUCCESS; const cfg_clausedef_t * const *clauseset; @@ -2536,18 +1393,18 @@ print_mapbody(cfg_printer_t *pctx, cfg_obj_t *obj) { elt != NULL; elt = ISC_LIST_NEXT(elt, link)) { print_indent(pctx); - print_cstr(pctx, clause->name); - print(pctx, " ", 1); - print_obj(pctx, elt->obj); - print(pctx, ";\n", 2); + cfg_print_cstr(pctx, clause->name); + cfg_print_chars(pctx, " ", 1); + cfg_print_obj(pctx, elt->obj); + cfg_print_chars(pctx, ";\n", 2); } } else { /* Single-valued. */ print_indent(pctx); - print_cstr(pctx, clause->name); - print(pctx, " ", 1); - print_obj(pctx, obj); - print(pctx, ";\n", 2); + cfg_print_cstr(pctx, clause->name); + cfg_print_chars(pctx, " ", 1); + cfg_print_obj(pctx, obj); + cfg_print_chars(pctx, ";\n", 2); } } else if (result == ISC_R_NOTFOUND) { ; /* do nothing */ @@ -2558,14 +1415,92 @@ print_mapbody(cfg_printer_t *pctx, cfg_obj_t *obj) { } } -static void -print_map(cfg_printer_t *pctx, cfg_obj_t *obj) { +void +cfg_doc_mapbody(cfg_printer_t *pctx, const cfg_type_t *type) { + const cfg_clausedef_t * const *clauseset; + const cfg_clausedef_t *clause; + + for (clauseset = type->of; *clauseset != NULL; clauseset++) { + for (clause = *clauseset; + clause->name != NULL; + clause++) { + 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); + } + } +} + +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, cfg_obj_t *obj) { if (obj->value.map.id != NULL) { - print_obj(pctx, obj->value.map.id); - print(pctx, " ", 1); + cfg_print_obj(pctx, obj->value.map.id); + cfg_print_chars(pctx, " ", 1); } print_open(pctx); - print_mapbody(pctx, obj); + cfg_print_mapbody(pctx, 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; + + if (type->parse == cfg_parse_named_map) { + cfg_doc_obj(pctx, &cfg_type_astring); + cfg_print_chars(pctx, " ", 1); + } else if (type->parse == cfg_parse_addressed_map) { + cfg_doc_obj(pctx, &cfg_type_netaddr); + cfg_print_chars(pctx, " ", 1); + } + + print_open(pctx); + + for (clauseset = type->of; *clauseset != NULL; clauseset++) { + for (clause = *clauseset; + clause->name != NULL; + clause++) { + print_indent(pctx); + cfg_print_cstr(pctx, clause->name); + if (clause->type->print != cfg_print_void) + cfg_print_chars(pctx, " ", 1); + cfg_doc_obj(pctx, clause->type); + cfg_print_chars(pctx, ";", 1); + print_clause_flags(pctx, clause->flags); + cfg_print_chars(pctx, "\n", 1); + } + } print_close(pctx); } @@ -2610,8 +1545,8 @@ parse_token(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { UNUSED(type); - CHECK(create_cfgobj(pctx, &cfg_type_token, &obj)); - CHECK(cfg_gettoken(pctx, QSTRING)); + CHECK(cfg_create_obj(pctx, &cfg_type_token, &obj)); + CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING)); if (pctx->token.type == isc_tokentype_eof) { cfg_ungettoken(pctx); result = ISC_R_EOF; @@ -2630,8 +1565,10 @@ parse_token(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { return (result); } -static cfg_type_t cfg_type_token = { - "token", parse_token, print_ustring, &cfg_rep_string, NULL }; +cfg_type_t cfg_type_token = { + "token", parse_token, cfg_print_ustring, cfg_doc_terminal, + &cfg_rep_string, NULL +}; /* * An unsupported option. This is just a list of tokens with balanced braces @@ -2644,7 +1581,7 @@ parse_unsupported(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { isc_result_t result; int braces = 0; - CHECK(create_list(pctx, type, &listobj)); + CHECK(cfg_create_list(pctx, type, &listobj)); for (;;) { cfg_listelt_t *elt = NULL; @@ -2660,12 +1597,12 @@ parse_unsupported(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { break; } if (pctx->token.type == isc_tokentype_eof || braces < 0) { - parser_error(pctx, LOG_NEAR, "unexpected token"); + cfg_parser_error(pctx, CFG_LOG_NEAR, "unexpected token"); result = ISC_R_UNEXPECTEDTOKEN; goto cleanup; } - CHECK(parse_list_elt(pctx, &cfg_type_token, &elt)); + CHECK(cfg_parse_listelt(pctx, &cfg_type_token, &elt)); ISC_LIST_APPEND(listobj->value.list, elt, link); } INSIST(braces == 0); @@ -2677,85 +1614,18 @@ parse_unsupported(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { return (result); } -static cfg_type_t cfg_type_unsupported = { - "unsupported", parse_unsupported, print_spacelist, +cfg_type_t cfg_type_unsupported = { + "unsupported", parse_unsupported, cfg_print_spacelist, cfg_doc_terminal, &cfg_rep_list, NULL }; /* - * A "controls" statement is represented as a map with the multivalued - * "inet" and "unix" clauses. Inet controls are tuples; unix controls - * are cfg_unsupported_t objects. - */ - -static keyword_type_t controls_allow_kw = { - "allow", &cfg_type_bracketed_aml }; -static cfg_type_t cfg_type_controls_allow = { - "controls_allow", parse_keyvalue, - print_keyvalue, &cfg_rep_list, &controls_allow_kw -}; - -static keyword_type_t controls_keys_kw = { - "keys", &cfg_type_keylist }; -static cfg_type_t cfg_type_controls_keys = { - "controls_keys", parse_optional_keyvalue, - print_keyvalue, &cfg_rep_list, &controls_keys_kw -}; - -static cfg_tuplefielddef_t inetcontrol_fields[] = { - { "address", &cfg_type_controls_sockaddr, 0 }, - { "allow", &cfg_type_controls_allow, 0 }, - { "keys", &cfg_type_controls_keys, 0 }, - { NULL, NULL, 0 } -}; -static cfg_type_t cfg_type_inetcontrol = { - "inetcontrol", parse_tuple, print_tuple, &cfg_rep_tuple, - inetcontrol_fields -}; - -static cfg_clausedef_t -controls_clauses[] = { - { "inet", &cfg_type_inetcontrol, CFG_CLAUSEFLAG_MULTI }, - { "unix", &cfg_type_unsupported, - CFG_CLAUSEFLAG_MULTI|CFG_CLAUSEFLAG_NOTIMP }, - { NULL, NULL, 0 } -}; -static cfg_clausedef_t * -controls_clausesets[] = { - controls_clauses, - NULL -}; -static cfg_type_t cfg_type_controls = { - "controls", parse_map, print_map, &cfg_rep_map, &controls_clausesets -}; - -/* - * An optional class, as used in view and zone statements. - */ -static isc_result_t -parse_optional_class(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - isc_result_t result; - UNUSED(type); - CHECK(cfg_peektoken(pctx, 0)); - if (pctx->token.type == isc_tokentype_string) - CHECK(parse(pctx, &cfg_type_ustring, ret)); - else - CHECK(parse(pctx, &cfg_type_void, ret)); - cleanup: - return (result); -} - -static cfg_type_t cfg_type_optional_class = { - "optional_class", parse_optional_class, NULL, NULL, NULL }; - - -/* * Try interpreting the current token as a network address. * - * If WILDOK is set in flags, "*" can be used as a wildcard - * and at least one of V4OK and V6OK must also be set. The - * "*" is interpreted as the IPv4 wildcard address if V4OK is - * set (including the case where V4OK and V6OK are both set), + * 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 + * set (including the case where CFG_ADDR_V4OK and CFG_ADDR_V6OK are both set), * and the IPv6 wildcard address otherwise. */ static isc_result_t @@ -2767,25 +1637,25 @@ token_addr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na) { if (pctx->token.type != isc_tokentype_string) return (ISC_R_UNEXPECTEDTOKEN); - s = pctx->token.value.as_pointer; - if ((flags & WILDOK) != 0 && strcmp(s, "*") == 0) { - if ((flags & V4OK) != 0) { + s = TOKEN_STRING(pctx); + if ((flags & CFG_ADDR_WILDOK) != 0 && strcmp(s, "*") == 0) { + if ((flags & CFG_ADDR_V4OK) != 0) { isc_netaddr_any(na); return (ISC_R_SUCCESS); - } else if ((flags & V6OK) != 0) { + } else if ((flags & CFG_ADDR_V6OK) != 0) { isc_netaddr_any6(na); return (ISC_R_SUCCESS); } else { INSIST(0); } } else { - if ((flags & (V4OK | V4PREFIXOK)) != 0) { + if ((flags & (CFG_ADDR_V4OK | CFG_ADDR_V4PREFIXOK)) != 0) { if (inet_pton(AF_INET, s, &in4a) == 1) { isc_netaddr_fromin(na, &in4a); return (ISC_R_SUCCESS); } } - if ((flags & V4PREFIXOK) != 0 && + if ((flags & CFG_ADDR_V4PREFIXOK) != 0 && strlen(s) <= 15U) { char buf[64]; int i; @@ -2799,9 +1669,35 @@ token_addr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na) { } } } - if (flags & V6OK) { - if (inet_pton(AF_INET6, s, &in6a) == 1) { + if ((flags & CFG_ADDR_V6OK) != 0 && + strlen(s) <= 127U) { + char buf[128]; /* see lib/bind9/getaddresses.c */ + char *d; /* zone delimiter */ + isc_uint32_t zone = 0; /* scope zone ID */ + + strlcpy(buf, s, sizeof(buf)); + d = strchr(buf, '%'); + if (d != NULL) + *d = '\0'; + + if (inet_pton(AF_INET6, buf, &in6a) == 1) { + if (d != NULL) { +#ifdef ISC_PLATFORM_HAVESCOPEID + isc_result_t result; + + result = isc_netscope_pton(AF_INET6, + d + 1, + &in6a, + &zone); + if (result != ISC_R_SUCCESS) + return (result); +#else + return (ISC_R_BADADDRESSFORM); +#endif + } + isc_netaddr_fromin6(na, &in6a); + isc_netaddr_setzone(na, zone); return (ISC_R_SUCCESS); } } @@ -2809,44 +1705,44 @@ token_addr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na) { return (ISC_R_UNEXPECTEDTOKEN); } -static isc_result_t -get_addr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na) { +isc_result_t +cfg_parse_rawaddr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na) { isc_result_t result; CHECK(cfg_gettoken(pctx, 0)); result = token_addr(pctx, flags, na); if (result == ISC_R_UNEXPECTEDTOKEN) - parser_error(pctx, LOG_NEAR, "expected IP address"); + cfg_parser_error(pctx, CFG_LOG_NEAR, "expected IP address"); cleanup: return (result); } -static isc_boolean_t -looking_at_netaddr(cfg_parser_t *pctx, unsigned int flags) { +isc_boolean_t +cfg_lookingat_netaddr(cfg_parser_t *pctx, unsigned int flags) { isc_result_t result; isc_netaddr_t na_dummy; result = token_addr(pctx, flags, &na_dummy); return (ISC_TF(result == ISC_R_SUCCESS)); } -static isc_result_t -get_port(cfg_parser_t *pctx, unsigned int flags, in_port_t *port) { +isc_result_t +cfg_parse_rawport(cfg_parser_t *pctx, unsigned int flags, in_port_t *port) { isc_result_t result; CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER)); - if ((flags & WILDOK) != 0 && + if ((flags & CFG_ADDR_WILDOK) != 0 && pctx->token.type == isc_tokentype_string && - strcmp(pctx->token.value.as_pointer, "*") == 0) { + strcmp(TOKEN_STRING(pctx), "*") == 0) { *port = 0; return (ISC_R_SUCCESS); } if (pctx->token.type != isc_tokentype_number) { - parser_error(pctx, LOG_NEAR, + cfg_parser_error(pctx, CFG_LOG_NEAR, "expected port number or '*'"); return (ISC_R_UNEXPECTEDTOKEN); } if (pctx->token.value.as_ulong >= 65536U) { - parser_error(pctx, LOG_NEAR, + cfg_parser_error(pctx, CFG_LOG_NEAR, "port number out of range"); return (ISC_R_UNEXPECTEDTOKEN); } @@ -2856,80 +1752,8 @@ get_port(cfg_parser_t *pctx, unsigned int flags, in_port_t *port) { return (result); } -static isc_result_t -parse_querysource(cfg_parser_t *pctx, int flags, cfg_obj_t **ret) { - isc_result_t result; - cfg_obj_t *obj = NULL; - isc_netaddr_t netaddr; - in_port_t port; - unsigned int have_address = 0; - unsigned int have_port = 0; - - if ((flags & V4OK) != 0) - isc_netaddr_any(&netaddr); - else if ((flags & V6OK) != 0) - isc_netaddr_any6(&netaddr); - else - INSIST(0); - - port = 0; - - CHECK(create_cfgobj(pctx, &cfg_type_querysource, &obj)); - for (;;) { - CHECK(cfg_peektoken(pctx, 0)); - if (pctx->token.type == isc_tokentype_string) { - if (strcasecmp(pctx->token.value.as_pointer, - "address") == 0) - { - /* read "address" */ - CHECK(cfg_gettoken(pctx, 0)); - CHECK(get_addr(pctx, flags|WILDOK, &netaddr)); - have_address++; - } else if (strcasecmp(pctx->token.value.as_pointer, - "port") == 0) - { - /* read "port" */ - CHECK(cfg_gettoken(pctx, 0)); - CHECK(get_port(pctx, WILDOK, &port)); - have_port++; - } else { - parser_error(pctx, LOG_NEAR, - "expected 'address' or 'port'"); - return (ISC_R_UNEXPECTEDTOKEN); - } - } else - break; - } - if (have_address > 1 || have_port > 1 || - have_address + have_port == 0) { - parser_error(pctx, 0, "expected one address and/or port"); - return (ISC_R_UNEXPECTEDTOKEN); - } - - isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, port); - *ret = obj; - return (ISC_R_SUCCESS); - - cleanup: - parser_error(pctx, LOG_NEAR, "invalid query source"); - CLEANUP_OBJ(obj); - return (result); -} - -static isc_result_t -parse_querysource4(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - UNUSED(type); - return (parse_querysource(pctx, V4OK, ret)); -} - -static isc_result_t -parse_querysource6(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - UNUSED(type); - return (parse_querysource(pctx, V6OK, ret)); -} - -static void -print_isc_netaddr(cfg_printer_t *pctx, isc_netaddr_t *na) { +void +cfg_print_rawaddr(cfg_printer_t *pctx, isc_netaddr_t *na) { isc_result_t result; char text[128]; isc_buffer_t buf; @@ -2937,26 +1761,9 @@ print_isc_netaddr(cfg_printer_t *pctx, isc_netaddr_t *na) { isc_buffer_init(&buf, text, sizeof(text)); result = isc_netaddr_totext(na, &buf); RUNTIME_CHECK(result == ISC_R_SUCCESS); - print(pctx, isc_buffer_base(&buf), isc_buffer_usedlength(&buf)); + cfg_print_chars(pctx, isc_buffer_base(&buf), isc_buffer_usedlength(&buf)); } -static void -print_querysource(cfg_printer_t *pctx, cfg_obj_t *obj) { - isc_netaddr_t na; - isc_netaddr_fromsockaddr(&na, &obj->value.sockaddr); - print(pctx, "address ", 8); - print_isc_netaddr(pctx, &na); - print(pctx, " port ", 6); - print_uint(pctx, isc_sockaddr_getport(&obj->value.sockaddr)); -} - -static cfg_type_t cfg_type_querysource4 = { - "querysource4", parse_querysource4, NULL, NULL, NULL }; -static cfg_type_t cfg_type_querysource6 = { - "querysource6", parse_querysource6, NULL, NULL, NULL }; -static cfg_type_t cfg_type_querysource = { - "querysource", NULL, print_querysource, &cfg_rep_sockaddr, NULL }; - /* netaddr */ static isc_result_t @@ -2965,8 +1772,8 @@ parse_netaddr(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { cfg_obj_t *obj = NULL; isc_netaddr_t netaddr; UNUSED(type); - CHECK(create_cfgobj(pctx, type, &obj)); - CHECK(get_addr(pctx, V4OK|V6OK, &netaddr)); + CHECK(cfg_create_obj(pctx, type, &obj)); + CHECK(cfg_parse_rawaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V6OK, &netaddr)); isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, 0); *ret = obj; return (ISC_R_SUCCESS); @@ -2975,20 +1782,25 @@ parse_netaddr(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { return (result); } -static cfg_type_t cfg_type_netaddr = { - "netaddr", parse_netaddr, print_sockaddr, &cfg_rep_sockaddr, NULL }; +cfg_type_t cfg_type_netaddr = { + "netaddr", parse_netaddr, cfg_print_sockaddr, cfg_doc_terminal, + &cfg_rep_sockaddr, NULL +}; /* netprefix */ -static isc_result_t -parse_netprefix(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { +isc_result_t +cfg_parse_netprefix(cfg_parser_t *pctx, const cfg_type_t *type, + cfg_obj_t **ret) +{ cfg_obj_t *obj = NULL; isc_result_t result; isc_netaddr_t netaddr; unsigned int addrlen, prefixlen; UNUSED(type); - CHECK(get_addr(pctx, V4OK|V4PREFIXOK|V6OK, &netaddr)); + CHECK(cfg_parse_rawaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V4PREFIXOK | + CFG_ADDR_V6OK, &netaddr)); switch (netaddr.family) { case AF_INET: addrlen = 32; @@ -3007,35 +1819,35 @@ parse_netprefix(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { CHECK(cfg_gettoken(pctx, 0)); /* read "/" */ CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER)); if (pctx->token.type != isc_tokentype_number) { - parser_error(pctx, LOG_NEAR, + cfg_parser_error(pctx, CFG_LOG_NEAR, "expected prefix length"); return (ISC_R_UNEXPECTEDTOKEN); } prefixlen = pctx->token.value.as_ulong; if (prefixlen > addrlen) { - parser_error(pctx, LOG_NOPREP, + cfg_parser_error(pctx, CFG_LOG_NOPREP, "invalid prefix length"); return (ISC_R_RANGE); } } else { prefixlen = addrlen; } - CHECK(create_cfgobj(pctx, &cfg_type_netprefix, &obj)); + CHECK(cfg_create_obj(pctx, &cfg_type_netprefix, &obj)); obj->value.netprefix.address = netaddr; obj->value.netprefix.prefixlen = prefixlen; *ret = obj; return (ISC_R_SUCCESS); cleanup: - parser_error(pctx, LOG_NEAR, "expected network prefix"); + cfg_parser_error(pctx, CFG_LOG_NEAR, "expected network prefix"); return (result); } static void print_netprefix(cfg_printer_t *pctx, cfg_obj_t *obj) { cfg_netprefix_t *p = &obj->value.netprefix; - print_isc_netaddr(pctx, &p->address); - print(pctx, "/", 1); - print_uint(pctx, p->prefixlen); + cfg_print_rawaddr(pctx, &p->address); + cfg_print_chars(pctx, "/", 1); + cfg_print_rawuint(pctx, p->prefixlen); } isc_boolean_t @@ -3052,79 +1864,9 @@ cfg_obj_asnetprefix(cfg_obj_t *obj, isc_netaddr_t *netaddr, *prefixlen = obj->value.netprefix.prefixlen; } -static cfg_type_t cfg_type_netprefix = { - "netprefix", parse_netprefix, print_netprefix, &cfg_rep_netprefix, NULL }; - -/* addrmatchelt */ - -static isc_result_t -parse_addrmatchelt(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - isc_result_t result; - UNUSED(type); - - CHECK(cfg_peektoken(pctx, QSTRING)); - - if (pctx->token.type == isc_tokentype_string || - pctx->token.type == isc_tokentype_qstring) { - if (pctx->token.type == isc_tokentype_string && - (strcasecmp(pctx->token.value.as_pointer, "key") == 0)) { - CHECK(parse(pctx, &cfg_type_keyref, ret)); - } else { - if (looking_at_netaddr(pctx, V4OK|V4PREFIXOK|V6OK)) { - CHECK(parse_netprefix(pctx, NULL, ret)); - } else { - CHECK(parse_astring(pctx, NULL, ret)); - } - } - } else if (pctx->token.type == isc_tokentype_special) { - if (pctx->token.value.as_char == '{') { - /* Nested match list. */ - CHECK(parse(pctx, &cfg_type_bracketed_aml, ret)); - } else if (pctx->token.value.as_char == '!') { - CHECK(cfg_gettoken(pctx, 0)); /* read "!" */ - CHECK(parse(pctx, &cfg_type_negated, ret)); - } else { - goto bad; - } - } else { - bad: - parser_error(pctx, LOG_NEAR, - "expected IP match list element"); - return (ISC_R_UNEXPECTEDTOKEN); - } - cleanup: - return (result); -} - -/* - * A negated address match list element (like "! 10.0.0.1"). - * Somewhat sneakily, the caller is expected to parse the - * "!", but not to print it. - */ - -static cfg_tuplefielddef_t negated_fields[] = { - { "value", &cfg_type_addrmatchelt, 0 }, - { NULL, NULL, 0 } -}; - -static void -print_negated(cfg_printer_t *pctx, cfg_obj_t *obj) { - print(pctx, "!", 1); - print_tuple(pctx, obj); -} - -static cfg_type_t cfg_type_negated = { - "negated", parse_tuple, print_negated, &cfg_rep_tuple, - &negated_fields -}; - -/* an address match list element */ - -static cfg_type_t cfg_type_addrmatchelt = { - "address_match_element", parse_addrmatchelt, NULL, NULL, NULL }; -static cfg_type_t cfg_type_bracketed_aml = { - "bracketed_aml", parse_bracketed_list, print_bracketed_list, - &cfg_rep_list, &cfg_type_addrmatchelt +cfg_type_t cfg_type_netprefix = { + "netprefix", cfg_parse_netprefix, print_netprefix, cfg_doc_terminal, + &cfg_rep_netprefix, NULL }; static isc_result_t @@ -3136,13 +1878,13 @@ parse_sockaddrsub(cfg_parser_t *pctx, const cfg_type_t *type, in_port_t port = 0; cfg_obj_t *obj = NULL; - CHECK(create_cfgobj(pctx, type, &obj)); - CHECK(get_addr(pctx, flags, &netaddr)); + 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(pctx->token.value.as_pointer, "port") == 0) { + strcasecmp(TOKEN_STRING(pctx), "port") == 0) { CHECK(cfg_gettoken(pctx, 0)); /* read "port" */ - CHECK(get_port(pctx, flags, &port)); + CHECK(cfg_parse_rawport(pctx, flags, &port)); } isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, port); *ret = obj; @@ -3153,25 +1895,62 @@ parse_sockaddrsub(cfg_parser_t *pctx, const cfg_type_t *type, return (result); } -static isc_result_t -parse_sockaddr(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { +static unsigned int sockaddr_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK; +cfg_type_t cfg_type_sockaddr = { + "sockaddr", cfg_parse_sockaddr, cfg_print_sockaddr, cfg_doc_sockaddr, + &cfg_rep_sockaddr, &sockaddr_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; - return (parse_sockaddrsub(pctx, &cfg_type_sockaddr4wild, *flagp, ret)); + return (parse_sockaddrsub(pctx, &cfg_type_sockaddr, *flagp, ret)); } -static void -print_sockaddr(cfg_printer_t *pctx, cfg_obj_t *obj) { +void +cfg_print_sockaddr(cfg_printer_t *pctx, cfg_obj_t *obj) { isc_netaddr_t netaddr; in_port_t port; char buf[ISC_NETADDR_FORMATSIZE]; isc_netaddr_fromsockaddr(&netaddr, &obj->value.sockaddr); isc_netaddr_format(&netaddr, buf, sizeof(buf)); - print_cstr(pctx, buf); + cfg_print_cstr(pctx, buf); port = isc_sockaddr_getport(&obj->value.sockaddr); if (port != 0) { - print(pctx, " port ", 6); - print_uint(pctx, port); + cfg_print_chars(pctx, " port ", 6); + cfg_print_rawuint(pctx, port); + } +} + +void +cfg_doc_sockaddr(cfg_printer_t *pctx, const cfg_type_t *type) { + const unsigned int *flagp = type->of; + int n = 0; + cfg_print_chars(pctx, "( ", 2); + if (*flagp & CFG_ADDR_V4OK) { + if (n != 0) + cfg_print_chars(pctx, " | ", 3); + cfg_print_cstr(pctx, "<ipv4_address>"); + n++; + } + if (*flagp & CFG_ADDR_V6OK) { + if (n != 0) + cfg_print_chars(pctx, " | ", 3); + cfg_print_cstr(pctx, "<ipv6_address>"); + n++; + } + if (*flagp & CFG_ADDR_WILDOK) { + if (n != 0) + cfg_print_chars(pctx, " | ", 3); + cfg_print_chars(pctx, "*", 1); + n++; + } + cfg_print_chars(pctx, " ) ", 3); + if (*flagp & CFG_ADDR_WILDOK) { + cfg_print_cstr(pctx, "[ port ( <integer> | * ) ]"); + } else { + cfg_print_cstr(pctx, "[ port <integer> ]"); } } @@ -3187,344 +1966,7 @@ cfg_obj_assockaddr(cfg_obj_t *obj) { return (&obj->value.sockaddr); } -/* An IPv4/IPv6 address with optional port, "*" accepted as wildcard. */ -static unsigned int sockaddr4wild_flags = WILDOK|V4OK; -static cfg_type_t cfg_type_sockaddr4wild = { - "sockaddr4wild", parse_sockaddr, print_sockaddr, - &cfg_rep_sockaddr, &sockaddr4wild_flags -}; - -static unsigned int sockaddr6wild_flags = WILDOK|V6OK; -static cfg_type_t cfg_type_sockaddr6wild = { - "v6addrportwild", parse_sockaddr, print_sockaddr, - &cfg_rep_sockaddr, &sockaddr6wild_flags -}; - -static unsigned int sockaddr_flags = V4OK|V6OK; -static cfg_type_t cfg_type_sockaddr = { - "sockaddr", parse_sockaddr, print_sockaddr, - &cfg_rep_sockaddr, &sockaddr_flags -}; - -/* - * The socket address syntax in the "controls" statement is silly. - * It allows both socket address families, but also allows "*", - * whis is gratuitously interpreted as the IPv4 wildcard address. - */ -static unsigned int controls_sockaddr_flags = V4OK|V6OK|WILDOK; -static cfg_type_t cfg_type_controls_sockaddr = { - "controls_sockaddr", parse_sockaddr, print_sockaddr, - &cfg_rep_sockaddr, &controls_sockaddr_flags }; - - -/* - * Handle the special kludge syntax of the "keys" clause in the "server" - * statement, which takes a single key with our without braces and semicolon. - */ -static isc_result_t -parse_server_key_kludge(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) -{ - isc_result_t result; - isc_boolean_t braces = ISC_FALSE; - UNUSED(type); - - /* Allow opening brace. */ - CHECK(cfg_peektoken(pctx, 0)); - if (pctx->token.type == isc_tokentype_special && - pctx->token.value.as_char == '{') { - result = cfg_gettoken(pctx, 0); - braces = ISC_TRUE; - } - - CHECK(parse(pctx, &cfg_type_astring, ret)); - - if (braces) { - /* Skip semicolon if present. */ - CHECK(cfg_peektoken(pctx, 0)); - if (pctx->token.type == isc_tokentype_special && - pctx->token.value.as_char == ';') - CHECK(cfg_gettoken(pctx, 0)); - - CHECK(parse_special(pctx, '}')); - } - cleanup: - return (result); -} -static cfg_type_t cfg_type_server_key_kludge = { - "server_key", parse_server_key_kludge, NULL, NULL, NULL }; - - -/* - * An optional logging facility. - */ - -static isc_result_t -parse_optional_facility(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) -{ - isc_result_t result; - UNUSED(type); - - CHECK(cfg_peektoken(pctx, QSTRING)); - if (pctx->token.type == isc_tokentype_string || - pctx->token.type == isc_tokentype_qstring) { - CHECK(parse(pctx, &cfg_type_astring, ret)); - } else { - CHECK(parse(pctx, &cfg_type_void, ret)); - } - cleanup: - return (result); -} - -static cfg_type_t cfg_type_optional_facility = { - "optional_facility", parse_optional_facility, NULL, NULL, NULL }; - - -/* - * A log severity. Return as a string, except "debug N", - * which is returned as a keyword object. - */ - -static keyword_type_t debug_kw = { "debug", &cfg_type_uint32 }; -static cfg_type_t cfg_type_debuglevel = { - "debuglevel", parse_keyvalue, - print_keyvalue, &cfg_rep_uint32, &debug_kw -}; - -static isc_result_t -parse_logseverity(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - isc_result_t result; - UNUSED(type); - - CHECK(cfg_peektoken(pctx, 0)); - if (pctx->token.type == isc_tokentype_string && - strcasecmp(pctx->token.value.as_pointer, "debug") == 0) { - CHECK(cfg_gettoken(pctx, 0)); /* read "debug" */ - CHECK(cfg_peektoken(pctx, ISC_LEXOPT_NUMBER)); - if (pctx->token.type == isc_tokentype_number) { - CHECK(parse_uint32(pctx, NULL, ret)); - } else { - /* - * The debug level is optional and defaults to 1. - * This makes little sense, but we support it for - * compatibility with BIND 8. - */ - CHECK(create_cfgobj(pctx, &cfg_type_uint32, ret)); - (*ret)->value.uint32 = 1; - } - (*ret)->type = &cfg_type_debuglevel; /* XXX kludge */ - } else { - CHECK(parse(pctx, &cfg_type_loglevel, ret)); - } - cleanup: - return (result); -} - -static cfg_type_t cfg_type_logseverity = { - "logseverity", parse_logseverity, NULL, NULL, NULL }; - -/* - * The "file" clause of the "channel" statement. - * This is yet another special case. - */ - -static const char *logversions_enums[] = { "unlimited", NULL }; -static isc_result_t -parse_logversions(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - return (parse_enum_or_other(pctx, type, &cfg_type_uint32, ret)); -} -static cfg_type_t cfg_type_logversions = { - "logversions", parse_logversions, print_ustring, - &cfg_rep_string, logversions_enums -}; - -static cfg_tuplefielddef_t logfile_fields[] = { - { "file", &cfg_type_qstring, 0 }, - { "versions", &cfg_type_logversions, 0 }, - { "size", &cfg_type_size, 0 }, - { NULL, NULL, 0 } -}; - -static isc_result_t -parse_logfile(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - isc_result_t result; - cfg_obj_t *obj = NULL; - const cfg_tuplefielddef_t *fields = type->of; - - CHECK(create_tuple(pctx, type, &obj)); - - /* Parse the mandatory "file" field */ - CHECK(parse(pctx, fields[0].type, &obj->value.tuple[0])); - - /* Parse "versions" and "size" fields in any order. */ - for (;;) { - CHECK(cfg_peektoken(pctx, 0)); - if (pctx->token.type == isc_tokentype_string) { - CHECK(cfg_gettoken(pctx, 0)); - if (strcasecmp(pctx->token.value.as_pointer, - "versions") == 0 && - obj->value.tuple[1] == NULL) { - CHECK(parse(pctx, fields[1].type, - &obj->value.tuple[1])); - } else if (strcasecmp(pctx->token.value.as_pointer, - "size") == 0 && - obj->value.tuple[2] == NULL) { - CHECK(parse(pctx, fields[2].type, - &obj->value.tuple[2])); - } else { - break; - } - } else { - break; - } - } - - /* Create void objects for missing optional values. */ - if (obj->value.tuple[1] == NULL) - CHECK(parse_void(pctx, NULL, &obj->value.tuple[1])); - if (obj->value.tuple[2] == NULL) - CHECK(parse_void(pctx, NULL, &obj->value.tuple[2])); - - *ret = obj; - return (ISC_R_SUCCESS); - - cleanup: - CLEANUP_OBJ(obj); - return (result); -} - -static void -print_logfile(cfg_printer_t *pctx, cfg_obj_t *obj) { - print_obj(pctx, obj->value.tuple[0]); /* file */ - if (obj->value.tuple[1]->type->print != print_void) { - print(pctx, " versions ", 10); - print_obj(pctx, obj->value.tuple[1]); - } - if (obj->value.tuple[2]->type->print != print_void) { - print(pctx, " size ", 6); - print_obj(pctx, obj->value.tuple[2]); - } -} - -static cfg_type_t cfg_type_logfile = { - "logfile", parse_logfile, print_logfile, &cfg_rep_tuple, - logfile_fields -}; - - -/* - * lwres - */ - -static cfg_tuplefielddef_t lwres_view_fields[] = { - { "name", &cfg_type_astring, 0 }, - { "class", &cfg_type_optional_class, 0 }, - { NULL, NULL, 0 } -}; -static cfg_type_t cfg_type_lwres_view = { - "lwres_view", parse_tuple, print_tuple, &cfg_rep_tuple, - lwres_view_fields -}; - -static cfg_type_t cfg_type_lwres_searchlist = { - "lwres_searchlist", parse_bracketed_list, print_bracketed_list, - &cfg_rep_list, &cfg_type_astring }; - -static cfg_clausedef_t -lwres_clauses[] = { - { "listen-on", &cfg_type_portiplist, 0 }, - { "view", &cfg_type_lwres_view, 0 }, - { "search", &cfg_type_lwres_searchlist, 0 }, - { "ndots", &cfg_type_uint32, 0 }, - { NULL, NULL, 0 } -}; - -static cfg_clausedef_t * -lwres_clausesets[] = { - lwres_clauses, - NULL -}; -static cfg_type_t cfg_type_lwres = { - "lwres", parse_map, print_map, &cfg_rep_map, lwres_clausesets }; - -/* - * rndc - */ - -static cfg_clausedef_t -rndcconf_options_clauses[] = { - { "default-server", &cfg_type_astring, 0 }, - { "default-key", &cfg_type_astring, 0 }, - { "default-port", &cfg_type_uint32, 0 }, - { NULL, NULL, 0 } -}; - -static cfg_clausedef_t * -rndcconf_options_clausesets[] = { - rndcconf_options_clauses, - NULL -}; - -static cfg_type_t cfg_type_rndcconf_options = { - "rndcconf_options", parse_map, print_map, &cfg_rep_map, - rndcconf_options_clausesets -}; - -static cfg_clausedef_t -rndcconf_server_clauses[] = { - { "key", &cfg_type_astring, 0 }, - { "port", &cfg_type_uint32, 0 }, - { NULL, NULL, 0 } -}; - -static cfg_clausedef_t * -rndcconf_server_clausesets[] = { - rndcconf_server_clauses, - NULL -}; - -static cfg_type_t cfg_type_rndcconf_server = { - "rndcconf_server", parse_named_map, print_map, &cfg_rep_map, - rndcconf_server_clausesets -}; - -static cfg_clausedef_t -rndcconf_clauses[] = { - { "key", &cfg_type_key, CFG_CLAUSEFLAG_MULTI }, - { "server", &cfg_type_rndcconf_server, CFG_CLAUSEFLAG_MULTI }, - { "options", &cfg_type_rndcconf_options, 0 }, - { NULL, NULL, 0 } -}; - -static cfg_clausedef_t * -rndcconf_clausesets[] = { - rndcconf_clauses, - NULL -}; - -LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_rndcconf = { - "rndcconf", parse_mapbody, print_mapbody, &cfg_rep_map, - rndcconf_clausesets -}; - -static cfg_clausedef_t -rndckey_clauses[] = { - { "key", &cfg_type_key, 0 }, - { NULL, NULL, 0 } -}; - -static cfg_clausedef_t * -rndckey_clausesets[] = { - rndckey_clauses, - NULL -}; - -LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_rndckey = { - "rndckey", parse_mapbody, print_mapbody, &cfg_rep_map, - rndckey_clausesets -}; - - -static isc_result_t +isc_result_t cfg_gettoken(cfg_parser_t *pctx, int options) { isc_result_t result; @@ -3566,23 +2008,23 @@ cfg_gettoken(cfg_parser_t *pctx, int options) { case ISC_R_NOSPACE: /* More understandable than "ran out of space". */ - parser_error(pctx, LOG_NEAR, "token too big"); + cfg_parser_error(pctx, CFG_LOG_NEAR, "token too big"); break; case ISC_R_IOERROR: - parser_error(pctx, 0, "%s", + cfg_parser_error(pctx, 0, "%s", isc_result_totext(result)); break; default: - parser_error(pctx, LOG_NEAR, "%s", - isc_result_totext(result)); + cfg_parser_error(pctx, CFG_LOG_NEAR, "%s", + isc_result_totext(result)); break; } return (result); } -static void +void cfg_ungettoken(cfg_parser_t *pctx) { if (pctx->seen_eof) return; @@ -3590,7 +2032,7 @@ cfg_ungettoken(cfg_parser_t *pctx) { pctx->ungotten = ISC_TRUE; } -static isc_result_t +isc_result_t cfg_peektoken(cfg_parser_t *pctx, int options) { isc_result_t result; CHECK(cfg_gettoken(pctx, options)); @@ -3607,20 +2049,20 @@ static isc_result_t cfg_getstringtoken(cfg_parser_t *pctx) { isc_result_t result; - result = cfg_gettoken(pctx, QSTRING); + result = cfg_gettoken(pctx, CFG_LEXOPT_QSTRING); if (result != ISC_R_SUCCESS) return (result); if (pctx->token.type != isc_tokentype_string && pctx->token.type != isc_tokentype_qstring) { - parser_error(pctx, LOG_NEAR, "expected string"); + cfg_parser_error(pctx, CFG_LOG_NEAR, "expected string"); return (ISC_R_UNEXPECTEDTOKEN); } return (ISC_R_SUCCESS); } -static void -parser_error(cfg_parser_t *pctx, unsigned int flags, const char *fmt, ...) { +void +cfg_parser_error(cfg_parser_t *pctx, unsigned int flags, const char *fmt, ...) { va_list args; va_start(args, fmt); parser_complain(pctx, ISC_FALSE, flags, fmt, args); @@ -3628,8 +2070,8 @@ parser_error(cfg_parser_t *pctx, unsigned int flags, const char *fmt, ...) { pctx->errors++; } -static void -parser_warning(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; va_start(args, fmt); parser_complain(pctx, ISC_TRUE, flags, fmt, args); @@ -3679,7 +2121,7 @@ parser_complain(cfg_parser_t *pctx, isc_boolean_t is_warning, FATAL_ERROR(__FILE__, __LINE__, "error message would overflow"); - if ((flags & (LOG_NEAR|LOG_BEFORE|LOG_NOPREP)) != 0) { + if ((flags & (CFG_LOG_NEAR|CFG_LOG_BEFORE|CFG_LOG_NOPREP)) != 0) { isc_region_t r; if (pctx->ungotten) @@ -3702,9 +2144,9 @@ parser_complain(cfg_parser_t *pctx, isc_boolean_t is_warning, } /* Choose a preposition. */ - if (flags & LOG_NEAR) + if (flags & CFG_LOG_NEAR) prep = " near "; - else if (flags & LOG_BEFORE) + else if (flags & CFG_LOG_BEFORE) prep = " before "; else prep = " "; @@ -3733,8 +2175,18 @@ cfg_obj_log(cfg_obj_t *obj, isc_log_t *lctx, int level, const char *fmt, ...) { va_end(ap); } -static isc_result_t -create_cfgobj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { +const char * +cfg_obj_file(cfg_obj_t *obj) { + return (obj->file); +} + +unsigned int +cfg_obj_line(cfg_obj_t *obj) { + return (obj->line); +} + +isc_result_t +cfg_create_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { cfg_obj_t *obj; obj = isc_mem_get(pctx->mctx, sizeof(cfg_obj_t)); @@ -3767,7 +2219,7 @@ create_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { isc_symtab_t *symtab = NULL; cfg_obj_t *obj = NULL; - CHECK(create_cfgobj(pctx, type, &obj)); + CHECK(cfg_create_obj(pctx, type, &obj)); CHECK(isc_symtab_create(pctx->mctx, 5, /* XXX */ map_symtabitem_destroy, pctx, ISC_FALSE, &symtab)); @@ -3812,151 +2264,16 @@ free_noop(cfg_parser_t *pctx, cfg_obj_t *obj) { UNUSED(obj); } -/* - * Data and functions for printing grammar summaries. - */ -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 } -}; - -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) - print(pctx, " // ", 4); - else - print(pctx, ", ", 2); - print_cstr(pctx, p->text); - first = ISC_FALSE; - } - } +void +cfg_doc_obj(cfg_printer_t *pctx, const cfg_type_t *type) { + type->doc(pctx, type); } -static void -print_grammar(cfg_printer_t *pctx, const cfg_type_t *type) { - if (type->print == print_mapbody) { - const cfg_clausedef_t * const *clauseset; - const cfg_clausedef_t *clause; - - for (clauseset = type->of; *clauseset != NULL; clauseset++) { - for (clause = *clauseset; - clause->name != NULL; - clause++) { - print_cstr(pctx, clause->name); - print(pctx, " ", 1); - print_grammar(pctx, clause->type); - print(pctx, ";", 1); - /* XXX print flags here? */ - print(pctx, "\n\n", 2); - } - } - } else if (type->print == print_map) { - const cfg_clausedef_t * const *clauseset; - const cfg_clausedef_t *clause; - - if (type->parse == parse_named_map) { - print_grammar(pctx, &cfg_type_astring); - print(pctx, " ", 1); - } - - print_open(pctx); - - for (clauseset = type->of; *clauseset != NULL; clauseset++) { - for (clause = *clauseset; - clause->name != NULL; - clause++) { - print_indent(pctx); - print_cstr(pctx, clause->name); - if (clause->type->print != print_void) - print(pctx, " ", 1); - print_grammar(pctx, clause->type); - print(pctx, ";", 1); - print_clause_flags(pctx, clause->flags); - print(pctx, "\n", 1); - } - } - print_close(pctx); - } else if (type->print == print_tuple) { - const cfg_tuplefielddef_t *fields = type->of; - const cfg_tuplefielddef_t *f; - isc_boolean_t need_space = ISC_FALSE; - - for (f = fields; f->name != NULL; f++) { - if (need_space) - print(pctx, " ", 1); - print_grammar(pctx, f->type); - need_space = ISC_TF(f->type->print != print_void); - } - } else if (type->parse == parse_enum) { - const char * const *p; - print(pctx, "( ", 2); - for (p = type->of; *p != NULL; p++) { - print_cstr(pctx, *p); - if (p[1] != NULL) - print(pctx, " | ", 3); - } - print(pctx, " )", 2); - } else if (type->print == print_bracketed_list) { - print(pctx, "{ ", 2); - print_grammar(pctx, type->of); - print(pctx, "; ... }", 7); - } else if (type->parse == parse_keyvalue) { - const keyword_type_t *kw = type->of; - print_cstr(pctx, kw->name); - print(pctx, " ", 1); - print_grammar(pctx, kw->type); - } else if (type->parse == parse_optional_keyvalue) { - const keyword_type_t *kw = type->of; - print(pctx, "[ ", 2); - print_cstr(pctx, kw->name); - print(pctx, " ", 1); - print_grammar(pctx, kw->type); - print(pctx, " ]", 2); - } else if (type->parse == parse_sockaddr) { - const unsigned int *flagp = type->of; - int n = 0; - print(pctx, "( ", 2); - if (*flagp & V4OK) { - if (n != 0) - print(pctx, " | ", 3); - print_cstr(pctx, "<ipv4_address>"); - n++; - } - if (*flagp & V6OK) { - if (n != 0) - print(pctx, " | ", 3); - print_cstr(pctx, "<ipv6_address>"); - n++; - } - if (*flagp & WILDOK) { - if (n != 0) - print(pctx, " | ", 3); - print(pctx, "*", 1); - n++; - } - print(pctx, " ) ", 3); - if (*flagp & WILDOK) { - print_cstr(pctx, "[ port ( <integer> | * ) ]"); - } else { - print_cstr(pctx, "[ port <integer> ]"); - } - } else if (type->print == print_void) { - /* Print nothing. */ - } else { - print(pctx, "<", 1); - print_cstr(pctx, type->name); - print(pctx, ">", 1); - } +void +cfg_doc_terminal(cfg_printer_t *pctx, const cfg_type_t *type) { + cfg_print_chars(pctx, "<", 1); + cfg_print_cstr(pctx, type->name); + cfg_print_chars(pctx, ">", 1); } void @@ -3968,5 +2285,5 @@ cfg_print_grammar(const cfg_type_t *type, pctx.f = f; pctx.closure = closure; pctx.indent = 0; - print_grammar(&pctx, type); + cfg_doc_obj(&pctx, type); } |
