00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <config.h>
00023
00024 #include <isc/buffer.h>
00025 #include <isc/dir.h>
00026 #include <isc/formatcheck.h>
00027 #include <isc/lex.h>
00028 #include <isc/log.h>
00029 #include <isc/mem.h>
00030 #include <isc/net.h>
00031 #include <isc/netaddr.h>
00032 #include <isc/netscope.h>
00033 #include <isc/print.h>
00034 #include <isc/string.h>
00035 #include <isc/sockaddr.h>
00036 #include <isc/symtab.h>
00037 #include <isc/util.h>
00038
00039 #include <isccfg/cfg.h>
00040 #include <isccfg/grammar.h>
00041 #include <isccfg/log.h>
00042
00043
00044 #define CAT CFG_LOGCATEGORY_CONFIG
00045 #define MOD CFG_LOGMODULE_PARSER
00046
00047 #define MAP_SYM 1
00048
00049 #define TOKEN_STRING(pctx) (pctx->token.value.as_textregion.base)
00050
00051
00052 #define CHECK(op) \
00053 do { result = (op); \
00054 if (result != ISC_R_SUCCESS) goto cleanup; \
00055 } while (0)
00056
00057
00058 #define CLEANUP_OBJ(obj) \
00059 do { if ((obj) != NULL) cfg_obj_destroy(pctx, &(obj)); } while (0)
00060
00061
00062
00063
00064
00065
00066 static void
00067 free_tuple(cfg_parser_t *pctx, cfg_obj_t *obj);
00068
00069 static isc_result_t
00070 parse_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
00071
00072 static void
00073 print_list(cfg_printer_t *pctx, const cfg_obj_t *obj);
00074
00075 static void
00076 free_list(cfg_parser_t *pctx, cfg_obj_t *obj);
00077
00078 static isc_result_t
00079 create_listelt(cfg_parser_t *pctx, cfg_listelt_t **eltp);
00080
00081 static isc_result_t
00082 create_string(cfg_parser_t *pctx, const char *contents, const cfg_type_t *type,
00083 cfg_obj_t **ret);
00084
00085 static void
00086 free_string(cfg_parser_t *pctx, cfg_obj_t *obj);
00087
00088 static isc_result_t
00089 create_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **objp);
00090
00091 static void
00092 free_map(cfg_parser_t *pctx, cfg_obj_t *obj);
00093
00094 static isc_result_t
00095 parse_symtab_elt(cfg_parser_t *pctx, const char *name,
00096 cfg_type_t *elttype, isc_symtab_t *symtab,
00097 isc_boolean_t callback);
00098
00099 static void
00100 free_noop(cfg_parser_t *pctx, cfg_obj_t *obj);
00101
00102 static isc_result_t
00103 cfg_getstringtoken(cfg_parser_t *pctx);
00104
00105 static void
00106 parser_complain(cfg_parser_t *pctx, isc_boolean_t is_warning,
00107 unsigned int flags, const char *format, va_list args);
00108
00109
00110
00111
00112
00113
00114
00115 cfg_rep_t cfg_rep_uint32 = { "uint32", free_noop };
00116 cfg_rep_t cfg_rep_uint64 = { "uint64", free_noop };
00117 cfg_rep_t cfg_rep_string = { "string", free_string };
00118 cfg_rep_t cfg_rep_boolean = { "boolean", free_noop };
00119 cfg_rep_t cfg_rep_map = { "map", free_map };
00120 cfg_rep_t cfg_rep_list = { "list", free_list };
00121 cfg_rep_t cfg_rep_tuple = { "tuple", free_tuple };
00122 cfg_rep_t cfg_rep_sockaddr = { "sockaddr", free_noop };
00123 cfg_rep_t cfg_rep_netprefix = { "netprefix", free_noop };
00124 cfg_rep_t cfg_rep_void = { "void", free_noop };
00125
00126
00127
00128
00129
00130
00131
00132
00133 static cfg_type_t cfg_type_implicitlist = {
00134 "implicitlist", NULL, print_list, NULL, &cfg_rep_list, NULL };
00135
00136
00137
00138 void
00139 cfg_print_obj(cfg_printer_t *pctx, const cfg_obj_t *obj) {
00140 obj->type->print(pctx, obj);
00141 }
00142
00143 void
00144 cfg_print_chars(cfg_printer_t *pctx, const char *text, int len) {
00145 pctx->f(pctx->closure, text, len);
00146 }
00147
00148 static void
00149 print_open(cfg_printer_t *pctx) {
00150 if ((pctx->flags & CFG_PRINTER_ONELINE) != 0)
00151 cfg_print_cstr(pctx, "{ ");
00152 else {
00153 cfg_print_cstr(pctx, "{\n");
00154 pctx->indent++;
00155 }
00156 }
00157
00158 static void
00159 print_indent(cfg_printer_t *pctx) {
00160 int indent = pctx->indent;
00161 if ((pctx->flags & CFG_PRINTER_ONELINE) != 0) {
00162 cfg_print_cstr(pctx, " ");
00163 return;
00164 }
00165 while (indent > 0) {
00166 cfg_print_cstr(pctx, "\t");
00167 indent--;
00168 }
00169 }
00170
00171 static void
00172 print_close(cfg_printer_t *pctx) {
00173 if ((pctx->flags & CFG_PRINTER_ONELINE) == 0) {
00174 pctx->indent--;
00175 print_indent(pctx);
00176 }
00177 cfg_print_cstr(pctx, "}");
00178 }
00179
00180 isc_result_t
00181 cfg_parse_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
00182 isc_result_t result;
00183 INSIST(ret != NULL && *ret == NULL);
00184 result = type->parse(pctx, type, ret);
00185 if (result != ISC_R_SUCCESS)
00186 return (result);
00187 INSIST(*ret != NULL);
00188 return (ISC_R_SUCCESS);
00189 }
00190
00191 void
00192 cfg_print(const cfg_obj_t *obj,
00193 void (*f)(void *closure, const char *text, int textlen),
00194 void *closure)
00195 {
00196 cfg_printx(obj, 0, f, closure);
00197 }
00198
00199 void
00200 cfg_printx(const cfg_obj_t *obj, unsigned int flags,
00201 void (*f)(void *closure, const char *text, int textlen),
00202 void *closure)
00203 {
00204 cfg_printer_t pctx;
00205 pctx.f = f;
00206 pctx.closure = closure;
00207 pctx.indent = 0;
00208 pctx.flags = flags;
00209 obj->type->print(&pctx, obj);
00210 }
00211
00212
00213
00214 isc_result_t
00215 cfg_create_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
00216 isc_result_t result;
00217 const cfg_tuplefielddef_t *fields = type->of;
00218 const cfg_tuplefielddef_t *f;
00219 cfg_obj_t *obj = NULL;
00220 unsigned int nfields = 0;
00221 int i;
00222
00223 for (f = fields; f->name != NULL; f++)
00224 nfields++;
00225
00226 CHECK(cfg_create_obj(pctx, type, &obj));
00227 obj->value.tuple = isc_mem_get(pctx->mctx,
00228 nfields * sizeof(cfg_obj_t *));
00229 if (obj->value.tuple == NULL) {
00230 result = ISC_R_NOMEMORY;
00231 goto cleanup;
00232 }
00233 for (f = fields, i = 0; f->name != NULL; f++, i++)
00234 obj->value.tuple[i] = NULL;
00235 *ret = obj;
00236 return (ISC_R_SUCCESS);
00237
00238 cleanup:
00239 if (obj != NULL)
00240 isc_mem_put(pctx->mctx, obj, sizeof(*obj));
00241 return (result);
00242 }
00243
00244 isc_result_t
00245 cfg_parse_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret)
00246 {
00247 isc_result_t result;
00248 const cfg_tuplefielddef_t *fields = type->of;
00249 const cfg_tuplefielddef_t *f;
00250 cfg_obj_t *obj = NULL;
00251 unsigned int i;
00252
00253 CHECK(cfg_create_tuple(pctx, type, &obj));
00254 for (f = fields, i = 0; f->name != NULL; f++, i++)
00255 CHECK(cfg_parse_obj(pctx, f->type, &obj->value.tuple[i]));
00256
00257 *ret = obj;
00258 return (ISC_R_SUCCESS);
00259
00260 cleanup:
00261 CLEANUP_OBJ(obj);
00262 return (result);
00263 }
00264
00265 void
00266 cfg_print_tuple(cfg_printer_t *pctx, const cfg_obj_t *obj) {
00267 unsigned int i;
00268 const cfg_tuplefielddef_t *fields = obj->type->of;
00269 const cfg_tuplefielddef_t *f;
00270 isc_boolean_t need_space = ISC_FALSE;
00271
00272 for (f = fields, i = 0; f->name != NULL; f++, i++) {
00273 const cfg_obj_t *fieldobj = obj->value.tuple[i];
00274 if (need_space)
00275 cfg_print_cstr(pctx, " ");
00276 cfg_print_obj(pctx, fieldobj);
00277 need_space = ISC_TF(fieldobj->type->print != cfg_print_void);
00278 }
00279 }
00280
00281 void
00282 cfg_doc_tuple(cfg_printer_t *pctx, const cfg_type_t *type) {
00283 const cfg_tuplefielddef_t *fields = type->of;
00284 const cfg_tuplefielddef_t *f;
00285 isc_boolean_t need_space = ISC_FALSE;
00286
00287 for (f = fields; f->name != NULL; f++) {
00288 if (need_space)
00289 cfg_print_cstr(pctx, " ");
00290 cfg_doc_obj(pctx, f->type);
00291 need_space = ISC_TF(f->type->print != cfg_print_void);
00292 }
00293 }
00294
00295 static void
00296 free_tuple(cfg_parser_t *pctx, cfg_obj_t *obj) {
00297 unsigned int i;
00298 const cfg_tuplefielddef_t *fields = obj->type->of;
00299 const cfg_tuplefielddef_t *f;
00300 unsigned int nfields = 0;
00301
00302 if (obj->value.tuple == NULL)
00303 return;
00304
00305 for (f = fields, i = 0; f->name != NULL; f++, i++) {
00306 CLEANUP_OBJ(obj->value.tuple[i]);
00307 nfields++;
00308 }
00309 isc_mem_put(pctx->mctx, obj->value.tuple,
00310 nfields * sizeof(cfg_obj_t *));
00311 }
00312
00313 isc_boolean_t
00314 cfg_obj_istuple(const cfg_obj_t *obj) {
00315 REQUIRE(obj != NULL);
00316 return (ISC_TF(obj->type->rep == &cfg_rep_tuple));
00317 }
00318
00319 const cfg_obj_t *
00320 cfg_tuple_get(const cfg_obj_t *tupleobj, const char* name) {
00321 unsigned int i;
00322 const cfg_tuplefielddef_t *fields;
00323 const cfg_tuplefielddef_t *f;
00324
00325 REQUIRE(tupleobj != NULL && tupleobj->type->rep == &cfg_rep_tuple);
00326
00327 fields = tupleobj->type->of;
00328 for (f = fields, i = 0; f->name != NULL; f++, i++) {
00329 if (strcmp(f->name, name) == 0)
00330 return (tupleobj->value.tuple[i]);
00331 }
00332 INSIST(0);
00333 return (NULL);
00334 }
00335
00336 isc_result_t
00337 cfg_parse_special(cfg_parser_t *pctx, int special) {
00338 isc_result_t result;
00339 CHECK(cfg_gettoken(pctx, 0));
00340 if (pctx->token.type == isc_tokentype_special &&
00341 pctx->token.value.as_char == special)
00342 return (ISC_R_SUCCESS);
00343
00344 cfg_parser_error(pctx, CFG_LOG_NEAR, "'%c' expected", special);
00345 return (ISC_R_UNEXPECTEDTOKEN);
00346 cleanup:
00347 return (result);
00348 }
00349
00350
00351
00352
00353
00354
00355
00356
00357 static isc_result_t
00358 parse_semicolon(cfg_parser_t *pctx) {
00359 isc_result_t result;
00360 CHECK(cfg_gettoken(pctx, 0));
00361 if (pctx->token.type == isc_tokentype_special &&
00362 pctx->token.value.as_char == ';')
00363 return (ISC_R_SUCCESS);
00364
00365 cfg_parser_error(pctx, CFG_LOG_BEFORE, "missing ';'");
00366 cfg_ungettoken(pctx);
00367 cleanup:
00368 return (result);
00369 }
00370
00371
00372
00373
00374 static isc_result_t
00375 parse_eof(cfg_parser_t *pctx) {
00376 isc_result_t result;
00377 CHECK(cfg_gettoken(pctx, 0));
00378
00379 if (pctx->token.type == isc_tokentype_eof)
00380 return (ISC_R_SUCCESS);
00381
00382 cfg_parser_error(pctx, CFG_LOG_NEAR, "syntax error");
00383 return (ISC_R_UNEXPECTEDTOKEN);
00384 cleanup:
00385 return (result);
00386 }
00387
00388
00389
00390 static cfg_type_t cfg_type_filelist = {
00391 "filelist", NULL, print_list, NULL, &cfg_rep_list,
00392 &cfg_type_qstring
00393 };
00394
00395 isc_result_t
00396 cfg_parser_create(isc_mem_t *mctx, isc_log_t *lctx, cfg_parser_t **ret) {
00397 isc_result_t result;
00398 cfg_parser_t *pctx;
00399 isc_lexspecials_t specials;
00400
00401 REQUIRE(mctx != NULL);
00402 REQUIRE(ret != NULL && *ret == NULL);
00403
00404 pctx = isc_mem_get(mctx, sizeof(*pctx));
00405 if (pctx == NULL)
00406 return (ISC_R_NOMEMORY);
00407
00408 pctx->mctx = NULL;
00409 isc_mem_attach(mctx, &pctx->mctx);
00410
00411 result = isc_refcount_init(&pctx->references, 1);
00412 if (result != ISC_R_SUCCESS) {
00413 isc_mem_putanddetach(&pctx->mctx, pctx, sizeof(*pctx));
00414 return (result);
00415 }
00416
00417 pctx->lctx = lctx;
00418 pctx->lexer = NULL;
00419 pctx->seen_eof = ISC_FALSE;
00420 pctx->ungotten = ISC_FALSE;
00421 pctx->errors = 0;
00422 pctx->warnings = 0;
00423 pctx->open_files = NULL;
00424 pctx->closed_files = NULL;
00425 pctx->line = 0;
00426 pctx->callback = NULL;
00427 pctx->callbackarg = NULL;
00428 pctx->token.type = isc_tokentype_unknown;
00429 pctx->flags = 0;
00430
00431 memset(specials, 0, sizeof(specials));
00432 specials['{'] = 1;
00433 specials['}'] = 1;
00434 specials[';'] = 1;
00435 specials['/'] = 1;
00436 specials['"'] = 1;
00437 specials['!'] = 1;
00438
00439 CHECK(isc_lex_create(pctx->mctx, 1024, &pctx->lexer));
00440
00441 isc_lex_setspecials(pctx->lexer, specials);
00442 isc_lex_setcomments(pctx->lexer, (ISC_LEXCOMMENT_C |
00443 ISC_LEXCOMMENT_CPLUSPLUS |
00444 ISC_LEXCOMMENT_SHELL));
00445
00446 CHECK(cfg_create_list(pctx, &cfg_type_filelist, &pctx->open_files));
00447 CHECK(cfg_create_list(pctx, &cfg_type_filelist, &pctx->closed_files));
00448
00449 *ret = pctx;
00450 return (ISC_R_SUCCESS);
00451
00452 cleanup:
00453 if (pctx->lexer != NULL)
00454 isc_lex_destroy(&pctx->lexer);
00455 CLEANUP_OBJ(pctx->open_files);
00456 CLEANUP_OBJ(pctx->closed_files);
00457 isc_mem_putanddetach(&pctx->mctx, pctx, sizeof(*pctx));
00458 return (result);
00459 }
00460
00461 static isc_result_t
00462 parser_openfile(cfg_parser_t *pctx, const char *filename) {
00463 isc_result_t result;
00464 cfg_listelt_t *elt = NULL;
00465 cfg_obj_t *stringobj = NULL;
00466
00467 result = isc_lex_openfile(pctx->lexer, filename);
00468 if (result != ISC_R_SUCCESS) {
00469 cfg_parser_error(pctx, 0, "open: %s: %s",
00470 filename, isc_result_totext(result));
00471 goto cleanup;
00472 }
00473
00474 CHECK(create_string(pctx, filename, &cfg_type_qstring, &stringobj));
00475 CHECK(create_listelt(pctx, &elt));
00476 elt->obj = stringobj;
00477 ISC_LIST_APPEND(pctx->open_files->value.list, elt, link);
00478
00479 return (ISC_R_SUCCESS);
00480 cleanup:
00481 CLEANUP_OBJ(stringobj);
00482 return (result);
00483 }
00484
00485 void
00486 cfg_parser_setcallback(cfg_parser_t *pctx,
00487 cfg_parsecallback_t callback,
00488 void *arg)
00489 {
00490 pctx->callback = callback;
00491 pctx->callbackarg = arg;
00492 }
00493
00494 void
00495 cfg_parser_reset(cfg_parser_t *pctx) {
00496 REQUIRE(pctx != NULL);
00497
00498 if (pctx->lexer != NULL)
00499 isc_lex_close(pctx->lexer);
00500
00501 pctx->seen_eof = ISC_FALSE;
00502 pctx->ungotten = ISC_FALSE;
00503 pctx->errors = 0;
00504 pctx->warnings = 0;
00505 pctx->line = 0;
00506 }
00507
00508
00509
00510
00511
00512 static isc_result_t
00513 parse2(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
00514 isc_result_t result;
00515 cfg_obj_t *obj = NULL;
00516
00517 result = cfg_parse_obj(pctx, type, &obj);
00518
00519 if (pctx->errors != 0) {
00520
00521 if (result == ISC_R_SUCCESS)
00522 result = ISC_R_FAILURE;
00523 goto cleanup;
00524 }
00525
00526 if (result != ISC_R_SUCCESS) {
00527
00528 cfg_parser_error(pctx, 0, "parsing failed");
00529 goto cleanup;
00530 }
00531
00532 CHECK(parse_eof(pctx));
00533
00534 *ret = obj;
00535 return (ISC_R_SUCCESS);
00536
00537 cleanup:
00538 CLEANUP_OBJ(obj);
00539 return (result);
00540 }
00541
00542 isc_result_t
00543 cfg_parse_file(cfg_parser_t *pctx, const char *filename,
00544 const cfg_type_t *type, cfg_obj_t **ret)
00545 {
00546 isc_result_t result;
00547
00548 REQUIRE(filename != NULL);
00549
00550 CHECK(parser_openfile(pctx, filename));
00551 CHECK(parse2(pctx, type, ret));
00552 cleanup:
00553 return (result);
00554 }
00555
00556
00557 isc_result_t
00558 cfg_parse_buffer(cfg_parser_t *pctx, isc_buffer_t *buffer,
00559 const cfg_type_t *type, cfg_obj_t **ret)
00560 {
00561 isc_result_t result;
00562
00563 REQUIRE(buffer != NULL);
00564
00565 CHECK(isc_lex_openbuffer(pctx->lexer, buffer));
00566 CHECK(parse2(pctx, type, ret));
00567
00568 cleanup:
00569 return (result);
00570 }
00571
00572 void
00573 cfg_parser_attach(cfg_parser_t *src, cfg_parser_t **dest) {
00574 REQUIRE(src != NULL);
00575 REQUIRE(dest != NULL && *dest == NULL);
00576 isc_refcount_increment(&src->references, NULL);
00577 *dest = src;
00578 }
00579
00580 void
00581 cfg_parser_destroy(cfg_parser_t **pctxp) {
00582 cfg_parser_t *pctx = *pctxp;
00583 unsigned int refs;
00584
00585 isc_refcount_decrement(&pctx->references, &refs);
00586 if (refs == 0) {
00587 isc_lex_destroy(&pctx->lexer);
00588
00589
00590
00591
00592
00593 CLEANUP_OBJ(pctx->open_files);
00594 CLEANUP_OBJ(pctx->closed_files);
00595 isc_mem_putanddetach(&pctx->mctx, pctx, sizeof(*pctx));
00596 }
00597 *pctxp = NULL;
00598 }
00599
00600
00601
00602
00603 isc_result_t
00604 cfg_parse_void(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
00605 UNUSED(type);
00606 return (cfg_create_obj(pctx, &cfg_type_void, ret));
00607 }
00608
00609 void
00610 cfg_print_void(cfg_printer_t *pctx, const cfg_obj_t *obj) {
00611 UNUSED(pctx);
00612 UNUSED(obj);
00613 }
00614
00615 void
00616 cfg_doc_void(cfg_printer_t *pctx, const cfg_type_t *type) {
00617 UNUSED(pctx);
00618 UNUSED(type);
00619 }
00620
00621 isc_boolean_t
00622 cfg_obj_isvoid(const cfg_obj_t *obj) {
00623 REQUIRE(obj != NULL);
00624 return (ISC_TF(obj->type->rep == &cfg_rep_void));
00625 }
00626
00627 cfg_type_t cfg_type_void = {
00628 "void", cfg_parse_void, cfg_print_void, cfg_doc_void, &cfg_rep_void,
00629 NULL };
00630
00631
00632
00633
00634
00635 isc_result_t
00636 cfg_parse_uint32(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
00637 isc_result_t result;
00638 cfg_obj_t *obj = NULL;
00639 UNUSED(type);
00640
00641 CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER));
00642 if (pctx->token.type != isc_tokentype_number) {
00643 cfg_parser_error(pctx, CFG_LOG_NEAR, "expected number");
00644 return (ISC_R_UNEXPECTEDTOKEN);
00645 }
00646
00647 CHECK(cfg_create_obj(pctx, &cfg_type_uint32, &obj));
00648
00649 obj->value.uint32 = pctx->token.value.as_ulong;
00650 *ret = obj;
00651 cleanup:
00652 return (result);
00653 }
00654
00655 void
00656 cfg_print_cstr(cfg_printer_t *pctx, const char *s) {
00657 cfg_print_chars(pctx, s, strlen(s));
00658 }
00659
00660 void
00661 cfg_print_rawuint(cfg_printer_t *pctx, unsigned int u) {
00662 char buf[32];
00663 snprintf(buf, sizeof(buf), "%u", u);
00664 cfg_print_cstr(pctx, buf);
00665 }
00666
00667 void
00668 cfg_print_uint32(cfg_printer_t *pctx, const cfg_obj_t *obj) {
00669 cfg_print_rawuint(pctx, obj->value.uint32);
00670 }
00671
00672 isc_boolean_t
00673 cfg_obj_isuint32(const cfg_obj_t *obj) {
00674 REQUIRE(obj != NULL);
00675 return (ISC_TF(obj->type->rep == &cfg_rep_uint32));
00676 }
00677
00678 isc_uint32_t
00679 cfg_obj_asuint32(const cfg_obj_t *obj) {
00680 REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_uint32);
00681 return (obj->value.uint32);
00682 }
00683
00684 cfg_type_t cfg_type_uint32 = {
00685 "integer", cfg_parse_uint32, cfg_print_uint32, cfg_doc_terminal,
00686 &cfg_rep_uint32, NULL
00687 };
00688
00689
00690
00691
00692
00693 isc_boolean_t
00694 cfg_obj_isuint64(const cfg_obj_t *obj) {
00695 REQUIRE(obj != NULL);
00696 return (ISC_TF(obj->type->rep == &cfg_rep_uint64));
00697 }
00698
00699 isc_uint64_t
00700 cfg_obj_asuint64(const cfg_obj_t *obj) {
00701 REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_uint64);
00702 return (obj->value.uint64);
00703 }
00704
00705 void
00706 cfg_print_uint64(cfg_printer_t *pctx, const cfg_obj_t *obj) {
00707 char buf[32];
00708 snprintf(buf, sizeof(buf), "%" ISC_PRINT_QUADFORMAT "u",
00709 obj->value.uint64);
00710 cfg_print_cstr(pctx, buf);
00711 }
00712
00713 cfg_type_t cfg_type_uint64 = {
00714 "64_bit_integer", NULL, cfg_print_uint64, cfg_doc_terminal,
00715 &cfg_rep_uint64, NULL
00716 };
00717
00718
00719
00720
00721
00722
00723
00724 static isc_result_t
00725 create_string(cfg_parser_t *pctx, const char *contents, const cfg_type_t *type,
00726 cfg_obj_t **ret)
00727 {
00728 isc_result_t result;
00729 cfg_obj_t *obj = NULL;
00730 int len;
00731
00732 CHECK(cfg_create_obj(pctx, type, &obj));
00733 len = strlen(contents);
00734 obj->value.string.length = len;
00735 obj->value.string.base = isc_mem_get(pctx->mctx, len + 1);
00736 if (obj->value.string.base == 0) {
00737 isc_mem_put(pctx->mctx, obj, sizeof(*obj));
00738 return (ISC_R_NOMEMORY);
00739 }
00740 memmove(obj->value.string.base, contents, len);
00741 obj->value.string.base[len] = '\0';
00742
00743 *ret = obj;
00744 cleanup:
00745 return (result);
00746 }
00747
00748 isc_result_t
00749 cfg_parse_qstring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
00750 isc_result_t result;
00751 UNUSED(type);
00752
00753 CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
00754 if (pctx->token.type != isc_tokentype_qstring) {
00755 cfg_parser_error(pctx, CFG_LOG_NEAR, "expected quoted string");
00756 return (ISC_R_UNEXPECTEDTOKEN);
00757 }
00758 return (create_string(pctx,
00759 TOKEN_STRING(pctx),
00760 &cfg_type_qstring,
00761 ret));
00762 cleanup:
00763 return (result);
00764 }
00765
00766 static isc_result_t
00767 parse_ustring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
00768 isc_result_t result;
00769 UNUSED(type);
00770
00771 CHECK(cfg_gettoken(pctx, 0));
00772 if (pctx->token.type != isc_tokentype_string) {
00773 cfg_parser_error(pctx, CFG_LOG_NEAR, "expected unquoted string");
00774 return (ISC_R_UNEXPECTEDTOKEN);
00775 }
00776 return (create_string(pctx,
00777 TOKEN_STRING(pctx),
00778 &cfg_type_ustring,
00779 ret));
00780 cleanup:
00781 return (result);
00782 }
00783
00784 isc_result_t
00785 cfg_parse_astring(cfg_parser_t *pctx, const cfg_type_t *type,
00786 cfg_obj_t **ret)
00787 {
00788 isc_result_t result;
00789 UNUSED(type);
00790
00791 CHECK(cfg_getstringtoken(pctx));
00792 return (create_string(pctx,
00793 TOKEN_STRING(pctx),
00794 &cfg_type_qstring,
00795 ret));
00796 cleanup:
00797 return (result);
00798 }
00799
00800 isc_result_t
00801 cfg_parse_sstring(cfg_parser_t *pctx, const cfg_type_t *type,
00802 cfg_obj_t **ret)
00803 {
00804 isc_result_t result;
00805 UNUSED(type);
00806
00807 CHECK(cfg_getstringtoken(pctx));
00808 return (create_string(pctx,
00809 TOKEN_STRING(pctx),
00810 &cfg_type_sstring,
00811 ret));
00812 cleanup:
00813 return (result);
00814 }
00815
00816 isc_boolean_t
00817 cfg_is_enum(const char *s, const char *const *enums) {
00818 const char * const *p;
00819 for (p = enums; *p != NULL; p++) {
00820 if (strcasecmp(*p, s) == 0)
00821 return (ISC_TRUE);
00822 }
00823 return (ISC_FALSE);
00824 }
00825
00826 static isc_result_t
00827 check_enum(cfg_parser_t *pctx, cfg_obj_t *obj, const char *const *enums) {
00828 const char *s = obj->value.string.base;
00829 if (cfg_is_enum(s, enums))
00830 return (ISC_R_SUCCESS);
00831 cfg_parser_error(pctx, 0, "'%s' unexpected", s);
00832 return (ISC_R_UNEXPECTEDTOKEN);
00833 }
00834
00835 isc_result_t
00836 cfg_parse_enum(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
00837 isc_result_t result;
00838 cfg_obj_t *obj = NULL;
00839 CHECK(parse_ustring(pctx, NULL, &obj));
00840 CHECK(check_enum(pctx, obj, type->of));
00841 *ret = obj;
00842 return (ISC_R_SUCCESS);
00843 cleanup:
00844 CLEANUP_OBJ(obj);
00845 return (result);
00846 }
00847
00848 void
00849 cfg_doc_enum(cfg_printer_t *pctx, const cfg_type_t *type) {
00850 const char * const *p;
00851 cfg_print_cstr(pctx, "( ");
00852 for (p = type->of; *p != NULL; p++) {
00853 cfg_print_cstr(pctx, *p);
00854 if (p[1] != NULL)
00855 cfg_print_cstr(pctx, " | ");
00856 }
00857 cfg_print_cstr(pctx, " )");
00858 }
00859
00860 void
00861 cfg_print_ustring(cfg_printer_t *pctx, const cfg_obj_t *obj) {
00862 cfg_print_chars(pctx, obj->value.string.base, obj->value.string.length);
00863 }
00864
00865 static void
00866 print_qstring(cfg_printer_t *pctx, const cfg_obj_t *obj) {
00867 cfg_print_cstr(pctx, "\"");
00868 cfg_print_ustring(pctx, obj);
00869 cfg_print_cstr(pctx, "\"");
00870 }
00871
00872 static void
00873 print_sstring(cfg_printer_t *pctx, const cfg_obj_t *obj) {
00874 cfg_print_cstr(pctx, "\"");
00875 if ((pctx->flags & CFG_PRINTER_XKEY) != 0) {
00876 unsigned int len = obj->value.string.length;
00877 while (len-- > 0)
00878 cfg_print_cstr(pctx, "?");
00879 } else
00880 cfg_print_ustring(pctx, obj);
00881 cfg_print_cstr(pctx, "\"");
00882 }
00883
00884 static void
00885 free_string(cfg_parser_t *pctx, cfg_obj_t *obj) {
00886 isc_mem_put(pctx->mctx, obj->value.string.base,
00887 obj->value.string.length + 1);
00888 }
00889
00890 isc_boolean_t
00891 cfg_obj_isstring(const cfg_obj_t *obj) {
00892 REQUIRE(obj != NULL);
00893 return (ISC_TF(obj->type->rep == &cfg_rep_string));
00894 }
00895
00896 const char *
00897 cfg_obj_asstring(const cfg_obj_t *obj) {
00898 REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_string);
00899 return (obj->value.string.base);
00900 }
00901
00902
00903 cfg_type_t cfg_type_qstring = {
00904 "quoted_string", cfg_parse_qstring, print_qstring, cfg_doc_terminal,
00905 &cfg_rep_string, NULL
00906 };
00907
00908
00909 cfg_type_t cfg_type_ustring = {
00910 "string", parse_ustring, cfg_print_ustring, cfg_doc_terminal,
00911 &cfg_rep_string, NULL
00912 };
00913
00914
00915 cfg_type_t cfg_type_astring = {
00916 "string", cfg_parse_astring, print_qstring, cfg_doc_terminal,
00917 &cfg_rep_string, NULL
00918 };
00919
00920
00921
00922
00923
00924 cfg_type_t cfg_type_sstring = {
00925 "string", cfg_parse_sstring, print_sstring, cfg_doc_terminal,
00926 &cfg_rep_string, NULL
00927 };
00928
00929
00930
00931
00932
00933 isc_boolean_t
00934 cfg_obj_isboolean(const cfg_obj_t *obj) {
00935 REQUIRE(obj != NULL);
00936 return (ISC_TF(obj->type->rep == &cfg_rep_boolean));
00937 }
00938
00939 isc_boolean_t
00940 cfg_obj_asboolean(const cfg_obj_t *obj) {
00941 REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_boolean);
00942 return (obj->value.boolean);
00943 }
00944
00945 isc_result_t
00946 cfg_parse_boolean(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret)
00947 {
00948 isc_result_t result;
00949 isc_boolean_t value;
00950 cfg_obj_t *obj = NULL;
00951 UNUSED(type);
00952
00953 result = cfg_gettoken(pctx, 0);
00954 if (result != ISC_R_SUCCESS)
00955 return (result);
00956
00957 if (pctx->token.type != isc_tokentype_string)
00958 goto bad_boolean;
00959
00960 if ((strcasecmp(TOKEN_STRING(pctx), "true") == 0) ||
00961 (strcasecmp(TOKEN_STRING(pctx), "yes") == 0) ||
00962 (strcmp(TOKEN_STRING(pctx), "1") == 0)) {
00963 value = ISC_TRUE;
00964 } else if ((strcasecmp(TOKEN_STRING(pctx), "false") == 0) ||
00965 (strcasecmp(TOKEN_STRING(pctx), "no") == 0) ||
00966 (strcmp(TOKEN_STRING(pctx), "0") == 0)) {
00967 value = ISC_FALSE;
00968 } else {
00969 goto bad_boolean;
00970 }
00971
00972 CHECK(cfg_create_obj(pctx, &cfg_type_boolean, &obj));
00973 obj->value.boolean = value;
00974 *ret = obj;
00975 return (result);
00976
00977 bad_boolean:
00978 cfg_parser_error(pctx, CFG_LOG_NEAR, "boolean expected");
00979 return (ISC_R_UNEXPECTEDTOKEN);
00980
00981 cleanup:
00982 return (result);
00983 }
00984
00985 void
00986 cfg_print_boolean(cfg_printer_t *pctx, const cfg_obj_t *obj) {
00987 if (obj->value.boolean)
00988 cfg_print_cstr(pctx, "yes");
00989 else
00990 cfg_print_cstr(pctx, "no");
00991 }
00992
00993 cfg_type_t cfg_type_boolean = {
00994 "boolean", cfg_parse_boolean, cfg_print_boolean, cfg_doc_terminal,
00995 &cfg_rep_boolean, NULL
00996 };
00997
00998
00999
01000
01001
01002 isc_result_t
01003 cfg_create_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **obj) {
01004 isc_result_t result;
01005 CHECK(cfg_create_obj(pctx, type, obj));
01006 ISC_LIST_INIT((*obj)->value.list);
01007 cleanup:
01008 return (result);
01009 }
01010
01011 static isc_result_t
01012 create_listelt(cfg_parser_t *pctx, cfg_listelt_t **eltp) {
01013 cfg_listelt_t *elt;
01014 elt = isc_mem_get(pctx->mctx, sizeof(*elt));
01015 if (elt == NULL)
01016 return (ISC_R_NOMEMORY);
01017 elt->obj = NULL;
01018 ISC_LINK_INIT(elt, link);
01019 *eltp = elt;
01020 return (ISC_R_SUCCESS);
01021 }
01022
01023 static void
01024 free_listelt(cfg_parser_t *pctx, cfg_listelt_t *elt) {
01025 if (elt->obj != NULL)
01026 cfg_obj_destroy(pctx, &elt->obj);
01027 isc_mem_put(pctx->mctx, elt, sizeof(*elt));
01028 }
01029
01030 static void
01031 free_list(cfg_parser_t *pctx, cfg_obj_t *obj) {
01032 cfg_listelt_t *elt, *next;
01033 for (elt = ISC_LIST_HEAD(obj->value.list);
01034 elt != NULL;
01035 elt = next)
01036 {
01037 next = ISC_LIST_NEXT(elt, link);
01038 free_listelt(pctx, elt);
01039 }
01040 }
01041
01042 isc_result_t
01043 cfg_parse_listelt(cfg_parser_t *pctx, const cfg_type_t *elttype,
01044 cfg_listelt_t **ret)
01045 {
01046 isc_result_t result;
01047 cfg_listelt_t *elt = NULL;
01048 cfg_obj_t *value = NULL;
01049
01050 CHECK(create_listelt(pctx, &elt));
01051
01052 result = cfg_parse_obj(pctx, elttype, &value);
01053 if (result != ISC_R_SUCCESS)
01054 goto cleanup;
01055
01056 elt->obj = value;
01057
01058 *ret = elt;
01059 return (ISC_R_SUCCESS);
01060
01061 cleanup:
01062 isc_mem_put(pctx->mctx, elt, sizeof(*elt));
01063 return (result);
01064 }
01065
01066
01067
01068
01069
01070 static isc_result_t
01071 parse_list(cfg_parser_t *pctx, const cfg_type_t *listtype, cfg_obj_t **ret)
01072 {
01073 cfg_obj_t *listobj = NULL;
01074 const cfg_type_t *listof = listtype->of;
01075 isc_result_t result;
01076 cfg_listelt_t *elt = NULL;
01077
01078 CHECK(cfg_create_list(pctx, listtype, &listobj));
01079
01080 for (;;) {
01081 CHECK(cfg_peektoken(pctx, 0));
01082 if (pctx->token.type == isc_tokentype_special &&
01083 pctx->token.value.as_char == '}')
01084 break;
01085 CHECK(cfg_parse_listelt(pctx, listof, &elt));
01086 CHECK(parse_semicolon(pctx));
01087 ISC_LIST_APPEND(listobj->value.list, elt, link);
01088 elt = NULL;
01089 }
01090 *ret = listobj;
01091 return (ISC_R_SUCCESS);
01092
01093 cleanup:
01094 if (elt != NULL)
01095 free_listelt(pctx, elt);
01096 CLEANUP_OBJ(listobj);
01097 return (result);
01098 }
01099
01100 static void
01101 print_list(cfg_printer_t *pctx, const cfg_obj_t *obj) {
01102 const cfg_list_t *list = &obj->value.list;
01103 const cfg_listelt_t *elt;
01104
01105 for (elt = ISC_LIST_HEAD(*list);
01106 elt != NULL;
01107 elt = ISC_LIST_NEXT(elt, link))
01108 {
01109 if ((pctx->flags & CFG_PRINTER_ONELINE) != 0) {
01110 cfg_print_obj(pctx, elt->obj);
01111 cfg_print_cstr(pctx, "; ");
01112 } else {
01113 print_indent(pctx);
01114 cfg_print_obj(pctx, elt->obj);
01115 cfg_print_cstr(pctx, ";\n");
01116 }
01117 }
01118 }
01119
01120 isc_result_t
01121 cfg_parse_bracketed_list(cfg_parser_t *pctx, const cfg_type_t *type,
01122 cfg_obj_t **ret)
01123 {
01124 isc_result_t result;
01125 CHECK(cfg_parse_special(pctx, '{'));
01126 CHECK(parse_list(pctx, type, ret));
01127 CHECK(cfg_parse_special(pctx, '}'));
01128 cleanup:
01129 return (result);
01130 }
01131
01132 void
01133 cfg_print_bracketed_list(cfg_printer_t *pctx, const cfg_obj_t *obj) {
01134 print_open(pctx);
01135 print_list(pctx, obj);
01136 print_close(pctx);
01137 }
01138
01139 void
01140 cfg_doc_bracketed_list(cfg_printer_t *pctx, const cfg_type_t *type) {
01141 cfg_print_cstr(pctx, "{ ");
01142 cfg_doc_obj(pctx, type->of);
01143 cfg_print_cstr(pctx, "; ... }");
01144 }
01145
01146
01147
01148
01149
01150
01151 isc_result_t
01152 cfg_parse_spacelist(cfg_parser_t *pctx, const cfg_type_t *listtype,
01153 cfg_obj_t **ret)
01154 {
01155 cfg_obj_t *listobj = NULL;
01156 const cfg_type_t *listof = listtype->of;
01157 isc_result_t result;
01158
01159 CHECK(cfg_create_list(pctx, listtype, &listobj));
01160
01161 for (;;) {
01162 cfg_listelt_t *elt = NULL;
01163
01164 CHECK(cfg_peektoken(pctx, 0));
01165 if (pctx->token.type == isc_tokentype_special &&
01166 pctx->token.value.as_char == ';')
01167 break;
01168 CHECK(cfg_parse_listelt(pctx, listof, &elt));
01169 ISC_LIST_APPEND(listobj->value.list, elt, link);
01170 }
01171 *ret = listobj;
01172 return (ISC_R_SUCCESS);
01173
01174 cleanup:
01175 CLEANUP_OBJ(listobj);
01176 return (result);
01177 }
01178
01179 void
01180 cfg_print_spacelist(cfg_printer_t *pctx, const cfg_obj_t *obj) {
01181 const cfg_list_t *list = &obj->value.list;
01182 const cfg_listelt_t *elt;
01183
01184 for (elt = ISC_LIST_HEAD(*list);
01185 elt != NULL;
01186 elt = ISC_LIST_NEXT(elt, link)) {
01187 cfg_print_obj(pctx, elt->obj);
01188 if (ISC_LIST_NEXT(elt, link) != NULL)
01189 cfg_print_cstr(pctx, " ");
01190 }
01191 }
01192
01193 isc_boolean_t
01194 cfg_obj_islist(const cfg_obj_t *obj) {
01195 REQUIRE(obj != NULL);
01196 return (ISC_TF(obj->type->rep == &cfg_rep_list));
01197 }
01198
01199 const cfg_listelt_t *
01200 cfg_list_first(const cfg_obj_t *obj) {
01201 REQUIRE(obj == NULL || obj->type->rep == &cfg_rep_list);
01202 if (obj == NULL)
01203 return (NULL);
01204 return (ISC_LIST_HEAD(obj->value.list));
01205 }
01206
01207 const cfg_listelt_t *
01208 cfg_list_next(const cfg_listelt_t *elt) {
01209 REQUIRE(elt != NULL);
01210 return (ISC_LIST_NEXT(elt, link));
01211 }
01212
01213
01214
01215
01216
01217 unsigned int
01218 cfg_list_length(const cfg_obj_t *obj, isc_boolean_t recurse) {
01219 const cfg_listelt_t *elt;
01220 unsigned int count = 0;
01221
01222 if (obj == NULL || !cfg_obj_islist(obj))
01223 return (0U);
01224 for (elt = cfg_list_first(obj);
01225 elt != NULL;
01226 elt = cfg_list_next(elt)) {
01227 if (recurse && cfg_obj_islist(elt->obj)) {
01228 count += cfg_list_length(elt->obj, recurse);
01229 } else {
01230 count++;
01231 }
01232 }
01233 return (count);
01234 }
01235
01236 cfg_obj_t *
01237 cfg_listelt_value(const cfg_listelt_t *elt) {
01238 REQUIRE(elt != NULL);
01239 return (elt->obj);
01240 }
01241
01242
01243
01244
01245
01246
01247
01248
01249
01250
01251
01252
01253
01254
01255
01256 isc_result_t
01257 cfg_parse_mapbody(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret)
01258 {
01259 const cfg_clausedef_t * const *clausesets = type->of;
01260 isc_result_t result;
01261 const cfg_clausedef_t * const *clauseset;
01262 const cfg_clausedef_t *clause;
01263 cfg_obj_t *value = NULL;
01264 cfg_obj_t *obj = NULL;
01265 cfg_obj_t *eltobj = NULL;
01266 cfg_obj_t *includename = NULL;
01267 isc_symvalue_t symval;
01268 cfg_list_t *list = NULL;
01269
01270 CHECK(create_map(pctx, type, &obj));
01271
01272 obj->value.map.clausesets = clausesets;
01273
01274 for (;;) {
01275 cfg_listelt_t *elt;
01276
01277 redo:
01278
01279
01280
01281 CHECK(cfg_gettoken(pctx, 0));
01282
01283 if (pctx->token.type != isc_tokentype_string) {
01284 cfg_ungettoken(pctx);
01285 break;
01286 }
01287
01288
01289
01290
01291
01292 if (strcasecmp(TOKEN_STRING(pctx), "include") == 0) {
01293
01294
01295
01296
01297
01298 CHECK(cfg_parse_obj(pctx, &cfg_type_qstring, &includename));
01299 CHECK(parse_semicolon(pctx));
01300 CHECK(parser_openfile(pctx, includename->
01301 value.string.base));
01302 cfg_obj_destroy(pctx, &includename);
01303 goto redo;
01304 }
01305
01306 clause = NULL;
01307 for (clauseset = clausesets; *clauseset != NULL; clauseset++) {
01308 for (clause = *clauseset;
01309 clause->name != NULL;
01310 clause++) {
01311 if (strcasecmp(TOKEN_STRING(pctx),
01312 clause->name) == 0)
01313 goto done;
01314 }
01315 }
01316 done:
01317 if (clause == NULL || clause->name == NULL) {
01318 cfg_parser_error(pctx, CFG_LOG_NOPREP, "unknown option");
01319
01320
01321
01322
01323 CHECK(cfg_parse_obj(pctx, &cfg_type_unsupported, &eltobj));
01324 cfg_obj_destroy(pctx, &eltobj);
01325 CHECK(parse_semicolon(pctx));
01326 continue;
01327 }
01328
01329
01330
01331
01332 if ((clause->flags & CFG_CLAUSEFLAG_OBSOLETE) != 0)
01333 cfg_parser_warning(pctx, 0, "option '%s' is obsolete",
01334 clause->name);
01335 if ((clause->flags & CFG_CLAUSEFLAG_NOTIMP) != 0)
01336 cfg_parser_warning(pctx, 0, "option '%s' is "
01337 "not implemented", clause->name);
01338 if ((clause->flags & CFG_CLAUSEFLAG_NYI) != 0)
01339 cfg_parser_warning(pctx, 0, "option '%s' is "
01340 "not implemented", clause->name);
01341
01342 if ((clause->flags & CFG_CLAUSEFLAG_NOTCONFIGURED) != 0) {
01343 cfg_parser_warning(pctx, 0, "option '%s' was not "
01344 "enabled at compile time",
01345 clause->name);
01346 result = ISC_R_FAILURE;
01347 goto cleanup;
01348 }
01349
01350
01351
01352
01353
01354
01355
01356
01357 result = isc_symtab_lookup(obj->value.map.symtab,
01358 clause->name, 0, &symval);
01359
01360 if ((clause->flags & CFG_CLAUSEFLAG_MULTI) != 0) {
01361
01362 cfg_obj_t *listobj = NULL;
01363 if (result == ISC_R_NOTFOUND) {
01364 CHECK(cfg_create_list(pctx,
01365 &cfg_type_implicitlist,
01366 &listobj));
01367 symval.as_pointer = listobj;
01368 result = isc_symtab_define(obj->value.
01369 map.symtab,
01370 clause->name,
01371 1, symval,
01372 isc_symexists_reject);
01373 if (result != ISC_R_SUCCESS) {
01374 cfg_parser_error(pctx, CFG_LOG_NEAR,
01375 "isc_symtab_define(%s) "
01376 "failed", clause->name);
01377 isc_mem_put(pctx->mctx, list,
01378 sizeof(cfg_list_t));
01379 goto cleanup;
01380 }
01381 } else {
01382 INSIST(result == ISC_R_SUCCESS);
01383 listobj = symval.as_pointer;
01384 }
01385
01386 elt = NULL;
01387 CHECK(cfg_parse_listelt(pctx, clause->type, &elt));
01388 CHECK(parse_semicolon(pctx));
01389
01390 ISC_LIST_APPEND(listobj->value.list, elt, link);
01391 } else {
01392
01393 if (result == ISC_R_NOTFOUND) {
01394 isc_boolean_t callback =
01395 ISC_TF((clause->flags &
01396 CFG_CLAUSEFLAG_CALLBACK) != 0);
01397 CHECK(parse_symtab_elt(pctx, clause->name,
01398 clause->type,
01399 obj->value.map.symtab,
01400 callback));
01401 CHECK(parse_semicolon(pctx));
01402 } else if (result == ISC_R_SUCCESS) {
01403 cfg_parser_error(pctx, CFG_LOG_NEAR, "'%s' redefined",
01404 clause->name);
01405 result = ISC_R_EXISTS;
01406 goto cleanup;
01407 } else {
01408 cfg_parser_error(pctx, CFG_LOG_NEAR,
01409 "isc_symtab_define() failed");
01410 goto cleanup;
01411 }
01412 }
01413 }
01414
01415
01416 *ret = obj;
01417 return (ISC_R_SUCCESS);
01418
01419 cleanup:
01420 CLEANUP_OBJ(value);
01421 CLEANUP_OBJ(obj);
01422 CLEANUP_OBJ(eltobj);
01423 CLEANUP_OBJ(includename);
01424 return (result);
01425 }
01426
01427 static isc_result_t
01428 parse_symtab_elt(cfg_parser_t *pctx, const char *name,
01429 cfg_type_t *elttype, isc_symtab_t *symtab,
01430 isc_boolean_t callback)
01431 {
01432 isc_result_t result;
01433 cfg_obj_t *obj = NULL;
01434 isc_symvalue_t symval;
01435
01436 CHECK(cfg_parse_obj(pctx, elttype, &obj));
01437
01438 if (callback && pctx->callback != NULL)
01439 CHECK(pctx->callback(name, obj, pctx->callbackarg));
01440
01441 symval.as_pointer = obj;
01442 CHECK(isc_symtab_define(symtab, name,
01443 1, symval,
01444 isc_symexists_reject));
01445 return (ISC_R_SUCCESS);
01446
01447 cleanup:
01448 CLEANUP_OBJ(obj);
01449 return (result);
01450 }
01451
01452
01453
01454
01455 isc_result_t
01456 cfg_parse_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
01457 isc_result_t result;
01458 CHECK(cfg_parse_special(pctx, '{'));
01459 CHECK(cfg_parse_mapbody(pctx, type, ret));
01460 CHECK(cfg_parse_special(pctx, '}'));
01461 cleanup:
01462 return (result);
01463 }
01464
01465
01466
01467
01468 static isc_result_t
01469 parse_any_named_map(cfg_parser_t *pctx, cfg_type_t *nametype, const cfg_type_t *type,
01470 cfg_obj_t **ret)
01471 {
01472 isc_result_t result;
01473 cfg_obj_t *idobj = NULL;
01474 cfg_obj_t *mapobj = NULL;
01475
01476 CHECK(cfg_parse_obj(pctx, nametype, &idobj));
01477 CHECK(cfg_parse_map(pctx, type, &mapobj));
01478 mapobj->value.map.id = idobj;
01479 *ret = mapobj;
01480 return (result);
01481 cleanup:
01482 CLEANUP_OBJ(idobj);
01483 CLEANUP_OBJ(mapobj);
01484 return (result);
01485 }
01486
01487
01488
01489
01490
01491 isc_result_t
01492 cfg_parse_named_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
01493 return (parse_any_named_map(pctx, &cfg_type_astring, type, ret));
01494 }
01495
01496
01497
01498
01499
01500 isc_result_t
01501 cfg_parse_addressed_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
01502 return (parse_any_named_map(pctx, &cfg_type_netaddr, type, ret));
01503 }
01504
01505
01506
01507
01508
01509 isc_result_t
01510 cfg_parse_netprefix_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
01511 return (parse_any_named_map(pctx, &cfg_type_netprefix, type, ret));
01512 }
01513
01514 static void
01515 print_symval(cfg_printer_t *pctx, const char *name, cfg_obj_t *obj) {
01516 if ((pctx->flags & CFG_PRINTER_ONELINE) == 0)
01517 print_indent(pctx);
01518
01519 cfg_print_cstr(pctx, name);
01520 cfg_print_cstr(pctx, " ");
01521 cfg_print_obj(pctx, obj);
01522
01523 if ((pctx->flags & CFG_PRINTER_ONELINE) == 0)
01524 cfg_print_cstr(pctx, ";\n");
01525 else
01526 cfg_print_cstr(pctx, "; ");
01527 }
01528
01529 void
01530 cfg_print_mapbody(cfg_printer_t *pctx, const cfg_obj_t *obj) {
01531 isc_result_t result = ISC_R_SUCCESS;
01532 const cfg_clausedef_t * const *clauseset;
01533
01534 for (clauseset = obj->value.map.clausesets;
01535 *clauseset != NULL;
01536 clauseset++)
01537 {
01538 isc_symvalue_t symval;
01539 const cfg_clausedef_t *clause;
01540
01541 for (clause = *clauseset;
01542 clause->name != NULL;
01543 clause++) {
01544 result = isc_symtab_lookup(obj->value.map.symtab,
01545 clause->name, 0, &symval);
01546 if (result == ISC_R_SUCCESS) {
01547 cfg_obj_t *symobj = symval.as_pointer;
01548 if (symobj->type == &cfg_type_implicitlist) {
01549
01550 cfg_list_t *list = &symobj->value.list;
01551 cfg_listelt_t *elt;
01552 for (elt = ISC_LIST_HEAD(*list);
01553 elt != NULL;
01554 elt = ISC_LIST_NEXT(elt, link)) {
01555 print_symval(pctx,
01556 clause->name,
01557 elt->obj);
01558 }
01559 } else {
01560
01561 print_symval(pctx, clause->name,
01562 symobj);
01563 }
01564 } else if (result == ISC_R_NOTFOUND) {
01565 ;
01566 } else {
01567 INSIST(0);
01568 }
01569 }
01570 }
01571 }
01572
01573 void
01574 cfg_doc_mapbody(cfg_printer_t *pctx, const cfg_type_t *type) {
01575 const cfg_clausedef_t * const *clauseset;
01576 const cfg_clausedef_t *clause;
01577
01578 for (clauseset = type->of; *clauseset != NULL; clauseset++) {
01579 for (clause = *clauseset;
01580 clause->name != NULL;
01581 clause++) {
01582 cfg_print_cstr(pctx, clause->name);
01583 cfg_print_cstr(pctx, " ");
01584 cfg_doc_obj(pctx, clause->type);
01585
01586 cfg_print_cstr(pctx, ";\n\n");
01587 }
01588 }
01589 }
01590
01591 static struct flagtext {
01592 unsigned int flag;
01593 const char *text;
01594 } flagtexts[] = {
01595 { CFG_CLAUSEFLAG_NOTIMP, "not implemented" },
01596 { CFG_CLAUSEFLAG_NYI, "not yet implemented" },
01597 { CFG_CLAUSEFLAG_OBSOLETE, "obsolete" },
01598 { CFG_CLAUSEFLAG_NEWDEFAULT, "default changed" },
01599 { CFG_CLAUSEFLAG_TESTONLY, "test only" },
01600 { CFG_CLAUSEFLAG_NOTCONFIGURED, "not configured" },
01601 { 0, NULL }
01602 };
01603
01604 void
01605 cfg_print_map(cfg_printer_t *pctx, const cfg_obj_t *obj) {
01606 if (obj->value.map.id != NULL) {
01607 cfg_print_obj(pctx, obj->value.map.id);
01608 cfg_print_cstr(pctx, " ");
01609 }
01610 print_open(pctx);
01611 cfg_print_mapbody(pctx, obj);
01612 print_close(pctx);
01613 }
01614
01615 static void
01616 print_clause_flags(cfg_printer_t *pctx, unsigned int flags) {
01617 struct flagtext *p;
01618 isc_boolean_t first = ISC_TRUE;
01619 for (p = flagtexts; p->flag != 0; p++) {
01620 if ((flags & p->flag) != 0) {
01621 if (first)
01622 cfg_print_cstr(pctx, " // ");
01623 else
01624 cfg_print_cstr(pctx, ", ");
01625 cfg_print_cstr(pctx, p->text);
01626 first = ISC_FALSE;
01627 }
01628 }
01629 }
01630
01631 void
01632 cfg_doc_map(cfg_printer_t *pctx, const cfg_type_t *type) {
01633 const cfg_clausedef_t * const *clauseset;
01634 const cfg_clausedef_t *clause;
01635
01636 if (type->parse == cfg_parse_named_map) {
01637 cfg_doc_obj(pctx, &cfg_type_astring);
01638 cfg_print_cstr(pctx, " ");
01639 } else if (type->parse == cfg_parse_addressed_map) {
01640 cfg_doc_obj(pctx, &cfg_type_netaddr);
01641 cfg_print_cstr(pctx, " ");
01642 } else if (type->parse == cfg_parse_netprefix_map) {
01643 cfg_doc_obj(pctx, &cfg_type_netprefix);
01644 cfg_print_cstr(pctx, " ");
01645 }
01646
01647 print_open(pctx);
01648
01649 for (clauseset = type->of; *clauseset != NULL; clauseset++) {
01650 for (clause = *clauseset;
01651 clause->name != NULL;
01652 clause++) {
01653 print_indent(pctx);
01654 cfg_print_cstr(pctx, clause->name);
01655 if (clause->type->print != cfg_print_void)
01656 cfg_print_cstr(pctx, " ");
01657 cfg_doc_obj(pctx, clause->type);
01658 cfg_print_cstr(pctx, ";");
01659 print_clause_flags(pctx, clause->flags);
01660 cfg_print_cstr(pctx, "\n");
01661 }
01662 }
01663 print_close(pctx);
01664 }
01665
01666 isc_boolean_t
01667 cfg_obj_ismap(const cfg_obj_t *obj) {
01668 REQUIRE(obj != NULL);
01669 return (ISC_TF(obj->type->rep == &cfg_rep_map));
01670 }
01671
01672 isc_result_t
01673 cfg_map_get(const cfg_obj_t *mapobj, const char* name, const cfg_obj_t **obj) {
01674 isc_result_t result;
01675 isc_symvalue_t val;
01676 const cfg_map_t *map;
01677
01678 REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map);
01679 REQUIRE(name != NULL);
01680 REQUIRE(obj != NULL && *obj == NULL);
01681
01682 map = &mapobj->value.map;
01683
01684 result = isc_symtab_lookup(map->symtab, name, MAP_SYM, &val);
01685 if (result != ISC_R_SUCCESS)
01686 return (result);
01687 *obj = val.as_pointer;
01688 return (ISC_R_SUCCESS);
01689 }
01690
01691 const cfg_obj_t *
01692 cfg_map_getname(const cfg_obj_t *mapobj) {
01693 REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map);
01694 return (mapobj->value.map.id);
01695 }
01696
01697 unsigned int
01698 cfg_map_count(const cfg_obj_t *mapobj) {
01699 const cfg_map_t *map;
01700 REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map);
01701 map = &mapobj->value.map;
01702 return (isc_symtab_count(map->symtab));
01703 }
01704
01705
01706 static isc_result_t
01707 parse_token(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
01708 cfg_obj_t *obj = NULL;
01709 isc_result_t result;
01710 isc_region_t r;
01711
01712 UNUSED(type);
01713
01714 CHECK(cfg_create_obj(pctx, &cfg_type_token, &obj));
01715 CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
01716 if (pctx->token.type == isc_tokentype_eof) {
01717 cfg_ungettoken(pctx);
01718 result = ISC_R_EOF;
01719 goto cleanup;
01720 }
01721
01722 isc_lex_getlasttokentext(pctx->lexer, &pctx->token, &r);
01723
01724 obj->value.string.base = isc_mem_get(pctx->mctx, r.length + 1);
01725 if (obj->value.string.base == NULL) {
01726 result = ISC_R_NOMEMORY;
01727 goto cleanup;
01728 }
01729 obj->value.string.length = r.length;
01730 memmove(obj->value.string.base, r.base, r.length);
01731 obj->value.string.base[r.length] = '\0';
01732 *ret = obj;
01733 return (result);
01734
01735 cleanup:
01736 if (obj != NULL)
01737 isc_mem_put(pctx->mctx, obj, sizeof(*obj));
01738 return (result);
01739 }
01740
01741 cfg_type_t cfg_type_token = {
01742 "token", parse_token, cfg_print_ustring, cfg_doc_terminal,
01743 &cfg_rep_string, NULL
01744 };
01745
01746
01747
01748
01749
01750
01751 static isc_result_t
01752 parse_unsupported(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
01753 cfg_obj_t *listobj = NULL;
01754 isc_result_t result;
01755 int braces = 0;
01756
01757 CHECK(cfg_create_list(pctx, type, &listobj));
01758
01759 for (;;) {
01760 cfg_listelt_t *elt = NULL;
01761
01762 CHECK(cfg_peektoken(pctx, 0));
01763 if (pctx->token.type == isc_tokentype_special) {
01764 if (pctx->token.value.as_char == '{')
01765 braces++;
01766 else if (pctx->token.value.as_char == '}')
01767 braces--;
01768 else if (pctx->token.value.as_char == ';')
01769 if (braces == 0)
01770 break;
01771 }
01772 if (pctx->token.type == isc_tokentype_eof || braces < 0) {
01773 cfg_parser_error(pctx, CFG_LOG_NEAR, "unexpected token");
01774 result = ISC_R_UNEXPECTEDTOKEN;
01775 goto cleanup;
01776 }
01777
01778 CHECK(cfg_parse_listelt(pctx, &cfg_type_token, &elt));
01779 ISC_LIST_APPEND(listobj->value.list, elt, link);
01780 }
01781 INSIST(braces == 0);
01782 *ret = listobj;
01783 return (ISC_R_SUCCESS);
01784
01785 cleanup:
01786 CLEANUP_OBJ(listobj);
01787 return (result);
01788 }
01789
01790 cfg_type_t cfg_type_unsupported = {
01791 "unsupported", parse_unsupported, cfg_print_spacelist, cfg_doc_terminal,
01792 &cfg_rep_list, NULL
01793 };
01794
01795
01796
01797
01798
01799
01800
01801
01802
01803
01804 static isc_result_t
01805 token_addr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na) {
01806 char *s;
01807 struct in_addr in4a;
01808 struct in6_addr in6a;
01809
01810 if (pctx->token.type != isc_tokentype_string)
01811 return (ISC_R_UNEXPECTEDTOKEN);
01812
01813 s = TOKEN_STRING(pctx);
01814 if ((flags & CFG_ADDR_WILDOK) != 0 && strcmp(s, "*") == 0) {
01815 if ((flags & CFG_ADDR_V4OK) != 0) {
01816 isc_netaddr_any(na);
01817 return (ISC_R_SUCCESS);
01818 } else if ((flags & CFG_ADDR_V6OK) != 0) {
01819 isc_netaddr_any6(na);
01820 return (ISC_R_SUCCESS);
01821 } else {
01822 INSIST(0);
01823 }
01824 } else {
01825 if ((flags & (CFG_ADDR_V4OK | CFG_ADDR_V4PREFIXOK)) != 0) {
01826 if (inet_pton(AF_INET, s, &in4a) == 1) {
01827 isc_netaddr_fromin(na, &in4a);
01828 return (ISC_R_SUCCESS);
01829 }
01830 }
01831 if ((flags & CFG_ADDR_V4PREFIXOK) != 0 &&
01832 strlen(s) <= 15U) {
01833 char buf[64];
01834 int i;
01835
01836 strcpy(buf, s);
01837 for (i = 0; i < 3; i++) {
01838 strcat(buf, ".0");
01839 if (inet_pton(AF_INET, buf, &in4a) == 1) {
01840 isc_netaddr_fromin(na, &in4a);
01841 return (ISC_R_SUCCESS);
01842 }
01843 }
01844 }
01845 if ((flags & CFG_ADDR_V6OK) != 0 &&
01846 strlen(s) <= 127U) {
01847 char buf[128];
01848 char *d;
01849 isc_uint32_t zone = 0;
01850
01851 strcpy(buf, s);
01852 d = strchr(buf, '%');
01853 if (d != NULL)
01854 *d = '\0';
01855
01856 if (inet_pton(AF_INET6, buf, &in6a) == 1) {
01857 if (d != NULL) {
01858 #ifdef ISC_PLATFORM_HAVESCOPEID
01859 isc_result_t result;
01860
01861 result = isc_netscope_pton(AF_INET6,
01862 d + 1,
01863 &in6a,
01864 &zone);
01865 if (result != ISC_R_SUCCESS)
01866 return (result);
01867 #else
01868 return (ISC_R_BADADDRESSFORM);
01869 #endif
01870 }
01871
01872 isc_netaddr_fromin6(na, &in6a);
01873 isc_netaddr_setzone(na, zone);
01874 return (ISC_R_SUCCESS);
01875 }
01876 }
01877 }
01878 return (ISC_R_UNEXPECTEDTOKEN);
01879 }
01880
01881 isc_result_t
01882 cfg_parse_rawaddr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na) {
01883 isc_result_t result;
01884 const char *wild = "";
01885 const char *prefix = "";
01886
01887 CHECK(cfg_gettoken(pctx, 0));
01888 result = token_addr(pctx, flags, na);
01889 if (result == ISC_R_UNEXPECTEDTOKEN) {
01890 if ((flags & CFG_ADDR_WILDOK) != 0)
01891 wild = " or '*'";
01892 if ((flags & CFG_ADDR_V4PREFIXOK) != 0)
01893 wild = " or IPv4 prefix";
01894 if ((flags & CFG_ADDR_MASK) == CFG_ADDR_V4OK)
01895 cfg_parser_error(pctx, CFG_LOG_NEAR,
01896 "expected IPv4 address%s%s",
01897 prefix, wild);
01898 else if ((flags & CFG_ADDR_MASK) == CFG_ADDR_V6OK)
01899 cfg_parser_error(pctx, CFG_LOG_NEAR,
01900 "expected IPv6 address%s%s",
01901 prefix, wild);
01902 else
01903 cfg_parser_error(pctx, CFG_LOG_NEAR,
01904 "expected IP address%s%s",
01905 prefix, wild);
01906 }
01907 cleanup:
01908 return (result);
01909 }
01910
01911 isc_boolean_t
01912 cfg_lookingat_netaddr(cfg_parser_t *pctx, unsigned int flags) {
01913 isc_result_t result;
01914 isc_netaddr_t na_dummy;
01915 result = token_addr(pctx, flags, &na_dummy);
01916 return (ISC_TF(result == ISC_R_SUCCESS));
01917 }
01918
01919 isc_result_t
01920 cfg_parse_rawport(cfg_parser_t *pctx, unsigned int flags, in_port_t *port) {
01921 isc_result_t result;
01922
01923 CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER));
01924
01925 if ((flags & CFG_ADDR_WILDOK) != 0 &&
01926 pctx->token.type == isc_tokentype_string &&
01927 strcmp(TOKEN_STRING(pctx), "*") == 0) {
01928 *port = 0;
01929 return (ISC_R_SUCCESS);
01930 }
01931 if (pctx->token.type != isc_tokentype_number) {
01932 cfg_parser_error(pctx, CFG_LOG_NEAR,
01933 "expected port number or '*'");
01934 return (ISC_R_UNEXPECTEDTOKEN);
01935 }
01936 if (pctx->token.value.as_ulong >= 65536U) {
01937 cfg_parser_error(pctx, CFG_LOG_NEAR,
01938 "port number out of range");
01939 return (ISC_R_UNEXPECTEDTOKEN);
01940 }
01941 *port = (in_port_t)(pctx->token.value.as_ulong);
01942 return (ISC_R_SUCCESS);
01943 cleanup:
01944 return (result);
01945 }
01946
01947 void
01948 cfg_print_rawaddr(cfg_printer_t *pctx, const isc_netaddr_t *na) {
01949 isc_result_t result;
01950 char text[128];
01951 isc_buffer_t buf;
01952
01953 isc_buffer_init(&buf, text, sizeof(text));
01954 result = isc_netaddr_totext(na, &buf);
01955 RUNTIME_CHECK(result == ISC_R_SUCCESS);
01956 cfg_print_chars(pctx, isc_buffer_base(&buf),
01957 isc_buffer_usedlength(&buf));
01958 }
01959
01960 isc_result_t
01961 cfg_parse_dscp(cfg_parser_t *pctx, isc_dscp_t *dscp) {
01962 isc_result_t result;
01963
01964 CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER));
01965
01966 if (pctx->token.type != isc_tokentype_number) {
01967 cfg_parser_error(pctx, CFG_LOG_NEAR,
01968 "expected number");
01969 return (ISC_R_UNEXPECTEDTOKEN);
01970 }
01971 if (pctx->token.value.as_ulong > 63U) {
01972 cfg_parser_error(pctx, CFG_LOG_NEAR,
01973 "dscp out of range");
01974 return (ISC_R_RANGE);
01975 }
01976 *dscp = (isc_dscp_t)(pctx->token.value.as_ulong);
01977 return (ISC_R_SUCCESS);
01978 cleanup:
01979 return (result);
01980 }
01981
01982
01983
01984 static unsigned int netaddr_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK;
01985 static unsigned int netaddr4_flags = CFG_ADDR_V4OK;
01986 static unsigned int netaddr4wild_flags = CFG_ADDR_V4OK | CFG_ADDR_WILDOK;
01987 static unsigned int netaddr6_flags = CFG_ADDR_V6OK;
01988 static unsigned int netaddr6wild_flags = CFG_ADDR_V6OK | CFG_ADDR_WILDOK;
01989
01990 static isc_result_t
01991 parse_netaddr(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
01992 isc_result_t result;
01993 cfg_obj_t *obj = NULL;
01994 isc_netaddr_t netaddr;
01995 unsigned int flags = *(const unsigned int *)type->of;
01996
01997 CHECK(cfg_create_obj(pctx, type, &obj));
01998 CHECK(cfg_parse_rawaddr(pctx, flags, &netaddr));
01999 isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, 0);
02000 *ret = obj;
02001 return (ISC_R_SUCCESS);
02002 cleanup:
02003 CLEANUP_OBJ(obj);
02004 return (result);
02005 }
02006
02007 static void
02008 cfg_doc_netaddr(cfg_printer_t *pctx, const cfg_type_t *type) {
02009 const unsigned int *flagp = type->of;
02010 int n = 0;
02011 if (*flagp != CFG_ADDR_V4OK && *flagp != CFG_ADDR_V6OK)
02012 cfg_print_cstr(pctx, "( ");
02013 if (*flagp & CFG_ADDR_V4OK) {
02014 cfg_print_cstr(pctx, "<ipv4_address>");
02015 n++;
02016 }
02017 if (*flagp & CFG_ADDR_V6OK) {
02018 if (n != 0)
02019 cfg_print_cstr(pctx, " | ");
02020 cfg_print_cstr(pctx, "<ipv6_address>");
02021 n++;
02022 }
02023 if (*flagp & CFG_ADDR_WILDOK) {
02024 if (n != 0)
02025 cfg_print_cstr(pctx, " | ");
02026 cfg_print_cstr(pctx, "*");
02027 n++;
02028 POST(n);
02029 }
02030 if (*flagp != CFG_ADDR_V4OK && *flagp != CFG_ADDR_V6OK)
02031 cfg_print_cstr(pctx, " )");
02032 }
02033
02034 cfg_type_t cfg_type_netaddr = {
02035 "netaddr", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
02036 &cfg_rep_sockaddr, &netaddr_flags
02037 };
02038
02039 cfg_type_t cfg_type_netaddr4 = {
02040 "netaddr4", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
02041 &cfg_rep_sockaddr, &netaddr4_flags
02042 };
02043
02044 cfg_type_t cfg_type_netaddr4wild = {
02045 "netaddr4wild", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
02046 &cfg_rep_sockaddr, &netaddr4wild_flags
02047 };
02048
02049 cfg_type_t cfg_type_netaddr6 = {
02050 "netaddr6", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
02051 &cfg_rep_sockaddr, &netaddr6_flags
02052 };
02053
02054 cfg_type_t cfg_type_netaddr6wild = {
02055 "netaddr6wild", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
02056 &cfg_rep_sockaddr, &netaddr6wild_flags
02057 };
02058
02059
02060
02061 isc_result_t
02062 cfg_parse_netprefix(cfg_parser_t *pctx, const cfg_type_t *type,
02063 cfg_obj_t **ret)
02064 {
02065 cfg_obj_t *obj = NULL;
02066 isc_result_t result;
02067 isc_netaddr_t netaddr;
02068 unsigned int addrlen = 0, prefixlen;
02069 UNUSED(type);
02070
02071 CHECK(cfg_parse_rawaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V4PREFIXOK |
02072 CFG_ADDR_V6OK, &netaddr));
02073 switch (netaddr.family) {
02074 case AF_INET:
02075 addrlen = 32;
02076 break;
02077 case AF_INET6:
02078 addrlen = 128;
02079 break;
02080 default:
02081 INSIST(0);
02082 break;
02083 }
02084 CHECK(cfg_peektoken(pctx, 0));
02085 if (pctx->token.type == isc_tokentype_special &&
02086 pctx->token.value.as_char == '/') {
02087 CHECK(cfg_gettoken(pctx, 0));
02088 CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER));
02089 if (pctx->token.type != isc_tokentype_number) {
02090 cfg_parser_error(pctx, CFG_LOG_NEAR,
02091 "expected prefix length");
02092 return (ISC_R_UNEXPECTEDTOKEN);
02093 }
02094 prefixlen = pctx->token.value.as_ulong;
02095 if (prefixlen > addrlen) {
02096 cfg_parser_error(pctx, CFG_LOG_NOPREP,
02097 "invalid prefix length");
02098 return (ISC_R_RANGE);
02099 }
02100 } else {
02101 prefixlen = addrlen;
02102 }
02103 CHECK(cfg_create_obj(pctx, &cfg_type_netprefix, &obj));
02104 obj->value.netprefix.address = netaddr;
02105 obj->value.netprefix.prefixlen = prefixlen;
02106 *ret = obj;
02107 return (ISC_R_SUCCESS);
02108 cleanup:
02109 cfg_parser_error(pctx, CFG_LOG_NEAR, "expected network prefix");
02110 return (result);
02111 }
02112
02113 static void
02114 print_netprefix(cfg_printer_t *pctx, const cfg_obj_t *obj) {
02115 const cfg_netprefix_t *p = &obj->value.netprefix;
02116
02117 cfg_print_rawaddr(pctx, &p->address);
02118 cfg_print_cstr(pctx, "/");
02119 cfg_print_rawuint(pctx, p->prefixlen);
02120 }
02121
02122 isc_boolean_t
02123 cfg_obj_isnetprefix(const cfg_obj_t *obj) {
02124 REQUIRE(obj != NULL);
02125 return (ISC_TF(obj->type->rep == &cfg_rep_netprefix));
02126 }
02127
02128 void
02129 cfg_obj_asnetprefix(const cfg_obj_t *obj, isc_netaddr_t *netaddr,
02130 unsigned int *prefixlen)
02131 {
02132 REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_netprefix);
02133 REQUIRE(netaddr != NULL);
02134 REQUIRE(prefixlen != NULL);
02135
02136 *netaddr = obj->value.netprefix.address;
02137 *prefixlen = obj->value.netprefix.prefixlen;
02138 }
02139
02140 cfg_type_t cfg_type_netprefix = {
02141 "netprefix", cfg_parse_netprefix, print_netprefix, cfg_doc_terminal,
02142 &cfg_rep_netprefix, NULL
02143 };
02144
02145 static isc_result_t
02146 parse_sockaddrsub(cfg_parser_t *pctx, const cfg_type_t *type,
02147 int flags, cfg_obj_t **ret)
02148 {
02149 isc_result_t result;
02150 isc_netaddr_t netaddr;
02151 in_port_t port = 0;
02152 isc_dscp_t dscp = -1;
02153 cfg_obj_t *obj = NULL;
02154 int have_port = 0, have_dscp = 0;
02155
02156 CHECK(cfg_create_obj(pctx, type, &obj));
02157 CHECK(cfg_parse_rawaddr(pctx, flags, &netaddr));
02158 for (;;) {
02159 CHECK(cfg_peektoken(pctx, 0));
02160 if (pctx->token.type == isc_tokentype_string) {
02161 if (strcasecmp(TOKEN_STRING(pctx), "port") == 0) {
02162 CHECK(cfg_gettoken(pctx, 0));
02163 CHECK(cfg_parse_rawport(pctx, flags, &port));
02164 ++have_port;
02165 } else if ((flags & CFG_ADDR_DSCPOK) != 0 &&
02166 strcasecmp(TOKEN_STRING(pctx), "dscp") == 0)
02167 {
02168 CHECK(cfg_gettoken(pctx, 0));
02169 CHECK(cfg_parse_dscp(pctx, &dscp));
02170 ++have_dscp;
02171 } else
02172 break;
02173 } else
02174 break;
02175 }
02176 if (have_port > 1) {
02177 cfg_parser_error(pctx, 0, "expected at most one port");
02178 result = ISC_R_UNEXPECTEDTOKEN;
02179 goto cleanup;
02180 }
02181
02182 if (have_dscp > 1) {
02183 cfg_parser_error(pctx, 0, "expected at most one dscp");
02184 result = ISC_R_UNEXPECTEDTOKEN;
02185 goto cleanup;
02186 }
02187 isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, port);
02188 obj->value.sockaddrdscp.dscp = dscp;
02189 *ret = obj;
02190 return (ISC_R_SUCCESS);
02191
02192 cleanup:
02193 CLEANUP_OBJ(obj);
02194 return (result);
02195 }
02196
02197 static unsigned int sockaddr_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK;
02198 cfg_type_t cfg_type_sockaddr = {
02199 "sockaddr", cfg_parse_sockaddr, cfg_print_sockaddr, cfg_doc_sockaddr,
02200 &cfg_rep_sockaddr, &sockaddr_flags
02201 };
02202
02203 static unsigned int sockaddrdscp_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK |
02204 CFG_ADDR_DSCPOK;
02205 cfg_type_t cfg_type_sockaddrdscp = {
02206 "sockaddr", cfg_parse_sockaddr, cfg_print_sockaddr, cfg_doc_sockaddr,
02207 &cfg_rep_sockaddr, &sockaddrdscp_flags
02208 };
02209
02210 isc_result_t
02211 cfg_parse_sockaddr(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
02212 const unsigned int *flagp = type->of;
02213 return (parse_sockaddrsub(pctx, &cfg_type_sockaddr, *flagp, ret));
02214 }
02215
02216 void
02217 cfg_print_sockaddr(cfg_printer_t *pctx, const cfg_obj_t *obj) {
02218 isc_netaddr_t netaddr;
02219 in_port_t port;
02220 char buf[ISC_NETADDR_FORMATSIZE];
02221
02222 isc_netaddr_fromsockaddr(&netaddr, &obj->value.sockaddr);
02223 isc_netaddr_format(&netaddr, buf, sizeof(buf));
02224 cfg_print_cstr(pctx, buf);
02225 port = isc_sockaddr_getport(&obj->value.sockaddr);
02226 if (port != 0) {
02227 cfg_print_cstr(pctx, " port ");
02228 cfg_print_rawuint(pctx, port);
02229 }
02230 if (obj->value.sockaddrdscp.dscp != -1) {
02231 cfg_print_cstr(pctx, " dscp ");
02232 cfg_print_rawuint(pctx, obj->value.sockaddrdscp.dscp);
02233 }
02234 }
02235
02236 void
02237 cfg_doc_sockaddr(cfg_printer_t *pctx, const cfg_type_t *type) {
02238 const unsigned int *flagp = type->of;
02239 int n = 0;
02240 cfg_print_cstr(pctx, "( ");
02241 if (*flagp & CFG_ADDR_V4OK) {
02242 cfg_print_cstr(pctx, "<ipv4_address>");
02243 n++;
02244 }
02245 if (*flagp & CFG_ADDR_V6OK) {
02246 if (n != 0)
02247 cfg_print_cstr(pctx, " | ");
02248 cfg_print_cstr(pctx, "<ipv6_address>");
02249 n++;
02250 }
02251 if (*flagp & CFG_ADDR_WILDOK) {
02252 if (n != 0)
02253 cfg_print_cstr(pctx, " | ");
02254 cfg_print_cstr(pctx, "*");
02255 n++;
02256 POST(n);
02257 }
02258 cfg_print_cstr(pctx, " ) ");
02259 if (*flagp & CFG_ADDR_WILDOK) {
02260 cfg_print_cstr(pctx, "[ port ( <integer> | * ) ]");
02261 } else {
02262 cfg_print_cstr(pctx, "[ port <integer> ]");
02263 }
02264 if ((*flagp & CFG_ADDR_DSCPOK) != 0) {
02265 cfg_print_cstr(pctx, " [ dscp <integer> ]");
02266 }
02267 }
02268
02269 isc_boolean_t
02270 cfg_obj_issockaddr(const cfg_obj_t *obj) {
02271 REQUIRE(obj != NULL);
02272 return (ISC_TF(obj->type->rep == &cfg_rep_sockaddr));
02273 }
02274
02275 const isc_sockaddr_t *
02276 cfg_obj_assockaddr(const cfg_obj_t *obj) {
02277 REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_sockaddr);
02278 return (&obj->value.sockaddr);
02279 }
02280
02281 isc_dscp_t
02282 cfg_obj_getdscp(const cfg_obj_t *obj) {
02283 REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_sockaddr);
02284 return (obj->value.sockaddrdscp.dscp);
02285 }
02286
02287 isc_result_t
02288 cfg_gettoken(cfg_parser_t *pctx, int options) {
02289 isc_result_t result;
02290
02291 if (pctx->seen_eof)
02292 return (ISC_R_SUCCESS);
02293
02294 options |= (ISC_LEXOPT_EOF | ISC_LEXOPT_NOMORE);
02295
02296 redo:
02297 pctx->token.type = isc_tokentype_unknown;
02298 result = isc_lex_gettoken(pctx->lexer, options, &pctx->token);
02299 pctx->ungotten = ISC_FALSE;
02300 pctx->line = isc_lex_getsourceline(pctx->lexer);
02301
02302 switch (result) {
02303 case ISC_R_SUCCESS:
02304 if (pctx->token.type == isc_tokentype_eof) {
02305 result = isc_lex_close(pctx->lexer);
02306 INSIST(result == ISC_R_NOMORE ||
02307 result == ISC_R_SUCCESS);
02308
02309 if (isc_lex_getsourcename(pctx->lexer) != NULL) {
02310
02311
02312
02313 cfg_listelt_t *elt;
02314 elt = ISC_LIST_TAIL(pctx->open_files->
02315 value.list);
02316 INSIST(elt != NULL);
02317 ISC_LIST_UNLINK(pctx->open_files->
02318 value.list, elt, link);
02319 ISC_LIST_APPEND(pctx->closed_files->
02320 value.list, elt, link);
02321 goto redo;
02322 }
02323 pctx->seen_eof = ISC_TRUE;
02324 }
02325 break;
02326
02327 case ISC_R_NOSPACE:
02328
02329 cfg_parser_error(pctx, CFG_LOG_NEAR, "token too big");
02330 break;
02331
02332 case ISC_R_IOERROR:
02333 cfg_parser_error(pctx, 0, "%s",
02334 isc_result_totext(result));
02335 break;
02336
02337 default:
02338 cfg_parser_error(pctx, CFG_LOG_NEAR, "%s",
02339 isc_result_totext(result));
02340 break;
02341 }
02342 return (result);
02343 }
02344
02345 void
02346 cfg_ungettoken(cfg_parser_t *pctx) {
02347 if (pctx->seen_eof)
02348 return;
02349 isc_lex_ungettoken(pctx->lexer, &pctx->token);
02350 pctx->ungotten = ISC_TRUE;
02351 }
02352
02353 isc_result_t
02354 cfg_peektoken(cfg_parser_t *pctx, int options) {
02355 isc_result_t result;
02356 CHECK(cfg_gettoken(pctx, options));
02357 cfg_ungettoken(pctx);
02358 cleanup:
02359 return (result);
02360 }
02361
02362
02363
02364
02365
02366 static isc_result_t
02367 cfg_getstringtoken(cfg_parser_t *pctx) {
02368 isc_result_t result;
02369
02370 result = cfg_gettoken(pctx, CFG_LEXOPT_QSTRING);
02371 if (result != ISC_R_SUCCESS)
02372 return (result);
02373
02374 if (pctx->token.type != isc_tokentype_string &&
02375 pctx->token.type != isc_tokentype_qstring) {
02376 cfg_parser_error(pctx, CFG_LOG_NEAR, "expected string");
02377 return (ISC_R_UNEXPECTEDTOKEN);
02378 }
02379 return (ISC_R_SUCCESS);
02380 }
02381
02382 void
02383 cfg_parser_error(cfg_parser_t *pctx, unsigned int flags, const char *fmt, ...) {
02384 va_list args;
02385 va_start(args, fmt);
02386 parser_complain(pctx, ISC_FALSE, flags, fmt, args);
02387 va_end(args);
02388 pctx->errors++;
02389 }
02390
02391 void
02392 cfg_parser_warning(cfg_parser_t *pctx, unsigned int flags, const char *fmt, ...) {
02393 va_list args;
02394 va_start(args, fmt);
02395 parser_complain(pctx, ISC_TRUE, flags, fmt, args);
02396 va_end(args);
02397 pctx->warnings++;
02398 }
02399
02400 #define MAX_LOG_TOKEN 30
02401
02402 static isc_boolean_t
02403 have_current_file(cfg_parser_t *pctx) {
02404 cfg_listelt_t *elt;
02405 if (pctx->open_files == NULL)
02406 return (ISC_FALSE);
02407
02408 elt = ISC_LIST_TAIL(pctx->open_files->value.list);
02409 if (elt == NULL)
02410 return (ISC_FALSE);
02411
02412 return (ISC_TRUE);
02413 }
02414
02415 static char *
02416 current_file(cfg_parser_t *pctx) {
02417 static char none[] = "none";
02418 cfg_listelt_t *elt;
02419 cfg_obj_t *fileobj;
02420
02421 if (!have_current_file(pctx))
02422 return (none);
02423
02424 elt = ISC_LIST_TAIL(pctx->open_files->value.list);
02425 if (elt == NULL)
02426 return (none);
02427
02428 fileobj = elt->obj;
02429 INSIST(fileobj->type == &cfg_type_qstring);
02430 return (fileobj->value.string.base);
02431 }
02432
02433 static void
02434 parser_complain(cfg_parser_t *pctx, isc_boolean_t is_warning,
02435 unsigned int flags, const char *format,
02436 va_list args)
02437 {
02438 char tokenbuf[MAX_LOG_TOKEN + 10];
02439 static char where[ISC_DIR_PATHMAX + 100];
02440 static char message[2048];
02441 int level = ISC_LOG_ERROR;
02442 const char *prep = "";
02443 size_t len;
02444
02445 if (is_warning)
02446 level = ISC_LOG_WARNING;
02447
02448 where[0] = '\0';
02449 if (have_current_file(pctx))
02450 snprintf(where, sizeof(where), "%s:%u: ",
02451 current_file(pctx), pctx->line);
02452
02453 len = vsnprintf(message, sizeof(message), format, args);
02454 if (len >= sizeof(message))
02455 FATAL_ERROR(__FILE__, __LINE__,
02456 "error message would overflow");
02457
02458 if ((flags & (CFG_LOG_NEAR|CFG_LOG_BEFORE|CFG_LOG_NOPREP)) != 0) {
02459 isc_region_t r;
02460
02461 if (pctx->ungotten)
02462 (void)cfg_gettoken(pctx, 0);
02463
02464 if (pctx->token.type == isc_tokentype_eof) {
02465 snprintf(tokenbuf, sizeof(tokenbuf), "end of file");
02466 } else if (pctx->token.type == isc_tokentype_unknown) {
02467 flags = 0;
02468 tokenbuf[0] = '\0';
02469 } else {
02470 isc_lex_getlasttokentext(pctx->lexer,
02471 &pctx->token, &r);
02472 if (r.length > MAX_LOG_TOKEN)
02473 snprintf(tokenbuf, sizeof(tokenbuf),
02474 "'%.*s...'", MAX_LOG_TOKEN, r.base);
02475 else
02476 snprintf(tokenbuf, sizeof(tokenbuf),
02477 "'%.*s'", (int)r.length, r.base);
02478 }
02479
02480
02481 if (flags & CFG_LOG_NEAR)
02482 prep = " near ";
02483 else if (flags & CFG_LOG_BEFORE)
02484 prep = " before ";
02485 else
02486 prep = " ";
02487 } else {
02488 tokenbuf[0] = '\0';
02489 }
02490 isc_log_write(pctx->lctx, CAT, MOD, level,
02491 "%s%s%s%s", where, message, prep, tokenbuf);
02492 }
02493
02494 void
02495 cfg_obj_log(const cfg_obj_t *obj, isc_log_t *lctx, int level,
02496 const char *fmt, ...) {
02497 va_list ap;
02498 char msgbuf[2048];
02499
02500 if (! isc_log_wouldlog(lctx, level))
02501 return;
02502
02503 va_start(ap, fmt);
02504
02505 vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
02506 isc_log_write(lctx, CAT, MOD, level,
02507 "%s:%u: %s",
02508 obj->file == NULL ? "<unknown file>" : obj->file,
02509 obj->line, msgbuf);
02510 va_end(ap);
02511 }
02512
02513 const char *
02514 cfg_obj_file(const cfg_obj_t *obj) {
02515 return (obj->file);
02516 }
02517
02518 unsigned int
02519 cfg_obj_line(const cfg_obj_t *obj) {
02520 return (obj->line);
02521 }
02522
02523 isc_result_t
02524 cfg_create_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
02525 isc_result_t result;
02526 cfg_obj_t *obj;
02527
02528 obj = isc_mem_get(pctx->mctx, sizeof(cfg_obj_t));
02529 if (obj == NULL)
02530 return (ISC_R_NOMEMORY);
02531 obj->type = type;
02532 obj->file = current_file(pctx);
02533 obj->line = pctx->line;
02534 result = isc_refcount_init(&obj->references, 1);
02535 if (result != ISC_R_SUCCESS) {
02536 isc_mem_put(pctx->mctx, obj, sizeof(cfg_obj_t));
02537 return (result);
02538 }
02539 *ret = obj;
02540 return (ISC_R_SUCCESS);
02541 }
02542
02543
02544 static void
02545 map_symtabitem_destroy(char *key, unsigned int type,
02546 isc_symvalue_t symval, void *userarg)
02547 {
02548 cfg_obj_t *obj = symval.as_pointer;
02549 cfg_parser_t *pctx = (cfg_parser_t *)userarg;
02550
02551 UNUSED(key);
02552 UNUSED(type);
02553
02554 cfg_obj_destroy(pctx, &obj);
02555 }
02556
02557 static isc_result_t
02558 create_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
02559 isc_result_t result;
02560 isc_symtab_t *symtab = NULL;
02561 cfg_obj_t *obj = NULL;
02562
02563 CHECK(cfg_create_obj(pctx, type, &obj));
02564 CHECK(isc_symtab_create(pctx->mctx, 5,
02565 map_symtabitem_destroy,
02566 pctx, ISC_FALSE, &symtab));
02567 obj->value.map.symtab = symtab;
02568 obj->value.map.id = NULL;
02569
02570 *ret = obj;
02571 return (ISC_R_SUCCESS);
02572
02573 cleanup:
02574 if (obj != NULL)
02575 isc_mem_put(pctx->mctx, obj, sizeof(*obj));
02576 return (result);
02577 }
02578
02579 static void
02580 free_map(cfg_parser_t *pctx, cfg_obj_t *obj) {
02581 CLEANUP_OBJ(obj->value.map.id);
02582 isc_symtab_destroy(&obj->value.map.symtab);
02583 }
02584
02585 isc_boolean_t
02586 cfg_obj_istype(const cfg_obj_t *obj, const cfg_type_t *type) {
02587 return (ISC_TF(obj->type == type));
02588 }
02589
02590
02591
02592
02593 void
02594 cfg_obj_destroy(cfg_parser_t *pctx, cfg_obj_t **objp) {
02595 cfg_obj_t *obj;
02596 unsigned int refs;
02597
02598 REQUIRE(objp != NULL && *objp != NULL);
02599 REQUIRE(pctx != NULL);
02600
02601 obj = *objp;
02602
02603 isc_refcount_decrement(&obj->references, &refs);
02604 if (refs == 0) {
02605 obj->type->rep->free(pctx, obj);
02606 isc_refcount_destroy(&obj->references);
02607 isc_mem_put(pctx->mctx, obj, sizeof(cfg_obj_t));
02608 }
02609 *objp = NULL;
02610 }
02611
02612 void
02613 cfg_obj_attach(cfg_obj_t *src, cfg_obj_t **dest) {
02614 REQUIRE(src != NULL);
02615 REQUIRE(dest != NULL && *dest == NULL);
02616 isc_refcount_increment(&src->references, NULL);
02617 *dest = src;
02618 }
02619
02620 static void
02621 free_noop(cfg_parser_t *pctx, cfg_obj_t *obj) {
02622 UNUSED(pctx);
02623 UNUSED(obj);
02624 }
02625
02626 void
02627 cfg_doc_obj(cfg_printer_t *pctx, const cfg_type_t *type) {
02628 type->doc(pctx, type);
02629 }
02630
02631 void
02632 cfg_doc_terminal(cfg_printer_t *pctx, const cfg_type_t *type) {
02633 cfg_print_cstr(pctx, "<");
02634 cfg_print_cstr(pctx, type->name);
02635 cfg_print_cstr(pctx, ">");
02636 }
02637
02638 void
02639 cfg_print_grammar(const cfg_type_t *type,
02640 void (*f)(void *closure, const char *text, int textlen),
02641 void *closure)
02642 {
02643 cfg_printer_t pctx;
02644 pctx.f = f;
02645 pctx.closure = closure;
02646 pctx.indent = 0;
02647 pctx.flags = 0;
02648 cfg_doc_obj(&pctx, type);
02649 }
02650
02651 isc_result_t
02652 cfg_parser_mapadd(cfg_parser_t *pctx, cfg_obj_t *mapobj,
02653 cfg_obj_t *obj, const char *clausename)
02654 {
02655 isc_result_t result = ISC_R_SUCCESS;
02656 const cfg_map_t *map;
02657 isc_symvalue_t symval;
02658 cfg_obj_t *destobj = NULL;
02659 cfg_listelt_t *elt = NULL;
02660 const cfg_clausedef_t * const *clauseset;
02661 const cfg_clausedef_t *clause;
02662
02663 REQUIRE(pctx != NULL);
02664 REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map);
02665 REQUIRE(obj != NULL);
02666
02667 map = &mapobj->value.map;
02668
02669 clause = NULL;
02670 for (clauseset = map->clausesets; *clauseset != NULL; clauseset++) {
02671 for (clause = *clauseset; clause->name != NULL; clause++) {
02672 if (strcasecmp(clause->name, clausename) == 0) {
02673 goto breakout;
02674 }
02675 }
02676 }
02677
02678 breakout:
02679 if (clause == NULL || clause->name == NULL)
02680 return (ISC_R_FAILURE);
02681
02682 result = isc_symtab_lookup(map->symtab, clausename, 0, &symval);
02683 if (result == ISC_R_NOTFOUND) {
02684 if ((clause->flags & CFG_CLAUSEFLAG_MULTI) != 0) {
02685 CHECK(cfg_create_list(pctx, &cfg_type_implicitlist,
02686 &destobj));
02687 CHECK(create_listelt(pctx, &elt));
02688 cfg_obj_attach(obj, &elt->obj);
02689 ISC_LIST_APPEND(destobj->value.list, elt, link);
02690 symval.as_pointer = destobj;
02691 } else
02692 symval.as_pointer = obj;
02693
02694 CHECK(isc_symtab_define(map->symtab, clausename, 1, symval,
02695 isc_symexists_reject));
02696 } else {
02697 cfg_obj_t *destobj2 = symval.as_pointer;
02698
02699 INSIST(result == ISC_R_SUCCESS);
02700
02701 if (destobj2->type == &cfg_type_implicitlist) {
02702 CHECK(create_listelt(pctx, &elt));
02703 cfg_obj_attach(obj, &elt->obj);
02704 ISC_LIST_APPEND(destobj2->value.list, elt, link);
02705 } else
02706 result = ISC_R_EXISTS;
02707 }
02708
02709 destobj = NULL;
02710 elt = NULL;
02711
02712 cleanup:
02713 if (elt != NULL)
02714 free_listelt(pctx, elt);
02715 CLEANUP_OBJ(destobj);
02716
02717 return (result);
02718 }