Remove zone data within the transaction.
.TP
\fBzone\-purge\fP \fIzone\fP\&... [\fIfilter\fP\&...]
-Purge zone data, file, journal, timers, and kaspdb.
-Filters are \fB+expire\fP, \fB+timers\fP, \fB+zonefile\fP, \fB+journal\fP,
-and \fB+kaspdb\fP\&.
+Purge zone data, zone file, journal, timers, and/or KASP data of specified zones.
+Available filters are \fB+expire\fP, \fB+zonefile\fP, \fB+journal\fP, \fB+timers\fP,
+and \fB+kaspdb\fP\&. If no filter is specified, all filters are enabled.
+It the zone is no longer configured, add \fB+orphan\fP filter (zone file cannot
+be purged in this case).
.TP
\fBzone\-stats\fP \fIzone\fP [\fImodule\fP[\fB\&.\fP\fIcounter\fP]]
Show zone statistics counter(s). To print also counters with value 0, use
Remove zone data within the transaction.
**zone-purge** *zone*... [*filter*...]
- Purge zone data, file, journal, timers, and kaspdb.
- Filters are **+expire**, **+timers**, **+zonefile**, **+journal**,
- and **+kaspdb**.
+ Purge zone data, zone file, journal, timers, and/or KASP data of specified zones.
+ Available filters are **+expire**, **+zonefile**, **+journal**, **+timers**,
+ and **+kaspdb**. If no filter is specified, all filters are enabled.
+ It the zone is no longer configured, add **+orphan** filter (zone file cannot
+ be purged in this case).
**zone-stats** *zone* [*module*\ [\ **.**\ *counter*\ ]]
Show zone statistics counter(s). To print also counters with value 0, use
#include "contrib/macros.h"
#include "contrib/mempattern.h"
#include "contrib/string.h"
+#include "contrib/ucw/lists.h"
#include "zscanner/scanner.h"
#include "contrib/strtonum.h"
return zone_update_remove_node(zone->control_update, owner);
}
}
+}
+
+static bool zone_exists(const knot_dname_t *zone, void *data)
+{
+ assert(zone);
+ assert(data);
+ knot_zonedb_t *db = data;
+
+ return knot_zonedb_find(db, zone) != NULL;
+}
+
+static bool zone_names_distinct(const knot_dname_t *zone, void *data)
+{
+ assert(zone);
+ assert(data);
+
+ knot_dname_t *zone_to_purge = data;
+
+ return !knot_dname_is_equal(zone, zone_to_purge);
+}
+
+static int orphans_purge(ctl_args_t *args)
+{
+ assert(args->data[KNOT_CTL_IDX_FILTER] != NULL);
+ bool only_orphan = (strlen(args->data[KNOT_CTL_IDX_FILTER]) == 1);
+
+ if (args->data[KNOT_CTL_IDX_ZONE] == NULL) {
+ // Purge KASP DB.
+ if (only_orphan || MATCH_AND_FILTER(args, CTL_FILTER_PURGE_KASPDB)) {
+ list_t zones;
+ init_list(&zones);
+ if (kasp_db_open(*kaspdb()) == KNOT_EOK &&
+ kasp_db_list_zones(*kaspdb(), &zones) == KNOT_EOK) {
+ ptrnode_t *zn;
+ WALK_LIST(zn, zones) {
+ knot_dname_t *zone_name = (knot_dname_t *)zn->d;
+ if (!zone_exists(zone_name, args->server->zone_db)) {
+ (void)kasp_db_delete_all(*kaspdb(), zone_name);
+ }
+ knot_dname_free(zone_name, NULL);
+ }
+ ptrlist_free(&zones, NULL);
+ }
+ }
+
+ // Purge zone journals of unconfigured zones.
+ if (only_orphan || MATCH_AND_FILTER(args, CTL_FILTER_PURGE_JOURNAL)) {
+ list_t zones;
+ init_list(&zones);
+ if (journal_db_list_zones(&args->server->journal_db, &zones) == KNOT_EOK) {
+ ptrnode_t *zn;
+ WALK_LIST(zn, zones) {
+ journal_t journal = { 0 };
+ knot_dname_t *zone_name = (knot_dname_t *)zn->d;
+ if (!zone_exists(zone_name, args->server->zone_db) &&
+ journal_open(&journal, &args->server->journal_db,
+ zone_name) == KNOT_EOK) {
+ journal_scrape(&journal);
+ journal_close(&journal);
+ }
+ knot_dname_free(zone_name, NULL);
+ }
+ ptrlist_free(&zones, NULL);
+ }
+ }
+
+ // Purge timers of unconfigured zones.
+ if (only_orphan || MATCH_AND_FILTER(args, CTL_FILTER_PURGE_TIMERS)) {
+ (void)zone_timers_sweep(args->server->timers_db,
+ zone_exists, args->server->zone_db);
+ }
+ } else {
+ uint8_t buff[KNOT_DNAME_MAXLEN];
+ while (true) {
+ knot_dname_t *zone_name =
+ knot_dname_from_str(buff, args->data[KNOT_CTL_IDX_ZONE],
+ sizeof(buff));
+ if (zone_name == NULL) {
+ log_ctl_zone_str_error(args->data[KNOT_CTL_IDX_ZONE],
+ "control, error (%s)",
+ knot_strerror(KNOT_EINVAL));
+ send_error(args, knot_strerror(KNOT_EINVAL));
+ return KNOT_EINVAL;
+ }
+ knot_dname_to_lower(zone_name);
+
+ if (!zone_exists(zone_name, args->server->zone_db)) {
+ // Purge KASP DB.
+ if (only_orphan || MATCH_AND_FILTER(args, CTL_FILTER_PURGE_KASPDB)) {
+ if (kasp_db_open(*kaspdb()) == KNOT_EOK) {
+ (void) kasp_db_delete_all(*kaspdb(), zone_name);
+ }
+ }
+
+ // Purge zone journal.
+ if (only_orphan || MATCH_AND_FILTER(args, CTL_FILTER_PURGE_JOURNAL)) {
+ journal_t journal = { 0 };
+ if (journal_open(&journal, &args->server->journal_db,
+ zone_name) == KNOT_EOK) {
+ (void)journal_scrape(&journal);
+ journal_close(&journal);
+ }
+ }
+
+ // Purge zone timers.
+ if (only_orphan || MATCH_AND_FILTER(args, CTL_FILTER_PURGE_TIMERS)) {
+ (void)zone_timers_sweep(args->server->timers_db,
+ zone_names_distinct, zone_name);
+ }
+ }
+
+ // Get next zone name.
+ int ret = knot_ctl_receive(args->ctl, &args->type, &args->data);
+ if (ret != KNOT_EOK || args->type != KNOT_CTL_TYPE_DATA) {
+ break;
+ }
+ ctl_log_data(&args->data);
+ }
+ }
+
+ return KNOT_EOK;
}
static int zone_purge(zone_t *zone, ctl_args_t *args)
case CTL_ZONE_UNSET:
return zones_apply(args, zone_txn_unset);
case CTL_ZONE_PURGE:
- return zones_apply(args, zone_purge);
+ if (MATCH_AND_FILTER(args, CTL_FILTER_PURGE_ORPHAN)) {
+ return orphans_purge(args);
+ } else {
+ return zones_apply(args, zone_purge);
+ }
case CTL_ZONE_STATS:
return zones_apply(args, zone_stats);
default:
-/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#define CTL_FILTER_PURGE_ZONEFILE 'f'
#define CTL_FILTER_PURGE_JOURNAL 'j'
#define CTL_FILTER_PURGE_KASPDB 'k'
+#define CTL_FILTER_PURGE_ORPHAN 'o'
/*! Control commands. */
typedef enum {
if (txn->ret == KNOT_EOK && *compare_metaflag == '\0') {
compare_metaflag -= metaflag_len;
if (strcmp(compare_metaflag, MDKEY_PERZONE_FLAGS) == 0) {
- char *found_zone = knot_dname_to_str_alloc((const knot_dname_t *)key.data);
+ knot_dname_t *found_zone = knot_dname_copy((const knot_dname_t *)key.data, NULL);
+ if (found_zone == NULL) {
+ txn->ret = KNOT_ENOMEM;
+ break;
+ }
ptrlist_add(zones, found_zone, NULL);
}
}
-/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
}
}
-static bool zone_exists(const knot_dname_t *zone, void *data)
-{
- assert(zone);
- assert(data);
-
- knot_zonedb_t *db = data;
-
- return knot_zonedb_find(db, zone) != NULL;
-}
-
void zonedb_reload(conf_t *conf, server_t *server)
{
if (conf == NULL || server == NULL) {
/* Wait for readers to finish reading old zone database. */
synchronize_rcu();
- /* Sweep the timer database. */
- if (server->timers_db != NULL) {
- int ret = zone_timers_sweep(server->timers_db, zone_exists, db_new);
- if (ret != KNOT_EOK) {
- log_warning("failed to clear persistent timer DB (%s)",
- knot_strerror(ret));
- }
- }
-
/* Remove old zone DB. */
remove_old_zonedb(conf, db_old, db_new);
}
-/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
ret = journal_db_list_zones(&jdb, &zones);
if (ret == KNOT_EOK) {
ptrnode_t *zn;
+ char buff[KNOT_DNAME_TXT_MAXLEN + 1];
WALK_LIST(zn, zones) {
- printf("%s\n", (char *)zn->d);
+ printf("%s\n", knot_dname_to_str(buff, (knot_dname_t *)zn->d, sizeof(buff)));
free(zn->d);
}
ptrlist_free(&zones, NULL);
{ "+zonefile", CTL_FILTER_PURGE_ZONEFILE },
{ "+journal", CTL_FILTER_PURGE_JOURNAL },
{ "+kaspdb", CTL_FILTER_PURGE_KASPDB },
+ { "+orphan", CTL_FILTER_PURGE_ORPHAN },
};
const filter_desc_t null_filter = { 0 };
{ CMD_ZONE_GET, "<zone> [<owner> [<type>]]", "Get zone data within the transaction." },
{ CMD_ZONE_SET, "<zone> <owner> [<ttl>] <type> <rdata>", "Add zone record within the transaction." },
{ CMD_ZONE_UNSET, "<zone> <owner> [<type> [<rdata>]]", "Remove zone data within the transaction." },
- { CMD_ZONE_PURGE, "<zone>... [<filter>...]", "Purge zone data, file, journal, and timers." },
+ { CMD_ZONE_PURGE, "<zone>... [<filter>...]", "Purge zone data, zone file, journal, timers, and KASP data." },
{ CMD_ZONE_STATS, "<zone> [<module>[.<counter>]]", "Show zone statistics counter(s)."},
{ CMD_ZONE_STATUS, "<zone> [<filter>...]", "Show the zone status." },
{ "", "", "" },