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);
+}