blob: ae2a9ef66051ea90b0eea12be04a231fa447142f [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;
143 struct lyd_set *s1 = NULL, *s2 = NULL;
144 int copy;
145
146 if (!to || !from || to->schema != from->schema) {
147 ly_errno = LY_EINVAL;
148 return EXIT_FAILURE;
149 }
150
151 switch(to->schema->nodetype) {
152 case LYS_LIST:
153 case LYS_CONTAINER:
154 if (!from->child) {
155 /* from is selection node, so we want to make the to selection node now */
156 while (to->child) {
157 lyd_free(to->child);
158 }
159 } else if (to->child) {
160 /* both to and from are containment nodes and it was already checked
161 * (by calling filter_compare()) that they selects the same target.
162 * Therefore we can skip the content match nodes (they are the same in
163 * both of them) and merge only the selection and containment nodes */
164
165 /* first, get know if to and from contain some selection or containment
166 * nodes. Because if one of them does not contain any such a node it
167 * selects all the data so it does not make sense to limit it by any
168 * selection/containment node.
169 */
170 s1 = lyd_set_new();
171 s2 = lyd_set_new();
172 LY_TREE_FOR(to->child, diter1) {
173 /* is selection node */
Michal Vasko4c183312015-09-25 10:41:47 +0200174 if ((diter1->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))
175 && !((struct lyd_node_leaf_list *)diter1)->value_str) {
Radek Krejci3e0addb2015-08-27 16:37:59 +0200176 lyd_set_add(s1, diter1);
Michal Vasko17cc7062015-12-10 14:31:48 +0100177 } else if ((diter1->schema->nodetype == LYS_ANYXML) && !((struct lyd_node_anyxml *)diter1)->value->child) {
Radek Krejci3e0addb2015-08-27 16:37:59 +0200178 lyd_set_add(s1, diter1);
179 } else if (diter1->schema->nodetype & (LYS_CONTAINER | LYS_LIST)) {
180 /* or containment node */
181 lyd_set_add(s1, diter1);
182 }
183 }
184
185 LY_TREE_FOR(from->child, diter2) {
186 /* is selection node */
Michal Vasko4c183312015-09-25 10:41:47 +0200187 if ((diter2->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))
188 && !((struct lyd_node_leaf_list *)diter2)->value_str) {
Radek Krejci3e0addb2015-08-27 16:37:59 +0200189 lyd_set_add(s2, diter2);
Michal Vasko17cc7062015-12-10 14:31:48 +0100190 } else if ((diter2->schema->nodetype == LYS_ANYXML) && !((struct lyd_node_anyxml *)diter2)->value->child) {
Radek Krejci3e0addb2015-08-27 16:37:59 +0200191 lyd_set_add(s2, diter2);
192 } else if (diter2->schema->nodetype & (LYS_CONTAINER | LYS_LIST)) {
193 /* or containment node */
194 lyd_set_add(s2, diter2);
195 }
196 }
197
198 if (!s1->number) {
199 /* to already selects all content, so nothing is needed */
200 break;
201 } else if (!s2->number) {
202 /* from selects all content, so make to select it too by
203 * removing all selection and containment nodes
204 */
205 for (i = 0; i < s1->number; i++) {
206 lyd_free(s1->set[i]);
207 }
208 break;
209 } else {
210 /* both contain some selection or containment node(s), so merge them */
211 for (j = 0; j < s2->number; j++) { /* from */
212 copy = 0;
213 for (i = 0; i < s1->number; i++) { /* to */
214 if (s1->set[i]->schema != s2->set[j]->schema) {
215 continue;
216 }
217
218 /* we have something similar to diter1, explore it more */
219 switch (s2->set[j]->schema->nodetype) {
220 case LYS_LIST:
221 case LYS_CONTAINER:
222 if (!filter_compare(s2->set[j], s1->set[i])) {
223 /* merge the two containers into the to */
224 filter_merge(s1->set[i], s2->set[j]);
225 } else {
226 /* check that some of them is not a selection node */
227 if (!s2->set[j]->child) {
228 /* from is selection node, so keep only it because to selects subset */
229 lyd_free(s1->set[i]);
230 /* set the flag to copy the from child at the end */
231 copy = 1;
232 continue;
233 } else if (!s1->set[i]->child) {
234 /* to is already selection node, so ignore the from child */
235 } else {
236 /* they are different so keep trying to search for some other matching instance */
237 continue;
238 }
239 }
240
241 break;
242 case LYS_ANYXML:
243 case LYS_LEAFLIST:
244 case LYS_LEAF:
245 /* here it can be only a selection node, so do not duplicate it (keep i < s1->number) */
246 break;
247 default:
248 /* keep compiler silent */
249 break;
250 }
251
252 /* we have a match, so do not duplicate the current from child and go to check next from child */
253 /* i < s1->number */
254 break;
255 }
256
257 if (copy || i == s1->number) {
258 /* the node is not yet present in to, so move it there */
259 lyd_unlink(s2->set[j]);
260 if (to->child) {
261 to->child->prev->next = s2->set[j];
262 s2->set[j]->prev = to->child->prev;
263 to->child->prev = s2->set[j];
264 } else {
265 to->child = s2->set[j];
266 }
267 s2->set[j]->parent = to;
268 }
269 }
270 }
271 } /* else from is empty, so nothing to do */
272
273 break;
274
275 default:
276 /* no other type needed to cover,
277 * keep the default branch to make compiler silent */
278 break;
279 }
280
281 lyd_set_free(s1);
282 lyd_set_free(s2);
283
284 return EXIT_SUCCESS;
285}
286
Radek Krejcieab784a2015-08-27 09:56:53 +0200287int
Michal Vasko1e62a092015-12-01 12:27:20 +0100288lyv_data_context(const struct lyd_node *node, int options, unsigned int line, struct unres_data *unres)
Radek Krejcieab784a2015-08-27 09:56:53 +0200289{
Michal Vaskocf024702015-10-08 15:01:42 +0200290 assert(node);
Radek Krejcieab784a2015-08-27 09:56:53 +0200291
292 /* check if the node instance is enabled by if-feature */
Michal Vaskocf024702015-10-08 15:01:42 +0200293 if (lys_is_disabled(node->schema, 2)) {
294 LOGVAL(LYE_INELEM, line, node->schema->name);
295 return EXIT_FAILURE;
296 }
297
298 /* check all relevant when conditions */
Michal Vasko0d182ba2015-10-09 09:29:14 +0200299 if (unres) {
Michal Vasko1e62a092015-12-01 12:27:20 +0100300 if (unres_data_add(unres, (struct lyd_node *)node, UNRES_WHEN, line) == -1) {
Michal Vasko0d182ba2015-10-09 09:29:14 +0200301 return EXIT_FAILURE;
302 }
303 } else {
Michal Vasko1e62a092015-12-01 12:27:20 +0100304 if (resolve_unres_data_item((struct lyd_node *)node, UNRES_WHEN, 0, line)) {
Michal Vasko0d182ba2015-10-09 09:29:14 +0200305 return EXIT_FAILURE;
306 }
Radek Krejcieab784a2015-08-27 09:56:53 +0200307 }
308
309 /* check for (non-)presence of status data in edit-config data */
Radek Krejci20cdf632015-11-09 14:44:58 +0100310 if ((options & (LYD_OPT_EDIT | LYD_OPT_GETCONFIG)) && (node->schema->flags & LYS_CONFIG_R)) {
Michal Vaskocf024702015-10-08 15:01:42 +0200311 LOGVAL(LYE_INELEM, line, node->schema->name);
Radek Krejcieab784a2015-08-27 09:56:53 +0200312 return EXIT_FAILURE;
313 }
314
315 return EXIT_SUCCESS;
316}
Michal Vaskocf024702015-10-08 15:01:42 +0200317
Radek Krejcieab784a2015-08-27 09:56:53 +0200318int
Michal Vaskocf024702015-10-08 15:01:42 +0200319lyv_data_content(struct lyd_node *node, int options, unsigned int line, struct unres_data *unres)
Radek Krejcieab784a2015-08-27 09:56:53 +0200320{
Michal Vasko1e62a092015-12-01 12:27:20 +0100321 const struct lys_node *schema, *siter;
322 const struct lys_node *cs, *ch;
Radek Krejcieab784a2015-08-27 09:56:53 +0200323 struct lyd_node *diter, *start;
Radek Krejcicf509982015-12-15 09:22:44 +0100324 struct lys_ident *ident;
Radek Krejcieab784a2015-08-27 09:56:53 +0200325
326 assert(node);
327 assert(node->schema);
328
329 schema = node->schema; /* shortcut */
330
331 /* check presence of all keys in case of list */
Radek Krejci20cdf632015-11-09 14:44:58 +0100332 if (schema->nodetype == LYS_LIST && !(options & (LYD_OPT_FILTER | LYD_OPT_GET | LYD_OPT_GETCONFIG))) {
Radek Krejci27aaa732015-09-04 15:24:04 +0200333 siter = (struct lys_node *)lyv_keys_present(node);
Radek Krejcieab784a2015-08-27 09:56:53 +0200334 if (siter) {
335 /* key not found in the data */
336 LOGVAL(LYE_MISSELEM, line, siter->name, schema->name);
337 return EXIT_FAILURE;
338 }
339 }
340
341 /* mandatory children */
Radek Krejci20cdf632015-11-09 14:44:58 +0100342 if ((schema->nodetype & (LYS_CONTAINER | LYS_LIST))
343 && !(options & (LYD_OPT_FILTER | LYD_OPT_EDIT | LYD_OPT_GET | LYD_OPT_GETCONFIG))) {
Radek Krejcieab784a2015-08-27 09:56:53 +0200344 siter = ly_check_mandatory(node);
345 if (siter) {
346 if (siter->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
347 LOGVAL(LYE_SPEC, line, "Number of \"%s\" instances in \"%s\" does not follow min/max constraints.",
348 siter->name, siter->parent->name);
349 } else {
350 LOGVAL(LYE_MISSELEM, line, siter->name, siter->parent->name);
351 }
352 return EXIT_FAILURE;
353 }
354 }
355
356 /* get the first sibling */
357 if (node->parent) {
358 start = node->parent->child;
359 } else {
360 for (start = node; start->prev->next; start = start->prev);
361 }
362
Radek Krejcieab784a2015-08-27 09:56:53 +0200363 /* check that there are no data from different choice case */
Radek Krejci37bda002015-08-27 11:23:56 +0200364 if (!(options & LYD_OPT_FILTER)) {
365 /* init loop condition */
366 ch = schema;
367
368 while (ch->parent && (ch->parent->nodetype & (LYS_CASE | LYS_CHOICE))) {
369 if (ch->parent->nodetype == LYS_CHOICE) {
370 cs = NULL;
371 ch = ch->parent;
372 } else { /* ch->parent->nodetype == LYS_CASE */
373 cs = ch->parent;
374 ch = ch->parent->parent;
Radek Krejcieab784a2015-08-27 09:56:53 +0200375 }
376
Radek Krejci37bda002015-08-27 11:23:56 +0200377 for (diter = start; diter; diter = diter->next) {
378 if (diter == node) {
379 continue;
380 }
381
382 /* find correct level to compare */
383 for (siter = diter->schema->parent; siter; siter = siter->parent) {
384 if (siter->nodetype == LYS_CHOICE) {
385 if (siter == ch) {
386 LOGVAL(LYE_MCASEDATA, line, ch->name);
387 return EXIT_FAILURE;
388 } else {
389 continue;
390 }
391 }
392
393 if (siter->nodetype == LYS_CASE) {
394 if (siter->parent != ch) {
395 continue;
396 } else if (!cs || cs != siter) {
397 LOGVAL(LYE_MCASEDATA, line, ch->name);
398 return EXIT_FAILURE;
399 }
400 }
401
402 /* diter is from something else choice (subtree) */
403 break;
404 }
Radek Krejcieab784a2015-08-27 09:56:53 +0200405 }
406 }
407 }
408
Radek Krejci3e0addb2015-08-27 16:37:59 +0200409 /* keep this check the last since in case of filter it affects the data and can modify the tree */
410 /* check number of instances (similar to list uniqueness) for non-list nodes */
411 if (schema->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_ANYXML)) {
412 /* find duplicity */
413 for (diter = start; diter; diter = diter->next) {
414 if (diter->schema == schema && diter != node) {
415 if (options & LYD_OPT_FILTER) {
416 /* normalize the filter if needed */
417 switch (schema->nodetype) {
418 case LYS_CONTAINER:
419 if (!filter_compare(diter, node)) {
420 /* merge the two containers, diter will be kept ... */
421 filter_merge(diter, node);
422 /* ... and node will be removed (ly_errno is not set) */
423 return EXIT_FAILURE;
424 } else {
425 /* check that some of them is not a selection node */
426 if (!diter->child) {
427 /* keep diter since it selects all such containers
428 * and let remove the node since it selects just a subset */
429 return EXIT_FAILURE;
430 } else if (!node->child) {
431 /* keep the node and remove diter since it selects subset
432 * of what is selected by node */
433 lyd_free(diter);
434 }
435 /* keep them as they are */
436 return EXIT_SUCCESS;
437 }
438 break;
439 case LYS_LEAF:
Michal Vasko4c183312015-09-25 10:41:47 +0200440 if (!((struct lyd_node_leaf_list *)diter)->value_str
441 && ((struct lyd_node_leaf_list *)node)->value_str) {
Radek Krejci3e0addb2015-08-27 16:37:59 +0200442 /* the first instance is selection node but the new instance is content match node ->
443 * since content match node also works as selection node. keep only the new instance
444 */
445 lyd_free(diter);
446 /* return success to keep the node in the tree */
447 return EXIT_SUCCESS;
Michal Vasko4c183312015-09-25 10:41:47 +0200448 } else if (!((struct lyd_node_leaf_list *)node)->value_str
449 || ((struct lyd_node_leaf_list *)diter)->value_str ==
450 ((struct lyd_node_leaf_list *)node)->value_str) {
Radek Krejci3e0addb2015-08-27 16:37:59 +0200451 /* keep the previous instance and remove the current one ->
452 * return failure but do not set ly_errno */
453 return EXIT_FAILURE;
454 }
455 break;
456 case LYS_ANYXML:
457 /* filtering according to the anyxml content is not allowed,
458 * so anyxml is always a selection node with no content.
459 * Therefore multiple instances of anyxml does not make sense
460 */
461 /* failure is returned but no ly_errno is set */
462 return EXIT_FAILURE;
463 default:
464 /* not possible, but necessary to silence compiler warnings */
465 break;
466 }
467 /* we are done */
468 break;
469 } else {
470 LOGVAL(LYE_TOOMANY, line, schema->name, schema->parent ? schema->parent->name : "data tree");
471 return EXIT_FAILURE;
472 }
473 }
474 }
Radek Krejci27aaa732015-09-04 15:24:04 +0200475 } else if (schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
476 /* uniqueness of list/leaflist instances */
Radek Krejci3e0addb2015-08-27 16:37:59 +0200477
Radek Krejci27aaa732015-09-04 15:24:04 +0200478 /* get the first list/leaflist instance sibling */
Radek Krejci20cdf632015-11-09 14:44:58 +0100479 if (options & (LYD_OPT_GET | LYD_OPT_GETCONFIG)) {
480 /* skip key uniqueness check in case of get/get-config data */
481 start = NULL;
Radek Krejci27aaa732015-09-04 15:24:04 +0200482 } else {
Radek Krejci9fdfd792015-11-09 15:41:14 +0100483 diter = start;
Radek Krejci27aaa732015-09-04 15:24:04 +0200484 start = NULL;
Radek Krejci9fdfd792015-11-09 15:41:14 +0100485 while(diter) {
486 if (diter == node) {
487 diter = diter->next;
488 continue;
489 }
490
Radek Krejci27aaa732015-09-04 15:24:04 +0200491 if (diter->schema == node->schema) {
492 /* the same list instance */
493 start = diter;
Radek Krejci9fdfd792015-11-09 15:41:14 +0100494 break;
Radek Krejci3e0addb2015-08-27 16:37:59 +0200495 }
Radek Krejci9fdfd792015-11-09 15:41:14 +0100496 diter = diter->next;
Radek Krejcieab784a2015-08-27 09:56:53 +0200497 }
498 }
Radek Krejci3e0addb2015-08-27 16:37:59 +0200499
Radek Krejci27aaa732015-09-04 15:24:04 +0200500 /* check uniqueness of the list/leaflist instances (compare values) */
501 for (diter = start; diter; diter = diter->next) {
502 if (diter->schema != node->schema || diter == node) {
Radek Krejcieab784a2015-08-27 09:56:53 +0200503 continue;
504 }
505
506 if (options & LYD_OPT_FILTER) {
507 /* compare content match nodes */
Radek Krejci3e0addb2015-08-27 16:37:59 +0200508 if (!filter_compare(diter, node)) {
Radek Krejcieab784a2015-08-27 09:56:53 +0200509 /* merge both nodes */
510 /* add selection and containment nodes from result into the diter,
511 * but only in case the diter already contains some selection nodes,
512 * otherwise it already will return all the data */
Radek Krejci3e0addb2015-08-27 16:37:59 +0200513 filter_merge(diter, node);
Radek Krejcieab784a2015-08-27 09:56:53 +0200514
515 /* not the error, just return no data */
Radek Krejcieab784a2015-08-27 09:56:53 +0200516 /* failure is returned but no ly_errno is set */
517 return EXIT_FAILURE;
Radek Krejci27aaa732015-09-04 15:24:04 +0200518 } else if (node->schema->nodetype == LYS_LEAFLIST) {
519 /* in contrast to lists, leaflists can be still safely optimized if one of them
520 * is selection node. In that case wee need to keep the other node, which is content
521 * match node and it somehow limit the data to be filtered.
522 */
Michal Vasko4c183312015-09-25 10:41:47 +0200523 if (!((struct lyd_node_leaf_list *)diter)->value_str) {
Radek Krejci27aaa732015-09-04 15:24:04 +0200524 /* the other instance is selection node, keep the new one whatever it is */
525 lyd_free(diter);
526 break;
Michal Vasko4c183312015-09-25 10:41:47 +0200527 } else if (!((struct lyd_node_leaf_list *)node)->value_str) {
Radek Krejci27aaa732015-09-04 15:24:04 +0200528 /* the new instance is selection node, keep the previous instance which is
529 * content match node */
530 /* failure is returned but no ly_errno is set */
531 return EXIT_FAILURE;
532 }
Radek Krejcieab784a2015-08-27 09:56:53 +0200533 }
Radek Krejci27aaa732015-09-04 15:24:04 +0200534 } else if (!lyd_compare(diter, node, 1)) { /* comparing keys and unique combinations */
535 LOGVAL(LYE_DUPLIST, line, schema->name);
536 return EXIT_FAILURE;
Radek Krejcieab784a2015-08-27 09:56:53 +0200537 }
538 }
539 }
540
Radek Krejcicf509982015-12-15 09:22:44 +0100541 /* status of the identity value */
542 if ((schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && (((struct lyd_node_leaf_list *)node)->value_type == LY_TYPE_IDENT)) {
543 ident = ((struct lyd_node_leaf_list *)node)->value.ident;
544 if (check_status(schema->flags, schema->module, schema->name,
545 ident->flags, ident->module, ident->name, line)) {
546 return EXIT_FAILURE;
547 }
548 }
549
Michal Vaskobf19d252015-10-08 15:39:17 +0200550 /* check must conditions */
Michal Vasko0d182ba2015-10-09 09:29:14 +0200551 if (unres) {
552 if (unres_data_add(unres, node, UNRES_MUST, line) == -1) {
553 return EXIT_FAILURE;
554 }
555 } else {
556 if (resolve_unres_data_item(node, UNRES_MUST, 0, line)) {
557 return EXIT_FAILURE;
558 }
Michal Vaskobf19d252015-10-08 15:39:17 +0200559 }
560
Radek Krejcieab784a2015-08-27 09:56:53 +0200561 return EXIT_SUCCESS;
562}