blob: 30620cef46ae767c2376c56b39bbb035d5a25f82 [file] [log] [blame]
Radek Krejcib1c12512015-08-11 11:22:04 +02001/**
2 * @file validation.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief Data tree validation functions
5 *
6 * Copyright (c) 2015 CESNET, z.s.p.o.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of the Company nor the names of its contributors
18 * may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 */
21
Radek Krejcieab784a2015-08-27 09:56:53 +020022#include <assert.h>
Radek Krejcib1c12512015-08-11 11:22:04 +020023#include <stdlib.h>
Michal Vaskocf024702015-10-08 15:01:42 +020024#include <string.h>
Radek Krejcib1c12512015-08-11 11:22:04 +020025
Radek Krejcieab784a2015-08-27 09:56:53 +020026#include "common.h"
Michal Vaskocf024702015-10-08 15:01:42 +020027#include "validation.h"
Radek Krejcib1c12512015-08-11 11:22:04 +020028#include "libyang.h"
Michal Vaskocf024702015-10-08 15:01:42 +020029#include "xpath.h"
Radek Krejcicf509982015-12-15 09:22:44 +010030#include "parser.h"
Michal Vaskocf024702015-10-08 15:01:42 +020031#include "resolve.h"
32#include "tree_internal.h"
Michal Vaskofc5744d2015-10-22 12:09:34 +020033#include "xml_internal.h"
Radek Krejcib1c12512015-08-11 11:22:04 +020034
Radek Krejcieab784a2015-08-27 09:56:53 +020035static struct lys_node_leaf *
Michal Vasko1e62a092015-12-01 12:27:20 +010036lyv_keys_present(const struct lyd_node *list)
Radek Krejcib1c12512015-08-11 11:22:04 +020037{
38 struct lyd_node *aux;
39 struct lys_node_list *schema;
40 int i;
41
42 schema = (struct lys_node_list *)list->schema;
43
44 for (i = 0; i < schema->keys_size; i++) {
45 for (aux = list->child; aux; aux = aux->next) {
46 if (aux->schema == (struct lys_node *)schema->keys[i]) {
47 break;
48 }
49 }
50 if (!aux) {
51 /* key not found in the data */
Radek Krejci1073cc02015-08-12 20:37:39 +020052 return schema->keys[i];
Radek Krejcib1c12512015-08-11 11:22:04 +020053 }
54 }
55
56 return EXIT_SUCCESS;
57}
Radek Krejcieab784a2015-08-27 09:56:53 +020058
Radek Krejci3e0addb2015-08-27 16:37:59 +020059/**
60 * @brief Compare filter nodes
61 *
62 * @param[in] first The first data node to compare
63 * @param[in] second The second node to compare
64 * @return 0 if both filter nodes selects the same data.
65 */
66static int
Michal Vasko1e62a092015-12-01 12:27:20 +010067filter_compare(const struct lyd_node *first, const struct lyd_node *second)
Radek Krejci3e0addb2015-08-27 16:37:59 +020068{
69 struct lyd_node *diter1, *diter2;
70 int match, c1, c2;
71
72 assert(first);
73 assert(second);
74
75 if (first->schema != second->schema) {
76 return 1;
77 }
78
79
80 switch (first->schema->nodetype) {
81 case LYS_CONTAINER:
82 case LYS_LIST:
83 /* check if all the content match nodes are the same */
84 c1 = 0;
85 LY_TREE_FOR(first->child, diter1) {
86 if (!(diter1->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
87 continue;
Michal Vasko4c183312015-09-25 10:41:47 +020088 } else if (!((struct lyd_node_leaf_list *)diter1)->value_str) {
Radek Krejci3e0addb2015-08-27 16:37:59 +020089 /* selection node */
90 continue;
91 }
92
93 match = 0;
94 LY_TREE_FOR(second->child, diter2) {
95 if (diter2->schema != diter1->schema) {
96 continue;
Michal Vasko4c183312015-09-25 10:41:47 +020097 } else if (((struct lyd_node_leaf_list *)diter1)->value_str !=
98 ((struct lyd_node_leaf_list *)diter2)->value_str) {
Radek Krejci3e0addb2015-08-27 16:37:59 +020099 continue;
100 }
101 match = 1;
102 c1++;
103 }
104 if (!match) {
105 return 1;
106 }
107 }
108 /* get number of content match nodes in the second to get know if there are some
109 * that are not present in first
110 */
111 c2 = 0;
112 LY_TREE_FOR(second->child, diter2) {
113 if (!(diter2->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
114 continue;
Michal Vasko4c183312015-09-25 10:41:47 +0200115 } else if (!((struct lyd_node_leaf_list *)diter2)->value_str) {
Radek Krejci3e0addb2015-08-27 16:37:59 +0200116 /* selection node */
117 continue;
118 }
119 c2++;
120 }
121 if (c1 != c2) {
122 return 1;
123 }
124 break;
125 case LYS_LEAF:
126 case LYS_LEAFLIST:
Michal Vasko4c183312015-09-25 10:41:47 +0200127 if (((struct lyd_node_leaf_list *)first)->value_str != ((struct lyd_node_leaf_list *)second)->value_str) {
Radek Krejci3e0addb2015-08-27 16:37:59 +0200128 return 1;
129 }
130 break;
131 default:
132 /* no more tests are needed */
133 break;
134 }
135 return 0;
136}
137
138static int
139filter_merge(struct lyd_node *to, struct lyd_node *from)
140{
141 struct lyd_node *diter1, *diter2;
142 unsigned int i, j;
Radek Krejcidc154432016-01-21 11:10:59 +0100143 struct ly_set *s1 = NULL, *s2 = NULL;
Radek Krejci3e0addb2015-08-27 16:37:59 +0200144 int copy;
Radek Krejci488fd542016-01-07 12:54:08 +0100145 int ret = EXIT_FAILURE;
Radek Krejci3e0addb2015-08-27 16:37:59 +0200146
147 if (!to || !from || to->schema != from->schema) {
148 ly_errno = LY_EINVAL;
149 return EXIT_FAILURE;
150 }
151
152 switch(to->schema->nodetype) {
153 case LYS_LIST:
154 case LYS_CONTAINER:
155 if (!from->child) {
156 /* from is selection node, so we want to make the to selection node now */
157 while (to->child) {
158 lyd_free(to->child);
159 }
160 } else if (to->child) {
161 /* both to and from are containment nodes and it was already checked
162 * (by calling filter_compare()) that they selects the same target.
163 * Therefore we can skip the content match nodes (they are the same in
164 * both of them) and merge only the selection and containment nodes */
165
166 /* first, get know if to and from contain some selection or containment
167 * nodes. Because if one of them does not contain any such a node it
168 * selects all the data so it does not make sense to limit it by any
169 * selection/containment node.
170 */
Radek Krejcidc154432016-01-21 11:10:59 +0100171 s1 = ly_set_new();
172 s2 = ly_set_new();
Radek Krejci488fd542016-01-07 12:54:08 +0100173 if (!s1 || !s2) {
174 LOGMEM;
175 goto cleanup;
176 }
Radek Krejci3e0addb2015-08-27 16:37:59 +0200177 LY_TREE_FOR(to->child, diter1) {
178 /* is selection node */
Michal Vasko4c183312015-09-25 10:41:47 +0200179 if ((diter1->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))
180 && !((struct lyd_node_leaf_list *)diter1)->value_str) {
Radek Krejcidc154432016-01-21 11:10:59 +0100181 if (ly_set_add(s1, diter1)) {
Radek Krejci488fd542016-01-07 12:54:08 +0100182 goto cleanup;
183 }
Michal Vasko17cc7062015-12-10 14:31:48 +0100184 } else if ((diter1->schema->nodetype == LYS_ANYXML) && !((struct lyd_node_anyxml *)diter1)->value->child) {
Radek Krejcidc154432016-01-21 11:10:59 +0100185 if (ly_set_add(s1, diter1)) {
Radek Krejci488fd542016-01-07 12:54:08 +0100186 goto cleanup;
187 }
Radek Krejci3e0addb2015-08-27 16:37:59 +0200188 } else if (diter1->schema->nodetype & (LYS_CONTAINER | LYS_LIST)) {
189 /* or containment node */
Radek Krejcidc154432016-01-21 11:10:59 +0100190 if (ly_set_add(s1, diter1)) {
Radek Krejci488fd542016-01-07 12:54:08 +0100191 goto cleanup;
192 }
Radek Krejci3e0addb2015-08-27 16:37:59 +0200193 }
194 }
195
196 LY_TREE_FOR(from->child, diter2) {
197 /* is selection node */
Michal Vasko4c183312015-09-25 10:41:47 +0200198 if ((diter2->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))
199 && !((struct lyd_node_leaf_list *)diter2)->value_str) {
Radek Krejcidc154432016-01-21 11:10:59 +0100200 if (ly_set_add(s2, diter2)) {
Radek Krejci488fd542016-01-07 12:54:08 +0100201 goto cleanup;
202 }
Michal Vasko17cc7062015-12-10 14:31:48 +0100203 } else if ((diter2->schema->nodetype == LYS_ANYXML) && !((struct lyd_node_anyxml *)diter2)->value->child) {
Radek Krejcidc154432016-01-21 11:10:59 +0100204 if (ly_set_add(s2, diter2)) {
Radek Krejci488fd542016-01-07 12:54:08 +0100205 goto cleanup;
206 }
Radek Krejci3e0addb2015-08-27 16:37:59 +0200207 } else if (diter2->schema->nodetype & (LYS_CONTAINER | LYS_LIST)) {
208 /* or containment node */
Radek Krejcidc154432016-01-21 11:10:59 +0100209 if (ly_set_add(s2, diter2)) {
Radek Krejci488fd542016-01-07 12:54:08 +0100210 goto cleanup;
211 }
Radek Krejci3e0addb2015-08-27 16:37:59 +0200212 }
213 }
214
215 if (!s1->number) {
216 /* to already selects all content, so nothing is needed */
217 break;
218 } else if (!s2->number) {
219 /* from selects all content, so make to select it too by
220 * removing all selection and containment nodes
221 */
222 for (i = 0; i < s1->number; i++) {
Radek Krejcidc154432016-01-21 11:10:59 +0100223 lyd_free(s1->dset[i]);
Radek Krejci3e0addb2015-08-27 16:37:59 +0200224 }
225 break;
226 } else {
227 /* both contain some selection or containment node(s), so merge them */
228 for (j = 0; j < s2->number; j++) { /* from */
229 copy = 0;
230 for (i = 0; i < s1->number; i++) { /* to */
Radek Krejcidc154432016-01-21 11:10:59 +0100231 if (s1->dset[i]->schema != s2->dset[j]->schema) {
Radek Krejci3e0addb2015-08-27 16:37:59 +0200232 continue;
233 }
234
235 /* we have something similar to diter1, explore it more */
Radek Krejcidc154432016-01-21 11:10:59 +0100236 switch (s2->dset[j]->schema->nodetype) {
Radek Krejci3e0addb2015-08-27 16:37:59 +0200237 case LYS_LIST:
238 case LYS_CONTAINER:
Radek Krejcidc154432016-01-21 11:10:59 +0100239 if (!filter_compare(s2->dset[j], s1->dset[i])) {
Radek Krejci3e0addb2015-08-27 16:37:59 +0200240 /* merge the two containers into the to */
Radek Krejcidc154432016-01-21 11:10:59 +0100241 filter_merge(s1->dset[i], s2->dset[j]);
Radek Krejci3e0addb2015-08-27 16:37:59 +0200242 } else {
243 /* check that some of them is not a selection node */
Radek Krejcidc154432016-01-21 11:10:59 +0100244 if (!s2->dset[j]->child) {
Radek Krejci3e0addb2015-08-27 16:37:59 +0200245 /* from is selection node, so keep only it because to selects subset */
Radek Krejcidc154432016-01-21 11:10:59 +0100246 lyd_free(s1->dset[i]);
Radek Krejci3e0addb2015-08-27 16:37:59 +0200247 /* set the flag to copy the from child at the end */
248 copy = 1;
249 continue;
Radek Krejcidc154432016-01-21 11:10:59 +0100250 } else if (!s1->dset[i]->child) {
Radek Krejci3e0addb2015-08-27 16:37:59 +0200251 /* to is already selection node, so ignore the from child */
252 } else {
253 /* they are different so keep trying to search for some other matching instance */
254 continue;
255 }
256 }
257
258 break;
259 case LYS_ANYXML:
260 case LYS_LEAFLIST:
261 case LYS_LEAF:
262 /* here it can be only a selection node, so do not duplicate it (keep i < s1->number) */
263 break;
264 default:
265 /* keep compiler silent */
266 break;
267 }
268
269 /* we have a match, so do not duplicate the current from child and go to check next from child */
270 /* i < s1->number */
271 break;
272 }
273
274 if (copy || i == s1->number) {
275 /* the node is not yet present in to, so move it there */
Radek Krejcidc154432016-01-21 11:10:59 +0100276 lyd_unlink(s2->dset[j]);
Radek Krejci3e0addb2015-08-27 16:37:59 +0200277 if (to->child) {
Radek Krejcidc154432016-01-21 11:10:59 +0100278 to->child->prev->next = s2->dset[j];
279 s2->dset[j]->prev = to->child->prev;
280 to->child->prev = s2->dset[j];
Radek Krejci3e0addb2015-08-27 16:37:59 +0200281 } else {
Radek Krejcidc154432016-01-21 11:10:59 +0100282 to->child = s2->dset[j];
Radek Krejci3e0addb2015-08-27 16:37:59 +0200283 }
Radek Krejcidc154432016-01-21 11:10:59 +0100284 s2->dset[j]->parent = to;
Radek Krejci3e0addb2015-08-27 16:37:59 +0200285 }
286 }
287 }
288 } /* else from is empty, so nothing to do */
289
290 break;
291
292 default:
293 /* no other type needed to cover,
294 * keep the default branch to make compiler silent */
295 break;
296 }
Radek Krejci488fd542016-01-07 12:54:08 +0100297 ret = EXIT_SUCCESS;
Radek Krejci3e0addb2015-08-27 16:37:59 +0200298
Radek Krejci488fd542016-01-07 12:54:08 +0100299cleanup:
Radek Krejcidc154432016-01-21 11:10:59 +0100300 ly_set_free(s1);
301 ly_set_free(s2);
Radek Krejci3e0addb2015-08-27 16:37:59 +0200302
Radek Krejci488fd542016-01-07 12:54:08 +0100303 return ret;
Radek Krejci3e0addb2015-08-27 16:37:59 +0200304}
305
Radek Krejcieab784a2015-08-27 09:56:53 +0200306int
Radek Krejci46c4cd72016-01-21 15:13:52 +0100307lyv_data_value(struct lyd_node *node, int options)
308{
309 int rc;
310
311 assert(node);
312
313 if (!(node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
314 /* nothing to check */
315 return EXIT_SUCCESS;
316 }
317
318 switch (((struct lys_node_leaf *)node->schema)->type.base) {
319 case LY_TYPE_LEAFREF:
320 if (!((struct lyd_node_leaf_list *)node)->value.leafref) {
321 if (options & (LYD_OPT_FILTER | LYD_OPT_EDIT | LYD_OPT_GET | LYD_OPT_GETCONFIG)) {
322 /* in this case the leafref is always unresolved */
323 if (!(((struct lyd_node_leaf_list *)node)->value_type & LY_TYPE_LEAFREF_UNRES)) {
324 LOGVAL(LYE_SPEC, 0, "lyv_data_value(): Invalid options for given data.");
325 return EXIT_FAILURE;
326 }
327 } else {
328 /* try to resolve leafref */
329 rc = resolve_unres_data_item(node, UNRES_LEAFREF, 0, 0);
330 if (rc) {
331 return EXIT_FAILURE;
332 }
333 }
334 }
335 break;
Radek Krejci4ce42be2016-02-03 13:04:41 +0100336 case LY_TYPE_INST:
337 if (!(options & (LYD_OPT_FILTER | LYD_OPT_EDIT | LYD_OPT_GET | LYD_OPT_GETCONFIG)) &&
338 ((struct lys_node_leaf *)node->schema)->type.info.inst.req > -1) {
339 /* try to resolve instance-identifier to get know if the target exists */
340 rc = resolve_unres_data_item(node, UNRES_INSTID, 0, 0);
341 if (rc) {
342 return EXIT_FAILURE;
343 }
344 }
345 break;
Radek Krejci46c4cd72016-01-21 15:13:52 +0100346 default:
347 /* do nothing */
348 break;
349 }
350
351 return EXIT_SUCCESS;
352}
353
354int
Michal Vasko1e62a092015-12-01 12:27:20 +0100355lyv_data_context(const struct lyd_node *node, int options, unsigned int line, struct unres_data *unres)
Radek Krejcieab784a2015-08-27 09:56:53 +0200356{
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100357 struct lyd_node *iter;
358 struct lys_node *siter = NULL;
359
Michal Vaskocf024702015-10-08 15:01:42 +0200360 assert(node);
Radek Krejcieab784a2015-08-27 09:56:53 +0200361
362 /* check if the node instance is enabled by if-feature */
Michal Vaskocf024702015-10-08 15:01:42 +0200363 if (lys_is_disabled(node->schema, 2)) {
364 LOGVAL(LYE_INELEM, line, node->schema->name);
365 return EXIT_FAILURE;
366 }
367
368 /* check all relevant when conditions */
Michal Vasko0d182ba2015-10-09 09:29:14 +0200369 if (unres) {
Michal Vasko1e62a092015-12-01 12:27:20 +0100370 if (unres_data_add(unres, (struct lyd_node *)node, UNRES_WHEN, line) == -1) {
Michal Vasko0d182ba2015-10-09 09:29:14 +0200371 return EXIT_FAILURE;
372 }
373 } else {
Michal Vasko1e62a092015-12-01 12:27:20 +0100374 if (resolve_unres_data_item((struct lyd_node *)node, UNRES_WHEN, 0, line)) {
Michal Vasko0d182ba2015-10-09 09:29:14 +0200375 return EXIT_FAILURE;
376 }
Radek Krejcieab784a2015-08-27 09:56:53 +0200377 }
378
379 /* check for (non-)presence of status data in edit-config data */
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100380 if ((options & (LYD_OPT_EDIT | LYD_OPT_GETCONFIG | LYD_OPT_CONFIG)) && (node->schema->flags & LYS_CONFIG_R)) {
Michal Vaskocf024702015-10-08 15:01:42 +0200381 LOGVAL(LYE_INELEM, line, node->schema->name);
Radek Krejcieab784a2015-08-27 09:56:53 +0200382 return EXIT_FAILURE;
383 }
384
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100385 /* check elements order in case of RPC's input and output */
Radek Krejcica7efb72016-01-18 13:06:01 +0100386 if (node->validity && lyp_is_rpc(node->schema)) {
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100387 siter = node->schema->prev;
388 for (iter = node->prev; iter->next; iter = iter->prev) {
389 while (siter->next) {
390 if (siter == iter->schema) {
391 break;
392 }
393 siter = siter->prev;
394 }
395
396 if (!siter->next) {
397 /* schema node of the node's predecessors not found in node's schema node predecessors
398 * so the elements are in wrong order */
399 LOGVAL(LYE_INORDER, line, node->schema->name, iter->schema->name);
400 return EXIT_FAILURE;
401 }
402 }
403 }
404
Radek Krejcieab784a2015-08-27 09:56:53 +0200405 return EXIT_SUCCESS;
406}
Michal Vaskocf024702015-10-08 15:01:42 +0200407
Radek Krejcieab784a2015-08-27 09:56:53 +0200408int
Michal Vaskocf024702015-10-08 15:01:42 +0200409lyv_data_content(struct lyd_node *node, int options, unsigned int line, struct unres_data *unres)
Radek Krejcieab784a2015-08-27 09:56:53 +0200410{
Michal Vasko1e62a092015-12-01 12:27:20 +0100411 const struct lys_node *schema, *siter;
412 const struct lys_node *cs, *ch;
Radek Krejcieab784a2015-08-27 09:56:53 +0200413 struct lyd_node *diter, *start;
Radek Krejcicf509982015-12-15 09:22:44 +0100414 struct lys_ident *ident;
Radek Krejci4eaf5a82015-12-15 15:10:38 +0100415 struct lys_tpdf *tpdf;
Radek Krejcieab784a2015-08-27 09:56:53 +0200416
417 assert(node);
418 assert(node->schema);
419
420 schema = node->schema; /* shortcut */
421
Radek Krejcica7efb72016-01-18 13:06:01 +0100422 if (node->validity) {
423 /* check presence of all keys in case of list */
424 if (schema->nodetype == LYS_LIST && !(options & (LYD_OPT_FILTER | LYD_OPT_GET | LYD_OPT_GETCONFIG))) {
425 siter = (struct lys_node *)lyv_keys_present(node);
426 if (siter) {
427 /* key not found in the data */
428 LOGVAL(LYE_MISSELEM, line, siter->name, schema->name);
429 return EXIT_FAILURE;
Radek Krejcieab784a2015-08-27 09:56:53 +0200430 }
431 }
Radek Krejcieab784a2015-08-27 09:56:53 +0200432
Radek Krejcica7efb72016-01-18 13:06:01 +0100433 /* mandatory children */
434 if ((schema->nodetype & (LYS_CONTAINER | LYS_LIST))
435 && !(options & (LYD_OPT_FILTER | LYD_OPT_EDIT | LYD_OPT_GET | LYD_OPT_GETCONFIG))) {
Radek Krejci2342cf62016-01-29 16:48:23 +0100436 siter = ly_check_mandatory(node, NULL);
Radek Krejcica7efb72016-01-18 13:06:01 +0100437 if (siter) {
438 if (siter->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
439 LOGVAL(LYE_SPEC, line, "Number of \"%s\" instances in \"%s\" does not follow min/max constraints.",
440 siter->name, siter->parent->name);
Radek Krejci3e0addb2015-08-27 16:37:59 +0200441 } else {
Radek Krejcica7efb72016-01-18 13:06:01 +0100442 LOGVAL(LYE_MISSELEM, line, siter->name, siter->parent->name);
Radek Krejci3e0addb2015-08-27 16:37:59 +0200443 }
Radek Krejcica7efb72016-01-18 13:06:01 +0100444 return EXIT_FAILURE;
Radek Krejci3e0addb2015-08-27 16:37:59 +0200445 }
446 }
Radek Krejci3e0addb2015-08-27 16:37:59 +0200447
Radek Krejcica7efb72016-01-18 13:06:01 +0100448 /* get the first sibling */
449 if (node->parent) {
450 start = node->parent->child;
Radek Krejci27aaa732015-09-04 15:24:04 +0200451 } else {
Radek Krejcica7efb72016-01-18 13:06:01 +0100452 for (start = node; start->prev->next; start = start->prev);
453 }
454
455 /* check that there are no data from different choice case */
456 if (!(options & LYD_OPT_FILTER)) {
457 /* init loop condition */
458 ch = schema;
459
460 while (ch->parent && (ch->parent->nodetype & (LYS_CASE | LYS_CHOICE))) {
461 if (ch->parent->nodetype == LYS_CHOICE) {
462 cs = NULL;
463 ch = ch->parent;
464 } else { /* ch->parent->nodetype == LYS_CASE */
465 cs = ch->parent;
466 ch = ch->parent->parent;
Radek Krejci9fdfd792015-11-09 15:41:14 +0100467 }
468
Radek Krejcica7efb72016-01-18 13:06:01 +0100469 for (diter = start; diter; diter = diter->next) {
470 if (diter == node) {
471 continue;
472 }
473
474 /* find correct level to compare */
475 for (siter = diter->schema->parent; siter; siter = siter->parent) {
476 if (siter->nodetype == LYS_CHOICE) {
477 if (siter == ch) {
478 LOGVAL(LYE_MCASEDATA, line, ch->name);
479 return EXIT_FAILURE;
480 } else {
481 continue;
482 }
483 }
484
485 if (siter->nodetype == LYS_CASE) {
486 if (siter->parent != ch) {
487 continue;
488 } else if (!cs || cs != siter) {
489 LOGVAL(LYE_MCASEDATA, line, ch->name);
490 return EXIT_FAILURE;
491 }
492 }
493
494 /* diter is from something else choice (subtree) */
495 break;
496 }
Radek Krejci3e0addb2015-08-27 16:37:59 +0200497 }
Radek Krejcieab784a2015-08-27 09:56:53 +0200498 }
499 }
Radek Krejci3e0addb2015-08-27 16:37:59 +0200500
Radek Krejcica7efb72016-01-18 13:06:01 +0100501 /* keep this check the last since in case of filter it affects the data and can modify the tree */
502 /* check number of instances (similar to list uniqueness) for non-list nodes */
503 if (schema->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_ANYXML)) {
504 /* find duplicity */
505 for (diter = start; diter; diter = diter->next) {
506 if (diter->schema == schema && diter != node) {
507 if (options & LYD_OPT_FILTER) {
508 /* normalize the filter if needed */
509 switch (schema->nodetype) {
510 case LYS_CONTAINER:
511 if (!filter_compare(diter, node)) {
512 /* merge the two containers, diter will be kept ... */
513 filter_merge(diter, node);
514 /* ... and node will be removed (ly_errno is not set) */
515 return EXIT_FAILURE;
516 } else {
517 /* check that some of them is not a selection node */
518 if (!diter->child) {
519 /* keep diter since it selects all such containers
520 * and let remove the node since it selects just a subset */
521 return EXIT_FAILURE;
522 } else if (!node->child) {
523 /* keep the node and remove diter since it selects subset
524 * of what is selected by node */
525 lyd_free(diter);
526 }
527 /* keep them as they are */
528 return EXIT_SUCCESS;
529 }
530 break;
531 case LYS_LEAF:
532 if (!((struct lyd_node_leaf_list *)diter)->value_str
533 && ((struct lyd_node_leaf_list *)node)->value_str) {
534 /* the first instance is selection node but the new instance is content match node ->
535 * since content match node also works as selection node. keep only the new instance
536 */
537 lyd_free(diter);
538 /* return success to keep the node in the tree */
539 return EXIT_SUCCESS;
540 } else if (!((struct lyd_node_leaf_list *)node)->value_str
541 || ((struct lyd_node_leaf_list *)diter)->value_str ==
542 ((struct lyd_node_leaf_list *)node)->value_str) {
543 /* keep the previous instance and remove the current one ->
544 * return failure but do not set ly_errno */
545 return EXIT_FAILURE;
546 }
547 break;
548 case LYS_ANYXML:
549 /* filtering according to the anyxml content is not allowed,
550 * so anyxml is always a selection node with no content.
551 * Therefore multiple instances of anyxml does not make sense
552 */
553 /* failure is returned but no ly_errno is set */
554 return EXIT_FAILURE;
555 default:
556 /* not possible, but necessary to silence compiler warnings */
557 break;
558 }
559 /* we are done */
Radek Krejci27aaa732015-09-04 15:24:04 +0200560 break;
Radek Krejcica7efb72016-01-18 13:06:01 +0100561 } else {
562 LOGVAL(LYE_TOOMANY, line, schema->name, schema->parent ? schema->parent->name : "data tree");
Radek Krejci27aaa732015-09-04 15:24:04 +0200563 return EXIT_FAILURE;
564 }
Radek Krejcieab784a2015-08-27 09:56:53 +0200565 }
Radek Krejcieab784a2015-08-27 09:56:53 +0200566 }
Radek Krejcica7efb72016-01-18 13:06:01 +0100567 } else if (schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
568 /* uniqueness of list/leaflist instances */
Radek Krejcieab784a2015-08-27 09:56:53 +0200569
Radek Krejcica7efb72016-01-18 13:06:01 +0100570 /* get the first list/leaflist instance sibling */
571 if (options & (LYD_OPT_GET | LYD_OPT_GETCONFIG)) {
572 /* skip key uniqueness check in case of get/get-config data */
573 start = NULL;
574 } else {
575 diter = start;
576 start = NULL;
577 while(diter) {
578 if (diter == node) {
579 diter = diter->next;
580 continue;
581 }
Radek Krejci4eaf5a82015-12-15 15:10:38 +0100582
Radek Krejcica7efb72016-01-18 13:06:01 +0100583 if (diter->schema == node->schema) {
584 /* the same list instance */
585 start = diter;
586 break;
587 }
588 diter = diter->next;
589 }
590 }
591
592 /* check uniqueness of the list/leaflist instances (compare values) */
593 for (diter = start; diter; diter = diter->next) {
594 if (diter->schema != node->schema || diter == node ||
595 diter->validity) { /* skip comparison that will be done in future when checking diter as node */
596 continue;
597 }
598
599 if (options & LYD_OPT_FILTER) {
600 /* compare content match nodes */
601 if (!filter_compare(diter, node)) {
602 /* merge both nodes */
603 /* add selection and containment nodes from result into the diter,
604 * but only in case the diter already contains some selection nodes,
605 * otherwise it already will return all the data */
606 filter_merge(diter, node);
607
608 /* not the error, just return no data */
609 /* failure is returned but no ly_errno is set */
610 return EXIT_FAILURE;
611 } else if (node->schema->nodetype == LYS_LEAFLIST) {
612 /* in contrast to lists, leaflists can be still safely optimized if one of them
613 * is selection node. In that case wee need to keep the other node, which is content
614 * match node and it somehow limit the data to be filtered.
615 */
616 if (!((struct lyd_node_leaf_list *)diter)->value_str) {
617 /* the other instance is selection node, keep the new one whatever it is */
618 lyd_free(diter);
619 break;
620 } else if (!((struct lyd_node_leaf_list *)node)->value_str) {
621 /* the new instance is selection node, keep the previous instance which is
622 * content match node */
623 /* failure is returned but no ly_errno is set */
624 return EXIT_FAILURE;
625 }
626 }
627 } else if (!lyd_compare(diter, node, 1)) { /* comparing keys and unique combinations */
628 LOGVAL(LYE_DUPLIST, line, schema->name);
Radek Krejci4eaf5a82015-12-15 15:10:38 +0100629 return EXIT_FAILURE;
630 }
Radek Krejci4eaf5a82015-12-15 15:10:38 +0100631 }
632 }
Radek Krejcica7efb72016-01-18 13:06:01 +0100633
634 /* status - of the node's schema node itself and all its parents that
635 * cannot have their own instance (like a choice statement) */
636 siter = node->schema;
637 do {
638 if (((siter->flags & LYS_STATUS_MASK) == LYS_STATUS_OBSLT) && (options & LYD_OPT_OBSOLETE)) {
639 LOGVAL(LYE_OBSDATA, line, node->schema->name);
Radek Krejci4eaf5a82015-12-15 15:10:38 +0100640 return EXIT_FAILURE;
641 }
Radek Krejcica7efb72016-01-18 13:06:01 +0100642 siter = siter->parent;
643 } while(siter && !(siter->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST)));
644
645 /* status of the identity value */
646 if (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
647 if (options & LYD_OPT_OBSOLETE) {
648 /* check that we are not instantiating obsolete type */
649 tpdf = ((struct lys_node_leaf *)node->schema)->type.der;
650 while(tpdf) {
651 if ((tpdf->flags & LYS_STATUS_MASK) == LYS_STATUS_OBSLT) {
652 LOGVAL(LYE_OBSTYPE, line, node->schema->name, tpdf->name);
653 return EXIT_FAILURE;
654 }
655 tpdf = tpdf->type.der;
656 }
657 }
658 if (((struct lyd_node_leaf_list *)node)->value_type == LY_TYPE_IDENT) {
659 ident = ((struct lyd_node_leaf_list *)node)->value.ident;
Radek Krejcic6556022016-01-27 15:16:45 +0100660 if (lyp_check_status(schema->flags, schema->module, schema->name,
Radek Krejcica7efb72016-01-18 13:06:01 +0100661 ident->flags, ident->module, ident->name, line)) {
662 return EXIT_FAILURE;
663 }
664 }
Radek Krejci4eaf5a82015-12-15 15:10:38 +0100665 }
Radek Krejcicf509982015-12-15 09:22:44 +0100666 }
667
Michal Vaskobf19d252015-10-08 15:39:17 +0200668 /* check must conditions */
Michal Vasko0d182ba2015-10-09 09:29:14 +0200669 if (unres) {
670 if (unres_data_add(unres, node, UNRES_MUST, line) == -1) {
671 return EXIT_FAILURE;
672 }
673 } else {
674 if (resolve_unres_data_item(node, UNRES_MUST, 0, line)) {
675 return EXIT_FAILURE;
676 }
Michal Vaskobf19d252015-10-08 15:39:17 +0200677 }
678
Radek Krejcieab784a2015-08-27 09:56:53 +0200679 return EXIT_SUCCESS;
680}