schema tree CHANGE clarify lys_feature_enable() when enabling all features
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 3eeec1e..b6de10a 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -708,7 +708,7 @@
lys_feature_change(const struct lysc_module *mod, const char *name, int value)
{
int all = 0;
- unsigned int u;
+ unsigned int u, changed_count, disabled_count;
struct lysc_feature *f, **df;
struct lysc_iffeature *iff;
struct ly_set *changed;
@@ -723,8 +723,10 @@
all = 1;
}
changed = ly_set_new();
+ changed_count = 0;
- for (u = 0; u < LY_ARRAY_SIZE(mod->features); ++u) {
+run:
+ for (disabled_count = u = 0; u < LY_ARRAY_SIZE(mod->features); ++u) {
f = &mod->features[u];
if (all || !strcmp(f->name, name)) {
if ((value && (f->flags & LYS_FENABLED)) || (!value && !(f->flags & LYS_FENABLED))) {
@@ -743,9 +745,7 @@
LY_ARRAY_FOR(f->iffeatures, struct lysc_iffeature, iff) {
if (!lysc_iffeature_value(iff)) {
if (all) {
- LOGWRN(mod->ctx,
- "Feature \"%s\" cannot be enabled since it is disabled by its if-feature condition(s).",
- f->name);
+ ++disabled_count;
goto next;
} else {
LOGERR(mod->ctx, LY_EDENIED,
@@ -781,6 +781,34 @@
return LY_EINVAL;
}
+ if (value && all && disabled_count) {
+ if (changed_count == changed->count) {
+ /* no change in last run -> not able to enable all ... */
+ /* ... print errors */
+ for (u = 0; disabled_count && u < LY_ARRAY_SIZE(mod->features); ++u) {
+ if (!(mod->features[u].flags & LYS_FENABLED)) {
+ LOGERR(mod->ctx, LY_EDENIED,
+ "Feature \"%s\" cannot be enabled since it is disabled by its if-feature condition(s).",
+ mod->features[u].name);
+ --disabled_count;
+ }
+ }
+ /* ... restore the original state */
+ for (u = 0; u < changed->count; ++u) {
+ f = changed->objs[u];
+ /* re-disable the feature */
+ f->flags &= ~LYS_FENABLED;
+ }
+
+ ly_set_free(changed, NULL);
+ return LY_EDENIED;
+ } else {
+ /* we did some change in last run, try it again */
+ changed_count = changed->count;
+ goto run;
+ }
+ }
+
/* reflect change(s) in the dependent features */
for (u = 0; u < changed->count; ++u) {
/* If a dependent feature is enabled, it can be now changed by the change (to false) of the value of
diff --git a/src/tree_schema.h b/src/tree_schema.h
index bb42de5..9e1af05 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -909,6 +909,14 @@
*
* By default, when the module is loaded by libyang parser, all features are disabled.
*
+ * If all features are being enabled, it must be possible respecting their if-feature conditions. For example,
+ * enabling all features on the following feature set will fail since it is not possible to enable both features
+ * (and it is unclear which of them should be enabled then). In this case the LY_EDENIED is returned and the feature
+ * is untouched.
+ *
+ * feature f1;
+ * feature f2 { if-feature 'not f1';}
+ *
* @param[in] module Module where the feature will be enabled.
* @param[in] feature Name of the feature to enable. To enable all features at once, use asterisk (`*`) character.
* @return LY_ERR value.
diff --git a/tests/src/test_tree_schema_compile.c b/tests/src/test_tree_schema_compile.c
index 33fa92d..45ab3d9 100644
--- a/tests/src/test_tree_schema_compile.c
+++ b/tests/src/test_tree_schema_compile.c
@@ -214,6 +214,8 @@
/* enabling feature that cannot be enabled due to its if-features */
assert_int_equal(LY_EDENIED, lys_feature_enable(&mod, "orfeature"));
logbuf_assert("Feature \"orfeature\" cannot be enabled since it is disabled by its if-feature condition(s).");
+ assert_int_equal(LY_EDENIED, lys_feature_enable(&mod, "*"));
+ logbuf_assert("Feature \"f6\" cannot be enabled since it is disabled by its if-feature condition(s).");
/* */
assert_int_equal(LY_EINVAL, lys_feature_enable(&mod, "xxx"));