diff --git a/CHANGES b/CHANGES index fb869c3153..f0c22752ab 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,12 @@ +4030. [func] "rndc delzone" is now applicable to zones that were + configured in named.conf, as well as zones that + were added via "rndc addzone". (Note, however, that + if named.conf is not also modified, the deleted zone + will return when named is reloaded.) [RT #37887] + +4029. [func] "rndc showzone" displays the current configuration + of a specified zone. [RT #37887] + 4028. [bug] $GENERATE with a zero step was not being caught as a error. A $GENERATE with a / but no step was not being caught as a error. [RT #38262] diff --git a/bin/named/control.c b/bin/named/control.c index 41be1f3653..cb91f2e4ca 100644 --- a/bin/named/control.c +++ b/bin/named/control.c @@ -206,9 +206,11 @@ ns_control_docommand(isccc_sexpr_t *message, isc_buffer_t **text) { command_compare(command, NS_COMMAND_LOADKEYS)) { result = ns_server_rekey(ns_g_server, command, text); } else if (command_compare(command, NS_COMMAND_ADDZONE)) { - result = ns_server_add_zone(ns_g_server, command, text); + result = ns_server_addzone(ns_g_server, command, text); } else if (command_compare(command, NS_COMMAND_DELZONE)) { - result = ns_server_del_zone(ns_g_server, command, text); + result = ns_server_delzone(ns_g_server, command, text); + } else if (command_compare(command, NS_COMMAND_SHOWZONE)) { + result = ns_server_showzone(ns_g_server, command, text); } else if (command_compare(command, NS_COMMAND_SIGNING)) { result = ns_server_signing(ns_g_server, command, text); } else if (command_compare(command, NS_COMMAND_ZONESTATUS)) { diff --git a/bin/named/include/named/control.h b/bin/named/include/named/control.h index ee1d696945..2ecb4fa07f 100644 --- a/bin/named/include/named/control.h +++ b/bin/named/include/named/control.h @@ -63,6 +63,7 @@ #define NS_COMMAND_SIGN "sign" #define NS_COMMAND_LOADKEYS "loadkeys" #define NS_COMMAND_ADDZONE "addzone" +#define NS_COMMAND_SHOWZONE "showzone" #define NS_COMMAND_DELZONE "delzone" #define NS_COMMAND_SYNC "sync" #define NS_COMMAND_SIGNING "signing" diff --git a/bin/named/include/named/globals.h b/bin/named/include/named/globals.h index 5b660d8add..a575b95224 100644 --- a/bin/named/include/named/globals.h +++ b/bin/named/include/named/globals.h @@ -67,6 +67,7 @@ EXTERN unsigned int ns_g_cpus_detected INIT(1); EXTERN isc_timermgr_t * ns_g_timermgr INIT(NULL); EXTERN isc_socketmgr_t * ns_g_socketmgr INIT(NULL); EXTERN cfg_parser_t * ns_g_parser INIT(NULL); +EXTERN cfg_parser_t * ns_g_addparser INIT(NULL); EXTERN const char * ns_g_version INIT(VERSION); EXTERN const char * ns_g_product INIT(PRODUCT); EXTERN const char * ns_g_description INIT(DESCRIPTION); diff --git a/bin/named/include/named/server.h b/bin/named/include/named/server.h index 953eae77d3..5444e4fb30 100644 --- a/bin/named/include/named/server.h +++ b/bin/named/include/named/server.h @@ -373,13 +373,19 @@ ns_server_validation(ns_server_t *server, char *args, isc_buffer_t **text); * Add a zone to a running process */ isc_result_t -ns_server_add_zone(ns_server_t *server, char *args, isc_buffer_t **text); +ns_server_addzone(ns_server_t *server, char *args, isc_buffer_t **text); /*% * Deletes a zone from a running process */ isc_result_t -ns_server_del_zone(ns_server_t *server, char *args, isc_buffer_t **text); +ns_server_delzone(ns_server_t *server, char *args, isc_buffer_t **text); + +/*% + * Show current configuration for a given zone + */ +isc_result_t +ns_server_showzone(ns_server_t *server, char *args, isc_buffer_t **text); /*% * Lists the status of the signing records for a given zone. diff --git a/bin/named/server.c b/bin/named/server.c index 8b1c1e9f0f..cc07901d95 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -247,9 +247,10 @@ struct zonelistentry { */ struct cfg_context { isc_mem_t * mctx; - cfg_parser_t * parser; + cfg_parser_t * conf_parser; + cfg_parser_t * add_parser; cfg_obj_t * config; - cfg_parser_t * nzparser; + cfg_obj_t * vconfig; cfg_obj_t * nzconfig; cfg_aclconfctx_t * actx; }; @@ -5307,13 +5308,11 @@ configure_session_key(const cfg_obj_t **maps, ns_server_t *server, static isc_result_t setup_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig, - cfg_parser_t *parser, cfg_aclconfctx_t *actx) + cfg_parser_t *conf_parser, cfg_aclconfctx_t *actx) { isc_result_t result = ISC_R_SUCCESS; isc_boolean_t allow = ISC_FALSE; struct cfg_context *nzcfg = NULL; - cfg_parser_t *nzparser = NULL; - cfg_obj_t *nzconfig = NULL; const cfg_obj_t *maps[4]; const cfg_obj_t *options = NULL, *voptions = NULL; const cfg_obj_t *nz = NULL; @@ -5346,33 +5345,31 @@ setup_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig, return (ISC_R_NOMEMORY); } + memset(nzcfg, 0, sizeof(*nzcfg)); + dns_view_setnewzones(view, allow, nzcfg, newzone_cfgctx_destroy); - memset(nzcfg, 0, sizeof(*nzcfg)); - isc_mem_attach(view->mctx, &nzcfg->mctx); cfg_obj_attach(config, &nzcfg->config); - cfg_parser_attach(parser, &nzcfg->parser); + if (vconfig != NULL) + cfg_obj_attach(vconfig, &nzcfg->vconfig); + + /* + * We attach the parser that was used for config as well + * as the one that wil be used for added zones, to avoid + * a shutdown race later. + */ + cfg_parser_attach(conf_parser, &nzcfg->conf_parser); + cfg_parser_attach(ns_g_addparser, &nzcfg->add_parser); + isc_mem_attach(view->mctx, &nzcfg->mctx); cfg_aclconfctx_attach(actx, &nzcfg->actx); /* - * Attempt to create a parser and parse the newzones - * file. If successful, preserve both; otherwise leave - * them NULL. + * This may be called in multiple views, so we reset + * the parser each time. */ - result = cfg_parser_create(view->mctx, ns_g_lctx, &nzparser); - if (result == ISC_R_SUCCESS) - result = cfg_parse_file(nzparser, view->new_zone_file, - &cfg_type_newzones, &nzconfig); - if (result == ISC_R_SUCCESS) { - cfg_parser_attach(nzparser, &nzcfg->nzparser); - cfg_obj_attach(nzconfig, &nzcfg->nzconfig); - } - - if (nzparser != NULL) { - if (nzconfig != NULL) - cfg_obj_destroy(nzparser, &nzconfig); - cfg_parser_destroy(&nzparser); - } + cfg_parser_reset(ns_g_addparser); + result = cfg_parse_file(ns_g_addparser, view->new_zone_file, + &cfg_type_newzones, &nzcfg->nzconfig); return (ISC_R_SUCCESS); } @@ -5948,9 +5945,9 @@ load_configuration(const char *filename, ns_server_t *server, INSIST(view != NULL); num_zones += count_zones(voptions); + CHECK(setup_newzones(view, config, vconfig, conf_parser, ns_g_aclconfctx)); - nzctx = view->new_zone_config; if (nzctx != NULL && nzctx->nzconfig != NULL) num_zones += count_zones(nzctx->nzconfig); @@ -5968,7 +5965,7 @@ load_configuration(const char *filename, ns_server_t *server, num_zones = count_zones(config); - CHECK(setup_newzones(view, config, NULL, conf_parser, + CHECK(setup_newzones(view, config, NULL, conf_parser, ns_g_aclconfctx)); nzctx = view->new_zone_config; @@ -6614,6 +6611,9 @@ run_server(isc_task_t *task, isc_event_t *event) { CHECKFATAL(cfg_parser_create(ns_g_mctx, NULL, &ns_g_parser), "creating default configuration parser"); + CHECKFATAL(cfg_parser_create(ns_g_mctx, NULL, &ns_g_addparser), + "creating additional configuration parser"); + if (ns_g_lwresdonly) CHECKFATAL(load_configuration(lwresd_g_conffile, server, ISC_TRUE), @@ -6663,6 +6663,7 @@ shutdown_server(isc_task_t *task, isc_event_t *event) { cfg_obj_destroy(ns_g_parser, &ns_g_config); cfg_parser_destroy(&ns_g_parser); + cfg_parser_destroy(&ns_g_addparser); for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; @@ -8948,40 +8949,45 @@ add_comment(FILE *fp, const char *viewname) { * Act on an "addzone" command from the command channel. */ isc_result_t -ns_server_add_zone(ns_server_t *server, char *args, isc_buffer_t **text) { - isc_result_t result, tresult; - isc_buffer_t argbuf; - size_t arglen; - cfg_parser_t *parser = NULL; - cfg_obj_t *config = NULL; - const cfg_obj_t *vconfig = NULL; - const cfg_obj_t *views = NULL; - const cfg_obj_t *parms = NULL; - const cfg_obj_t *obj = NULL; - const cfg_listelt_t *element; - const char *zonename; - const char *classname = NULL; - const char *argp; - const char *viewname = NULL; - dns_rdataclass_t rdclass; - dns_view_t *view = NULL; - isc_buffer_t buf; - dns_fixedname_t fname; - dns_name_t *dnsname; - dns_zone_t *zone = NULL; - FILE *fp = NULL; - struct cfg_context *cfg = NULL; - char namebuf[DNS_NAME_FORMATSIZE]; - off_t offset; +ns_server_addzone(ns_server_t *server, char *args, isc_buffer_t **text) { + isc_result_t result, tresult; + isc_buffer_t argbuf; + size_t arglen; + cfg_obj_t *config = NULL; + const cfg_obj_t *zlist = NULL; + const cfg_obj_t *parms = NULL; + const cfg_obj_t *obj = NULL; + const char *zonename; + const char *classname = NULL; + const char *argp; + const char *viewname = NULL; + dns_rdataclass_t rdclass; + dns_view_t *view = NULL; + isc_buffer_t buf; + dns_fixedname_t fname; + dns_name_t *dnsname; + dns_zone_t *zone = NULL; + FILE *fp = NULL; + struct cfg_context *cfg = NULL; + char namebuf[DNS_NAME_FORMATSIZE]; + off_t offset; /* Try to parse the argument string */ arglen = strlen(args); isc_buffer_init(&argbuf, args, (unsigned int)arglen); isc_buffer_add(&argbuf, strlen(args)); - CHECK(cfg_parser_create(server->mctx, ns_g_lctx, &parser)); - CHECK(cfg_parse_buffer(parser, &argbuf, &cfg_type_addzoneconf, - &config)); - CHECK(cfg_map_get(config, "addzone", &parms)); + + /* convert "addzone" to "zone", for the parser's benefit */ + isc_buffer_forward(&argbuf, 3); + + cfg_parser_reset(ns_g_addparser); + CHECK(cfg_parse_buffer(ns_g_addparser, &argbuf, + &cfg_type_addzoneconf, &config)); + CHECK(cfg_map_get(config, "zone", &zlist)); + if (! cfg_obj_islist(zlist)) + CHECK(ISC_R_FAILURE); + + parms = cfg_listelt_value(cfg_list_first(zlist)); zonename = cfg_obj_asstring(cfg_tuple_get(parms, "name")); isc_buffer_constinit(&buf, zonename, strlen(zonename)); @@ -9026,24 +9032,9 @@ ns_server_add_zone(ns_server_t *server, char *args, isc_buffer_t **text) { /* Create our sub-zone anyway */ dns_zone_detach(&zone); zone = NULL; - } - else if (result != ISC_R_NOTFOUND) + } else if (result != ISC_R_NOTFOUND) goto cleanup; - /* Find the view statement */ - cfg_map_get(cfg->config, "view", &views); - for (element = cfg_list_first(views); - element != NULL; - element = cfg_list_next(element)) - { - const char *vname; - vconfig = cfg_listelt_value(element); - vname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name")); - if (vname && !strcasecmp(vname, viewname)) - break; - vconfig = NULL; - } - /* Open save file for write configuration */ result = isc_stdio_open(view->new_zone_file, "a", &fp); if (result != ISC_R_SUCCESS) { @@ -9061,7 +9052,7 @@ ns_server_add_zone(ns_server_t *server, char *args, isc_buffer_t **text) { result = isc_task_beginexclusive(server->task); RUNTIME_CHECK(result == ISC_R_SUCCESS); dns_view_thaw(view); - result = configure_zone(cfg->config, parms, vconfig, + result = configure_zone(cfg->config, parms, cfg->vconfig, server->mctx, view, NULL, cfg->actx, ISC_FALSE, ISC_FALSE); dns_view_freeze(view); @@ -9075,6 +9066,19 @@ ns_server_add_zone(ns_server_t *server, char *args, isc_buffer_t **text) { /* Is it there yet? */ CHECK(dns_zt_find(view->zonetable, dnsname, 0, NULL, &zone)); + /* + * If there wasn't a previous newzone config, just save the one + * we've created. If there was a previous one, merge the new + * zone into it. + */ + if (cfg->nzconfig == NULL) + cfg_obj_attach(config, &cfg->nzconfig); + else { + cfg_obj_t *p; + DE_CONST(parms, p); + cfg_parser_mapadd(cfg->add_parser, cfg->nzconfig, p, "zone"); + } + /* * Load the zone from the master file. If this fails, we'll * need to undo the configuration we've done already. @@ -9148,13 +9152,10 @@ ns_server_add_zone(ns_server_t *server, char *args, isc_buffer_t **text) { cleanup: if (isc_buffer_usedlength(*text) > 0) (void) putnull(text); + if (config != NULL) + cfg_obj_destroy(ns_g_addparser, &config); if (fp != NULL) isc_stdio_close(fp); - if (parser != NULL) { - if (config != NULL) - cfg_obj_destroy(parser, &config); - cfg_parser_destroy(&parser); - } if (zone != NULL) dns_zone_detach(&zone); if (view != NULL) @@ -9165,11 +9166,11 @@ ns_server_add_zone(ns_server_t *server, char *args, isc_buffer_t **text) { static isc_boolean_t inuse(const char* file, isc_boolean_t first, isc_buffer_t **text) { -#define INUSEMSG "The following files were in use and may now be removed:\n" - if (file != NULL && isc_file_exists(file)) { if (first) - (void) putstr(text, INUSEMSG); + (void) putstr(text, + "The following files were in use " + "and may now be removed:\n"); else (void) putstr(text, "\n"); (void) putstr(text, file); @@ -9179,84 +9180,26 @@ inuse(const char* file, isc_boolean_t first, isc_buffer_t **text) { return (first); } -/* - * Act on a "delzone" command from the command channel. - */ -isc_result_t -ns_server_del_zone(ns_server_t *server, char *args, isc_buffer_t **text) { +static isc_result_t +nzf_remove(const char *nzfile, const char *viewname, const char *zonename) { + size_t znamelen; isc_result_t result; - dns_zone_t *zone = NULL; - dns_zone_t *raw = NULL; - dns_zone_t *mayberaw; - dns_view_t *view = NULL; - dns_db_t *dbp = NULL; - const char *filename = NULL; - char *tmpname = NULL; - char buf[1024]; - const char *zonename = NULL; - size_t znamelen = 0; FILE *ifp = NULL, *ofp = NULL; - isc_boolean_t exclusive = ISC_FALSE; - isc_boolean_t cleanup = ISC_FALSE; + char tmp[1024], buf[1024]; isc_boolean_t inheader = ISC_TRUE; - const char *file, *arg; - /* Parse parameters */ - (void) next_token(&args, " \t"); - arg = next_token(&args, " \t"); - if (arg != NULL && - (strcmp(arg, "-clean") == 0 || strcmp(arg, "-clear") == 0)) { - cleanup = ISC_TRUE; - arg = next_token(&args, " \t"); - } - - CHECK(zone_from_args(server, args, arg, &zone, &zonename, - text, ISC_FALSE)); - if (zone == NULL) { - result = ISC_R_UNEXPECTEDEND; - goto cleanup; - } - - result = isc_task_beginexclusive(server->task); - RUNTIME_CHECK(result == ISC_R_SUCCESS); - exclusive = ISC_TRUE; - - /* - * Was this zone originally added at runtime? - * If not, we can't delete it now. - */ - if (!dns_zone_getadded(zone)) { - result = ISC_R_NOPERM; - goto cleanup; - } - - INSIST(zonename != NULL); znamelen = strlen(zonename); - /* Dig out configuration for this zone */ - view = dns_zone_getview(zone); - filename = view->new_zone_file; - if (filename == NULL) { - /* No adding zones in this view */ - result = ISC_R_FAILURE; - goto cleanup; - } - /* Rewrite zone list */ - result = isc_stdio_open(filename, "r", &ifp); + result = isc_stdio_open(nzfile, "r", &ifp); if (ifp != NULL && result == ISC_R_SUCCESS) { char *found = NULL, *p = NULL; size_t n; /* Create a temporary file */ - CHECK(isc_string_printf(buf, 1023, "%s.%ld", filename, - (long)getpid())); - if (!(tmpname = isc_mem_strdup(server->mctx, buf))) { - result = ISC_R_NOMEMORY; - goto cleanup; - } - CHECK(isc_stdio_open(tmpname, "w", &ofp)); - CHECK(add_comment(ofp, view->name)); + CHECK(isc_file_template("", "nzf-XXXXXXXX", tmp, sizeof(tmp))); + CHECK(isc_stdio_open(tmp, "w", &ofp)); + CHECK(add_comment(ofp, viewname)); /* Look for the entry for that zone */ while (fgets(buf, 1024, ifp)) { @@ -9302,20 +9245,20 @@ ns_server_del_zone(ns_server_t *server, char *args, isc_buffer_t **text) { break; } - /* Copy the rest of the buffer out and continue */ + /* Copy the buffer out and continue */ fputs(buf, ofp); } /* Skip over an option block (matching # of braces) */ if (found) { - int obrace = 0, cbrace = 0; + int openbrace = 0, closebrace = 0; for (;;) { while (*p) { - if (*p == '{') obrace++; - if (*p == '}') cbrace++; + if (*p == '{') openbrace++; + else if (*p == '}') closebrace++; p++; } - if (obrace && (obrace == cbrace)) + if (openbrace && (openbrace == closebrace)) break; if (!fgets(buf, 1024, ifp)) break; @@ -9333,7 +9276,7 @@ ns_server_del_zone(ns_server_t *server, char *args, isc_buffer_t **text) { } /* Move temporary into place */ - CHECK(isc_file_rename(tmpname, view->new_zone_file)); + CHECK(isc_file_rename(tmp, nzfile)); } else { isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_WARNING, @@ -9343,44 +9286,111 @@ ns_server_del_zone(ns_server_t *server, char *args, isc_buffer_t **text) { } } + cleanup: + if (ifp != NULL) + isc_stdio_close(ifp); + if (ofp != NULL) + isc_stdio_close(ofp); + + return (result); +} + +/* + * Act on a "delzone" command from the command channel. + */ +isc_result_t +ns_server_delzone(ns_server_t *server, char *args, isc_buffer_t **text) { + isc_result_t result, tresult; + dns_zone_t *zone = NULL; + dns_zone_t *raw = NULL; + dns_zone_t *mayberaw; + dns_view_t *view = NULL; + dns_db_t *dbp = NULL; + const char *zonename = NULL; + isc_boolean_t exclusive = ISC_FALSE; + isc_boolean_t cleanup = ISC_FALSE; + const char *file, *arg; + isc_boolean_t added; + + /* Skip the command name. */ + arg = next_token(&args, " \t"); + if (arg == NULL) + return (ISC_R_UNEXPECTEDEND); + + /* Find out what we are to do. */ + arg = next_token(&args, " \t"); + if (arg == NULL) + return (ISC_R_UNEXPECTEDEND); + + if (strcmp(arg, "-clean") == 0 || strcmp(arg, "-clear") == 0) { + cleanup = ISC_TRUE; + arg = next_token(&args, " \t"); + } + + CHECK(zone_from_args(server, args, arg, &zone, &zonename, + text, ISC_FALSE)); + if (zone == NULL) { + result = ISC_R_UNEXPECTEDEND; + goto cleanup; + } + + INSIST(zonename != NULL); + + result = isc_task_beginexclusive(server->task); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + exclusive = ISC_TRUE; + + /* Dig out configuration for this zone */ + view = dns_zone_getview(zone); + /* Stop answering for this zone */ if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) { dns_db_detach(&dbp); dns_zone_unload(zone); } + /* Remove the zone from the new_zone_file if applicable */ + added = dns_zone_getadded(zone); + if (added && view->new_zone_file != NULL) + CHECK(nzf_remove(view->new_zone_file, view->name, zonename)); + /* Clean up stub / slave zone files */ dns_zone_getraw(zone, &raw); mayberaw = (raw != NULL) ? raw : zone; - if (cleanup) { - isc_result_t tresult; + if (!added) { + TCHECK(putstr(text, "zone '")); + TCHECK(putstr(text, zonename)); + TCHECK(putstr(text, "' is no longer loaded.\n")); + TCHECK(putstr(text, "To keep it from returning ")); + TCHECK(putstr(text, "when the server is restarted, it\n")); + TCHECK(putstr(text, "must also be removed from named.conf.")); + } else if (cleanup) { file = dns_zone_getfile(mayberaw); - if (isc_file_exists(file)) - isc_file_remove(file); + isc_file_remove(file); file = dns_zone_getjournal(mayberaw); - if (isc_file_exists(file)) - isc_file_remove(file); + isc_file_remove(file); if (zone != mayberaw) { file = dns_zone_getfile(zone); - if (isc_file_exists(file)) - isc_file_remove(file); + isc_file_remove(file); file = dns_zone_getjournal(zone); - if (isc_file_exists(file)) - isc_file_remove(file); + isc_file_remove(file); } - TCHECK(putstr(text, "zone ")); + TCHECK(putstr(text, "zone '")); TCHECK(putstr(text, zonename)); - TCHECK(putstr(text, " and associated files deleted")); - TCHECK(putnull(text)); + TCHECK(putstr(text, "' and associated files were deleted.")); } else if (dns_zone_gettype(mayberaw) == dns_zone_slave || dns_zone_gettype(mayberaw) == dns_zone_stub) { isc_boolean_t first; + TCHECK(putstr(text, "zone '")); + TCHECK(putstr(text, zonename)); + TCHECK(putstr(text, "' was deleted.\n")); + file = dns_zone_getfile(mayberaw); first = inuse(file, ISC_TRUE, text); @@ -9392,9 +9402,8 @@ ns_server_del_zone(ns_server_t *server, char *args, isc_buffer_t **text) { first = inuse(file, first, text); file = dns_zone_getjournal(zone); - (void)inuse(file, first, text); + (void) inuse(file, first, text); } - (void) putnull(text); } CHECK(dns_zt_unmount(view->zonetable, zone)); @@ -9411,24 +9420,114 @@ ns_server_del_zone(ns_server_t *server, char *args, isc_buffer_t **text) { cleanup: if (isc_buffer_usedlength(*text) > 0) (void) putnull(text); - if (exclusive) - isc_task_endexclusive(server->task); - if (ifp != NULL) - isc_stdio_close(ifp); - if (ofp != NULL) { - isc_stdio_close(ofp); - isc_file_remove(tmpname); - } - if (tmpname != NULL) - isc_mem_free(server->mctx, tmpname); if (raw != NULL) dns_zone_detach(&raw); + if (exclusive) + isc_task_endexclusive(server->task); if (zone != NULL) dns_zone_detach(&zone); return (result); } +/* + * Act on a "showzone" command from the command channel. + */ +static const cfg_obj_t * +find_name_in_list_from_map(const cfg_obj_t *config, + const char *map_key_for_list, + const char *name) +{ + const cfg_obj_t *list = NULL; + const cfg_listelt_t *element; + const cfg_obj_t *result; + + cfg_map_get(config, map_key_for_list, &list); + for (element = cfg_list_first(list); + element != NULL; + element = cfg_list_next(element)) + { + const char *vname; + result = cfg_listelt_value(element); + INSIST(result != NULL); + vname = cfg_obj_asstring(cfg_tuple_get(result, "name")); + if (vname != NULL && !strcasecmp(vname, name)) + break; + result = NULL; + } + + return (result); +} + +static void +dumpit(void *arg, const char *buf, int len) { + isc_buffer_t **tpp = arg; + putmem(tpp, buf, len); +} + +isc_result_t +ns_server_showzone(ns_server_t *server, char *args, isc_buffer_t **text) { + isc_result_t result; + const cfg_obj_t *vconfig = NULL, *zconfig = NULL; + const char *zonename = NULL; + const cfg_obj_t *map; + dns_view_t *view = NULL; + dns_zone_t *zone = NULL; + struct cfg_context *cfg = NULL; + isc_boolean_t exclusive = ISC_FALSE; + + /* Parse parameters */ + CHECK(zone_from_args(server, args, NULL, &zone, &zonename, + text, ISC_TRUE)); + if (zone == NULL) { + result = ISC_R_UNEXPECTEDEND; + goto cleanup; + } + + view = dns_zone_getview(zone); + dns_zone_detach(&zone); + + cfg = (struct cfg_context *) view->new_zone_config; + if (cfg == NULL) { + result = ISC_R_FAILURE; + goto cleanup; + } + + result = isc_task_beginexclusive(server->task); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + exclusive = ISC_TRUE; + + /* Find the view statement */ + vconfig = find_name_in_list_from_map(cfg->config, "view", view->name); + + /* Find the zone statement */ + if (vconfig != NULL) + map = cfg_tuple_get(vconfig, "options"); + else + map = cfg->config; + + zconfig = find_name_in_list_from_map(map, "zone", zonename); + if (zconfig == NULL) + zconfig = find_name_in_list_from_map(cfg->nzconfig, + "zone", zonename); + if (zconfig == NULL) + CHECK(ISC_R_NOTFOUND); + + putstr(text, "zone "); + cfg_printx(zconfig, CFG_PRINTER_ONELINE, dumpit, text); + putstr(text, ";"); + + result = ISC_R_SUCCESS; + + cleanup: + if (isc_buffer_usedlength(*text) > 0) + (void) putnull(text); + if (exclusive) + isc_task_endexclusive(server->task); + + return (result); +} + static void newzone_cfgctx_destroy(void **cfgp) { struct cfg_context *cfg; @@ -9437,20 +9536,22 @@ newzone_cfgctx_destroy(void **cfgp) { cfg = *cfgp; + if (cfg->conf_parser != NULL) { + if (cfg->config != NULL) + cfg_obj_destroy(cfg->conf_parser, &cfg->config); + if (cfg->vconfig != NULL) + cfg_obj_destroy(cfg->conf_parser, &cfg->vconfig); + cfg_parser_destroy(&cfg->conf_parser); + } + if (cfg->add_parser != NULL) { + if (cfg->nzconfig != NULL) + cfg_obj_destroy(cfg->add_parser, &cfg->nzconfig); + cfg_parser_destroy(&cfg->add_parser); + } + if (cfg->actx != NULL) cfg_aclconfctx_detach(&cfg->actx); - if (cfg->parser != NULL) { - if (cfg->config != NULL) - cfg_obj_destroy(cfg->parser, &cfg->config); - cfg_parser_destroy(&cfg->parser); - } - if (cfg->nzparser != NULL) { - if (cfg->nzconfig != NULL) - cfg_obj_destroy(cfg->nzparser, &cfg->nzconfig); - cfg_parser_destroy(&cfg->nzparser); - } - isc_mem_putanddetach(&cfg->mctx, cfg, sizeof(*cfg)); *cfgp = NULL; } diff --git a/bin/rndc/rndc.docbook b/bin/rndc/rndc.docbook index b688fe8e96..55af7c67c6 100644 --- a/bin/rndc/rndc.docbook +++ b/bin/rndc/rndc.docbook @@ -730,9 +730,6 @@ Delete a zone while the server is running. - Only zones that were originally added via - rndc addzone can be deleted - in this manner. If the is specified, @@ -744,6 +741,25 @@ be cleaned up will be reported in the output of the rndc delzone command.) + + If the zone was originally added via + rndc addzone, then it will be + removed permanently. However, if it was originally + configured in named.conf, then + that original configuration is still in place; when + the server is restarted or reconfigured, the zone will + come back. To remove it permanently, it must also be + removed from named.conf + + + + + + showzone zone class view + + + Print the configuration of a running zone. + diff --git a/bin/tests/system/addzone/tests.sh b/bin/tests/system/addzone/tests.sh index ff7b5c05f0..a6fe69da24 100755 --- a/bin/tests/system/addzone/tests.sh +++ b/bin/tests/system/addzone/tests.sh @@ -92,6 +92,15 @@ n=`expr $n + 1` if [ $ret != 0 ]; then echo "I:failed"; fi status=`expr $status + $ret` +echo "I:checking rndc showzone with previously added zone ($n)" +ret=0 +$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 showzone previous.example > rndc.out.ns2.$n +expected='zone "previous.example" { type master; file "previous.db"; };' +[ "`cat rndc.out.ns2.$n`" = "$expected" ] || ret=1 +n=`expr $n + 1` +if [ $ret != 0 ]; then echo "I:failed"; fi +status=`expr $status + $ret` + echo "I:deleting previously added zone ($n)" ret=0 $RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 delzone previous.example 2>&1 | sed 's/^/I:ns2 /' @@ -130,13 +139,20 @@ n=`expr $n + 1` if [ $ret != 0 ]; then echo "I:failed"; fi status=`expr $status + $ret` -echo "I:attempt to delete a normally-loaded zone ($n)" +echo "I:checking rndc showzone with a normally-loaded zone ($n)" +ret=0 +$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 showzone normal.example > rndc.out.ns2.$n +expected='zone "normal.example" { type master; file "normal.db"; };' +[ "`cat rndc.out.ns2.$n`" = "$expected" ] || ret=1 +n=`expr $n + 1` +if [ $ret != 0 ]; then echo "I:failed"; fi +status=`expr $status + $ret` + +echo "I:delete a normally-loaded zone ($n)" ret=0 $RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 delzone normal.example 2> rndc.out.ns2.$n -grep "permission denied" rndc.out.ns2.$n > /dev/null || ret=1 $DIG $DIGOPTS @10.53.0.2 a.normal.example a > dig.out.ns2.$n -grep 'status: NOERROR' dig.out.ns2.$n > /dev/null || ret=1 -grep '^a.normal.example' dig.out.ns2.$n > /dev/null || ret=1 +grep 'status: REFUSED' dig.out.ns2.$n > /dev/null || ret=1 n=`expr $n + 1` if [ $ret != 0 ]; then echo "I:failed"; fi status=`expr $status + $ret` @@ -267,6 +283,14 @@ n=`expr $n + 1` if [ $ret != 0 ]; then echo "I:failed"; fi status=`expr $status + $ret` +echo "I:checking rndc showzone with newly added zone ($n)" +ret=0 +$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 showzone added.example in external > rndc.out.ns2.$n +expected='zone "added.example" in external { type master; file "added.db"; };' +[ "`cat rndc.out.ns2.$n`" = "$expected" ] || ret=1 +n=`expr $n + 1` +if [ $ret != 0 ]; then echo "I:failed"; fi +status=`expr $status + $ret` echo "I:deleting newly added zone ($n)" ret=0 diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml index b459d6a04d..406dc646d9 100644 --- a/doc/arm/Bv9ARM-book.xml +++ b/doc/arm/Bv9ARM-book.xml @@ -5894,8 +5894,7 @@ options { If yes, then zones can be - added at runtime via rndc addzone - or deleted via rndc delzone. + added at runtime via rndc addzone. The default is no. diff --git a/doc/arm/notes.xml b/doc/arm/notes.xml index e0f7338872..52ffd6c9a5 100644 --- a/doc/arm/notes.xml +++ b/doc/arm/notes.xml @@ -251,6 +251,23 @@ line option. + + + rndc delzone can now be applied to zones + which were configured in named.conf; + it is no longer restricted to zones which were added by + rndc addzone. (Note, however, that + this does not edit named.conf; the zone + must be removed from the configuration or it will return + when named is restarted or reloaded.) + + + + + rndc showzone displays the current + configuration for a specified zone. + + diff --git a/lib/isccfg/include/isccfg/cfg.h b/lib/isccfg/include/isccfg/cfg.h index e6176ecbc4..a0af6bfb07 100644 --- a/lib/isccfg/include/isccfg/cfg.h +++ b/lib/isccfg/include/isccfg/cfg.h @@ -39,7 +39,6 @@ #include #include - /*** *** Types ***/ @@ -144,6 +143,26 @@ cfg_parse_buffer(cfg_parser_t *pctx, isc_buffer_t *buffer, *\li others - file contains errors */ +isc_result_t +cfg_parser_mapadd(cfg_parser_t *pctx, cfg_obj_t *mapobj, + cfg_obj_t *obj, const char *clause); +/*%< + * Add the object 'obj' to the specified clause in mapbody 'mapobj'. + * Used for adding new zones. + * + * Require: + * \li 'obj' is a valid cfg_obj_t. + * \li 'mapobj' is a valid cfg_obj_t of type map. + * \li 'pctx' is a valid cfg_parser_t. + */ + +void +cfg_parser_reset(cfg_parser_t *pctx); +/*%< + * Reset an existing parser so it can be re-used for a new file or + * buffer. + */ + void cfg_parser_destroy(cfg_parser_t **pctxp); /*%< @@ -412,6 +431,7 @@ cfg_printx(const cfg_obj_t *obj, unsigned int flags, void *closure); #define CFG_PRINTER_XKEY 0x1 /* '?' out shared keys. */ +#define CFG_PRINTER_ONELINE 0x2 /* print config as a single line */ /*%< * Print the configuration object 'obj' by repeatedly calling the @@ -475,7 +495,6 @@ cfg_obj_line(const cfg_obj_t *obj); * Return the line in file where this object was defined. */ - ISC_LANG_ENDDECLS #endif /* ISCCFG_CFG_H */ diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c index ed8424d559..0fffdd49d6 100644 --- a/lib/isccfg/namedconf.c +++ b/lib/isccfg/namedconf.c @@ -304,9 +304,9 @@ parse_matchname(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { static void doc_matchname(cfg_printer_t *pctx, const cfg_type_t *type) { - cfg_print_chars(pctx, "[ ", 2); + cfg_print_cstr(pctx, "[ "); cfg_doc_obj(pctx, type->of); - cfg_print_chars(pctx, " ]", 2); + cfg_print_cstr(pctx, " ]"); } static const char *matchtype_enums[] = { @@ -739,11 +739,11 @@ parse_boolorauto(cfg_parser_t *pctx, const cfg_type_t *type, static void print_boolorauto(cfg_printer_t *pctx, const cfg_obj_t *obj) { if (obj->type->rep == &cfg_rep_void) - cfg_print_chars(pctx, "auto", 4); + cfg_print_cstr(pctx, "auto"); else if (obj->value.boolean) - cfg_print_chars(pctx, "yes", 3); + cfg_print_cstr(pctx, "yes"); else - cfg_print_chars(pctx, "no", 2); + cfg_print_cstr(pctx, "no"); } static void @@ -1117,18 +1117,18 @@ doc_rpz_policy(cfg_printer_t *pctx, const cfg_type_t *type) { /* * This is cfg_doc_enum() without the trailing " )". */ - cfg_print_chars(pctx, "( ", 2); + cfg_print_cstr(pctx, "( "); for (p = type->of; *p != NULL; p++) { cfg_print_cstr(pctx, *p); if (p[1] != NULL) - cfg_print_chars(pctx, " | ", 3); + cfg_print_cstr(pctx, " | "); } } static void doc_rpz_cname(cfg_printer_t *pctx, const cfg_type_t *type) { cfg_doc_terminal(pctx, type); - cfg_print_chars(pctx, " )", 2); + cfg_print_cstr(pctx, " )"); } /* @@ -1232,9 +1232,9 @@ cfg_print_kv_tuple(cfg_printer_t *pctx, const cfg_obj_t *obj) { if (fieldobj->type->print == cfg_print_void) continue; if (i != 0) { - cfg_print_chars(pctx, " ", 1); + cfg_print_cstr(pctx, " "); cfg_print_cstr(pctx, f->name); - cfg_print_chars(pctx, " ", 1); + cfg_print_cstr(pctx, " "); } cfg_print_obj(pctx, fieldobj); } @@ -1247,14 +1247,14 @@ cfg_doc_kv_tuple(cfg_printer_t *pctx, const cfg_type_t *type) { fields = type->of; for (f = fields; f->name != NULL; f++) { if (f != fields) { - cfg_print_chars(pctx, " [ ", 3); + cfg_print_cstr(pctx, " [ "); cfg_print_cstr(pctx, f->name); if (f->type->doc != cfg_doc_void) - cfg_print_chars(pctx, " ", 1); + cfg_print_cstr(pctx, " "); } cfg_doc_obj(pctx, f->type); if (f != fields) - cfg_print_chars(pctx, " ]", 2); + cfg_print_cstr(pctx, " ]"); } } @@ -1931,11 +1931,11 @@ static cfg_tuplefielddef_t addzone_fields[] = { { NULL, NULL, 0 } }; static cfg_type_t cfg_type_addzone = { - "addzone", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, addzone_fields }; + "zone", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, addzone_fields }; static cfg_clausedef_t addzoneconf_clauses[] = { - { "addzone", &cfg_type_addzone, 0 }, + { "zone", &cfg_type_addzone, CFG_CLAUSEFLAG_MULTI }, { NULL, NULL, 0 } }; @@ -2119,7 +2119,7 @@ static void print_keyvalue(cfg_printer_t *pctx, const cfg_obj_t *obj) { const keyword_type_t *kw = obj->type->of; cfg_print_cstr(pctx, kw->name); - cfg_print_chars(pctx, " ", 1); + cfg_print_cstr(pctx, " "); kw->type->print(pctx, obj); } @@ -2127,18 +2127,18 @@ static void doc_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type) { const keyword_type_t *kw = type->of; cfg_print_cstr(pctx, kw->name); - cfg_print_chars(pctx, " ", 1); + cfg_print_cstr(pctx, " "); cfg_doc_obj(pctx, kw->type); } static void doc_optional_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type) { const keyword_type_t *kw = type->of; - cfg_print_chars(pctx, "[ ", 2); + cfg_print_cstr(pctx, "[ "); cfg_print_cstr(pctx, kw->name); - cfg_print_chars(pctx, " ", 1); + cfg_print_cstr(pctx, " "); cfg_doc_obj(pctx, kw->type); - cfg_print_chars(pctx, " ]", 2); + cfg_print_cstr(pctx, " ]"); } static const char *dialup_enums[] = { @@ -2283,9 +2283,9 @@ doc_geoip(cfg_printer_t *pctx, const cfg_type_t *type) { cfg_print_cstr(pctx, "[ db "); cfg_doc_enum(pctx, &cfg_type_geoipdb); cfg_print_cstr(pctx, " ]"); - cfg_print_chars(pctx, " ", 1); + cfg_print_cstr(pctx, " "); cfg_doc_enum(pctx, &cfg_type_geoiptype); - cfg_print_chars(pctx, " ", 1); + cfg_print_cstr(pctx, " "); cfg_print_cstr(pctx, ""); } #endif /* HAVE_GEOIP */ @@ -2399,11 +2399,11 @@ static cfg_type_t cfg_type_controls = { static void doc_optional_bracketed_list(cfg_printer_t *pctx, const cfg_type_t *type) { const keyword_type_t *kw = type->of; - cfg_print_chars(pctx, "[ ", 2); + cfg_print_cstr(pctx, "[ "); cfg_print_cstr(pctx, kw->name); - cfg_print_chars(pctx, " ", 1); + cfg_print_cstr(pctx, " "); cfg_doc_obj(pctx, kw->type); - cfg_print_chars(pctx, " ]", 2); + cfg_print_cstr(pctx, " ]"); } static cfg_type_t cfg_type_optional_allow = { @@ -2646,7 +2646,7 @@ static cfg_tuplefielddef_t negated_fields[] = { static void print_negated(cfg_printer_t *pctx, const cfg_obj_t *obj) { - cfg_print_chars(pctx, "!", 1); + cfg_print_cstr(pctx, "!"); cfg_print_tuple(pctx, obj); } @@ -2881,9 +2881,9 @@ static void doc_logfile(cfg_printer_t *pctx, const cfg_type_t *type) { UNUSED(type); cfg_print_cstr(pctx, ""); - cfg_print_chars(pctx, " ", 1); + cfg_print_cstr(pctx, " "); cfg_print_cstr(pctx, "[ versions ( \"unlimited\" | ) ]"); - cfg_print_chars(pctx, " ", 1); + cfg_print_cstr(pctx, " "); cfg_print_cstr(pctx, "[ size ]"); } @@ -3049,25 +3049,25 @@ static cfg_type_t cfg_type_nameport = { static void doc_sockaddrnameport(cfg_printer_t *pctx, const cfg_type_t *type) { UNUSED(type); - cfg_print_chars(pctx, "( ", 2); + cfg_print_cstr(pctx, "( "); cfg_print_cstr(pctx, ""); - cfg_print_chars(pctx, " ", 1); + cfg_print_cstr(pctx, " "); cfg_print_cstr(pctx, "[ port ]"); - cfg_print_chars(pctx, " ", 1); + cfg_print_cstr(pctx, " "); cfg_print_cstr(pctx, "[ dscp ]"); - cfg_print_chars(pctx, " | ", 3); + cfg_print_cstr(pctx, " | "); cfg_print_cstr(pctx, ""); - cfg_print_chars(pctx, " ", 1); + cfg_print_cstr(pctx, " "); cfg_print_cstr(pctx, "[ port ]"); - cfg_print_chars(pctx, " ", 1); + cfg_print_cstr(pctx, " "); cfg_print_cstr(pctx, "[ dscp ]"); - cfg_print_chars(pctx, " | ", 3); + cfg_print_cstr(pctx, " | "); cfg_print_cstr(pctx, ""); - cfg_print_chars(pctx, " ", 1); + cfg_print_cstr(pctx, " "); cfg_print_cstr(pctx, "[ port ]"); - cfg_print_chars(pctx, " ", 1); + cfg_print_cstr(pctx, " "); cfg_print_cstr(pctx, "[ dscp ]"); - cfg_print_chars(pctx, " )", 2); + cfg_print_cstr(pctx, " )"); } static isc_result_t @@ -3141,17 +3141,17 @@ static cfg_type_t cfg_type_nameportiplist = { static void doc_masterselement(cfg_printer_t *pctx, const cfg_type_t *type) { UNUSED(type); - cfg_print_chars(pctx, "( ", 2); + cfg_print_cstr(pctx, "( "); cfg_print_cstr(pctx, ""); - cfg_print_chars(pctx, " | ", 3); + cfg_print_cstr(pctx, " | "); cfg_print_cstr(pctx, ""); - cfg_print_chars(pctx, " ", 1); + cfg_print_cstr(pctx, " "); cfg_print_cstr(pctx, "[ port ]"); - cfg_print_chars(pctx, " | ", 3); + cfg_print_cstr(pctx, " | "); cfg_print_cstr(pctx, ""); - cfg_print_chars(pctx, " ", 1); + cfg_print_cstr(pctx, " "); cfg_print_cstr(pctx, "[ port ]"); - cfg_print_chars(pctx, " )", 2); + cfg_print_cstr(pctx, " )"); } static isc_result_t diff --git a/lib/isccfg/parser.c b/lib/isccfg/parser.c index 3c4444d57e..956853b039 100644 --- a/lib/isccfg/parser.c +++ b/lib/isccfg/parser.c @@ -147,24 +147,34 @@ cfg_print_chars(cfg_printer_t *pctx, const char *text, int len) { static void print_open(cfg_printer_t *pctx) { - cfg_print_chars(pctx, "{\n", 2); - pctx->indent++; + if ((pctx->flags & CFG_PRINTER_ONELINE) != 0) + cfg_print_cstr(pctx, "{ "); + else { + cfg_print_cstr(pctx, "{\n"); + pctx->indent++; + } } static void print_indent(cfg_printer_t *pctx) { int indent = pctx->indent; + if ((pctx->flags & CFG_PRINTER_ONELINE) != 0) { + cfg_print_cstr(pctx, " "); + return; + } while (indent > 0) { - cfg_print_chars(pctx, "\t", 1); + cfg_print_cstr(pctx, "\t"); indent--; } } static void print_close(cfg_printer_t *pctx) { - pctx->indent--; - print_indent(pctx); - cfg_print_chars(pctx, "}", 1); + if ((pctx->flags & CFG_PRINTER_ONELINE) == 0) { + pctx->indent--; + print_indent(pctx); + } + cfg_print_cstr(pctx, "}"); } isc_result_t @@ -262,7 +272,7 @@ cfg_print_tuple(cfg_printer_t *pctx, const cfg_obj_t *obj) { for (f = fields, i = 0; f->name != NULL; f++, i++) { const cfg_obj_t *fieldobj = obj->value.tuple[i]; if (need_space) - cfg_print_chars(pctx, " ", 1); + cfg_print_cstr(pctx, " "); cfg_print_obj(pctx, fieldobj); need_space = ISC_TF(fieldobj->type->print != cfg_print_void); } @@ -276,7 +286,7 @@ cfg_doc_tuple(cfg_printer_t *pctx, const cfg_type_t *type) { for (f = fields; f->name != NULL; f++) { if (need_space) - cfg_print_chars(pctx, " ", 1); + cfg_print_cstr(pctx, " "); cfg_doc_obj(pctx, f->type); need_space = ISC_TF(f->type->print != cfg_print_void); } @@ -481,6 +491,20 @@ cfg_parser_setcallback(cfg_parser_t *pctx, pctx->callbackarg = arg; } +void +cfg_parser_reset(cfg_parser_t *pctx) { + REQUIRE(pctx != NULL); + + if (pctx->lexer != NULL) + isc_lex_close(pctx->lexer); + + pctx->seen_eof = ISC_FALSE; + pctx->ungotten = ISC_FALSE; + pctx->errors = 0; + pctx->warnings = 0; + pctx->line = 0; +} + /* * Parse a configuration using a pctx where a lexer has already * been set up with a source. @@ -535,9 +559,12 @@ cfg_parse_buffer(cfg_parser_t *pctx, isc_buffer_t *buffer, const cfg_type_t *type, cfg_obj_t **ret) { isc_result_t result; + REQUIRE(buffer != NULL); + CHECK(isc_lex_openbuffer(pctx->lexer, buffer)); CHECK(parse2(pctx, type, ret)); + cleanup: return (result); } @@ -821,13 +848,13 @@ cfg_parse_enum(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { void cfg_doc_enum(cfg_printer_t *pctx, const cfg_type_t *type) { const char * const *p; - cfg_print_chars(pctx, "( ", 2); + cfg_print_cstr(pctx, "( "); for (p = type->of; *p != NULL; p++) { cfg_print_cstr(pctx, *p); if (p[1] != NULL) - cfg_print_chars(pctx, " | ", 3); + cfg_print_cstr(pctx, " | "); } - cfg_print_chars(pctx, " )", 2); + cfg_print_cstr(pctx, " )"); } void @@ -837,21 +864,21 @@ cfg_print_ustring(cfg_printer_t *pctx, const cfg_obj_t *obj) { static void print_qstring(cfg_printer_t *pctx, const cfg_obj_t *obj) { - cfg_print_chars(pctx, "\"", 1); + cfg_print_cstr(pctx, "\""); cfg_print_ustring(pctx, obj); - cfg_print_chars(pctx, "\"", 1); + cfg_print_cstr(pctx, "\""); } static void print_sstring(cfg_printer_t *pctx, const cfg_obj_t *obj) { - cfg_print_chars(pctx, "\"", 1); + cfg_print_cstr(pctx, "\""); if ((pctx->flags & CFG_PRINTER_XKEY) != 0) { unsigned int len = obj->value.string.length; while (len-- > 0) - cfg_print_chars(pctx, "?", 1); + cfg_print_cstr(pctx, "?"); } else cfg_print_ustring(pctx, obj); - cfg_print_chars(pctx, "\"", 1); + cfg_print_cstr(pctx, "\""); } static void @@ -958,9 +985,9 @@ cfg_parse_boolean(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) void cfg_print_boolean(cfg_printer_t *pctx, const cfg_obj_t *obj) { if (obj->value.boolean) - cfg_print_chars(pctx, "yes", 3); + cfg_print_cstr(pctx, "yes"); else - cfg_print_chars(pctx, "no", 2); + cfg_print_cstr(pctx, "no"); } cfg_type_t cfg_type_boolean = { @@ -994,8 +1021,9 @@ create_listelt(cfg_parser_t *pctx, cfg_listelt_t **eltp) { } static void -free_list_elt(cfg_parser_t *pctx, cfg_listelt_t *elt) { - cfg_obj_destroy(pctx, &elt->obj); +free_listelt(cfg_parser_t *pctx, cfg_listelt_t *elt) { + if (elt->obj != NULL) + cfg_obj_destroy(pctx, &elt->obj); isc_mem_put(pctx->mctx, elt, sizeof(*elt)); } @@ -1007,7 +1035,7 @@ free_list(cfg_parser_t *pctx, cfg_obj_t *obj) { elt = next) { next = ISC_LIST_NEXT(elt, link); - free_list_elt(pctx, elt); + free_listelt(pctx, elt); } } @@ -1064,7 +1092,7 @@ parse_list(cfg_parser_t *pctx, const cfg_type_t *listtype, cfg_obj_t **ret) cleanup: if (elt != NULL) - free_list_elt(pctx, elt); + free_listelt(pctx, elt); CLEANUP_OBJ(listobj); return (result); } @@ -1076,10 +1104,16 @@ print_list(cfg_printer_t *pctx, const cfg_obj_t *obj) { for (elt = ISC_LIST_HEAD(*list); elt != NULL; - elt = ISC_LIST_NEXT(elt, link)) { - print_indent(pctx); - cfg_print_obj(pctx, elt->obj); - cfg_print_chars(pctx, ";\n", 2); + elt = ISC_LIST_NEXT(elt, link)) + { + if ((pctx->flags & CFG_PRINTER_ONELINE) != 0) { + cfg_print_obj(pctx, elt->obj); + cfg_print_cstr(pctx, "; "); + } else { + print_indent(pctx); + cfg_print_obj(pctx, elt->obj); + cfg_print_cstr(pctx, ";\n"); + } } } @@ -1104,9 +1138,9 @@ cfg_print_bracketed_list(cfg_printer_t *pctx, const cfg_obj_t *obj) { void cfg_doc_bracketed_list(cfg_printer_t *pctx, const cfg_type_t *type) { - cfg_print_chars(pctx, "{ ", 2); + cfg_print_cstr(pctx, "{ "); cfg_doc_obj(pctx, type->of); - cfg_print_chars(pctx, "; ... }", 7); + cfg_print_cstr(pctx, "; ... }"); } /* @@ -1152,7 +1186,7 @@ cfg_print_spacelist(cfg_printer_t *pctx, const cfg_obj_t *obj) { elt = ISC_LIST_NEXT(elt, link)) { cfg_print_obj(pctx, elt->obj); if (ISC_LIST_NEXT(elt, link) != NULL) - cfg_print_chars(pctx, " ", 1); + cfg_print_cstr(pctx, " "); } } @@ -1476,10 +1510,24 @@ cfg_parse_netprefix_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t ** return (parse_any_named_map(pctx, &cfg_type_netprefix, type, ret)); } +static void +print_symval(cfg_printer_t *pctx, const char *name, cfg_obj_t *obj) { + if ((pctx->flags & CFG_PRINTER_ONELINE) == 0) + print_indent(pctx); + + cfg_print_cstr(pctx, name); + cfg_print_cstr(pctx, " "); + cfg_print_obj(pctx, obj); + + if ((pctx->flags & CFG_PRINTER_ONELINE) == 0) + cfg_print_cstr(pctx, ";\n"); + else + cfg_print_cstr(pctx, "; "); +} + void cfg_print_mapbody(cfg_printer_t *pctx, const cfg_obj_t *obj) { isc_result_t result = ISC_R_SUCCESS; - const cfg_clausedef_t * const *clauseset; for (clauseset = obj->value.map.clausesets; @@ -1503,19 +1551,13 @@ cfg_print_mapbody(cfg_printer_t *pctx, const cfg_obj_t *obj) { 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); + print_symval(pctx, + clause->name, + elt->obj); } } 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); + print_symval(pctx, clause->name, obj); } } else if (result == ISC_R_NOTFOUND) { ; /* do nothing */ @@ -1536,11 +1578,10 @@ cfg_doc_mapbody(cfg_printer_t *pctx, const cfg_type_t *type) { clause->name != NULL; clause++) { cfg_print_cstr(pctx, clause->name); - cfg_print_chars(pctx, " ", 1); + cfg_print_cstr(pctx, " "); cfg_doc_obj(pctx, clause->type); - cfg_print_chars(pctx, ";", 1); /* XXX print flags here? */ - cfg_print_chars(pctx, "\n\n", 2); + cfg_print_cstr(pctx, ";\n\n"); } } } @@ -1562,7 +1603,7 @@ void cfg_print_map(cfg_printer_t *pctx, const cfg_obj_t *obj) { if (obj->value.map.id != NULL) { cfg_print_obj(pctx, obj->value.map.id); - cfg_print_chars(pctx, " ", 1); + cfg_print_cstr(pctx, " "); } print_open(pctx); cfg_print_mapbody(pctx, obj); @@ -1576,9 +1617,9 @@ print_clause_flags(cfg_printer_t *pctx, unsigned int flags) { for (p = flagtexts; p->flag != 0; p++) { if ((flags & p->flag) != 0) { if (first) - cfg_print_chars(pctx, " // ", 4); + cfg_print_cstr(pctx, " // "); else - cfg_print_chars(pctx, ", ", 2); + cfg_print_cstr(pctx, ", "); cfg_print_cstr(pctx, p->text); first = ISC_FALSE; } @@ -1592,13 +1633,13 @@ cfg_doc_map(cfg_printer_t *pctx, const cfg_type_t *type) { if (type->parse == cfg_parse_named_map) { cfg_doc_obj(pctx, &cfg_type_astring); - cfg_print_chars(pctx, " ", 1); + cfg_print_cstr(pctx, " "); } else if (type->parse == cfg_parse_addressed_map) { cfg_doc_obj(pctx, &cfg_type_netaddr); - cfg_print_chars(pctx, " ", 1); + cfg_print_cstr(pctx, " "); } else if (type->parse == cfg_parse_netprefix_map) { cfg_doc_obj(pctx, &cfg_type_netprefix); - cfg_print_chars(pctx, " ", 1); + cfg_print_cstr(pctx, " "); } print_open(pctx); @@ -1610,11 +1651,11 @@ cfg_doc_map(cfg_printer_t *pctx, const cfg_type_t *type) { print_indent(pctx); cfg_print_cstr(pctx, clause->name); if (clause->type->print != cfg_print_void) - cfg_print_chars(pctx, " ", 1); + cfg_print_cstr(pctx, " "); cfg_doc_obj(pctx, clause->type); - cfg_print_chars(pctx, ";", 1); + cfg_print_cstr(pctx, ";"); print_clause_flags(pctx, clause->flags); - cfg_print_chars(pctx, "\n", 1); + cfg_print_cstr(pctx, "\n"); } } print_close(pctx); @@ -1910,7 +1951,8 @@ cfg_print_rawaddr(cfg_printer_t *pctx, const isc_netaddr_t *na) { isc_buffer_init(&buf, text, sizeof(text)); result = isc_netaddr_totext(na, &buf); RUNTIME_CHECK(result == ISC_R_SUCCESS); - cfg_print_chars(pctx, isc_buffer_base(&buf), isc_buffer_usedlength(&buf)); + cfg_print_chars(pctx, isc_buffer_base(&buf), + isc_buffer_usedlength(&buf)); } isc_result_t @@ -1965,26 +2007,26 @@ cfg_doc_netaddr(cfg_printer_t *pctx, const cfg_type_t *type) { const unsigned int *flagp = type->of; int n = 0; if (*flagp != CFG_ADDR_V4OK && *flagp != CFG_ADDR_V6OK) - cfg_print_chars(pctx, "( ", 2); + cfg_print_cstr(pctx, "( "); if (*flagp & CFG_ADDR_V4OK) { cfg_print_cstr(pctx, ""); n++; } if (*flagp & CFG_ADDR_V6OK) { if (n != 0) - cfg_print_chars(pctx, " | ", 3); + cfg_print_cstr(pctx, " | "); cfg_print_cstr(pctx, ""); n++; } if (*flagp & CFG_ADDR_WILDOK) { if (n != 0) - cfg_print_chars(pctx, " | ", 3); - cfg_print_chars(pctx, "*", 1); + cfg_print_cstr(pctx, " | "); + cfg_print_cstr(pctx, "*"); n++; POST(n); } if (*flagp != CFG_ADDR_V4OK && *flagp != CFG_ADDR_V6OK) - cfg_print_chars(pctx, " )", 2); + cfg_print_cstr(pctx, " )"); } cfg_type_t cfg_type_netaddr = { @@ -2071,7 +2113,7 @@ print_netprefix(cfg_printer_t *pctx, const cfg_obj_t *obj) { const cfg_netprefix_t *p = &obj->value.netprefix; cfg_print_rawaddr(pctx, &p->address); - cfg_print_chars(pctx, "/", 1); + cfg_print_cstr(pctx, "/"); cfg_print_rawuint(pctx, p->prefixlen); } @@ -2180,11 +2222,11 @@ cfg_print_sockaddr(cfg_printer_t *pctx, const cfg_obj_t *obj) { cfg_print_cstr(pctx, buf); port = isc_sockaddr_getport(&obj->value.sockaddr); if (port != 0) { - cfg_print_chars(pctx, " port ", 6); + cfg_print_cstr(pctx, " port "); cfg_print_rawuint(pctx, port); } if (obj->value.sockaddrdscp.dscp != -1) { - cfg_print_chars(pctx, " dscp ", 6); + cfg_print_cstr(pctx, " dscp "); cfg_print_rawuint(pctx, obj->value.sockaddrdscp.dscp); } } @@ -2193,25 +2235,25 @@ void cfg_doc_sockaddr(cfg_printer_t *pctx, const cfg_type_t *type) { const unsigned int *flagp = type->of; int n = 0; - cfg_print_chars(pctx, "( ", 2); + cfg_print_cstr(pctx, "( "); if (*flagp & CFG_ADDR_V4OK) { cfg_print_cstr(pctx, ""); n++; } if (*flagp & CFG_ADDR_V6OK) { if (n != 0) - cfg_print_chars(pctx, " | ", 3); + cfg_print_cstr(pctx, " | "); cfg_print_cstr(pctx, ""); n++; } if (*flagp & CFG_ADDR_WILDOK) { if (n != 0) - cfg_print_chars(pctx, " | ", 3); - cfg_print_chars(pctx, "*", 1); + cfg_print_cstr(pctx, " | "); + cfg_print_cstr(pctx, "*"); n++; POST(n); } - cfg_print_chars(pctx, " ) ", 3); + cfg_print_cstr(pctx, " ) "); if (*flagp & CFG_ADDR_WILDOK) { cfg_print_cstr(pctx, "[ port ( | * ) ]"); } else { @@ -2510,7 +2552,6 @@ map_symtabitem_destroy(char *key, unsigned int type, cfg_obj_destroy(pctx, &obj); } - static isc_result_t create_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { isc_result_t result; @@ -2587,9 +2628,9 @@ cfg_doc_obj(cfg_printer_t *pctx, const cfg_type_t *type) { void cfg_doc_terminal(cfg_printer_t *pctx, const cfg_type_t *type) { - cfg_print_chars(pctx, "<", 1); + cfg_print_cstr(pctx, "<"); cfg_print_cstr(pctx, type->name); - cfg_print_chars(pctx, ">", 1); + cfg_print_cstr(pctx, ">"); } void @@ -2604,3 +2645,72 @@ cfg_print_grammar(const cfg_type_t *type, pctx.flags = 0; cfg_doc_obj(&pctx, type); } + +isc_result_t +cfg_parser_mapadd(cfg_parser_t *pctx, cfg_obj_t *mapobj, + cfg_obj_t *obj, const char *clausename) +{ + isc_result_t result = ISC_R_SUCCESS; + const cfg_map_t *map; + isc_symvalue_t symval; + cfg_obj_t *destobj = NULL; + cfg_listelt_t *elt = NULL; + const cfg_clausedef_t * const *clauseset; + const cfg_clausedef_t *clause; + + REQUIRE(pctx != NULL); + REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map); + REQUIRE(obj != NULL); + + map = &mapobj->value.map; + + clause = NULL; + for (clauseset = map->clausesets; *clauseset != NULL; clauseset++) { + for (clause = *clauseset; clause->name != NULL; clause++) { + if (strcasecmp(clause->name, clausename) == 0) { + goto breakout; + } + } + } + + breakout: + if (clause == NULL || clause->name == NULL) + return (ISC_R_FAILURE); + + result = isc_symtab_lookup(map->symtab, clausename, 0, &symval); + if (result == ISC_R_NOTFOUND) { + if ((clause->flags & CFG_CLAUSEFLAG_MULTI) != 0) { + CHECK(cfg_create_list(pctx, &cfg_type_implicitlist, + &destobj)); + CHECK(create_listelt(pctx, &elt)); + cfg_obj_attach(obj, &elt->obj); + ISC_LIST_APPEND(destobj->value.list, elt, link); + symval.as_pointer = destobj; + } else + symval.as_pointer = obj; + + CHECK(isc_symtab_define(map->symtab, clausename, 1, symval, + isc_symexists_reject)); + } else { + cfg_obj_t *destobj2 = symval.as_pointer; + + INSIST(result == ISC_R_SUCCESS); + + if (destobj2->type == &cfg_type_implicitlist) { + CHECK(create_listelt(pctx, &elt)); + cfg_obj_attach(obj, &elt->obj); + ISC_LIST_APPEND(destobj2->value.list, elt, link); + } else + result = ISC_R_EXISTS; + } + + destobj = NULL; + elt = NULL; + + cleanup: + if (elt != NULL) + free_listelt(pctx, elt); + CLEANUP_OBJ(destobj); + + return (result); +}