📄 parser.c
字号:
for (;;) { cfg_listelt_t *elt; redo: /* * Parse the option name and see if it is known. */ CHECK(cfg_gettoken(pctx, 0)); if (pctx->token.type != isc_tokentype_string) { cfg_ungettoken(pctx); break; } /* * We accept "include" statements wherever a map body * clause can occur. */ if (strcasecmp(TOKEN_STRING(pctx), "include") == 0) { /* * Turn the file name into a temporary configuration * object just so that it is not overwritten by the * semicolon token. */ CHECK(cfg_parse_obj(pctx, &cfg_type_qstring, &includename)); CHECK(parse_semicolon(pctx)); CHECK(parser_openfile(pctx, includename-> value.string.base)); cfg_obj_destroy(pctx, &includename); goto redo; } clause = NULL; for (clauseset = clausesets; *clauseset != NULL; clauseset++) { for (clause = *clauseset; clause->name != NULL; clause++) { if (strcasecmp(TOKEN_STRING(pctx), clause->name) == 0) goto done; } } done: if (clause == NULL || clause->name == NULL) { cfg_parser_error(pctx, CFG_LOG_NOPREP, "unknown option"); /* * Try to recover by parsing this option as an unknown * option and discarding it. */ CHECK(cfg_parse_obj(pctx, &cfg_type_unsupported, &eltobj)); cfg_obj_destroy(pctx, &eltobj); CHECK(parse_semicolon(pctx)); continue; } /* Clause is known. */ /* Issue warnings if appropriate */ if ((clause->flags & CFG_CLAUSEFLAG_OBSOLETE) != 0) cfg_parser_warning(pctx, 0, "option '%s' is obsolete", clause->name); if ((clause->flags & CFG_CLAUSEFLAG_NOTIMP) != 0) cfg_parser_warning(pctx, 0, "option '%s' is " "not implemented", clause->name); if ((clause->flags & CFG_CLAUSEFLAG_NYI) != 0) cfg_parser_warning(pctx, 0, "option '%s' is " "not implemented", clause->name); /* * Don't log options with CFG_CLAUSEFLAG_NEWDEFAULT * set here - we need to log the *lack* of such an option, * not its presence. */ /* See if the clause already has a value; if not create one. */ result = isc_symtab_lookup(obj->value.map.symtab, clause->name, 0, &symval); if ((clause->flags & CFG_CLAUSEFLAG_MULTI) != 0) { /* Multivalued clause */ cfg_obj_t *listobj = NULL; if (result == ISC_R_NOTFOUND) { CHECK(cfg_create_list(pctx, &cfg_type_implicitlist, &listobj)); symval.as_pointer = listobj; result = isc_symtab_define(obj->value. map.symtab, clause->name, 1, symval, isc_symexists_reject); if (result != ISC_R_SUCCESS) { cfg_parser_error(pctx, CFG_LOG_NEAR, "isc_symtab_define(%s) " "failed", clause->name); isc_mem_put(pctx->mctx, list, sizeof(cfg_list_t)); goto cleanup; } } else { INSIST(result == ISC_R_SUCCESS); listobj = symval.as_pointer; } elt = NULL; CHECK(cfg_parse_listelt(pctx, clause->type, &elt)); CHECK(parse_semicolon(pctx)); ISC_LIST_APPEND(listobj->value.list, elt, link); } else { /* Single-valued clause */ if (result == ISC_R_NOTFOUND) { isc_boolean_t callback = ISC_TF((clause->flags & CFG_CLAUSEFLAG_CALLBACK) != 0); CHECK(parse_symtab_elt(pctx, clause->name, clause->type, obj->value.map.symtab, callback)); CHECK(parse_semicolon(pctx)); } else if (result == ISC_R_SUCCESS) { cfg_parser_error(pctx, CFG_LOG_NEAR, "'%s' redefined", clause->name); result = ISC_R_EXISTS; goto cleanup; } else { cfg_parser_error(pctx, CFG_LOG_NEAR, "isc_symtab_define() failed"); goto cleanup; } } } *ret = obj; return (ISC_R_SUCCESS); cleanup: CLEANUP_OBJ(value); CLEANUP_OBJ(obj); CLEANUP_OBJ(eltobj); CLEANUP_OBJ(includename); return (result);}static isc_result_tparse_symtab_elt(cfg_parser_t *pctx, const char *name, cfg_type_t *elttype, isc_symtab_t *symtab, isc_boolean_t callback){ isc_result_t result; cfg_obj_t *obj = NULL; isc_symvalue_t symval; CHECK(cfg_parse_obj(pctx, elttype, &obj)); if (callback && pctx->callback != NULL) CHECK(pctx->callback(name, obj, pctx->callbackarg)); symval.as_pointer = obj; CHECK(isc_symtab_define(symtab, name, 1, symval, isc_symexists_reject)); return (ISC_R_SUCCESS); cleanup: CLEANUP_OBJ(obj); return (result);}/* * Parse a map; e.g., "{ foo 1; bar { glub; }; zap true; zap false; }" */isc_result_tcfg_parse_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { isc_result_t result; CHECK(cfg_parse_special(pctx, '{')); CHECK(cfg_parse_mapbody(pctx, type, ret)); CHECK(cfg_parse_special(pctx, '}')); cleanup: return (result);}/* * Subroutine for cfg_parse_named_map() and cfg_parse_addressed_map(). */static isc_result_tparse_any_named_map(cfg_parser_t *pctx, cfg_type_t *nametype, const cfg_type_t *type, cfg_obj_t **ret){ isc_result_t result; cfg_obj_t *idobj = NULL; cfg_obj_t *mapobj = NULL; CHECK(cfg_parse_obj(pctx, nametype, &idobj)); CHECK(cfg_parse_map(pctx, type, &mapobj)); mapobj->value.map.id = idobj; idobj = NULL; *ret = mapobj; cleanup: CLEANUP_OBJ(idobj); return (result);}/* * Parse a map identified by a string name. E.g., "name { foo 1; }". * Used for the "key" and "channel" statements. */isc_result_tcfg_parse_named_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { return (parse_any_named_map(pctx, &cfg_type_astring, type, ret));}/* * Parse a map identified by a network address. * Used for the "server" statement. */isc_result_tcfg_parse_addressed_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { return (parse_any_named_map(pctx, &cfg_type_netaddr, type, ret));}voidcfg_print_mapbody(cfg_printer_t *pctx, cfg_obj_t *obj) { isc_result_t result = ISC_R_SUCCESS; const cfg_clausedef_t * const *clauseset; for (clauseset = obj->value.map.clausesets; *clauseset != NULL; clauseset++) { isc_symvalue_t symval; const cfg_clausedef_t *clause; for (clause = *clauseset; clause->name != NULL; clause++) { result = isc_symtab_lookup(obj->value.map.symtab, clause->name, 0, &symval); if (result == ISC_R_SUCCESS) { cfg_obj_t *obj = symval.as_pointer; if (obj->type == &cfg_type_implicitlist) { /* Multivalued. */ cfg_list_t *list = &obj->value.list; cfg_listelt_t *elt; for (elt = ISC_LIST_HEAD(*list); elt != NULL; elt = ISC_LIST_NEXT(elt, link)) { print_indent(pctx); cfg_print_cstr(pctx, clause->name); cfg_print_chars(pctx, " ", 1); cfg_print_obj(pctx, elt->obj); cfg_print_chars(pctx, ";\n", 2); } } else { /* Single-valued. */ print_indent(pctx); cfg_print_cstr(pctx, clause->name); cfg_print_chars(pctx, " ", 1); cfg_print_obj(pctx, obj); cfg_print_chars(pctx, ";\n", 2); } } else if (result == ISC_R_NOTFOUND) { ; /* do nothing */ } else { INSIST(0); } } }}voidcfg_doc_mapbody(cfg_printer_t *pctx, const cfg_type_t *type) { const cfg_clausedef_t * const *clauseset; const cfg_clausedef_t *clause; for (clauseset = type->of; *clauseset != NULL; clauseset++) { for (clause = *clauseset; clause->name != NULL; clause++) { cfg_print_cstr(pctx, clause->name); cfg_print_chars(pctx, " ", 1); cfg_doc_obj(pctx, clause->type); cfg_print_chars(pctx, ";", 1); /* XXX print flags here? */ cfg_print_chars(pctx, "\n\n", 2); } }}static struct flagtext { unsigned int flag; const char *text;} flagtexts[] = { { CFG_CLAUSEFLAG_NOTIMP, "not implemented" }, { CFG_CLAUSEFLAG_NYI, "not yet implemented" }, { CFG_CLAUSEFLAG_OBSOLETE, "obsolete" }, { CFG_CLAUSEFLAG_NEWDEFAULT, "default changed" }, { 0, NULL }};voidcfg_print_map(cfg_printer_t *pctx, cfg_obj_t *obj) { if (obj->value.map.id != NULL) { cfg_print_obj(pctx, obj->value.map.id); cfg_print_chars(pctx, " ", 1); } print_open(pctx); cfg_print_mapbody(pctx, obj); print_close(pctx);}static voidprint_clause_flags(cfg_printer_t *pctx, unsigned int flags) { struct flagtext *p; isc_boolean_t first = ISC_TRUE; for (p = flagtexts; p->flag != 0; p++) { if ((flags & p->flag) != 0) { if (first) cfg_print_chars(pctx, " // ", 4); else cfg_print_chars(pctx, ", ", 2); cfg_print_cstr(pctx, p->text); first = ISC_FALSE; } }}voidcfg_doc_map(cfg_printer_t *pctx, const cfg_type_t *type) { const cfg_clausedef_t * const *clauseset; const cfg_clausedef_t *clause; if (type->parse == cfg_parse_named_map) { cfg_doc_obj(pctx, &cfg_type_astring); cfg_print_chars(pctx, " ", 1); } else if (type->parse == cfg_parse_addressed_map) { cfg_doc_obj(pctx, &cfg_type_netaddr); cfg_print_chars(pctx, " ", 1); } print_open(pctx); for (clauseset = type->of; *clauseset != NULL; clauseset++) { for (clause = *clauseset; clause->name != NULL; clause++) { print_indent(pctx); cfg_print_cstr(pctx, clause->name); if (clause->type->print != cfg_print_void) cfg_print_chars(pctx, " ", 1); cfg_doc_obj(pctx, clause->type); cfg_print_chars(pctx, ";", 1); print_clause_flags(pctx, clause->flags); cfg_print_chars(pctx, "\n", 1); } } print_close(pctx);}isc_boolean_tcfg_obj_ismap(cfg_obj_t *obj) { REQUIRE(obj != NULL); return (ISC_TF(obj->type->rep == &cfg_rep_map));}isc_result_tcfg_map_get(cfg_obj_t *mapobj, const char* name, cfg_obj_t **obj) { isc_result_t result; isc_symvalue_t val; cfg_map_t *map; REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map); REQUIRE(name != NULL); REQUIRE(obj != NULL && *obj == NULL); map = &mapobj->value.map; result = isc_symtab_lookup(map->symtab, name, MAP_SYM, &val); if (result != ISC_R_SUCCESS) return (result); *obj = val.as_pointer; return (ISC_R_SUCCESS);}cfg_obj_t *cfg_map_getname(cfg_obj_t *mapobj) { REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map); return (mapobj->value.map.id);}/* Parse an arbitrary token, storing its raw text representation. */static isc_result_tparse_token(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { cfg_obj_t *obj = NULL; isc_result_t result; isc_region_t r; UNUSED(type); CHECK(cfg_create_obj(pctx, &cfg_type_token, &obj)); CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING)); if (pctx->token.type == isc_tokentype_eof) { cfg_ungettoken(pctx); result = ISC_R_EOF; goto cleanup; } isc_lex_getlasttokentext(pctx->lexer, &pctx->token, &r); obj->value.string.base = isc_mem_get(pctx->mctx, r.length + 1); obj->value.string.length = r.length; memcpy(obj->value.string.base, r.base, r.length); obj->value.string.base[r.length] = '\0'; *ret = obj; cleanup: return (result);}cfg_type_t cfg_type_token = { "token", parse_token, cfg_print_ustring, cfg_doc_terminal, &cfg_rep_string, NULL};/* * An unsupported option. This is just a list of tokens with balanced braces * ending in a semicolon. */static isc_result_tparse_unsupported(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { cfg_obj_t *listobj = NULL; isc_result_t result; int braces = 0; CHECK(cfg_create_list(pctx, type, &listobj)); for (;;) { cfg_listelt_t *elt = NULL; CHECK(cfg_peektoken(pctx, 0)); if (pctx->token.type == isc_tokentype_special) { if (pctx->token.value.as_char == '{') braces++; else if (pctx->token.value.as_char == '}') braces--; else if (pctx->token.value.as_char == ';') if (braces == 0) break; } if (pctx->token.type == isc_tokentype_eof || braces < 0) { cfg_parser_error(pctx, CFG_LOG_NEAR, "unexpected token"); result = ISC_R_UNEXPECTEDTOKEN; goto cleanup; } CHECK(cfg_parse_listelt(pctx, &cfg_type_token, &elt)); ISC_LIST_APPEND(listobj->value.list, elt, link); } INSIST(braces == 0); *ret = listobj; return (ISC_R_SUCCESS); cleanup: CLEANUP_OBJ(listobj); return (result);}cfg_type_t cfg_type_unsupported = { "unsupported", parse_unsupported, cfg_print_spacelist, cfg_doc_terminal, &cfg_rep_list, NULL};/* * Try interpreting the current token as a network address. * * If CFG_ADDR_WILDOK is set in flags, "*" can be used as a wildcard * and at least one of CFG_ADDR_V4OK and CFG_ADDR_V6OK must also be set. The * "*" is interpreted as the IPv4 wildcard address if CFG_ADDR_V4OK is * set (including the case where CFG_ADDR_V4OK and CFG_ADDR_V6OK are both set), * and the IPv6 wildcard address otherwise. */static isc_result_ttoken_addr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na) { char *s; struct in_addr in4a; struct in6_addr in6a; if (pctx->token.type != isc_tokentype_string) return (ISC_R_UNEXPECTEDTOKEN); s = TOKEN_STRING(pctx); if ((flags & CFG_ADDR_WILDOK) != 0 && strcmp(s, "*") == 0) { if ((flags & CFG_ADDR_V4OK) != 0) { isc_netaddr_any(na); return (ISC_R_SUCCESS); } else if ((flags & CFG_ADDR_V6OK) != 0) { isc_netaddr_any6(na); return (ISC_R_SUCCESS); } else { INSIST(0); } } else { if ((flags & (CFG_ADDR_V4OK | CFG_ADDR_V4PREFIXOK)) != 0) { if (inet_pton(AF_INET, s, &in4a) == 1) { isc_netaddr_fromin(na, &in4a); return (ISC_R_SUCCESS); } } if ((flags & CFG_ADDR_V4PREFIXOK) != 0 && strlen(s) <= 15U) { char buf[64]; int i; strcpy(buf, s); for (i = 0; i < 3; i++) { strcat(buf, ".0"); if (inet_pton(AF_INET, buf, &in4a) == 1) { isc_netaddr_fromin(na, &in4a); return (ISC_R_SUCCESS); } } } if ((flags & CFG_ADDR_V6OK) != 0 && strlen(s) <= 127U) { char buf[128]; /* see lib/bind9/getaddresses.c */ char *d; /* zone delimiter */ isc_uint32_t zone = 0; /* scope zone ID */ strcpy(buf, s); d = strchr(buf, '%'); if (d != NULL) *d = '\0'; if (inet_pton(AF_INET6, buf, &in6a) == 1) { if (d != NULL) {#ifdef ISC_PLATFORM_HAVESCOPEID isc_result_t result; result = isc_netscope_pton(AF_INET6, d + 1, &in6a, &zone); if (result != ISC_R_SUCCESS) return (result);#else return (ISC_R_BADADDRESSFORM);#endif } isc_netaddr_fromin6(na, &in6a); isc_netaddr_setzone(na, zone); return (ISC_R_SUCCESS); } } } return (ISC_R_UNEXPECTEDTOKEN);}isc_result_tcfg_parse_rawaddr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na) { isc_result_t result; CHECK(cfg_gettoken(pctx, 0)); result = token_addr(pctx, flags, na); if (result == ISC_R_UNEXPECTEDTOKEN) cfg_parser_error(pctx, CFG_LOG_NEAR, "expected IP address"); cleanup: return (result);}isc_boolean_t
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -