diff --git a/Knot.files b/Knot.files index df7f8df43db7163a85f897bedef6ffee19e085c8..d9fa5360e270755c503731a4c9ac6435aff0c1ae 100644 --- a/Knot.files +++ b/Knot.files @@ -488,6 +488,7 @@ tests/acl.c tests/base32hex.c tests/base64.c tests/changeset.c +tests/conf.c tests/descriptor.c tests/dname.c tests/dthreads.c @@ -497,6 +498,7 @@ tests/fake_server.h tests/fdset.c tests/hattrie.c tests/hhash.c +tests/internal_mem.c tests/journal.c tests/namedb.c tests/net_shortwrite.c diff --git a/src/knot/conf/conf.c b/src/knot/conf/conf.c index eb5163b1c2e4d52509c595f3f98a28b536f4a9a3..719042828e51d1692eb885bcf6cbeb49cc38d5a9 100644 --- a/src/knot/conf/conf.c +++ b/src/knot/conf/conf.c @@ -41,6 +41,7 @@ #include "libknot/internal/mempool.h" #include "libknot/internal/namedb/namedb_lmdb.h" #include "libknot/internal/sockaddr.h" +#include "libknot/internal/strlcat.h" #include "libknot/yparser/ypformat.h" #include "libknot/yparser/yptrafo.h" @@ -1218,91 +1219,114 @@ void conf_data( } } -static char* dname_to_filename( - const knot_dname_t *name, - const char *suffix) +static char* get_filename( + conf_t *conf, + const knot_dname_t *zone, + const char *name) { - char *str = knot_dname_to_str_alloc(name); - if (str == NULL) { - return NULL; - } + const char *end = name + strlen(name); + char out[1024] = ""; - // Replace possible slashes with underscores. - for (char *ch = str; *ch != '\0'; ch++) { - if (*ch == '/') { - *ch = '_'; + do { + // Search for a formatter. + const char *pos = strchr(name, '%'); + + // If no formatter, copy the rest of the name. + if (pos == NULL) { + if (strlcat(out, name, sizeof(out)) >= sizeof(out)) { + return NULL; + } + break; } - } - char *out = sprintf_alloc("%s%s", str, suffix); - free(str); + // Copy constant block. + char *block = strndup(name, pos - name); + if (block == NULL || + strlcat(out, block, sizeof(out)) >= sizeof(out)) { + return NULL; + } + free(block); - return out; + // Move name pointer behind the formatter. + name = pos + 2; + + char buff[512] = ""; + + const char type = *(pos + 1); + switch (type) { + case '%': + strlcat(buff, "%", sizeof(buff)); + break; + case 's': + if (knot_dname_to_str(buff, zone, sizeof(buff)) == NULL) { + return NULL; + } + + // Replace possible slashes with underscores. + for (char *ch = buff; *ch != '\0'; ch++) { + if (*ch == '/') { + *ch = '_'; + } + } + break; + case '\0': + log_zone_warning(zone, "ignoring missing trailing " + "zonefile formatter"); + continue; + default: + log_zone_warning(zone, "ignoring zonefile formatter '%c'", + type); + continue; + } + + if (strlcat(out, buff, sizeof(out)) >= sizeof(out)) { + return NULL; + } + } while (name < end); + + // Use storage prefix if not absolute path. + if (out[0] == '/') { + return strdup(out); + } else { + conf_val_t val = conf_zone_get(conf, C_STORAGE, zone); + char *storage = conf_abs_path(&val, NULL); + if (storage == NULL) { + return NULL; + } + char *abs = sprintf_alloc("%s/%s", storage, out); + free(storage); + return abs; + } } char* conf_zonefile( conf_t *conf, const knot_dname_t *zone) { - assert(conf != NULL && zone != NULL); - - // Item 'file' is not template item (cannot use conf_zone_get)! */ - const char *file = NULL; - conf_val_t file_val = { NULL }; - file_val.code = conf_db_get(conf, &conf->read_txn, C_ZONE, C_FILE, - zone, knot_dname_size(zone), &file_val); - if (file_val.code == KNOT_EOK) { - file = conf_str(&file_val); - if (file != NULL && file[0] == '/') { - return strdup(file); - } - } - - char *abs_storage = NULL; - conf_val_t storage_val = conf_zone_get(conf, C_STORAGE, zone); - if (storage_val.code == KNOT_EOK) { - abs_storage = conf_abs_path(&storage_val, NULL); - if (abs_storage == NULL) { - return NULL; - } + if (conf == NULL || zone == NULL) { + return NULL; } - char *out = NULL; + conf_val_t val = conf_zone_get(conf, C_FILE, zone); + const char *file = conf_str(&val); + // Use default zonefile name pattern if not specified. if (file == NULL) { - char *file = dname_to_filename(zone, "zone"); - out = sprintf_alloc("%s/%s", abs_storage, file); - free(file); - } else { - out = sprintf_alloc("%s/%s", abs_storage, file); + file = "%szone"; } - free(abs_storage); - - return out; + return get_filename(conf, zone, file); } char* conf_journalfile( conf_t *conf, const knot_dname_t *zone) { - assert(conf != NULL && zone != NULL); - - char *abs_storage = NULL; - conf_val_t storage_val = conf_zone_get(conf, C_STORAGE, zone); - if (storage_val.code == KNOT_EOK) { - abs_storage = conf_abs_path(&storage_val, NULL); - if (abs_storage == NULL) { - return NULL; - } + if (conf == NULL || zone == NULL) { + return NULL; } - char *name = dname_to_filename(zone, "diff.db"); - char *out = sprintf_alloc("%s/%s", abs_storage, name); - free(name); - free(abs_storage); - - return out; + return get_filename(conf, zone, "%sdb"); } size_t conf_udp_threads( diff --git a/src/knot/conf/scheme.c b/src/knot/conf/scheme.c index fd3fbbb7a599865c5da0fd66b59f6e63e023b6b9..2f402d118dc1cacc4bf5afd705cc1a3498be023f 100644 --- a/src/knot/conf/scheme.c +++ b/src/knot/conf/scheme.c @@ -133,6 +133,7 @@ static const yp_item_t desc_remote[] = { }; #define ZONE_ITEMS \ + { C_FILE, YP_TSTR, YP_VNONE }, \ { C_STORAGE, YP_TSTR, YP_VSTR = { STORAGE_DIR } }, \ { C_MASTER, YP_TREF, YP_VREF = { C_RMT }, YP_FMULTI, { check_ref } }, \ { C_NOTIFY, YP_TREF, YP_VREF = { C_RMT }, YP_FMULTI, { check_ref } }, \ @@ -157,7 +158,6 @@ static const yp_item_t desc_template[] = { static const yp_item_t desc_zone[] = { { C_DOMAIN, YP_TDNAME, YP_VNONE }, - { C_FILE, YP_TSTR, YP_VNONE }, { C_TPL, YP_TREF, YP_VREF = { C_TPL }, YP_FNONE, { check_ref } }, ZONE_ITEMS { NULL } diff --git a/tests/.gitignore b/tests/.gitignore index eadb81baf8f022ee9d1b28bba9a610c49547267c..cc3481e0f727f3e30b76460ddeb88b52d4799abf 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -7,6 +7,7 @@ acl base32hex base64 changeset +conf descriptor dname dnssec_keys diff --git a/tests/Makefile.am b/tests/Makefile.am index 4df95258ccaee37826a87e41730bc328c99d78bb..087749e0647ee0c9b4154123379ab87fb2c38807 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -15,6 +15,7 @@ check_PROGRAMS = \ base32hex \ base64 \ changeset \ + conf \ descriptor \ dname \ dthreads \ @@ -64,6 +65,7 @@ check-local: $(check_PROGRAMS) $(check_PROGRAMS) acl_SOURCES = acl.c test_conf.h +conf_SOURCES = conf.c test_conf.h process_query_SOURCES = process_query.c fake_server.h test_conf.h process_answer_SOURCES = process_answer.c fake_server.h test_conf.h CLEANFILES = runtests.log diff --git a/tests/conf.c b/tests/conf.c new file mode 100644 index 0000000000000000000000000000000000000000..2aafd7566557a5ab1f8db82f51e8733804d2de85 --- /dev/null +++ b/tests/conf.c @@ -0,0 +1,75 @@ +/* Copyright (C) 2011 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 + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <tap/basic.h> + +#include "test_conf.h" + +#define ZONE1 "0/25.2.0.192.in-addr.arpa." +#define ZONE2 "." + +static void test_conf_zonefile(void) +{ + int ret; + char *file; + + knot_dname_t *zone1 = knot_dname_from_str_alloc(ZONE1); + ok(zone1 != NULL, "create dname "ZONE1); + knot_dname_t *zone2 = knot_dname_from_str_alloc(ZONE2); + ok(zone2 != NULL, "create dname "ZONE2); + + const char *conf_str = + "template:\n" + " - id: default\n" + " storage: /tmp\n" + "\n" + "zone:\n" + " - domain: "ZONE1"\n" + " file: dir/a%%b/%ssuffix/%a\n" + "zone:\n" + " - domain: "ZONE2"\n" + " file: /%s\n"; + + ret = test_conf(conf_str, NULL); + ok(ret == KNOT_EOK, "Prepare configuration"); + + // Relative path with formatters. + file = conf_zonefile(conf(), zone1); + ok(file != NULL, "Get zonefile path for "ZONE1); + ok(strcmp(file, "/tmp/dir/a%b/0_25.2.0.192.in-addr.arpa.suffix/") == 0, + "Zonefile path compare for "ZONE1); + free(file); + + // Absolute path without formatters. + file = conf_zonefile(conf(), zone2); + ok(file != NULL, "Get zonefile path for "ZONE2); + ok(strcmp(file, "/.") == 0, + "Zonefile path compare for "ZONE2); + free(file); + + conf_free(conf(), false); + knot_dname_free(&zone1, NULL); + knot_dname_free(&zone2, NULL); +} + +int main(int argc, char *argv[]) +{ + plan_lazy(); + + test_conf_zonefile(); + + return 0; +}