diff --git a/src/knot/conf/conf.c b/src/knot/conf/conf.c index 5c0f6c63aa59d71786c1d991566f7ba185125a09..d69094916019b9655782f571a5b4ad760eddf82c 100644 --- a/src/knot/conf/conf.c +++ b/src/knot/conf/conf.c @@ -539,6 +539,70 @@ bool conf_val_equal( return false; } +conf_mix_iter_t conf_mix_iter( + conf_t *conf, + conf_val_t *mix_id) +{ + assert(mix_id != NULL && mix_id->item != NULL); + assert(mix_id->item->type == YP_TREF && + mix_id->item->var.r.ref != NULL && + mix_id->item->var.r.grp_ref != NULL && + mix_id->item->var.r.ref->var.g.id->type == YP_TSTR && + mix_id->item->var.r.grp_ref->var.g.id->type == YP_TSTR); + + conf_mix_iter_t iter = { + .conf = conf, + .mix_id = mix_id, + .id = mix_id + }; + + if (mix_id->code != KNOT_EOK) { + return iter; + } + + iter.sub_id = conf_id_get_txn(conf, &conf->read_txn, + mix_id->item->var.r.grp_ref_name, + mix_id->item->var.r.ref_name, + mix_id); + if (iter.sub_id.code == KNOT_EOK) { + conf_val(&iter.sub_id); + iter.id = &iter.sub_id; + iter.nested = true; + } + + return iter; +} + +void conf_mix_iter_next( + conf_mix_iter_t *iter) +{ + conf_val_next(iter->id); + if (iter->nested) { + if (iter->id->code == KNOT_EOK) { + return; + } + conf_val_next(iter->mix_id); + if (iter->mix_id->code != KNOT_EOK) { + return; + } + } else if (iter->id->code != KNOT_EOK){ + return; + } + + iter->sub_id = conf_id_get_txn(iter->conf, &iter->conf->read_txn, + iter->mix_id->item->var.r.grp_ref_name, + iter->mix_id->item->var.r.ref_name, + iter->mix_id); + if (iter->sub_id.code == KNOT_EOK) { + conf_val(&iter->sub_id); + iter->id = &iter->sub_id; + iter->nested = true; + } else { + iter->id = iter->mix_id; + iter->nested = false; + } +} + int64_t conf_int( conf_val_t *val) { diff --git a/src/knot/conf/conf.h b/src/knot/conf/conf.h index d85c159fed24f0088b67d2f600e0933bf0dd5f7d..e45b3ec73310a9bf1161ff82478415f21fd59397 100644 --- a/src/knot/conf/conf.h +++ b/src/knot/conf/conf.h @@ -48,6 +48,20 @@ typedef struct { int code; } conf_iter_t; +/*! Configuration iterator over mixed references (e.g. remote and remotes). */ +typedef struct { + /*! Configuration context. */ + conf_t *conf; + /*! Mixed references. */ + conf_val_t *mix_id; + /*! Temporary nested references. */ + conf_val_t sub_id; + /*! Current (possibly expanded) reference to use. */ + conf_val_t *id; + /*! Nested references in use indication. */ + bool nested; +} conf_mix_iter_t; + /*! Configuration module getter output. */ typedef struct { /*! Module name. */ @@ -407,6 +421,30 @@ bool conf_val_equal( conf_val_t *val2 ); +/*! + * Prepares a mixed reference iterator. + * + * The following access is through val->id. + * + * \param[in] conf Configuration. + * \param[in] mix_id First mixed reference. + * + * \return Mixed reference iterator. + */ +conf_mix_iter_t conf_mix_iter( + conf_t *conf, + conf_val_t *mix_id +); + +/*! + * Increments the mixed iterator. + * + * \param[in] iter Mixed reference iterator. + */ +void conf_mix_iter_next( + conf_mix_iter_t *iter +); + /*! * Gets the numeric value of the item. * diff --git a/src/knot/conf/tools.c b/src/knot/conf/tools.c index 74e2841da7470243c9618b6d9b9c86617f0951de..f7cbfc28014a263300387ee7d626858d336949cf 100644 --- a/src/knot/conf/tools.c +++ b/src/knot/conf/tools.c @@ -212,12 +212,27 @@ int check_ref( knotd_conf_check_args_t *args) { const yp_item_t *ref = args->item->var.r.ref; + const yp_item_t *ref2 = args->item->var.r.grp_ref; - // Try to find a referenced block with the id. - if (!conf_rawid_exists_txn(args->extra->conf, args->extra->txn, ref->name, - args->data, args->data_len)) { - args->err_str = "invalid reference"; - return KNOT_ENOENT; + bool found1 = false, found2 = false; + + // Try to find the id in the first section. + found1 = conf_rawid_exists_txn(args->extra->conf, args->extra->txn, + ref->name, args->data, args->data_len); + if (ref2 != NULL) { + // Try to find the id in the second section if supported. + found2 = conf_rawid_exists_txn(args->extra->conf, args->extra->txn, + ref2->name, args->data, args->data_len); + } + + if (found1 == found2) { + if (found1) { + args->err_str = "ambiguous reference"; + return KNOT_ENOENT; + } else { + args->err_str = "invalid reference"; + return KNOT_ENOENT; + } } return KNOT_EOK; diff --git a/src/libknot/yparser/ypschema.c b/src/libknot/yparser/ypschema.c index 0da1ff12b296172001bd77beeed0d7aa4d486b46..0ac5b571e8bce73fd91237a46b239def139e76a9 100644 --- a/src/libknot/yparser/ypschema.c +++ b/src/libknot/yparser/ypschema.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2021 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 @@ -43,15 +43,24 @@ static int set_ref_item( return KNOT_EINVAL; } - // Get reference category. + // Get referenced section. const yp_name_t *ref_name = dst->var.r.ref_name; const yp_item_t *ref = yp_schema_find(ref_name, NULL, schema); if (ref == NULL) { return KNOT_YP_EINVAL_ITEM; } - dst->var.r.ref = ref; + // Get referenced group if supported. + const yp_name_t *grp_ref_name = dst->var.r.grp_ref_name; + if (grp_ref_name != NULL) { + const yp_item_t *grp_ref = yp_schema_find(grp_ref_name, NULL, schema); + if (grp_ref == NULL) { + return KNOT_YP_EINVAL_ITEM; + } + dst->var.r.grp_ref = grp_ref; + } + return KNOT_EOK; } diff --git a/src/libknot/yparser/ypschema.h b/src/libknot/yparser/ypschema.h index bb3e425af0aa90e2ae8925c3d1abdd18428bd225..91e516574785be955c2fdfb5dda39ba72d484591 100644 --- a/src/libknot/yparser/ypschema.h +++ b/src/libknot/yparser/ypschema.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2021 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 @@ -168,10 +168,14 @@ typedef union { } d; /*! Reference variables. */ struct { - /*! Referenced group name. */ + /*! Referenced section name. */ yp_name_t const *ref_name; - /*! Referenced item (dynamic value). */ + /*! Referenced group section name (optional). */ + yp_name_t const *grp_ref_name; + /*! Referenced section item (dynamic value). */ yp_item_t const *ref; + /*! Referenced group section item (dynamic value). */ + yp_item_t const *grp_ref; } r; /*! Group variables. */ struct {