1 /* $NetBSD: parser.c,v 1.9 2015/07/08 17:29:00 christos Exp $ */
4 * Copyright (C) 2004-2015 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 2000-2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
26 #include <isc/buffer.h>
28 #include <isc/formatcheck.h>
33 #include <isc/netaddr.h>
34 #include <isc/netscope.h>
35 #include <isc/print.h>
36 #include <isc/string.h>
37 #include <isc/sockaddr.h>
38 #include <isc/symtab.h>
41 #include <isccfg/cfg.h>
42 #include <isccfg/grammar.h>
43 #include <isccfg/log.h>
46 #define CAT CFG_LOGCATEGORY_CONFIG
47 #define MOD CFG_LOGMODULE_PARSER
49 #define MAP_SYM 1 /* Unique type for isc_symtab */
51 #define TOKEN_STRING(pctx) (pctx->token.value.as_textregion.base)
53 /* Check a return value. */
56 if (result != ISC_R_SUCCESS) goto cleanup; \
57 } while (/*CONSTCOND*/0)
59 /* Clean up a configuration object if non-NULL. */
60 #define CLEANUP_OBJ(obj) \
61 do { if ((obj) != NULL) cfg_obj_destroy(pctx, &(obj)); } while (/*CONSTCOND*/0)
65 * Forward declarations of static functions.
69 free_tuple(cfg_parser_t
*pctx
, cfg_obj_t
*obj
);
72 parse_list(cfg_parser_t
*pctx
, const cfg_type_t
*type
, cfg_obj_t
**ret
);
75 print_list(cfg_printer_t
*pctx
, const cfg_obj_t
*obj
);
78 free_list(cfg_parser_t
*pctx
, cfg_obj_t
*obj
);
81 create_listelt(cfg_parser_t
*pctx
, cfg_listelt_t
**eltp
);
84 create_string(cfg_parser_t
*pctx
, const char *contents
, const cfg_type_t
*type
,
88 free_string(cfg_parser_t
*pctx
, cfg_obj_t
*obj
);
91 create_map(cfg_parser_t
*pctx
, const cfg_type_t
*type
, cfg_obj_t
**objp
);
94 free_map(cfg_parser_t
*pctx
, cfg_obj_t
*obj
);
97 parse_symtab_elt(cfg_parser_t
*pctx
, const char *name
,
98 cfg_type_t
*elttype
, isc_symtab_t
*symtab
,
99 isc_boolean_t callback
);
102 free_noop(cfg_parser_t
*pctx
, cfg_obj_t
*obj
);
105 cfg_getstringtoken(cfg_parser_t
*pctx
);
108 parser_complain(cfg_parser_t
*pctx
, isc_boolean_t is_warning
,
109 unsigned int flags
, const char *format
, va_list args
);
112 * Data representations. These correspond to members of the
113 * "value" union in struct cfg_obj (except "void", which does
114 * not need a union member).
117 cfg_rep_t cfg_rep_uint32
= { "uint32", free_noop
};
118 cfg_rep_t cfg_rep_uint64
= { "uint64", free_noop
};
119 cfg_rep_t cfg_rep_string
= { "string", free_string
};
120 cfg_rep_t cfg_rep_boolean
= { "boolean", free_noop
};
121 cfg_rep_t cfg_rep_map
= { "map", free_map
};
122 cfg_rep_t cfg_rep_list
= { "list", free_list
};
123 cfg_rep_t cfg_rep_tuple
= { "tuple", free_tuple
};
124 cfg_rep_t cfg_rep_sockaddr
= { "sockaddr", free_noop
};
125 cfg_rep_t cfg_rep_netprefix
= { "netprefix", free_noop
};
126 cfg_rep_t cfg_rep_void
= { "void", free_noop
};
129 * Configuration type definitions.
133 * An implicit list. These are formed by clauses that occur multiple times.
135 static cfg_type_t cfg_type_implicitlist
= {
136 "implicitlist", NULL
, print_list
, NULL
, &cfg_rep_list
, NULL
};
141 cfg_print_obj(cfg_printer_t
*pctx
, const cfg_obj_t
*obj
) {
142 obj
->type
->print(pctx
, obj
);
146 cfg_print_chars(cfg_printer_t
*pctx
, const char *text
, int len
) {
147 pctx
->f(pctx
->closure
, text
, len
);
151 print_open(cfg_printer_t
*pctx
) {
152 cfg_print_chars(pctx
, "{\n", 2);
157 print_indent(cfg_printer_t
*pctx
) {
158 int indent
= pctx
->indent
;
160 cfg_print_chars(pctx
, "\t", 1);
166 print_close(cfg_printer_t
*pctx
) {
169 cfg_print_chars(pctx
, "}", 1);
173 cfg_parse_obj(cfg_parser_t
*pctx
, const cfg_type_t
*type
, cfg_obj_t
**ret
) {
175 INSIST(ret
!= NULL
&& *ret
== NULL
);
176 result
= type
->parse(pctx
, type
, ret
);
177 if (result
!= ISC_R_SUCCESS
)
179 INSIST(*ret
!= NULL
);
180 return (ISC_R_SUCCESS
);
184 cfg_print(const cfg_obj_t
*obj
,
185 void (*f
)(void *closure
, const char *text
, int textlen
),
188 cfg_printx(obj
, 0, f
, closure
);
192 cfg_printx(const cfg_obj_t
*obj
, unsigned int flags
,
193 void (*f
)(void *closure
, const char *text
, int textlen
),
198 pctx
.closure
= closure
;
201 obj
->type
->print(&pctx
, obj
);
207 cfg_create_tuple(cfg_parser_t
*pctx
, const cfg_type_t
*type
, cfg_obj_t
**ret
) {
209 const cfg_tuplefielddef_t
*fields
= type
->of
;
210 const cfg_tuplefielddef_t
*f
;
211 cfg_obj_t
*obj
= NULL
;
212 unsigned int nfields
= 0;
215 for (f
= fields
; f
->name
!= NULL
; f
++)
218 CHECK(cfg_create_obj(pctx
, type
, &obj
));
219 obj
->value
.tuple
= isc_mem_get(pctx
->mctx
,
220 nfields
* sizeof(cfg_obj_t
*));
221 if (obj
->value
.tuple
== NULL
) {
222 result
= ISC_R_NOMEMORY
;
225 for (f
= fields
, i
= 0; f
->name
!= NULL
; f
++, i
++)
226 obj
->value
.tuple
[i
] = NULL
;
228 return (ISC_R_SUCCESS
);
232 isc_mem_put(pctx
->mctx
, obj
, sizeof(*obj
));
237 cfg_parse_tuple(cfg_parser_t
*pctx
, const cfg_type_t
*type
, cfg_obj_t
**ret
)
240 const cfg_tuplefielddef_t
*fields
= type
->of
;
241 const cfg_tuplefielddef_t
*f
;
242 cfg_obj_t
*obj
= NULL
;
245 CHECK(cfg_create_tuple(pctx
, type
, &obj
));
246 for (f
= fields
, i
= 0; f
->name
!= NULL
; f
++, i
++)
247 CHECK(cfg_parse_obj(pctx
, f
->type
, &obj
->value
.tuple
[i
]));
250 return (ISC_R_SUCCESS
);
258 cfg_print_tuple(cfg_printer_t
*pctx
, const cfg_obj_t
*obj
) {
260 const cfg_tuplefielddef_t
*fields
= obj
->type
->of
;
261 const cfg_tuplefielddef_t
*f
;
262 isc_boolean_t need_space
= ISC_FALSE
;
264 for (f
= fields
, i
= 0; f
->name
!= NULL
; f
++, i
++) {
265 const cfg_obj_t
*fieldobj
= obj
->value
.tuple
[i
];
267 cfg_print_chars(pctx
, " ", 1);
268 cfg_print_obj(pctx
, fieldobj
);
269 need_space
= ISC_TF(fieldobj
->type
->print
!= cfg_print_void
);
274 cfg_doc_tuple(cfg_printer_t
*pctx
, const cfg_type_t
*type
) {
275 const cfg_tuplefielddef_t
*fields
= type
->of
;
276 const cfg_tuplefielddef_t
*f
;
277 isc_boolean_t need_space
= ISC_FALSE
;
279 for (f
= fields
; f
->name
!= NULL
; f
++) {
281 cfg_print_chars(pctx
, " ", 1);
282 cfg_doc_obj(pctx
, f
->type
);
283 need_space
= ISC_TF(f
->type
->print
!= cfg_print_void
);
288 free_tuple(cfg_parser_t
*pctx
, cfg_obj_t
*obj
) {
290 const cfg_tuplefielddef_t
*fields
= obj
->type
->of
;
291 const cfg_tuplefielddef_t
*f
;
292 unsigned int nfields
= 0;
294 if (obj
->value
.tuple
== NULL
)
297 for (f
= fields
, i
= 0; f
->name
!= NULL
; f
++, i
++) {
298 CLEANUP_OBJ(obj
->value
.tuple
[i
]);
301 isc_mem_put(pctx
->mctx
, obj
->value
.tuple
,
302 nfields
* sizeof(cfg_obj_t
*));
306 cfg_obj_istuple(const cfg_obj_t
*obj
) {
307 REQUIRE(obj
!= NULL
);
308 return (ISC_TF(obj
->type
->rep
== &cfg_rep_tuple
));
312 cfg_tuple_get(const cfg_obj_t
*tupleobj
, const char* name
) {
314 const cfg_tuplefielddef_t
*fields
;
315 const cfg_tuplefielddef_t
*f
;
317 REQUIRE(tupleobj
!= NULL
&& tupleobj
->type
->rep
== &cfg_rep_tuple
);
319 fields
= tupleobj
->type
->of
;
320 for (f
= fields
, i
= 0; f
->name
!= NULL
; f
++, i
++) {
321 if (strcmp(f
->name
, name
) == 0)
322 return (tupleobj
->value
.tuple
[i
]);
329 cfg_parse_special(cfg_parser_t
*pctx
, int special
) {
331 CHECK(cfg_gettoken(pctx
, 0));
332 if (pctx
->token
.type
== isc_tokentype_special
&&
333 pctx
->token
.value
.as_char
== special
)
334 return (ISC_R_SUCCESS
);
336 cfg_parser_error(pctx
, CFG_LOG_NEAR
, "'%c' expected", special
);
337 return (ISC_R_UNEXPECTEDTOKEN
);
343 * Parse a required semicolon. If it is not there, log
344 * an error and increment the error count but continue
345 * parsing. Since the next token is pushed back,
346 * care must be taken to make sure it is eventually
347 * consumed or an infinite loop may result.
350 parse_semicolon(cfg_parser_t
*pctx
) {
352 CHECK(cfg_gettoken(pctx
, 0));
353 if (pctx
->token
.type
== isc_tokentype_special
&&
354 pctx
->token
.value
.as_char
== ';')
355 return (ISC_R_SUCCESS
);
357 cfg_parser_error(pctx
, CFG_LOG_BEFORE
, "missing ';'");
358 cfg_ungettoken(pctx
);
364 * Parse EOF, logging and returning an error if not there.
367 parse_eof(cfg_parser_t
*pctx
) {
369 CHECK(cfg_gettoken(pctx
, 0));
371 if (pctx
->token
.type
== isc_tokentype_eof
)
372 return (ISC_R_SUCCESS
);
374 cfg_parser_error(pctx
, CFG_LOG_NEAR
, "syntax error");
375 return (ISC_R_UNEXPECTEDTOKEN
);
380 /* A list of files, used internally for pctx->files. */
382 static cfg_type_t cfg_type_filelist
= {
383 "filelist", NULL
, print_list
, NULL
, &cfg_rep_list
,
388 cfg_parser_create(isc_mem_t
*mctx
, isc_log_t
*lctx
, cfg_parser_t
**ret
) {
391 isc_lexspecials_t specials
;
393 REQUIRE(mctx
!= NULL
);
394 REQUIRE(ret
!= NULL
&& *ret
== NULL
);
396 pctx
= isc_mem_get(mctx
, sizeof(*pctx
));
398 return (ISC_R_NOMEMORY
);
401 isc_mem_attach(mctx
, &pctx
->mctx
);
403 result
= isc_refcount_init(&pctx
->references
, 1);
404 if (result
!= ISC_R_SUCCESS
) {
405 isc_mem_putanddetach(&pctx
->mctx
, pctx
, sizeof(*pctx
));
411 pctx
->seen_eof
= ISC_FALSE
;
412 pctx
->ungotten
= ISC_FALSE
;
415 pctx
->open_files
= NULL
;
416 pctx
->closed_files
= NULL
;
418 pctx
->callback
= NULL
;
419 pctx
->callbackarg
= NULL
;
420 pctx
->token
.type
= isc_tokentype_unknown
;
423 memset(specials
, 0, sizeof(specials
));
431 CHECK(isc_lex_create(pctx
->mctx
, 1024, &pctx
->lexer
));
433 isc_lex_setspecials(pctx
->lexer
, specials
);
434 isc_lex_setcomments(pctx
->lexer
, (ISC_LEXCOMMENT_C
|
435 ISC_LEXCOMMENT_CPLUSPLUS
|
436 ISC_LEXCOMMENT_SHELL
));
438 CHECK(cfg_create_list(pctx
, &cfg_type_filelist
, &pctx
->open_files
));
439 CHECK(cfg_create_list(pctx
, &cfg_type_filelist
, &pctx
->closed_files
));
442 return (ISC_R_SUCCESS
);
445 if (pctx
->lexer
!= NULL
)
446 isc_lex_destroy(&pctx
->lexer
);
447 CLEANUP_OBJ(pctx
->open_files
);
448 CLEANUP_OBJ(pctx
->closed_files
);
449 isc_mem_putanddetach(&pctx
->mctx
, pctx
, sizeof(*pctx
));
454 parser_openfile(cfg_parser_t
*pctx
, const char *filename
) {
456 cfg_listelt_t
*elt
= NULL
;
457 cfg_obj_t
*stringobj
= NULL
;
459 result
= isc_lex_openfile(pctx
->lexer
, filename
);
460 if (result
!= ISC_R_SUCCESS
) {
461 cfg_parser_error(pctx
, 0, "open: %s: %s",
462 filename
, isc_result_totext(result
));
466 CHECK(create_string(pctx
, filename
, &cfg_type_qstring
, &stringobj
));
467 CHECK(create_listelt(pctx
, &elt
));
468 elt
->obj
= stringobj
;
469 ISC_LIST_APPEND(pctx
->open_files
->value
.list
, elt
, link
);
471 return (ISC_R_SUCCESS
);
473 CLEANUP_OBJ(stringobj
);
478 cfg_parser_setcallback(cfg_parser_t
*pctx
,
479 cfg_parsecallback_t callback
,
482 pctx
->callback
= callback
;
483 pctx
->callbackarg
= arg
;
487 * Parse a configuration using a pctx where a lexer has already
488 * been set up with a source.
491 parse2(cfg_parser_t
*pctx
, const cfg_type_t
*type
, cfg_obj_t
**ret
) {
493 cfg_obj_t
*obj
= NULL
;
495 result
= cfg_parse_obj(pctx
, type
, &obj
);
497 if (pctx
->errors
!= 0) {
498 /* Errors have been logged. */
499 if (result
== ISC_R_SUCCESS
)
500 result
= ISC_R_FAILURE
;
504 if (result
!= ISC_R_SUCCESS
) {
505 /* Parsing failed but no errors have been logged. */
506 cfg_parser_error(pctx
, 0, "parsing failed");
510 CHECK(parse_eof(pctx
));
513 return (ISC_R_SUCCESS
);
521 cfg_parse_file(cfg_parser_t
*pctx
, const char *filename
,
522 const cfg_type_t
*type
, cfg_obj_t
**ret
)
526 REQUIRE(filename
!= NULL
);
528 CHECK(parser_openfile(pctx
, filename
));
529 CHECK(parse2(pctx
, type
, ret
));
536 cfg_parse_buffer(cfg_parser_t
*pctx
, isc_buffer_t
*buffer
,
537 const cfg_type_t
*type
, cfg_obj_t
**ret
)
540 REQUIRE(buffer
!= NULL
);
541 CHECK(isc_lex_openbuffer(pctx
->lexer
, buffer
));
542 CHECK(parse2(pctx
, type
, ret
));
548 cfg_parser_attach(cfg_parser_t
*src
, cfg_parser_t
**dest
) {
549 REQUIRE(src
!= NULL
);
550 REQUIRE(dest
!= NULL
&& *dest
== NULL
);
551 isc_refcount_increment(&src
->references
, NULL
);
556 cfg_parser_destroy(cfg_parser_t
**pctxp
) {
557 cfg_parser_t
*pctx
= *pctxp
;
560 isc_refcount_decrement(&pctx
->references
, &refs
);
562 isc_lex_destroy(&pctx
->lexer
);
564 * Cleaning up open_files does not
565 * close the files; that was already done
566 * by closing the lexer.
568 CLEANUP_OBJ(pctx
->open_files
);
569 CLEANUP_OBJ(pctx
->closed_files
);
570 isc_mem_putanddetach(&pctx
->mctx
, pctx
, sizeof(*pctx
));
579 cfg_parse_void(cfg_parser_t
*pctx
, const cfg_type_t
*type
, cfg_obj_t
**ret
) {
581 return (cfg_create_obj(pctx
, &cfg_type_void
, ret
));
585 cfg_print_void(cfg_printer_t
*pctx
, const cfg_obj_t
*obj
) {
591 cfg_doc_void(cfg_printer_t
*pctx
, const cfg_type_t
*type
) {
597 cfg_obj_isvoid(const cfg_obj_t
*obj
) {
598 REQUIRE(obj
!= NULL
);
599 return (ISC_TF(obj
->type
->rep
== &cfg_rep_void
));
602 cfg_type_t cfg_type_void
= {
603 "void", cfg_parse_void
, cfg_print_void
, cfg_doc_void
, &cfg_rep_void
,
611 cfg_parse_uint32(cfg_parser_t
*pctx
, const cfg_type_t
*type
, cfg_obj_t
**ret
) {
613 cfg_obj_t
*obj
= NULL
;
616 CHECK(cfg_gettoken(pctx
, ISC_LEXOPT_NUMBER
| ISC_LEXOPT_CNUMBER
));
617 if (pctx
->token
.type
!= isc_tokentype_number
) {
618 cfg_parser_error(pctx
, CFG_LOG_NEAR
, "expected number");
619 return (ISC_R_UNEXPECTEDTOKEN
);
622 CHECK(cfg_create_obj(pctx
, &cfg_type_uint32
, &obj
));
624 obj
->value
.uint32
= pctx
->token
.value
.as_ulong
;
631 cfg_print_cstr(cfg_printer_t
*pctx
, const char *s
) {
632 cfg_print_chars(pctx
, s
, strlen(s
));
636 cfg_print_rawuint(cfg_printer_t
*pctx
, unsigned int u
) {
638 snprintf(buf
, sizeof(buf
), "%u", u
);
639 cfg_print_cstr(pctx
, buf
);
643 cfg_print_uint32(cfg_printer_t
*pctx
, const cfg_obj_t
*obj
) {
644 cfg_print_rawuint(pctx
, obj
->value
.uint32
);
648 cfg_obj_isuint32(const cfg_obj_t
*obj
) {
649 REQUIRE(obj
!= NULL
);
650 return (ISC_TF(obj
->type
->rep
== &cfg_rep_uint32
));
654 cfg_obj_asuint32(const cfg_obj_t
*obj
) {
655 REQUIRE(obj
!= NULL
&& obj
->type
->rep
== &cfg_rep_uint32
);
656 return (obj
->value
.uint32
);
659 cfg_type_t cfg_type_uint32
= {
660 "integer", cfg_parse_uint32
, cfg_print_uint32
, cfg_doc_terminal
,
661 &cfg_rep_uint32
, NULL
669 cfg_obj_isuint64(const cfg_obj_t
*obj
) {
670 REQUIRE(obj
!= NULL
);
671 return (ISC_TF(obj
->type
->rep
== &cfg_rep_uint64
));
675 cfg_obj_asuint64(const cfg_obj_t
*obj
) {
676 REQUIRE(obj
!= NULL
&& obj
->type
->rep
== &cfg_rep_uint64
);
677 return (obj
->value
.uint64
);
681 cfg_print_uint64(cfg_printer_t
*pctx
, const cfg_obj_t
*obj
) {
683 snprintf(buf
, sizeof(buf
), "%" ISC_PRINT_QUADFORMAT
"u",
685 cfg_print_cstr(pctx
, buf
);
688 cfg_type_t cfg_type_uint64
= {
689 "64_bit_integer", NULL
, cfg_print_uint64
, cfg_doc_terminal
,
690 &cfg_rep_uint64
, NULL
694 * qstring (quoted string), ustring (unquoted string), astring
698 /* Create a string object from a null-terminated C string. */
700 create_string(cfg_parser_t
*pctx
, const char *contents
, const cfg_type_t
*type
,
704 cfg_obj_t
*obj
= NULL
;
707 CHECK(cfg_create_obj(pctx
, type
, &obj
));
708 len
= strlen(contents
);
709 obj
->value
.string
.length
= len
;
710 obj
->value
.string
.base
= isc_mem_get(pctx
->mctx
, len
+ 1);
711 if (obj
->value
.string
.base
== 0) {
712 isc_mem_put(pctx
->mctx
, obj
, sizeof(*obj
));
713 return (ISC_R_NOMEMORY
);
715 memmove(obj
->value
.string
.base
, contents
, len
);
716 obj
->value
.string
.base
[len
] = '\0';
724 cfg_parse_qstring(cfg_parser_t
*pctx
, const cfg_type_t
*type
, cfg_obj_t
**ret
) {
728 CHECK(cfg_gettoken(pctx
, CFG_LEXOPT_QSTRING
));
729 if (pctx
->token
.type
!= isc_tokentype_qstring
) {
730 cfg_parser_error(pctx
, CFG_LOG_NEAR
, "expected quoted string");
731 return (ISC_R_UNEXPECTEDTOKEN
);
733 return (create_string(pctx
,
742 parse_ustring(cfg_parser_t
*pctx
, const cfg_type_t
*type
, cfg_obj_t
**ret
) {
746 CHECK(cfg_gettoken(pctx
, 0));
747 if (pctx
->token
.type
!= isc_tokentype_string
) {
748 cfg_parser_error(pctx
, CFG_LOG_NEAR
, "expected unquoted string");
749 return (ISC_R_UNEXPECTEDTOKEN
);
751 return (create_string(pctx
,
760 cfg_parse_astring(cfg_parser_t
*pctx
, const cfg_type_t
*type
,
766 CHECK(cfg_getstringtoken(pctx
));
767 return (create_string(pctx
,
776 cfg_parse_sstring(cfg_parser_t
*pctx
, const cfg_type_t
*type
,
782 CHECK(cfg_getstringtoken(pctx
));
783 return (create_string(pctx
,
792 cfg_is_enum(const char *s
, const char *const *enums
) {
793 const char * const *p
;
794 for (p
= enums
; *p
!= NULL
; p
++) {
795 if (strcasecmp(*p
, s
) == 0)
802 check_enum(cfg_parser_t
*pctx
, cfg_obj_t
*obj
, const char *const *enums
) {
803 const char *s
= obj
->value
.string
.base
;
804 if (cfg_is_enum(s
, enums
))
805 return (ISC_R_SUCCESS
);
806 cfg_parser_error(pctx
, 0, "'%s' unexpected", s
);
807 return (ISC_R_UNEXPECTEDTOKEN
);
811 cfg_parse_enum(cfg_parser_t
*pctx
, const cfg_type_t
*type
, cfg_obj_t
**ret
) {
813 cfg_obj_t
*obj
= NULL
;
814 CHECK(parse_ustring(pctx
, NULL
, &obj
));
815 CHECK(check_enum(pctx
, obj
, type
->of
));
817 return (ISC_R_SUCCESS
);
824 cfg_doc_enum(cfg_printer_t
*pctx
, const cfg_type_t
*type
) {
825 const char * const *p
;
826 cfg_print_chars(pctx
, "( ", 2);
827 for (p
= type
->of
; *p
!= NULL
; p
++) {
828 cfg_print_cstr(pctx
, *p
);
830 cfg_print_chars(pctx
, " | ", 3);
832 cfg_print_chars(pctx
, " )", 2);
836 cfg_print_ustring(cfg_printer_t
*pctx
, const cfg_obj_t
*obj
) {
837 cfg_print_chars(pctx
, obj
->value
.string
.base
, obj
->value
.string
.length
);
841 print_qstring(cfg_printer_t
*pctx
, const cfg_obj_t
*obj
) {
842 cfg_print_chars(pctx
, "\"", 1);
843 cfg_print_ustring(pctx
, obj
);
844 cfg_print_chars(pctx
, "\"", 1);
848 print_sstring(cfg_printer_t
*pctx
, const cfg_obj_t
*obj
) {
849 cfg_print_chars(pctx
, "\"", 1);
850 if ((pctx
->flags
& CFG_PRINTER_XKEY
) != 0) {
851 unsigned int len
= obj
->value
.string
.length
;
853 cfg_print_chars(pctx
, "?", 1);
855 cfg_print_ustring(pctx
, obj
);
856 cfg_print_chars(pctx
, "\"", 1);
860 free_string(cfg_parser_t
*pctx
, cfg_obj_t
*obj
) {
861 isc_mem_put(pctx
->mctx
, obj
->value
.string
.base
,
862 obj
->value
.string
.length
+ 1);
866 cfg_obj_isstring(const cfg_obj_t
*obj
) {
867 REQUIRE(obj
!= NULL
);
868 return (ISC_TF(obj
->type
->rep
== &cfg_rep_string
));
872 cfg_obj_asstring(const cfg_obj_t
*obj
) {
873 REQUIRE(obj
!= NULL
&& obj
->type
->rep
== &cfg_rep_string
);
874 return (obj
->value
.string
.base
);
877 /* Quoted string only */
878 cfg_type_t cfg_type_qstring
= {
879 "quoted_string", cfg_parse_qstring
, print_qstring
, cfg_doc_terminal
,
880 &cfg_rep_string
, NULL
883 /* Unquoted string only */
884 cfg_type_t cfg_type_ustring
= {
885 "string", parse_ustring
, cfg_print_ustring
, cfg_doc_terminal
,
886 &cfg_rep_string
, NULL
889 /* Any string (quoted or unquoted); printed with quotes */
890 cfg_type_t cfg_type_astring
= {
891 "string", cfg_parse_astring
, print_qstring
, cfg_doc_terminal
,
892 &cfg_rep_string
, NULL
896 * Any string (quoted or unquoted); printed with quotes.
897 * If CFG_PRINTER_XKEY is set when printing the string will be '?' out.
899 cfg_type_t cfg_type_sstring
= {
900 "string", cfg_parse_sstring
, print_sstring
, cfg_doc_terminal
,
901 &cfg_rep_string
, NULL
909 cfg_obj_isboolean(const cfg_obj_t
*obj
) {
910 REQUIRE(obj
!= NULL
);
911 return (ISC_TF(obj
->type
->rep
== &cfg_rep_boolean
));
915 cfg_obj_asboolean(const cfg_obj_t
*obj
) {
916 REQUIRE(obj
!= NULL
&& obj
->type
->rep
== &cfg_rep_boolean
);
917 return (obj
->value
.boolean
);
921 cfg_parse_boolean(cfg_parser_t
*pctx
, const cfg_type_t
*type
, cfg_obj_t
**ret
)
925 cfg_obj_t
*obj
= NULL
;
928 result
= cfg_gettoken(pctx
, 0);
929 if (result
!= ISC_R_SUCCESS
)
932 if (pctx
->token
.type
!= isc_tokentype_string
)
935 if ((strcasecmp(TOKEN_STRING(pctx
), "true") == 0) ||
936 (strcasecmp(TOKEN_STRING(pctx
), "yes") == 0) ||
937 (strcmp(TOKEN_STRING(pctx
), "1") == 0)) {
939 } else if ((strcasecmp(TOKEN_STRING(pctx
), "false") == 0) ||
940 (strcasecmp(TOKEN_STRING(pctx
), "no") == 0) ||
941 (strcmp(TOKEN_STRING(pctx
), "0") == 0)) {
947 CHECK(cfg_create_obj(pctx
, &cfg_type_boolean
, &obj
));
948 obj
->value
.boolean
= value
;
953 cfg_parser_error(pctx
, CFG_LOG_NEAR
, "boolean expected");
954 return (ISC_R_UNEXPECTEDTOKEN
);
961 cfg_print_boolean(cfg_printer_t
*pctx
, const cfg_obj_t
*obj
) {
962 if (obj
->value
.boolean
)
963 cfg_print_chars(pctx
, "yes", 3);
965 cfg_print_chars(pctx
, "no", 2);
968 cfg_type_t cfg_type_boolean
= {
969 "boolean", cfg_parse_boolean
, cfg_print_boolean
, cfg_doc_terminal
,
970 &cfg_rep_boolean
, NULL
978 cfg_create_list(cfg_parser_t
*pctx
, const cfg_type_t
*type
, cfg_obj_t
**obj
) {
980 CHECK(cfg_create_obj(pctx
, type
, obj
));
981 ISC_LIST_INIT((*obj
)->value
.list
);
987 create_listelt(cfg_parser_t
*pctx
, cfg_listelt_t
**eltp
) {
989 elt
= isc_mem_get(pctx
->mctx
, sizeof(*elt
));
991 return (ISC_R_NOMEMORY
);
993 ISC_LINK_INIT(elt
, link
);
995 return (ISC_R_SUCCESS
);
999 free_list_elt(cfg_parser_t
*pctx
, cfg_listelt_t
*elt
) {
1000 cfg_obj_destroy(pctx
, &elt
->obj
);
1001 isc_mem_put(pctx
->mctx
, elt
, sizeof(*elt
));
1005 free_list(cfg_parser_t
*pctx
, cfg_obj_t
*obj
) {
1006 cfg_listelt_t
*elt
, *next
;
1007 for (elt
= ISC_LIST_HEAD(obj
->value
.list
);
1011 next
= ISC_LIST_NEXT(elt
, link
);
1012 free_list_elt(pctx
, elt
);
1017 cfg_parse_listelt(cfg_parser_t
*pctx
, const cfg_type_t
*elttype
,
1018 cfg_listelt_t
**ret
)
1020 isc_result_t result
;
1021 cfg_listelt_t
*elt
= NULL
;
1022 cfg_obj_t
*value
= NULL
;
1024 CHECK(create_listelt(pctx
, &elt
));
1026 result
= cfg_parse_obj(pctx
, elttype
, &value
);
1027 if (result
!= ISC_R_SUCCESS
)
1033 return (ISC_R_SUCCESS
);
1036 isc_mem_put(pctx
->mctx
, elt
, sizeof(*elt
));
1041 * Parse a homogeneous list whose elements are of type 'elttype'
1042 * and where each element is terminated by a semicolon.
1045 parse_list(cfg_parser_t
*pctx
, const cfg_type_t
*listtype
, cfg_obj_t
**ret
)
1047 cfg_obj_t
*listobj
= NULL
;
1048 const cfg_type_t
*listof
= listtype
->of
;
1049 isc_result_t result
;
1050 cfg_listelt_t
*elt
= NULL
;
1052 CHECK(cfg_create_list(pctx
, listtype
, &listobj
));
1055 CHECK(cfg_peektoken(pctx
, 0));
1056 if (pctx
->token
.type
== isc_tokentype_special
&&
1057 pctx
->token
.value
.as_char
== /*{*/ '}')
1059 CHECK(cfg_parse_listelt(pctx
, listof
, &elt
));
1060 CHECK(parse_semicolon(pctx
));
1061 ISC_LIST_APPEND(listobj
->value
.list
, elt
, link
);
1065 return (ISC_R_SUCCESS
);
1069 free_list_elt(pctx
, elt
);
1070 CLEANUP_OBJ(listobj
);
1075 print_list(cfg_printer_t
*pctx
, const cfg_obj_t
*obj
) {
1076 const cfg_list_t
*list
= &obj
->value
.list
;
1077 const cfg_listelt_t
*elt
;
1079 for (elt
= ISC_LIST_HEAD(*list
);
1081 elt
= ISC_LIST_NEXT(elt
, link
)) {
1083 cfg_print_obj(pctx
, elt
->obj
);
1084 cfg_print_chars(pctx
, ";\n", 2);
1089 cfg_parse_bracketed_list(cfg_parser_t
*pctx
, const cfg_type_t
*type
,
1092 isc_result_t result
;
1093 CHECK(cfg_parse_special(pctx
, '{'));
1094 CHECK(parse_list(pctx
, type
, ret
));
1095 CHECK(cfg_parse_special(pctx
, '}'));
1101 cfg_print_bracketed_list(cfg_printer_t
*pctx
, const cfg_obj_t
*obj
) {
1103 print_list(pctx
, obj
);
1108 cfg_doc_bracketed_list(cfg_printer_t
*pctx
, const cfg_type_t
*type
) {
1109 cfg_print_chars(pctx
, "{ ", 2);
1110 cfg_doc_obj(pctx
, type
->of
);
1111 cfg_print_chars(pctx
, "; ... }", 7);
1115 * Parse a homogeneous list whose elements are of type 'elttype'
1116 * and where elements are separated by space. The list ends
1117 * before the first semicolon.
1120 cfg_parse_spacelist(cfg_parser_t
*pctx
, const cfg_type_t
*listtype
,
1123 cfg_obj_t
*listobj
= NULL
;
1124 const cfg_type_t
*listof
= listtype
->of
;
1125 isc_result_t result
;
1127 CHECK(cfg_create_list(pctx
, listtype
, &listobj
));
1130 cfg_listelt_t
*elt
= NULL
;
1132 CHECK(cfg_peektoken(pctx
, 0));
1133 if (pctx
->token
.type
== isc_tokentype_special
&&
1134 pctx
->token
.value
.as_char
== ';')
1136 CHECK(cfg_parse_listelt(pctx
, listof
, &elt
));
1137 ISC_LIST_APPEND(listobj
->value
.list
, elt
, link
);
1140 return (ISC_R_SUCCESS
);
1143 CLEANUP_OBJ(listobj
);
1148 cfg_print_spacelist(cfg_printer_t
*pctx
, const cfg_obj_t
*obj
) {
1149 const cfg_list_t
*list
= &obj
->value
.list
;
1150 const cfg_listelt_t
*elt
;
1152 for (elt
= ISC_LIST_HEAD(*list
);
1154 elt
= ISC_LIST_NEXT(elt
, link
)) {
1155 cfg_print_obj(pctx
, elt
->obj
);
1156 if (ISC_LIST_NEXT(elt
, link
) != NULL
)
1157 cfg_print_chars(pctx
, " ", 1);
1162 cfg_obj_islist(const cfg_obj_t
*obj
) {
1163 REQUIRE(obj
!= NULL
);
1164 return (ISC_TF(obj
->type
->rep
== &cfg_rep_list
));
1167 const cfg_listelt_t
*
1168 cfg_list_first(const cfg_obj_t
*obj
) {
1169 REQUIRE(obj
== NULL
|| obj
->type
->rep
== &cfg_rep_list
);
1172 return (ISC_LIST_HEAD(obj
->value
.list
));
1175 const cfg_listelt_t
*
1176 cfg_list_next(const cfg_listelt_t
*elt
) {
1177 REQUIRE(elt
!= NULL
);
1178 return (ISC_LIST_NEXT(elt
, link
));
1182 * Return the length of a list object. If obj is NULL or is not
1186 cfg_list_length(const cfg_obj_t
*obj
, isc_boolean_t recurse
) {
1187 const cfg_listelt_t
*elt
;
1188 unsigned int count
= 0;
1190 if (obj
== NULL
|| !cfg_obj_islist(obj
))
1192 for (elt
= cfg_list_first(obj
);
1194 elt
= cfg_list_next(elt
)) {
1195 if (recurse
&& cfg_obj_islist(elt
->obj
)) {
1196 count
+= cfg_list_length(elt
->obj
, recurse
);
1205 cfg_listelt_value(const cfg_listelt_t
*elt
) {
1206 REQUIRE(elt
!= NULL
);
1215 * Parse a map body. That's something like
1217 * "foo 1; bar { glub; }; zap true; zap false;"
1219 * i.e., a sequence of option names followed by values and
1220 * terminated by semicolons. Used for the top level of
1221 * the named.conf syntax, as well as for the body of the
1222 * options, view, zone, and other statements.
1225 cfg_parse_mapbody(cfg_parser_t
*pctx
, const cfg_type_t
*type
, cfg_obj_t
**ret
)
1227 const cfg_clausedef_t
* const *clausesets
= type
->of
;
1228 isc_result_t result
;
1229 const cfg_clausedef_t
* const *clauseset
;
1230 const cfg_clausedef_t
*clause
;
1231 cfg_obj_t
*value
= NULL
;
1232 cfg_obj_t
*obj
= NULL
;
1233 cfg_obj_t
*eltobj
= NULL
;
1234 cfg_obj_t
*includename
= NULL
;
1235 isc_symvalue_t symval
;
1236 cfg_list_t
*list
= NULL
;
1238 CHECK(create_map(pctx
, type
, &obj
));
1240 obj
->value
.map
.clausesets
= clausesets
;
1247 * Parse the option name and see if it is known.
1249 CHECK(cfg_gettoken(pctx
, 0));
1251 if (pctx
->token
.type
!= isc_tokentype_string
) {
1252 cfg_ungettoken(pctx
);
1257 * We accept "include" statements wherever a map body
1260 if (strcasecmp(TOKEN_STRING(pctx
), "include") == 0) {
1262 * Turn the file name into a temporary configuration
1263 * object just so that it is not overwritten by the
1266 CHECK(cfg_parse_obj(pctx
, &cfg_type_qstring
, &includename
));
1267 CHECK(parse_semicolon(pctx
));
1268 CHECK(parser_openfile(pctx
, includename
->
1269 value
.string
.base
));
1270 cfg_obj_destroy(pctx
, &includename
);
1275 for (clauseset
= clausesets
; *clauseset
!= NULL
; clauseset
++) {
1276 for (clause
= *clauseset
;
1277 clause
->name
!= NULL
;
1279 if (strcasecmp(TOKEN_STRING(pctx
),
1285 if (clause
== NULL
|| clause
->name
== NULL
) {
1286 cfg_parser_error(pctx
, CFG_LOG_NOPREP
, "unknown option");
1288 * Try to recover by parsing this option as an unknown
1289 * option and discarding it.
1291 CHECK(cfg_parse_obj(pctx
, &cfg_type_unsupported
, &eltobj
));
1292 cfg_obj_destroy(pctx
, &eltobj
);
1293 CHECK(parse_semicolon(pctx
));
1297 /* Clause is known. */
1299 /* Issue warnings if appropriate */
1300 if ((clause
->flags
& CFG_CLAUSEFLAG_OBSOLETE
) != 0)
1301 cfg_parser_warning(pctx
, 0, "option '%s' is obsolete",
1303 if ((clause
->flags
& CFG_CLAUSEFLAG_NOTIMP
) != 0)
1304 cfg_parser_warning(pctx
, 0, "option '%s' is "
1305 "not implemented", clause
->name
);
1306 if ((clause
->flags
& CFG_CLAUSEFLAG_NYI
) != 0)
1307 cfg_parser_warning(pctx
, 0, "option '%s' is "
1308 "not implemented", clause
->name
);
1310 if ((clause
->flags
& CFG_CLAUSEFLAG_NOTCONFIGURED
) != 0) {
1311 cfg_parser_warning(pctx
, 0, "option '%s' was not "
1312 "enabled at compile time",
1314 result
= ISC_R_FAILURE
;
1319 * Don't log options with CFG_CLAUSEFLAG_NEWDEFAULT
1320 * set here - we need to log the *lack* of such an option,
1324 /* See if the clause already has a value; if not create one. */
1325 result
= isc_symtab_lookup(obj
->value
.map
.symtab
,
1326 clause
->name
, 0, &symval
);
1328 if ((clause
->flags
& CFG_CLAUSEFLAG_MULTI
) != 0) {
1329 /* Multivalued clause */
1330 cfg_obj_t
*listobj
= NULL
;
1331 if (result
== ISC_R_NOTFOUND
) {
1332 CHECK(cfg_create_list(pctx
,
1333 &cfg_type_implicitlist
,
1335 symval
.as_pointer
= listobj
;
1336 result
= isc_symtab_define(obj
->value
.
1340 isc_symexists_reject
);
1341 if (result
!= ISC_R_SUCCESS
) {
1342 cfg_parser_error(pctx
, CFG_LOG_NEAR
,
1343 "isc_symtab_define(%s) "
1344 "failed", clause
->name
);
1345 isc_mem_put(pctx
->mctx
, list
,
1346 sizeof(cfg_list_t
));
1350 INSIST(result
== ISC_R_SUCCESS
);
1351 listobj
= symval
.as_pointer
;
1355 CHECK(cfg_parse_listelt(pctx
, clause
->type
, &elt
));
1356 CHECK(parse_semicolon(pctx
));
1358 ISC_LIST_APPEND(listobj
->value
.list
, elt
, link
);
1360 /* Single-valued clause */
1361 if (result
== ISC_R_NOTFOUND
) {
1362 isc_boolean_t callback
=
1363 ISC_TF((clause
->flags
&
1364 CFG_CLAUSEFLAG_CALLBACK
) != 0);
1365 CHECK(parse_symtab_elt(pctx
, clause
->name
,
1367 obj
->value
.map
.symtab
,
1369 CHECK(parse_semicolon(pctx
));
1370 } else if (result
== ISC_R_SUCCESS
) {
1371 cfg_parser_error(pctx
, CFG_LOG_NEAR
, "'%s' redefined",
1373 result
= ISC_R_EXISTS
;
1376 cfg_parser_error(pctx
, CFG_LOG_NEAR
,
1377 "isc_symtab_define() failed");
1385 return (ISC_R_SUCCESS
);
1390 CLEANUP_OBJ(eltobj
);
1391 CLEANUP_OBJ(includename
);
1396 parse_symtab_elt(cfg_parser_t
*pctx
, const char *name
,
1397 cfg_type_t
*elttype
, isc_symtab_t
*symtab
,
1398 isc_boolean_t callback
)
1400 isc_result_t result
;
1401 cfg_obj_t
*obj
= NULL
;
1402 isc_symvalue_t symval
;
1404 CHECK(cfg_parse_obj(pctx
, elttype
, &obj
));
1406 if (callback
&& pctx
->callback
!= NULL
)
1407 CHECK(pctx
->callback(name
, obj
, pctx
->callbackarg
));
1409 symval
.as_pointer
= obj
;
1410 CHECK(isc_symtab_define(symtab
, name
,
1412 isc_symexists_reject
));
1413 return (ISC_R_SUCCESS
);
1421 * Parse a map; e.g., "{ foo 1; bar { glub; }; zap true; zap false; }"
1424 cfg_parse_map(cfg_parser_t
*pctx
, const cfg_type_t
*type
, cfg_obj_t
**ret
) {
1425 isc_result_t result
;
1426 CHECK(cfg_parse_special(pctx
, '{'));
1427 CHECK(cfg_parse_mapbody(pctx
, type
, ret
));
1428 CHECK(cfg_parse_special(pctx
, '}'));
1434 * Subroutine for cfg_parse_named_map() and cfg_parse_addressed_map().
1437 parse_any_named_map(cfg_parser_t
*pctx
, cfg_type_t
*nametype
, const cfg_type_t
*type
,
1440 isc_result_t result
;
1441 cfg_obj_t
*idobj
= NULL
;
1442 cfg_obj_t
*mapobj
= NULL
;
1444 CHECK(cfg_parse_obj(pctx
, nametype
, &idobj
));
1445 CHECK(cfg_parse_map(pctx
, type
, &mapobj
));
1446 mapobj
->value
.map
.id
= idobj
;
1455 * Parse a map identified by a string name. E.g., "name { foo 1; }".
1456 * Used for the "key" and "channel" statements.
1459 cfg_parse_named_map(cfg_parser_t
*pctx
, const cfg_type_t
*type
, cfg_obj_t
**ret
) {
1460 return (parse_any_named_map(pctx
, &cfg_type_astring
, type
, ret
));
1464 * Parse a map identified by a network address.
1465 * Used to be used for the "server" statement.
1468 cfg_parse_addressed_map(cfg_parser_t
*pctx
, const cfg_type_t
*type
, cfg_obj_t
**ret
) {
1469 return (parse_any_named_map(pctx
, &cfg_type_netaddr
, type
, ret
));
1473 * Parse a map identified by a network prefix.
1474 * Used for the "server" statement.
1477 cfg_parse_netprefix_map(cfg_parser_t
*pctx
, const cfg_type_t
*type
, cfg_obj_t
**ret
) {
1478 return (parse_any_named_map(pctx
, &cfg_type_netprefix
, type
, ret
));
1482 cfg_print_mapbody(cfg_printer_t
*pctx
, const cfg_obj_t
*obj
) {
1483 isc_result_t result
= ISC_R_SUCCESS
;
1485 const cfg_clausedef_t
* const *clauseset
;
1487 for (clauseset
= obj
->value
.map
.clausesets
;
1491 isc_symvalue_t symval
;
1492 const cfg_clausedef_t
*clause
;
1494 for (clause
= *clauseset
;
1495 clause
->name
!= NULL
;
1497 result
= isc_symtab_lookup(obj
->value
.map
.symtab
,
1498 clause
->name
, 0, &symval
);
1499 if (result
== ISC_R_SUCCESS
) {
1500 cfg_obj_t
*symobj
= symval
.as_pointer
;
1501 if (symobj
->type
== &cfg_type_implicitlist
) {
1503 cfg_list_t
*list
= &symobj
->value
.list
;
1505 for (elt
= ISC_LIST_HEAD(*list
);
1507 elt
= ISC_LIST_NEXT(elt
, link
)) {
1509 cfg_print_cstr(pctx
, clause
->name
);
1510 cfg_print_chars(pctx
, " ", 1);
1511 cfg_print_obj(pctx
, elt
->obj
);
1512 cfg_print_chars(pctx
, ";\n", 2);
1515 /* Single-valued. */
1517 cfg_print_cstr(pctx
, clause
->name
);
1518 cfg_print_chars(pctx
, " ", 1);
1519 cfg_print_obj(pctx
, symobj
);
1520 cfg_print_chars(pctx
, ";\n", 2);
1522 } else if (result
== ISC_R_NOTFOUND
) {
1532 cfg_doc_mapbody(cfg_printer_t
*pctx
, const cfg_type_t
*type
) {
1533 const cfg_clausedef_t
* const *clauseset
;
1534 const cfg_clausedef_t
*clause
;
1536 for (clauseset
= type
->of
; *clauseset
!= NULL
; clauseset
++) {
1537 for (clause
= *clauseset
;
1538 clause
->name
!= NULL
;
1540 cfg_print_cstr(pctx
, clause
->name
);
1541 cfg_print_chars(pctx
, " ", 1);
1542 cfg_doc_obj(pctx
, clause
->type
);
1543 cfg_print_chars(pctx
, ";", 1);
1544 /* XXX print flags here? */
1545 cfg_print_chars(pctx
, "\n\n", 2);
1550 static struct flagtext
{
1554 { CFG_CLAUSEFLAG_NOTIMP
, "not implemented" },
1555 { CFG_CLAUSEFLAG_NYI
, "not yet implemented" },
1556 { CFG_CLAUSEFLAG_OBSOLETE
, "obsolete" },
1557 { CFG_CLAUSEFLAG_NEWDEFAULT
, "default changed" },
1558 { CFG_CLAUSEFLAG_TESTONLY
, "test only" },
1559 { CFG_CLAUSEFLAG_NOTCONFIGURED
, "not configured" },
1564 cfg_print_map(cfg_printer_t
*pctx
, const cfg_obj_t
*obj
) {
1565 if (obj
->value
.map
.id
!= NULL
) {
1566 cfg_print_obj(pctx
, obj
->value
.map
.id
);
1567 cfg_print_chars(pctx
, " ", 1);
1570 cfg_print_mapbody(pctx
, obj
);
1575 print_clause_flags(cfg_printer_t
*pctx
, unsigned int flags
) {
1577 isc_boolean_t first
= ISC_TRUE
;
1578 for (p
= flagtexts
; p
->flag
!= 0; p
++) {
1579 if ((flags
& p
->flag
) != 0) {
1581 cfg_print_chars(pctx
, " // ", 4);
1583 cfg_print_chars(pctx
, ", ", 2);
1584 cfg_print_cstr(pctx
, p
->text
);
1591 cfg_doc_map(cfg_printer_t
*pctx
, const cfg_type_t
*type
) {
1592 const cfg_clausedef_t
* const *clauseset
;
1593 const cfg_clausedef_t
*clause
;
1595 if (type
->parse
== cfg_parse_named_map
) {
1596 cfg_doc_obj(pctx
, &cfg_type_astring
);
1597 cfg_print_chars(pctx
, " ", 1);
1598 } else if (type
->parse
== cfg_parse_addressed_map
) {
1599 cfg_doc_obj(pctx
, &cfg_type_netaddr
);
1600 cfg_print_chars(pctx
, " ", 1);
1601 } else if (type
->parse
== cfg_parse_netprefix_map
) {
1602 cfg_doc_obj(pctx
, &cfg_type_netprefix
);
1603 cfg_print_chars(pctx
, " ", 1);
1608 for (clauseset
= type
->of
; *clauseset
!= NULL
; clauseset
++) {
1609 for (clause
= *clauseset
;
1610 clause
->name
!= NULL
;
1613 cfg_print_cstr(pctx
, clause
->name
);
1614 if (clause
->type
->print
!= cfg_print_void
)
1615 cfg_print_chars(pctx
, " ", 1);
1616 cfg_doc_obj(pctx
, clause
->type
);
1617 cfg_print_chars(pctx
, ";", 1);
1618 print_clause_flags(pctx
, clause
->flags
);
1619 cfg_print_chars(pctx
, "\n", 1);
1626 cfg_obj_ismap(const cfg_obj_t
*obj
) {
1627 REQUIRE(obj
!= NULL
);
1628 return (ISC_TF(obj
->type
->rep
== &cfg_rep_map
));
1632 cfg_map_get(const cfg_obj_t
*mapobj
, const char* name
, const cfg_obj_t
**obj
) {
1633 isc_result_t result
;
1635 const cfg_map_t
*map
;
1637 REQUIRE(mapobj
!= NULL
&& mapobj
->type
->rep
== &cfg_rep_map
);
1638 REQUIRE(name
!= NULL
);
1639 REQUIRE(obj
!= NULL
&& *obj
== NULL
);
1641 map
= &mapobj
->value
.map
;
1643 result
= isc_symtab_lookup(map
->symtab
, name
, MAP_SYM
, &val
);
1644 if (result
!= ISC_R_SUCCESS
)
1646 *obj
= val
.as_pointer
;
1647 return (ISC_R_SUCCESS
);
1651 cfg_map_getname(const cfg_obj_t
*mapobj
) {
1652 REQUIRE(mapobj
!= NULL
&& mapobj
->type
->rep
== &cfg_rep_map
);
1653 return (mapobj
->value
.map
.id
);
1657 cfg_map_count(const cfg_obj_t
*mapobj
) {
1658 const cfg_map_t
*map
;
1659 REQUIRE(mapobj
!= NULL
&& mapobj
->type
->rep
== &cfg_rep_map
);
1660 map
= &mapobj
->value
.map
;
1661 return (isc_symtab_count(map
->symtab
));
1664 /* Parse an arbitrary token, storing its raw text representation. */
1666 parse_token(cfg_parser_t
*pctx
, const cfg_type_t
*type
, cfg_obj_t
**ret
) {
1667 cfg_obj_t
*obj
= NULL
;
1668 isc_result_t result
;
1673 CHECK(cfg_create_obj(pctx
, &cfg_type_token
, &obj
));
1674 CHECK(cfg_gettoken(pctx
, CFG_LEXOPT_QSTRING
));
1675 if (pctx
->token
.type
== isc_tokentype_eof
) {
1676 cfg_ungettoken(pctx
);
1681 isc_lex_getlasttokentext(pctx
->lexer
, &pctx
->token
, &r
);
1683 obj
->value
.string
.base
= isc_mem_get(pctx
->mctx
, r
.length
+ 1);
1684 if (obj
->value
.string
.base
== NULL
) {
1685 result
= ISC_R_NOMEMORY
;
1688 obj
->value
.string
.length
= r
.length
;
1689 memmove(obj
->value
.string
.base
, r
.base
, r
.length
);
1690 obj
->value
.string
.base
[r
.length
] = '\0';
1696 isc_mem_put(pctx
->mctx
, obj
, sizeof(*obj
));
1700 cfg_type_t cfg_type_token
= {
1701 "token", parse_token
, cfg_print_ustring
, cfg_doc_terminal
,
1702 &cfg_rep_string
, NULL
1706 * An unsupported option. This is just a list of tokens with balanced braces
1707 * ending in a semicolon.
1711 parse_unsupported(cfg_parser_t
*pctx
, const cfg_type_t
*type
, cfg_obj_t
**ret
) {
1712 cfg_obj_t
*listobj
= NULL
;
1713 isc_result_t result
;
1716 CHECK(cfg_create_list(pctx
, type
, &listobj
));
1719 cfg_listelt_t
*elt
= NULL
;
1721 CHECK(cfg_peektoken(pctx
, 0));
1722 if (pctx
->token
.type
== isc_tokentype_special
) {
1723 if (pctx
->token
.value
.as_char
== '{')
1725 else if (pctx
->token
.value
.as_char
== '}')
1727 else if (pctx
->token
.value
.as_char
== ';')
1731 if (pctx
->token
.type
== isc_tokentype_eof
|| braces
< 0) {
1732 cfg_parser_error(pctx
, CFG_LOG_NEAR
, "unexpected token");
1733 result
= ISC_R_UNEXPECTEDTOKEN
;
1737 CHECK(cfg_parse_listelt(pctx
, &cfg_type_token
, &elt
));
1738 ISC_LIST_APPEND(listobj
->value
.list
, elt
, link
);
1740 INSIST(braces
== 0);
1742 return (ISC_R_SUCCESS
);
1745 CLEANUP_OBJ(listobj
);
1749 cfg_type_t cfg_type_unsupported
= {
1750 "unsupported", parse_unsupported
, cfg_print_spacelist
, cfg_doc_terminal
,
1755 * Try interpreting the current token as a network address.
1757 * If CFG_ADDR_WILDOK is set in flags, "*" can be used as a wildcard
1758 * and at least one of CFG_ADDR_V4OK and CFG_ADDR_V6OK must also be set. The
1759 * "*" is interpreted as the IPv4 wildcard address if CFG_ADDR_V4OK is
1760 * set (including the case where CFG_ADDR_V4OK and CFG_ADDR_V6OK are both set),
1761 * and the IPv6 wildcard address otherwise.
1764 token_addr(cfg_parser_t
*pctx
, unsigned int flags
, isc_netaddr_t
*na
) {
1766 struct in_addr in4a
;
1767 struct in6_addr in6a
;
1769 if (pctx
->token
.type
!= isc_tokentype_string
)
1770 return (ISC_R_UNEXPECTEDTOKEN
);
1772 s
= TOKEN_STRING(pctx
);
1773 if ((flags
& CFG_ADDR_WILDOK
) != 0 && strcmp(s
, "*") == 0) {
1774 if ((flags
& CFG_ADDR_V4OK
) != 0) {
1775 isc_netaddr_any(na
);
1776 return (ISC_R_SUCCESS
);
1777 } else if ((flags
& CFG_ADDR_V6OK
) != 0) {
1778 isc_netaddr_any6(na
);
1779 return (ISC_R_SUCCESS
);
1784 if ((flags
& (CFG_ADDR_V4OK
| CFG_ADDR_V4PREFIXOK
)) != 0) {
1785 if (inet_pton(AF_INET
, s
, &in4a
) == 1) {
1786 isc_netaddr_fromin(na
, &in4a
);
1787 return (ISC_R_SUCCESS
);
1790 if ((flags
& CFG_ADDR_V4PREFIXOK
) != 0 &&
1796 for (i
= 0; i
< 3; i
++) {
1798 if (inet_pton(AF_INET
, buf
, &in4a
) == 1) {
1799 isc_netaddr_fromin(na
, &in4a
);
1800 return (ISC_R_SUCCESS
);
1804 if ((flags
& CFG_ADDR_V6OK
) != 0 &&
1805 strlen(s
) <= 127U) {
1806 char buf
[128]; /* see lib/bind9/getaddresses.c */
1807 char *d
; /* zone delimiter */
1808 isc_uint32_t zone
= 0; /* scope zone ID */
1811 d
= strchr(buf
, '%');
1815 if (inet_pton(AF_INET6
, buf
, &in6a
) == 1) {
1817 #ifdef ISC_PLATFORM_HAVESCOPEID
1818 isc_result_t result
;
1820 result
= isc_netscope_pton(AF_INET6
,
1824 if (result
!= ISC_R_SUCCESS
)
1827 return (ISC_R_BADADDRESSFORM
);
1831 isc_netaddr_fromin6(na
, &in6a
);
1832 isc_netaddr_setzone(na
, zone
);
1833 return (ISC_R_SUCCESS
);
1837 return (ISC_R_UNEXPECTEDTOKEN
);
1841 cfg_parse_rawaddr(cfg_parser_t
*pctx
, unsigned int flags
, isc_netaddr_t
*na
) {
1842 isc_result_t result
;
1843 const char *wild
= "";
1844 const char *prefix
= "";
1846 CHECK(cfg_gettoken(pctx
, 0));
1847 result
= token_addr(pctx
, flags
, na
);
1848 if (result
== ISC_R_UNEXPECTEDTOKEN
) {
1849 if ((flags
& CFG_ADDR_WILDOK
) != 0)
1851 if ((flags
& CFG_ADDR_V4PREFIXOK
) != 0)
1852 wild
= " or IPv4 prefix";
1853 if ((flags
& CFG_ADDR_MASK
) == CFG_ADDR_V4OK
)
1854 cfg_parser_error(pctx
, CFG_LOG_NEAR
,
1855 "expected IPv4 address%s%s",
1857 else if ((flags
& CFG_ADDR_MASK
) == CFG_ADDR_V6OK
)
1858 cfg_parser_error(pctx
, CFG_LOG_NEAR
,
1859 "expected IPv6 address%s%s",
1862 cfg_parser_error(pctx
, CFG_LOG_NEAR
,
1863 "expected IP address%s%s",
1871 cfg_lookingat_netaddr(cfg_parser_t
*pctx
, unsigned int flags
) {
1872 isc_result_t result
;
1873 isc_netaddr_t na_dummy
;
1874 result
= token_addr(pctx
, flags
, &na_dummy
);
1875 return (ISC_TF(result
== ISC_R_SUCCESS
));
1879 cfg_parse_rawport(cfg_parser_t
*pctx
, unsigned int flags
, in_port_t
*port
) {
1880 isc_result_t result
;
1882 CHECK(cfg_gettoken(pctx
, ISC_LEXOPT_NUMBER
));
1884 if ((flags
& CFG_ADDR_WILDOK
) != 0 &&
1885 pctx
->token
.type
== isc_tokentype_string
&&
1886 strcmp(TOKEN_STRING(pctx
), "*") == 0) {
1888 return (ISC_R_SUCCESS
);
1890 if (pctx
->token
.type
!= isc_tokentype_number
) {
1891 cfg_parser_error(pctx
, CFG_LOG_NEAR
,
1892 "expected port number or '*'");
1893 return (ISC_R_UNEXPECTEDTOKEN
);
1895 if (pctx
->token
.value
.as_ulong
>= 65536U) {
1896 cfg_parser_error(pctx
, CFG_LOG_NEAR
,
1897 "port number out of range");
1898 return (ISC_R_UNEXPECTEDTOKEN
);
1900 *port
= (in_port_t
)(pctx
->token
.value
.as_ulong
);
1901 return (ISC_R_SUCCESS
);
1907 cfg_print_rawaddr(cfg_printer_t
*pctx
, const isc_netaddr_t
*na
) {
1908 isc_result_t result
;
1912 isc_buffer_init(&buf
, text
, sizeof(text
));
1913 result
= isc_netaddr_totext(na
, &buf
);
1914 RUNTIME_CHECK(result
== ISC_R_SUCCESS
);
1915 cfg_print_chars(pctx
, isc_buffer_base(&buf
), isc_buffer_usedlength(&buf
));
1919 cfg_parse_dscp(cfg_parser_t
*pctx
, isc_dscp_t
*dscp
) {
1920 isc_result_t result
;
1922 CHECK(cfg_gettoken(pctx
, ISC_LEXOPT_NUMBER
| ISC_LEXOPT_CNUMBER
));
1924 if (pctx
->token
.type
!= isc_tokentype_number
) {
1925 cfg_parser_error(pctx
, CFG_LOG_NEAR
,
1927 return (ISC_R_UNEXPECTEDTOKEN
);
1929 if (pctx
->token
.value
.as_ulong
> 63U) {
1930 cfg_parser_error(pctx
, CFG_LOG_NEAR
,
1931 "dscp out of range");
1932 return (ISC_R_RANGE
);
1934 *dscp
= (isc_dscp_t
)(pctx
->token
.value
.as_ulong
);
1935 return (ISC_R_SUCCESS
);
1942 static unsigned int netaddr_flags
= CFG_ADDR_V4OK
| CFG_ADDR_V6OK
;
1943 static unsigned int netaddr4_flags
= CFG_ADDR_V4OK
;
1944 static unsigned int netaddr4wild_flags
= CFG_ADDR_V4OK
| CFG_ADDR_WILDOK
;
1945 static unsigned int netaddr6_flags
= CFG_ADDR_V6OK
;
1946 static unsigned int netaddr6wild_flags
= CFG_ADDR_V6OK
| CFG_ADDR_WILDOK
;
1949 parse_netaddr(cfg_parser_t
*pctx
, const cfg_type_t
*type
, cfg_obj_t
**ret
) {
1950 isc_result_t result
;
1951 cfg_obj_t
*obj
= NULL
;
1952 isc_netaddr_t netaddr
;
1953 unsigned int flags
= *(const unsigned int *)type
->of
;
1955 CHECK(cfg_create_obj(pctx
, type
, &obj
));
1956 CHECK(cfg_parse_rawaddr(pctx
, flags
, &netaddr
));
1957 isc_sockaddr_fromnetaddr(&obj
->value
.sockaddr
, &netaddr
, 0);
1959 return (ISC_R_SUCCESS
);
1966 cfg_doc_netaddr(cfg_printer_t
*pctx
, const cfg_type_t
*type
) {
1967 const unsigned int *flagp
= type
->of
;
1969 if (*flagp
!= CFG_ADDR_V4OK
&& *flagp
!= CFG_ADDR_V6OK
)
1970 cfg_print_chars(pctx
, "( ", 2);
1971 if (*flagp
& CFG_ADDR_V4OK
) {
1972 cfg_print_cstr(pctx
, "<ipv4_address>");
1975 if (*flagp
& CFG_ADDR_V6OK
) {
1977 cfg_print_chars(pctx
, " | ", 3);
1978 cfg_print_cstr(pctx
, "<ipv6_address>");
1981 if (*flagp
& CFG_ADDR_WILDOK
) {
1983 cfg_print_chars(pctx
, " | ", 3);
1984 cfg_print_chars(pctx
, "*", 1);
1988 if (*flagp
!= CFG_ADDR_V4OK
&& *flagp
!= CFG_ADDR_V6OK
)
1989 cfg_print_chars(pctx
, " )", 2);
1992 cfg_type_t cfg_type_netaddr
= {
1993 "netaddr", parse_netaddr
, cfg_print_sockaddr
, cfg_doc_netaddr
,
1994 &cfg_rep_sockaddr
, &netaddr_flags
1997 cfg_type_t cfg_type_netaddr4
= {
1998 "netaddr4", parse_netaddr
, cfg_print_sockaddr
, cfg_doc_netaddr
,
1999 &cfg_rep_sockaddr
, &netaddr4_flags
2002 cfg_type_t cfg_type_netaddr4wild
= {
2003 "netaddr4wild", parse_netaddr
, cfg_print_sockaddr
, cfg_doc_netaddr
,
2004 &cfg_rep_sockaddr
, &netaddr4wild_flags
2007 cfg_type_t cfg_type_netaddr6
= {
2008 "netaddr6", parse_netaddr
, cfg_print_sockaddr
, cfg_doc_netaddr
,
2009 &cfg_rep_sockaddr
, &netaddr6_flags
2012 cfg_type_t cfg_type_netaddr6wild
= {
2013 "netaddr6wild", parse_netaddr
, cfg_print_sockaddr
, cfg_doc_netaddr
,
2014 &cfg_rep_sockaddr
, &netaddr6wild_flags
2020 cfg_parse_netprefix(cfg_parser_t
*pctx
, const cfg_type_t
*type
,
2023 cfg_obj_t
*obj
= NULL
;
2024 isc_result_t result
;
2025 isc_netaddr_t netaddr
;
2026 unsigned int addrlen
= 0, prefixlen
;
2029 CHECK(cfg_parse_rawaddr(pctx
, CFG_ADDR_V4OK
| CFG_ADDR_V4PREFIXOK
|
2030 CFG_ADDR_V6OK
, &netaddr
));
2031 switch (netaddr
.family
) {
2042 CHECK(cfg_peektoken(pctx
, 0));
2043 if (pctx
->token
.type
== isc_tokentype_special
&&
2044 pctx
->token
.value
.as_char
== '/') {
2045 CHECK(cfg_gettoken(pctx
, 0)); /* read "/" */
2046 CHECK(cfg_gettoken(pctx
, ISC_LEXOPT_NUMBER
));
2047 if (pctx
->token
.type
!= isc_tokentype_number
) {
2048 cfg_parser_error(pctx
, CFG_LOG_NEAR
,
2049 "expected prefix length");
2050 return (ISC_R_UNEXPECTEDTOKEN
);
2052 prefixlen
= pctx
->token
.value
.as_ulong
;
2053 if (prefixlen
> addrlen
) {
2054 cfg_parser_error(pctx
, CFG_LOG_NOPREP
,
2055 "invalid prefix length");
2056 return (ISC_R_RANGE
);
2059 prefixlen
= addrlen
;
2061 CHECK(cfg_create_obj(pctx
, &cfg_type_netprefix
, &obj
));
2062 obj
->value
.netprefix
.address
= netaddr
;
2063 obj
->value
.netprefix
.prefixlen
= prefixlen
;
2065 return (ISC_R_SUCCESS
);
2067 cfg_parser_error(pctx
, CFG_LOG_NEAR
, "expected network prefix");
2072 print_netprefix(cfg_printer_t
*pctx
, const cfg_obj_t
*obj
) {
2073 const cfg_netprefix_t
*p
= &obj
->value
.netprefix
;
2075 cfg_print_rawaddr(pctx
, &p
->address
);
2076 cfg_print_chars(pctx
, "/", 1);
2077 cfg_print_rawuint(pctx
, p
->prefixlen
);
2081 cfg_obj_isnetprefix(const cfg_obj_t
*obj
) {
2082 REQUIRE(obj
!= NULL
);
2083 return (ISC_TF(obj
->type
->rep
== &cfg_rep_netprefix
));
2087 cfg_obj_asnetprefix(const cfg_obj_t
*obj
, isc_netaddr_t
*netaddr
,
2088 unsigned int *prefixlen
)
2090 REQUIRE(obj
!= NULL
&& obj
->type
->rep
== &cfg_rep_netprefix
);
2091 REQUIRE(netaddr
!= NULL
);
2092 REQUIRE(prefixlen
!= NULL
);
2094 *netaddr
= obj
->value
.netprefix
.address
;
2095 *prefixlen
= obj
->value
.netprefix
.prefixlen
;
2098 cfg_type_t cfg_type_netprefix
= {
2099 "netprefix", cfg_parse_netprefix
, print_netprefix
, cfg_doc_terminal
,
2100 &cfg_rep_netprefix
, NULL
2104 parse_sockaddrsub(cfg_parser_t
*pctx
, const cfg_type_t
*type
,
2105 int flags
, cfg_obj_t
**ret
)
2107 isc_result_t result
;
2108 isc_netaddr_t netaddr
;
2110 isc_dscp_t dscp
= -1;
2111 cfg_obj_t
*obj
= NULL
;
2112 int have_port
= 0, have_dscp
= 0;
2114 CHECK(cfg_create_obj(pctx
, type
, &obj
));
2115 CHECK(cfg_parse_rawaddr(pctx
, flags
, &netaddr
));
2117 CHECK(cfg_peektoken(pctx
, 0));
2118 if (pctx
->token
.type
== isc_tokentype_string
) {
2119 if (strcasecmp(TOKEN_STRING(pctx
), "port") == 0) {
2120 CHECK(cfg_gettoken(pctx
, 0)); /* read "port" */
2121 CHECK(cfg_parse_rawport(pctx
, flags
, &port
));
2123 } else if ((flags
& CFG_ADDR_DSCPOK
) != 0 &&
2124 strcasecmp(TOKEN_STRING(pctx
), "dscp") == 0)
2126 CHECK(cfg_gettoken(pctx
, 0)); /* read "dscp" */
2127 CHECK(cfg_parse_dscp(pctx
, &dscp
));
2134 if (have_port
> 1) {
2135 cfg_parser_error(pctx
, 0, "expected at most one port");
2136 result
= ISC_R_UNEXPECTEDTOKEN
;
2140 if (have_dscp
> 1) {
2141 cfg_parser_error(pctx
, 0, "expected at most one dscp");
2142 result
= ISC_R_UNEXPECTEDTOKEN
;
2145 isc_sockaddr_fromnetaddr(&obj
->value
.sockaddr
, &netaddr
, port
);
2146 obj
->value
.sockaddrdscp
.dscp
= dscp
;
2148 return (ISC_R_SUCCESS
);
2155 static unsigned int sockaddr_flags
= CFG_ADDR_V4OK
| CFG_ADDR_V6OK
;
2156 cfg_type_t cfg_type_sockaddr
= {
2157 "sockaddr", cfg_parse_sockaddr
, cfg_print_sockaddr
, cfg_doc_sockaddr
,
2158 &cfg_rep_sockaddr
, &sockaddr_flags
2161 static unsigned int sockaddrdscp_flags
= CFG_ADDR_V4OK
| CFG_ADDR_V6OK
|
2163 cfg_type_t cfg_type_sockaddrdscp
= {
2164 "sockaddr", cfg_parse_sockaddr
, cfg_print_sockaddr
, cfg_doc_sockaddr
,
2165 &cfg_rep_sockaddr
, &sockaddrdscp_flags
2169 cfg_parse_sockaddr(cfg_parser_t
*pctx
, const cfg_type_t
*type
, cfg_obj_t
**ret
) {
2170 const unsigned int *flagp
= type
->of
;
2171 return (parse_sockaddrsub(pctx
, &cfg_type_sockaddr
, *flagp
, ret
));
2175 cfg_print_sockaddr(cfg_printer_t
*pctx
, const cfg_obj_t
*obj
) {
2176 isc_netaddr_t netaddr
;
2178 char buf
[ISC_NETADDR_FORMATSIZE
];
2180 isc_netaddr_fromsockaddr(&netaddr
, &obj
->value
.sockaddr
);
2181 isc_netaddr_format(&netaddr
, buf
, sizeof(buf
));
2182 cfg_print_cstr(pctx
, buf
);
2183 port
= isc_sockaddr_getport(&obj
->value
.sockaddr
);
2185 cfg_print_chars(pctx
, " port ", 6);
2186 cfg_print_rawuint(pctx
, port
);
2188 if (obj
->value
.sockaddrdscp
.dscp
!= -1) {
2189 cfg_print_chars(pctx
, " dscp ", 6);
2190 cfg_print_rawuint(pctx
, obj
->value
.sockaddrdscp
.dscp
);
2195 cfg_doc_sockaddr(cfg_printer_t
*pctx
, const cfg_type_t
*type
) {
2196 const unsigned int *flagp
= type
->of
;
2198 cfg_print_chars(pctx
, "( ", 2);
2199 if (*flagp
& CFG_ADDR_V4OK
) {
2200 cfg_print_cstr(pctx
, "<ipv4_address>");
2203 if (*flagp
& CFG_ADDR_V6OK
) {
2205 cfg_print_chars(pctx
, " | ", 3);
2206 cfg_print_cstr(pctx
, "<ipv6_address>");
2209 if (*flagp
& CFG_ADDR_WILDOK
) {
2211 cfg_print_chars(pctx
, " | ", 3);
2212 cfg_print_chars(pctx
, "*", 1);
2216 cfg_print_chars(pctx
, " ) ", 3);
2217 if (*flagp
& CFG_ADDR_WILDOK
) {
2218 cfg_print_cstr(pctx
, "[ port ( <integer> | * ) ]");
2220 cfg_print_cstr(pctx
, "[ port <integer> ]");
2222 if ((*flagp
& CFG_ADDR_DSCPOK
) != 0) {
2223 cfg_print_cstr(pctx
, " [ dscp <integer> ]");
2228 cfg_obj_issockaddr(const cfg_obj_t
*obj
) {
2229 REQUIRE(obj
!= NULL
);
2230 return (ISC_TF(obj
->type
->rep
== &cfg_rep_sockaddr
));
2233 const isc_sockaddr_t
*
2234 cfg_obj_assockaddr(const cfg_obj_t
*obj
) {
2235 REQUIRE(obj
!= NULL
&& obj
->type
->rep
== &cfg_rep_sockaddr
);
2236 return (&obj
->value
.sockaddr
);
2240 cfg_obj_getdscp(const cfg_obj_t
*obj
) {
2241 REQUIRE(obj
!= NULL
&& obj
->type
->rep
== &cfg_rep_sockaddr
);
2242 return (obj
->value
.sockaddrdscp
.dscp
);
2246 cfg_gettoken(cfg_parser_t
*pctx
, int options
) {
2247 isc_result_t result
;
2250 return (ISC_R_SUCCESS
);
2252 options
|= (ISC_LEXOPT_EOF
| ISC_LEXOPT_NOMORE
);
2255 pctx
->token
.type
= isc_tokentype_unknown
;
2256 result
= isc_lex_gettoken(pctx
->lexer
, options
, &pctx
->token
);
2257 pctx
->ungotten
= ISC_FALSE
;
2258 pctx
->line
= isc_lex_getsourceline(pctx
->lexer
);
2262 if (pctx
->token
.type
== isc_tokentype_eof
) {
2263 result
= isc_lex_close(pctx
->lexer
);
2264 INSIST(result
== ISC_R_NOMORE
||
2265 result
== ISC_R_SUCCESS
);
2267 if (isc_lex_getsourcename(pctx
->lexer
) != NULL
) {
2269 * Closed an included file, not the main file.
2272 elt
= ISC_LIST_TAIL(pctx
->open_files
->
2274 INSIST(elt
!= NULL
);
2275 ISC_LIST_UNLINK(pctx
->open_files
->
2276 value
.list
, elt
, link
);
2277 ISC_LIST_APPEND(pctx
->closed_files
->
2278 value
.list
, elt
, link
);
2281 pctx
->seen_eof
= ISC_TRUE
;
2286 /* More understandable than "ran out of space". */
2287 cfg_parser_error(pctx
, CFG_LOG_NEAR
, "token too big");
2291 cfg_parser_error(pctx
, 0, "%s",
2292 isc_result_totext(result
));
2296 cfg_parser_error(pctx
, CFG_LOG_NEAR
, "%s",
2297 isc_result_totext(result
));
2304 cfg_ungettoken(cfg_parser_t
*pctx
) {
2307 isc_lex_ungettoken(pctx
->lexer
, &pctx
->token
);
2308 pctx
->ungotten
= ISC_TRUE
;
2312 cfg_peektoken(cfg_parser_t
*pctx
, int options
) {
2313 isc_result_t result
;
2314 CHECK(cfg_gettoken(pctx
, options
));
2315 cfg_ungettoken(pctx
);
2321 * Get a string token, accepting both the quoted and the unquoted form.
2322 * Log an error if the next token is not a string.
2325 cfg_getstringtoken(cfg_parser_t
*pctx
) {
2326 isc_result_t result
;
2328 result
= cfg_gettoken(pctx
, CFG_LEXOPT_QSTRING
);
2329 if (result
!= ISC_R_SUCCESS
)
2332 if (pctx
->token
.type
!= isc_tokentype_string
&&
2333 pctx
->token
.type
!= isc_tokentype_qstring
) {
2334 cfg_parser_error(pctx
, CFG_LOG_NEAR
, "expected string");
2335 return (ISC_R_UNEXPECTEDTOKEN
);
2337 return (ISC_R_SUCCESS
);
2341 cfg_parser_error(cfg_parser_t
*pctx
, unsigned int flags
, const char *fmt
, ...) {
2343 va_start(args
, fmt
);
2344 parser_complain(pctx
, ISC_FALSE
, flags
, fmt
, args
);
2350 cfg_parser_warning(cfg_parser_t
*pctx
, unsigned int flags
, const char *fmt
, ...) {
2352 va_start(args
, fmt
);
2353 parser_complain(pctx
, ISC_TRUE
, flags
, fmt
, args
);
2358 #define MAX_LOG_TOKEN 30 /* How much of a token to quote in log messages. */
2360 static isc_boolean_t
2361 have_current_file(cfg_parser_t
*pctx
) {
2363 if (pctx
->open_files
== NULL
)
2366 elt
= ISC_LIST_TAIL(pctx
->open_files
->value
.list
);
2374 current_file(cfg_parser_t
*pctx
) {
2375 static char none
[] = "none";
2379 if (!have_current_file(pctx
))
2382 elt
= ISC_LIST_TAIL(pctx
->open_files
->value
.list
);
2383 if (elt
== NULL
) /* shouldn't be possible, but... */
2387 INSIST(fileobj
->type
== &cfg_type_qstring
);
2388 return (fileobj
->value
.string
.base
);
2392 parser_complain(cfg_parser_t
*pctx
, isc_boolean_t is_warning
,
2393 unsigned int flags
, const char *format
,
2396 char tokenbuf
[MAX_LOG_TOKEN
+ 10];
2397 static char where
[ISC_DIR_PATHMAX
+ 100];
2398 static char message
[2048];
2399 int level
= ISC_LOG_ERROR
;
2400 const char *prep
= "";
2404 level
= ISC_LOG_WARNING
;
2407 if (have_current_file(pctx
))
2408 snprintf(where
, sizeof(where
), "%s:%u: ",
2409 current_file(pctx
), pctx
->line
);
2411 len
= vsnprintf(message
, sizeof(message
), format
, args
);
2412 if (len
>= sizeof(message
))
2413 FATAL_ERROR(__FILE__
, __LINE__
,
2414 "error message would overflow");
2416 if ((flags
& (CFG_LOG_NEAR
|CFG_LOG_BEFORE
|CFG_LOG_NOPREP
)) != 0) {
2420 (void)cfg_gettoken(pctx
, 0);
2422 if (pctx
->token
.type
== isc_tokentype_eof
) {
2423 snprintf(tokenbuf
, sizeof(tokenbuf
), "end of file");
2424 } else if (pctx
->token
.type
== isc_tokentype_unknown
) {
2428 isc_lex_getlasttokentext(pctx
->lexer
,
2430 if (r
.length
> MAX_LOG_TOKEN
)
2431 snprintf(tokenbuf
, sizeof(tokenbuf
),
2432 "'%.*s...'", MAX_LOG_TOKEN
, r
.base
);
2434 snprintf(tokenbuf
, sizeof(tokenbuf
),
2435 "'%.*s'", (int)r
.length
, r
.base
);
2438 /* Choose a preposition. */
2439 if (flags
& CFG_LOG_NEAR
)
2441 else if (flags
& CFG_LOG_BEFORE
)
2448 isc_log_write(pctx
->lctx
, CAT
, MOD
, level
,
2449 "%s%s%s%s", where
, message
, prep
, tokenbuf
);
2453 cfg_obj_log(const cfg_obj_t
*obj
, isc_log_t
*lctx
, int level
,
2454 const char *fmt
, ...) {
2458 if (! isc_log_wouldlog(lctx
, level
))
2463 vsnprintf(msgbuf
, sizeof(msgbuf
), fmt
, ap
);
2464 isc_log_write(lctx
, CAT
, MOD
, level
,
2466 obj
->file
== NULL
? "<unknown file>" : obj
->file
,
2472 cfg_obj_file(const cfg_obj_t
*obj
) {
2477 cfg_obj_line(const cfg_obj_t
*obj
) {
2482 cfg_create_obj(cfg_parser_t
*pctx
, const cfg_type_t
*type
, cfg_obj_t
**ret
) {
2483 isc_result_t result
;
2486 obj
= isc_mem_get(pctx
->mctx
, sizeof(cfg_obj_t
));
2488 return (ISC_R_NOMEMORY
);
2490 obj
->file
= current_file(pctx
);
2491 obj
->line
= pctx
->line
;
2492 result
= isc_refcount_init(&obj
->references
, 1);
2493 if (result
!= ISC_R_SUCCESS
) {
2494 isc_mem_put(pctx
->mctx
, obj
, sizeof(cfg_obj_t
));
2498 return (ISC_R_SUCCESS
);
2503 map_symtabitem_destroy(char *key
, unsigned int type
,
2504 isc_symvalue_t symval
, void *userarg
)
2506 cfg_obj_t
*obj
= symval
.as_pointer
;
2507 cfg_parser_t
*pctx
= (cfg_parser_t
*)userarg
;
2512 cfg_obj_destroy(pctx
, &obj
);
2517 create_map(cfg_parser_t
*pctx
, const cfg_type_t
*type
, cfg_obj_t
**ret
) {
2518 isc_result_t result
;
2519 isc_symtab_t
*symtab
= NULL
;
2520 cfg_obj_t
*obj
= NULL
;
2522 CHECK(cfg_create_obj(pctx
, type
, &obj
));
2523 CHECK(isc_symtab_create(pctx
->mctx
, 5, /* XXX */
2524 map_symtabitem_destroy
,
2525 pctx
, ISC_FALSE
, &symtab
));
2526 obj
->value
.map
.symtab
= symtab
;
2527 obj
->value
.map
.id
= NULL
;
2530 return (ISC_R_SUCCESS
);
2534 isc_mem_put(pctx
->mctx
, obj
, sizeof(*obj
));
2539 free_map(cfg_parser_t
*pctx
, cfg_obj_t
*obj
) {
2540 CLEANUP_OBJ(obj
->value
.map
.id
);
2541 isc_symtab_destroy(&obj
->value
.map
.symtab
);
2545 cfg_obj_istype(const cfg_obj_t
*obj
, const cfg_type_t
*type
) {
2546 return (ISC_TF(obj
->type
== type
));
2550 * Destroy 'obj', a configuration object created in 'pctx'.
2553 cfg_obj_destroy(cfg_parser_t
*pctx
, cfg_obj_t
**objp
) {
2557 REQUIRE(objp
!= NULL
&& *objp
!= NULL
);
2558 REQUIRE(pctx
!= NULL
);
2562 isc_refcount_decrement(&obj
->references
, &refs
);
2564 obj
->type
->rep
->free(pctx
, obj
);
2565 isc_refcount_destroy(&obj
->references
);
2566 isc_mem_put(pctx
->mctx
, obj
, sizeof(cfg_obj_t
));
2572 cfg_obj_attach(cfg_obj_t
*src
, cfg_obj_t
**dest
) {
2573 REQUIRE(src
!= NULL
);
2574 REQUIRE(dest
!= NULL
&& *dest
== NULL
);
2575 isc_refcount_increment(&src
->references
, NULL
);
2580 free_noop(cfg_parser_t
*pctx
, cfg_obj_t
*obj
) {
2586 cfg_doc_obj(cfg_printer_t
*pctx
, const cfg_type_t
*type
) {
2587 type
->doc(pctx
, type
);
2591 cfg_doc_terminal(cfg_printer_t
*pctx
, const cfg_type_t
*type
) {
2592 cfg_print_chars(pctx
, "<", 1);
2593 cfg_print_cstr(pctx
, type
->name
);
2594 cfg_print_chars(pctx
, ">", 1);
2598 cfg_print_grammar(const cfg_type_t
*type
,
2599 void (*f
)(void *closure
, const char *text
, int textlen
),
2604 pctx
.closure
= closure
;
2607 cfg_doc_obj(&pctx
, type
);