From 74eb2f5cbc98d9646bcd13ffcb17688f0db5ab8d Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Tue, 6 Jan 2015 22:57:57 -0800 Subject: [PATCH] [master] rndc showzone / rndc delzone of non-added zones 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] --- CHANGES | 9 + bin/named/control.c | 6 +- bin/named/include/named/control.h | 1 + bin/named/include/named/globals.h | 1 + bin/named/include/named/server.h | 10 +- bin/named/server.c | 479 ++++++++++++++++++------------ bin/rndc/rndc.docbook | 22 +- bin/tests/system/addzone/tests.sh | 32 +- doc/arm/Bv9ARM-book.xml | 3 +- doc/arm/notes.xml | 17 ++ lib/isccfg/include/isccfg/cfg.h | 23 +- lib/isccfg/namedconf.c | 88 +++--- lib/isccfg/parser.c | 248 +++++++++++----- 13 files changed, 622 insertions(+), 317 deletions(-) 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); +}