parser.c revision 135446
1/* 2 * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 2000-2003 Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 * PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18/* $Id: parser.c,v 1.70.2.20.2.18 2004/05/15 03:46:13 jinmei Exp $ */ 19 20#include <config.h> 21 22#include <isc/buffer.h> 23#include <isc/dir.h> 24#include <isc/formatcheck.h> 25#include <isc/lex.h> 26#include <isc/log.h> 27#include <isc/mem.h> 28#include <isc/net.h> 29#include <isc/netaddr.h> 30#include <isc/print.h> 31#include <isc/string.h> 32#include <isc/sockaddr.h> 33#include <isc/netscope.h> 34#include <isc/util.h> 35#include <isc/symtab.h> 36 37#include <isccfg/cfg.h> 38#include <isccfg/grammar.h> 39#include <isccfg/log.h> 40 41/* Shorthand */ 42#define CAT CFG_LOGCATEGORY_CONFIG 43#define MOD CFG_LOGMODULE_PARSER 44 45#define MAP_SYM 1 /* Unique type for isc_symtab */ 46 47#define TOKEN_STRING(pctx) (pctx->token.value.as_textregion.base) 48 49/* Check a return value. */ 50#define CHECK(op) \ 51 do { result = (op); \ 52 if (result != ISC_R_SUCCESS) goto cleanup; \ 53 } while (0) 54 55/* Clean up a configuration object if non-NULL. */ 56#define CLEANUP_OBJ(obj) \ 57 do { if ((obj) != NULL) cfg_obj_destroy(pctx, &(obj)); } while (0) 58 59 60/* 61 * Forward declarations of static functions. 62 */ 63 64static void 65free_tuple(cfg_parser_t *pctx, cfg_obj_t *obj); 66 67static isc_result_t 68parse_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret); 69 70static void 71print_list(cfg_printer_t *pctx, cfg_obj_t *obj); 72 73static void 74free_list(cfg_parser_t *pctx, cfg_obj_t *obj); 75 76static isc_result_t 77create_listelt(cfg_parser_t *pctx, cfg_listelt_t **eltp); 78 79static isc_result_t 80create_string(cfg_parser_t *pctx, const char *contents, const cfg_type_t *type, 81 cfg_obj_t **ret); 82 83static void 84free_string(cfg_parser_t *pctx, cfg_obj_t *obj); 85 86static isc_result_t 87create_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **objp); 88 89static void 90free_map(cfg_parser_t *pctx, cfg_obj_t *obj); 91 92static isc_result_t 93parse_symtab_elt(cfg_parser_t *pctx, const char *name, 94 cfg_type_t *elttype, isc_symtab_t *symtab, 95 isc_boolean_t callback); 96 97static void 98free_noop(cfg_parser_t *pctx, cfg_obj_t *obj); 99 100static isc_result_t 101cfg_getstringtoken(cfg_parser_t *pctx); 102 103static void 104parser_complain(cfg_parser_t *pctx, isc_boolean_t is_warning, 105 unsigned int flags, const char *format, va_list args); 106 107/* 108 * Data representations. These correspond to members of the 109 * "value" union in struct cfg_obj (except "void", which does 110 * not need a union member). 111 */ 112 113cfg_rep_t cfg_rep_uint32 = { "uint32", free_noop }; 114cfg_rep_t cfg_rep_uint64 = { "uint64", free_noop }; 115cfg_rep_t cfg_rep_string = { "string", free_string }; 116cfg_rep_t cfg_rep_boolean = { "boolean", free_noop }; 117cfg_rep_t cfg_rep_map = { "map", free_map }; 118cfg_rep_t cfg_rep_list = { "list", free_list }; 119cfg_rep_t cfg_rep_tuple = { "tuple", free_tuple }; 120cfg_rep_t cfg_rep_sockaddr = { "sockaddr", free_noop }; 121cfg_rep_t cfg_rep_netprefix = { "netprefix", free_noop }; 122cfg_rep_t cfg_rep_void = { "void", free_noop }; 123 124/* 125 * Configuration type definitions. 126 */ 127 128/* 129 * An implicit list. These are formed by clauses that occur multiple times. 130 */ 131static cfg_type_t cfg_type_implicitlist = { 132 "implicitlist", NULL, print_list, NULL, &cfg_rep_list, NULL }; 133 134/* Functions. */ 135 136void 137cfg_print_obj(cfg_printer_t *pctx, cfg_obj_t *obj) { 138 obj->type->print(pctx, obj); 139} 140 141void 142cfg_print_chars(cfg_printer_t *pctx, const char *text, int len) { 143 pctx->f(pctx->closure, text, len); 144} 145 146static void 147print_open(cfg_printer_t *pctx) { 148 cfg_print_chars(pctx, "{\n", 2); 149 pctx->indent++; 150} 151 152static void 153print_indent(cfg_printer_t *pctx) { 154 int indent = pctx->indent; 155 while (indent > 0) { 156 cfg_print_chars(pctx, "\t", 1); 157 indent--; 158 } 159} 160 161static void 162print_close(cfg_printer_t *pctx) { 163 pctx->indent--; 164 print_indent(pctx); 165 cfg_print_chars(pctx, "}", 1); 166} 167 168isc_result_t 169cfg_parse_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 170 isc_result_t result; 171 INSIST(ret != NULL && *ret == NULL); 172 result = type->parse(pctx, type, ret); 173 if (result != ISC_R_SUCCESS) 174 return (result); 175 INSIST(*ret != NULL); 176 return (ISC_R_SUCCESS); 177} 178 179void 180cfg_print(cfg_obj_t *obj, 181 void (*f)(void *closure, const char *text, int textlen), 182 void *closure) 183{ 184 cfg_printer_t pctx; 185 pctx.f = f; 186 pctx.closure = closure; 187 pctx.indent = 0; 188 obj->type->print(&pctx, obj); 189} 190 191 192/* Tuples. */ 193 194isc_result_t 195cfg_create_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 196 isc_result_t result; 197 const cfg_tuplefielddef_t *fields = type->of; 198 const cfg_tuplefielddef_t *f; 199 cfg_obj_t *obj = NULL; 200 unsigned int nfields = 0; 201 int i; 202 203 for (f = fields; f->name != NULL; f++) 204 nfields++; 205 206 CHECK(cfg_create_obj(pctx, type, &obj)); 207 obj->value.tuple = isc_mem_get(pctx->mctx, 208 nfields * sizeof(cfg_obj_t *)); 209 if (obj->value.tuple == NULL) { 210 result = ISC_R_NOMEMORY; 211 goto cleanup; 212 } 213 for (f = fields, i = 0; f->name != NULL; f++, i++) 214 obj->value.tuple[i] = NULL; 215 *ret = obj; 216 return (ISC_R_SUCCESS); 217 218 cleanup: 219 if (obj != NULL) 220 isc_mem_put(pctx->mctx, obj, sizeof(*obj)); 221 return (result); 222} 223 224isc_result_t 225cfg_parse_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) 226{ 227 isc_result_t result; 228 const cfg_tuplefielddef_t *fields = type->of; 229 const cfg_tuplefielddef_t *f; 230 cfg_obj_t *obj = NULL; 231 unsigned int i; 232 233 CHECK(cfg_create_tuple(pctx, type, &obj)); 234 for (f = fields, i = 0; f->name != NULL; f++, i++) 235 CHECK(cfg_parse_obj(pctx, f->type, &obj->value.tuple[i])); 236 237 *ret = obj; 238 return (ISC_R_SUCCESS); 239 240 cleanup: 241 CLEANUP_OBJ(obj); 242 return (result); 243} 244 245void 246cfg_print_tuple(cfg_printer_t *pctx, cfg_obj_t *obj) { 247 unsigned int i; 248 const cfg_tuplefielddef_t *fields = obj->type->of; 249 const cfg_tuplefielddef_t *f; 250 isc_boolean_t need_space = ISC_FALSE; 251 252 for (f = fields, i = 0; f->name != NULL; f++, i++) { 253 cfg_obj_t *fieldobj = obj->value.tuple[i]; 254 if (need_space) 255 cfg_print_chars(pctx, " ", 1); 256 cfg_print_obj(pctx, fieldobj); 257 need_space = ISC_TF(fieldobj->type->print != cfg_print_void); 258 } 259} 260 261void 262cfg_doc_tuple(cfg_printer_t *pctx, const cfg_type_t *type) { 263 const cfg_tuplefielddef_t *fields = type->of; 264 const cfg_tuplefielddef_t *f; 265 isc_boolean_t need_space = ISC_FALSE; 266 267 for (f = fields; f->name != NULL; f++) { 268 if (need_space) 269 cfg_print_chars(pctx, " ", 1); 270 cfg_doc_obj(pctx, f->type); 271 need_space = ISC_TF(f->type->print != cfg_print_void); 272 } 273} 274 275static void 276free_tuple(cfg_parser_t *pctx, cfg_obj_t *obj) { 277 unsigned int i; 278 const cfg_tuplefielddef_t *fields = obj->type->of; 279 const cfg_tuplefielddef_t *f; 280 unsigned int nfields = 0; 281 282 if (obj->value.tuple == NULL) 283 return; 284 285 for (f = fields, i = 0; f->name != NULL; f++, i++) { 286 CLEANUP_OBJ(obj->value.tuple[i]); 287 nfields++; 288 } 289 isc_mem_put(pctx->mctx, obj->value.tuple, 290 nfields * sizeof(cfg_obj_t *)); 291} 292 293isc_boolean_t 294cfg_obj_istuple(cfg_obj_t *obj) { 295 REQUIRE(obj != NULL); 296 return (ISC_TF(obj->type->rep == &cfg_rep_tuple)); 297} 298 299cfg_obj_t * 300cfg_tuple_get(cfg_obj_t *tupleobj, const char* name) { 301 unsigned int i; 302 const cfg_tuplefielddef_t *fields; 303 const cfg_tuplefielddef_t *f; 304 305 REQUIRE(tupleobj != NULL && tupleobj->type->rep == &cfg_rep_tuple); 306 307 fields = tupleobj->type->of; 308 for (f = fields, i = 0; f->name != NULL; f++, i++) { 309 if (strcmp(f->name, name) == 0) 310 return (tupleobj->value.tuple[i]); 311 } 312 INSIST(0); 313 return (NULL); 314} 315 316isc_result_t 317cfg_parse_special(cfg_parser_t *pctx, int special) { 318 isc_result_t result; 319 CHECK(cfg_gettoken(pctx, 0)); 320 if (pctx->token.type == isc_tokentype_special && 321 pctx->token.value.as_char == special) 322 return (ISC_R_SUCCESS); 323 324 cfg_parser_error(pctx, CFG_LOG_NEAR, "'%c' expected", special); 325 return (ISC_R_UNEXPECTEDTOKEN); 326 cleanup: 327 return (result); 328} 329 330/* 331 * Parse a required semicolon. If it is not there, log 332 * an error and increment the error count but continue 333 * parsing. Since the next token is pushed back, 334 * care must be taken to make sure it is eventually 335 * consumed or an infinite loop may result. 336 */ 337static isc_result_t 338parse_semicolon(cfg_parser_t *pctx) { 339 isc_result_t result; 340 CHECK(cfg_gettoken(pctx, 0)); 341 if (pctx->token.type == isc_tokentype_special && 342 pctx->token.value.as_char == ';') 343 return (ISC_R_SUCCESS); 344 345 cfg_parser_error(pctx, CFG_LOG_BEFORE, "missing ';'"); 346 cfg_ungettoken(pctx); 347 cleanup: 348 return (result); 349} 350 351/* 352 * Parse EOF, logging and returning an error if not there. 353 */ 354static isc_result_t 355parse_eof(cfg_parser_t *pctx) { 356 isc_result_t result; 357 CHECK(cfg_gettoken(pctx, 0)); 358 359 if (pctx->token.type == isc_tokentype_eof) 360 return (ISC_R_SUCCESS); 361 362 cfg_parser_error(pctx, CFG_LOG_NEAR, "syntax error"); 363 return (ISC_R_UNEXPECTEDTOKEN); 364 cleanup: 365 return (result); 366} 367 368/* A list of files, used internally for pctx->files. */ 369 370static cfg_type_t cfg_type_filelist = { 371 "filelist", NULL, print_list, NULL, &cfg_rep_list, 372 &cfg_type_qstring 373}; 374 375isc_result_t 376cfg_parser_create(isc_mem_t *mctx, isc_log_t *lctx, cfg_parser_t **ret) { 377 isc_result_t result; 378 cfg_parser_t *pctx; 379 isc_lexspecials_t specials; 380 381 REQUIRE(mctx != NULL); 382 REQUIRE(ret != NULL && *ret == NULL); 383 384 pctx = isc_mem_get(mctx, sizeof(*pctx)); 385 if (pctx == NULL) 386 return (ISC_R_NOMEMORY); 387 388 pctx->mctx = mctx; 389 pctx->lctx = lctx; 390 pctx->lexer = NULL; 391 pctx->seen_eof = ISC_FALSE; 392 pctx->ungotten = ISC_FALSE; 393 pctx->errors = 0; 394 pctx->warnings = 0; 395 pctx->open_files = NULL; 396 pctx->closed_files = NULL; 397 pctx->line = 0; 398 pctx->callback = NULL; 399 pctx->callbackarg = NULL; 400 pctx->token.type = isc_tokentype_unknown; 401 402 memset(specials, 0, sizeof(specials)); 403 specials['{'] = 1; 404 specials['}'] = 1; 405 specials[';'] = 1; 406 specials['/'] = 1; 407 specials['"'] = 1; 408 specials['!'] = 1; 409 410 CHECK(isc_lex_create(pctx->mctx, 1024, &pctx->lexer)); 411 412 isc_lex_setspecials(pctx->lexer, specials); 413 isc_lex_setcomments(pctx->lexer, (ISC_LEXCOMMENT_C | 414 ISC_LEXCOMMENT_CPLUSPLUS | 415 ISC_LEXCOMMENT_SHELL)); 416 417 CHECK(cfg_create_list(pctx, &cfg_type_filelist, &pctx->open_files)); 418 CHECK(cfg_create_list(pctx, &cfg_type_filelist, &pctx->closed_files)); 419 420 *ret = pctx; 421 return (ISC_R_SUCCESS); 422 423 cleanup: 424 if (pctx->lexer != NULL) 425 isc_lex_destroy(&pctx->lexer); 426 CLEANUP_OBJ(pctx->open_files); 427 CLEANUP_OBJ(pctx->closed_files); 428 isc_mem_put(mctx, pctx, sizeof(*pctx)); 429 return (result); 430} 431 432static isc_result_t 433parser_openfile(cfg_parser_t *pctx, const char *filename) { 434 isc_result_t result; 435 cfg_listelt_t *elt = NULL; 436 cfg_obj_t *stringobj = NULL; 437 438 result = isc_lex_openfile(pctx->lexer, filename); 439 if (result != ISC_R_SUCCESS) { 440 cfg_parser_error(pctx, 0, "open: %s: %s", 441 filename, isc_result_totext(result)); 442 goto cleanup; 443 } 444 445 CHECK(create_string(pctx, filename, &cfg_type_qstring, &stringobj)); 446 CHECK(create_listelt(pctx, &elt)); 447 elt->obj = stringobj; 448 ISC_LIST_APPEND(pctx->open_files->value.list, elt, link); 449 450 return (ISC_R_SUCCESS); 451 cleanup: 452 CLEANUP_OBJ(stringobj); 453 return (result); 454} 455 456void 457cfg_parser_setcallback(cfg_parser_t *pctx, 458 cfg_parsecallback_t callback, 459 void *arg) 460{ 461 pctx->callback = callback; 462 pctx->callbackarg = arg; 463} 464 465/* 466 * Parse a configuration using a pctx where a lexer has already 467 * been set up with a source. 468 */ 469static isc_result_t 470parse2(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 471 isc_result_t result; 472 cfg_obj_t *obj = NULL; 473 474 result = cfg_parse_obj(pctx, type, &obj); 475 476 if (pctx->errors != 0) { 477 /* Errors have been logged. */ 478 if (result == ISC_R_SUCCESS) 479 result = ISC_R_FAILURE; 480 goto cleanup; 481 } 482 483 if (result != ISC_R_SUCCESS) { 484 /* Parsing failed but no errors have been logged. */ 485 cfg_parser_error(pctx, 0, "parsing failed"); 486 goto cleanup; 487 } 488 489 CHECK(parse_eof(pctx)); 490 491 *ret = obj; 492 return (ISC_R_SUCCESS); 493 494 cleanup: 495 CLEANUP_OBJ(obj); 496 return (result); 497} 498 499isc_result_t 500cfg_parse_file(cfg_parser_t *pctx, const char *filename, 501 const cfg_type_t *type, cfg_obj_t **ret) 502{ 503 isc_result_t result; 504 505 REQUIRE(filename != NULL); 506 507 CHECK(parser_openfile(pctx, filename)); 508 CHECK(parse2(pctx, type, ret)); 509 cleanup: 510 return (result); 511} 512 513 514isc_result_t 515cfg_parse_buffer(cfg_parser_t *pctx, isc_buffer_t *buffer, 516 const cfg_type_t *type, cfg_obj_t **ret) 517{ 518 isc_result_t result; 519 REQUIRE(buffer != NULL); 520 CHECK(isc_lex_openbuffer(pctx->lexer, buffer)); 521 CHECK(parse2(pctx, type, ret)); 522 cleanup: 523 return (result); 524} 525 526void 527cfg_parser_destroy(cfg_parser_t **pctxp) { 528 cfg_parser_t *pctx = *pctxp; 529 isc_lex_destroy(&pctx->lexer); 530 /* 531 * Cleaning up open_files does not 532 * close the files; that was already done 533 * by closing the lexer. 534 */ 535 CLEANUP_OBJ(pctx->open_files); 536 CLEANUP_OBJ(pctx->closed_files); 537 isc_mem_put(pctx->mctx, pctx, sizeof(*pctx)); 538 *pctxp = NULL; 539} 540 541/* 542 * void 543 */ 544isc_result_t 545cfg_parse_void(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 546 UNUSED(type); 547 return (cfg_create_obj(pctx, &cfg_type_void, ret)); 548} 549 550void 551cfg_print_void(cfg_printer_t *pctx, cfg_obj_t *obj) { 552 UNUSED(pctx); 553 UNUSED(obj); 554} 555 556void 557cfg_doc_void(cfg_printer_t *pctx, const cfg_type_t *type) { 558 UNUSED(pctx); 559 UNUSED(type); 560} 561 562isc_boolean_t 563cfg_obj_isvoid(cfg_obj_t *obj) { 564 REQUIRE(obj != NULL); 565 return (ISC_TF(obj->type->rep == &cfg_rep_void)); 566} 567 568cfg_type_t cfg_type_void = { 569 "void", cfg_parse_void, cfg_print_void, cfg_doc_void, &cfg_rep_void, 570 NULL }; 571 572 573/* 574 * uint32 575 */ 576isc_result_t 577cfg_parse_uint32(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 578 isc_result_t result; 579 cfg_obj_t *obj = NULL; 580 UNUSED(type); 581 582 CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER)); 583 if (pctx->token.type != isc_tokentype_number) { 584 cfg_parser_error(pctx, CFG_LOG_NEAR, "expected number"); 585 return (ISC_R_UNEXPECTEDTOKEN); 586 } 587 588 CHECK(cfg_create_obj(pctx, &cfg_type_uint32, &obj)); 589 590 obj->value.uint32 = pctx->token.value.as_ulong; 591 *ret = obj; 592 cleanup: 593 return (result); 594} 595 596void 597cfg_print_cstr(cfg_printer_t *pctx, const char *s) { 598 cfg_print_chars(pctx, s, strlen(s)); 599} 600 601void 602cfg_print_rawuint(cfg_printer_t *pctx, unsigned int u) { 603 char buf[32]; 604 snprintf(buf, sizeof(buf), "%u", u); 605 cfg_print_cstr(pctx, buf); 606} 607 608void 609cfg_print_uint32(cfg_printer_t *pctx, cfg_obj_t *obj) { 610 cfg_print_rawuint(pctx, obj->value.uint32); 611} 612 613isc_boolean_t 614cfg_obj_isuint32(cfg_obj_t *obj) { 615 REQUIRE(obj != NULL); 616 return (ISC_TF(obj->type->rep == &cfg_rep_uint32)); 617} 618 619isc_uint32_t 620cfg_obj_asuint32(cfg_obj_t *obj) { 621 REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_uint32); 622 return (obj->value.uint32); 623} 624 625cfg_type_t cfg_type_uint32 = { 626 "integer", cfg_parse_uint32, cfg_print_uint32, cfg_doc_terminal, 627 &cfg_rep_uint32, NULL 628}; 629 630 631/* 632 * uint64 633 */ 634isc_boolean_t 635cfg_obj_isuint64(cfg_obj_t *obj) { 636 REQUIRE(obj != NULL); 637 return (ISC_TF(obj->type->rep == &cfg_rep_uint64)); 638} 639 640isc_uint64_t 641cfg_obj_asuint64(cfg_obj_t *obj) { 642 REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_uint64); 643 return (obj->value.uint64); 644} 645 646void 647cfg_print_uint64(cfg_printer_t *pctx, cfg_obj_t *obj) { 648 char buf[32]; 649 snprintf(buf, sizeof(buf), "%" ISC_PRINT_QUADFORMAT "u", 650 obj->value.uint64); 651 cfg_print_cstr(pctx, buf); 652} 653 654cfg_type_t cfg_type_uint64 = { 655 "64_bit_integer", NULL, cfg_print_uint64, cfg_doc_terminal, 656 &cfg_rep_uint64, NULL 657}; 658 659/* 660 * qstring (quoted string), ustring (unquoted string), astring 661 * (any string) 662 */ 663 664/* Create a string object from a null-terminated C string. */ 665static isc_result_t 666create_string(cfg_parser_t *pctx, const char *contents, const cfg_type_t *type, 667 cfg_obj_t **ret) 668{ 669 isc_result_t result; 670 cfg_obj_t *obj = NULL; 671 int len; 672 673 CHECK(cfg_create_obj(pctx, type, &obj)); 674 len = strlen(contents); 675 obj->value.string.length = len; 676 obj->value.string.base = isc_mem_get(pctx->mctx, len + 1); 677 if (obj->value.string.base == 0) { 678 isc_mem_put(pctx->mctx, obj, sizeof(*obj)); 679 return (ISC_R_NOMEMORY); 680 } 681 memcpy(obj->value.string.base, contents, len); 682 obj->value.string.base[len] = '\0'; 683 684 *ret = obj; 685 cleanup: 686 return (result); 687} 688 689isc_result_t 690cfg_parse_qstring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 691 isc_result_t result; 692 UNUSED(type); 693 694 CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING)); 695 if (pctx->token.type != isc_tokentype_qstring) { 696 cfg_parser_error(pctx, CFG_LOG_NEAR, "expected quoted string"); 697 return (ISC_R_UNEXPECTEDTOKEN); 698 } 699 return (create_string(pctx, 700 TOKEN_STRING(pctx), 701 &cfg_type_qstring, 702 ret)); 703 cleanup: 704 return (result); 705} 706 707static isc_result_t 708parse_ustring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 709 isc_result_t result; 710 UNUSED(type); 711 712 CHECK(cfg_gettoken(pctx, 0)); 713 if (pctx->token.type != isc_tokentype_string) { 714 cfg_parser_error(pctx, CFG_LOG_NEAR, "expected unquoted string"); 715 return (ISC_R_UNEXPECTEDTOKEN); 716 } 717 return (create_string(pctx, 718 TOKEN_STRING(pctx), 719 &cfg_type_ustring, 720 ret)); 721 cleanup: 722 return (result); 723} 724 725isc_result_t 726cfg_parse_astring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 727 isc_result_t result; 728 UNUSED(type); 729 730 CHECK(cfg_getstringtoken(pctx)); 731 return (create_string(pctx, 732 TOKEN_STRING(pctx), 733 &cfg_type_qstring, 734 ret)); 735 cleanup: 736 return (result); 737} 738 739isc_boolean_t 740cfg_is_enum(const char *s, const char *const *enums) { 741 const char * const *p; 742 for (p = enums; *p != NULL; p++) { 743 if (strcasecmp(*p, s) == 0) 744 return (ISC_TRUE); 745 } 746 return (ISC_FALSE); 747} 748 749static isc_result_t 750check_enum(cfg_parser_t *pctx, cfg_obj_t *obj, const char *const *enums) { 751 const char *s = obj->value.string.base; 752 if (cfg_is_enum(s, enums)) 753 return (ISC_R_SUCCESS); 754 cfg_parser_error(pctx, 0, "'%s' unexpected", s); 755 return (ISC_R_UNEXPECTEDTOKEN); 756} 757 758isc_result_t 759cfg_parse_enum(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 760 isc_result_t result; 761 cfg_obj_t *obj = NULL; 762 CHECK(parse_ustring(pctx, NULL, &obj)); 763 CHECK(check_enum(pctx, obj, type->of)); 764 *ret = obj; 765 return (ISC_R_SUCCESS); 766 cleanup: 767 CLEANUP_OBJ(obj); 768 return (result); 769} 770 771void 772cfg_doc_enum(cfg_printer_t *pctx, const cfg_type_t *type) { 773 const char * const *p; 774 cfg_print_chars(pctx, "( ", 2); 775 for (p = type->of; *p != NULL; p++) { 776 cfg_print_cstr(pctx, *p); 777 if (p[1] != NULL) 778 cfg_print_chars(pctx, " | ", 3); 779 } 780 cfg_print_chars(pctx, " )", 2); 781} 782 783void 784cfg_print_ustring(cfg_printer_t *pctx, cfg_obj_t *obj) { 785 cfg_print_chars(pctx, obj->value.string.base, obj->value.string.length); 786} 787 788static void 789print_qstring(cfg_printer_t *pctx, cfg_obj_t *obj) { 790 cfg_print_chars(pctx, "\"", 1); 791 cfg_print_ustring(pctx, obj); 792 cfg_print_chars(pctx, "\"", 1); 793} 794 795static void 796free_string(cfg_parser_t *pctx, cfg_obj_t *obj) { 797 isc_mem_put(pctx->mctx, obj->value.string.base, 798 obj->value.string.length + 1); 799} 800 801isc_boolean_t 802cfg_obj_isstring(cfg_obj_t *obj) { 803 REQUIRE(obj != NULL); 804 return (ISC_TF(obj->type->rep == &cfg_rep_string)); 805} 806 807char * 808cfg_obj_asstring(cfg_obj_t *obj) { 809 REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_string); 810 return (obj->value.string.base); 811} 812 813/* Quoted string only */ 814cfg_type_t cfg_type_qstring = { 815 "quoted_string", cfg_parse_qstring, print_qstring, cfg_doc_terminal, 816 &cfg_rep_string, NULL 817}; 818 819/* Unquoted string only */ 820cfg_type_t cfg_type_ustring = { 821 "string", parse_ustring, cfg_print_ustring, cfg_doc_terminal, 822 &cfg_rep_string, NULL 823}; 824 825/* Any string (quoted or unquoted); printed with quotes */ 826cfg_type_t cfg_type_astring = { 827 "string", cfg_parse_astring, print_qstring, cfg_doc_terminal, 828 &cfg_rep_string, NULL 829}; 830 831/* 832 * Booleans 833 */ 834 835isc_boolean_t 836cfg_obj_isboolean(cfg_obj_t *obj) { 837 REQUIRE(obj != NULL); 838 return (ISC_TF(obj->type->rep == &cfg_rep_boolean)); 839} 840 841isc_boolean_t 842cfg_obj_asboolean(cfg_obj_t *obj) { 843 REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_boolean); 844 return (obj->value.boolean); 845} 846 847static isc_result_t 848parse_boolean(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) 849{ 850 isc_result_t result; 851 isc_boolean_t value; 852 cfg_obj_t *obj = NULL; 853 UNUSED(type); 854 855 result = cfg_gettoken(pctx, 0); 856 if (result != ISC_R_SUCCESS) 857 return (result); 858 859 if (pctx->token.type != isc_tokentype_string) 860 goto bad_boolean; 861 862 if ((strcasecmp(TOKEN_STRING(pctx), "true") == 0) || 863 (strcasecmp(TOKEN_STRING(pctx), "yes") == 0) || 864 (strcmp(TOKEN_STRING(pctx), "1") == 0)) { 865 value = ISC_TRUE; 866 } else if ((strcasecmp(TOKEN_STRING(pctx), "false") == 0) || 867 (strcasecmp(TOKEN_STRING(pctx), "no") == 0) || 868 (strcmp(TOKEN_STRING(pctx), "0") == 0)) { 869 value = ISC_FALSE; 870 } else { 871 goto bad_boolean; 872 } 873 874 CHECK(cfg_create_obj(pctx, &cfg_type_boolean, &obj)); 875 obj->value.boolean = value; 876 *ret = obj; 877 return (result); 878 879 bad_boolean: 880 cfg_parser_error(pctx, CFG_LOG_NEAR, "boolean expected"); 881 return (ISC_R_UNEXPECTEDTOKEN); 882 883 cleanup: 884 return (result); 885} 886 887static void 888print_boolean(cfg_printer_t *pctx, cfg_obj_t *obj) { 889 if (obj->value.boolean) 890 cfg_print_chars(pctx, "yes", 3); 891 else 892 cfg_print_chars(pctx, "no", 2); 893} 894 895cfg_type_t cfg_type_boolean = { 896 "boolean", parse_boolean, print_boolean, cfg_doc_terminal, 897 &cfg_rep_boolean, NULL 898}; 899 900/* 901 * Lists. 902 */ 903 904isc_result_t 905cfg_create_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **obj) { 906 isc_result_t result; 907 CHECK(cfg_create_obj(pctx, type, obj)); 908 ISC_LIST_INIT((*obj)->value.list); 909 cleanup: 910 return (result); 911} 912 913static isc_result_t 914create_listelt(cfg_parser_t *pctx, cfg_listelt_t **eltp) { 915 cfg_listelt_t *elt; 916 elt = isc_mem_get(pctx->mctx, sizeof(*elt)); 917 if (elt == NULL) 918 return (ISC_R_NOMEMORY); 919 elt->obj = NULL; 920 ISC_LINK_INIT(elt, link); 921 *eltp = elt; 922 return (ISC_R_SUCCESS); 923} 924 925static void 926free_list_elt(cfg_parser_t *pctx, cfg_listelt_t *elt) { 927 cfg_obj_destroy(pctx, &elt->obj); 928 isc_mem_put(pctx->mctx, elt, sizeof(*elt)); 929} 930 931static void 932free_list(cfg_parser_t *pctx, cfg_obj_t *obj) { 933 cfg_listelt_t *elt, *next; 934 for (elt = ISC_LIST_HEAD(obj->value.list); 935 elt != NULL; 936 elt = next) 937 { 938 next = ISC_LIST_NEXT(elt, link); 939 free_list_elt(pctx, elt); 940 } 941} 942 943isc_result_t 944cfg_parse_listelt(cfg_parser_t *pctx, const cfg_type_t *elttype, 945 cfg_listelt_t **ret) 946{ 947 isc_result_t result; 948 cfg_listelt_t *elt = NULL; 949 cfg_obj_t *value = NULL; 950 951 CHECK(create_listelt(pctx, &elt)); 952 953 result = cfg_parse_obj(pctx, elttype, &value); 954 if (result != ISC_R_SUCCESS) 955 goto cleanup; 956 957 elt->obj = value; 958 959 *ret = elt; 960 return (ISC_R_SUCCESS); 961 962 cleanup: 963 isc_mem_put(pctx->mctx, elt, sizeof(*elt)); 964 return (result); 965} 966 967/* 968 * Parse a homogeneous list whose elements are of type 'elttype' 969 * and where each element is terminated by a semicolon. 970 */ 971static isc_result_t 972parse_list(cfg_parser_t *pctx, const cfg_type_t *listtype, cfg_obj_t **ret) 973{ 974 cfg_obj_t *listobj = NULL; 975 const cfg_type_t *listof = listtype->of; 976 isc_result_t result; 977 cfg_listelt_t *elt = NULL; 978 979 CHECK(cfg_create_list(pctx, listtype, &listobj)); 980 981 for (;;) { 982 CHECK(cfg_peektoken(pctx, 0)); 983 if (pctx->token.type == isc_tokentype_special && 984 pctx->token.value.as_char == /*{*/ '}') 985 break; 986 CHECK(cfg_parse_listelt(pctx, listof, &elt)); 987 CHECK(parse_semicolon(pctx)); 988 ISC_LIST_APPEND(listobj->value.list, elt, link); 989 elt = NULL; 990 } 991 *ret = listobj; 992 return (ISC_R_SUCCESS); 993 994 cleanup: 995 if (elt != NULL) 996 free_list_elt(pctx, elt); 997 CLEANUP_OBJ(listobj); 998 return (result); 999} 1000 1001static void 1002print_list(cfg_printer_t *pctx, cfg_obj_t *obj) { 1003 cfg_list_t *list = &obj->value.list; 1004 cfg_listelt_t *elt; 1005 1006 for (elt = ISC_LIST_HEAD(*list); 1007 elt != NULL; 1008 elt = ISC_LIST_NEXT(elt, link)) { 1009 print_indent(pctx); 1010 cfg_print_obj(pctx, elt->obj); 1011 cfg_print_chars(pctx, ";\n", 2); 1012 } 1013} 1014 1015isc_result_t 1016cfg_parse_bracketed_list(cfg_parser_t *pctx, const cfg_type_t *type, 1017 cfg_obj_t **ret) 1018{ 1019 isc_result_t result; 1020 CHECK(cfg_parse_special(pctx, '{')); 1021 CHECK(parse_list(pctx, type, ret)); 1022 CHECK(cfg_parse_special(pctx, '}')); 1023 cleanup: 1024 return (result); 1025} 1026 1027void 1028cfg_print_bracketed_list(cfg_printer_t *pctx, cfg_obj_t *obj) { 1029 print_open(pctx); 1030 print_list(pctx, obj); 1031 print_close(pctx); 1032} 1033 1034void 1035cfg_doc_bracketed_list(cfg_printer_t *pctx, const cfg_type_t *type) { 1036 cfg_print_chars(pctx, "{ ", 2); 1037 cfg_doc_obj(pctx, type->of); 1038 cfg_print_chars(pctx, "; ... }", 7); 1039} 1040 1041/* 1042 * Parse a homogeneous list whose elements are of type 'elttype' 1043 * and where elements are separated by space. The list ends 1044 * before the first semicolon. 1045 */ 1046isc_result_t 1047cfg_parse_spacelist(cfg_parser_t *pctx, const cfg_type_t *listtype, 1048 cfg_obj_t **ret) 1049{ 1050 cfg_obj_t *listobj = NULL; 1051 const cfg_type_t *listof = listtype->of; 1052 isc_result_t result; 1053 1054 CHECK(cfg_create_list(pctx, listtype, &listobj)); 1055 1056 for (;;) { 1057 cfg_listelt_t *elt = NULL; 1058 1059 CHECK(cfg_peektoken(pctx, 0)); 1060 if (pctx->token.type == isc_tokentype_special && 1061 pctx->token.value.as_char == ';') 1062 break; 1063 CHECK(cfg_parse_listelt(pctx, listof, &elt)); 1064 ISC_LIST_APPEND(listobj->value.list, elt, link); 1065 } 1066 *ret = listobj; 1067 return (ISC_R_SUCCESS); 1068 1069 cleanup: 1070 CLEANUP_OBJ(listobj); 1071 return (result); 1072} 1073 1074void 1075cfg_print_spacelist(cfg_printer_t *pctx, cfg_obj_t *obj) { 1076 cfg_list_t *list = &obj->value.list; 1077 cfg_listelt_t *elt; 1078 1079 for (elt = ISC_LIST_HEAD(*list); 1080 elt != NULL; 1081 elt = ISC_LIST_NEXT(elt, link)) { 1082 cfg_print_obj(pctx, elt->obj); 1083 if (ISC_LIST_NEXT(elt, link) != NULL) 1084 cfg_print_chars(pctx, " ", 1); 1085 } 1086} 1087 1088 1089isc_boolean_t 1090cfg_obj_islist(cfg_obj_t *obj) { 1091 REQUIRE(obj != NULL); 1092 return (ISC_TF(obj->type->rep == &cfg_rep_list)); 1093} 1094 1095cfg_listelt_t * 1096cfg_list_first(cfg_obj_t *obj) { 1097 REQUIRE(obj == NULL || obj->type->rep == &cfg_rep_list); 1098 if (obj == NULL) 1099 return (NULL); 1100 return (ISC_LIST_HEAD(obj->value.list)); 1101} 1102 1103cfg_listelt_t * 1104cfg_list_next(cfg_listelt_t *elt) { 1105 REQUIRE(elt != NULL); 1106 return (ISC_LIST_NEXT(elt, link)); 1107} 1108 1109cfg_obj_t * 1110cfg_listelt_value(cfg_listelt_t *elt) { 1111 REQUIRE(elt != NULL); 1112 return (elt->obj); 1113} 1114 1115/* 1116 * Maps. 1117 */ 1118 1119/* 1120 * Parse a map body. That's something like 1121 * 1122 * "foo 1; bar { glub; }; zap true; zap false;" 1123 * 1124 * i.e., a sequence of option names followed by values and 1125 * terminated by semicolons. Used for the top level of 1126 * the named.conf syntax, as well as for the body of the 1127 * options, view, zone, and other statements. 1128 */ 1129isc_result_t 1130cfg_parse_mapbody(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) 1131{ 1132 const cfg_clausedef_t * const *clausesets = type->of; 1133 isc_result_t result; 1134 const cfg_clausedef_t * const *clauseset; 1135 const cfg_clausedef_t *clause; 1136 cfg_obj_t *value = NULL; 1137 cfg_obj_t *obj = NULL; 1138 cfg_obj_t *eltobj = NULL; 1139 cfg_obj_t *includename = NULL; 1140 isc_symvalue_t symval; 1141 cfg_list_t *list = NULL; 1142 1143 CHECK(create_map(pctx, type, &obj)); 1144 1145 obj->value.map.clausesets = clausesets; 1146 1147 for (;;) { 1148 cfg_listelt_t *elt; 1149 1150 redo: 1151 /* 1152 * Parse the option name and see if it is known. 1153 */ 1154 CHECK(cfg_gettoken(pctx, 0)); 1155 1156 if (pctx->token.type != isc_tokentype_string) { 1157 cfg_ungettoken(pctx); 1158 break; 1159 } 1160 1161 /* 1162 * We accept "include" statements wherever a map body 1163 * clause can occur. 1164 */ 1165 if (strcasecmp(TOKEN_STRING(pctx), "include") == 0) { 1166 /* 1167 * Turn the file name into a temporary configuration 1168 * object just so that it is not overwritten by the 1169 * semicolon token. 1170 */ 1171 CHECK(cfg_parse_obj(pctx, &cfg_type_qstring, &includename)); 1172 CHECK(parse_semicolon(pctx)); 1173 CHECK(parser_openfile(pctx, includename-> 1174 value.string.base)); 1175 cfg_obj_destroy(pctx, &includename); 1176 goto redo; 1177 } 1178 1179 clause = NULL; 1180 for (clauseset = clausesets; *clauseset != NULL; clauseset++) { 1181 for (clause = *clauseset; 1182 clause->name != NULL; 1183 clause++) { 1184 if (strcasecmp(TOKEN_STRING(pctx), 1185 clause->name) == 0) 1186 goto done; 1187 } 1188 } 1189 done: 1190 if (clause == NULL || clause->name == NULL) { 1191 cfg_parser_error(pctx, CFG_LOG_NOPREP, "unknown option"); 1192 /* 1193 * Try to recover by parsing this option as an unknown 1194 * option and discarding it. 1195 */ 1196 CHECK(cfg_parse_obj(pctx, &cfg_type_unsupported, &eltobj)); 1197 cfg_obj_destroy(pctx, &eltobj); 1198 CHECK(parse_semicolon(pctx)); 1199 continue; 1200 } 1201 1202 /* Clause is known. */ 1203 1204 /* Issue warnings if appropriate */ 1205 if ((clause->flags & CFG_CLAUSEFLAG_OBSOLETE) != 0) 1206 cfg_parser_warning(pctx, 0, "option '%s' is obsolete", 1207 clause->name); 1208 if ((clause->flags & CFG_CLAUSEFLAG_NOTIMP) != 0) 1209 cfg_parser_warning(pctx, 0, "option '%s' is " 1210 "not implemented", clause->name); 1211 if ((clause->flags & CFG_CLAUSEFLAG_NYI) != 0) 1212 cfg_parser_warning(pctx, 0, "option '%s' is " 1213 "not implemented", clause->name); 1214 /* 1215 * Don't log options with CFG_CLAUSEFLAG_NEWDEFAULT 1216 * set here - we need to log the *lack* of such an option, 1217 * not its presence. 1218 */ 1219 1220 /* See if the clause already has a value; if not create one. */ 1221 result = isc_symtab_lookup(obj->value.map.symtab, 1222 clause->name, 0, &symval); 1223 1224 if ((clause->flags & CFG_CLAUSEFLAG_MULTI) != 0) { 1225 /* Multivalued clause */ 1226 cfg_obj_t *listobj = NULL; 1227 if (result == ISC_R_NOTFOUND) { 1228 CHECK(cfg_create_list(pctx, 1229 &cfg_type_implicitlist, 1230 &listobj)); 1231 symval.as_pointer = listobj; 1232 result = isc_symtab_define(obj->value. 1233 map.symtab, 1234 clause->name, 1235 1, symval, 1236 isc_symexists_reject); 1237 if (result != ISC_R_SUCCESS) { 1238 cfg_parser_error(pctx, CFG_LOG_NEAR, 1239 "isc_symtab_define(%s) " 1240 "failed", clause->name); 1241 isc_mem_put(pctx->mctx, list, 1242 sizeof(cfg_list_t)); 1243 goto cleanup; 1244 } 1245 } else { 1246 INSIST(result == ISC_R_SUCCESS); 1247 listobj = symval.as_pointer; 1248 } 1249 1250 elt = NULL; 1251 CHECK(cfg_parse_listelt(pctx, clause->type, &elt)); 1252 CHECK(parse_semicolon(pctx)); 1253 1254 ISC_LIST_APPEND(listobj->value.list, elt, link); 1255 } else { 1256 /* Single-valued clause */ 1257 if (result == ISC_R_NOTFOUND) { 1258 isc_boolean_t callback = 1259 ISC_TF((clause->flags & 1260 CFG_CLAUSEFLAG_CALLBACK) != 0); 1261 CHECK(parse_symtab_elt(pctx, clause->name, 1262 clause->type, 1263 obj->value.map.symtab, 1264 callback)); 1265 CHECK(parse_semicolon(pctx)); 1266 } else if (result == ISC_R_SUCCESS) { 1267 cfg_parser_error(pctx, CFG_LOG_NEAR, "'%s' redefined", 1268 clause->name); 1269 result = ISC_R_EXISTS; 1270 goto cleanup; 1271 } else { 1272 cfg_parser_error(pctx, CFG_LOG_NEAR, 1273 "isc_symtab_define() failed"); 1274 goto cleanup; 1275 } 1276 } 1277 } 1278 1279 1280 *ret = obj; 1281 return (ISC_R_SUCCESS); 1282 1283 cleanup: 1284 CLEANUP_OBJ(value); 1285 CLEANUP_OBJ(obj); 1286 CLEANUP_OBJ(eltobj); 1287 CLEANUP_OBJ(includename); 1288 return (result); 1289} 1290 1291static isc_result_t 1292parse_symtab_elt(cfg_parser_t *pctx, const char *name, 1293 cfg_type_t *elttype, isc_symtab_t *symtab, 1294 isc_boolean_t callback) 1295{ 1296 isc_result_t result; 1297 cfg_obj_t *obj = NULL; 1298 isc_symvalue_t symval; 1299 1300 CHECK(cfg_parse_obj(pctx, elttype, &obj)); 1301 1302 if (callback && pctx->callback != NULL) 1303 CHECK(pctx->callback(name, obj, pctx->callbackarg)); 1304 1305 symval.as_pointer = obj; 1306 CHECK(isc_symtab_define(symtab, name, 1307 1, symval, 1308 isc_symexists_reject)); 1309 return (ISC_R_SUCCESS); 1310 1311 cleanup: 1312 CLEANUP_OBJ(obj); 1313 return (result); 1314} 1315 1316/* 1317 * Parse a map; e.g., "{ foo 1; bar { glub; }; zap true; zap false; }" 1318 */ 1319isc_result_t 1320cfg_parse_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 1321 isc_result_t result; 1322 CHECK(cfg_parse_special(pctx, '{')); 1323 CHECK(cfg_parse_mapbody(pctx, type, ret)); 1324 CHECK(cfg_parse_special(pctx, '}')); 1325 cleanup: 1326 return (result); 1327} 1328 1329/* 1330 * Subroutine for cfg_parse_named_map() and cfg_parse_addressed_map(). 1331 */ 1332static isc_result_t 1333parse_any_named_map(cfg_parser_t *pctx, cfg_type_t *nametype, const cfg_type_t *type, 1334 cfg_obj_t **ret) 1335{ 1336 isc_result_t result; 1337 cfg_obj_t *idobj = NULL; 1338 cfg_obj_t *mapobj = NULL; 1339 1340 CHECK(cfg_parse_obj(pctx, nametype, &idobj)); 1341 CHECK(cfg_parse_map(pctx, type, &mapobj)); 1342 mapobj->value.map.id = idobj; 1343 idobj = NULL; 1344 *ret = mapobj; 1345 cleanup: 1346 CLEANUP_OBJ(idobj); 1347 return (result); 1348} 1349 1350/* 1351 * Parse a map identified by a string name. E.g., "name { foo 1; }". 1352 * Used for the "key" and "channel" statements. 1353 */ 1354isc_result_t 1355cfg_parse_named_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 1356 return (parse_any_named_map(pctx, &cfg_type_astring, type, ret)); 1357} 1358 1359/* 1360 * Parse a map identified by a network address. 1361 * Used for the "server" statement. 1362 */ 1363isc_result_t 1364cfg_parse_addressed_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 1365 return (parse_any_named_map(pctx, &cfg_type_netaddr, type, ret)); 1366} 1367 1368void 1369cfg_print_mapbody(cfg_printer_t *pctx, cfg_obj_t *obj) { 1370 isc_result_t result = ISC_R_SUCCESS; 1371 1372 const cfg_clausedef_t * const *clauseset; 1373 1374 for (clauseset = obj->value.map.clausesets; 1375 *clauseset != NULL; 1376 clauseset++) 1377 { 1378 isc_symvalue_t symval; 1379 const cfg_clausedef_t *clause; 1380 1381 for (clause = *clauseset; 1382 clause->name != NULL; 1383 clause++) { 1384 result = isc_symtab_lookup(obj->value.map.symtab, 1385 clause->name, 0, &symval); 1386 if (result == ISC_R_SUCCESS) { 1387 cfg_obj_t *obj = symval.as_pointer; 1388 if (obj->type == &cfg_type_implicitlist) { 1389 /* Multivalued. */ 1390 cfg_list_t *list = &obj->value.list; 1391 cfg_listelt_t *elt; 1392 for (elt = ISC_LIST_HEAD(*list); 1393 elt != NULL; 1394 elt = ISC_LIST_NEXT(elt, link)) { 1395 print_indent(pctx); 1396 cfg_print_cstr(pctx, clause->name); 1397 cfg_print_chars(pctx, " ", 1); 1398 cfg_print_obj(pctx, elt->obj); 1399 cfg_print_chars(pctx, ";\n", 2); 1400 } 1401 } else { 1402 /* Single-valued. */ 1403 print_indent(pctx); 1404 cfg_print_cstr(pctx, clause->name); 1405 cfg_print_chars(pctx, " ", 1); 1406 cfg_print_obj(pctx, obj); 1407 cfg_print_chars(pctx, ";\n", 2); 1408 } 1409 } else if (result == ISC_R_NOTFOUND) { 1410 ; /* do nothing */ 1411 } else { 1412 INSIST(0); 1413 } 1414 } 1415 } 1416} 1417 1418void 1419cfg_doc_mapbody(cfg_printer_t *pctx, const cfg_type_t *type) { 1420 const cfg_clausedef_t * const *clauseset; 1421 const cfg_clausedef_t *clause; 1422 1423 for (clauseset = type->of; *clauseset != NULL; clauseset++) { 1424 for (clause = *clauseset; 1425 clause->name != NULL; 1426 clause++) { 1427 cfg_print_cstr(pctx, clause->name); 1428 cfg_print_chars(pctx, " ", 1); 1429 cfg_doc_obj(pctx, clause->type); 1430 cfg_print_chars(pctx, ";", 1); 1431 /* XXX print flags here? */ 1432 cfg_print_chars(pctx, "\n\n", 2); 1433 } 1434 } 1435} 1436 1437static struct flagtext { 1438 unsigned int flag; 1439 const char *text; 1440} flagtexts[] = { 1441 { CFG_CLAUSEFLAG_NOTIMP, "not implemented" }, 1442 { CFG_CLAUSEFLAG_NYI, "not yet implemented" }, 1443 { CFG_CLAUSEFLAG_OBSOLETE, "obsolete" }, 1444 { CFG_CLAUSEFLAG_NEWDEFAULT, "default changed" }, 1445 { 0, NULL } 1446}; 1447 1448void 1449cfg_print_map(cfg_printer_t *pctx, cfg_obj_t *obj) { 1450 if (obj->value.map.id != NULL) { 1451 cfg_print_obj(pctx, obj->value.map.id); 1452 cfg_print_chars(pctx, " ", 1); 1453 } 1454 print_open(pctx); 1455 cfg_print_mapbody(pctx, obj); 1456 print_close(pctx); 1457} 1458 1459static void 1460print_clause_flags(cfg_printer_t *pctx, unsigned int flags) { 1461 struct flagtext *p; 1462 isc_boolean_t first = ISC_TRUE; 1463 for (p = flagtexts; p->flag != 0; p++) { 1464 if ((flags & p->flag) != 0) { 1465 if (first) 1466 cfg_print_chars(pctx, " // ", 4); 1467 else 1468 cfg_print_chars(pctx, ", ", 2); 1469 cfg_print_cstr(pctx, p->text); 1470 first = ISC_FALSE; 1471 } 1472 } 1473} 1474 1475void 1476cfg_doc_map(cfg_printer_t *pctx, const cfg_type_t *type) { 1477 const cfg_clausedef_t * const *clauseset; 1478 const cfg_clausedef_t *clause; 1479 1480 if (type->parse == cfg_parse_named_map) { 1481 cfg_doc_obj(pctx, &cfg_type_astring); 1482 cfg_print_chars(pctx, " ", 1); 1483 } else if (type->parse == cfg_parse_addressed_map) { 1484 cfg_doc_obj(pctx, &cfg_type_netaddr); 1485 cfg_print_chars(pctx, " ", 1); 1486 } 1487 1488 print_open(pctx); 1489 1490 for (clauseset = type->of; *clauseset != NULL; clauseset++) { 1491 for (clause = *clauseset; 1492 clause->name != NULL; 1493 clause++) { 1494 print_indent(pctx); 1495 cfg_print_cstr(pctx, clause->name); 1496 if (clause->type->print != cfg_print_void) 1497 cfg_print_chars(pctx, " ", 1); 1498 cfg_doc_obj(pctx, clause->type); 1499 cfg_print_chars(pctx, ";", 1); 1500 print_clause_flags(pctx, clause->flags); 1501 cfg_print_chars(pctx, "\n", 1); 1502 } 1503 } 1504 print_close(pctx); 1505} 1506 1507isc_boolean_t 1508cfg_obj_ismap(cfg_obj_t *obj) { 1509 REQUIRE(obj != NULL); 1510 return (ISC_TF(obj->type->rep == &cfg_rep_map)); 1511} 1512 1513isc_result_t 1514cfg_map_get(cfg_obj_t *mapobj, const char* name, cfg_obj_t **obj) { 1515 isc_result_t result; 1516 isc_symvalue_t val; 1517 cfg_map_t *map; 1518 1519 REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map); 1520 REQUIRE(name != NULL); 1521 REQUIRE(obj != NULL && *obj == NULL); 1522 1523 map = &mapobj->value.map; 1524 1525 result = isc_symtab_lookup(map->symtab, name, MAP_SYM, &val); 1526 if (result != ISC_R_SUCCESS) 1527 return (result); 1528 *obj = val.as_pointer; 1529 return (ISC_R_SUCCESS); 1530} 1531 1532cfg_obj_t * 1533cfg_map_getname(cfg_obj_t *mapobj) { 1534 REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map); 1535 return (mapobj->value.map.id); 1536} 1537 1538 1539/* Parse an arbitrary token, storing its raw text representation. */ 1540static isc_result_t 1541parse_token(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 1542 cfg_obj_t *obj = NULL; 1543 isc_result_t result; 1544 isc_region_t r; 1545 1546 UNUSED(type); 1547 1548 CHECK(cfg_create_obj(pctx, &cfg_type_token, &obj)); 1549 CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING)); 1550 if (pctx->token.type == isc_tokentype_eof) { 1551 cfg_ungettoken(pctx); 1552 result = ISC_R_EOF; 1553 goto cleanup; 1554 } 1555 1556 isc_lex_getlasttokentext(pctx->lexer, &pctx->token, &r); 1557 1558 obj->value.string.base = isc_mem_get(pctx->mctx, r.length + 1); 1559 obj->value.string.length = r.length; 1560 memcpy(obj->value.string.base, r.base, r.length); 1561 obj->value.string.base[r.length] = '\0'; 1562 *ret = obj; 1563 1564 cleanup: 1565 return (result); 1566} 1567 1568cfg_type_t cfg_type_token = { 1569 "token", parse_token, cfg_print_ustring, cfg_doc_terminal, 1570 &cfg_rep_string, NULL 1571}; 1572 1573/* 1574 * An unsupported option. This is just a list of tokens with balanced braces 1575 * ending in a semicolon. 1576 */ 1577 1578static isc_result_t 1579parse_unsupported(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 1580 cfg_obj_t *listobj = NULL; 1581 isc_result_t result; 1582 int braces = 0; 1583 1584 CHECK(cfg_create_list(pctx, type, &listobj)); 1585 1586 for (;;) { 1587 cfg_listelt_t *elt = NULL; 1588 1589 CHECK(cfg_peektoken(pctx, 0)); 1590 if (pctx->token.type == isc_tokentype_special) { 1591 if (pctx->token.value.as_char == '{') 1592 braces++; 1593 else if (pctx->token.value.as_char == '}') 1594 braces--; 1595 else if (pctx->token.value.as_char == ';') 1596 if (braces == 0) 1597 break; 1598 } 1599 if (pctx->token.type == isc_tokentype_eof || braces < 0) { 1600 cfg_parser_error(pctx, CFG_LOG_NEAR, "unexpected token"); 1601 result = ISC_R_UNEXPECTEDTOKEN; 1602 goto cleanup; 1603 } 1604 1605 CHECK(cfg_parse_listelt(pctx, &cfg_type_token, &elt)); 1606 ISC_LIST_APPEND(listobj->value.list, elt, link); 1607 } 1608 INSIST(braces == 0); 1609 *ret = listobj; 1610 return (ISC_R_SUCCESS); 1611 1612 cleanup: 1613 CLEANUP_OBJ(listobj); 1614 return (result); 1615} 1616 1617cfg_type_t cfg_type_unsupported = { 1618 "unsupported", parse_unsupported, cfg_print_spacelist, cfg_doc_terminal, 1619 &cfg_rep_list, NULL 1620}; 1621 1622/* 1623 * Try interpreting the current token as a network address. 1624 * 1625 * If CFG_ADDR_WILDOK is set in flags, "*" can be used as a wildcard 1626 * and at least one of CFG_ADDR_V4OK and CFG_ADDR_V6OK must also be set. The 1627 * "*" is interpreted as the IPv4 wildcard address if CFG_ADDR_V4OK is 1628 * set (including the case where CFG_ADDR_V4OK and CFG_ADDR_V6OK are both set), 1629 * and the IPv6 wildcard address otherwise. 1630 */ 1631static isc_result_t 1632token_addr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na) { 1633 char *s; 1634 struct in_addr in4a; 1635 struct in6_addr in6a; 1636 1637 if (pctx->token.type != isc_tokentype_string) 1638 return (ISC_R_UNEXPECTEDTOKEN); 1639 1640 s = TOKEN_STRING(pctx); 1641 if ((flags & CFG_ADDR_WILDOK) != 0 && strcmp(s, "*") == 0) { 1642 if ((flags & CFG_ADDR_V4OK) != 0) { 1643 isc_netaddr_any(na); 1644 return (ISC_R_SUCCESS); 1645 } else if ((flags & CFG_ADDR_V6OK) != 0) { 1646 isc_netaddr_any6(na); 1647 return (ISC_R_SUCCESS); 1648 } else { 1649 INSIST(0); 1650 } 1651 } else { 1652 if ((flags & (CFG_ADDR_V4OK | CFG_ADDR_V4PREFIXOK)) != 0) { 1653 if (inet_pton(AF_INET, s, &in4a) == 1) { 1654 isc_netaddr_fromin(na, &in4a); 1655 return (ISC_R_SUCCESS); 1656 } 1657 } 1658 if ((flags & CFG_ADDR_V4PREFIXOK) != 0 && 1659 strlen(s) <= 15U) { 1660 char buf[64]; 1661 int i; 1662 1663 strcpy(buf, s); 1664 for (i = 0; i < 3; i++) { 1665 strcat(buf, ".0"); 1666 if (inet_pton(AF_INET, buf, &in4a) == 1) { 1667 isc_netaddr_fromin(na, &in4a); 1668 return (ISC_R_SUCCESS); 1669 } 1670 } 1671 } 1672 if ((flags & CFG_ADDR_V6OK) != 0 && 1673 strlen(s) <= 127U) { 1674 char buf[128]; /* see lib/bind9/getaddresses.c */ 1675 char *d; /* zone delimiter */ 1676 isc_uint32_t zone = 0; /* scope zone ID */ 1677 1678 strcpy(buf, s); 1679 d = strchr(buf, '%'); 1680 if (d != NULL) 1681 *d = '\0'; 1682 1683 if (inet_pton(AF_INET6, buf, &in6a) == 1) { 1684 if (d != NULL) { 1685#ifdef ISC_PLATFORM_HAVESCOPEID 1686 isc_result_t result; 1687 1688 result = isc_netscope_pton(AF_INET6, 1689 d + 1, 1690 &in6a, 1691 &zone); 1692 if (result != ISC_R_SUCCESS) 1693 return (result); 1694#else 1695 return (ISC_R_BADADDRESSFORM); 1696#endif 1697 } 1698 1699 isc_netaddr_fromin6(na, &in6a); 1700 isc_netaddr_setzone(na, zone); 1701 return (ISC_R_SUCCESS); 1702 } 1703 } 1704 } 1705 return (ISC_R_UNEXPECTEDTOKEN); 1706} 1707 1708isc_result_t 1709cfg_parse_rawaddr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na) { 1710 isc_result_t result; 1711 CHECK(cfg_gettoken(pctx, 0)); 1712 result = token_addr(pctx, flags, na); 1713 if (result == ISC_R_UNEXPECTEDTOKEN) 1714 cfg_parser_error(pctx, CFG_LOG_NEAR, "expected IP address"); 1715 cleanup: 1716 return (result); 1717} 1718 1719isc_boolean_t 1720cfg_lookingat_netaddr(cfg_parser_t *pctx, unsigned int flags) { 1721 isc_result_t result; 1722 isc_netaddr_t na_dummy; 1723 result = token_addr(pctx, flags, &na_dummy); 1724 return (ISC_TF(result == ISC_R_SUCCESS)); 1725} 1726 1727isc_result_t 1728cfg_parse_rawport(cfg_parser_t *pctx, unsigned int flags, in_port_t *port) { 1729 isc_result_t result; 1730 1731 CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER)); 1732 1733 if ((flags & CFG_ADDR_WILDOK) != 0 && 1734 pctx->token.type == isc_tokentype_string && 1735 strcmp(TOKEN_STRING(pctx), "*") == 0) { 1736 *port = 0; 1737 return (ISC_R_SUCCESS); 1738 } 1739 if (pctx->token.type != isc_tokentype_number) { 1740 cfg_parser_error(pctx, CFG_LOG_NEAR, 1741 "expected port number or '*'"); 1742 return (ISC_R_UNEXPECTEDTOKEN); 1743 } 1744 if (pctx->token.value.as_ulong >= 65536U) { 1745 cfg_parser_error(pctx, CFG_LOG_NEAR, 1746 "port number out of range"); 1747 return (ISC_R_UNEXPECTEDTOKEN); 1748 } 1749 *port = (in_port_t)(pctx->token.value.as_ulong); 1750 return (ISC_R_SUCCESS); 1751 cleanup: 1752 return (result); 1753} 1754 1755void 1756cfg_print_rawaddr(cfg_printer_t *pctx, isc_netaddr_t *na) { 1757 isc_result_t result; 1758 char text[128]; 1759 isc_buffer_t buf; 1760 1761 isc_buffer_init(&buf, text, sizeof(text)); 1762 result = isc_netaddr_totext(na, &buf); 1763 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1764 cfg_print_chars(pctx, isc_buffer_base(&buf), isc_buffer_usedlength(&buf)); 1765} 1766 1767/* netaddr */ 1768 1769static isc_result_t 1770parse_netaddr(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 1771 isc_result_t result; 1772 cfg_obj_t *obj = NULL; 1773 isc_netaddr_t netaddr; 1774 UNUSED(type); 1775 CHECK(cfg_create_obj(pctx, type, &obj)); 1776 CHECK(cfg_parse_rawaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V6OK, &netaddr)); 1777 isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, 0); 1778 *ret = obj; 1779 return (ISC_R_SUCCESS); 1780 cleanup: 1781 CLEANUP_OBJ(obj); 1782 return (result); 1783} 1784 1785cfg_type_t cfg_type_netaddr = { 1786 "netaddr", parse_netaddr, cfg_print_sockaddr, cfg_doc_terminal, 1787 &cfg_rep_sockaddr, NULL 1788}; 1789 1790/* netprefix */ 1791 1792isc_result_t 1793cfg_parse_netprefix(cfg_parser_t *pctx, const cfg_type_t *type, 1794 cfg_obj_t **ret) 1795{ 1796 cfg_obj_t *obj = NULL; 1797 isc_result_t result; 1798 isc_netaddr_t netaddr; 1799 unsigned int addrlen, prefixlen; 1800 UNUSED(type); 1801 1802 CHECK(cfg_parse_rawaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V4PREFIXOK | 1803 CFG_ADDR_V6OK, &netaddr)); 1804 switch (netaddr.family) { 1805 case AF_INET: 1806 addrlen = 32; 1807 break; 1808 case AF_INET6: 1809 addrlen = 128; 1810 break; 1811 default: 1812 addrlen = 0; 1813 INSIST(0); 1814 break; 1815 } 1816 CHECK(cfg_peektoken(pctx, 0)); 1817 if (pctx->token.type == isc_tokentype_special && 1818 pctx->token.value.as_char == '/') { 1819 CHECK(cfg_gettoken(pctx, 0)); /* read "/" */ 1820 CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER)); 1821 if (pctx->token.type != isc_tokentype_number) { 1822 cfg_parser_error(pctx, CFG_LOG_NEAR, 1823 "expected prefix length"); 1824 return (ISC_R_UNEXPECTEDTOKEN); 1825 } 1826 prefixlen = pctx->token.value.as_ulong; 1827 if (prefixlen > addrlen) { 1828 cfg_parser_error(pctx, CFG_LOG_NOPREP, 1829 "invalid prefix length"); 1830 return (ISC_R_RANGE); 1831 } 1832 } else { 1833 prefixlen = addrlen; 1834 } 1835 CHECK(cfg_create_obj(pctx, &cfg_type_netprefix, &obj)); 1836 obj->value.netprefix.address = netaddr; 1837 obj->value.netprefix.prefixlen = prefixlen; 1838 *ret = obj; 1839 return (ISC_R_SUCCESS); 1840 cleanup: 1841 cfg_parser_error(pctx, CFG_LOG_NEAR, "expected network prefix"); 1842 return (result); 1843} 1844 1845static void 1846print_netprefix(cfg_printer_t *pctx, cfg_obj_t *obj) { 1847 cfg_netprefix_t *p = &obj->value.netprefix; 1848 cfg_print_rawaddr(pctx, &p->address); 1849 cfg_print_chars(pctx, "/", 1); 1850 cfg_print_rawuint(pctx, p->prefixlen); 1851} 1852 1853isc_boolean_t 1854cfg_obj_isnetprefix(cfg_obj_t *obj) { 1855 REQUIRE(obj != NULL); 1856 return (ISC_TF(obj->type->rep == &cfg_rep_netprefix)); 1857} 1858 1859void 1860cfg_obj_asnetprefix(cfg_obj_t *obj, isc_netaddr_t *netaddr, 1861 unsigned int *prefixlen) { 1862 REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_netprefix); 1863 *netaddr = obj->value.netprefix.address; 1864 *prefixlen = obj->value.netprefix.prefixlen; 1865} 1866 1867cfg_type_t cfg_type_netprefix = { 1868 "netprefix", cfg_parse_netprefix, print_netprefix, cfg_doc_terminal, 1869 &cfg_rep_netprefix, NULL 1870}; 1871 1872static isc_result_t 1873parse_sockaddrsub(cfg_parser_t *pctx, const cfg_type_t *type, 1874 int flags, cfg_obj_t **ret) 1875{ 1876 isc_result_t result; 1877 isc_netaddr_t netaddr; 1878 in_port_t port = 0; 1879 cfg_obj_t *obj = NULL; 1880 1881 CHECK(cfg_create_obj(pctx, type, &obj)); 1882 CHECK(cfg_parse_rawaddr(pctx, flags, &netaddr)); 1883 CHECK(cfg_peektoken(pctx, 0)); 1884 if (pctx->token.type == isc_tokentype_string && 1885 strcasecmp(TOKEN_STRING(pctx), "port") == 0) { 1886 CHECK(cfg_gettoken(pctx, 0)); /* read "port" */ 1887 CHECK(cfg_parse_rawport(pctx, flags, &port)); 1888 } 1889 isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, port); 1890 *ret = obj; 1891 return (ISC_R_SUCCESS); 1892 1893 cleanup: 1894 CLEANUP_OBJ(obj); 1895 return (result); 1896} 1897 1898static unsigned int sockaddr_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK; 1899cfg_type_t cfg_type_sockaddr = { 1900 "sockaddr", cfg_parse_sockaddr, cfg_print_sockaddr, cfg_doc_sockaddr, 1901 &cfg_rep_sockaddr, &sockaddr_flags 1902}; 1903 1904isc_result_t 1905cfg_parse_sockaddr(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 1906 const unsigned int *flagp = type->of; 1907 return (parse_sockaddrsub(pctx, &cfg_type_sockaddr, *flagp, ret)); 1908} 1909 1910void 1911cfg_print_sockaddr(cfg_printer_t *pctx, cfg_obj_t *obj) { 1912 isc_netaddr_t netaddr; 1913 in_port_t port; 1914 char buf[ISC_NETADDR_FORMATSIZE]; 1915 1916 isc_netaddr_fromsockaddr(&netaddr, &obj->value.sockaddr); 1917 isc_netaddr_format(&netaddr, buf, sizeof(buf)); 1918 cfg_print_cstr(pctx, buf); 1919 port = isc_sockaddr_getport(&obj->value.sockaddr); 1920 if (port != 0) { 1921 cfg_print_chars(pctx, " port ", 6); 1922 cfg_print_rawuint(pctx, port); 1923 } 1924} 1925 1926void 1927cfg_doc_sockaddr(cfg_printer_t *pctx, const cfg_type_t *type) { 1928 const unsigned int *flagp = type->of; 1929 int n = 0; 1930 cfg_print_chars(pctx, "( ", 2); 1931 if (*flagp & CFG_ADDR_V4OK) { 1932 if (n != 0) 1933 cfg_print_chars(pctx, " | ", 3); 1934 cfg_print_cstr(pctx, "<ipv4_address>"); 1935 n++; 1936 } 1937 if (*flagp & CFG_ADDR_V6OK) { 1938 if (n != 0) 1939 cfg_print_chars(pctx, " | ", 3); 1940 cfg_print_cstr(pctx, "<ipv6_address>"); 1941 n++; 1942 } 1943 if (*flagp & CFG_ADDR_WILDOK) { 1944 if (n != 0) 1945 cfg_print_chars(pctx, " | ", 3); 1946 cfg_print_chars(pctx, "*", 1); 1947 n++; 1948 } 1949 cfg_print_chars(pctx, " ) ", 3); 1950 if (*flagp & CFG_ADDR_WILDOK) { 1951 cfg_print_cstr(pctx, "[ port ( <integer> | * ) ]"); 1952 } else { 1953 cfg_print_cstr(pctx, "[ port <integer> ]"); 1954 } 1955} 1956 1957isc_boolean_t 1958cfg_obj_issockaddr(cfg_obj_t *obj) { 1959 REQUIRE(obj != NULL); 1960 return (ISC_TF(obj->type->rep == &cfg_rep_sockaddr)); 1961} 1962 1963isc_sockaddr_t * 1964cfg_obj_assockaddr(cfg_obj_t *obj) { 1965 REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_sockaddr); 1966 return (&obj->value.sockaddr); 1967} 1968 1969isc_result_t 1970cfg_gettoken(cfg_parser_t *pctx, int options) { 1971 isc_result_t result; 1972 1973 if (pctx->seen_eof) 1974 return (ISC_R_SUCCESS); 1975 1976 options |= (ISC_LEXOPT_EOF | ISC_LEXOPT_NOMORE); 1977 1978 redo: 1979 pctx->token.type = isc_tokentype_unknown; 1980 result = isc_lex_gettoken(pctx->lexer, options, &pctx->token); 1981 pctx->ungotten = ISC_FALSE; 1982 pctx->line = isc_lex_getsourceline(pctx->lexer); 1983 1984 switch (result) { 1985 case ISC_R_SUCCESS: 1986 if (pctx->token.type == isc_tokentype_eof) { 1987 result = isc_lex_close(pctx->lexer); 1988 INSIST(result == ISC_R_NOMORE || 1989 result == ISC_R_SUCCESS); 1990 1991 if (isc_lex_getsourcename(pctx->lexer) != NULL) { 1992 /* 1993 * Closed an included file, not the main file. 1994 */ 1995 cfg_listelt_t *elt; 1996 elt = ISC_LIST_TAIL(pctx->open_files-> 1997 value.list); 1998 INSIST(elt != NULL); 1999 ISC_LIST_UNLINK(pctx->open_files-> 2000 value.list, elt, link); 2001 ISC_LIST_APPEND(pctx->closed_files-> 2002 value.list, elt, link); 2003 goto redo; 2004 } 2005 pctx->seen_eof = ISC_TRUE; 2006 } 2007 break; 2008 2009 case ISC_R_NOSPACE: 2010 /* More understandable than "ran out of space". */ 2011 cfg_parser_error(pctx, CFG_LOG_NEAR, "token too big"); 2012 break; 2013 2014 case ISC_R_IOERROR: 2015 cfg_parser_error(pctx, 0, "%s", 2016 isc_result_totext(result)); 2017 break; 2018 2019 default: 2020 cfg_parser_error(pctx, CFG_LOG_NEAR, "%s", 2021 isc_result_totext(result)); 2022 break; 2023 } 2024 return (result); 2025} 2026 2027void 2028cfg_ungettoken(cfg_parser_t *pctx) { 2029 if (pctx->seen_eof) 2030 return; 2031 isc_lex_ungettoken(pctx->lexer, &pctx->token); 2032 pctx->ungotten = ISC_TRUE; 2033} 2034 2035isc_result_t 2036cfg_peektoken(cfg_parser_t *pctx, int options) { 2037 isc_result_t result; 2038 CHECK(cfg_gettoken(pctx, options)); 2039 cfg_ungettoken(pctx); 2040 cleanup: 2041 return (result); 2042} 2043 2044/* 2045 * Get a string token, accepting both the quoted and the unquoted form. 2046 * Log an error if the next token is not a string. 2047 */ 2048static isc_result_t 2049cfg_getstringtoken(cfg_parser_t *pctx) { 2050 isc_result_t result; 2051 2052 result = cfg_gettoken(pctx, CFG_LEXOPT_QSTRING); 2053 if (result != ISC_R_SUCCESS) 2054 return (result); 2055 2056 if (pctx->token.type != isc_tokentype_string && 2057 pctx->token.type != isc_tokentype_qstring) { 2058 cfg_parser_error(pctx, CFG_LOG_NEAR, "expected string"); 2059 return (ISC_R_UNEXPECTEDTOKEN); 2060 } 2061 return (ISC_R_SUCCESS); 2062} 2063 2064void 2065cfg_parser_error(cfg_parser_t *pctx, unsigned int flags, const char *fmt, ...) { 2066 va_list args; 2067 va_start(args, fmt); 2068 parser_complain(pctx, ISC_FALSE, flags, fmt, args); 2069 va_end(args); 2070 pctx->errors++; 2071} 2072 2073void 2074cfg_parser_warning(cfg_parser_t *pctx, unsigned int flags, const char *fmt, ...) { 2075 va_list args; 2076 va_start(args, fmt); 2077 parser_complain(pctx, ISC_TRUE, flags, fmt, args); 2078 va_end(args); 2079 pctx->warnings++; 2080} 2081 2082#define MAX_LOG_TOKEN 30 /* How much of a token to quote in log messages. */ 2083 2084static char * 2085current_file(cfg_parser_t *pctx) { 2086 static char none[] = "none"; 2087 cfg_listelt_t *elt; 2088 cfg_obj_t *fileobj; 2089 2090 if (pctx->open_files == NULL) 2091 return (none); 2092 elt = ISC_LIST_TAIL(pctx->open_files->value.list); 2093 if (elt == NULL) 2094 return (none); 2095 2096 fileobj = elt->obj; 2097 INSIST(fileobj->type == &cfg_type_qstring); 2098 return (fileobj->value.string.base); 2099} 2100 2101static void 2102parser_complain(cfg_parser_t *pctx, isc_boolean_t is_warning, 2103 unsigned int flags, const char *format, 2104 va_list args) 2105{ 2106 char tokenbuf[MAX_LOG_TOKEN + 10]; 2107 static char where[ISC_DIR_PATHMAX + 100]; 2108 static char message[2048]; 2109 int level = ISC_LOG_ERROR; 2110 const char *prep = ""; 2111 size_t len; 2112 2113 if (is_warning) 2114 level = ISC_LOG_WARNING; 2115 2116 snprintf(where, sizeof(where), "%s:%u: ", 2117 current_file(pctx), pctx->line); 2118 2119 len = vsnprintf(message, sizeof(message), format, args); 2120 if (len >= sizeof(message)) 2121 FATAL_ERROR(__FILE__, __LINE__, 2122 "error message would overflow"); 2123 2124 if ((flags & (CFG_LOG_NEAR|CFG_LOG_BEFORE|CFG_LOG_NOPREP)) != 0) { 2125 isc_region_t r; 2126 2127 if (pctx->ungotten) 2128 (void)cfg_gettoken(pctx, 0); 2129 2130 if (pctx->token.type == isc_tokentype_eof) { 2131 snprintf(tokenbuf, sizeof(tokenbuf), "end of file"); 2132 } else if (pctx->token.type == isc_tokentype_unknown) { 2133 flags = 0; 2134 tokenbuf[0] = '\0'; 2135 } else { 2136 isc_lex_getlasttokentext(pctx->lexer, 2137 &pctx->token, &r); 2138 if (r.length > MAX_LOG_TOKEN) 2139 snprintf(tokenbuf, sizeof(tokenbuf), 2140 "'%.*s...'", MAX_LOG_TOKEN, r.base); 2141 else 2142 snprintf(tokenbuf, sizeof(tokenbuf), 2143 "'%.*s'", (int)r.length, r.base); 2144 } 2145 2146 /* Choose a preposition. */ 2147 if (flags & CFG_LOG_NEAR) 2148 prep = " near "; 2149 else if (flags & CFG_LOG_BEFORE) 2150 prep = " before "; 2151 else 2152 prep = " "; 2153 } else { 2154 tokenbuf[0] = '\0'; 2155 } 2156 isc_log_write(pctx->lctx, CAT, MOD, level, 2157 "%s%s%s%s", where, message, prep, tokenbuf); 2158} 2159 2160void 2161cfg_obj_log(cfg_obj_t *obj, isc_log_t *lctx, int level, const char *fmt, ...) { 2162 va_list ap; 2163 char msgbuf[2048]; 2164 2165 if (! isc_log_wouldlog(lctx, level)) 2166 return; 2167 2168 va_start(ap, fmt); 2169 2170 vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap); 2171 isc_log_write(lctx, CAT, MOD, level, 2172 "%s:%u: %s", 2173 obj->file == NULL ? "<unknown file>" : obj->file, 2174 obj->line, msgbuf); 2175 va_end(ap); 2176} 2177 2178const char * 2179cfg_obj_file(cfg_obj_t *obj) { 2180 return (obj->file); 2181} 2182 2183unsigned int 2184cfg_obj_line(cfg_obj_t *obj) { 2185 return (obj->line); 2186} 2187 2188isc_result_t 2189cfg_create_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 2190 cfg_obj_t *obj; 2191 2192 obj = isc_mem_get(pctx->mctx, sizeof(cfg_obj_t)); 2193 if (obj == NULL) 2194 return (ISC_R_NOMEMORY); 2195 obj->type = type; 2196 obj->file = current_file(pctx); 2197 obj->line = pctx->line; 2198 *ret = obj; 2199 return (ISC_R_SUCCESS); 2200} 2201 2202static void 2203map_symtabitem_destroy(char *key, unsigned int type, 2204 isc_symvalue_t symval, void *userarg) 2205{ 2206 cfg_obj_t *obj = symval.as_pointer; 2207 cfg_parser_t *pctx = (cfg_parser_t *)userarg; 2208 2209 UNUSED(key); 2210 UNUSED(type); 2211 2212 cfg_obj_destroy(pctx, &obj); 2213} 2214 2215 2216static isc_result_t 2217create_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 2218 isc_result_t result; 2219 isc_symtab_t *symtab = NULL; 2220 cfg_obj_t *obj = NULL; 2221 2222 CHECK(cfg_create_obj(pctx, type, &obj)); 2223 CHECK(isc_symtab_create(pctx->mctx, 5, /* XXX */ 2224 map_symtabitem_destroy, 2225 pctx, ISC_FALSE, &symtab)); 2226 2227 obj->value.map.symtab = symtab; 2228 obj->value.map.id = NULL; 2229 2230 *ret = obj; 2231 return (ISC_R_SUCCESS); 2232 2233 cleanup: 2234 if (obj != NULL) 2235 isc_mem_put(pctx->mctx, obj, sizeof(*obj)); 2236 return (result); 2237} 2238 2239static void 2240free_map(cfg_parser_t *pctx, cfg_obj_t *obj) { 2241 CLEANUP_OBJ(obj->value.map.id); 2242 isc_symtab_destroy(&obj->value.map.symtab); 2243} 2244 2245isc_boolean_t 2246cfg_obj_istype(cfg_obj_t *obj, const cfg_type_t *type) { 2247 return (ISC_TF(obj->type == type)); 2248} 2249 2250/* 2251 * Destroy 'obj', a configuration object created in 'pctx'. 2252 */ 2253void 2254cfg_obj_destroy(cfg_parser_t *pctx, cfg_obj_t **objp) { 2255 cfg_obj_t *obj = *objp; 2256 obj->type->rep->free(pctx, obj); 2257 isc_mem_put(pctx->mctx, obj, sizeof(cfg_obj_t)); 2258 *objp = NULL; 2259} 2260 2261static void 2262free_noop(cfg_parser_t *pctx, cfg_obj_t *obj) { 2263 UNUSED(pctx); 2264 UNUSED(obj); 2265} 2266 2267void 2268cfg_doc_obj(cfg_printer_t *pctx, const cfg_type_t *type) { 2269 type->doc(pctx, type); 2270} 2271 2272void 2273cfg_doc_terminal(cfg_printer_t *pctx, const cfg_type_t *type) { 2274 cfg_print_chars(pctx, "<", 1); 2275 cfg_print_cstr(pctx, type->name); 2276 cfg_print_chars(pctx, ">", 1); 2277} 2278 2279void 2280cfg_print_grammar(const cfg_type_t *type, 2281 void (*f)(void *closure, const char *text, int textlen), 2282 void *closure) 2283{ 2284 cfg_printer_t pctx; 2285 pctx.f = f; 2286 pctx.closure = closure; 2287 pctx.indent = 0; 2288 cfg_doc_obj(&pctx, type); 2289} 2290