1 /**
2 * @file resolve.c
3 * @author Michal Vasko <mvasko@cesnet.cz>
4 * @brief libyang resolve functions
5 *
6 * Copyright (c) 2015 - 2018 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
14
15 #define _GNU_SOURCE
16
17 #include <stdlib.h>
18 #include <assert.h>
19 #include <string.h>
20 #include <ctype.h>
21 #include <inttypes.h>
22 #include <limits.h>
23
24 #include "libyang.h"
25 #include "resolve.h"
26 #include "common.h"
27 #include "xpath.h"
28 #include "parser.h"
29 #include "parser_yang.h"
30 #include "xml_internal.h"
31 #include "hash_table.h"
32 #include "tree_internal.h"
33 #include "extensions.h"
34 #include "validation.h"
35
36 /* internal parsed predicate structure */
37 struct parsed_pred {
38 const struct lys_node *schema;
39 const char *pred_str;
40 int pred_str_len;
41
42 int len;
43 struct {
44 const char *mod_name;
45 int mod_name_len;
46 const char *name;
47 int nam_len;
48 const char *value;
49 int val_len;
50 } *pred;
51 };
52
53 static int
check_overflow_mul(int64_t num1,int64_t num2)54 check_overflow_mul(int64_t num1, int64_t num2)
55 {
56 if (((num1 == -1) && (num2 == INT64_MIN)) || ((num2 == -1) && (num1 == INT64_MIN))) {
57 return 1;
58 }
59
60 if ((num1 > INT64_MAX / num2) || (num1 < INT64_MIN / num2)) {
61 return 1;
62 }
63
64 return 0;
65 }
66
67 static int
check_overflow_sub(int64_t num1,int64_t num2)68 check_overflow_sub(int64_t num1, int64_t num2)
69 {
70 if (((num2 < 0) && (num1 > INT64_MAX + num2)) || ((num2 > 0) && (num1 < INT64_MIN + num2))) {
71 return 1;
72 }
73
74 return 0;
75 }
76
77 static int
check_overflow_add(int64_t num1,int64_t num2)78 check_overflow_add(int64_t num1, int64_t num2)
79 {
80 if (((num2 > 0) && (num1 > INT64_MAX - num2)) || ((num2 < 0) && (num1 < INT64_MIN - num2))) {
81 return 1;
82 }
83
84 return 0;
85 }
86
87 int
parse_range_dec64(const char ** str_num,uint8_t dig,int64_t * num)88 parse_range_dec64(const char **str_num, uint8_t dig, int64_t *num)
89 {
90 const char *ptr;
91 int minus = 0;
92 int64_t ret = 0;
93 int8_t str_exp, str_dig = -1, trailing_zeros = 0;
94
95 ptr = *str_num;
96
97 if (ptr[0] == '-') {
98 minus = 1;
99 ++ptr;
100 } else if (ptr[0] == '+') {
101 ++ptr;
102 }
103
104 if (!isdigit(ptr[0])) {
105 /* there must be at least one */
106 return 1;
107 }
108
109 for (str_exp = 0; isdigit(ptr[0]) || ((ptr[0] == '.') && (str_dig < 0)); ++ptr) {
110 if (str_exp > 18) {
111 return 1;
112 }
113
114 if (ptr[0] == '.') {
115 if (ptr[1] == '.') {
116 /* it's the next interval */
117 break;
118 }
119 ++str_dig;
120 } else {
121 if (check_overflow_mul(ret, 10)) {
122 return 1;
123 }
124 ret *= 10;
125
126 if (minus) {
127 if (check_overflow_sub(ret, ptr[0] - '0')) {
128 return 1;
129 }
130 ret -= ptr[0] - '0';
131 } else {
132 if (check_overflow_add(ret, ptr[0] - '0')) {
133 return 1;
134 }
135 ret += ptr[0] - '0';
136 }
137 if (str_dig > -1) {
138 ++str_dig;
139 if (ptr[0] == '0') {
140 /* possibly trailing zero */
141 trailing_zeros++;
142 } else {
143 trailing_zeros = 0;
144 }
145 }
146 ++str_exp;
147 }
148 }
149 if (str_dig == 0) {
150 /* no digits after '.' */
151 return 1;
152 } else if (str_dig == -1) {
153 /* there are 0 numbers after the floating point */
154 str_dig = 0;
155 }
156 /* remove trailing zeros */
157 if (trailing_zeros) {
158 str_dig -= trailing_zeros;
159 str_exp -= trailing_zeros;
160 ret = ret / dec_pow(trailing_zeros);
161 }
162
163 /* it's parsed, now adjust the number based on fraction-digits, if needed */
164 if (str_dig < dig) {
165 if ((str_exp - 1) + (dig - str_dig) > 18) {
166 return 1;
167 }
168
169 if (check_overflow_mul(ret, dec_pow(dig - str_dig))) {
170 return 1;
171 }
172 ret *= dec_pow(dig - str_dig);
173 }
174 if (str_dig > dig) {
175 return 1;
176 }
177
178 *str_num = ptr;
179 *num = ret;
180
181 return 0;
182 }
183
184 /**
185 * @brief Parse an identifier.
186 *
187 * ;; An identifier MUST NOT start with (('X'|'x') ('M'|'m') ('L'|'l'))
188 * identifier = (ALPHA / "_")
189 * *(ALPHA / DIGIT / "_" / "-" / ".")
190 *
191 * @param[in] id Identifier to use.
192 *
193 * @return Number of characters successfully parsed.
194 */
195 unsigned int
parse_identifier(const char * id)196 parse_identifier(const char *id)
197 {
198 unsigned int parsed = 0;
199
200 assert(id);
201
202 if (!isalpha(id[0]) && (id[0] != '_')) {
203 return -parsed;
204 }
205
206 ++parsed;
207 ++id;
208
209 while (isalnum(id[0]) || (id[0] == '_') || (id[0] == '-') || (id[0] == '.')) {
210 ++parsed;
211 ++id;
212 }
213
214 return parsed;
215 }
216
217 /**
218 * @brief Parse a node-identifier.
219 *
220 * node-identifier = [module-name ":"] identifier
221 *
222 * @param[in] id Identifier to use.
223 * @param[out] mod_name Points to the module name, NULL if there is not any.
224 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
225 * @param[out] name Points to the node name.
226 * @param[out] nam_len Length of the node name.
227 * @param[out] all_desc Whether the path starts with '/', only supported in extended paths.
228 * @param[in] extended Whether to accept an extended path (support for [prefix:]*, /[prefix:]*, /[prefix:]., prefix:#identifier).
229 *
230 * @return Number of characters successfully parsed,
231 * positive on success, negative on failure.
232 */
233 static int
parse_node_identifier(const char * id,const char ** mod_name,int * mod_name_len,const char ** name,int * nam_len,int * all_desc,int extended)234 parse_node_identifier(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len,
235 int *all_desc, int extended)
236 {
237 int parsed = 0, ret, all_desc_local = 0, first_id_len;
238 const char *first_id;
239
240 assert(id);
241 assert((mod_name && mod_name_len) || (!mod_name && !mod_name_len));
242 assert((name && nam_len) || (!name && !nam_len));
243
244 if (mod_name) {
245 *mod_name = NULL;
246 *mod_name_len = 0;
247 }
248 if (name) {
249 *name = NULL;
250 *nam_len = 0;
251 }
252
253 if (extended) {
254 /* try to parse only the extended expressions */
255 if (id[parsed] == '/') {
256 if (all_desc) {
257 *all_desc = 1;
258 }
259 all_desc_local = 1;
260 } else {
261 if (all_desc) {
262 *all_desc = 0;
263 }
264 }
265
266 /* is there a prefix? */
267 ret = parse_identifier(id + all_desc_local);
268 if (ret > 0) {
269 if (id[all_desc_local + ret] != ':') {
270 /* this is not a prefix, so not an extended id */
271 goto standard_id;
272 }
273
274 if (mod_name) {
275 *mod_name = id + all_desc_local;
276 *mod_name_len = ret;
277 }
278
279 /* "/" and ":" */
280 ret += all_desc_local + 1;
281 } else {
282 ret = all_desc_local;
283 }
284
285 /* parse either "*" or "." */
286 if (*(id + ret) == '*') {
287 if (name) {
288 *name = id + ret;
289 *nam_len = 1;
290 }
291 ++ret;
292
293 return ret;
294 } else if (*(id + ret) == '.') {
295 if (!all_desc_local) {
296 /* /. is redundant expression, we do not accept it */
297 return -ret;
298 }
299
300 if (name) {
301 *name = id + ret;
302 *nam_len = 1;
303 }
304 ++ret;
305
306 return ret;
307 } else if (*(id + ret) == '#') {
308 if (all_desc_local || !ret) {
309 /* no prefix */
310 return 0;
311 }
312 parsed = ret + 1;
313 if ((ret = parse_identifier(id + parsed)) < 1) {
314 return -parsed + ret;
315 }
316 *name = id + parsed - 1;
317 *nam_len = ret + 1;
318 return parsed + ret;
319 }
320 /* else a standard id, parse it all again */
321 }
322
323 standard_id:
324 if ((ret = parse_identifier(id)) < 1) {
325 return ret;
326 }
327
328 first_id = id;
329 first_id_len = ret;
330
331 parsed += ret;
332 id += ret;
333
334 /* there is prefix */
335 if (id[0] == ':') {
336 ++parsed;
337 ++id;
338
339 /* there isn't */
340 } else {
341 if (name) {
342 *name = first_id;
343 *nam_len = first_id_len;
344 }
345
346 return parsed;
347 }
348
349 /* identifier (node name) */
350 if ((ret = parse_identifier(id)) < 1) {
351 return -parsed + ret;
352 }
353
354 if (mod_name) {
355 *mod_name = first_id;
356 *mod_name_len = first_id_len;
357 }
358 if (name) {
359 *name = id;
360 *nam_len = ret;
361 }
362
363 return parsed + ret;
364 }
365
366 /**
367 * @brief Parse a path-predicate (leafref).
368 *
369 * path-predicate = "[" *WSP path-equality-expr *WSP "]"
370 * path-equality-expr = node-identifier *WSP "=" *WSP path-key-expr
371 *
372 * @param[in] id Identifier to use.
373 * @param[out] prefix Points to the prefix, NULL if there is not any.
374 * @param[out] pref_len Length of the prefix, 0 if there is not any.
375 * @param[out] name Points to the node name.
376 * @param[out] nam_len Length of the node name.
377 * @param[out] path_key_expr Points to the path-key-expr.
378 * @param[out] pke_len Length of the path-key-expr.
379 * @param[out] has_predicate Flag to mark whether there is another predicate following.
380 *
381 * @return Number of characters successfully parsed,
382 * positive on success, negative on failure.
383 */
384 static int
parse_path_predicate(const char * id,const char ** prefix,int * pref_len,const char ** name,int * nam_len,const char ** path_key_expr,int * pke_len,int * has_predicate)385 parse_path_predicate(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
386 const char **path_key_expr, int *pke_len, int *has_predicate)
387 {
388 const char *ptr;
389 int parsed = 0, ret;
390
391 assert(id);
392 if (prefix) {
393 *prefix = NULL;
394 }
395 if (pref_len) {
396 *pref_len = 0;
397 }
398 if (name) {
399 *name = NULL;
400 }
401 if (nam_len) {
402 *nam_len = 0;
403 }
404 if (path_key_expr) {
405 *path_key_expr = NULL;
406 }
407 if (pke_len) {
408 *pke_len = 0;
409 }
410 if (has_predicate) {
411 *has_predicate = 0;
412 }
413
414 if (id[0] != '[') {
415 return -parsed;
416 }
417
418 ++parsed;
419 ++id;
420
421 while (isspace(id[0])) {
422 ++parsed;
423 ++id;
424 }
425
426 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len, NULL, 0)) < 1) {
427 return -parsed + ret;
428 }
429
430 parsed += ret;
431 id += ret;
432
433 while (isspace(id[0])) {
434 ++parsed;
435 ++id;
436 }
437
438 if (id[0] != '=') {
439 return -parsed;
440 }
441
442 ++parsed;
443 ++id;
444
445 while (isspace(id[0])) {
446 ++parsed;
447 ++id;
448 }
449
450 if ((ptr = strchr(id, ']')) == NULL) {
451 return -parsed;
452 }
453
454 --ptr;
455 while (isspace(ptr[0])) {
456 --ptr;
457 }
458 ++ptr;
459
460 ret = ptr-id;
461 if (path_key_expr) {
462 *path_key_expr = id;
463 }
464 if (pke_len) {
465 *pke_len = ret;
466 }
467
468 parsed += ret;
469 id += ret;
470
471 while (isspace(id[0])) {
472 ++parsed;
473 ++id;
474 }
475
476 assert(id[0] == ']');
477
478 if (id[1] == '[') {
479 *has_predicate = 1;
480 }
481
482 return parsed+1;
483 }
484
485 /**
486 * @brief Parse a path-key-expr (leafref). First call parses "current()", all
487 * the ".." and the first node-identifier, other calls parse a single
488 * node-identifier each.
489 *
490 * path-key-expr = current-function-invocation *WSP "/" *WSP
491 * rel-path-keyexpr
492 * rel-path-keyexpr = 1*(".." *WSP "/" *WSP)
493 * *(node-identifier *WSP "/" *WSP)
494 * node-identifier
495 *
496 * @param[in] id Identifier to use.
497 * @param[out] prefix Points to the prefix, NULL if there is not any.
498 * @param[out] pref_len Length of the prefix, 0 if there is not any.
499 * @param[out] name Points to the node name.
500 * @param[out] nam_len Length of the node name.
501 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
502 * must not be changed between consecutive calls.
503 * @return Number of characters successfully parsed,
504 * positive on success, negative on failure.
505 */
506 static int
parse_path_key_expr(const char * id,const char ** prefix,int * pref_len,const char ** name,int * nam_len,int * parent_times)507 parse_path_key_expr(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
508 int *parent_times)
509 {
510 int parsed = 0, ret, par_times = 0;
511
512 assert(id);
513 assert(parent_times);
514 if (prefix) {
515 *prefix = NULL;
516 }
517 if (pref_len) {
518 *pref_len = 0;
519 }
520 if (name) {
521 *name = NULL;
522 }
523 if (nam_len) {
524 *nam_len = 0;
525 }
526
527 if (!*parent_times) {
528 /* current-function-invocation *WSP "/" *WSP rel-path-keyexpr */
529 if (strncmp(id, "current()", 9)) {
530 return -parsed;
531 }
532
533 parsed += 9;
534 id += 9;
535
536 while (isspace(id[0])) {
537 ++parsed;
538 ++id;
539 }
540
541 if (id[0] != '/') {
542 return -parsed;
543 }
544
545 ++parsed;
546 ++id;
547
548 while (isspace(id[0])) {
549 ++parsed;
550 ++id;
551 }
552
553 /* rel-path-keyexpr */
554 if (strncmp(id, "..", 2)) {
555 return -parsed;
556 }
557 ++par_times;
558
559 parsed += 2;
560 id += 2;
561
562 while (isspace(id[0])) {
563 ++parsed;
564 ++id;
565 }
566 }
567
568 /* 1*(".." *WSP "/" *WSP) *(node-identifier *WSP "/" *WSP) node-identifier
569 *
570 * first parent reference with whitespaces already parsed
571 */
572 if (id[0] != '/') {
573 return -parsed;
574 }
575
576 ++parsed;
577 ++id;
578
579 while (isspace(id[0])) {
580 ++parsed;
581 ++id;
582 }
583
584 while (!strncmp(id, "..", 2) && !*parent_times) {
585 ++par_times;
586
587 parsed += 2;
588 id += 2;
589
590 while (isspace(id[0])) {
591 ++parsed;
592 ++id;
593 }
594
595 if (id[0] != '/') {
596 return -parsed;
597 }
598
599 ++parsed;
600 ++id;
601
602 while (isspace(id[0])) {
603 ++parsed;
604 ++id;
605 }
606 }
607
608 if (!*parent_times) {
609 *parent_times = par_times;
610 }
611
612 /* all parent references must be parsed at this point */
613 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len, NULL, 0)) < 1) {
614 return -parsed + ret;
615 }
616
617 parsed += ret;
618 id += ret;
619
620 return parsed;
621 }
622
623 /**
624 * @brief Parse path-arg (leafref).
625 *
626 * path-arg = absolute-path / relative-path
627 * absolute-path = 1*("/" (node-identifier *path-predicate))
628 * relative-path = 1*(".." "/") descendant-path
629 *
630 * @param[in] mod Module of the context node to get correct prefix in case it is not explicitly specified
631 * @param[in] id Identifier to use.
632 * @param[out] prefix Points to the prefix, NULL if there is not any.
633 * @param[out] pref_len Length of the prefix, 0 if there is not any.
634 * @param[out] name Points to the node name.
635 * @param[out] nam_len Length of the node name.
636 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
637 * must not be changed between consecutive calls. -1 if the
638 * path is relative.
639 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
640 *
641 * @return Number of characters successfully parsed,
642 * positive on success, negative on failure.
643 */
644 static int
parse_path_arg(const struct lys_module * mod,const char * id,const char ** prefix,int * pref_len,const char ** name,int * nam_len,int * parent_times,int * has_predicate)645 parse_path_arg(const struct lys_module *mod, const char *id, const char **prefix, int *pref_len,
646 const char **name, int *nam_len, int *parent_times, int *has_predicate)
647 {
648 int parsed = 0, ret, par_times = 0;
649
650 assert(id);
651 assert(parent_times);
652 if (prefix) {
653 *prefix = NULL;
654 }
655 if (pref_len) {
656 *pref_len = 0;
657 }
658 if (name) {
659 *name = NULL;
660 }
661 if (nam_len) {
662 *nam_len = 0;
663 }
664 if (has_predicate) {
665 *has_predicate = 0;
666 }
667
668 if (!*parent_times && !strncmp(id, "..", 2)) {
669 ++par_times;
670
671 parsed += 2;
672 id += 2;
673
674 while (!strncmp(id, "/..", 3)) {
675 ++par_times;
676
677 parsed += 3;
678 id += 3;
679 }
680 }
681
682 if (!*parent_times) {
683 if (par_times) {
684 *parent_times = par_times;
685 } else {
686 *parent_times = -1;
687 }
688 }
689
690 if (id[0] != '/') {
691 return -parsed;
692 }
693
694 /* skip '/' */
695 ++parsed;
696 ++id;
697
698 /* node-identifier ([prefix:]identifier) */
699 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len, NULL, 0)) < 1) {
700 return -parsed + ret;
701 }
702 if (prefix && !(*prefix)) {
703 /* actually we always need prefix even it is not specified */
704 *prefix = lys_main_module(mod)->name;
705 *pref_len = strlen(*prefix);
706 }
707
708 parsed += ret;
709 id += ret;
710
711 /* there is no predicate */
712 if ((id[0] == '/') || !id[0]) {
713 return parsed;
714 } else if (id[0] != '[') {
715 return -parsed;
716 }
717
718 if (has_predicate) {
719 *has_predicate = 1;
720 }
721
722 return parsed;
723 }
724
725 /**
726 * @brief Parse instance-identifier in JSON data format. That means that prefixes
727 * are actually model names.
728 *
729 * instance-identifier = 1*("/" (node-identifier *predicate))
730 *
731 * @param[in] id Identifier to use.
732 * @param[out] model Points to the model name.
733 * @param[out] mod_len Length of the model name.
734 * @param[out] name Points to the node name.
735 * @param[out] nam_len Length of the node name.
736 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
737 *
738 * @return Number of characters successfully parsed,
739 * positive on success, negative on failure.
740 */
741 static int
parse_instance_identifier(const char * id,const char ** model,int * mod_len,const char ** name,int * nam_len,int * has_predicate)742 parse_instance_identifier(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
743 int *has_predicate)
744 {
745 int parsed = 0, ret;
746
747 assert(id && model && mod_len && name && nam_len);
748
749 if (has_predicate) {
750 *has_predicate = 0;
751 }
752
753 if (id[0] != '/') {
754 return -parsed;
755 }
756
757 ++parsed;
758 ++id;
759
760 if ((ret = parse_identifier(id)) < 1) {
761 return ret;
762 }
763
764 *name = id;
765 *nam_len = ret;
766
767 *model = NULL;
768 *mod_len = 0;
769
770 parsed += ret;
771 id += ret;
772
773 if (id[0] == ':') {
774 /* we have prefix */
775 *model = *name;
776 *mod_len = *nam_len;
777
778 ++parsed;
779 ++id;
780
781 if ((ret = parse_identifier(id)) < 1) {
782 return ret;
783 }
784
785 *name = id;
786 *nam_len = ret;
787
788 parsed += ret;
789 id += ret;
790 }
791
792 if (id[0] == '[' && has_predicate) {
793 *has_predicate = 1;
794 }
795
796 return parsed;
797 }
798
799 /**
800 * @brief Parse predicate (instance-identifier) in JSON data format. That means that prefixes
801 * (which are mandatory) are actually model names.
802 *
803 * predicate = "[" *WSP (predicate-expr / pos) *WSP "]"
804 * predicate-expr = (node-identifier / ".") *WSP "=" *WSP
805 * ((DQUOTE string DQUOTE) /
806 * (SQUOTE string SQUOTE))
807 * pos = non-negative-integer-value
808 *
809 * @param[in] id Identifier to use.
810 * @param[out] model Points to the model name.
811 * @param[out] mod_len Length of the model name.
812 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
813 * @param[out] nam_len Length of the node name.
814 * @param[out] value Value the node-identifier must have (string from the grammar),
815 * NULL if there is not any.
816 * @param[out] val_len Length of the value, 0 if there is not any.
817 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
818 *
819 * @return Number of characters successfully parsed,
820 * positive on success, negative on failure.
821 */
822 static int
parse_predicate(const char * id,const char ** model,int * mod_len,const char ** name,int * nam_len,const char ** value,int * val_len,int * has_predicate)823 parse_predicate(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
824 const char **value, int *val_len, int *has_predicate)
825 {
826 const char *ptr;
827 int parsed = 0, ret;
828 char quote;
829
830 assert(id);
831 if (model) {
832 assert(mod_len);
833 *model = NULL;
834 *mod_len = 0;
835 }
836 if (name) {
837 assert(nam_len);
838 *name = NULL;
839 *nam_len = 0;
840 }
841 if (value) {
842 assert(val_len);
843 *value = NULL;
844 *val_len = 0;
845 }
846 if (has_predicate) {
847 *has_predicate = 0;
848 }
849
850 if (id[0] != '[') {
851 return -parsed;
852 }
853
854 ++parsed;
855 ++id;
856
857 while (isspace(id[0])) {
858 ++parsed;
859 ++id;
860 }
861
862 /* pos */
863 if (isdigit(id[0])) {
864 if (name) {
865 *name = id;
866 }
867
868 if (id[0] == '0') {
869 return -parsed;
870 }
871
872 while (isdigit(id[0])) {
873 ++parsed;
874 ++id;
875 }
876
877 if (nam_len) {
878 *nam_len = id-(*name);
879 }
880
881 /* "." or node-identifier */
882 } else {
883 if (id[0] == '.') {
884 if (name) {
885 *name = id;
886 }
887 if (nam_len) {
888 *nam_len = 1;
889 }
890
891 ++parsed;
892 ++id;
893
894 } else {
895 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len, NULL, 0)) < 1) {
896 return -parsed + ret;
897 }
898
899 parsed += ret;
900 id += ret;
901 }
902
903 while (isspace(id[0])) {
904 ++parsed;
905 ++id;
906 }
907
908 if (id[0] != '=') {
909 return -parsed;
910 }
911
912 ++parsed;
913 ++id;
914
915 while (isspace(id[0])) {
916 ++parsed;
917 ++id;
918 }
919
920 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
921 if ((id[0] == '\"') || (id[0] == '\'')) {
922 quote = id[0];
923
924 ++parsed;
925 ++id;
926
927 for (ptr = id; ptr && ptr[0] != quote; ++ptr) {
928 if (ptr[0] == '\\') {
929 ++ptr;
930 }
931 }
932 if (!ptr) {
933 return -parsed;
934 }
935 ret = ptr - id;
936
937 if (value) {
938 *value = id;
939 }
940 if (val_len) {
941 *val_len = ret;
942 }
943
944 parsed += ret + 1;
945 id += ret + 1;
946 } else {
947 return -parsed;
948 }
949 }
950
951 while (isspace(id[0])) {
952 ++parsed;
953 ++id;
954 }
955
956 if (id[0] != ']') {
957 return -parsed;
958 }
959
960 ++parsed;
961 ++id;
962
963 if ((id[0] == '[') && has_predicate) {
964 *has_predicate = 1;
965 }
966
967 return parsed;
968 }
969
970 /**
971 * @brief Parse schema-nodeid.
972 *
973 * schema-nodeid = absolute-schema-nodeid /
974 * descendant-schema-nodeid
975 * absolute-schema-nodeid = 1*("/" node-identifier)
976 * descendant-schema-nodeid = ["." "/"]
977 * node-identifier
978 * absolute-schema-nodeid
979 *
980 * @param[in] id Identifier to use.
981 * @param[out] mod_name Points to the module name, NULL if there is not any.
982 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
983 * @param[out] name Points to the node name.
984 * @param[out] nam_len Length of the node name.
985 * @param[out] is_relative Flag to mark whether the nodeid is absolute or descendant. Must be -1
986 * on the first call, must not be changed between consecutive calls.
987 * @param[out] has_predicate Flag to mark whether there is a predicate specified. It cannot be
988 * based on the grammar, in those cases use NULL.
989 * @param[in] extended Whether to accept an extended path (support for /[prefix:]*, //[prefix:]*, //[prefix:].).
990 *
991 * @return Number of characters successfully parsed,
992 * positive on success, negative on failure.
993 */
994 int
parse_schema_nodeid(const char * id,const char ** mod_name,int * mod_name_len,const char ** name,int * nam_len,int * is_relative,int * has_predicate,int * all_desc,int extended)995 parse_schema_nodeid(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len,
996 int *is_relative, int *has_predicate, int *all_desc, int extended)
997 {
998 int parsed = 0, ret;
999
1000 assert(id);
1001 assert(is_relative);
1002
1003 if (has_predicate) {
1004 *has_predicate = 0;
1005 }
1006
1007 if (id[0] != '/') {
1008 if (*is_relative != -1) {
1009 return -parsed;
1010 } else {
1011 *is_relative = 1;
1012 }
1013 if (!strncmp(id, "./", 2)) {
1014 parsed += 2;
1015 id += 2;
1016 }
1017 } else {
1018 if (*is_relative == -1) {
1019 *is_relative = 0;
1020 }
1021 ++parsed;
1022 ++id;
1023 }
1024
1025 if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len, all_desc, extended)) < 1) {
1026 return -parsed + ret;
1027 }
1028
1029 parsed += ret;
1030 id += ret;
1031
1032 if ((id[0] == '[') && has_predicate) {
1033 *has_predicate = 1;
1034 }
1035
1036 return parsed;
1037 }
1038
1039 /**
1040 * @brief Parse schema predicate (special format internally used).
1041 *
1042 * predicate = "[" *WSP predicate-expr *WSP "]"
1043 * predicate-expr = "." / [prefix:]identifier / positive-integer / key-with-value
1044 * key-with-value = identifier *WSP "=" *WSP
1045 * ((DQUOTE string DQUOTE) /
1046 * (SQUOTE string SQUOTE))
1047 *
1048 * @param[in] id Identifier to use.
1049 * @param[out] mod_name Points to the list key module name.
1050 * @param[out] mod_name_len Length of \p mod_name.
1051 * @param[out] name Points to the list key name.
1052 * @param[out] nam_len Length of \p name.
1053 * @param[out] value Points to the key value. If specified, key-with-value is expected.
1054 * @param[out] val_len Length of \p value.
1055 * @param[out] has_predicate Flag to mark whether there is another predicate specified.
1056 */
1057 int
parse_schema_json_predicate(const char * id,const char ** mod_name,int * mod_name_len,const char ** name,int * nam_len,const char ** value,int * val_len,int * has_predicate)1058 parse_schema_json_predicate(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len,
1059 const char **value, int *val_len, int *has_predicate)
1060 {
1061 const char *ptr;
1062 int parsed = 0, ret;
1063 char quote;
1064
1065 assert(id);
1066 if (mod_name) {
1067 *mod_name = NULL;
1068 }
1069 if (mod_name_len) {
1070 *mod_name_len = 0;
1071 }
1072 if (name) {
1073 *name = NULL;
1074 }
1075 if (nam_len) {
1076 *nam_len = 0;
1077 }
1078 if (value) {
1079 *value = NULL;
1080 }
1081 if (val_len) {
1082 *val_len = 0;
1083 }
1084 if (has_predicate) {
1085 *has_predicate = 0;
1086 }
1087
1088 if (id[0] != '[') {
1089 return -parsed;
1090 }
1091
1092 ++parsed;
1093 ++id;
1094
1095 while (isspace(id[0])) {
1096 ++parsed;
1097 ++id;
1098 }
1099
1100 /* identifier */
1101 if (id[0] == '.') {
1102 ret = 1;
1103
1104 if (name) {
1105 *name = id;
1106 }
1107 if (nam_len) {
1108 *nam_len = ret;
1109 }
1110 } else if (isdigit(id[0])) {
1111 if (id[0] == '0') {
1112 return -parsed;
1113 }
1114 ret = 1;
1115 while (isdigit(id[ret])) {
1116 ++ret;
1117 }
1118
1119 if (name) {
1120 *name = id;
1121 }
1122 if (nam_len) {
1123 *nam_len = ret;
1124 }
1125 } else if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len, NULL, 0)) < 1) {
1126 return -parsed + ret;
1127 }
1128
1129 parsed += ret;
1130 id += ret;
1131
1132 while (isspace(id[0])) {
1133 ++parsed;
1134 ++id;
1135 }
1136
1137 /* there is value as well */
1138 if (id[0] == '=') {
1139 if (name && isdigit(**name)) {
1140 return -parsed;
1141 }
1142
1143 ++parsed;
1144 ++id;
1145
1146 while (isspace(id[0])) {
1147 ++parsed;
1148 ++id;
1149 }
1150
1151 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
1152 if ((id[0] == '\"') || (id[0] == '\'')) {
1153 quote = id[0];
1154
1155 ++parsed;
1156 ++id;
1157
1158 for (ptr = id; ptr[0] && ptr[0] != quote; ++ptr) {
1159 if (ptr[0] == '\\') {
1160 ++ptr;
1161 }
1162 }
1163 if (!ptr[0]) {
1164 return -parsed;
1165 }
1166 ret = ptr - id;
1167
1168 if (value) {
1169 *value = id;
1170 }
1171 if (val_len) {
1172 *val_len = ret;
1173 }
1174
1175 parsed += ret + 1;
1176 id += ret + 1;
1177 } else {
1178 return -parsed;
1179 }
1180
1181 while (isspace(id[0])) {
1182 ++parsed;
1183 ++id;
1184 }
1185 }
1186
1187 if (id[0] != ']') {
1188 return -parsed;
1189 }
1190
1191 ++parsed;
1192 ++id;
1193
1194 if ((id[0] == '[') && has_predicate) {
1195 *has_predicate = 1;
1196 }
1197
1198 return parsed;
1199 }
1200
1201 static struct lyd_node *
resolve_json_data_node_hash(struct lyd_node * siblings,struct parsed_pred pp)1202 resolve_json_data_node_hash(struct lyd_node *siblings, struct parsed_pred pp)
1203 {
1204 struct lyd_node *ret = NULL;
1205 char *key_or_value = NULL;
1206
1207 if (pp.schema->nodetype == LYS_LEAFLIST) {
1208 assert((pp.len == 1) && (pp.pred[0].name[0] == '.') && (pp.pred[0].nam_len == 1));
1209
1210 key_or_value = strndup(pp.pred[0].value, pp.pred[0].val_len);
1211 } else if (pp.schema->nodetype == LYS_LIST) {
1212 key_or_value = strndup(pp.pred_str, pp.pred_str_len);
1213 }
1214
1215 /* try to find the node */
1216 lyd_find_sibling_val(siblings, pp.schema, key_or_value, &ret);
1217 free(key_or_value);
1218
1219 return ret;
1220 }
1221
1222 /**
1223 * @brief Resolve (find) a feature definition. Logs directly.
1224 *
1225 * @param[in] feat_name Feature name to resolve.
1226 * @param[in] len Length of \p feat_name.
1227 * @param[in] node Node with the if-feature expression.
1228 * @param[out] feature Pointer to be set to point to the feature definition, if feature not found
1229 * (return code 1), the pointer is untouched.
1230 *
1231 * @return 0 on success, 1 on forward reference, -1 on error.
1232 */
1233 static int
resolve_feature(const char * feat_name,uint16_t len,const struct lys_node * node,struct lys_feature ** feature)1234 resolve_feature(const char *feat_name, uint16_t len, const struct lys_node *node, struct lys_feature **feature)
1235 {
1236 char *str;
1237 const char *mod_name, *name;
1238 int mod_name_len, nam_len, i, j;
1239 const struct lys_module *module;
1240
1241 assert(feature);
1242
1243 /* check prefix */
1244 if ((i = parse_node_identifier(feat_name, &mod_name, &mod_name_len, &name, &nam_len, NULL, 0)) < 1) {
1245 LOGVAL(node->module->ctx, LYE_INCHAR, LY_VLOG_NONE, NULL, feat_name[-i], &feat_name[-i]);
1246 return -1;
1247 }
1248
1249 module = lyp_get_module(lys_node_module(node), NULL, 0, mod_name, mod_name_len, 0);
1250 if (!module) {
1251 /* identity refers unknown data model */
1252 LOGVAL(node->module->ctx, LYE_INMOD_LEN, LY_VLOG_NONE, NULL, mod_name_len, mod_name);
1253 return -1;
1254 }
1255
1256 if (module != node->module && module == lys_node_module(node)) {
1257 /* first, try to search directly in submodule where the feature was mentioned */
1258 for (j = 0; j < node->module->features_size; j++) {
1259 if (!strncmp(name, node->module->features[j].name, nam_len) && !node->module->features[j].name[nam_len]) {
1260 /* check status */
1261 if (lyp_check_status(node->flags, lys_node_module(node), node->name, node->module->features[j].flags,
1262 node->module->features[j].module, node->module->features[j].name, NULL)) {
1263 return -1;
1264 }
1265 *feature = &node->module->features[j];
1266 return 0;
1267 }
1268 }
1269 }
1270
1271 /* search in the identified module ... */
1272 for (j = 0; j < module->features_size; j++) {
1273 if (!strncmp(name, module->features[j].name, nam_len) && !module->features[j].name[nam_len]) {
1274 /* check status */
1275 if (lyp_check_status(node->flags, lys_node_module(node), node->name, module->features[j].flags,
1276 module->features[j].module, module->features[j].name, NULL)) {
1277 return -1;
1278 }
1279 *feature = &module->features[j];
1280 return 0;
1281 }
1282 }
1283 /* ... and all its submodules */
1284 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
1285 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
1286 if (!strncmp(name, module->inc[i].submodule->features[j].name, nam_len)
1287 && !module->inc[i].submodule->features[j].name[nam_len]) {
1288 /* check status */
1289 if (lyp_check_status(node->flags, lys_node_module(node), node->name,
1290 module->inc[i].submodule->features[j].flags,
1291 module->inc[i].submodule->features[j].module,
1292 module->inc[i].submodule->features[j].name, NULL)) {
1293 return -1;
1294 }
1295 *feature = &module->inc[i].submodule->features[j];
1296 return 0;
1297 }
1298 }
1299 }
1300
1301 /* not found */
1302 str = strndup(feat_name, len);
1303 LOGVAL(node->module->ctx, LYE_INRESOLV, LY_VLOG_NONE, NULL, "feature", str);
1304 free(str);
1305 return 1;
1306 }
1307
1308 /*
1309 * @return
1310 * - 1 if enabled
1311 * - 0 if disabled
1312 */
1313 static int
resolve_feature_value(const struct lys_feature * feat)1314 resolve_feature_value(const struct lys_feature *feat)
1315 {
1316 int i;
1317
1318 for (i = 0; i < feat->iffeature_size; i++) {
1319 if (!resolve_iffeature(&feat->iffeature[i])) {
1320 return 0;
1321 }
1322 }
1323
1324 return feat->flags & LYS_FENABLED ? 1 : 0;
1325 }
1326
1327 static int
resolve_iffeature_recursive(struct lys_iffeature * expr,int * index_e,int * index_f)1328 resolve_iffeature_recursive(struct lys_iffeature *expr, int *index_e, int *index_f)
1329 {
1330 uint8_t op;
1331 int a, b;
1332
1333 op = iff_getop(expr->expr, *index_e);
1334 (*index_e)++;
1335
1336 switch (op) {
1337 case LYS_IFF_F:
1338 /* resolve feature */
1339 return resolve_feature_value(expr->features[(*index_f)++]);
1340 case LYS_IFF_NOT:
1341 /* invert result */
1342 return resolve_iffeature_recursive(expr, index_e, index_f) ? 0 : 1;
1343 case LYS_IFF_AND:
1344 case LYS_IFF_OR:
1345 a = resolve_iffeature_recursive(expr, index_e, index_f);
1346 b = resolve_iffeature_recursive(expr, index_e, index_f);
1347 if (op == LYS_IFF_AND) {
1348 return a && b;
1349 } else { /* LYS_IFF_OR */
1350 return a || b;
1351 }
1352 }
1353
1354 return 0;
1355 }
1356
1357 int
resolve_iffeature(struct lys_iffeature * expr)1358 resolve_iffeature(struct lys_iffeature *expr)
1359 {
1360 int index_e = 0, index_f = 0;
1361
1362 if (expr->expr && expr->features[0]) {
1363 return resolve_iffeature_recursive(expr, &index_e, &index_f);
1364 }
1365 return 0;
1366 }
1367
1368 struct iff_stack {
1369 int size;
1370 int index; /* first empty item */
1371 uint8_t *stack;
1372 };
1373
1374 static int
iff_stack_push(struct iff_stack * stack,uint8_t value)1375 iff_stack_push(struct iff_stack *stack, uint8_t value)
1376 {
1377 if (stack->index == stack->size) {
1378 stack->size += 4;
1379 stack->stack = ly_realloc(stack->stack, stack->size * sizeof *stack->stack);
1380 LY_CHECK_ERR_RETURN(!stack->stack, LOGMEM(NULL); stack->size = 0, EXIT_FAILURE);
1381 }
1382
1383 stack->stack[stack->index++] = value;
1384 return EXIT_SUCCESS;
1385 }
1386
1387 static uint8_t
iff_stack_pop(struct iff_stack * stack)1388 iff_stack_pop(struct iff_stack *stack)
1389 {
1390 stack->index--;
1391 return stack->stack[stack->index];
1392 }
1393
1394 static void
iff_stack_clean(struct iff_stack * stack)1395 iff_stack_clean(struct iff_stack *stack)
1396 {
1397 stack->size = 0;
1398 free(stack->stack);
1399 }
1400
1401 static void
iff_setop(uint8_t * list,uint8_t op,int pos)1402 iff_setop(uint8_t *list, uint8_t op, int pos)
1403 {
1404 uint8_t *item;
1405 uint8_t mask = 3;
1406
1407 assert(pos >= 0);
1408 assert(op <= 3); /* max 2 bits */
1409
1410 item = &list[pos / 4];
1411 mask = mask << 2 * (pos % 4);
1412 *item = (*item) & ~mask;
1413 *item = (*item) | (op << 2 * (pos % 4));
1414 }
1415
1416 uint8_t
iff_getop(uint8_t * list,int pos)1417 iff_getop(uint8_t *list, int pos)
1418 {
1419 uint8_t *item;
1420 uint8_t mask = 3, result;
1421
1422 assert(pos >= 0);
1423
1424 item = &list[pos / 4];
1425 result = (*item) & (mask << 2 * (pos % 4));
1426 return result >> 2 * (pos % 4);
1427 }
1428
1429 #define LYS_IFF_LP 0x04 /* ( */
1430 #define LYS_IFF_RP 0x08 /* ) */
1431
1432 /* internal structure for passing data for UNRES_IFFEAT */
1433 struct unres_iffeat_data {
1434 struct lys_node *node;
1435 const char *fname;
1436 int infeature;
1437 };
1438
1439 void
resolve_iffeature_getsizes(struct lys_iffeature * iffeat,unsigned int * expr_size,unsigned int * feat_size)1440 resolve_iffeature_getsizes(struct lys_iffeature *iffeat, unsigned int *expr_size, unsigned int *feat_size)
1441 {
1442 unsigned int e = 0, f = 0, r = 0;
1443 uint8_t op;
1444
1445 assert(iffeat);
1446
1447 if (!iffeat->expr) {
1448 goto result;
1449 }
1450
1451 do {
1452 op = iff_getop(iffeat->expr, e++);
1453 switch (op) {
1454 case LYS_IFF_NOT:
1455 if (!r) {
1456 r += 1;
1457 }
1458 break;
1459 case LYS_IFF_AND:
1460 case LYS_IFF_OR:
1461 if (!r) {
1462 r += 2;
1463 } else {
1464 r += 1;
1465 }
1466 break;
1467 case LYS_IFF_F:
1468 f++;
1469 if (r) {
1470 r--;
1471 }
1472 break;
1473 }
1474 } while(r);
1475
1476 result:
1477 if (expr_size) {
1478 *expr_size = e;
1479 }
1480 if (feat_size) {
1481 *feat_size = f;
1482 }
1483 }
1484
1485 int
resolve_iffeature_compile(struct lys_iffeature * iffeat_expr,const char * value,struct lys_node * node,int infeature,struct unres_schema * unres)1486 resolve_iffeature_compile(struct lys_iffeature *iffeat_expr, const char *value, struct lys_node *node,
1487 int infeature, struct unres_schema *unres)
1488 {
1489 const char *c = value;
1490 int r, rc = EXIT_FAILURE;
1491 int i, j, last_not, checkversion = 0;
1492 unsigned int f_size = 0, expr_size = 0, f_exp = 1;
1493 uint8_t op;
1494 struct iff_stack stack = {0, 0, NULL};
1495 struct unres_iffeat_data *iff_data;
1496 struct ly_ctx *ctx = node->module->ctx;
1497
1498 assert(c);
1499
1500 if (isspace(c[0])) {
1501 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_NONE, NULL, c[0], c);
1502 return EXIT_FAILURE;
1503 }
1504
1505 /* pre-parse the expression to get sizes for arrays, also do some syntax checks of the expression */
1506 for (i = j = last_not = 0; c[i]; i++) {
1507 if (c[i] == '(') {
1508 checkversion = 1;
1509 j++;
1510 continue;
1511 } else if (c[i] == ')') {
1512 j--;
1513 continue;
1514 } else if (isspace(c[i])) {
1515 continue;
1516 }
1517
1518 if (!strncmp(&c[i], "not", r = 3) || !strncmp(&c[i], "and", r = 3) || !strncmp(&c[i], "or", r = 2)) {
1519 if (c[i + r] == '\0') {
1520 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1521 return EXIT_FAILURE;
1522 } else if (!isspace(c[i + r])) {
1523 /* feature name starting with the not/and/or */
1524 last_not = 0;
1525 f_size++;
1526 } else if (c[i] == 'n') { /* not operation */
1527 if (last_not) {
1528 /* double not */
1529 expr_size = expr_size - 2;
1530 last_not = 0;
1531 } else {
1532 last_not = 1;
1533 }
1534 } else { /* and, or */
1535 f_exp++;
1536 /* not a not operation */
1537 last_not = 0;
1538 }
1539 i += r;
1540 } else {
1541 f_size++;
1542 last_not = 0;
1543 }
1544 expr_size++;
1545
1546 while (!isspace(c[i])) {
1547 if (c[i] == '(') {
1548 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1549 return EXIT_FAILURE;
1550 } else if (!c[i] || c[i] == ')') {
1551 i--;
1552 break;
1553 }
1554 i++;
1555 }
1556 }
1557 if (j || f_exp != f_size) {
1558 /* not matching count of ( and ) */
1559 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1560 return EXIT_FAILURE;
1561 }
1562
1563 if (checkversion || expr_size > 1) {
1564 /* check that we have 1.1 module */
1565 if (node->module->version != LYS_VERSION_1_1) {
1566 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1567 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "YANG 1.1 if-feature expression found in 1.0 module.");
1568 return EXIT_FAILURE;
1569 }
1570 }
1571
1572 /* allocate the memory */
1573 iffeat_expr->expr = calloc((j = (expr_size / 4) + ((expr_size % 4) ? 1 : 0)), sizeof *iffeat_expr->expr);
1574 iffeat_expr->features = calloc(f_size, sizeof *iffeat_expr->features);
1575 stack.stack = malloc(expr_size * sizeof *stack.stack);
1576 LY_CHECK_ERR_GOTO(!stack.stack || !iffeat_expr->expr || !iffeat_expr->features, LOGMEM(ctx), error);
1577 stack.size = expr_size;
1578 f_size--; expr_size--; /* used as indexes from now */
1579
1580 for (i--; i >= 0; i--) {
1581 if (c[i] == ')') {
1582 /* push it on stack */
1583 iff_stack_push(&stack, LYS_IFF_RP);
1584 continue;
1585 } else if (c[i] == '(') {
1586 /* pop from the stack into result all operators until ) */
1587 while((op = iff_stack_pop(&stack)) != LYS_IFF_RP) {
1588 iff_setop(iffeat_expr->expr, op, expr_size--);
1589 }
1590 continue;
1591 } else if (isspace(c[i])) {
1592 continue;
1593 }
1594
1595 /* end operator or operand -> find beginning and get what is it */
1596 j = i + 1;
1597 while (i >= 0 && !isspace(c[i]) && c[i] != '(') {
1598 i--;
1599 }
1600 i++; /* get back by one step */
1601
1602 if (!strncmp(&c[i], "not", 3) && isspace(c[i + 3])) {
1603 if (stack.index && stack.stack[stack.index - 1] == LYS_IFF_NOT) {
1604 /* double not */
1605 iff_stack_pop(&stack);
1606 } else {
1607 /* not has the highest priority, so do not pop from the stack
1608 * as in case of AND and OR */
1609 iff_stack_push(&stack, LYS_IFF_NOT);
1610 }
1611 } else if (!strncmp(&c[i], "and", 3) && isspace(c[i + 3])) {
1612 /* as for OR - pop from the stack all operators with the same or higher
1613 * priority and store them to the result, then push the AND to the stack */
1614 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_AND) {
1615 op = iff_stack_pop(&stack);
1616 iff_setop(iffeat_expr->expr, op, expr_size--);
1617 }
1618 iff_stack_push(&stack, LYS_IFF_AND);
1619 } else if (!strncmp(&c[i], "or", 2) && isspace(c[i + 2])) {
1620 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_OR) {
1621 op = iff_stack_pop(&stack);
1622 iff_setop(iffeat_expr->expr, op, expr_size--);
1623 }
1624 iff_stack_push(&stack, LYS_IFF_OR);
1625 } else {
1626 /* feature name, length is j - i */
1627
1628 /* add it to the result */
1629 iff_setop(iffeat_expr->expr, LYS_IFF_F, expr_size--);
1630
1631 /* now get the link to the feature definition. Since it can be
1632 * forward referenced, we have to keep the feature name in auxiliary
1633 * structure passed into unres */
1634 iff_data = malloc(sizeof *iff_data);
1635 LY_CHECK_ERR_GOTO(!iff_data, LOGMEM(ctx), error);
1636 iff_data->node = node;
1637 iff_data->fname = lydict_insert(node->module->ctx, &c[i], j - i);
1638 iff_data->infeature = infeature;
1639 r = unres_schema_add_node(node->module, unres, &iffeat_expr->features[f_size], UNRES_IFFEAT,
1640 (struct lys_node *)iff_data);
1641 f_size--;
1642
1643 if (r == -1) {
1644 lydict_remove(node->module->ctx, iff_data->fname);
1645 free(iff_data);
1646 goto error;
1647 }
1648 }
1649 }
1650 while (stack.index) {
1651 op = iff_stack_pop(&stack);
1652 iff_setop(iffeat_expr->expr, op, expr_size--);
1653 }
1654
1655 if (++expr_size || ++f_size) {
1656 /* not all expected operators and operands found */
1657 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1658 rc = EXIT_FAILURE;
1659 } else {
1660 rc = EXIT_SUCCESS;
1661 }
1662
1663 error:
1664 /* cleanup */
1665 iff_stack_clean(&stack);
1666
1667 return rc;
1668 }
1669
1670 /**
1671 * @brief Resolve (find) a data node based on a schema-nodeid.
1672 *
1673 * Used for resolving unique statements - so id is expected to be relative and local (without reference to a different
1674 * module).
1675 *
1676 */
1677 struct lyd_node *
resolve_data_descendant_schema_nodeid(const char * nodeid,struct lyd_node * start)1678 resolve_data_descendant_schema_nodeid(const char *nodeid, struct lyd_node *start)
1679 {
1680 char *str, *token, *p;
1681 struct lyd_node *result = NULL, *iter;
1682 const struct lys_node *schema = NULL;
1683
1684 assert(nodeid && start);
1685
1686 if (nodeid[0] == '/') {
1687 return NULL;
1688 }
1689
1690 str = p = strdup(nodeid);
1691 LY_CHECK_ERR_RETURN(!str, LOGMEM(start->schema->module->ctx), NULL);
1692
1693 while (p) {
1694 token = p;
1695 p = strchr(p, '/');
1696 if (p) {
1697 *p = '\0';
1698 p++;
1699 }
1700
1701 if (p) {
1702 /* inner node */
1703 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema,
1704 LYS_CONTAINER | LYS_CHOICE | LYS_CASE | LYS_LEAF, 0, &schema)
1705 || !schema) {
1706 result = NULL;
1707 break;
1708 }
1709
1710 if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
1711 continue;
1712 }
1713 } else {
1714 /* final node */
1715 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema, LYS_LEAF, 0, &schema)
1716 || !schema) {
1717 result = NULL;
1718 break;
1719 }
1720 }
1721 LY_TREE_FOR(result ? result->child : start, iter) {
1722 if (iter->schema == schema) {
1723 /* move in data tree according to returned schema */
1724 result = iter;
1725 break;
1726 }
1727 }
1728 if (!iter) {
1729 /* instance not found */
1730 result = NULL;
1731 break;
1732 }
1733 }
1734 free(str);
1735
1736 return result;
1737 }
1738
1739 int
schema_nodeid_siblingcheck(const struct lys_node * sibling,const struct lys_module * cur_module,const char * mod_name,int mod_name_len,const char * name,int nam_len)1740 schema_nodeid_siblingcheck(const struct lys_node *sibling, const struct lys_module *cur_module, const char *mod_name,
1741 int mod_name_len, const char *name, int nam_len)
1742 {
1743 const struct lys_module *prefix_mod;
1744
1745 /* handle special names */
1746 if (name[0] == '*') {
1747 return 2;
1748 } else if (name[0] == '.') {
1749 return 3;
1750 }
1751
1752 /* name check */
1753 if (strncmp(name, sibling->name, nam_len) || sibling->name[nam_len]) {
1754 return 1;
1755 }
1756
1757 /* module check */
1758 if (mod_name) {
1759 prefix_mod = lyp_get_module(cur_module, NULL, 0, mod_name, mod_name_len, 0);
1760 if (!prefix_mod) {
1761 return -1;
1762 }
1763 } else {
1764 prefix_mod = cur_module;
1765 }
1766 if (prefix_mod != lys_node_module(sibling)) {
1767 return 1;
1768 }
1769
1770 /* match */
1771 return 0;
1772 }
1773
1774 /* keys do not have to be ordered and do not have to be all of them */
1775 static int
resolve_extended_schema_nodeid_predicate(const char * nodeid,const struct lys_node * node,const struct lys_module * cur_module,int * nodeid_end)1776 resolve_extended_schema_nodeid_predicate(const char *nodeid, const struct lys_node *node,
1777 const struct lys_module *cur_module, int *nodeid_end)
1778 {
1779 int mod_len, nam_len, has_predicate, r, i;
1780 const char *model, *name;
1781 struct lys_node_list *list;
1782
1783 if (!(node->nodetype & (LYS_LIST | LYS_LEAFLIST))) {
1784 return 1;
1785 }
1786
1787 list = (struct lys_node_list *)node;
1788 do {
1789 r = parse_schema_json_predicate(nodeid, &model, &mod_len, &name, &nam_len, NULL, NULL, &has_predicate);
1790 if (r < 1) {
1791 LOGVAL(cur_module->ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, nodeid[r], &nodeid[r]);
1792 return -1;
1793 }
1794 nodeid += r;
1795
1796 if (node->nodetype == LYS_LEAFLIST) {
1797 /* just check syntax */
1798 if (model || !name || (name[0] != '.') || has_predicate) {
1799 return 1;
1800 }
1801 break;
1802 } else {
1803 /* check the key */
1804 for (i = 0; i < list->keys_size; ++i) {
1805 if (strncmp(list->keys[i]->name, name, nam_len) || list->keys[i]->name[nam_len]) {
1806 continue;
1807 }
1808 if (model) {
1809 if (strncmp(lys_node_module((struct lys_node *)list->keys[i])->name, model, mod_len)
1810 || lys_node_module((struct lys_node *)list->keys[i])->name[mod_len]) {
1811 continue;
1812 }
1813 } else {
1814 if (lys_node_module((struct lys_node *)list->keys[i]) != cur_module) {
1815 continue;
1816 }
1817 }
1818
1819 /* match */
1820 break;
1821 }
1822
1823 if (i == list->keys_size) {
1824 return 1;
1825 }
1826 }
1827 } while (has_predicate);
1828
1829 if (!nodeid[0]) {
1830 *nodeid_end = 1;
1831 }
1832 return 0;
1833 }
1834
1835 /* start_parent - relative, module - absolute, -1 error (logged), EXIT_SUCCESS ok
1836 */
1837 int
resolve_schema_nodeid(const char * nodeid,const struct lys_node * start_parent,const struct lys_module * cur_module,struct ly_set ** ret,int extended,int no_node_error)1838 resolve_schema_nodeid(const char *nodeid, const struct lys_node *start_parent, const struct lys_module *cur_module,
1839 struct ly_set **ret, int extended, int no_node_error)
1840 {
1841 const char *name, *mod_name, *id, *backup_mod_name = NULL, *yang_data_name = NULL;
1842 const struct lys_node *sibling, *next, *elem;
1843 struct lys_node_augment *last_aug;
1844 int r, nam_len, mod_name_len = 0, is_relative = -1, all_desc, has_predicate, nodeid_end = 0;
1845 int yang_data_name_len, backup_mod_name_len = 0;
1846 /* resolved import module from the start module, it must match the next node-name-match sibling */
1847 const struct lys_module *start_mod, *aux_mod = NULL;
1848 char *str;
1849 struct ly_ctx *ctx;
1850
1851 assert(nodeid && (start_parent || cur_module) && ret);
1852 *ret = NULL;
1853
1854 if (!cur_module) {
1855 cur_module = lys_node_module(start_parent);
1856 }
1857 ctx = cur_module->ctx;
1858 id = nodeid;
1859
1860 r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL, NULL, 1);
1861 if (r < 1) {
1862 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
1863 return -1;
1864 }
1865
1866 if (name[0] == '#') {
1867 if (is_relative) {
1868 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, '#', name);
1869 return -1;
1870 }
1871 yang_data_name = name + 1;
1872 yang_data_name_len = nam_len - 1;
1873 backup_mod_name = mod_name;
1874 backup_mod_name_len = mod_name_len;
1875 id += r;
1876 } else {
1877 is_relative = -1;
1878 }
1879
1880 r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate,
1881 (extended ? &all_desc : NULL), extended);
1882 if (r < 1) {
1883 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
1884 return -1;
1885 }
1886 id += r;
1887
1888 if (backup_mod_name) {
1889 mod_name = backup_mod_name;
1890 mod_name_len = backup_mod_name_len;
1891 }
1892
1893 if (is_relative && !start_parent) {
1894 LOGVAL(ctx, LYE_SPEC, LY_VLOG_STR, nodeid, "Starting node must be provided for relative paths.");
1895 return -1;
1896 }
1897
1898 /* descendant-schema-nodeid */
1899 if (is_relative) {
1900 cur_module = start_mod = lys_node_module(start_parent);
1901
1902 /* absolute-schema-nodeid */
1903 } else {
1904 start_mod = lyp_get_module(cur_module, NULL, 0, mod_name, mod_name_len, 0);
1905 if (!start_mod) {
1906 str = strndup(mod_name, mod_name_len);
1907 LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str);
1908 free(str);
1909 return -1;
1910 }
1911 start_parent = NULL;
1912 if (yang_data_name) {
1913 start_parent = lyp_get_yang_data_template(start_mod, yang_data_name, yang_data_name_len);
1914 if (!start_parent) {
1915 str = strndup(nodeid, (yang_data_name + yang_data_name_len) - nodeid);
1916 LOGVAL(ctx, LYE_PATH_INNODE, LY_VLOG_STR, str);
1917 free(str);
1918 return -1;
1919 }
1920 }
1921 }
1922
1923 while (1) {
1924 sibling = NULL;
1925 last_aug = NULL;
1926
1927 if (start_parent) {
1928 if (mod_name && (strncmp(mod_name, cur_module->name, mod_name_len)
1929 || (mod_name_len != (signed)strlen(cur_module->name)))) {
1930 /* we are getting into another module (augment) */
1931 aux_mod = lyp_get_module(cur_module, NULL, 0, mod_name, mod_name_len, 0);
1932 if (!aux_mod) {
1933 str = strndup(mod_name, mod_name_len);
1934 LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str);
1935 free(str);
1936 return -1;
1937 }
1938 } else {
1939 /* there is no mod_name, so why are we checking augments again?
1940 * because this module may be not implemented and it augments something in another module and
1941 * there is another augment augmenting that previous one */
1942 aux_mod = cur_module;
1943 }
1944
1945 /* look into augments */
1946 if (!extended) {
1947 get_next_augment:
1948 last_aug = lys_getnext_target_aug(last_aug, aux_mod, start_parent);
1949 }
1950 }
1951
1952 while ((sibling = lys_getnext(sibling, (last_aug ? (struct lys_node *)last_aug : start_parent), start_mod,
1953 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_PARENTUSES | LYS_GETNEXT_NOSTATECHECK))) {
1954 r = schema_nodeid_siblingcheck(sibling, cur_module, mod_name, mod_name_len, name, nam_len);
1955
1956 /* resolve predicate */
1957 if (extended && ((r == 0) || (r == 2) || (r == 3)) && has_predicate) {
1958 r = resolve_extended_schema_nodeid_predicate(id, sibling, cur_module, &nodeid_end);
1959 if (r == 1) {
1960 continue;
1961 } else if (r == -1) {
1962 return -1;
1963 }
1964 } else if (!id[0]) {
1965 nodeid_end = 1;
1966 }
1967
1968 if (r == 0) {
1969 /* one matching result */
1970 if (nodeid_end) {
1971 *ret = ly_set_new();
1972 LY_CHECK_ERR_RETURN(!*ret, LOGMEM(ctx), -1);
1973 ly_set_add(*ret, (void *)sibling, LY_SET_OPT_USEASLIST);
1974 } else {
1975 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
1976 return -1;
1977 }
1978 start_parent = sibling;
1979 }
1980 break;
1981 } else if (r == 1) {
1982 continue;
1983 } else if (r == 2) {
1984 /* "*" */
1985 if (!*ret) {
1986 *ret = ly_set_new();
1987 LY_CHECK_ERR_RETURN(!*ret, LOGMEM(ctx), -1);
1988 }
1989 ly_set_add(*ret, (void *)sibling, LY_SET_OPT_USEASLIST);
1990 if (all_desc) {
1991 LY_TREE_DFS_BEGIN(sibling, next, elem) {
1992 if (elem != sibling) {
1993 ly_set_add(*ret, (void *)elem, LY_SET_OPT_USEASLIST);
1994 }
1995
1996 LY_TREE_DFS_END(sibling, next, elem);
1997 }
1998 }
1999 } else if (r == 3) {
2000 /* "." */
2001 if (!*ret) {
2002 *ret = ly_set_new();
2003 LY_CHECK_ERR_RETURN(!*ret, LOGMEM(ctx), -1);
2004 if (start_parent) {
2005 ly_set_add(*ret, (void *)start_parent, LY_SET_OPT_USEASLIST);
2006 }
2007 }
2008 ly_set_add(*ret, (void *)sibling, LY_SET_OPT_USEASLIST);
2009 if (all_desc) {
2010 LY_TREE_DFS_BEGIN(sibling, next, elem) {
2011 if (elem != sibling) {
2012 ly_set_add(*ret, (void *)elem, LY_SET_OPT_USEASLIST);
2013 }
2014
2015 LY_TREE_DFS_END(sibling, next, elem);
2016 }
2017 }
2018 } else {
2019 LOGINT(ctx);
2020 return -1;
2021 }
2022 }
2023
2024 /* skip predicate */
2025 if (extended && has_predicate) {
2026 while (id[0] == '[') {
2027 id = strchr(id, ']');
2028 if (!id) {
2029 LOGINT(ctx);
2030 return -1;
2031 }
2032 ++id;
2033 }
2034 }
2035
2036 if (nodeid_end && ((r == 0) || (r == 2) || (r == 3))) {
2037 return EXIT_SUCCESS;
2038 }
2039
2040 /* no match */
2041 if (!sibling) {
2042 if (last_aug) {
2043 /* it still could be in another augment */
2044 goto get_next_augment;
2045 }
2046 if (no_node_error) {
2047 str = strndup(nodeid, (name - nodeid) + nam_len);
2048 LOGVAL(ctx, LYE_PATH_INNODE, LY_VLOG_STR, str);
2049 free(str);
2050 return -1;
2051 }
2052 *ret = NULL;
2053 return EXIT_SUCCESS;
2054 }
2055
2056 r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate,
2057 (extended ? &all_desc : NULL), extended);
2058 if (r < 1) {
2059 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2060 return -1;
2061 }
2062 id += r;
2063 }
2064
2065 /* cannot get here */
2066 LOGINT(ctx);
2067 return -1;
2068 }
2069
2070 /* unique, refine,
2071 * >0 - unexpected char on position (ret - 1),
2072 * 0 - ok (but ret can still be NULL),
2073 * -1 - error,
2074 * -2 - violated no_innerlist */
2075 int
resolve_descendant_schema_nodeid(const char * nodeid,const struct lys_node * start,int ret_nodetype,int no_innerlist,const struct lys_node ** ret)2076 resolve_descendant_schema_nodeid(const char *nodeid, const struct lys_node *start, int ret_nodetype,
2077 int no_innerlist, const struct lys_node **ret)
2078 {
2079 const char *name, *mod_name, *id;
2080 const struct lys_node *sibling, *start_parent;
2081 int r, nam_len, mod_name_len, is_relative = -1;
2082 /* resolved import module from the start module, it must match the next node-name-match sibling */
2083 const struct lys_module *module;
2084
2085 assert(nodeid && ret);
2086 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT | LYS_GROUPING)));
2087
2088 if (!start) {
2089 /* leaf not found */
2090 return 0;
2091 }
2092
2093 id = nodeid;
2094 module = lys_node_module(start);
2095
2096 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL, NULL, 0)) < 1) {
2097 return ((id - nodeid) - r) + 1;
2098 }
2099 id += r;
2100
2101 if (!is_relative) {
2102 return -1;
2103 }
2104
2105 start_parent = lys_parent(start);
2106 while ((start_parent->nodetype == LYS_USES) && lys_parent(start_parent)) {
2107 start_parent = lys_parent(start_parent);
2108 }
2109
2110 while (1) {
2111 sibling = NULL;
2112 while ((sibling = lys_getnext(sibling, start_parent, module,
2113 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_PARENTUSES
2114 | LYS_GETNEXT_NOSTATECHECK))) {
2115 r = schema_nodeid_siblingcheck(sibling, module, mod_name, mod_name_len, name, nam_len);
2116 if (r == 0) {
2117 if (!id[0]) {
2118 if (!(sibling->nodetype & ret_nodetype)) {
2119 /* wrong node type, too bad */
2120 continue;
2121 }
2122 *ret = sibling;
2123 return EXIT_SUCCESS;
2124 }
2125 start_parent = sibling;
2126 break;
2127 } else if (r == 1) {
2128 continue;
2129 } else {
2130 return -1;
2131 }
2132 }
2133
2134 /* no match */
2135 if (!sibling) {
2136 *ret = NULL;
2137 return EXIT_SUCCESS;
2138 } else if (no_innerlist && sibling->nodetype == LYS_LIST) {
2139 *ret = NULL;
2140 return -2;
2141 }
2142
2143 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL, NULL, 0)) < 1) {
2144 return ((id - nodeid) - r) + 1;
2145 }
2146 id += r;
2147 }
2148
2149 /* cannot get here */
2150 LOGINT(module->ctx);
2151 return -1;
2152 }
2153
2154 /* choice default */
2155 int
resolve_choice_default_schema_nodeid(const char * nodeid,const struct lys_node * start,const struct lys_node ** ret)2156 resolve_choice_default_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node **ret)
2157 {
2158 /* cannot actually be a path */
2159 if (strchr(nodeid, '/')) {
2160 return -1;
2161 }
2162
2163 return resolve_descendant_schema_nodeid(nodeid, start, LYS_NO_RPC_NOTIF_NODE, 0, ret);
2164 }
2165
2166 /* uses, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
2167 static int
resolve_uses_schema_nodeid(const char * nodeid,const struct lys_node * start,const struct lys_node_grp ** ret)2168 resolve_uses_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node_grp **ret)
2169 {
2170 const struct lys_module *module;
2171 const char *mod_prefix, *name;
2172 int i, mod_prefix_len, nam_len;
2173
2174 /* parse the identifier, it must be parsed on one call */
2175 if (((i = parse_node_identifier(nodeid, &mod_prefix, &mod_prefix_len, &name, &nam_len, NULL, 0)) < 1) || nodeid[i]) {
2176 return -i + 1;
2177 }
2178
2179 module = lyp_get_module(start->module, mod_prefix, mod_prefix_len, NULL, 0, 0);
2180 if (!module) {
2181 return -1;
2182 }
2183 if (module != lys_main_module(start->module)) {
2184 start = module->data;
2185 }
2186
2187 *ret = lys_find_grouping_up(name, (struct lys_node *)start);
2188
2189 return EXIT_SUCCESS;
2190 }
2191
2192 int
resolve_absolute_schema_nodeid(const char * nodeid,const struct lys_module * module,int ret_nodetype,const struct lys_node ** ret)2193 resolve_absolute_schema_nodeid(const char *nodeid, const struct lys_module *module, int ret_nodetype,
2194 const struct lys_node **ret)
2195 {
2196 const char *name, *mod_name, *id;
2197 const struct lys_node *sibling, *start_parent;
2198 int r, nam_len, mod_name_len, is_relative = -1;
2199 const struct lys_module *abs_start_mod;
2200
2201 assert(nodeid && module && ret);
2202 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
2203
2204 id = nodeid;
2205 start_parent = NULL;
2206
2207 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL, NULL, 0)) < 1) {
2208 return ((id - nodeid) - r) + 1;
2209 }
2210 id += r;
2211
2212 if (is_relative) {
2213 return -1;
2214 }
2215
2216 abs_start_mod = lyp_get_module(module, NULL, 0, mod_name, mod_name_len, 0);
2217 if (!abs_start_mod) {
2218 return -1;
2219 }
2220
2221 while (1) {
2222 sibling = NULL;
2223 while ((sibling = lys_getnext(sibling, start_parent, abs_start_mod, LYS_GETNEXT_WITHCHOICE
2224 | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_WITHGROUPING | LYS_GETNEXT_NOSTATECHECK))) {
2225 r = schema_nodeid_siblingcheck(sibling, module, mod_name, mod_name_len, name, nam_len);
2226 if (r == 0) {
2227 if (!id[0]) {
2228 if (!(sibling->nodetype & ret_nodetype)) {
2229 /* wrong node type, too bad */
2230 continue;
2231 }
2232 *ret = sibling;
2233 return EXIT_SUCCESS;
2234 }
2235 start_parent = sibling;
2236 break;
2237 } else if (r == 1) {
2238 continue;
2239 } else {
2240 return -1;
2241 }
2242 }
2243
2244 /* no match */
2245 if (!sibling) {
2246 *ret = NULL;
2247 return EXIT_SUCCESS;
2248 }
2249
2250 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL, NULL, 0)) < 1) {
2251 return ((id - nodeid) - r) + 1;
2252 }
2253 id += r;
2254 }
2255
2256 /* cannot get here */
2257 LOGINT(module->ctx);
2258 return -1;
2259 }
2260
2261 static int
resolve_json_schema_list_predicate(const char * predicate,const struct lys_node_list * list,int * parsed)2262 resolve_json_schema_list_predicate(const char *predicate, const struct lys_node_list *list, int *parsed)
2263 {
2264 const char *mod_name, *name;
2265 int mod_name_len, nam_len, has_predicate, i;
2266 struct lys_node *key;
2267
2268 if (((i = parse_schema_json_predicate(predicate, &mod_name, &mod_name_len, &name, &nam_len, NULL, NULL, &has_predicate)) < 1)
2269 || !strncmp(name, ".", nam_len)) {
2270 LOGVAL(list->module->ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-i], &predicate[-i]);
2271 return -1;
2272 }
2273
2274 predicate += i;
2275 *parsed += i;
2276
2277 if (!isdigit(name[0])) {
2278 for (i = 0; i < list->keys_size; ++i) {
2279 key = (struct lys_node *)list->keys[i];
2280 if (!strncmp(key->name, name, nam_len) && !key->name[nam_len]) {
2281 break;
2282 }
2283 }
2284
2285 if (i == list->keys_size) {
2286 LOGVAL(list->module->ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
2287 return -1;
2288 }
2289 }
2290
2291 /* more predicates? */
2292 if (has_predicate) {
2293 return resolve_json_schema_list_predicate(predicate, list, parsed);
2294 }
2295
2296 return 0;
2297 }
2298
2299 /* cannot return LYS_GROUPING, LYS_AUGMENT, LYS_USES, logs directly */
2300 const struct lys_node *
resolve_json_nodeid(const char * nodeid,const struct ly_ctx * ctx,const struct lys_node * start,int output)2301 resolve_json_nodeid(const char *nodeid, const struct ly_ctx *ctx, const struct lys_node *start, int output)
2302 {
2303 char *str;
2304 const char *name, *mod_name, *id, *backup_mod_name = NULL, *yang_data_name = NULL;
2305 const struct lys_node *sibling, *start_parent, *parent;
2306 int r, nam_len, mod_name_len, is_relative = -1, has_predicate;
2307 int yang_data_name_len, backup_mod_name_len;
2308 /* resolved import module from the start module, it must match the next node-name-match sibling */
2309 const struct lys_module *prefix_mod, *module, *prev_mod;
2310
2311 assert(nodeid && (ctx || start));
2312 if (!ctx) {
2313 ctx = start->module->ctx;
2314 }
2315
2316 id = nodeid;
2317
2318 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL, NULL, 1)) < 1) {
2319 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2320 return NULL;
2321 }
2322
2323 if (name[0] == '#') {
2324 if (is_relative) {
2325 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, '#', name);
2326 return NULL;
2327 }
2328 yang_data_name = name + 1;
2329 yang_data_name_len = nam_len - 1;
2330 backup_mod_name = mod_name;
2331 backup_mod_name_len = mod_name_len;
2332 id += r;
2333 } else {
2334 is_relative = -1;
2335 }
2336
2337 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate, NULL, 0)) < 1) {
2338 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2339 return NULL;
2340 }
2341 id += r;
2342
2343 if (backup_mod_name) {
2344 mod_name = backup_mod_name;
2345 mod_name_len = backup_mod_name_len;
2346 }
2347
2348 if (is_relative) {
2349 assert(start);
2350 start_parent = start;
2351 while (start_parent && (start_parent->nodetype == LYS_USES)) {
2352 start_parent = lys_parent(start_parent);
2353 }
2354 module = start->module;
2355 } else {
2356 if (!mod_name) {
2357 str = strndup(nodeid, (name + nam_len) - nodeid);
2358 LOGVAL(ctx, LYE_PATH_MISSMOD, LY_VLOG_STR, str);
2359 free(str);
2360 return NULL;
2361 }
2362
2363 str = strndup(mod_name, mod_name_len);
2364 module = ly_ctx_get_module(ctx, str, NULL, 1);
2365 free(str);
2366
2367 if (!module) {
2368 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2369 LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str);
2370 free(str);
2371 return NULL;
2372 }
2373 start_parent = NULL;
2374 if (yang_data_name) {
2375 start_parent = lyp_get_yang_data_template(module, yang_data_name, yang_data_name_len);
2376 if (!start_parent) {
2377 str = strndup(nodeid, (yang_data_name + yang_data_name_len) - nodeid);
2378 LOGVAL(ctx, LYE_PATH_INNODE, LY_VLOG_STR, str);
2379 free(str);
2380 return NULL;
2381 }
2382 }
2383
2384 /* now it's as if there was no module name */
2385 mod_name = NULL;
2386 mod_name_len = 0;
2387 }
2388
2389 prev_mod = module;
2390
2391 while (1) {
2392 sibling = NULL;
2393 while ((sibling = lys_getnext(sibling, start_parent, module, 0))) {
2394 /* name match */
2395 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
2396 /* output check */
2397 for (parent = lys_parent(sibling); parent && !(parent->nodetype & (LYS_INPUT | LYS_OUTPUT)); parent = lys_parent(parent));
2398 if (parent) {
2399 if (output && (parent->nodetype == LYS_INPUT)) {
2400 continue;
2401 } else if (!output && (parent->nodetype == LYS_OUTPUT)) {
2402 continue;
2403 }
2404 }
2405
2406 /* module check */
2407 if (mod_name) {
2408 /* will also find an augment module */
2409 prefix_mod = ly_ctx_nget_module(ctx, mod_name, mod_name_len, NULL, 1);
2410
2411 if (!prefix_mod) {
2412 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2413 LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str);
2414 free(str);
2415 return NULL;
2416 }
2417 } else {
2418 prefix_mod = prev_mod;
2419 }
2420 if (prefix_mod != lys_node_module(sibling)) {
2421 continue;
2422 }
2423
2424 /* do we have some predicates on it? */
2425 if (has_predicate) {
2426 r = 0;
2427 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
2428 if ((r = parse_schema_json_predicate(id, NULL, NULL, NULL, NULL, NULL, NULL, &has_predicate)) < 1) {
2429 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2430 return NULL;
2431 }
2432 } else if (sibling->nodetype == LYS_LIST) {
2433 if (resolve_json_schema_list_predicate(id, (const struct lys_node_list *)sibling, &r)) {
2434 return NULL;
2435 }
2436 } else {
2437 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2438 return NULL;
2439 }
2440 id += r;
2441 }
2442
2443 /* the result node? */
2444 if (!id[0]) {
2445 return sibling;
2446 }
2447
2448 /* move down the tree, if possible */
2449 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
2450 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2451 return NULL;
2452 }
2453 start_parent = sibling;
2454
2455 /* update prev mod */
2456 prev_mod = (start_parent->child ? lys_node_module(start_parent->child) : module);
2457 break;
2458 }
2459 }
2460
2461 /* no match */
2462 if (!sibling) {
2463 str = strndup(nodeid, (name + nam_len) - nodeid);
2464 LOGVAL(ctx, LYE_PATH_INNODE, LY_VLOG_STR, str);
2465 free(str);
2466 return NULL;
2467 }
2468
2469 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate, NULL, 0)) < 1) {
2470 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2471 return NULL;
2472 }
2473 id += r;
2474 }
2475
2476 /* cannot get here */
2477 LOGINT(ctx);
2478 return NULL;
2479 }
2480
2481 static int
resolve_partial_json_data_list_predicate(struct parsed_pred pp,struct lyd_node * node,int position)2482 resolve_partial_json_data_list_predicate(struct parsed_pred pp, struct lyd_node *node, int position)
2483 {
2484 uint16_t i;
2485 char *val_str;
2486 struct lyd_node_leaf_list *key;
2487 struct lys_node_list *slist;
2488 struct ly_ctx *ctx;
2489
2490 assert(node);
2491 assert(node->schema->nodetype == LYS_LIST);
2492 assert(pp.len);
2493
2494 ctx = node->schema->module->ctx;
2495 slist = (struct lys_node_list *)node->schema;
2496
2497 /* is the predicate a number? */
2498 if (isdigit(pp.pred[0].name[0])) {
2499 if (position == atoi(pp.pred[0].name)) {
2500 /* match */
2501 return 0;
2502 } else {
2503 /* not a match */
2504 return 1;
2505 }
2506 }
2507
2508 key = (struct lyd_node_leaf_list *)node->child;
2509 if (!key) {
2510 /* it is not a position, so we need a key for it to be a match */
2511 return 1;
2512 }
2513
2514 /* go through all the keys */
2515 for (i = 0; i < slist->keys_size; ++i) {
2516 if (strncmp(key->schema->name, pp.pred[i].name, pp.pred[i].nam_len) || key->schema->name[pp.pred[i].nam_len]) {
2517 LOGVAL(ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, pp.pred[i].name);
2518 return -1;
2519 }
2520
2521 if (pp.pred[i].mod_name) {
2522 /* specific module, check that the found key is from that module */
2523 if (strncmp(lyd_node_module((struct lyd_node *)key)->name, pp.pred[i].mod_name, pp.pred[i].mod_name_len)
2524 || lyd_node_module((struct lyd_node *)key)->name[pp.pred[i].mod_name_len]) {
2525 LOGVAL(ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, pp.pred[i].name);
2526 return -1;
2527 }
2528
2529 /* but if the module is the same as the parent, it should have been omitted */
2530 if (lyd_node_module((struct lyd_node *)key) == lyd_node_module(node)) {
2531 LOGVAL(ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, pp.pred[i].name);
2532 return -1;
2533 }
2534 } else {
2535 /* no module, so it must be the same as the list (parent) */
2536 if (lyd_node_module((struct lyd_node *)key) != lyd_node_module(node)) {
2537 LOGVAL(ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, pp.pred[i].name);
2538 return -1;
2539 }
2540 }
2541
2542 /* get canonical value */
2543 val_str = lyd_make_canonical(key->schema, pp.pred[i].value, pp.pred[i].val_len);
2544 if (!val_str) {
2545 return -1;
2546 }
2547
2548 /* value does not match */
2549 if (strcmp(key->value_str, val_str)) {
2550 free(val_str);
2551 return 1;
2552 }
2553 free(val_str);
2554
2555 key = (struct lyd_node_leaf_list *)key->next;
2556 }
2557
2558 return 0;
2559 }
2560
2561 /**
2562 * @brief get the closest parent of the node (or the node itself) identified by the nodeid (path)
2563 *
2564 * @param[in] nodeid Node data path to find
2565 * @param[in] llist_value If the \p nodeid identifies leaf-list, this is expected value of the leaf-list instance.
2566 * @param[in] options Bitmask of options flags, see @ref pathoptions.
2567 * @param[out] parsed Number of characters processed in \p id
2568 * @return The closes parent (or the node itself) from the path
2569 */
2570 struct lyd_node *
resolve_partial_json_data_nodeid(const char * nodeid,const char * llist_value,struct lyd_node * start,int options,int * parsed)2571 resolve_partial_json_data_nodeid(const char *nodeid, const char *llist_value, struct lyd_node *start, int options,
2572 int *parsed)
2573 {
2574 const char *id, *mod_name, *name, *data_val, *llval;
2575 int r, ret, mod_name_len, nam_len, is_relative = -1, list_instance_position;
2576 int has_predicate, last_parsed = 0, llval_len;
2577 struct lyd_node *sibling, *last_match = NULL;
2578 struct lyd_node_leaf_list *llist;
2579 const struct lys_module *prev_mod;
2580 struct ly_ctx *ctx;
2581 const struct lys_node *ssibling, *sparent;
2582 struct lys_node_list *slist;
2583 struct parsed_pred pp;
2584
2585 assert(nodeid && start && parsed);
2586
2587 memset(&pp, 0, sizeof pp);
2588 ctx = start->schema->module->ctx;
2589 id = nodeid;
2590
2591 /* parse first nodeid in case it is yang-data extension */
2592 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL, NULL, 1)) < 1) {
2593 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2594 goto error;
2595 }
2596
2597 if (name[0] == '#') {
2598 if (is_relative) {
2599 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, '#', name);
2600 goto error;
2601 }
2602 id += r;
2603 last_parsed = r;
2604 } else {
2605 is_relative = -1;
2606 }
2607
2608 /* parse first nodeid */
2609 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate, NULL, 0)) < 1) {
2610 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2611 goto error;
2612 }
2613 id += r;
2614 /* add it to parsed only after the data node was actually found */
2615 last_parsed += r;
2616
2617 if (is_relative) {
2618 prev_mod = lyd_node_module(start);
2619 start = (start->schema->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_RPC | LYS_ACTION | LYS_NOTIF)) ? start->child : NULL;
2620 } else {
2621 for (; start->parent; start = start->parent);
2622 prev_mod = lyd_node_module(start);
2623 }
2624 if (!start) {
2625 /* there are no siblings to search */
2626 return NULL;
2627 }
2628
2629 /* do not duplicate code, use predicate parsing from the loop */
2630 goto parse_predicates;
2631
2632 while (1) {
2633 /* find the correct schema node first */
2634 ssibling = NULL;
2635 sparent = (start && start->parent) ? start->parent->schema : NULL;
2636 while ((ssibling = lys_getnext(ssibling, sparent, prev_mod, 0))) {
2637 /* skip invalid input/output nodes */
2638 if (sparent && (sparent->nodetype & (LYS_RPC | LYS_ACTION))) {
2639 if (options & LYD_PATH_OPT_OUTPUT) {
2640 if (lys_parent(ssibling)->nodetype == LYS_INPUT) {
2641 continue;
2642 }
2643 } else {
2644 if (lys_parent(ssibling)->nodetype == LYS_OUTPUT) {
2645 continue;
2646 }
2647 }
2648 }
2649
2650 if (!schema_nodeid_siblingcheck(ssibling, prev_mod, mod_name, mod_name_len, name, nam_len)) {
2651 break;
2652 }
2653 }
2654 if (!ssibling) {
2655 /* there is not even such a schema node */
2656 free(pp.pred);
2657 return last_match;
2658 }
2659 pp.schema = ssibling;
2660
2661 /* unify leaf-list value - it is possible to specify last-node value as both a predicate or parameter if
2662 * is a leaf-list, unify both cases and the value will in both cases be in the predicate structure */
2663 if (!id[0] && !pp.len && (ssibling->nodetype == LYS_LEAFLIST)) {
2664 pp.len = 1;
2665 pp.pred = calloc(1, sizeof *pp.pred);
2666 LY_CHECK_ERR_GOTO(!pp.pred, LOGMEM(ctx), error);
2667
2668 pp.pred[0].name = ".";
2669 pp.pred[0].nam_len = 1;
2670 pp.pred[0].value = (llist_value ? llist_value : "");
2671 pp.pred[0].val_len = strlen(pp.pred[0].value);
2672 }
2673
2674 if (ssibling->nodetype & (LYS_LEAFLIST | LYS_LEAF)) {
2675 /* check leaf/leaf-list predicate */
2676 if (pp.len > 1) {
2677 LOGVAL(ctx, LYE_PATH_PREDTOOMANY, LY_VLOG_NONE, NULL);
2678 goto error;
2679 } else if (pp.len) {
2680 if ((pp.pred[0].name[0] != '.') || (pp.pred[0].nam_len != 1)) {
2681 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, pp.pred[0].name[0], pp.pred[0].name);
2682 goto error;
2683 }
2684 if ((((struct lys_node_leaf *)ssibling)->type.base == LY_TYPE_IDENT) && !strnchr(pp.pred[0].value, ':', pp.pred[0].val_len)) {
2685 LOGVAL(ctx, LYE_PATH_INIDENTREF, LY_VLOG_LYS, ssibling, pp.pred[0].val_len, pp.pred[0].value);
2686 goto error;
2687 }
2688 }
2689 } else if (ssibling->nodetype == LYS_LIST) {
2690 /* list should have predicates for all the keys or position */
2691 slist = (struct lys_node_list *)ssibling;
2692 if (!pp.len) {
2693 /* none match */
2694 return last_match;
2695 } else if (!isdigit(pp.pred[0].name[0])) {
2696 /* list predicate is not a position, so there must be all the keys */
2697 if (pp.len > slist->keys_size) {
2698 LOGVAL(ctx, LYE_PATH_PREDTOOMANY, LY_VLOG_NONE, NULL);
2699 goto error;
2700 } else if (pp.len < slist->keys_size) {
2701 LOGVAL(ctx, LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, slist->keys[pp.len]->name);
2702 goto error;
2703 }
2704 /* check that all identityrefs have module name, otherwise the hash of the list instance will never match!! */
2705 for (r = 0; r < pp.len; ++r) {
2706 if ((slist->keys[r]->type.base == LY_TYPE_IDENT) && !strnchr(pp.pred[r].value, ':', pp.pred[r].val_len)) {
2707 LOGVAL(ctx, LYE_PATH_INIDENTREF, LY_VLOG_LYS, slist->keys[r], pp.pred[r].val_len, pp.pred[r].value);
2708 goto error;
2709 }
2710 }
2711 }
2712 } else if (pp.pred) {
2713 /* no other nodes allow predicates */
2714 LOGVAL(ctx, LYE_PATH_PREDTOOMANY, LY_VLOG_NONE, NULL);
2715 goto error;
2716 }
2717
2718 /* we will not be matching list position, keyless lists, or non-configuration leaf-lists this way */
2719 if (((pp.schema->nodetype != LYS_LIST) || (((struct lys_node_list *)pp.schema)->keys_size && !isdigit(pp.pred[0].name[0])))
2720 && ((pp.schema->nodetype != LYS_LEAFLIST) || (pp.schema->flags & LYS_CONFIG_W))) {
2721 sibling = resolve_json_data_node_hash(start, pp);
2722 } else {
2723 list_instance_position = 0;
2724 LY_TREE_FOR(start, sibling) {
2725 /* RPC/action data check, return simply invalid argument, because the data tree is invalid */
2726 if (lys_parent(sibling->schema)) {
2727 if (options & LYD_PATH_OPT_OUTPUT) {
2728 if (lys_parent(sibling->schema)->nodetype == LYS_INPUT) {
2729 LOGERR(ctx, LY_EINVAL, "Provided data tree includes some RPC input nodes (%s).", sibling->schema->name);
2730 goto error;
2731 }
2732 } else {
2733 if (lys_parent(sibling->schema)->nodetype == LYS_OUTPUT) {
2734 LOGERR(ctx, LY_EINVAL, "Provided data tree includes some RPC output nodes (%s).", sibling->schema->name);
2735 goto error;
2736 }
2737 }
2738 }
2739
2740 if (sibling->schema != ssibling) {
2741 /* wrong schema node */
2742 continue;
2743 }
2744
2745 /* leaf-list, did we find it with the correct value or not? */
2746 if (ssibling->nodetype == LYS_LEAFLIST) {
2747 if (!(ssibling->flags & LYS_CONFIG_W)) {
2748 /* non-configuration leaf-lists will never match */
2749 continue;
2750 }
2751
2752 llist = (struct lyd_node_leaf_list *)sibling;
2753
2754 /* get the expected leaf-list value */
2755 llval = NULL;
2756 llval_len = 0;
2757 if (pp.pred) {
2758 /* it was already checked that it is correct */
2759 llval = pp.pred[0].value;
2760 llval_len = pp.pred[0].val_len;
2761
2762 }
2763
2764 /* make value canonical (remove module name prefix) unless it was specified with it */
2765 if (llval && !strchr(llval, ':') && (llist->value_type & LY_TYPE_IDENT)
2766 && !strncmp(llist->value_str, lyd_node_module(sibling)->name, strlen(lyd_node_module(sibling)->name))
2767 && (llist->value_str[strlen(lyd_node_module(sibling)->name)] == ':')) {
2768 data_val = llist->value_str + strlen(lyd_node_module(sibling)->name) + 1;
2769 } else {
2770 data_val = llist->value_str;
2771 }
2772
2773 if ((!llval && data_val && data_val[0]) || (llval && (strncmp(llval, data_val, llval_len)
2774 || data_val[llval_len]))) {
2775 continue;
2776 }
2777
2778 } else if (ssibling->nodetype == LYS_LIST) {
2779 /* list, we likely need predicates'n'stuff then, but if without a predicate, we are always creating it */
2780 ++list_instance_position;
2781 ret = resolve_partial_json_data_list_predicate(pp, sibling, list_instance_position);
2782 if (ret == -1) {
2783 goto error;
2784 } else if (ret == 1) {
2785 /* this list instance does not match */
2786 continue;
2787 }
2788 }
2789
2790 break;
2791 }
2792 }
2793
2794 /* no match, return last match */
2795 if (!sibling) {
2796 free(pp.pred);
2797 return last_match;
2798 }
2799
2800 /* we found a next matching node */
2801 *parsed += last_parsed;
2802 last_match = sibling;
2803 prev_mod = lyd_node_module(sibling);
2804
2805 /* the result node? */
2806 if (!id[0]) {
2807 free(pp.pred);
2808 return last_match;
2809 }
2810
2811 /* move down the tree, if possible, and continue */
2812 if (ssibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
2813 /* there can be no children even through expected, error */
2814 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2815 goto error;
2816 } else if (!sibling->child) {
2817 /* there could be some children, but are not, return what we found so far */
2818 free(pp.pred);
2819 return last_match;
2820 }
2821 start = sibling->child;
2822
2823 /* parse nodeid */
2824 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate, NULL, 0)) < 1) {
2825 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2826 goto error;
2827 }
2828 id += r;
2829 last_parsed = r;
2830
2831 parse_predicates:
2832 /* parse all the predicates */
2833 free(pp.pred);
2834 pp.schema = NULL;
2835 pp.pred_str = NULL;
2836 pp.pred_str_len = 0;
2837 pp.len = 0;
2838 pp.pred = NULL;
2839 while (has_predicate) {
2840 if (!pp.pred_str) {
2841 pp.pred_str = id;
2842 }
2843
2844 ++pp.len;
2845 pp.pred = ly_realloc(pp.pred, pp.len * sizeof *pp.pred);
2846 LY_CHECK_ERR_GOTO(!pp.pred, LOGMEM(ctx), error);
2847 if ((r = parse_schema_json_predicate(id, &pp.pred[pp.len - 1].mod_name, &pp.pred[pp.len - 1].mod_name_len,
2848 &pp.pred[pp.len - 1].name, &pp.pred[pp.len - 1].nam_len, &pp.pred[pp.len - 1].value,
2849 &pp.pred[pp.len - 1].val_len, &has_predicate)) < 1) {
2850 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2851 goto error;
2852 }
2853
2854 id += r;
2855 last_parsed += r;
2856 pp.pred_str_len += r;
2857 }
2858 }
2859
2860 error:
2861 *parsed = -1;
2862 free(pp.pred);
2863 return NULL;
2864 }
2865
2866 /**
2867 * @brief Resolves length or range intervals. Does not log.
2868 * Syntax is assumed to be correct, *ret MUST be NULL.
2869 *
2870 * @param[in] ctx Context for errors.
2871 * @param[in] str_restr Restriction as a string.
2872 * @param[in] type Type of the restriction.
2873 * @param[out] ret Final interval structure that starts with
2874 * the interval of the initial type, continues with intervals
2875 * of any superior types derived from the initial one, and
2876 * finishes with intervals from our \p type.
2877 *
2878 * @return EXIT_SUCCESS on succes, -1 on error.
2879 */
2880 int
resolve_len_ran_interval(struct ly_ctx * ctx,const char * str_restr,struct lys_type * type,struct len_ran_intv ** ret)2881 resolve_len_ran_interval(struct ly_ctx *ctx, const char *str_restr, struct lys_type *type, struct len_ran_intv **ret)
2882 {
2883 /* 0 - unsigned, 1 - signed, 2 - floating point */
2884 int kind;
2885 int64_t local_smin = 0, local_smax = 0, local_fmin, local_fmax;
2886 uint64_t local_umin, local_umax = 0;
2887 uint8_t local_fdig = 0;
2888 const char *seg_ptr, *ptr;
2889 struct len_ran_intv *local_intv = NULL, *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
2890
2891 switch (type->base) {
2892 case LY_TYPE_BINARY:
2893 kind = 0;
2894 local_umin = 0;
2895 local_umax = 18446744073709551615UL;
2896
2897 if (!str_restr && type->info.binary.length) {
2898 str_restr = type->info.binary.length->expr;
2899 }
2900 break;
2901 case LY_TYPE_DEC64:
2902 kind = 2;
2903 local_fmin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2904 local_fmax = __INT64_C(9223372036854775807);
2905 local_fdig = type->info.dec64.dig;
2906
2907 if (!str_restr && type->info.dec64.range) {
2908 str_restr = type->info.dec64.range->expr;
2909 }
2910 break;
2911 case LY_TYPE_INT8:
2912 kind = 1;
2913 local_smin = __INT64_C(-128);
2914 local_smax = __INT64_C(127);
2915
2916 if (!str_restr && type->info.num.range) {
2917 str_restr = type->info.num.range->expr;
2918 }
2919 break;
2920 case LY_TYPE_INT16:
2921 kind = 1;
2922 local_smin = __INT64_C(-32768);
2923 local_smax = __INT64_C(32767);
2924
2925 if (!str_restr && type->info.num.range) {
2926 str_restr = type->info.num.range->expr;
2927 }
2928 break;
2929 case LY_TYPE_INT32:
2930 kind = 1;
2931 local_smin = __INT64_C(-2147483648);
2932 local_smax = __INT64_C(2147483647);
2933
2934 if (!str_restr && type->info.num.range) {
2935 str_restr = type->info.num.range->expr;
2936 }
2937 break;
2938 case LY_TYPE_INT64:
2939 kind = 1;
2940 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2941 local_smax = __INT64_C(9223372036854775807);
2942
2943 if (!str_restr && type->info.num.range) {
2944 str_restr = type->info.num.range->expr;
2945 }
2946 break;
2947 case LY_TYPE_UINT8:
2948 kind = 0;
2949 local_umin = __UINT64_C(0);
2950 local_umax = __UINT64_C(255);
2951
2952 if (!str_restr && type->info.num.range) {
2953 str_restr = type->info.num.range->expr;
2954 }
2955 break;
2956 case LY_TYPE_UINT16:
2957 kind = 0;
2958 local_umin = __UINT64_C(0);
2959 local_umax = __UINT64_C(65535);
2960
2961 if (!str_restr && type->info.num.range) {
2962 str_restr = type->info.num.range->expr;
2963 }
2964 break;
2965 case LY_TYPE_UINT32:
2966 kind = 0;
2967 local_umin = __UINT64_C(0);
2968 local_umax = __UINT64_C(4294967295);
2969
2970 if (!str_restr && type->info.num.range) {
2971 str_restr = type->info.num.range->expr;
2972 }
2973 break;
2974 case LY_TYPE_UINT64:
2975 kind = 0;
2976 local_umin = __UINT64_C(0);
2977 local_umax = __UINT64_C(18446744073709551615);
2978
2979 if (!str_restr && type->info.num.range) {
2980 str_restr = type->info.num.range->expr;
2981 }
2982 break;
2983 case LY_TYPE_STRING:
2984 kind = 0;
2985 local_umin = __UINT64_C(0);
2986 local_umax = __UINT64_C(18446744073709551615);
2987
2988 if (!str_restr && type->info.str.length) {
2989 str_restr = type->info.str.length->expr;
2990 }
2991 break;
2992 default:
2993 return -1;
2994 }
2995
2996 /* process superior types */
2997 if (type->der) {
2998 if (resolve_len_ran_interval(ctx, NULL, &type->der->type, &intv)) {
2999 return -1;
3000 }
3001 assert(!intv || (intv->kind == kind));
3002 }
3003
3004 if (!str_restr) {
3005 /* we do not have any restriction, return superior ones */
3006 *ret = intv;
3007 return EXIT_SUCCESS;
3008 }
3009
3010 /* adjust local min and max */
3011 if (intv) {
3012 tmp_intv = intv;
3013
3014 if (kind == 0) {
3015 local_umin = tmp_intv->value.uval.min;
3016 } else if (kind == 1) {
3017 local_smin = tmp_intv->value.sval.min;
3018 } else if (kind == 2) {
3019 local_fmin = tmp_intv->value.fval.min;
3020 }
3021
3022 while (tmp_intv->next) {
3023 tmp_intv = tmp_intv->next;
3024 }
3025
3026 if (kind == 0) {
3027 local_umax = tmp_intv->value.uval.max;
3028 } else if (kind == 1) {
3029 local_smax = tmp_intv->value.sval.max;
3030 } else if (kind == 2) {
3031 local_fmax = tmp_intv->value.fval.max;
3032 }
3033 }
3034
3035 /* finally parse our restriction */
3036 seg_ptr = str_restr;
3037 tmp_intv = NULL;
3038 while (1) {
3039 if (!tmp_local_intv) {
3040 assert(!local_intv);
3041 local_intv = malloc(sizeof *local_intv);
3042 tmp_local_intv = local_intv;
3043 } else {
3044 tmp_local_intv->next = malloc(sizeof *tmp_local_intv);
3045 tmp_local_intv = tmp_local_intv->next;
3046 }
3047 LY_CHECK_ERR_GOTO(!tmp_local_intv, LOGMEM(ctx), error);
3048
3049 tmp_local_intv->kind = kind;
3050 tmp_local_intv->type = type;
3051 tmp_local_intv->next = NULL;
3052
3053 /* min */
3054 ptr = seg_ptr;
3055 while (isspace(ptr[0])) {
3056 ++ptr;
3057 }
3058 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
3059 if (kind == 0) {
3060 tmp_local_intv->value.uval.min = strtoull(ptr, (char **)&ptr, 10);
3061 } else if (kind == 1) {
3062 tmp_local_intv->value.sval.min = strtoll(ptr, (char **)&ptr, 10);
3063 } else if (kind == 2) {
3064 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.min)) {
3065 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
3066 goto error;
3067 }
3068 }
3069 } else if (!strncmp(ptr, "min", 3)) {
3070 if (kind == 0) {
3071 tmp_local_intv->value.uval.min = local_umin;
3072 } else if (kind == 1) {
3073 tmp_local_intv->value.sval.min = local_smin;
3074 } else if (kind == 2) {
3075 tmp_local_intv->value.fval.min = local_fmin;
3076 }
3077
3078 ptr += 3;
3079 } else if (!strncmp(ptr, "max", 3)) {
3080 if (kind == 0) {
3081 tmp_local_intv->value.uval.min = local_umax;
3082 } else if (kind == 1) {
3083 tmp_local_intv->value.sval.min = local_smax;
3084 } else if (kind == 2) {
3085 tmp_local_intv->value.fval.min = local_fmax;
3086 }
3087
3088 ptr += 3;
3089 } else {
3090 goto error;
3091 }
3092
3093 while (isspace(ptr[0])) {
3094 ptr++;
3095 }
3096
3097 /* no interval or interval */
3098 if ((ptr[0] == '|') || !ptr[0]) {
3099 if (kind == 0) {
3100 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
3101 } else if (kind == 1) {
3102 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
3103 } else if (kind == 2) {
3104 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
3105 }
3106 } else if (!strncmp(ptr, "..", 2)) {
3107 /* skip ".." */
3108 ptr += 2;
3109 while (isspace(ptr[0])) {
3110 ++ptr;
3111 }
3112
3113 /* max */
3114 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
3115 if (kind == 0) {
3116 tmp_local_intv->value.uval.max = strtoull(ptr, (char **)&ptr, 10);
3117 } else if (kind == 1) {
3118 tmp_local_intv->value.sval.max = strtoll(ptr, (char **)&ptr, 10);
3119 } else if (kind == 2) {
3120 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.max)) {
3121 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
3122 goto error;
3123 }
3124 }
3125 } else if (!strncmp(ptr, "max", 3)) {
3126 if (kind == 0) {
3127 tmp_local_intv->value.uval.max = local_umax;
3128 } else if (kind == 1) {
3129 tmp_local_intv->value.sval.max = local_smax;
3130 } else if (kind == 2) {
3131 tmp_local_intv->value.fval.max = local_fmax;
3132 }
3133 } else {
3134 goto error;
3135 }
3136 } else {
3137 goto error;
3138 }
3139
3140 /* check min and max in correct order */
3141 if (kind == 0) {
3142 /* current segment */
3143 if (tmp_local_intv->value.uval.min > tmp_local_intv->value.uval.max) {
3144 goto error;
3145 }
3146 if (tmp_local_intv->value.uval.min < local_umin || tmp_local_intv->value.uval.max > local_umax) {
3147 goto error;
3148 }
3149 /* segments sholud be ascending order */
3150 if (tmp_intv && (tmp_intv->value.uval.max >= tmp_local_intv->value.uval.min)) {
3151 goto error;
3152 }
3153 } else if (kind == 1) {
3154 if (tmp_local_intv->value.sval.min > tmp_local_intv->value.sval.max) {
3155 goto error;
3156 }
3157 if (tmp_local_intv->value.sval.min < local_smin || tmp_local_intv->value.sval.max > local_smax) {
3158 goto error;
3159 }
3160 if (tmp_intv && (tmp_intv->value.sval.max >= tmp_local_intv->value.sval.min)) {
3161 goto error;
3162 }
3163 } else if (kind == 2) {
3164 if (tmp_local_intv->value.fval.min > tmp_local_intv->value.fval.max) {
3165 goto error;
3166 }
3167 if (tmp_local_intv->value.fval.min < local_fmin || tmp_local_intv->value.fval.max > local_fmax) {
3168 goto error;
3169 }
3170 if (tmp_intv && (tmp_intv->value.fval.max >= tmp_local_intv->value.fval.min)) {
3171 /* fraction-digits value is always the same (it cannot be changed in derived types) */
3172 goto error;
3173 }
3174 }
3175
3176 /* next segment (next OR) */
3177 seg_ptr = strchr(seg_ptr, '|');
3178 if (!seg_ptr) {
3179 break;
3180 }
3181 seg_ptr++;
3182 tmp_intv = tmp_local_intv;
3183 }
3184
3185 /* check local restrictions against superior ones */
3186 if (intv) {
3187 tmp_intv = intv;
3188 tmp_local_intv = local_intv;
3189
3190 while (tmp_local_intv && tmp_intv) {
3191 /* reuse local variables */
3192 if (kind == 0) {
3193 local_umin = tmp_local_intv->value.uval.min;
3194 local_umax = tmp_local_intv->value.uval.max;
3195
3196 /* it must be in this interval */
3197 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
3198 /* this interval is covered, next one */
3199 if (local_umax <= tmp_intv->value.uval.max) {
3200 tmp_local_intv = tmp_local_intv->next;
3201 continue;
3202 /* ascending order of restrictions -> fail */
3203 } else {
3204 goto error;
3205 }
3206 }
3207 } else if (kind == 1) {
3208 local_smin = tmp_local_intv->value.sval.min;
3209 local_smax = tmp_local_intv->value.sval.max;
3210
3211 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
3212 if (local_smax <= tmp_intv->value.sval.max) {
3213 tmp_local_intv = tmp_local_intv->next;
3214 continue;
3215 } else {
3216 goto error;
3217 }
3218 }
3219 } else if (kind == 2) {
3220 local_fmin = tmp_local_intv->value.fval.min;
3221 local_fmax = tmp_local_intv->value.fval.max;
3222
3223 if ((dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.min, local_fdig) > -1)
3224 && (dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1)) {
3225 if (dec64cmp(local_fmax, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1) {
3226 tmp_local_intv = tmp_local_intv->next;
3227 continue;
3228 } else {
3229 goto error;
3230 }
3231 }
3232 }
3233
3234 tmp_intv = tmp_intv->next;
3235 }
3236
3237 /* some interval left uncovered -> fail */
3238 if (tmp_local_intv) {
3239 goto error;
3240 }
3241 }
3242
3243 /* append the local intervals to all the intervals of the superior types, return it all */
3244 if (intv) {
3245 for (tmp_intv = intv; tmp_intv->next; tmp_intv = tmp_intv->next);
3246 tmp_intv->next = local_intv;
3247 } else {
3248 intv = local_intv;
3249 }
3250 *ret = intv;
3251
3252 return EXIT_SUCCESS;
3253
3254 error:
3255 while (intv) {
3256 tmp_intv = intv->next;
3257 free(intv);
3258 intv = tmp_intv;
3259 }
3260 while (local_intv) {
3261 tmp_local_intv = local_intv->next;
3262 free(local_intv);
3263 local_intv = tmp_local_intv;
3264 }
3265
3266 return -1;
3267 }
3268
3269 static int
resolve_superior_type_check(struct lys_type * type)3270 resolve_superior_type_check(struct lys_type *type)
3271 {
3272 uint32_t i;
3273
3274 if (type->base == LY_TYPE_DER) {
3275 /* check that the referenced typedef is resolved */
3276 return EXIT_FAILURE;
3277 } else if (type->base == LY_TYPE_UNION) {
3278 /* check that all union types are resolved */
3279 for (i = 0; i < type->info.uni.count; ++i) {
3280 if (resolve_superior_type_check(&type->info.uni.types[i])) {
3281 return EXIT_FAILURE;
3282 }
3283 }
3284 } else if (type->base == LY_TYPE_LEAFREF) {
3285 /* check there is path in some derived type */
3286 while (!type->info.lref.path) {
3287 assert(type->der);
3288 type = &type->der->type;
3289 }
3290 }
3291
3292 return EXIT_SUCCESS;
3293 }
3294
3295 /**
3296 * @brief Resolve a typedef, return only resolved typedefs if derived. If leafref, it must be
3297 * resolved for this function to return it. Does not log.
3298 *
3299 * @param[in] name Typedef name.
3300 * @param[in] mod_name Typedef name module name.
3301 * @param[in] module Main module.
3302 * @param[in] parent Parent of the resolved type definition.
3303 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
3304 *
3305 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3306 */
3307 int
resolve_superior_type(const char * name,const char * mod_name,const struct lys_module * module,const struct lys_node * parent,struct lys_tpdf ** ret)3308 resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
3309 const struct lys_node *parent, struct lys_tpdf **ret)
3310 {
3311 int i, j;
3312 struct lys_tpdf *tpdf, *match;
3313 int tpdf_size;
3314
3315 if (!mod_name) {
3316 /* no prefix, try built-in types */
3317 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
3318 if (!strcmp(ly_types[i]->name, name)) {
3319 if (ret) {
3320 *ret = ly_types[i];
3321 }
3322 return EXIT_SUCCESS;
3323 }
3324 }
3325 } else {
3326 if (!strcmp(mod_name, module->name)) {
3327 /* prefix refers to the current module, ignore it */
3328 mod_name = NULL;
3329 }
3330 }
3331
3332 if (!mod_name && parent) {
3333 /* search in local typedefs */
3334 while (parent) {
3335 switch (parent->nodetype) {
3336 case LYS_CONTAINER:
3337 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
3338 tpdf = ((struct lys_node_container *)parent)->tpdf;
3339 break;
3340
3341 case LYS_LIST:
3342 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
3343 tpdf = ((struct lys_node_list *)parent)->tpdf;
3344 break;
3345
3346 case LYS_GROUPING:
3347 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
3348 tpdf = ((struct lys_node_grp *)parent)->tpdf;
3349 break;
3350
3351 case LYS_RPC:
3352 case LYS_ACTION:
3353 tpdf_size = ((struct lys_node_rpc_action *)parent)->tpdf_size;
3354 tpdf = ((struct lys_node_rpc_action *)parent)->tpdf;
3355 break;
3356
3357 case LYS_NOTIF:
3358 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
3359 tpdf = ((struct lys_node_notif *)parent)->tpdf;
3360 break;
3361
3362 case LYS_INPUT:
3363 case LYS_OUTPUT:
3364 tpdf_size = ((struct lys_node_inout *)parent)->tpdf_size;
3365 tpdf = ((struct lys_node_inout *)parent)->tpdf;
3366 break;
3367
3368 default:
3369 parent = lys_parent(parent);
3370 continue;
3371 }
3372
3373 for (i = 0; i < tpdf_size; i++) {
3374 if (!strcmp(tpdf[i].name, name)) {
3375 match = &tpdf[i];
3376 goto check_typedef;
3377 }
3378 }
3379
3380 parent = lys_parent(parent);
3381 }
3382 } else {
3383 /* get module where to search */
3384 module = lyp_get_module(module, NULL, 0, mod_name, 0, 0);
3385 if (!module) {
3386 return -1;
3387 }
3388 }
3389
3390 /* search in top level typedefs */
3391 for (i = 0; i < module->tpdf_size; i++) {
3392 if (!strcmp(module->tpdf[i].name, name)) {
3393 match = &module->tpdf[i];
3394 goto check_typedef;
3395 }
3396 }
3397
3398 /* search in submodules */
3399 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
3400 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
3401 if (!strcmp(module->inc[i].submodule->tpdf[j].name, name)) {
3402 match = &module->inc[i].submodule->tpdf[j];
3403 goto check_typedef;
3404 }
3405 }
3406 }
3407
3408 return EXIT_FAILURE;
3409
3410 check_typedef:
3411 if (resolve_superior_type_check(&match->type)) {
3412 return EXIT_FAILURE;
3413 }
3414
3415 if (ret) {
3416 *ret = match;
3417 }
3418 return EXIT_SUCCESS;
3419 }
3420
3421 /**
3422 * @brief Check the default \p value of the \p type. Logs directly.
3423 *
3424 * @param[in] type Type definition to use.
3425 * @param[in] value Default value to check.
3426 * @param[in] module Type module.
3427 *
3428 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3429 */
3430 static int
check_default(struct lys_type * type,const char ** value,struct lys_module * module,int tpdf)3431 check_default(struct lys_type *type, const char **value, struct lys_module *module, int tpdf)
3432 {
3433 struct lys_tpdf *base_tpdf = NULL;
3434 struct lyd_node_leaf_list node;
3435 const char *dflt = NULL;
3436 char *s;
3437 int ret = EXIT_SUCCESS, r;
3438 struct ly_ctx *ctx = module->ctx;
3439
3440 assert(value);
3441 memset(&node, 0, sizeof node);
3442
3443 if (type->base <= LY_TYPE_DER) {
3444 /* the type was not resolved yet, nothing to do for now */
3445 ret = EXIT_FAILURE;
3446 goto cleanup;
3447 } else if (!module->implemented && ((type->base == LY_TYPE_IDENT) || (type->base == LY_TYPE_INST))) {
3448 /* /instidsidentityrefs are checked when instantiated in data instead of typedef,
3449 * but the value has to be modified to include the prefix */
3450 if (*value) {
3451 if (strchr(*value, ':')) {
3452 dflt = transform_schema2json(module, *value);
3453 } else {
3454 /* default prefix of the module where the typedef is defined */
3455 if (asprintf(&s, "%s:%s", lys_main_module(module)->name, *value) == -1) {
3456 LOGMEM(ctx);
3457 ret = -1;
3458 goto cleanup;
3459 }
3460 dflt = lydict_insert_zc(ctx, s);
3461 }
3462 lydict_remove(ctx, *value);
3463 *value = dflt;
3464 dflt = NULL;
3465 }
3466 goto cleanup;
3467 } else if (type->base == LY_TYPE_LEAFREF && tpdf) {
3468 /* leafref in typedef cannot be checked */
3469 goto cleanup;
3470 }
3471
3472 dflt = lydict_insert(ctx, *value, 0);
3473 if (!dflt) {
3474 /* we do not have a new default value, so is there any to check even, in some base type? */
3475 for (base_tpdf = type->der; base_tpdf->type.der; base_tpdf = base_tpdf->type.der) {
3476 if (base_tpdf->dflt) {
3477 dflt = lydict_insert(ctx, base_tpdf->dflt, 0);
3478 break;
3479 }
3480 }
3481
3482 if (!dflt) {
3483 /* no default value, nothing to check, all is well */
3484 goto cleanup;
3485 }
3486
3487 /* so there is a default value in a base type, but can the default value be no longer valid (did we define some new restrictions)? */
3488 switch (type->base) {
3489 case LY_TYPE_IDENT:
3490 if (lys_main_module(base_tpdf->type.parent->module)->implemented) {
3491 goto cleanup;
3492 } else if ((type->base == LY_TYPE_IDENT) || (type->base == LY_TYPE_INST)) {
3493 /* impossible to check with a non-implemented module */
3494 goto cleanup;
3495 } else {
3496 /* check the default value from typedef, but use also the typedef's module
3497 * due to possible searching in imported modules which is expected in
3498 * typedef's module instead of module where the typedef is used */
3499 module = base_tpdf->module;
3500 }
3501 break;
3502 case LY_TYPE_INST:
3503 case LY_TYPE_LEAFREF:
3504 case LY_TYPE_BOOL:
3505 case LY_TYPE_EMPTY:
3506 /* these have no restrictions, so we would do the exact same work as the unres in the base typedef */
3507 goto cleanup;
3508 case LY_TYPE_BITS:
3509 /* the default value must match the restricted list of values, if the type was restricted */
3510 if (type->info.bits.count) {
3511 break;
3512 }
3513 goto cleanup;
3514 case LY_TYPE_ENUM:
3515 /* the default value must match the restricted list of values, if the type was restricted */
3516 if (type->info.enums.count) {
3517 break;
3518 }
3519 goto cleanup;
3520 case LY_TYPE_DEC64:
3521 if (type->info.dec64.range) {
3522 break;
3523 }
3524 goto cleanup;
3525 case LY_TYPE_BINARY:
3526 if (type->info.binary.length) {
3527 break;
3528 }
3529 goto cleanup;
3530 case LY_TYPE_INT8:
3531 case LY_TYPE_INT16:
3532 case LY_TYPE_INT32:
3533 case LY_TYPE_INT64:
3534 case LY_TYPE_UINT8:
3535 case LY_TYPE_UINT16:
3536 case LY_TYPE_UINT32:
3537 case LY_TYPE_UINT64:
3538 if (type->info.num.range) {
3539 break;
3540 }
3541 goto cleanup;
3542 case LY_TYPE_STRING:
3543 if (type->info.str.length || type->info.str.patterns) {
3544 break;
3545 }
3546 goto cleanup;
3547 case LY_TYPE_UNION:
3548 /* way too much trouble learning whether we need to check the default again, so just do it */
3549 break;
3550 default:
3551 LOGINT(ctx);
3552 ret = -1;
3553 goto cleanup;
3554 }
3555 } else if (type->base == LY_TYPE_EMPTY) {
3556 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "default", type->parent->name);
3557 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "The \"empty\" data type cannot have a default value.");
3558 ret = -1;
3559 goto cleanup;
3560 }
3561
3562 /* dummy leaf */
3563 memset(&node, 0, sizeof node);
3564 node.value_str = lydict_insert(ctx, dflt, 0);
3565 node.value_type = type->base;
3566
3567 if (tpdf) {
3568 node.schema = calloc(1, sizeof (struct lys_node_leaf));
3569 if (!node.schema) {
3570 LOGMEM(ctx);
3571 ret = -1;
3572 goto cleanup;
3573 }
3574 r = asprintf((char **)&node.schema->name, "typedef-%s-default", ((struct lys_tpdf *)type->parent)->name);
3575 if (r == -1) {
3576 LOGMEM(ctx);
3577 ret = -1;
3578 goto cleanup;
3579 }
3580 node.schema->module = module;
3581 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
3582 } else {
3583 node.schema = (struct lys_node *)type->parent;
3584 }
3585
3586 if (type->base == LY_TYPE_LEAFREF) {
3587 if (!type->info.lref.target) {
3588 ret = EXIT_FAILURE;
3589 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Default value \"%s\" cannot be checked in an unresolved leafref.",
3590 dflt);
3591 goto cleanup;
3592 }
3593 ret = check_default(&type->info.lref.target->type, &dflt, module, 0);
3594 if (!ret) {
3595 /* adopt possibly changed default value to its canonical form */
3596 if (*value) {
3597 lydict_remove(ctx, *value);
3598 *value = dflt;
3599 dflt = NULL;
3600 }
3601 }
3602 } else {
3603 if (!lyp_parse_value(type, &node.value_str, NULL, &node, NULL, module, 1, 1)) {
3604 /* possible forward reference */
3605 ret = EXIT_FAILURE;
3606 if (base_tpdf) {
3607 /* default value is defined in some base typedef */
3608 if ((type->base == LY_TYPE_BITS && type->der->type.der) ||
3609 (type->base == LY_TYPE_ENUM && type->der->type.der)) {
3610 /* we have refined bits/enums */
3611 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL,
3612 "Invalid value \"%s\" of the default statement inherited to \"%s\" from \"%s\" base type.",
3613 dflt, type->parent->name, base_tpdf->name);
3614 }
3615 }
3616 } else {
3617 /* success - adopt canonical form from the node into the default value */
3618 if (!ly_strequal(dflt, node.value_str, 1)) {
3619 /* this can happen only if we have non-inherited default value,
3620 * inherited default values are already in canonical form */
3621 assert(ly_strequal(dflt, *value, 1));
3622
3623 lydict_remove(ctx, *value);
3624 *value = node.value_str;
3625 node.value_str = NULL;
3626 }
3627 }
3628 }
3629
3630 cleanup:
3631 lyd_free_value(node.value, node.value_type, node.value_flags, type, node.value_str, NULL, NULL, NULL);
3632 lydict_remove(ctx, node.value_str);
3633 if (tpdf && node.schema) {
3634 free((char *)node.schema->name);
3635 free(node.schema);
3636 }
3637 lydict_remove(ctx, dflt);
3638
3639 return ret;
3640 }
3641
3642 /**
3643 * @brief Check a key for mandatory attributes. Logs directly.
3644 *
3645 * @param[in] key The key to check.
3646 * @param[in] flags What flags to check.
3647 * @param[in] list The list of all the keys.
3648 * @param[in] index Index of the key in the key list.
3649 * @param[in] name The name of the keys.
3650 * @param[in] len The name length.
3651 *
3652 * @return EXIT_SUCCESS on success, -1 on error.
3653 */
3654 static int
check_key(struct lys_node_list * list,int index,const char * name,int len)3655 check_key(struct lys_node_list *list, int index, const char *name, int len)
3656 {
3657 struct lys_node_leaf *key = list->keys[index];
3658 char *dup = NULL;
3659 int j;
3660 struct ly_ctx *ctx = list->module->ctx;
3661
3662 /* existence */
3663 if (!key) {
3664 if (name[len] != '\0') {
3665 dup = strdup(name);
3666 LY_CHECK_ERR_RETURN(!dup, LOGMEM(ctx), -1);
3667 dup[len] = '\0';
3668 name = dup;
3669 }
3670 LOGVAL(ctx, LYE_KEY_MISS, LY_VLOG_LYS, list, name);
3671 free(dup);
3672 return -1;
3673 }
3674
3675 /* uniqueness */
3676 for (j = index - 1; j >= 0; j--) {
3677 if (key == list->keys[j]) {
3678 LOGVAL(ctx, LYE_KEY_DUP, LY_VLOG_LYS, list, key->name);
3679 return -1;
3680 }
3681 }
3682
3683 /* key is a leaf */
3684 if (key->nodetype != LYS_LEAF) {
3685 LOGVAL(ctx, LYE_KEY_NLEAF, LY_VLOG_LYS, list, key->name);
3686 return -1;
3687 }
3688
3689 /* type of the leaf is not built-in empty */
3690 if (key->type.base == LY_TYPE_EMPTY && key->module->version < LYS_VERSION_1_1) {
3691 LOGVAL(ctx, LYE_KEY_TYPE, LY_VLOG_LYS, list, key->name);
3692 return -1;
3693 }
3694
3695 /* config attribute is the same as of the list */
3696 if ((key->flags & LYS_CONFIG_MASK) && (list->flags & LYS_CONFIG_MASK)
3697 && ((list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK))) {
3698 LOGVAL(ctx, LYE_KEY_CONFIG, LY_VLOG_LYS, list, key->name);
3699 return -1;
3700 }
3701
3702 /* key is not placed from augment */
3703 if (key->parent->nodetype == LYS_AUGMENT) {
3704 LOGVAL(ctx, LYE_KEY_MISS, LY_VLOG_LYS, key, key->name);
3705 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Key inserted from augment.");
3706 return -1;
3707 }
3708
3709 /* key is not when/if-feature -conditional
3710 * note that j is really assigned in condition to distinguish when and if-feature, it is not supposed to be a comparison */
3711 j = 0;
3712 if (key->when || (key->iffeature_size && (j = 1))) {
3713 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, key, j ? "if-feature" : "when", "leaf");
3714 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Key definition cannot depend on a \"%s\" condition.",
3715 j ? "if-feature" : "when");
3716 return -1;
3717 }
3718
3719 return EXIT_SUCCESS;
3720 }
3721
3722 /**
3723 * @brief Resolve (test the target exists) unique. Logs directly.
3724 *
3725 * @param[in] parent The parent node of the unique structure.
3726 * @param[in] uniq_str_path One path from the unique string.
3727 *
3728 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
3729 */
3730 int
resolve_unique(struct lys_node * parent,const char * uniq_str_path,uint8_t * trg_type)3731 resolve_unique(struct lys_node *parent, const char *uniq_str_path, uint8_t *trg_type)
3732 {
3733 int rc;
3734 const struct lys_node *leaf = NULL;
3735 struct ly_ctx *ctx = parent->module->ctx;
3736
3737 rc = resolve_descendant_schema_nodeid(uniq_str_path, *lys_child(parent, LYS_LEAF), LYS_LEAF, 1, &leaf);
3738 if (rc || !leaf) {
3739 if (rc) {
3740 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3741 if (rc > 0) {
3742 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_PREV, NULL, uniq_str_path[rc - 1], &uniq_str_path[rc - 1]);
3743 } else if (rc == -2) {
3744 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Unique argument references list.");
3745 }
3746 rc = -1;
3747 } else {
3748 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3749 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Target leaf not found.");
3750 rc = EXIT_FAILURE;
3751 }
3752 goto error;
3753 }
3754 if (leaf->nodetype != LYS_LEAF) {
3755 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3756 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Target is not a leaf.");
3757 return -1;
3758 }
3759
3760 /* check status */
3761 if (parent->nodetype != LYS_EXT && lyp_check_status(parent->flags, parent->module, parent->name,
3762 leaf->flags, leaf->module, leaf->name, leaf)) {
3763 return -1;
3764 }
3765
3766 /* check that all unique's targets are of the same config type */
3767 if (*trg_type) {
3768 if (((*trg_type == 1) && (leaf->flags & LYS_CONFIG_R)) || ((*trg_type == 2) && (leaf->flags & LYS_CONFIG_W))) {
3769 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3770 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
3771 "Leaf \"%s\" referenced in unique statement is config %s, but previous referenced leaf is config %s.",
3772 uniq_str_path, *trg_type == 1 ? "false" : "true", *trg_type == 1 ? "true" : "false");
3773 return -1;
3774 }
3775 } else {
3776 /* first unique */
3777 if (leaf->flags & LYS_CONFIG_W) {
3778 *trg_type = 1;
3779 } else {
3780 *trg_type = 2;
3781 }
3782 }
3783
3784 /* set leaf's unique flag */
3785 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
3786
3787 return EXIT_SUCCESS;
3788
3789 error:
3790
3791 return rc;
3792 }
3793
3794 void
unres_data_del(struct unres_data * unres,uint32_t i)3795 unres_data_del(struct unres_data *unres, uint32_t i)
3796 {
3797 /* there are items after the one deleted */
3798 if (i+1 < unres->count) {
3799 /* we only move the data, memory is left allocated, why bother */
3800 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
3801
3802 /* deleting the last item */
3803 } else if (i == 0) {
3804 free(unres->node);
3805 unres->node = NULL;
3806 }
3807
3808 /* if there are no items after and it is not the last one, just move the counter */
3809 --unres->count;
3810 }
3811
3812 /**
3813 * @brief Resolve (find) a data node from a specific module. Does not log.
3814 *
3815 * @param[in] mod Module to search in.
3816 * @param[in] name Name of the data node.
3817 * @param[in] nam_len Length of the name.
3818 * @param[in] start Data node to start the search from.
3819 * @param[in,out] parents Resolved nodes. If there are some parents,
3820 * they are replaced (!!) with the resolvents.
3821 *
3822 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3823 */
3824 static int
resolve_data(const struct lys_module * mod,const char * name,int nam_len,struct lyd_node * start,struct unres_data * parents)3825 resolve_data(const struct lys_module *mod, const char *name, int nam_len, struct lyd_node *start, struct unres_data *parents)
3826 {
3827 struct lyd_node *node;
3828 int flag;
3829 uint32_t i;
3830
3831 if (!parents->count) {
3832 parents->count = 1;
3833 parents->node = malloc(sizeof *parents->node);
3834 LY_CHECK_ERR_RETURN(!parents->node, LOGMEM(mod->ctx), -1);
3835 parents->node[0] = NULL;
3836 }
3837 for (i = 0; i < parents->count;) {
3838 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
3839 /* skip */
3840 ++i;
3841 continue;
3842 }
3843 flag = 0;
3844 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
3845 if (lyd_node_module(node) == mod && !strncmp(node->schema->name, name, nam_len)
3846 && node->schema->name[nam_len] == '\0') {
3847 /* matching target */
3848 if (!flag) {
3849 /* put node instead of the current parent */
3850 parents->node[i] = node;
3851 flag = 1;
3852 } else {
3853 /* multiple matching, so create a new node */
3854 ++parents->count;
3855 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
3856 LY_CHECK_ERR_RETURN(!parents->node, LOGMEM(mod->ctx), EXIT_FAILURE);
3857 parents->node[parents->count-1] = node;
3858 ++i;
3859 }
3860 }
3861 }
3862
3863 if (!flag) {
3864 /* remove item from the parents list */
3865 unres_data_del(parents, i);
3866 } else {
3867 ++i;
3868 }
3869 }
3870
3871 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
3872 }
3873
3874 static int
resolve_schema_leafref_valid_dep_flag(const struct lys_node * op_node,const struct lys_module * local_mod,const struct lys_node * first_node,int abs_path)3875 resolve_schema_leafref_valid_dep_flag(const struct lys_node *op_node, const struct lys_module *local_mod,
3876 const struct lys_node *first_node, int abs_path)
3877 {
3878 const struct lys_node *node;
3879
3880 if (!op_node) {
3881 /* leafref pointing to a different module */
3882 if (local_mod != lys_node_module(first_node)) {
3883 return 1;
3884 }
3885 } else if (lys_parent(op_node)) {
3886 /* inner operation (notif/action) */
3887 if (abs_path) {
3888 return 1;
3889 } else {
3890 /* if first_node parent is not op_node, it is external */
3891 for (node = first_node; node && (node != op_node); node = lys_parent(node));
3892 if (!node) {
3893 return 1;
3894 }
3895 }
3896 } else {
3897 /* top-level operation (notif/rpc) */
3898 if (op_node != first_node) {
3899 return 1;
3900 }
3901 }
3902
3903 return 0;
3904 }
3905
3906 /**
3907 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
3908 *
3909 * @param[in] path Path to use.
3910 * @param[in] context_node Predicate context node (where the predicate is placed).
3911 * @param[in] parent Path context node (where the path begins/is placed).
3912 * @param[in] node_set Set where to add nodes whose parent chain must be implemented.
3913 *
3914 * @return 0 on forward reference, otherwise the number
3915 * of characters successfully parsed,
3916 * positive on success, negative on failure.
3917 */
3918 static int
resolve_schema_leafref_predicate(const char * path,const struct lys_node * context_node,struct lys_node * parent,struct ly_set * node_set)3919 resolve_schema_leafref_predicate(const char *path, const struct lys_node *context_node, struct lys_node *parent,
3920 struct ly_set *node_set)
3921 {
3922 const struct lys_module *trg_mod;
3923 const struct lys_node *src_node, *dst_node, *tmp_parent;
3924 struct lys_node_augment *last_aug;
3925 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
3926 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, pke_parsed, parsed = 0;
3927 int has_predicate, dest_parent_times, i, rc;
3928 struct ly_ctx *ctx = context_node->module->ctx;
3929
3930 do {
3931 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
3932 &pke_len, &has_predicate)) < 1) {
3933 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYS, parent, path[-i], path - i);
3934 return -parsed + i;
3935 }
3936 parsed += i;
3937 path += i;
3938
3939 /* source (must be leaf) */
3940 if (sour_pref) {
3941 trg_mod = lyp_get_module(lys_node_module(parent), NULL, 0, sour_pref, sour_pref_len, 0);
3942 } else {
3943 trg_mod = lys_node_module(parent);
3944 }
3945 rc = lys_getnext_data(trg_mod, context_node, source, sour_len, LYS_LEAF | LYS_LEAFLIST, LYS_GETNEXT_NOSTATECHECK,
3946 &src_node);
3947 if (rc) {
3948 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref predicate", path-parsed);
3949 return 0;
3950 }
3951
3952 /* destination */
3953 dest_parent_times = 0;
3954 pke_parsed = 0;
3955 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3956 &dest_parent_times)) < 1) {
3957 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYS, parent, path_key_expr[-i], path_key_expr-i);
3958 return -parsed;
3959 }
3960 pke_parsed += i;
3961
3962 for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
3963 if (!dst_node) {
3964 /* we went too much into parents, there is no parent anymore */
3965 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref predicate", path_key_expr);
3966 return 0;
3967 }
3968
3969 if (dst_node->parent && (dst_node->parent->nodetype == LYS_AUGMENT)
3970 && !((struct lys_node_augment *)dst_node->parent)->target) {
3971 /* we are in an unresolved augment, cannot evaluate */
3972 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, dst_node->parent,
3973 "Cannot resolve leafref predicate \"%s\" because it is in an unresolved augment.", path_key_expr);
3974 return 0;
3975 }
3976
3977 /* path is supposed to be evaluated in data tree, so we have to skip
3978 * all schema nodes that cannot be instantiated in data tree */
3979 for (dst_node = lys_parent(dst_node);
3980 dst_node && !(dst_node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
3981 dst_node = lys_parent(dst_node));
3982 }
3983 while (1) {
3984 last_aug = NULL;
3985
3986 if (dest_pref) {
3987 trg_mod = lyp_get_module(lys_node_module(parent), NULL, 0, dest_pref, dest_pref_len, 0);
3988 } else {
3989 trg_mod = lys_node_module(parent);
3990 }
3991
3992 if (!trg_mod->implemented && dst_node) {
3993 get_next_augment:
3994 last_aug = lys_getnext_target_aug(last_aug, trg_mod, dst_node);
3995 }
3996
3997 tmp_parent = (last_aug ? (struct lys_node *)last_aug : dst_node);
3998 rc = lys_getnext_data(trg_mod, tmp_parent, dest, dest_len, LYS_CONTAINER | LYS_LIST | LYS_LEAF,
3999 LYS_GETNEXT_NOSTATECHECK, &dst_node);
4000 if (rc) {
4001 if (last_aug) {
4002 /* restore the correct augment target */
4003 dst_node = last_aug->target;
4004 goto get_next_augment;
4005 }
4006 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref predicate", path_key_expr);
4007 return 0;
4008 }
4009
4010 if (pke_len == pke_parsed) {
4011 break;
4012 }
4013
4014 if ((i = parse_path_key_expr(path_key_expr + pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
4015 &dest_parent_times)) < 1) {
4016 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYS, parent,
4017 (path_key_expr + pke_parsed)[-i], (path_key_expr + pke_parsed) - i);
4018 return -parsed;
4019 }
4020 pke_parsed += i;
4021 }
4022
4023 /* check source - dest match */
4024 if (dst_node->nodetype != src_node->nodetype) {
4025 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref predicate", path - parsed);
4026 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Destination node is not a %s, but a %s.",
4027 strnodetype(src_node->nodetype), strnodetype(dst_node->nodetype));
4028 return -parsed;
4029 }
4030
4031 /* add both nodes into node set */
4032 ly_set_add(node_set, (void *)dst_node, 0);
4033 ly_set_add(node_set, (void *)src_node, 0);
4034 } while (has_predicate);
4035
4036 return parsed;
4037 }
4038
4039 static int
check_leafref_features(struct lys_type * type)4040 check_leafref_features(struct lys_type *type)
4041 {
4042 struct lys_node *iter;
4043 struct ly_set *src_parents, *trg_parents, *features;
4044 struct lys_node_augment *aug;
4045 struct ly_ctx *ctx = ((struct lys_tpdf *)type->parent)->module->ctx;
4046 unsigned int i, j, size, x;
4047 int ret = EXIT_SUCCESS;
4048
4049 assert(type->parent);
4050
4051 src_parents = ly_set_new();
4052 trg_parents = ly_set_new();
4053 features = ly_set_new();
4054
4055 /* get parents chain of source (leafref) */
4056 for (iter = (struct lys_node *)type->parent; iter; iter = lys_parent(iter)) {
4057 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
4058 continue;
4059 }
4060 if (iter->parent && (iter->parent->nodetype == LYS_AUGMENT)) {
4061 aug = (struct lys_node_augment *)iter->parent;
4062 if ((aug->module->implemented && (aug->flags & LYS_NOTAPPLIED)) || !aug->target) {
4063 /* unresolved augment, wait until it's resolved */
4064 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, aug,
4065 "Cannot check leafref \"%s\" if-feature consistency because of an unresolved augment.", type->info.lref.path);
4066 ret = EXIT_FAILURE;
4067 goto cleanup;
4068 }
4069 /* also add this augment */
4070 ly_set_add(src_parents, aug, LY_SET_OPT_USEASLIST);
4071 }
4072 ly_set_add(src_parents, iter, LY_SET_OPT_USEASLIST);
4073 }
4074 /* get parents chain of target */
4075 for (iter = (struct lys_node *)type->info.lref.target; iter; iter = lys_parent(iter)) {
4076 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
4077 continue;
4078 }
4079 if (iter->parent && (iter->parent->nodetype == LYS_AUGMENT)) {
4080 aug = (struct lys_node_augment *)iter->parent;
4081 if ((aug->module->implemented && (aug->flags & LYS_NOTAPPLIED)) || !aug->target) {
4082 /* unresolved augment, wait until it's resolved */
4083 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, aug,
4084 "Cannot check leafref \"%s\" if-feature consistency because of an unresolved augment.", type->info.lref.path);
4085 ret = EXIT_FAILURE;
4086 goto cleanup;
4087 }
4088 }
4089 ly_set_add(trg_parents, iter, LY_SET_OPT_USEASLIST);
4090 }
4091
4092 /* compare the features used in if-feature statements in the rest of both
4093 * chains of parents. The set of features used for target must be a subset
4094 * of features used for the leafref. This is not a perfect, we should compare
4095 * the truth tables but it could require too much resources, so we simplify that */
4096 for (i = 0; i < src_parents->number; i++) {
4097 iter = src_parents->set.s[i]; /* shortcut */
4098 if (!iter->iffeature_size) {
4099 continue;
4100 }
4101 for (j = 0; j < iter->iffeature_size; j++) {
4102 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
4103 for (; size; size--) {
4104 if (!iter->iffeature[j].features[size - 1]) {
4105 /* not yet resolved feature, postpone this check */
4106 ret = EXIT_FAILURE;
4107 goto cleanup;
4108 }
4109 ly_set_add(features, iter->iffeature[j].features[size - 1], 0);
4110 }
4111 }
4112 }
4113 x = features->number;
4114 for (i = 0; i < trg_parents->number; i++) {
4115 iter = trg_parents->set.s[i]; /* shortcut */
4116 if (!iter->iffeature_size) {
4117 continue;
4118 }
4119 for (j = 0; j < iter->iffeature_size; j++) {
4120 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
4121 for (; size; size--) {
4122 if (!iter->iffeature[j].features[size - 1]) {
4123 /* not yet resolved feature, postpone this check */
4124 ret = EXIT_FAILURE;
4125 goto cleanup;
4126 }
4127 if ((unsigned)ly_set_add(features, iter->iffeature[j].features[size - 1], 0) >= x) {
4128 /* the feature is not present in features set of target's parents chain */
4129 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, type->parent,
4130 "Leafref is not conditional based on \"%s\" feature as its target.",
4131 iter->iffeature[j].features[size - 1]->name);
4132 for (iter = type->info.lref.target->parent; iter && (iter->nodetype != LYS_USES); iter = lys_parent(iter));
4133 if (iter) {
4134 /* we are in a uses so there can still be a refine that will add an if-feature */
4135 ret = EXIT_FAILURE;
4136 } else {
4137 ret = -1;
4138 }
4139 goto cleanup;
4140 }
4141 }
4142 }
4143 }
4144
4145 cleanup:
4146 ly_set_free(features);
4147 ly_set_free(src_parents);
4148 ly_set_free(trg_parents);
4149
4150 return ret;
4151 }
4152
4153 /**
4154 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
4155 *
4156 * @param[in] path Path to use.
4157 * @param[in] parent_node Parent of the leafref.
4158 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
4159 *
4160 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
4161 */
4162 static int
resolve_schema_leafref(struct lys_type * type,struct lys_node * parent,struct unres_schema * unres)4163 resolve_schema_leafref(struct lys_type *type, struct lys_node *parent, struct unres_schema *unres)
4164 {
4165 const struct lys_node *node, *op_node = NULL, *tmp_parent;
4166 struct ly_set *node_set;
4167 struct lys_node_augment *last_aug;
4168 const struct lys_module *tmp_mod, *cur_module;
4169 const char *id, *prefix, *name;
4170 int pref_len, nam_len, parent_times, has_predicate;
4171 int i, first_iter;
4172 struct ly_ctx *ctx = parent->module->ctx;
4173
4174 /* first check that we are not in an unresolved augment */
4175 for (node = parent; lys_parent(node); node = lys_parent(node));
4176 if (node->parent && (node->parent->nodetype == LYS_AUGMENT)) {
4177 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, node->parent,
4178 "Cannot resolve leafref \"%s\" because it is in an unresolved augment.", type->info.lref.path);
4179 return EXIT_FAILURE;
4180 }
4181
4182 first_iter = 1;
4183 parent_times = 0;
4184 id = type->info.lref.path;
4185 node_set = ly_set_new();
4186 if (!node_set) {
4187 LOGMEM(ctx);
4188 return -1;
4189 }
4190
4191 /* find operation schema we are in */
4192 for (op_node = lys_parent(parent);
4193 op_node && !(op_node->nodetype & (LYS_ACTION | LYS_NOTIF | LYS_RPC));
4194 op_node = lys_parent(op_node));
4195
4196 if (type->der->module) {
4197 /* typedef, take its local module */
4198 cur_module = type->der->module;
4199 } else {
4200 cur_module = lys_node_module(parent);
4201 }
4202 do {
4203 if ((i = parse_path_arg(cur_module, id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
4204 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYS, parent, id[-i], &id[-i]);
4205 ly_set_free(node_set);
4206 return -1;
4207 }
4208 id += i;
4209
4210 /* get the current module */
4211 tmp_mod = prefix ? lyp_get_module(cur_module, NULL, 0, prefix, pref_len, 0) : cur_module;
4212 if (!tmp_mod) {
4213 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", type->info.lref.path);
4214 ly_set_free(node_set);
4215 return EXIT_FAILURE;
4216 }
4217 last_aug = NULL;
4218
4219 if (first_iter) {
4220 if (parent_times == -1) {
4221 /* use module data */
4222 node = NULL;
4223
4224 } else if (parent_times > 0) {
4225 /* we are looking for the right parent */
4226 for (i = 0, node = parent; i < parent_times; i++) {
4227 /* path is supposed to be evaluated in data tree, so we have to skip
4228 * all schema nodes that cannot be instantiated in data tree */
4229 for (node = lys_parent(node);
4230 node && !(node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
4231 node = lys_parent(node));
4232
4233 if (!node) {
4234 if (i == parent_times - 1) {
4235 /* top-level */
4236 break;
4237 }
4238
4239 /* higher than top-level */
4240 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", type->info.lref.path);
4241 ly_set_free(node_set);
4242 return EXIT_FAILURE;
4243 }
4244 }
4245 } else {
4246 LOGINT(ctx);
4247 ly_set_free(node_set);
4248 return -1;
4249 }
4250 }
4251
4252 /* find the next node (either in unconnected augment or as a schema sibling, node is NULL for top-level node -
4253 * - useless to search for that in augments) */
4254 if (!tmp_mod->implemented && node) {
4255 get_next_augment:
4256 last_aug = lys_getnext_target_aug(last_aug, tmp_mod, node);
4257 }
4258
4259 tmp_parent = (last_aug ? (struct lys_node *)last_aug : node);
4260 node = NULL;
4261 while ((node = lys_getnext(node, tmp_parent, tmp_mod, LYS_GETNEXT_NOSTATECHECK))) {
4262 if (lys_node_module(node) != lys_main_module(tmp_mod)) {
4263 continue;
4264 }
4265 if (strncmp(node->name, name, nam_len) || node->name[nam_len]) {
4266 continue;
4267 }
4268 /* match */
4269 break;
4270 }
4271 if (!node) {
4272 if (last_aug) {
4273 /* restore the correct augment target */
4274 node = last_aug->target;
4275 goto get_next_augment;
4276 }
4277 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", type->info.lref.path);
4278 ly_set_free(node_set);
4279 return EXIT_FAILURE;
4280 }
4281
4282 if (first_iter) {
4283 /* find module whose data will actually contain this leafref */
4284 for (tmp_parent = parent; lys_parent(tmp_parent); tmp_parent = lys_parent(tmp_parent));
4285
4286 /* set external dependency flag, we can decide based on the first found node */
4287 if (resolve_schema_leafref_valid_dep_flag(op_node, lys_node_module(tmp_parent), node, (parent_times == -1 ? 1 : 0))) {
4288 parent->flags |= LYS_LEAFREF_DEP;
4289 }
4290 first_iter = 0;
4291 }
4292
4293 if (has_predicate) {
4294 /* we have predicate, so the current result must be list */
4295 if (node->nodetype != LYS_LIST) {
4296 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", type->info.lref.path);
4297 ly_set_free(node_set);
4298 return -1;
4299 }
4300
4301 i = resolve_schema_leafref_predicate(id, node, parent, node_set);
4302 if (!i) {
4303 ly_set_free(node_set);
4304 return EXIT_FAILURE;
4305 } else if (i < 0) {
4306 ly_set_free(node_set);
4307 return -1;
4308 }
4309 id += i;
4310 has_predicate = 0;
4311 }
4312 } while (id[0]);
4313
4314 /* the target must be leaf or leaf-list (in YANG 1.1 only) */
4315 if ((node->nodetype != LYS_LEAF) && (node->nodetype != LYS_LEAFLIST)) {
4316 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", type->info.lref.path);
4317 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Leafref target \"%s\" is not a leaf nor a leaf-list.", type->info.lref.path);
4318 ly_set_free(node_set);
4319 return -1;
4320 }
4321
4322 /* check status */
4323 if (lyp_check_status(parent->flags, parent->module, parent->name,
4324 node->flags, node->module, node->name, node)) {
4325 ly_set_free(node_set);
4326 return -1;
4327 }
4328
4329 /* assign */
4330 type->info.lref.target = (struct lys_node_leaf *)node;
4331
4332 /* add the target node into a set so its parent chain modules can be implemented */
4333 ly_set_add(node_set, (void *)node, 0);
4334
4335 /* find the actual module of this leafref, it can be in a foreign augment */
4336 for (node = parent; lys_parent(node); node = lys_parent(node));
4337 if (lys_node_module(node)->implemented) {
4338 /* make all the modules in the path implemented */
4339 for (i = 0; (unsigned)i < node_set->number; ++i) {
4340 for (node = node_set->set.s[i]; node; node = lys_parent(node)) {
4341 if (!lys_node_module(node)->implemented) {
4342 lys_node_module(node)->implemented = 1;
4343 if (unres_schema_add_node(lys_node_module(node), unres, NULL, UNRES_MOD_IMPLEMENT, NULL) == -1) {
4344 ly_set_free(node_set);
4345 return -1;
4346 }
4347 }
4348 }
4349
4350 /* check leafref that it is allowed */
4351 if (lys_leaf_check_leafref((struct lys_node_leaf *)node_set->set.s[i], (struct lys_node *)type->parent)) {
4352 ly_set_free(node_set);
4353 return -1;
4354 }
4355 }
4356 }
4357 ly_set_free(node_set);
4358
4359 /* check if leafref and its target are under common if-features */
4360 return check_leafref_features(type);
4361 }
4362
4363 /**
4364 * @brief Compare 2 data node values.
4365 *
4366 * Comparison performed on canonical forms, the first value
4367 * is first transformed into canonical form.
4368 *
4369 * @param[in] node Leaf/leaf-list with these values.
4370 * @param[in] noncan_val Non-canonical value.
4371 * @param[in] noncan_val_len Length of \p noncal_val.
4372 * @param[in] can_val Canonical value.
4373 * @return 1 if equal, 0 if not, -1 on error (logged).
4374 */
4375 static int
valequal(struct lys_node * node,const char * noncan_val,int noncan_val_len,const char * can_val)4376 valequal(struct lys_node *node, const char *noncan_val, int noncan_val_len, const char *can_val)
4377 {
4378 int ret;
4379 struct lyd_node_leaf_list leaf;
4380 struct lys_node_leaf *sleaf = (struct lys_node_leaf*)node;
4381
4382 /* dummy leaf */
4383 memset(&leaf, 0, sizeof leaf);
4384 leaf.value_str = lydict_insert(node->module->ctx, noncan_val, noncan_val_len);
4385
4386 repeat:
4387 leaf.value_type = sleaf->type.base;
4388 leaf.schema = node;
4389
4390 if (leaf.value_type == LY_TYPE_LEAFREF) {
4391 if (!sleaf->type.info.lref.target) {
4392 /* it should either be unresolved leafref (leaf.value_type are ORed flags) or it will be resolved */
4393 LOGINT(node->module->ctx);
4394 ret = -1;
4395 goto finish;
4396 }
4397 sleaf = sleaf->type.info.lref.target;
4398 goto repeat;
4399 } else {
4400 if (!lyp_parse_value(&sleaf->type, &leaf.value_str, NULL, &leaf, NULL, NULL, 0, 0)) {
4401 ret = -1;
4402 goto finish;
4403 }
4404 }
4405
4406 if (!strcmp(leaf.value_str, can_val)) {
4407 ret = 1;
4408 } else {
4409 ret = 0;
4410 }
4411
4412 finish:
4413 lydict_remove(node->module->ctx, leaf.value_str);
4414 return ret;
4415 }
4416
4417 /**
4418 * @brief Resolve instance-identifier predicate in JSON data format.
4419 * Does not log.
4420 *
4421 * @param[in] prev_mod Previous module to use in case there is no prefix.
4422 * @param[in] pred Predicate to use.
4423 * @param[in,out] node Node matching the restriction without
4424 * the predicate. If it does not satisfy the predicate,
4425 * it is set to NULL.
4426 *
4427 * @return Number of characters successfully parsed,
4428 * positive on success, negative on failure.
4429 */
4430 static int
resolve_instid_predicate(const struct lys_module * prev_mod,const char * pred,struct lyd_node ** node,int cur_idx)4431 resolve_instid_predicate(const struct lys_module *prev_mod, const char *pred, struct lyd_node **node, int cur_idx)
4432 {
4433 /* ... /node[key=value] ... */
4434 struct lyd_node_leaf_list *key;
4435 struct lys_node_leaf **list_keys = NULL;
4436 struct lys_node_list *slist = NULL;
4437 const char *model, *name, *value;
4438 int mod_len, nam_len, val_len, i, has_predicate, parsed;
4439 struct ly_ctx *ctx = prev_mod->ctx;
4440
4441 assert(pred && node && *node);
4442
4443 parsed = 0;
4444 do {
4445 if ((i = parse_predicate(pred + parsed, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
4446 return -parsed + i;
4447 }
4448 parsed += i;
4449
4450 if (!(*node)) {
4451 /* just parse it all */
4452 continue;
4453 }
4454
4455 /* target */
4456 if (name[0] == '.') {
4457 /* leaf-list value */
4458 if ((*node)->schema->nodetype != LYS_LEAFLIST) {
4459 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects leaf-list, but have %s \"%s\".",
4460 strnodetype((*node)->schema->nodetype), (*node)->schema->name);
4461 parsed = -1;
4462 goto cleanup;
4463 }
4464
4465 /* check the value */
4466 if (!valequal((*node)->schema, value, val_len, ((struct lyd_node_leaf_list *)*node)->value_str)) {
4467 *node = NULL;
4468 goto cleanup;
4469 }
4470
4471 } else if (isdigit(name[0])) {
4472 assert(!value);
4473
4474 /* keyless list position */
4475 if ((*node)->schema->nodetype != LYS_LIST) {
4476 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects list, but have %s \"%s\".",
4477 strnodetype((*node)->schema->nodetype), (*node)->schema->name);
4478 parsed = -1;
4479 goto cleanup;
4480 }
4481
4482 if (((struct lys_node_list *)(*node)->schema)->keys) {
4483 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects list without keys, but have list \"%s\".",
4484 (*node)->schema->name);
4485 parsed = -1;
4486 goto cleanup;
4487 }
4488
4489 /* check the index */
4490 if (atoi(name) != cur_idx) {
4491 *node = NULL;
4492 goto cleanup;
4493 }
4494
4495 } else {
4496 /* list key value */
4497 if ((*node)->schema->nodetype != LYS_LIST) {
4498 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects list, but have %s \"%s\".",
4499 strnodetype((*node)->schema->nodetype), (*node)->schema->name);
4500 parsed = -1;
4501 goto cleanup;
4502 }
4503 slist = (struct lys_node_list *)(*node)->schema;
4504
4505 /* prepare key array */
4506 if (!list_keys) {
4507 list_keys = malloc(slist->keys_size * sizeof *list_keys);
4508 LY_CHECK_ERR_RETURN(!list_keys, LOGMEM(ctx), -1);
4509 for (i = 0; i < slist->keys_size; ++i) {
4510 list_keys[i] = slist->keys[i];
4511 }
4512 }
4513
4514 /* find the schema key leaf */
4515 for (i = 0; i < slist->keys_size; ++i) {
4516 if (list_keys[i] && !strncmp(list_keys[i]->name, name, nam_len) && !list_keys[i]->name[nam_len]) {
4517 break;
4518 }
4519 }
4520 if (i == slist->keys_size) {
4521 /* this list has no such key */
4522 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects list with the key \"%.*s\","
4523 " but list \"%s\" does not define it.", nam_len, name, slist->name);
4524 parsed = -1;
4525 goto cleanup;
4526 }
4527
4528 /* check module */
4529 if (model) {
4530 if (strncmp(list_keys[i]->module->name, model, mod_len) || list_keys[i]->module->name[mod_len]) {
4531 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects key \"%s\" from module \"%.*s\", not \"%s\".",
4532 list_keys[i]->name, model, mod_len, list_keys[i]->module->name);
4533 parsed = -1;
4534 goto cleanup;
4535 }
4536 } else {
4537 if (list_keys[i]->module != prev_mod) {
4538 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects key \"%s\" from module \"%s\", not \"%s\".",
4539 list_keys[i]->name, prev_mod->name, list_keys[i]->module->name);
4540 parsed = -1;
4541 goto cleanup;
4542 }
4543 }
4544
4545 /* find the actual data key */
4546 for (key = (struct lyd_node_leaf_list *)(*node)->child; key; key = (struct lyd_node_leaf_list *)key->next) {
4547 if (key->schema == (struct lys_node *)list_keys[i]) {
4548 break;
4549 }
4550 }
4551 if (!key) {
4552 /* list instance is missing a key? definitely should not happen */
4553 LOGINT(ctx);
4554 parsed = -1;
4555 goto cleanup;
4556 }
4557
4558 /* check the value */
4559 if (!valequal(key->schema, value, val_len, key->value_str)) {
4560 *node = NULL;
4561 /* we still want to parse the whole predicate */
4562 continue;
4563 }
4564
4565 /* everything is fine, mark this key as resolved */
4566 list_keys[i] = NULL;
4567 }
4568 } while (has_predicate);
4569
4570 /* check that all list keys were specified */
4571 if (*node && list_keys) {
4572 for (i = 0; i < slist->keys_size; ++i) {
4573 if (list_keys[i]) {
4574 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier is missing list key \"%s\".", list_keys[i]->name);
4575 parsed = -1;
4576 goto cleanup;
4577 }
4578 }
4579 }
4580
4581 cleanup:
4582 free(list_keys);
4583 return parsed;
4584 }
4585
4586 static int
check_xpath(struct lys_node * node,int check_place)4587 check_xpath(struct lys_node *node, int check_place)
4588 {
4589 struct lys_node *parent;
4590 struct lyxp_set set;
4591 enum int_log_opts prev_ilo;
4592
4593 if (check_place) {
4594 parent = node;
4595 while (parent) {
4596 if (parent->nodetype == LYS_GROUPING) {
4597 /* unresolved grouping, skip for now (will be checked later) */
4598 return EXIT_SUCCESS;
4599 }
4600 if (parent->nodetype == LYS_AUGMENT) {
4601 if (!((struct lys_node_augment *)parent)->target) {
4602 /* unresolved augment, skip for now (will be checked later) */
4603 return EXIT_FAILURE;
4604 } else {
4605 parent = ((struct lys_node_augment *)parent)->target;
4606 continue;
4607 }
4608 }
4609 parent = parent->parent;
4610 }
4611 }
4612
4613 memset(&set, 0, sizeof set);
4614
4615 /* produce just warnings */
4616 ly_ilo_change(NULL, ILO_ERR2WRN, &prev_ilo, NULL);
4617 lyxp_node_atomize(node, &set, 1);
4618 ly_ilo_restore(NULL, prev_ilo, NULL, 0);
4619
4620 if (set.val.snodes) {
4621 free(set.val.snodes);
4622 }
4623 return EXIT_SUCCESS;
4624 }
4625
4626 static int
check_leafref_config(struct lys_node_leaf * leaf,struct lys_type * type)4627 check_leafref_config(struct lys_node_leaf *leaf, struct lys_type *type)
4628 {
4629 unsigned int i;
4630
4631 if (type->base == LY_TYPE_LEAFREF) {
4632 if ((leaf->flags & LYS_CONFIG_W) && type->info.lref.target && type->info.lref.req != -1 &&
4633 (type->info.lref.target->flags & LYS_CONFIG_R)) {
4634 LOGVAL(leaf->module->ctx, LYE_SPEC, LY_VLOG_LYS, leaf, "The leafref %s is config but refers to a non-config %s.",
4635 strnodetype(leaf->nodetype), strnodetype(type->info.lref.target->nodetype));
4636 return -1;
4637 }
4638 /* we can skip the test in case the leafref is not yet resolved. In that case the test is done in the time
4639 * of leafref resolving (lys_leaf_add_leafref_target()) */
4640 } else if (type->base == LY_TYPE_UNION) {
4641 for (i = 0; i < type->info.uni.count; i++) {
4642 if (check_leafref_config(leaf, &type->info.uni.types[i])) {
4643 return -1;
4644 }
4645 }
4646 }
4647 return 0;
4648 }
4649
4650 /**
4651 * @brief Passes config flag down to children, skips nodes without config flags.
4652 * Logs.
4653 *
4654 * @param[in] node Siblings and their children to have flags changed.
4655 * @param[in] clear Flag to clear all config flags if parent is LYS_NOTIF, LYS_INPUT, LYS_OUTPUT, LYS_RPC.
4656 * @param[in] flags Flags to assign to all the nodes.
4657 * @param[in,out] unres List of unresolved items.
4658 *
4659 * @return 0 on success, -1 on error.
4660 */
4661 int
inherit_config_flag(struct lys_node * node,int flags,int clear)4662 inherit_config_flag(struct lys_node *node, int flags, int clear)
4663 {
4664 struct lys_node_leaf *leaf;
4665 struct ly_ctx *ctx;
4666
4667 if (!node) {
4668 return 0;
4669 }
4670
4671 assert(!(flags ^ (flags & LYS_CONFIG_MASK)));
4672 ctx = node->module->ctx;
4673
4674 LY_TREE_FOR(node, node) {
4675 if (clear) {
4676 node->flags &= ~LYS_CONFIG_MASK;
4677 node->flags &= ~LYS_CONFIG_SET;
4678 } else {
4679 if (node->flags & LYS_CONFIG_SET) {
4680 /* skip nodes with an explicit config value */
4681 if ((flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
4682 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, node, "true", "config");
4683 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "State nodes cannot have configuration nodes as children.");
4684 return -1;
4685 }
4686 continue;
4687 }
4688
4689 if (!(node->nodetype & (LYS_USES | LYS_GROUPING))) {
4690 node->flags = (node->flags & ~LYS_CONFIG_MASK) | flags;
4691 /* check that configuration lists have keys */
4692 if ((node->nodetype == LYS_LIST) && (node->flags & LYS_CONFIG_W)
4693 && !((struct lys_node_list *)node)->keys_size) {
4694 LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_LYS, node, "key", "list");
4695 return -1;
4696 }
4697 }
4698 }
4699 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
4700 if (inherit_config_flag(node->child, flags, clear)) {
4701 return -1;
4702 }
4703 } else if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
4704 leaf = (struct lys_node_leaf *)node;
4705 if (check_leafref_config(leaf, &leaf->type)) {
4706 return -1;
4707 }
4708 }
4709 }
4710
4711 return 0;
4712 }
4713
4714 /**
4715 * @brief Resolve augment target. Logs directly.
4716 *
4717 * @param[in] aug Augment to use.
4718 * @param[in] uses Parent where to start the search in. If set, uses augment, if not, standalone augment.
4719 * @param[in,out] unres List of unresolved items.
4720 *
4721 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
4722 */
4723 static int
resolve_augment(struct lys_node_augment * aug,struct lys_node * uses,struct unres_schema * unres)4724 resolve_augment(struct lys_node_augment *aug, struct lys_node *uses, struct unres_schema *unres)
4725 {
4726 int rc;
4727 struct lys_node *sub, *next;
4728 struct lys_module *mod;
4729 struct ly_set *set;
4730 struct ly_ctx *ctx;
4731 struct lys_node_case *c;
4732
4733 assert(aug);
4734 mod = lys_main_module(aug->module);
4735 ctx = mod->ctx;
4736
4737 /* set it as not applied for now */
4738 aug->flags |= LYS_NOTAPPLIED;
4739
4740 /* it can already be resolved in case we returned EXIT_FAILURE from if block below */
4741 if (!aug->target) {
4742 /* resolve target node */
4743 rc = resolve_schema_nodeid(aug->target_name, uses, (uses ? NULL : lys_node_module((struct lys_node *)aug)), &set, 0, 0);
4744 if (rc == -1) {
4745 LOGVAL(ctx, LYE_PATH, LY_VLOG_LYS, aug);
4746 return -1;
4747 }
4748 if (!set) {
4749 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
4750 return EXIT_FAILURE;
4751 }
4752 aug->target = set->set.s[0];
4753 ly_set_free(set);
4754 }
4755
4756 /* make this module implemented if the target module is (if the target is in an unimplemented module,
4757 * it is fine because when we will be making that module implemented, its augment will be applied
4758 * and that augment target module made implemented, recursively) */
4759 if (mod->implemented && !lys_node_module(aug->target)->implemented) {
4760 lys_node_module(aug->target)->implemented = 1;
4761 if (unres_schema_add_node(lys_node_module(aug->target), unres, NULL, UNRES_MOD_IMPLEMENT, NULL) == -1) {
4762 return -1;
4763 }
4764 }
4765
4766 /* check for mandatory nodes - if the target node is in another module
4767 * the added nodes cannot be mandatory
4768 */
4769 if (!aug->parent && (lys_node_module((struct lys_node *)aug) != lys_node_module(aug->target))
4770 && (rc = lyp_check_mandatory_augment(aug, aug->target))) {
4771 return rc;
4772 }
4773
4774 /* check augment target type and then augment nodes type */
4775 if (aug->target->nodetype & (LYS_CONTAINER | LYS_LIST)) {
4776 LY_TREE_FOR(aug->child, sub) {
4777 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES
4778 | LYS_CHOICE | LYS_ACTION | LYS_NOTIF))) {
4779 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4780 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
4781 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
4782 return -1;
4783 }
4784 }
4785 } else if (aug->target->nodetype & (LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF)) {
4786 LY_TREE_FOR(aug->child, sub) {
4787 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES | LYS_CHOICE))) {
4788 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4789 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
4790 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
4791 return -1;
4792 }
4793 }
4794 } else if (aug->target->nodetype == LYS_CHOICE) {
4795 LY_TREE_FOR(aug->child, sub) {
4796 if (!(sub->nodetype & (LYS_CASE | LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
4797 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4798 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
4799 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
4800 return -1;
4801 }
4802 }
4803 } else {
4804 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, aug, aug->target_name, "target-node");
4805 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Invalid augment target node type \"%s\".", strnodetype(aug->target->nodetype));
4806 return -1;
4807 }
4808
4809 /* check identifier uniqueness as in lys_node_addchild() */
4810 LY_TREE_FOR(aug->child, sub) {
4811 if (lys_check_id(sub, aug->target, NULL)) {
4812 return -1;
4813 }
4814 }
4815
4816 if (aug->target->nodetype == LYS_CHOICE) {
4817 /* in the case of implicit cases, we have to create the nodes representing them
4818 * to serve as a target of the augments, they won't be printed, but they are expected in the tree */
4819 LY_TREE_FOR_SAFE(aug->child, next, sub) {
4820 if (sub->nodetype == LYS_CASE) {
4821 /* explicit case */
4822 continue;
4823 }
4824
4825 c = calloc(1, sizeof *c);
4826 LY_CHECK_ERR_RETURN(!c, LOGMEM(ctx), EXIT_FAILURE);
4827 c->name = lydict_insert(ctx, sub->name, 0);
4828 c->flags = LYS_IMPLICIT | (sub->flags & LYS_CONFIG_MASK);
4829 c->module = sub->module;
4830 c->nodetype = LYS_CASE;
4831 c->parent = sub->parent;
4832 c->prev = sub->prev != sub ? sub->prev : (struct lys_node*)c;
4833 if (c->prev->next) {
4834 c->prev->next = (struct lys_node*)c;
4835 } else {
4836 c->parent->child = (struct lys_node*)c;
4837 }
4838 c->next = sub->next;
4839 if (c->next) {
4840 c->next->prev = (struct lys_node*)c;
4841 } else {
4842 c->parent->child->prev = (struct lys_node*)c;
4843 }
4844 c->child = sub;
4845 sub->prev = sub;
4846 sub->next = NULL;
4847 sub->parent = (struct lys_node*)c;
4848 }
4849 }
4850
4851 LY_TREE_DFS_BEGIN(aug->child, next, sub) {
4852 if (sub->nodetype == LYS_ACTION) {
4853 /* we need to check parents */
4854 for (sub = aug->target; sub; sub = lys_parent(sub)) {
4855 if ((sub->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF))
4856 || ((sub->nodetype == LYS_LIST) && !((struct lys_node_list *)sub)->keys)) {
4857 LOGVAL(ctx, LYE_INPAR, LY_VLOG_LYS, aug->target, strnodetype(sub->nodetype), "action");
4858 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
4859 return -1;
4860 }
4861 }
4862 break;
4863 }
4864 LY_TREE_DFS_END(aug->child, next, sub);
4865 }
4866
4867 if (!aug->child) {
4868 /* empty augment, nothing to connect, but it is techincally applied */
4869 LOGWRN(ctx, "Augment \"%s\" without children.", aug->target_name);
4870 aug->flags &= ~LYS_NOTAPPLIED;
4871 } else if ((aug->parent || mod->implemented) && apply_aug(aug, unres)) {
4872 /* we try to connect the augment only in case the module is implemented or
4873 * the augment applies on the used grouping, anyway we failed here */
4874 return -1;
4875 }
4876
4877 return EXIT_SUCCESS;
4878 }
4879
4880 static int
resolve_extension(struct unres_ext * info,struct lys_ext_instance ** ext,struct unres_schema * unres)4881 resolve_extension(struct unres_ext *info, struct lys_ext_instance **ext, struct unres_schema *unres)
4882 {
4883 enum LY_VLOG_ELEM vlog_type;
4884 void *vlog_node;
4885 unsigned int i, j;
4886 struct lys_ext *e;
4887 char *ext_name, *ext_prefix, *tmp;
4888 struct lyxml_elem *next_yin, *yin;
4889 const struct lys_module *mod;
4890 struct lys_ext_instance *tmp_ext;
4891 struct ly_ctx *ctx = NULL;
4892 LYEXT_TYPE etype;
4893 int rt = 0;
4894
4895 switch (info->parent_type) {
4896 case LYEXT_PAR_NODE:
4897 vlog_node = info->parent;
4898 vlog_type = LY_VLOG_LYS;
4899 break;
4900 case LYEXT_PAR_MODULE:
4901 case LYEXT_PAR_IMPORT:
4902 case LYEXT_PAR_INCLUDE:
4903 vlog_node = NULL;
4904 vlog_type = LY_VLOG_LYS;
4905 break;
4906 default:
4907 vlog_node = NULL;
4908 vlog_type = LY_VLOG_NONE;
4909 break;
4910 }
4911
4912 if (info->datatype == LYS_IN_YIN) {
4913 /* YIN */
4914
4915 /* get the module where the extension is supposed to be defined */
4916 mod = lyp_get_import_module_ns(info->mod, info->data.yin->ns->value);
4917 if (!mod) {
4918 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, info->data.yin->name);
4919 return EXIT_FAILURE;
4920 }
4921 ctx = mod->ctx;
4922
4923 /* find the extension definition */
4924 e = NULL;
4925 for (i = 0; i < mod->extensions_size; i++) {
4926 if (ly_strequal(mod->extensions[i].name, info->data.yin->name, 1)) {
4927 e = &mod->extensions[i];
4928 break;
4929 }
4930 }
4931 /* try submodules */
4932 for (j = 0; !e && j < mod->inc_size; j++) {
4933 for (i = 0; i < mod->inc[j].submodule->extensions_size; i++) {
4934 if (ly_strequal(mod->inc[j].submodule->extensions[i].name, info->data.yin->name, 1)) {
4935 e = &mod->inc[j].submodule->extensions[i];
4936 break;
4937 }
4938 }
4939 }
4940 if (!e) {
4941 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, info->data.yin->name);
4942 return EXIT_FAILURE;
4943 }
4944
4945 /* we have the extension definition, so now it cannot be forward referenced and error is always fatal */
4946
4947 if (e->plugin && e->plugin->check_position) {
4948 /* common part - we have plugin with position checking function, use it first */
4949 rt = (*e->plugin->check_position)(info->parent, info->parent_type, info->substmt);
4950 if (rt == 1) {
4951 /* extension is not allowed here */
4952 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, e->name);
4953 return -1;
4954 } else if (rt == 2) {
4955 *ext = NULL;
4956 return EXIT_SUCCESS;
4957 }
4958 }
4959
4960 /* extension type-specific part - allocation */
4961 if (e->plugin) {
4962 etype = e->plugin->type;
4963 } else {
4964 /* default type */
4965 etype = LYEXT_FLAG;
4966 }
4967 switch (etype) {
4968 case LYEXT_FLAG:
4969 (*ext) = calloc(1, sizeof(struct lys_ext_instance));
4970 break;
4971 case LYEXT_COMPLEX:
4972 (*ext) = calloc(1, ((struct lyext_plugin_complex*)e->plugin)->instance_size);
4973 break;
4974 case LYEXT_ERR:
4975 /* we never should be here */
4976 LOGINT(ctx);
4977 return -1;
4978 }
4979 LY_CHECK_ERR_RETURN(!*ext, LOGMEM(ctx), -1);
4980
4981 /* common part for all extension types */
4982 (*ext)->def = e;
4983 (*ext)->parent = info->parent;
4984 (*ext)->parent_type = info->parent_type;
4985 (*ext)->insubstmt = info->substmt;
4986 (*ext)->insubstmt_index = info->substmt_index;
4987 (*ext)->ext_type = e->plugin ? e->plugin->type : LYEXT_FLAG;
4988 (*ext)->flags |= e->plugin ? e->plugin->flags : 0;
4989
4990 if (e->argument) {
4991 if (!(e->flags & LYS_YINELEM)) {
4992 (*ext)->arg_value = lyxml_get_attr(info->data.yin, e->argument, NULL);
4993 if (!(*ext)->arg_value) {
4994 LOGVAL(ctx, LYE_MISSARG, LY_VLOG_NONE, NULL, e->argument, info->data.yin->name);
4995 return -1;
4996 }
4997
4998 (*ext)->arg_value = lydict_insert(mod->ctx, (*ext)->arg_value, 0);
4999 } else {
5000 LY_TREE_FOR_SAFE(info->data.yin->child, next_yin, yin) {
5001 if (ly_strequal(yin->name, e->argument, 1)) {
5002 (*ext)->arg_value = lydict_insert(mod->ctx, yin->content, 0);
5003 lyxml_free(mod->ctx, yin);
5004 break;
5005 }
5006 }
5007 }
5008 }
5009
5010 if ((*ext)->flags & LYEXT_OPT_VALID &&
5011 (info->parent_type == LYEXT_PAR_NODE || info->parent_type == LYEXT_PAR_TPDF)) {
5012 ((struct lys_node *)info->parent)->flags |= LYS_VALID_EXT;
5013 }
5014
5015 (*ext)->nodetype = LYS_EXT;
5016 (*ext)->module = info->mod;
5017
5018 /* extension type-specific part - parsing content */
5019 switch (etype) {
5020 case LYEXT_FLAG:
5021 LY_TREE_FOR_SAFE(info->data.yin->child, next_yin, yin) {
5022 if (!yin->ns) {
5023 /* garbage */
5024 lyxml_free(mod->ctx, yin);
5025 continue;
5026 } else if (!strcmp(yin->ns->value, LY_NSYIN)) {
5027 /* standard YANG statements are not expected here */
5028 LOGVAL(ctx, LYE_INCHILDSTMT, vlog_type, vlog_node, yin->name, info->data.yin->name);
5029 return -1;
5030 } else if (yin->ns == info->data.yin->ns &&
5031 (e->flags & LYS_YINELEM) && ly_strequal(yin->name, e->argument, 1)) {
5032 /* we have the extension's argument */
5033 if ((*ext)->arg_value) {
5034 LOGVAL(ctx, LYE_TOOMANY, vlog_type, vlog_node, yin->name, info->data.yin->name);
5035 return -1;
5036 }
5037 (*ext)->arg_value = yin->content;
5038 yin->content = NULL;
5039 lyxml_free(mod->ctx, yin);
5040 } else {
5041 /* extension instance */
5042 if (lyp_yin_parse_subnode_ext(info->mod, *ext, LYEXT_PAR_EXTINST, yin,
5043 LYEXT_SUBSTMT_SELF, 0, unres)) {
5044 return -1;
5045 }
5046
5047 continue;
5048 }
5049 }
5050 break;
5051 case LYEXT_COMPLEX:
5052 ((struct lys_ext_instance_complex*)(*ext))->substmt = ((struct lyext_plugin_complex*)e->plugin)->substmt;
5053 if (lyp_yin_parse_complex_ext(info->mod, (struct lys_ext_instance_complex*)(*ext), info->data.yin, unres)) {
5054 /* TODO memory cleanup */
5055 return -1;
5056 }
5057 break;
5058 default:
5059 break;
5060 }
5061
5062 /* TODO - lyext_check_result_clb, other than LYEXT_FLAG plugins */
5063
5064 } else {
5065 /* YANG */
5066
5067 ext_prefix = (char *)(*ext)->def;
5068 tmp = strchr(ext_prefix, ':');
5069 if (!tmp) {
5070 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
5071 goto error;
5072 }
5073 ext_name = tmp + 1;
5074
5075 /* get the module where the extension is supposed to be defined */
5076 mod = lyp_get_module(info->mod, ext_prefix, tmp - ext_prefix, NULL, 0, 0);
5077 if (!mod) {
5078 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
5079 return EXIT_FAILURE;
5080 }
5081 ctx = mod->ctx;
5082
5083 /* find the extension definition */
5084 e = NULL;
5085 for (i = 0; i < mod->extensions_size; i++) {
5086 if (ly_strequal(mod->extensions[i].name, ext_name, 0)) {
5087 e = &mod->extensions[i];
5088 break;
5089 }
5090 }
5091 /* try submodules */
5092 for (j = 0; !e && j < mod->inc_size; j++) {
5093 for (i = 0; i < mod->inc[j].submodule->extensions_size; i++) {
5094 if (ly_strequal(mod->inc[j].submodule->extensions[i].name, ext_name, 0)) {
5095 e = &mod->inc[j].submodule->extensions[i];
5096 break;
5097 }
5098 }
5099 }
5100 if (!e) {
5101 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
5102 return EXIT_FAILURE;
5103 }
5104
5105 (*ext)->flags &= ~LYEXT_OPT_YANG;
5106 (*ext)->def = NULL;
5107
5108 /* we have the extension definition, so now it cannot be forward referenced and error is always fatal */
5109
5110 if (e->plugin && e->plugin->check_position) {
5111 /* common part - we have plugin with position checking function, use it first */
5112 rt = (*e->plugin->check_position)(info->parent, info->parent_type, info->substmt);
5113 if (rt == 1) {
5114 /* extension is not allowed here */
5115 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, e->name);
5116 goto error;
5117 } else if (rt == 2) {
5118 lys_extension_instances_free(ctx, (*ext)->ext, (*ext)->ext_size, NULL);
5119 lydict_remove(ctx, (*ext)->arg_value);
5120 free(*ext);
5121 *ext = NULL;
5122 free(ext_prefix);
5123 return EXIT_SUCCESS;
5124 }
5125 }
5126
5127 if (e->argument && !(*ext)->arg_value) {
5128 LOGVAL(ctx, LYE_MISSARG, LY_VLOG_NONE, NULL, e->argument, ext_name);
5129 goto error;
5130 }
5131
5132 /* extension common part */
5133 (*ext)->def = e;
5134 (*ext)->parent = info->parent;
5135 (*ext)->ext_type = e->plugin ? e->plugin->type : LYEXT_FLAG;
5136 (*ext)->flags |= e->plugin ? e->plugin->flags : 0;
5137
5138 if ((*ext)->flags & LYEXT_OPT_VALID &&
5139 (info->parent_type == LYEXT_PAR_NODE || info->parent_type == LYEXT_PAR_TPDF)) {
5140 ((struct lys_node *)info->parent)->flags |= LYS_VALID_EXT;
5141 }
5142
5143 (*ext)->module = info->mod;
5144 (*ext)->nodetype = LYS_EXT;
5145
5146 /* extension type-specific part */
5147 if (e->plugin) {
5148 etype = e->plugin->type;
5149 } else {
5150 /* default type */
5151 etype = LYEXT_FLAG;
5152 }
5153 switch (etype) {
5154 case LYEXT_FLAG:
5155 /* nothing change */
5156 break;
5157 case LYEXT_COMPLEX:
5158 tmp_ext = realloc(*ext, ((struct lyext_plugin_complex*)e->plugin)->instance_size);
5159 LY_CHECK_ERR_GOTO(!tmp_ext, LOGMEM(ctx), error);
5160 memset((char *)tmp_ext + offsetof(struct lys_ext_instance_complex, content), 0,
5161 ((struct lyext_plugin_complex*)e->plugin)->instance_size - offsetof(struct lys_ext_instance_complex, content));
5162 (*ext) = tmp_ext;
5163 ((struct lys_ext_instance_complex*)(*ext))->substmt = ((struct lyext_plugin_complex*)e->plugin)->substmt;
5164 if (info->data.yang) {
5165 *tmp = ':';
5166 if (yang_parse_ext_substatement(info->mod, unres, info->data.yang->ext_substmt, ext_prefix,
5167 (struct lys_ext_instance_complex*)(*ext))) {
5168 goto error;
5169 }
5170 if (yang_fill_extcomplex_module(info->mod->ctx, (struct lys_ext_instance_complex*)(*ext), ext_prefix,
5171 info->data.yang->ext_modules, info->mod->implemented)) {
5172 goto error;
5173 }
5174 }
5175 if (lyp_mand_check_ext((struct lys_ext_instance_complex*)(*ext), ext_prefix)) {
5176 goto error;
5177 }
5178 break;
5179 case LYEXT_ERR:
5180 /* we never should be here */
5181 LOGINT(ctx);
5182 goto error;
5183 }
5184
5185 if (yang_check_ext_instance(info->mod, &(*ext)->ext, &(*ext)->ext_size, *ext, unres)) {
5186 goto error;
5187 }
5188
5189 free(ext_prefix);
5190 }
5191
5192 return EXIT_SUCCESS;
5193 error:
5194 free(ext_prefix);
5195 return -1;
5196 }
5197
5198 /**
5199 * @brief Resolve (find) choice default case. Does not log.
5200 *
5201 * @param[in] choic Choice to use.
5202 * @param[in] dflt Name of the default case.
5203 *
5204 * @return Pointer to the default node or NULL.
5205 */
5206 static struct lys_node *
resolve_choice_dflt(struct lys_node_choice * choic,const char * dflt)5207 resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
5208 {
5209 struct lys_node *child, *ret;
5210
5211 LY_TREE_FOR(choic->child, child) {
5212 if (child->nodetype == LYS_USES) {
5213 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
5214 if (ret) {
5215 return ret;
5216 }
5217 }
5218
5219 if (ly_strequal(child->name, dflt, 1) && (child->nodetype & (LYS_ANYDATA | LYS_CASE
5220 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE))) {
5221 return child;
5222 }
5223 }
5224
5225 return NULL;
5226 }
5227
5228 /**
5229 * @brief Resolve uses, apply augments, refines. Logs directly.
5230 *
5231 * @param[in] uses Uses to use.
5232 * @param[in,out] unres List of unresolved items.
5233 *
5234 * @return EXIT_SUCCESS on success, -1 on error.
5235 */
5236 static int
resolve_uses(struct lys_node_uses * uses,struct unres_schema * unres)5237 resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres)
5238 {
5239 struct ly_ctx *ctx = uses->module->ctx; /* shortcut */
5240 struct lys_node *node = NULL, *next, *iter, **refine_nodes = NULL;
5241 struct lys_node *node_aux, *parent, *tmp;
5242 struct lys_node_leaflist *llist;
5243 struct lys_node_leaf *leaf;
5244 struct lys_refine *rfn;
5245 struct lys_restr *must, **old_must;
5246 struct lys_iffeature *iff, **old_iff;
5247 int i, j, k, rc;
5248 uint8_t size, *old_size;
5249 unsigned int usize, usize1, usize2;
5250
5251 assert(uses->grp);
5252
5253 /* check that the grouping is resolved (no unresolved uses inside) */
5254 assert(!uses->grp->unres_count);
5255
5256 /* copy the data nodes from grouping into the uses context */
5257 LY_TREE_FOR(uses->grp->child, node_aux) {
5258 if (node_aux->nodetype & LYS_GROUPING) {
5259 /* do not instantiate groupings from groupings */
5260 continue;
5261 }
5262 node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, unres, 0);
5263 if (!node) {
5264 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, uses->grp->name, "uses");
5265 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Copying data from grouping failed.");
5266 goto fail;
5267 }
5268 /* test the name of siblings */
5269 LY_TREE_FOR((uses->parent) ? *lys_child(uses->parent, LYS_USES) : lys_main_module(uses->module)->data, tmp) {
5270 if (!(tmp->nodetype & (LYS_USES | LYS_GROUPING | LYS_CASE)) && ly_strequal(tmp->name, node_aux->name, 1)) {
5271 goto fail;
5272 }
5273 }
5274 }
5275
5276 /* we managed to copy the grouping, the rest must be possible to resolve */
5277
5278 if (uses->refine_size) {
5279 refine_nodes = malloc(uses->refine_size * sizeof *refine_nodes);
5280 LY_CHECK_ERR_GOTO(!refine_nodes, LOGMEM(ctx), fail);
5281 }
5282
5283 /* apply refines */
5284 for (i = 0; i < uses->refine_size; i++) {
5285 rfn = &uses->refine[i];
5286 rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child,
5287 LYS_NO_RPC_NOTIF_NODE | LYS_ACTION | LYS_NOTIF,
5288 0, (const struct lys_node **)&node);
5289 if (rc || !node) {
5290 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
5291 goto fail;
5292 }
5293
5294 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
5295 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
5296 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Refine substatements not applicable to the target-node.");
5297 goto fail;
5298 }
5299 refine_nodes[i] = node;
5300
5301 /* description on any nodetype */
5302 if (rfn->dsc) {
5303 lydict_remove(ctx, node->dsc);
5304 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
5305 }
5306
5307 /* reference on any nodetype */
5308 if (rfn->ref) {
5309 lydict_remove(ctx, node->ref);
5310 node->ref = lydict_insert(ctx, rfn->ref, 0);
5311 }
5312
5313 /* config on any nodetype,
5314 * in case of notification or rpc/action, the config is not applicable (there is no config status) */
5315 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
5316 node->flags &= ~LYS_CONFIG_MASK;
5317 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
5318 }
5319
5320 /* default value ... */
5321 if (rfn->dflt_size) {
5322 if (node->nodetype == LYS_LEAF) {
5323 /* leaf */
5324 leaf = (struct lys_node_leaf *)node;
5325
5326 /* replace default value */
5327 lydict_remove(ctx, leaf->dflt);
5328 leaf->dflt = lydict_insert(ctx, rfn->dflt[0], 0);
5329
5330 /* check the default value */
5331 if (unres_schema_add_node(leaf->module, unres, &leaf->type, UNRES_TYPE_DFLT,
5332 (struct lys_node *)(&leaf->dflt)) == -1) {
5333 goto fail;
5334 }
5335 } else if (node->nodetype == LYS_LEAFLIST) {
5336 /* leaf-list */
5337 llist = (struct lys_node_leaflist *)node;
5338
5339 /* remove complete set of defaults in target */
5340 for (j = 0; j < llist->dflt_size; j++) {
5341 lydict_remove(ctx, llist->dflt[j]);
5342 }
5343 free(llist->dflt);
5344
5345 /* copy the default set from refine */
5346 llist->dflt = malloc(rfn->dflt_size * sizeof *llist->dflt);
5347 LY_CHECK_ERR_GOTO(!llist->dflt, LOGMEM(ctx), fail);
5348 llist->dflt_size = rfn->dflt_size;
5349 for (j = 0; j < llist->dflt_size; j++) {
5350 llist->dflt[j] = lydict_insert(ctx, rfn->dflt[j], 0);
5351 }
5352
5353 /* check default value */
5354 for (j = 0; j < llist->dflt_size; j++) {
5355 if (unres_schema_add_node(llist->module, unres, &llist->type, UNRES_TYPE_DFLT,
5356 (struct lys_node *)(&llist->dflt[j])) == -1) {
5357 goto fail;
5358 }
5359 }
5360 }
5361 }
5362
5363 /* mandatory on leaf, anyxml or choice */
5364 if (rfn->flags & LYS_MAND_MASK) {
5365 /* remove current value */
5366 node->flags &= ~LYS_MAND_MASK;
5367
5368 /* set new value */
5369 node->flags |= (rfn->flags & LYS_MAND_MASK);
5370
5371 if (rfn->flags & LYS_MAND_TRUE) {
5372 /* check if node has default value */
5373 if ((node->nodetype & LYS_LEAF) && ((struct lys_node_leaf *)node)->dflt) {
5374 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, uses,
5375 "The \"mandatory\" statement is forbidden on leaf with \"default\".");
5376 goto fail;
5377 }
5378 if ((node->nodetype & LYS_CHOICE) && ((struct lys_node_choice *)node)->dflt) {
5379 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, uses,
5380 "The \"mandatory\" statement is forbidden on choices with \"default\".");
5381 goto fail;
5382 }
5383 }
5384 }
5385
5386 /* presence on container */
5387 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
5388 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
5389 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
5390 }
5391
5392 /* min/max-elements on list or leaf-list */
5393 if (node->nodetype == LYS_LIST) {
5394 if (rfn->flags & LYS_RFN_MINSET) {
5395 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
5396 }
5397 if (rfn->flags & LYS_RFN_MAXSET) {
5398 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
5399 }
5400 } else if (node->nodetype == LYS_LEAFLIST) {
5401 if (rfn->flags & LYS_RFN_MINSET) {
5402 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
5403 }
5404 if (rfn->flags & LYS_RFN_MAXSET) {
5405 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
5406 }
5407 }
5408
5409 /* must in leaf, leaf-list, list, container or anyxml */
5410 if (rfn->must_size) {
5411 switch (node->nodetype) {
5412 case LYS_LEAF:
5413 old_size = &((struct lys_node_leaf *)node)->must_size;
5414 old_must = &((struct lys_node_leaf *)node)->must;
5415 break;
5416 case LYS_LEAFLIST:
5417 old_size = &((struct lys_node_leaflist *)node)->must_size;
5418 old_must = &((struct lys_node_leaflist *)node)->must;
5419 break;
5420 case LYS_LIST:
5421 old_size = &((struct lys_node_list *)node)->must_size;
5422 old_must = &((struct lys_node_list *)node)->must;
5423 break;
5424 case LYS_CONTAINER:
5425 old_size = &((struct lys_node_container *)node)->must_size;
5426 old_must = &((struct lys_node_container *)node)->must;
5427 break;
5428 case LYS_ANYXML:
5429 case LYS_ANYDATA:
5430 old_size = &((struct lys_node_anydata *)node)->must_size;
5431 old_must = &((struct lys_node_anydata *)node)->must;
5432 break;
5433 default:
5434 LOGINT(ctx);
5435 goto fail;
5436 }
5437
5438 size = *old_size + rfn->must_size;
5439 must = realloc(*old_must, size * sizeof *rfn->must);
5440 LY_CHECK_ERR_GOTO(!must, LOGMEM(ctx), fail);
5441 for (k = 0, j = *old_size; k < rfn->must_size; k++, j++) {
5442 must[j].ext_size = rfn->must[k].ext_size;
5443 lys_ext_dup(ctx, rfn->module, rfn->must[k].ext, rfn->must[k].ext_size, &rfn->must[k], LYEXT_PAR_RESTR,
5444 &must[j].ext, 0, unres);
5445 must[j].expr = lydict_insert(ctx, rfn->must[k].expr, 0);
5446 must[j].dsc = lydict_insert(ctx, rfn->must[k].dsc, 0);
5447 must[j].ref = lydict_insert(ctx, rfn->must[k].ref, 0);
5448 must[j].eapptag = lydict_insert(ctx, rfn->must[k].eapptag, 0);
5449 must[j].emsg = lydict_insert(ctx, rfn->must[k].emsg, 0);
5450 must[j].flags = rfn->must[k].flags;
5451 }
5452
5453 *old_must = must;
5454 *old_size = size;
5455
5456 /* check XPath dependencies again */
5457 if (unres_schema_add_node(node->module, unres, node, UNRES_XPATH, NULL) == -1) {
5458 goto fail;
5459 }
5460 }
5461
5462 /* if-feature in leaf, leaf-list, list, container or anyxml */
5463 if (rfn->iffeature_size) {
5464 old_size = &node->iffeature_size;
5465 old_iff = &node->iffeature;
5466
5467 size = *old_size + rfn->iffeature_size;
5468 iff = realloc(*old_iff, size * sizeof *rfn->iffeature);
5469 LY_CHECK_ERR_GOTO(!iff, LOGMEM(ctx), fail);
5470 *old_iff = iff;
5471
5472 for (k = 0, j = *old_size; k < rfn->iffeature_size; k++, j++) {
5473 resolve_iffeature_getsizes(&rfn->iffeature[k], &usize1, &usize2);
5474 if (usize1) {
5475 /* there is something to duplicate */
5476 /* duplicate compiled expression */
5477 usize = (usize1 / 4) + ((usize1 % 4) ? 1 : 0);
5478 iff[j].expr = malloc(usize * sizeof *iff[j].expr);
5479 LY_CHECK_ERR_GOTO(!iff[j].expr, LOGMEM(ctx), fail);
5480 memcpy(iff[j].expr, rfn->iffeature[k].expr, usize * sizeof *iff[j].expr);
5481
5482 /* duplicate list of feature pointers */
5483 iff[j].features = malloc(usize2 * sizeof *iff[k].features);
5484 LY_CHECK_ERR_GOTO(!iff[j].expr, LOGMEM(ctx), fail);
5485 memcpy(iff[j].features, rfn->iffeature[k].features, usize2 * sizeof *iff[j].features);
5486
5487 /* duplicate extensions */
5488 iff[j].ext_size = rfn->iffeature[k].ext_size;
5489 lys_ext_dup(ctx, rfn->module, rfn->iffeature[k].ext, rfn->iffeature[k].ext_size,
5490 &rfn->iffeature[k], LYEXT_PAR_IFFEATURE, &iff[j].ext, 0, unres);
5491 }
5492 (*old_size)++;
5493 }
5494 assert(*old_size == size);
5495 }
5496 }
5497
5498 /* apply augments */
5499 for (i = 0; i < uses->augment_size; i++) {
5500 rc = resolve_augment(&uses->augment[i], (struct lys_node *)uses, unres);
5501 if (rc) {
5502 goto fail;
5503 }
5504 }
5505
5506 /* check refines */
5507 for (i = 0; i < uses->refine_size; i++) {
5508 node = refine_nodes[i];
5509 rfn = &uses->refine[i];
5510
5511 /* config on any nodetype */
5512 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
5513 for (parent = lys_parent(node); parent && parent->nodetype == LYS_USES; parent = lys_parent(parent));
5514 if (parent && parent->nodetype != LYS_GROUPING && (parent->flags & LYS_CONFIG_MASK) &&
5515 ((parent->flags & LYS_CONFIG_MASK) != (rfn->flags & LYS_CONFIG_MASK)) &&
5516 (rfn->flags & LYS_CONFIG_W)) {
5517 /* setting config true under config false is prohibited */
5518 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
5519 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
5520 "changing config from 'false' to 'true' is prohibited while "
5521 "the target's parent is still config 'false'.");
5522 goto fail;
5523 }
5524
5525 /* inherit config change to the target children */
5526 LY_TREE_DFS_BEGIN(node->child, next, iter) {
5527 if (rfn->flags & LYS_CONFIG_W) {
5528 if (iter->flags & LYS_CONFIG_SET) {
5529 /* config is set explicitely, go to next sibling */
5530 next = NULL;
5531 goto nextsibling;
5532 }
5533 } else { /* LYS_CONFIG_R */
5534 if ((iter->flags & LYS_CONFIG_SET) && (iter->flags & LYS_CONFIG_W)) {
5535 /* error - we would have config data under status data */
5536 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
5537 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
5538 "changing config from 'true' to 'false' is prohibited while the target "
5539 "has still a children with explicit config 'true'.");
5540 goto fail;
5541 }
5542 }
5543 /* change config */
5544 iter->flags &= ~LYS_CONFIG_MASK;
5545 iter->flags |= (rfn->flags & LYS_CONFIG_MASK);
5546
5547 /* select next iter - modified LY_TREE_DFS_END */
5548 if (iter->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
5549 next = NULL;
5550 } else {
5551 next = iter->child;
5552 }
5553 nextsibling:
5554 if (!next) {
5555 /* try siblings */
5556 next = iter->next;
5557 }
5558 while (!next) {
5559 /* parent is already processed, go to its sibling */
5560 iter = lys_parent(iter);
5561
5562 /* no siblings, go back through parents */
5563 if (iter == node) {
5564 /* we are done, no next element to process */
5565 break;
5566 }
5567 next = iter->next;
5568 }
5569 }
5570 }
5571
5572 /* default value */
5573 if (rfn->dflt_size) {
5574 if (node->nodetype == LYS_CHOICE) {
5575 /* choice */
5576 ((struct lys_node_choice *)node)->dflt = resolve_choice_dflt((struct lys_node_choice *)node,
5577 rfn->dflt[0]);
5578 if (!((struct lys_node_choice *)node)->dflt) {
5579 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, rfn->dflt[0], "default");
5580 goto fail;
5581 }
5582 if (lyp_check_mandatory_choice(node)) {
5583 goto fail;
5584 }
5585 }
5586 }
5587
5588 /* min/max-elements on list or leaf-list */
5589 if (node->nodetype == LYS_LIST && ((struct lys_node_list *)node)->max) {
5590 if (((struct lys_node_list *)node)->min > ((struct lys_node_list *)node)->max) {
5591 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, uses, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
5592 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "\"min-elements\" is bigger than \"max-elements\".");
5593 goto fail;
5594 }
5595 } else if (node->nodetype == LYS_LEAFLIST && ((struct lys_node_leaflist *)node)->max) {
5596 if (((struct lys_node_leaflist *)node)->min > ((struct lys_node_leaflist *)node)->max) {
5597 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, uses, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
5598 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "\"min-elements\" is bigger than \"max-elements\".");
5599 goto fail;
5600 }
5601 }
5602
5603 /* additional checks */
5604 /* default value with mandatory/min-elements */
5605 if (node->nodetype == LYS_LEAFLIST) {
5606 llist = (struct lys_node_leaflist *)node;
5607 if (llist->dflt_size && llist->min) {
5608 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, uses, rfn->dflt_size ? "default" : "min-elements", "refine");
5609 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
5610 "The \"min-elements\" statement with non-zero value is forbidden on leaf-lists with the \"default\" statement.");
5611 goto fail;
5612 }
5613 } else if (node->nodetype == LYS_LEAF) {
5614 leaf = (struct lys_node_leaf *)node;
5615 if (leaf->dflt && (leaf->flags & LYS_MAND_TRUE)) {
5616 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, uses, rfn->dflt_size ? "default" : "mandatory", "refine");
5617 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
5618 "The \"mandatory\" statement is forbidden on leafs with the \"default\" statement.");
5619 goto fail;
5620 }
5621 }
5622
5623 /* check for mandatory node in default case, first find the closest parent choice to the changed node */
5624 if ((rfn->flags & LYS_MAND_TRUE) || rfn->mod.list.min) {
5625 for (parent = node->parent;
5626 parent && !(parent->nodetype & (LYS_CHOICE | LYS_GROUPING | LYS_ACTION | LYS_USES));
5627 parent = parent->parent) {
5628 if (parent->nodetype == LYS_CONTAINER && ((struct lys_node_container *)parent)->presence) {
5629 /* stop also on presence containers */
5630 break;
5631 }
5632 }
5633 /* and if it is a choice with the default case, check it for presence of a mandatory node in it */
5634 if (parent && parent->nodetype == LYS_CHOICE && ((struct lys_node_choice *)parent)->dflt) {
5635 if (lyp_check_mandatory_choice(parent)) {
5636 goto fail;
5637 }
5638 }
5639 }
5640 }
5641 free(refine_nodes);
5642
5643 /* check list config after all the refines were applied */
5644 LY_TREE_DFS_BEGIN((struct lys_node *)uses, next, iter) {
5645 if ((iter->nodetype == LYS_LIST) && (iter->flags & LYS_CONFIG_W)
5646 && !((struct lys_node_list *)iter)->keys_size) {
5647 LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_LYS, iter, "key", "list");
5648 goto fail;
5649 }
5650 LY_TREE_DFS_END((struct lys_node *)uses, next, iter);
5651 }
5652
5653 return EXIT_SUCCESS;
5654
5655 fail:
5656 LY_TREE_FOR_SAFE(uses->child, next, iter) {
5657 lys_node_free(ctx, iter, NULL, 0);
5658 }
5659 free(refine_nodes);
5660 return -1;
5661 }
5662
5663 void
resolve_identity_backlink_update(struct lys_ident * der,struct lys_ident * base)5664 resolve_identity_backlink_update(struct lys_ident *der, struct lys_ident *base)
5665 {
5666 int i;
5667
5668 assert(der && base);
5669
5670 if (!base->der) {
5671 /* create a set for backlinks if it does not exist */
5672 base->der = ly_set_new();
5673 }
5674 /* store backlink */
5675 ly_set_add(base->der, der, LY_SET_OPT_USEASLIST);
5676
5677 /* do it recursively */
5678 for (i = 0; i < base->base_size; i++) {
5679 resolve_identity_backlink_update(der, base->base[i]);
5680 }
5681 }
5682
5683 /**
5684 * @brief Resolve base identity recursively. Does not log.
5685 *
5686 * @param[in] module Main module.
5687 * @param[in] ident Identity to use.
5688 * @param[in] basename Base name of the identity.
5689 * @param[out] ret Pointer to the resolved identity. Can be NULL.
5690 *
5691 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on crucial error.
5692 */
5693 static int
resolve_base_ident_sub(const struct lys_module * module,struct lys_ident * ident,const char * basename,struct unres_schema * unres,struct lys_ident ** ret)5694 resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
5695 struct unres_schema *unres, struct lys_ident **ret)
5696 {
5697 uint32_t i, j;
5698 struct lys_ident *base = NULL;
5699 struct ly_ctx *ctx = module->ctx;
5700
5701 assert(ret);
5702
5703 /* search module */
5704 for (i = 0; i < module->ident_size; i++) {
5705 if (!strcmp(basename, module->ident[i].name)) {
5706
5707 if (!ident) {
5708 /* just search for type, so do not modify anything, just return
5709 * the base identity pointer */
5710 *ret = &module->ident[i];
5711 return EXIT_SUCCESS;
5712 }
5713
5714 base = &module->ident[i];
5715 goto matchfound;
5716 }
5717 }
5718
5719 /* search submodules */
5720 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
5721 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
5722 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
5723
5724 if (!ident) {
5725 *ret = &module->inc[j].submodule->ident[i];
5726 return EXIT_SUCCESS;
5727 }
5728
5729 base = &module->inc[j].submodule->ident[i];
5730 goto matchfound;
5731 }
5732 }
5733 }
5734
5735 matchfound:
5736 /* we found it somewhere */
5737 if (base) {
5738 /* is it already completely resolved? */
5739 for (i = 0; i < unres->count; i++) {
5740 if ((unres->item[i] == base) && (unres->type[i] == UNRES_IDENT)) {
5741 /* identity found, but not yet resolved, so do not return it in *res and try it again later */
5742
5743 /* simple check for circular reference,
5744 * the complete check is done as a side effect of using only completely
5745 * resolved identities (previous check of unres content) */
5746 if (ly_strequal((const char *)unres->str_snode[i], ident->name, 1)) {
5747 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, basename, "base");
5748 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Circular reference of \"%s\" identity.", basename);
5749 return -1;
5750 }
5751
5752 return EXIT_FAILURE;
5753 }
5754 }
5755
5756 /* checks done, store the result */
5757 *ret = base;
5758 return EXIT_SUCCESS;
5759 }
5760
5761 /* base not found (maybe a forward reference) */
5762 return EXIT_FAILURE;
5763 }
5764
5765 /**
5766 * @brief Resolve base identity. Logs directly.
5767 *
5768 * @param[in] module Main module.
5769 * @param[in] ident Identity to use.
5770 * @param[in] basename Base name of the identity.
5771 * @param[in] parent Either "type" or "identity".
5772 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
5773 *
5774 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
5775 */
5776 static int
resolve_base_ident(const struct lys_module * module,struct lys_ident * ident,const char * basename,const char * parent,struct lys_type * type,struct unres_schema * unres)5777 resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char *parent,
5778 struct lys_type *type, struct unres_schema *unres)
5779 {
5780 const char *name;
5781 int mod_name_len = 0, rc;
5782 struct lys_ident *target, **ret;
5783 uint16_t flags;
5784 struct lys_module *mod;
5785 struct ly_ctx *ctx = module->ctx;
5786
5787 assert((ident && !type) || (!ident && type));
5788
5789 if (!type) {
5790 /* have ident to resolve */
5791 ret = ⌖
5792 flags = ident->flags;
5793 mod = ident->module;
5794 } else {
5795 /* have type to fill */
5796 ++type->info.ident.count;
5797 type->info.ident.ref = ly_realloc(type->info.ident.ref, type->info.ident.count * sizeof *type->info.ident.ref);
5798 LY_CHECK_ERR_RETURN(!type->info.ident.ref, LOGMEM(ctx), -1);
5799
5800 ret = &type->info.ident.ref[type->info.ident.count - 1];
5801 flags = type->parent->flags;
5802 mod = type->parent->module;
5803 }
5804 *ret = NULL;
5805
5806 /* search for the base identity */
5807 name = strchr(basename, ':');
5808 if (name) {
5809 /* set name to correct position after colon */
5810 mod_name_len = name - basename;
5811 name++;
5812
5813 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
5814 /* prefix refers to the current module, ignore it */
5815 mod_name_len = 0;
5816 }
5817 } else {
5818 name = basename;
5819 }
5820
5821 /* get module where to search */
5822 module = lyp_get_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len, 0);
5823 if (!module) {
5824 /* identity refers unknown data model */
5825 LOGVAL(ctx, LYE_INMOD, LY_VLOG_NONE, NULL, basename);
5826 return -1;
5827 }
5828
5829 /* search in the identified module ... */
5830 rc = resolve_base_ident_sub(module, ident, name, unres, ret);
5831 if (!rc) {
5832 assert(*ret);
5833
5834 /* check status */
5835 if (lyp_check_status(flags, mod, ident ? ident->name : "of type",
5836 (*ret)->flags, (*ret)->module, (*ret)->name, NULL)) {
5837 rc = -1;
5838 } else if (ident) {
5839 ident->base[ident->base_size++] = *ret;
5840 if (lys_main_module(mod)->implemented) {
5841 /* in case of the implemented identity, maintain backlinks to it
5842 * from the base identities to make it available when resolving
5843 * data with the identity values (not implemented identity is not
5844 * allowed as an identityref value). */
5845 resolve_identity_backlink_update(ident, *ret);
5846 }
5847 }
5848 } else if (rc == EXIT_FAILURE) {
5849 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_NONE, NULL, parent, basename);
5850 if (type) {
5851 --type->info.ident.count;
5852 }
5853 }
5854
5855 return rc;
5856 }
5857
5858 /*
5859 * 1 - true (der is derived from base)
5860 * 0 - false (der is not derived from base)
5861 */
5862 static int
search_base_identity(struct lys_ident * der,struct lys_ident * base)5863 search_base_identity(struct lys_ident *der, struct lys_ident *base)
5864 {
5865 int i;
5866
5867 if (der == base) {
5868 return 1;
5869 } else {
5870 for(i = 0; i < der->base_size; i++) {
5871 if (search_base_identity(der->base[i], base) == 1) {
5872 return 1;
5873 }
5874 }
5875 }
5876
5877 return 0;
5878 }
5879
5880 /**
5881 * @brief Resolve JSON data format identityref. Logs directly.
5882 *
5883 * @param[in] type Identityref type.
5884 * @param[in] ident_name Identityref name.
5885 * @param[in] node Node where the identityref is being resolved
5886 * @param[in] dflt flag if we are resolving default value in the schema
5887 *
5888 * @return Pointer to the identity resolvent, NULL on error.
5889 */
5890 struct lys_ident *
resolve_identref(struct lys_type * type,const char * ident_name,struct lyd_node * node,struct lys_module * mod,int dflt)5891 resolve_identref(struct lys_type *type, const char *ident_name, struct lyd_node *node, struct lys_module *mod, int dflt)
5892 {
5893 const char *mod_name, *name;
5894 char *str;
5895 int mod_name_len, nam_len, rc;
5896 int need_implemented = 0;
5897 unsigned int i, j, found;
5898 struct lys_ident *der = NULL, *cur;
5899 struct lys_module *imod = NULL, *m, *tmod;
5900 struct ly_ctx *ctx;
5901
5902 assert(type && ident_name && mod);
5903 ctx = mod->ctx;
5904
5905 if (!type || (!type->info.ident.count && !type->der->module) || !ident_name) {
5906 return NULL;
5907 }
5908
5909 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, &nam_len, NULL, 0);
5910 if (rc < 1) {
5911 LOGVAL(ctx, LYE_INCHAR, node ? LY_VLOG_LYD : LY_VLOG_NONE, node, ident_name[-rc], &ident_name[-rc]);
5912 return NULL;
5913 } else if (rc < (signed)strlen(ident_name)) {
5914 LOGVAL(ctx, LYE_INCHAR, node ? LY_VLOG_LYD : LY_VLOG_NONE, node, ident_name[rc], &ident_name[rc]);
5915 return NULL;
5916 }
5917
5918 m = lys_main_module(mod); /* shortcut */
5919 if (!mod_name || (!strncmp(mod_name, m->name, mod_name_len) && !m->name[mod_name_len])) {
5920 /* identity is defined in the same module as node */
5921 imod = m;
5922 } else if (dflt) {
5923 /* solving identityref in default definition in schema -
5924 * find the identity's module in the imported modules list to have a correct revision */
5925 for (i = 0; i < mod->imp_size; i++) {
5926 if (!strncmp(mod_name, mod->imp[i].module->name, mod_name_len) && !mod->imp[i].module->name[mod_name_len]) {
5927 imod = mod->imp[i].module;
5928 break;
5929 }
5930 }
5931
5932 /* We may need to pull it from the module that the typedef came from */
5933 if (!imod && type && type->der->module) {
5934 tmod = type->der->module;
5935 for (i = 0; i < tmod->imp_size; i++) {
5936 if (!strncmp(mod_name, tmod->imp[i].module->name, mod_name_len) && !tmod->imp[i].module->name[mod_name_len]) {
5937 imod = tmod->imp[i].module;
5938 break;
5939 }
5940 }
5941 }
5942
5943 /* it can still be a default value in a foreign grouping */
5944 if (!imod) {
5945 str = strndup(mod_name, mod_name_len);
5946 imod = (struct lys_module *)ly_ctx_get_module(ctx, str, NULL, 1);
5947 free(str);
5948 }
5949 } else {
5950 /* solving identityref in data - get the module from the context */
5951 for (i = 0; i < (unsigned)mod->ctx->models.used; ++i) {
5952 imod = mod->ctx->models.list[i];
5953 if (!strncmp(mod_name, imod->name, mod_name_len) && !imod->name[mod_name_len]) {
5954 break;
5955 }
5956 imod = NULL;
5957 }
5958 if (!imod && mod->ctx->models.parsing_sub_modules_count) {
5959 /* we are currently parsing some module and checking XPath or a default value,
5960 * so take this module into account */
5961 for (i = 0; i < mod->ctx->models.parsing_sub_modules_count; i++) {
5962 imod = mod->ctx->models.parsing_sub_modules[i];
5963 if (imod->type) {
5964 /* skip submodules */
5965 continue;
5966 }
5967 if (!strncmp(mod_name, imod->name, mod_name_len) && !imod->name[mod_name_len]) {
5968 break;
5969 }
5970 imod = NULL;
5971 }
5972 }
5973 }
5974
5975 if (!dflt && (!imod || !imod->implemented) && ctx->data_clb) {
5976 /* the needed module was not found, but it may have been expected so call the data callback */
5977 if (imod) {
5978 ctx->data_clb(ctx, imod->name, imod->ns, LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
5979 } else if (mod_name) {
5980 str = strndup(mod_name, mod_name_len);
5981 imod = (struct lys_module *)ctx->data_clb(ctx, str, NULL, 0, ctx->data_clb_data);
5982 free(str);
5983 }
5984 }
5985 if (!imod) {
5986 goto fail;
5987 }
5988
5989 /* find the type with base definitions */
5990 while (!type->info.ident.count && type->der) {
5991 type = &type->der->type;
5992 }
5993 if (!type->info.ident.count) {
5994 goto fail;
5995 }
5996
5997 if (m != imod || lys_main_module(type->parent->module) != mod) {
5998 /* the type is not referencing the same schema,
5999 * THEN, we may need to make the module with the identity implemented, but only if it really
6000 * contains the identity */
6001 if (!imod->implemented) {
6002 cur = NULL;
6003 /* get the identity in the module */
6004 for (i = 0; i < imod->ident_size; i++) {
6005 if (!strcmp(name, imod->ident[i].name)) {
6006 cur = &imod->ident[i];
6007 break;
6008 }
6009 }
6010 if (!cur) {
6011 /* go through includes */
6012 for (j = 0; j < imod->inc_size; j++) {
6013 for (i = 0; i < imod->inc[j].submodule->ident_size; i++) {
6014 if (!strcmp(name, imod->inc[j].submodule->ident[i].name)) {
6015 cur = &imod->inc[j].submodule->ident[i];
6016 break;
6017 }
6018 }
6019 }
6020 if (!cur) {
6021 goto fail;
6022 }
6023 }
6024
6025 /* check that identity is derived from one of the type's base */
6026 while (type->der) {
6027 for (i = 0; i < type->info.ident.count; i++) {
6028 if (search_base_identity(cur, type->info.ident.ref[i])) {
6029 /* cur's base matches the type's base */
6030 need_implemented = 1;
6031 goto match;
6032 }
6033 }
6034 type = &type->der->type;
6035 }
6036 /* matching base not found */
6037 LOGVAL(ctx, LYE_SPEC, node ? LY_VLOG_LYD : LY_VLOG_NONE, node, "Identity used as identityref value is not implemented.");
6038 goto fail;
6039 }
6040 }
6041
6042 /* go through all the derived types of all the bases */
6043 found = 0;
6044 for (i = 0; i < type->info.ident.count; ++i) {
6045 cur = type->info.ident.ref[i];
6046 if (cur->der) {
6047 /* there are some derived identities */
6048 for (j = 0; j < cur->der->number; j++) {
6049 der = (struct lys_ident *)cur->der->set.g[j]; /* shortcut */
6050 if (!strcmp(der->name, name) && lys_main_module(der->module) == imod) {
6051 /* we have a match on this base */
6052 ++found;
6053 break;
6054 }
6055 }
6056 } else {
6057 LOGWRN(ctx, "Identity \"%s\" has no derived identities, identityref with this base can never be instatiated.",
6058 cur->name);
6059 }
6060 }
6061 if (found == type->info.ident.count) {
6062 /* match found for all bases */
6063 cur = der;
6064 goto match;
6065 } else {
6066 LOGVAL(ctx, LYE_SPEC, node ? LY_VLOG_LYD : LY_VLOG_NONE, node, "Identityref value is not derived from all its bases.");
6067 goto fail;
6068 }
6069
6070 fail:
6071 LOGVAL(ctx, LYE_INRESOLV, node ? LY_VLOG_LYD : LY_VLOG_NONE, node, "identityref", ident_name);
6072 return NULL;
6073
6074 match:
6075 if (!dflt) {
6076 for (i = 0; i < cur->iffeature_size; i++) {
6077 if (!resolve_iffeature(&cur->iffeature[i])) {
6078 if (node) {
6079 LOGVAL(ctx, LYE_INVAL, LY_VLOG_LYD, node, cur->name, node->schema->name);
6080 }
6081 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Identity \"%s\" is disabled by its %d. if-feature condition.",
6082 cur->name, i);
6083 return NULL;
6084 }
6085 }
6086 }
6087 if (need_implemented) {
6088 if (dflt) {
6089 /* later try to make the module implemented */
6090 LOGVRB("Making \"%s\" module implemented because of identityref default value \"%s\" used in the implemented \"%s\" module",
6091 imod->name, cur->name, mod->name);
6092 /* to be more effective we should use UNRES_MOD_IMPLEMENT but that would require changing prototype of
6093 * several functions with little gain */
6094 if (lys_set_implemented(imod)) {
6095 LOGERR(ctx, ly_errno, "Setting the module \"%s\" implemented because of used default identity \"%s\" failed.",
6096 imod->name, cur->name);
6097 goto fail;
6098 }
6099 } else {
6100 /* just say that it was found, but in a non-implemented module */
6101 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Identity found, but in a non-implemented module \"%s\".",
6102 lys_main_module(cur->module)->name);
6103 goto fail;
6104 }
6105 }
6106 return cur;
6107 }
6108
6109 /**
6110 * @brief Resolve unresolved uses. Logs directly.
6111 *
6112 * @param[in] uses Uses to use.
6113 * @param[in] unres Specific unres item.
6114 *
6115 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
6116 */
6117 static int
resolve_unres_schema_uses(struct lys_node_uses * uses,struct unres_schema * unres)6118 resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres)
6119 {
6120 int rc;
6121 struct lys_node *par_grp;
6122 struct ly_ctx *ctx = uses->module->ctx;
6123
6124 /* HACK: when a grouping has uses inside, all such uses have to be resolved before the grouping itself is used
6125 * in some uses. When we see such a uses, the grouping's unres counter is used to store number of so far
6126 * unresolved uses. The grouping cannot be used unless this counter is decreased back to 0. To remember
6127 * that the uses already increased grouping's counter, the LYS_USESGRP flag is used. */
6128 for (par_grp = lys_parent((struct lys_node *)uses); par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
6129 if (par_grp && ly_strequal(par_grp->name, uses->name, 1)) {
6130 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
6131 return -1;
6132 }
6133
6134 if (!uses->grp) {
6135 rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
6136 if (rc == -1) {
6137 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
6138 return -1;
6139 } else if (rc > 0) {
6140 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
6141 return -1;
6142 } else if (!uses->grp) {
6143 if (par_grp && !(uses->flags & LYS_USESGRP)) {
6144 if (++((struct lys_node_grp *)par_grp)->unres_count == 0) {
6145 LOGERR(ctx, LY_EINT, "Too many unresolved items (uses) inside a grouping.");
6146 return -1;
6147 }
6148 uses->flags |= LYS_USESGRP;
6149 }
6150 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
6151 return EXIT_FAILURE;
6152 }
6153 }
6154
6155 if (uses->grp->unres_count) {
6156 if (par_grp && !(uses->flags & LYS_USESGRP)) {
6157 if (++((struct lys_node_grp *)par_grp)->unres_count == 0) {
6158 LOGERR(ctx, LY_EINT, "Too many unresolved items (uses) inside a grouping.");
6159 return -1;
6160 }
6161 uses->flags |= LYS_USESGRP;
6162 } else {
6163 /* instantiate grouping only when it is completely resolved */
6164 uses->grp = NULL;
6165 }
6166 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
6167 return EXIT_FAILURE;
6168 }
6169
6170 rc = resolve_uses(uses, unres);
6171 if (!rc) {
6172 /* decrease unres count only if not first try */
6173 if (par_grp && (uses->flags & LYS_USESGRP)) {
6174 assert(((struct lys_node_grp *)par_grp)->unres_count);
6175 ((struct lys_node_grp *)par_grp)->unres_count--;
6176 uses->flags &= ~LYS_USESGRP;
6177 }
6178
6179 /* check status */
6180 if (lyp_check_status(uses->flags, uses->module, "of uses",
6181 uses->grp->flags, uses->grp->module, uses->grp->name,
6182 (struct lys_node *)uses)) {
6183 return -1;
6184 }
6185
6186 return EXIT_SUCCESS;
6187 }
6188
6189 return rc;
6190 }
6191
6192 /**
6193 * @brief Resolve list keys. Logs directly.
6194 *
6195 * @param[in] list List to use.
6196 * @param[in] keys_str Keys node value.
6197 *
6198 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
6199 */
6200 static int
resolve_list_keys(struct lys_node_list * list,const char * keys_str)6201 resolve_list_keys(struct lys_node_list *list, const char *keys_str)
6202 {
6203 int i, len, rc;
6204 const char *value;
6205 char *s = NULL;
6206 struct ly_ctx *ctx = list->module->ctx;
6207
6208 for (i = 0; i < list->keys_size; ++i) {
6209 assert(keys_str);
6210
6211 if (!list->child) {
6212 /* no child, possible forward reference */
6213 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
6214 return EXIT_FAILURE;
6215 }
6216 /* get the key name */
6217 if ((value = strpbrk(keys_str, " \t\n"))) {
6218 len = value - keys_str;
6219 while (isspace(value[0])) {
6220 value++;
6221 }
6222 } else {
6223 len = strlen(keys_str);
6224 }
6225
6226 rc = lys_getnext_data(lys_node_module((struct lys_node *)list), (struct lys_node *)list, keys_str, len, LYS_LEAF,
6227 LYS_GETNEXT_NOSTATECHECK, (const struct lys_node **)&list->keys[i]);
6228 if (rc) {
6229 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, list, "list key", keys_str);
6230 return EXIT_FAILURE;
6231 }
6232
6233 if (check_key(list, i, keys_str, len)) {
6234 /* check_key logs */
6235 return -1;
6236 }
6237
6238 /* check status */
6239 if (lyp_check_status(list->flags, list->module, list->name,
6240 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
6241 (struct lys_node *)list->keys[i])) {
6242 return -1;
6243 }
6244
6245 /* default value - is ignored, keep it but print a warning */
6246 if (list->keys[i]->dflt) {
6247 /* log is not hidden only in case this resolving fails and in such a case
6248 * we cannot get here
6249 */
6250 assert(log_opt == ILO_STORE);
6251 log_opt = ILO_LOG;
6252 LOGWRN(ctx, "Default value \"%s\" in the list key \"%s\" is ignored. (%s)", list->keys[i]->dflt,
6253 list->keys[i]->name, s = lys_path((struct lys_node*)list, LYS_PATH_FIRST_PREFIX));
6254 log_opt = ILO_STORE;
6255 free(s);
6256 }
6257
6258 /* prepare for next iteration */
6259 while (value && isspace(value[0])) {
6260 value++;
6261 }
6262 keys_str = value;
6263 }
6264
6265 return EXIT_SUCCESS;
6266 }
6267
6268 /**
6269 * @brief Resolve (check) all must conditions of \p node.
6270 * Logs directly.
6271 *
6272 * @param[in] node Data node with optional must statements.
6273 * @param[in] inout_parent If set, must in input or output parent of node->schema will be resolved.
6274 * @param[in] ignore_fail 0 - no, 1 - yes, 2 - yes, but only for external dependencies.
6275 * @param[in] multi_error 0 - no, 1 - yes.
6276 *
6277 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
6278 */
6279 static int
resolve_must(struct lyd_node * node,int inout_parent,int ignore_fail,int multi_error)6280 resolve_must(struct lyd_node *node, int inout_parent, int ignore_fail, int multi_error)
6281 {
6282 uint8_t i, must_size;
6283 struct lys_node *schema;
6284 struct lys_restr *must;
6285 struct lyxp_set set;
6286 struct ly_ctx *ctx = node->schema->module->ctx;
6287 int rc = EXIT_SUCCESS;
6288
6289 assert(node);
6290 memset(&set, 0, sizeof set);
6291
6292 if (inout_parent) {
6293 for (schema = lys_parent(node->schema);
6294 schema && (schema->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES));
6295 schema = lys_parent(schema));
6296 if (!schema || !(schema->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
6297 LOGINT(ctx);
6298 return -1;
6299 }
6300 must_size = ((struct lys_node_inout *)schema)->must_size;
6301 must = ((struct lys_node_inout *)schema)->must;
6302
6303 /* context node is the RPC/action */
6304 node = node->parent;
6305 if (!(node->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
6306 LOGINT(ctx);
6307 return -1;
6308 }
6309 } else {
6310 switch (node->schema->nodetype) {
6311 case LYS_CONTAINER:
6312 must_size = ((struct lys_node_container *)node->schema)->must_size;
6313 must = ((struct lys_node_container *)node->schema)->must;
6314 break;
6315 case LYS_LEAF:
6316 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
6317 must = ((struct lys_node_leaf *)node->schema)->must;
6318 break;
6319 case LYS_LEAFLIST:
6320 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
6321 must = ((struct lys_node_leaflist *)node->schema)->must;
6322 break;
6323 case LYS_LIST:
6324 must_size = ((struct lys_node_list *)node->schema)->must_size;
6325 must = ((struct lys_node_list *)node->schema)->must;
6326 break;
6327 case LYS_ANYXML:
6328 case LYS_ANYDATA:
6329 must_size = ((struct lys_node_anydata *)node->schema)->must_size;
6330 must = ((struct lys_node_anydata *)node->schema)->must;
6331 break;
6332 case LYS_NOTIF:
6333 must_size = ((struct lys_node_notif *)node->schema)->must_size;
6334 must = ((struct lys_node_notif *)node->schema)->must;
6335 break;
6336 default:
6337 must_size = 0;
6338 must = NULL;
6339 break;
6340 }
6341 }
6342
6343 for (i = 0; i < must_size; ++i) {
6344 if (lyxp_eval(must[i].expr, node, LYXP_NODE_ELEM, lyd_node_module(node), &set, LYXP_MUST)) {
6345 return -1;
6346 }
6347
6348 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_MUST);
6349
6350 if (!set.val.bool) {
6351 if ((ignore_fail == 1) || ((must[i].flags & (LYS_XPCONF_DEP | LYS_XPSTATE_DEP)) && (ignore_fail == 2))) {
6352 LOGVRB("Must condition \"%s\" not satisfied, but it is not required.", must[i].expr);
6353 } else {
6354 LOGVAL(ctx, LYE_NOMUST, LY_VLOG_LYD, node, must[i].expr);
6355 if (must[i].emsg) {
6356 ly_err_last_set_msg(ctx, must[i].emsg);
6357 }
6358 if (must[i].eapptag) {
6359 ly_err_last_set_apptag(ctx, must[i].eapptag);
6360 }
6361 rc = 1;
6362 if (!multi_error) {
6363 break;
6364 }
6365 }
6366 }
6367 }
6368
6369 return rc;
6370 }
6371
6372 /**
6373 * @brief Resolve (find) when condition schema context node. Does not log.
6374 *
6375 * @param[in] schema Schema node with the when condition.
6376 * @param[out] ctx_snode When schema context node.
6377 * @param[out] ctx_snode_type Schema context node type.
6378 */
6379 void
resolve_when_ctx_snode(const struct lys_node * schema,struct lys_node ** ctx_snode,enum lyxp_node_type * ctx_snode_type)6380 resolve_when_ctx_snode(const struct lys_node *schema, struct lys_node **ctx_snode, enum lyxp_node_type *ctx_snode_type)
6381 {
6382 const struct lys_node *sparent;
6383
6384 /* find a not schema-only node */
6385 *ctx_snode_type = LYXP_NODE_ELEM;
6386 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
6387 if (schema->nodetype == LYS_AUGMENT) {
6388 sparent = ((struct lys_node_augment *)schema)->target;
6389 } else {
6390 sparent = schema->parent;
6391 }
6392 if (!sparent) {
6393 /* context node is the document root (fake root in our case) */
6394 if (schema->flags & LYS_CONFIG_W) {
6395 *ctx_snode_type = LYXP_NODE_ROOT_CONFIG;
6396 } else {
6397 *ctx_snode_type = LYXP_NODE_ROOT;
6398 }
6399 /* we need the first top-level sibling, but no uses or groupings */
6400 schema = lys_getnext(NULL, NULL, lys_node_module(schema), LYS_GETNEXT_NOSTATECHECK);
6401 break;
6402 }
6403 schema = sparent;
6404 }
6405
6406 *ctx_snode = (struct lys_node *)schema;
6407 }
6408
6409 /**
6410 * @brief Resolve (find) when condition context node. Does not log.
6411 *
6412 * @param[in] node Data node, whose conditional definition is being decided.
6413 * @param[in] schema Schema node with the when condition.
6414 * @param[out] ctx_node Context node.
6415 * @param[out] ctx_node_type Context node type.
6416 *
6417 * @return EXIT_SUCCESS on success, -1 on error.
6418 */
6419 static int
resolve_when_ctx_node(struct lyd_node * node,struct lys_node * schema,struct lyd_node ** ctx_node,enum lyxp_node_type * ctx_node_type)6420 resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema, struct lyd_node **ctx_node,
6421 enum lyxp_node_type *ctx_node_type)
6422 {
6423 struct lyd_node *parent;
6424 struct lys_node *sparent;
6425 enum lyxp_node_type node_type;
6426 uint16_t i, data_depth, schema_depth;
6427
6428 resolve_when_ctx_snode(schema, &schema, &node_type);
6429
6430 if (node_type == LYXP_NODE_ELEM) {
6431 /* standard element context node */
6432 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
6433 for (sparent = schema, schema_depth = 0;
6434 sparent;
6435 sparent = (sparent->nodetype == LYS_AUGMENT ? ((struct lys_node_augment *)sparent)->target : sparent->parent)) {
6436 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_NOTIF | LYS_RPC)) {
6437 ++schema_depth;
6438 }
6439 }
6440 if (data_depth < schema_depth) {
6441 return -1;
6442 }
6443
6444 /* find the corresponding data node */
6445 for (i = 0; i < data_depth - schema_depth; ++i) {
6446 node = node->parent;
6447 }
6448 if (node->schema != schema) {
6449 return -1;
6450 }
6451 } else {
6452 /* root context node */
6453 while (node->parent) {
6454 node = node->parent;
6455 }
6456 while (node->prev->next) {
6457 node = node->prev;
6458 }
6459 }
6460
6461 *ctx_node = node;
6462 *ctx_node_type = node_type;
6463 return EXIT_SUCCESS;
6464 }
6465
6466 /**
6467 * @brief Temporarily unlink nodes as per YANG 1.1 RFC section 7.21.5 for when XPath evaluation.
6468 * The context node is adjusted if needed.
6469 *
6470 * @param[in] snode Schema node, whose children instances need to be unlinked.
6471 * @param[in,out] node Data siblings where to look for the children of \p snode. If it is unlinked,
6472 * it is moved to point to another sibling still in the original tree.
6473 * @param[in,out] ctx_node When context node, adjusted if needed.
6474 * @param[in] ctx_node_type Context node type, just for information to detect invalid situations.
6475 * @param[out] unlinked_nodes Unlinked siblings. Can be safely appended to \p node afterwards.
6476 * Ordering may change, but there will be no semantic change.
6477 *
6478 * @return EXIT_SUCCESS on success, -1 on error.
6479 */
6480 static int
resolve_when_unlink_nodes(struct lys_node * snode,struct lyd_node ** node,struct lyd_node ** ctx_node,enum lyxp_node_type ctx_node_type,struct lyd_node ** unlinked_nodes)6481 resolve_when_unlink_nodes(struct lys_node *snode, struct lyd_node **node, struct lyd_node **ctx_node,
6482 enum lyxp_node_type ctx_node_type, struct lyd_node **unlinked_nodes)
6483 {
6484 struct lyd_node *next, *elem;
6485 const struct lys_node *slast;
6486 struct ly_ctx *ctx = snode->module->ctx;
6487
6488 switch (snode->nodetype) {
6489 case LYS_AUGMENT:
6490 case LYS_USES:
6491 case LYS_CHOICE:
6492 case LYS_CASE:
6493 slast = NULL;
6494 while ((slast = lys_getnext(slast, snode, NULL, LYS_GETNEXT_PARENTUSES))) {
6495 if (slast->nodetype & (LYS_ACTION | LYS_NOTIF)) {
6496 continue;
6497 }
6498
6499 if (resolve_when_unlink_nodes((struct lys_node *)slast, node, ctx_node, ctx_node_type, unlinked_nodes)) {
6500 return -1;
6501 }
6502 }
6503 break;
6504 case LYS_CONTAINER:
6505 case LYS_LIST:
6506 case LYS_LEAF:
6507 case LYS_LEAFLIST:
6508 case LYS_ANYXML:
6509 case LYS_ANYDATA:
6510 LY_TREE_FOR_SAFE(lyd_first_sibling(*node), next, elem) {
6511 if (elem->schema == snode) {
6512
6513 if (elem == *ctx_node) {
6514 /* We are going to unlink our context node! This normally cannot happen,
6515 * but we use normal top-level data nodes for faking a document root node,
6516 * so if this is the context node, we just use the next top-level node.
6517 * Additionally, it can even happen that there are no top-level data nodes left,
6518 * all were unlinked, so in this case we pass NULL as the context node/data tree,
6519 * lyxp_eval() can handle this special situation.
6520 */
6521 if (ctx_node_type == LYXP_NODE_ELEM) {
6522 LOGINT(ctx);
6523 return -1;
6524 }
6525
6526 if (elem->prev == elem) {
6527 /* unlinking last top-level element, use an empty data tree */
6528 *ctx_node = NULL;
6529 } else {
6530 /* in this case just use the previous/last top-level data node */
6531 *ctx_node = elem->prev;
6532 }
6533 } else if (elem == *node) {
6534 /* We are going to unlink the currently processed node. This does not matter that
6535 * much, but we would lose access to the original data tree, so just move our
6536 * pointer somewhere still inside it.
6537 */
6538 if ((*node)->prev != *node) {
6539 *node = (*node)->prev;
6540 } else {
6541 /* the processed node with sibings were all unlinked, oh well */
6542 *node = NULL;
6543 }
6544 }
6545
6546 /* temporarily unlink the node */
6547 lyd_unlink_internal(elem, 0);
6548 if (*unlinked_nodes) {
6549 if (lyd_insert_after((*unlinked_nodes)->prev, elem)) {
6550 LOGINT(ctx);
6551 return -1;
6552 }
6553 } else {
6554 *unlinked_nodes = elem;
6555 }
6556
6557 if (snode->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_ANYDATA)) {
6558 /* there can be only one instance */
6559 break;
6560 }
6561 }
6562 }
6563 break;
6564 default:
6565 LOGINT(ctx);
6566 return -1;
6567 }
6568
6569 return EXIT_SUCCESS;
6570 }
6571
6572 /**
6573 * @brief Relink the unlinked nodes back.
6574 *
6575 * @param[in] node Data node to link the nodes back to. It can actually be the adjusted context node,
6576 * we simply need a sibling from the original data tree.
6577 * @param[in] unlinked_nodes Unlinked nodes to relink to \p node.
6578 * @param[in] ctx_node_type Context node type to distinguish between \p node being the parent
6579 * or the sibling of \p unlinked_nodes.
6580 *
6581 * @return EXIT_SUCCESS on success, -1 on error.
6582 */
6583 static int
resolve_when_relink_nodes(struct lyd_node * node,struct lyd_node * unlinked_nodes,enum lyxp_node_type ctx_node_type)6584 resolve_when_relink_nodes(struct lyd_node *node, struct lyd_node *unlinked_nodes, enum lyxp_node_type ctx_node_type)
6585 {
6586 struct lyd_node *elem;
6587
6588 LY_TREE_FOR_SAFE(unlinked_nodes, unlinked_nodes, elem) {
6589 lyd_unlink_internal(elem, 0);
6590 if (ctx_node_type == LYXP_NODE_ELEM) {
6591 if (lyd_insert_common(node, NULL, elem, 0)) {
6592 return -1;
6593 }
6594 } else {
6595 if (lyd_insert_nextto(node, elem, 0, 0)) {
6596 return -1;
6597 }
6598 }
6599 }
6600
6601 return EXIT_SUCCESS;
6602 }
6603
6604 int
resolve_applies_must(const struct lyd_node * node)6605 resolve_applies_must(const struct lyd_node *node)
6606 {
6607 int ret = 0;
6608 uint8_t must_size;
6609 struct lys_node *schema, *iter;
6610
6611 assert(node);
6612
6613 schema = node->schema;
6614
6615 /* their own must */
6616 switch (schema->nodetype) {
6617 case LYS_CONTAINER:
6618 must_size = ((struct lys_node_container *)schema)->must_size;
6619 break;
6620 case LYS_LEAF:
6621 must_size = ((struct lys_node_leaf *)schema)->must_size;
6622 break;
6623 case LYS_LEAFLIST:
6624 must_size = ((struct lys_node_leaflist *)schema)->must_size;
6625 break;
6626 case LYS_LIST:
6627 must_size = ((struct lys_node_list *)schema)->must_size;
6628 break;
6629 case LYS_ANYXML:
6630 case LYS_ANYDATA:
6631 must_size = ((struct lys_node_anydata *)schema)->must_size;
6632 break;
6633 case LYS_NOTIF:
6634 must_size = ((struct lys_node_notif *)schema)->must_size;
6635 break;
6636 default:
6637 must_size = 0;
6638 break;
6639 }
6640
6641 if (must_size) {
6642 ++ret;
6643 }
6644
6645 /* schema may be a direct data child of input/output with must (but it must be first, it needs to be evaluated only once) */
6646 if (!node->prev->next) {
6647 for (iter = lys_parent(schema); iter && (iter->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES)); iter = lys_parent(iter));
6648 if (iter && (iter->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
6649 ret += 0x2;
6650 }
6651 }
6652
6653 return ret;
6654 }
6655
6656 static struct lys_when *
snode_get_when(const struct lys_node * schema)6657 snode_get_when(const struct lys_node *schema)
6658 {
6659 switch (schema->nodetype) {
6660 case LYS_CONTAINER:
6661 return ((struct lys_node_container *)schema)->when;
6662 case LYS_CHOICE:
6663 return ((struct lys_node_choice *)schema)->when;
6664 case LYS_LEAF:
6665 return ((struct lys_node_leaf *)schema)->when;
6666 case LYS_LEAFLIST:
6667 return ((struct lys_node_leaflist *)schema)->when;
6668 case LYS_LIST:
6669 return ((struct lys_node_list *)schema)->when;
6670 case LYS_ANYDATA:
6671 case LYS_ANYXML:
6672 return ((struct lys_node_anydata *)schema)->when;
6673 case LYS_CASE:
6674 return ((struct lys_node_case *)schema)->when;
6675 case LYS_USES:
6676 return ((struct lys_node_uses *)schema)->when;
6677 case LYS_AUGMENT:
6678 return ((struct lys_node_augment *)schema)->when;
6679 default:
6680 return NULL;
6681 }
6682 }
6683
6684 int
resolve_applies_when(const struct lys_node * schema,int mode,const struct lys_node * stop)6685 resolve_applies_when(const struct lys_node *schema, int mode, const struct lys_node *stop)
6686 {
6687 const struct lys_node *parent;
6688
6689 assert(schema);
6690
6691 if (!(schema->nodetype & (LYS_NOTIF | LYS_RPC)) && snode_get_when(schema)) {
6692 return 1;
6693 }
6694
6695 parent = schema;
6696 goto check_augment;
6697
6698 while (parent) {
6699 /* stop conditions */
6700 if (!mode) {
6701 /* stop on node that can be instantiated in data tree */
6702 if (!(parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
6703 break;
6704 }
6705 } else {
6706 /* stop on the specified node */
6707 if (parent == stop) {
6708 break;
6709 }
6710 }
6711
6712 if (snode_get_when(parent)) {
6713 return 1;
6714 }
6715 check_augment:
6716
6717 if (parent->parent && (parent->parent->nodetype == LYS_AUGMENT) && snode_get_when(parent->parent)) {
6718 return 1;
6719 }
6720 parent = lys_parent(parent);
6721 }
6722
6723 return 0;
6724 }
6725
6726 /**
6727 * @brief Resolve (check) all when conditions relevant for \p node.
6728 * Logs directly.
6729 *
6730 * @param[in] node Data node, whose conditional reference, if such, is being decided.
6731 * @param[in] ignore_fail 1 if when does not have to be satisfied, 2 if it does not have to be satisfied
6732 * only when requiring external dependencies.
6733 *
6734 * @return
6735 * -1 - error, ly_errno is set
6736 * 0 - all "when" statements true
6737 * 0, ly_vecode = LYVE_NOWHEN - some "when" statement false, returned in failed_when
6738 * 1, ly_vecode = LYVE_INWHEN - nodes needed to resolve are conditional and not yet resolved (under another "when")
6739 */
6740 int
resolve_when(struct lyd_node * node,int ignore_fail,struct lys_when ** failed_when)6741 resolve_when(struct lyd_node *node, int ignore_fail, struct lys_when **failed_when)
6742 {
6743 struct lyd_node *ctx_node = NULL, *unlinked_nodes, *tmp_node;
6744 struct lys_node *sparent;
6745 struct lyxp_set set;
6746 enum lyxp_node_type ctx_node_type;
6747 struct ly_ctx *ctx = node->schema->module->ctx;
6748 int rc = 0;
6749
6750 assert(node);
6751 memset(&set, 0, sizeof set);
6752
6753 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC | LYS_ACTION)) && snode_get_when(node->schema)) {
6754 /* make the node dummy for the evaluation */
6755 node->validity |= LYD_VAL_INUSE;
6756 rc = lyxp_eval(snode_get_when(node->schema)->cond, node, LYXP_NODE_ELEM, lyd_node_module(node),
6757 &set, LYXP_WHEN);
6758 node->validity &= ~LYD_VAL_INUSE;
6759 if (rc) {
6760 if (rc == 1) {
6761 LOGVAL(ctx, LYE_INWHEN, LY_VLOG_LYD, node, snode_get_when(node->schema)->cond);
6762 }
6763 goto cleanup;
6764 }
6765
6766 /* set boolean result of the condition */
6767 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_WHEN);
6768 if (!set.val.bool) {
6769 node->when_status |= LYD_WHEN_FALSE;
6770 if ((ignore_fail == 1) || ((snode_get_when(node->schema)->flags & (LYS_XPCONF_DEP | LYS_XPSTATE_DEP))
6771 && (ignore_fail == 2))) {
6772 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.", snode_get_when(node->schema)->cond);
6773 } else {
6774 LOGVAL(ctx, LYE_NOWHEN, LY_VLOG_LYD, node, snode_get_when(node->schema)->cond);
6775 if (failed_when) {
6776 *failed_when = snode_get_when(node->schema);
6777 }
6778 goto cleanup;
6779 }
6780 }
6781
6782 /* free xpath set content */
6783 lyxp_set_cast(&set, LYXP_SET_EMPTY, node, lyd_node_module(node), 0);
6784 }
6785
6786 sparent = node->schema;
6787 goto check_augment;
6788
6789 /* check when in every schema node that affects node */
6790 while (sparent && (sparent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
6791 if (snode_get_when(sparent)) {
6792 if (!ctx_node) {
6793 rc = resolve_when_ctx_node(node, sparent, &ctx_node, &ctx_node_type);
6794 if (rc) {
6795 LOGINT(ctx);
6796 goto cleanup;
6797 }
6798 }
6799
6800 unlinked_nodes = NULL;
6801 /* we do not want our node pointer to change */
6802 tmp_node = node;
6803 rc = resolve_when_unlink_nodes(sparent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
6804 if (rc) {
6805 goto cleanup;
6806 }
6807
6808 rc = lyxp_eval(snode_get_when(sparent)->cond, ctx_node, ctx_node_type, lys_node_module(sparent),
6809 &set, LYXP_WHEN);
6810
6811 if (unlinked_nodes && ctx_node) {
6812 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
6813 rc = -1;
6814 goto cleanup;
6815 }
6816 }
6817
6818 if (rc) {
6819 if (rc == 1) {
6820 LOGVAL(ctx, LYE_INWHEN, LY_VLOG_LYD, node, snode_get_when(sparent)->cond);
6821 }
6822 goto cleanup;
6823 }
6824
6825 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent), LYXP_WHEN);
6826 if (!set.val.bool) {
6827 if ((ignore_fail == 1) || ((snode_get_when(sparent)->flags & (LYS_XPCONF_DEP | LYS_XPSTATE_DEP))
6828 && (ignore_fail == 2))) {
6829 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.", snode_get_when(sparent)->cond);
6830 } else {
6831 node->when_status |= LYD_WHEN_FALSE;
6832 LOGVAL(ctx, LYE_NOWHEN, LY_VLOG_LYD, node, snode_get_when(sparent)->cond);
6833 if (failed_when) {
6834 *failed_when = snode_get_when(sparent);
6835 }
6836 goto cleanup;
6837 }
6838 }
6839
6840 /* free xpath set content */
6841 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent), 0);
6842 }
6843
6844 check_augment:
6845 if ((sparent->parent && (sparent->parent->nodetype == LYS_AUGMENT) && snode_get_when(sparent->parent))) {
6846 if (!ctx_node) {
6847 rc = resolve_when_ctx_node(node, sparent->parent, &ctx_node, &ctx_node_type);
6848 if (rc) {
6849 LOGINT(ctx);
6850 goto cleanup;
6851 }
6852 }
6853
6854 unlinked_nodes = NULL;
6855 tmp_node = node;
6856 rc = resolve_when_unlink_nodes(sparent->parent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
6857 if (rc) {
6858 goto cleanup;
6859 }
6860
6861 rc = lyxp_eval(snode_get_when(sparent->parent)->cond, ctx_node, ctx_node_type,
6862 lys_node_module(sparent->parent), &set, LYXP_WHEN);
6863
6864 /* reconnect nodes, if ctx_node is NULL then all the nodes were unlinked, but linked together,
6865 * so the tree did not actually change and there is nothing for us to do
6866 */
6867 if (unlinked_nodes && ctx_node) {
6868 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
6869 rc = -1;
6870 goto cleanup;
6871 }
6872 }
6873
6874 if (rc) {
6875 if (rc == 1) {
6876 LOGVAL(ctx, LYE_INWHEN, LY_VLOG_LYD, node, snode_get_when(sparent->parent)->cond);
6877 }
6878 goto cleanup;
6879 }
6880
6881 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent->parent), LYXP_WHEN);
6882 if (!set.val.bool) {
6883 node->when_status |= LYD_WHEN_FALSE;
6884 if ((ignore_fail == 1) || ((snode_get_when(sparent->parent)->flags & (LYS_XPCONF_DEP | LYS_XPSTATE_DEP))
6885 && (ignore_fail == 2))) {
6886 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
6887 snode_get_when(sparent->parent)->cond);
6888 } else {
6889 LOGVAL(ctx, LYE_NOWHEN, LY_VLOG_LYD, node, snode_get_when(sparent->parent)->cond);
6890 if (failed_when) {
6891 *failed_when = snode_get_when(sparent->parent);
6892 }
6893 goto cleanup;
6894 }
6895 }
6896
6897 /* free xpath set content */
6898 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent->parent), 0);
6899 }
6900
6901 sparent = lys_parent(sparent);
6902 }
6903
6904 node->when_status |= LYD_WHEN_TRUE;
6905
6906 cleanup:
6907 /* free xpath set content */
6908 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node ? ctx_node : node, NULL, 0);
6909 return rc;
6910 }
6911
6912 static int
check_type_union_leafref(struct lys_type * type)6913 check_type_union_leafref(struct lys_type *type)
6914 {
6915 uint8_t i;
6916
6917 if ((type->base == LY_TYPE_UNION) && type->info.uni.count) {
6918 /* go through unions and look for leafref */
6919 for (i = 0; i < type->info.uni.count; ++i) {
6920 switch (type->info.uni.types[i].base) {
6921 case LY_TYPE_LEAFREF:
6922 return 1;
6923 case LY_TYPE_UNION:
6924 if (check_type_union_leafref(&type->info.uni.types[i])) {
6925 return 1;
6926 }
6927 break;
6928 default:
6929 break;
6930 }
6931 }
6932
6933 return 0;
6934 }
6935
6936 /* just inherit the flag value */
6937 return type->der->has_union_leafref;
6938 }
6939
6940 static void
free_ext_data(struct ly_ctx * ctx,struct unres_ext * ext_data)6941 free_ext_data(struct ly_ctx *ctx, struct unres_ext *ext_data)
6942 {
6943 /* cleanup on success or fatal error */
6944 if (ext_data->datatype == LYS_IN_YIN) {
6945 /* YIN */
6946 lyxml_free(ctx, ext_data->data.yin);
6947 } else {
6948 /* YANG */
6949 yang_free_ext_data(ext_data->data.yang);
6950 }
6951
6952 free(ext_data);
6953 }
6954
6955 /**
6956 * @brief Resolve a single unres schema item. Logs indirectly.
6957 *
6958 * @param[in] mod Main module.
6959 * @param[in] item Item to resolve. Type determined by \p type.
6960 * @param[in] type Type of the unresolved item.
6961 * @param[in] str_snode String, a schema node, or NULL.
6962 * @param[in] unres Unres schema structure to use.
6963 * @param[in] final_fail Whether we are just printing errors of the failed unres items.
6964 *
6965 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
6966 */
6967 static int
resolve_unres_schema_item(struct lys_module * mod,void * item,enum UNRES_ITEM type,void * str_snode,struct unres_schema * unres)6968 resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
6969 struct unres_schema *unres)
6970 {
6971 /* has_str - whether the str_snode is a string in a dictionary that needs to be freed */
6972 int rc = -1, has_str = 0, parent_type = 0, i, k;
6973 unsigned int j;
6974 struct ly_ctx * ctx = mod->ctx;
6975 struct lys_node *root, *next, *node, *par_grp;
6976 const char *expr;
6977 uint8_t *u;
6978
6979 struct ly_set *refs, *procs;
6980 struct lys_feature *ref, *feat;
6981 struct lys_ident *ident;
6982 struct lys_type *stype;
6983 struct lys_node_choice *choic;
6984 struct lyxml_elem *yin;
6985 struct yang_type *yang;
6986 struct unres_list_uniq *unique_info;
6987 struct unres_iffeat_data *iff_data;
6988 struct unres_ext *ext_data;
6989 struct lys_ext_instance *ext, **extlist;
6990 struct lyext_plugin *eplugin;
6991
6992 switch (type) {
6993 case UNRES_IDENT:
6994 expr = str_snode;
6995 has_str = 1;
6996 ident = item;
6997
6998 rc = resolve_base_ident(mod, ident, expr, "identity", NULL, unres);
6999 break;
7000 case UNRES_TYPE_IDENTREF:
7001 expr = str_snode;
7002 has_str = 1;
7003 stype = item;
7004
7005 rc = resolve_base_ident(mod, NULL, expr, "type", stype, unres);
7006 break;
7007 case UNRES_TYPE_LEAFREF:
7008 node = str_snode;
7009 stype = item;
7010
7011 rc = resolve_schema_leafref(stype, node, unres);
7012 break;
7013 case UNRES_TYPE_DER_EXT:
7014 parent_type++;
7015 /* falls through */
7016 case UNRES_TYPE_DER_TPDF:
7017 parent_type++;
7018 /* falls through */
7019 case UNRES_TYPE_DER:
7020 /* parent */
7021 node = str_snode;
7022 stype = item;
7023
7024 /* HACK type->der is temporarily unparsed type statement */
7025 yin = (struct lyxml_elem *)stype->der;
7026 stype->der = NULL;
7027
7028 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
7029 yang = (struct yang_type *)yin;
7030 rc = yang_check_type(mod, node, yang, stype, parent_type, unres);
7031
7032 if (rc) {
7033 /* may try again later */
7034 stype->der = (struct lys_tpdf *)yang;
7035 } else {
7036 /* we need to always be able to free this, it's safe only in this case */
7037 lydict_remove(ctx, yang->name);
7038 free(yang);
7039 }
7040
7041 } else {
7042 rc = fill_yin_type(mod, node, yin, stype, parent_type, unres);
7043 if (!rc || rc == -1) {
7044 /* we need to always be able to free this, it's safe only in this case */
7045 lyxml_free(ctx, yin);
7046 } else {
7047 /* may try again later, put all back how it was */
7048 stype->der = (struct lys_tpdf *)yin;
7049 }
7050 }
7051 if (rc == EXIT_SUCCESS) {
7052 /* it does not make sense to have leaf-list of empty type */
7053 if (!parent_type && node->nodetype == LYS_LEAFLIST && stype->base == LY_TYPE_EMPTY) {
7054 LOGWRN(ctx, "The leaf-list \"%s\" is of \"empty\" type, which does not make sense.", node->name);
7055 }
7056
7057 if ((type == UNRES_TYPE_DER_TPDF) && (stype->base == LY_TYPE_UNION)) {
7058 /* fill typedef union leafref flag */
7059 ((struct lys_tpdf *)stype->parent)->has_union_leafref = check_type_union_leafref(stype);
7060 } else if ((type == UNRES_TYPE_DER) && stype->der->has_union_leafref) {
7061 /* copy the type in case it has union leafref flag */
7062 if (lys_copy_union_leafrefs(mod, node, stype, NULL, unres)) {
7063 LOGERR(ctx, LY_EINT, "Failed to duplicate type.");
7064 return -1;
7065 }
7066 }
7067 } else if (rc == EXIT_FAILURE && !(stype->value_flags & LY_VALUE_UNRESGRP)) {
7068 /* forward reference - in case the type is in grouping, we have to make the grouping unusable
7069 * by uses statement until the type is resolved. We do that the same way as uses statements inside
7070 * grouping. The grouping cannot be used unless the unres counter is 0.
7071 * To remember that the grouping already increased the counter, the LYTYPE_GRP is used as value
7072 * of the type's base member. */
7073 for (par_grp = node; par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
7074 if (par_grp) {
7075 if (++((struct lys_node_grp *)par_grp)->unres_count == 0) {
7076 LOGERR(ctx, LY_EINT, "Too many unresolved items (type) inside a grouping.");
7077 return -1;
7078 }
7079 stype->value_flags |= LY_VALUE_UNRESGRP;
7080 }
7081 }
7082 break;
7083 case UNRES_IFFEAT:
7084 iff_data = str_snode;
7085 rc = resolve_feature(iff_data->fname, strlen(iff_data->fname), iff_data->node, item);
7086 if (!rc) {
7087 /* success */
7088 if (iff_data->infeature) {
7089 /* store backlink into the target feature to allow reverse changes in case of changing feature status */
7090 feat = *((struct lys_feature **)item);
7091 if (!feat->depfeatures) {
7092 feat->depfeatures = ly_set_new();
7093 }
7094 ly_set_add(feat->depfeatures, iff_data->node, LY_SET_OPT_USEASLIST);
7095 }
7096 /* cleanup temporary data */
7097 lydict_remove(ctx, iff_data->fname);
7098 free(iff_data);
7099 }
7100 break;
7101 case UNRES_FEATURE:
7102 feat = (struct lys_feature *)item;
7103
7104 if (feat->iffeature_size) {
7105 refs = ly_set_new();
7106 procs = ly_set_new();
7107 ly_set_add(procs, feat, 0);
7108
7109 while (procs->number) {
7110 ref = procs->set.g[procs->number - 1];
7111 ly_set_rm_index(procs, procs->number - 1);
7112
7113 for (i = 0; i < ref->iffeature_size; i++) {
7114 resolve_iffeature_getsizes(&ref->iffeature[i], NULL, &j);
7115 for (; j > 0 ; j--) {
7116 if (ref->iffeature[i].features[j - 1]) {
7117 if (ref->iffeature[i].features[j - 1] == feat) {
7118 LOGVAL(ctx, LYE_CIRC_FEATURES, LY_VLOG_NONE, NULL, feat->name);
7119 goto featurecheckdone;
7120 }
7121
7122 if (ref->iffeature[i].features[j - 1]->iffeature_size) {
7123 k = refs->number;
7124 if (ly_set_add(refs, ref->iffeature[i].features[j - 1], 0) == k) {
7125 /* not yet seen feature, add it for processing */
7126 ly_set_add(procs, ref->iffeature[i].features[j - 1], 0);
7127 }
7128 }
7129 } else {
7130 /* forward reference */
7131 rc = EXIT_FAILURE;
7132 goto featurecheckdone;
7133 }
7134 }
7135
7136 }
7137 }
7138 rc = EXIT_SUCCESS;
7139
7140 featurecheckdone:
7141 ly_set_free(refs);
7142 ly_set_free(procs);
7143 }
7144
7145 break;
7146 case UNRES_USES:
7147 rc = resolve_unres_schema_uses(item, unres);
7148 break;
7149 case UNRES_TYPEDEF_DFLT:
7150 parent_type++;
7151 /* falls through */
7152 case UNRES_TYPE_DFLT:
7153 stype = item;
7154 rc = check_default(stype, (const char **)str_snode, mod, parent_type);
7155 if ((rc == EXIT_FAILURE) && !parent_type && (stype->base == LY_TYPE_LEAFREF)) {
7156 for (par_grp = (struct lys_node *)stype->parent;
7157 par_grp && (par_grp->nodetype != LYS_GROUPING);
7158 par_grp = lys_parent(par_grp));
7159 if (par_grp) {
7160 /* checking default value in a grouping finished with forward reference means we cannot check the value */
7161 rc = EXIT_SUCCESS;
7162 }
7163 }
7164 break;
7165 case UNRES_CHOICE_DFLT:
7166 expr = str_snode;
7167 has_str = 1;
7168 choic = item;
7169
7170 if (!choic->dflt) {
7171 choic->dflt = resolve_choice_dflt(choic, expr);
7172 }
7173 if (choic->dflt) {
7174 rc = lyp_check_mandatory_choice((struct lys_node *)choic);
7175 } else {
7176 rc = EXIT_FAILURE;
7177 }
7178 break;
7179 case UNRES_LIST_KEYS:
7180 rc = resolve_list_keys(item, ((struct lys_node_list *)item)->keys_str);
7181 break;
7182 case UNRES_LIST_UNIQ:
7183 unique_info = (struct unres_list_uniq *)item;
7184 rc = resolve_unique(unique_info->list, unique_info->expr, unique_info->trg_type);
7185 break;
7186 case UNRES_AUGMENT:
7187 rc = resolve_augment(item, NULL, unres);
7188 break;
7189 case UNRES_XPATH:
7190 node = (struct lys_node *)item;
7191 rc = check_xpath(node, 1);
7192 break;
7193 case UNRES_MOD_IMPLEMENT:
7194 rc = lys_make_implemented_r(mod, unres);
7195 break;
7196 case UNRES_EXT:
7197 ext_data = (struct unres_ext *)str_snode;
7198 extlist = &(*(struct lys_ext_instance ***)item)[ext_data->ext_index];
7199 rc = resolve_extension(ext_data, extlist, unres);
7200 if (!rc && extlist[0]) {
7201 /* success */
7202 /* is there a callback to be done to finalize the extension? */
7203 eplugin = extlist[0]->def->plugin;
7204 if (eplugin) {
7205 if (eplugin->check_result || (eplugin->flags & LYEXT_OPT_INHERIT)) {
7206 u = malloc(sizeof *u);
7207 LY_CHECK_ERR_RETURN(!u, LOGMEM(ctx), -1);
7208 (*u) = ext_data->ext_index;
7209 if (unres_schema_add_node(mod, unres, item, UNRES_EXT_FINALIZE, (struct lys_node *)u) == -1) {
7210 /* something really bad happened since the extension finalization is not actually
7211 * being resolved while adding into unres, so something more serious with the unres
7212 * list itself must happened */
7213 return -1;
7214 }
7215 }
7216 }
7217 }
7218 break;
7219 case UNRES_EXT_FINALIZE:
7220 u = (uint8_t *)str_snode;
7221 ext = (*(struct lys_ext_instance ***)item)[*u];
7222 free(u);
7223
7224 eplugin = ext->def->plugin;
7225
7226 /* inherit */
7227 if ((eplugin->flags & LYEXT_OPT_INHERIT) && (ext->parent_type == LYEXT_PAR_NODE)) {
7228 root = (struct lys_node *)ext->parent;
7229 if (!(root->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
7230 LY_TREE_DFS_BEGIN(root->child, next, node) {
7231 /* first, check if the node already contain instance of the same extension,
7232 * in such a case we won't inherit. In case the node was actually defined as
7233 * augment data, we are supposed to check the same way also the augment node itself */
7234 if (lys_ext_instance_presence(ext->def, node->ext, node->ext_size) != -1) {
7235 goto inherit_dfs_sibling;
7236 } else if (node->parent != root && node->parent->nodetype == LYS_AUGMENT &&
7237 lys_ext_instance_presence(ext->def, node->parent->ext, node->parent->ext_size) != -1) {
7238 goto inherit_dfs_sibling;
7239 }
7240
7241 if (eplugin->check_inherit) {
7242 /* we have a callback to check the inheritance, use it */
7243 switch ((rc = (*eplugin->check_inherit)(ext, node))) {
7244 case 0:
7245 /* yes - continue with the inheriting code */
7246 break;
7247 case 1:
7248 /* no - continue with the node's sibling */
7249 goto inherit_dfs_sibling;
7250 case 2:
7251 /* no, but continue with the children, just skip the inheriting code for this node */
7252 goto inherit_dfs_child;
7253 default:
7254 LOGERR(ctx, LY_EINT, "Plugin's (%s:%s) check_inherit callback returns invalid value (%d),",
7255 ext->def->module->name, ext->def->name, rc);
7256 }
7257 }
7258
7259 /* inherit the extension */
7260 extlist = realloc(node->ext, (node->ext_size + 1) * sizeof *node->ext);
7261 LY_CHECK_ERR_RETURN(!extlist, LOGMEM(ctx), -1);
7262 extlist[node->ext_size] = malloc(sizeof **extlist);
7263 LY_CHECK_ERR_RETURN(!extlist[node->ext_size], LOGMEM(ctx); node->ext = extlist, -1);
7264 memcpy(extlist[node->ext_size], ext, sizeof *ext);
7265 extlist[node->ext_size]->flags |= LYEXT_OPT_INHERIT;
7266
7267 node->ext = extlist;
7268 node->ext_size++;
7269
7270 inherit_dfs_child:
7271 /* modification of - select element for the next run - children first */
7272 if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
7273 next = NULL;
7274 } else {
7275 next = node->child;
7276 }
7277 if (!next) {
7278 inherit_dfs_sibling:
7279 /* no children, try siblings */
7280 next = node->next;
7281 }
7282 while (!next) {
7283 /* go to the parent */
7284 node = lys_parent(node);
7285
7286 /* we are done if we are back in the root (the starter's parent */
7287 if (node == root) {
7288 break;
7289 }
7290
7291 /* parent is already processed, go to its sibling */
7292 next = node->next;
7293 }
7294 }
7295 }
7296 }
7297
7298 /* final check */
7299 if (eplugin->check_result) {
7300 if ((*eplugin->check_result)(ext)) {
7301 LOGERR(ctx, LY_EPLUGIN, "Resolving extension failed.");
7302 return -1;
7303 }
7304 }
7305
7306 rc = 0;
7307 break;
7308 default:
7309 LOGINT(ctx);
7310 break;
7311 }
7312
7313 if (has_str && !rc) {
7314 /* the string is no more needed in case of success.
7315 * In case of forward reference, we will try to resolve the string later */
7316 lydict_remove(ctx, str_snode);
7317 }
7318
7319 return rc;
7320 }
7321
7322 /* logs directly */
7323 static void
print_unres_schema_item_fail(void * item,enum UNRES_ITEM type,void * str_node)7324 print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node)
7325 {
7326 struct lyxml_elem *xml;
7327 struct lyxml_attr *attr;
7328 struct unres_iffeat_data *iff_data;
7329 const char *name = NULL;
7330 struct unres_ext *extinfo;
7331
7332 switch (type) {
7333 case UNRES_IDENT:
7334 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identity", (char *)str_node);
7335 break;
7336 case UNRES_TYPE_IDENTREF:
7337 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identityref", (char *)str_node);
7338 break;
7339 case UNRES_TYPE_LEAFREF:
7340 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "leafref",
7341 ((struct lys_type *)item)->info.lref.path);
7342 break;
7343 case UNRES_TYPE_DER_EXT:
7344 case UNRES_TYPE_DER_TPDF:
7345 case UNRES_TYPE_DER:
7346 xml = (struct lyxml_elem *)((struct lys_type *)item)->der;
7347 if (xml->flags & LY_YANG_STRUCTURE_FLAG) {
7348 name = ((struct yang_type *)xml)->name;
7349 } else {
7350 LY_TREE_FOR(xml->attr, attr) {
7351 if ((attr->type == LYXML_ATTR_STD) && !strcmp(attr->name, "name")) {
7352 name = attr->value;
7353 break;
7354 }
7355 }
7356 assert(attr);
7357 }
7358 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "derived type", name);
7359 break;
7360 case UNRES_IFFEAT:
7361 iff_data = str_node;
7362 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "if-feature", iff_data->fname);
7363 break;
7364 case UNRES_FEATURE:
7365 LOGVRB("There are unresolved if-features for \"%s\" feature circular dependency check, it will be attempted later",
7366 ((struct lys_feature *)item)->name);
7367 break;
7368 case UNRES_USES:
7369 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "uses", ((struct lys_node_uses *)item)->name);
7370 break;
7371 case UNRES_TYPEDEF_DFLT:
7372 case UNRES_TYPE_DFLT:
7373 if (*(char **)str_node) {
7374 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "type default", *(char **)str_node);
7375 } /* else no default value in the type itself, but we are checking some restrictions against
7376 * possible default value of some base type. The failure is caused by not resolved base type,
7377 * so it was already reported */
7378 break;
7379 case UNRES_CHOICE_DFLT:
7380 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "choice default", (char *)str_node);
7381 break;
7382 case UNRES_LIST_KEYS:
7383 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list keys", (char *)str_node);
7384 break;
7385 case UNRES_LIST_UNIQ:
7386 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list unique", (char *)str_node);
7387 break;
7388 case UNRES_AUGMENT:
7389 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "augment target",
7390 ((struct lys_node_augment *)item)->target_name);
7391 break;
7392 case UNRES_XPATH:
7393 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "XPath expressions of",
7394 ((struct lys_node *)item)->name);
7395 break;
7396 case UNRES_EXT:
7397 extinfo = (struct unres_ext *)str_node;
7398 name = extinfo->datatype == LYS_IN_YIN ? extinfo->data.yin->name : NULL; /* TODO YANG extension */
7399 LOGVRB("Resolving extension \"%s\" failed, it will be attempted later.", name);
7400 break;
7401 default:
7402 LOGINT(NULL);
7403 break;
7404 }
7405 }
7406
7407 /**
7408 * @brief Save extension instance parent for Compacting later.
7409 *
7410 * @param[in] ext_parents Extension instance parent set
7411 * @param[in] ext_par_types Extension instance parent type list, same size with ext_parents
7412 * @param[in] ext_list Extension instance array
7413 * @param[in] ext_data Unsolved extension instance data
7414 *
7415 * @return 0 on success, -1 on failure.
7416 */
7417 static int
save_skipped_ext_parent(struct ly_set * ext_parents,struct ly_set * ext_par_types,struct lys_ext_instance ** ext_list,struct unres_ext * ext_data)7418 save_skipped_ext_parent(struct ly_set *ext_parents, struct ly_set *ext_par_types,
7419 struct lys_ext_instance **ext_list, struct unres_ext *ext_data)
7420 {
7421 int rt;
7422
7423 if(!ext_list[ext_data->ext_index]) {
7424 rt = ly_set_add(ext_parents, ext_data->parent, 0);
7425 LY_CHECK_RETURN(rt == -1, rt);
7426 if (ext_parents->number != ext_par_types->number) {
7427 // a new skipped extension instance parent
7428 rt = ly_set_add(ext_par_types, (void *)ext_data->datatype, 1);
7429 LY_CHECK_RETURN(rt == -1, rt);
7430 }
7431 }
7432
7433 return 0;
7434 }
7435
7436 /**
7437 * @brief Remove all NULL items from the extension instance array of given parent.
7438 *
7439 * @param[in] ctx Context with the modules
7440 * @param[in] elem Extension instance parent
7441 * @param[in] elem_type Extension instance parent type
7442 *
7443 * @return 0 on success, -1 on failure.
7444 */
7445 static int
compact_ext_list(struct ly_ctx * ctx,void * elem,LYEXT_PAR elem_type)7446 compact_ext_list(struct ly_ctx *ctx, void *elem, LYEXT_PAR elem_type)
7447 {
7448 int rt;
7449 uint8_t *ext_size = 0, orig_size, i = 0, j = 0;
7450 struct lys_ext_instance ***ext_list = NULL;
7451
7452 rt = lyp_get_ext_list(ctx, elem, elem_type, &ext_list, &ext_size, NULL);
7453 LY_CHECK_RETURN(rt, -1);
7454
7455 orig_size = *ext_size;
7456
7457 while (i < *ext_size) {
7458 if (!(*ext_list)[i]) {
7459 /* this extension is skipped, move all extensions after it */
7460 for (j = i; j < *ext_size - 1; j++) {
7461 (*ext_list)[j] = (*ext_list)[j + 1];
7462 }
7463 --(*ext_size);
7464 } else {
7465 ++i;
7466 }
7467 }
7468
7469 lyp_reduce_ext_list(ext_list, *ext_size, orig_size);
7470
7471 return 0;
7472 }
7473
7474 static int
resolve_unres_schema_types(struct unres_schema * unres,enum UNRES_ITEM types,struct ly_ctx * ctx,int forward_ref,int print_all_errors,uint32_t * resolved)7475 resolve_unres_schema_types(struct unres_schema *unres, enum UNRES_ITEM types, struct ly_ctx *ctx, int forward_ref,
7476 int print_all_errors, uint32_t *resolved)
7477 {
7478 uint32_t i, unres_count, res_count;
7479 int ret = 0, rc;
7480 struct ly_err_item *prev_eitem;
7481 enum int_log_opts prev_ilo;
7482 LY_ERR prev_ly_errno = LY_SUCCESS;
7483 struct ly_set *ext_parents = NULL, *ext_par_types = NULL;
7484
7485 /* if there can be no forward references, every failure is final, so we can print it directly */
7486 if (forward_ref) {
7487 prev_ly_errno = ly_errno;
7488 ly_ilo_change(ctx, ILO_STORE, &prev_ilo, &prev_eitem);
7489 }
7490
7491 if ((types & UNRES_EXT)) {
7492 ext_parents = ly_set_new();
7493 ext_par_types = ly_set_new();
7494 LY_CHECK_ERR_GOTO(!ext_parents || !ext_par_types, ret = -1, finish);
7495 }
7496
7497 do {
7498 unres_count = 0;
7499 res_count = 0;
7500
7501 for (i = 0; i < unres->count; ++i) {
7502 /* UNRES_TYPE_LEAFREF must be resolved (for storing leafref target pointers);
7503 * if-features are resolved here to make sure that we will have all if-features for
7504 * later check of feature circular dependency */
7505 if (unres->type[i] & types) {
7506 ++unres_count;
7507 rc = resolve_unres_schema_item(unres->module[i], unres->item[i], unres->type[i], unres->str_snode[i], unres);
7508 if (unres->type[i] == UNRES_EXT_FINALIZE) {
7509 /* to avoid double free */
7510 unres->type[i] = UNRES_RESOLVED;
7511 }
7512
7513 if (unres->type[i] == UNRES_EXT) {
7514 if (!rc) {
7515 ret = save_skipped_ext_parent(ext_parents, ext_par_types,
7516 *(struct lys_ext_instance***) unres->item[i],
7517 (struct unres_ext*) unres->str_snode[i]);
7518 }
7519 if (!rc || rc == -1) {
7520 free_ext_data(ctx, unres->str_snode[i]);
7521 }
7522 LY_CHECK_GOTO(ret, finish);
7523 }
7524
7525 if (!rc || (unres->type[i] == UNRES_XPATH)) {
7526 /* invalid XPath can never cause an error, only a warning */
7527 if (unres->type[i] == UNRES_LIST_UNIQ) {
7528 /* free the allocated structure */
7529 free(unres->item[i]);
7530 }
7531
7532 unres->type[i] = UNRES_RESOLVED;
7533
7534 ++(*resolved);
7535 ++res_count;
7536 } else if ((rc == EXIT_FAILURE) && forward_ref) {
7537 /* forward reference, erase errors */
7538 ly_err_free_next(ctx, prev_eitem);
7539 } else if (print_all_errors) {
7540 /* just so that we quit the loop */
7541 ++res_count;
7542 ret = -1;
7543 } else {
7544 if (forward_ref) {
7545 ly_ilo_restore(ctx, prev_ilo, prev_eitem, 1);
7546 }
7547 ret = -1;
7548 goto finish;
7549 }
7550 }
7551 }
7552 } while (res_count && (res_count < unres_count));
7553
7554 if (res_count < unres_count) {
7555 assert(forward_ref);
7556 /* just print the errors (but we must free the ones we have and get them again :-/ ) */
7557 ly_ilo_restore(ctx, prev_ilo, prev_eitem, 0);
7558
7559 for (i = 0; i < unres->count; ++i) {
7560 if (unres->type[i] & types) {
7561 resolve_unres_schema_item(unres->module[i], unres->item[i], unres->type[i], unres->str_snode[i], unres);
7562 }
7563 }
7564 ret = -1;
7565 goto finish;
7566 }
7567
7568 if (forward_ref) {
7569 /* restore log */
7570 ly_ilo_restore(ctx, prev_ilo, prev_eitem, 0);
7571 ly_errno = prev_ly_errno;
7572 }
7573
7574 if ((types & UNRES_EXT)) {
7575 assert(ext_parents->number == ext_par_types->number);
7576 for (i = 0; i < ext_parents->number; ++i) {
7577 ret = compact_ext_list(ctx, ext_parents->set.g[i], (LYEXT_PAR)(uintptr_t)ext_parents->set.g[i]);
7578 LY_CHECK_GOTO(ret == -1, finish);
7579 }
7580 }
7581
7582 finish:
7583 ly_set_free(ext_parents);
7584 ly_set_free(ext_par_types);
7585 return ret;
7586 }
7587
7588 /**
7589 * @brief Resolve every unres schema item in the structure. Logs directly.
7590 *
7591 * @param[in] mod Main module.
7592 * @param[in] unres Unres schema structure to use.
7593 *
7594 * @return EXIT_SUCCESS on success, -1 on error.
7595 */
7596 int
resolve_unres_schema(struct lys_module * mod,struct unres_schema * unres)7597 resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
7598 {
7599 uint32_t resolved = 0;
7600
7601 assert(unres);
7602
7603 LOGVRB("Resolving \"%s\" unresolved schema nodes and their constraints...", mod->name);
7604
7605 /* UNRES_TYPE_LEAFREF must be resolved (for storing leafref target pointers);
7606 * if-features are resolved here to make sure that we will have all if-features for
7607 * later check of feature circular dependency */
7608 if (resolve_unres_schema_types(unres, UNRES_USES | UNRES_IFFEAT | UNRES_TYPE_DER | UNRES_TYPE_DER_TPDF | UNRES_TYPE_DER_TPDF
7609 | UNRES_AUGMENT | UNRES_CHOICE_DFLT | UNRES_IDENT,
7610 mod->ctx, 1, 0, &resolved)) {
7611 return -1;
7612 }
7613
7614 if (resolve_unres_schema_types(unres, UNRES_MOD_IMPLEMENT, mod->ctx, 1, 0, &resolved)) {
7615 return -1;
7616 }
7617
7618 /* another batch of resolved items (UNRES_MOD_IMPLEMENT must be set again because it can be added again) */
7619 if (resolve_unres_schema_types(unres, UNRES_TYPE_IDENTREF | UNRES_FEATURE | UNRES_TYPEDEF_DFLT | UNRES_TYPE_DFLT
7620 | UNRES_TYPE_LEAFREF | UNRES_LIST_KEYS | UNRES_LIST_UNIQ | UNRES_EXT | UNRES_MOD_IMPLEMENT,
7621 mod->ctx, 1, 0, &resolved)) {
7622 return -1;
7623 }
7624
7625 /* print xpath warnings and finalize extensions, keep it last to provide the complete schema tree information to the plugin's checkers */
7626 if (resolve_unres_schema_types(unres, UNRES_XPATH | UNRES_EXT_FINALIZE, mod->ctx, 0, 1, &resolved)) {
7627 return -1;
7628 }
7629
7630 LOGVRB("All \"%s\" schema nodes and constraints resolved.", mod->name);
7631 unres->count = 0;
7632 return EXIT_SUCCESS;
7633 }
7634
7635 /**
7636 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
7637 *
7638 * @param[in] mod Main module.
7639 * @param[in] unres Unres schema structure to use.
7640 * @param[in] item Item to resolve. Type determined by \p type.
7641 * @param[in] type Type of the unresolved item.
7642 * @param[in] str String argument.
7643 *
7644 * @return EXIT_SUCCESS on success, EXIT_FAILURE on storing the item in unres, -1 on error.
7645 */
7646 int
unres_schema_add_str(struct lys_module * mod,struct unres_schema * unres,void * item,enum UNRES_ITEM type,const char * str)7647 unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
7648 const char *str)
7649 {
7650 int rc;
7651 const char *dictstr;
7652
7653 dictstr = lydict_insert(mod->ctx, str, 0);
7654 rc = unres_schema_add_node(mod, unres, item, type, (struct lys_node *)dictstr);
7655
7656 if (rc < 0) {
7657 lydict_remove(mod->ctx, dictstr);
7658 }
7659 return rc;
7660 }
7661
7662 /**
7663 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
7664 *
7665 * @param[in] mod Main module.
7666 * @param[in] unres Unres schema structure to use.
7667 * @param[in] item Item to resolve. Type determined by \p type.
7668 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
7669 * @param[in] snode Schema node argument.
7670 *
7671 * @return EXIT_SUCCESS on success, EXIT_FAILURE on storing the item in unres, -1 on error.
7672 */
7673 int
unres_schema_add_node(struct lys_module * mod,struct unres_schema * unres,void * item,enum UNRES_ITEM type,struct lys_node * snode)7674 unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
7675 struct lys_node *snode)
7676 {
7677 int rc;
7678 uint32_t u;
7679 enum int_log_opts prev_ilo;
7680 struct ly_err_item *prev_eitem;
7681 LY_ERR prev_ly_errno;
7682 struct lyxml_elem *yin;
7683 struct lys_type *stype;
7684 struct ly_ctx *ctx = mod->ctx;
7685
7686 assert(unres && (item || (type == UNRES_MOD_IMPLEMENT)) && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID)
7687 && (type != UNRES_WHEN) && (type != UNRES_MUST)));
7688
7689 /* check for duplicities in unres */
7690 for (u = 0; u < unres->count; u++) {
7691 if (unres->type[u] == type && unres->item[u] == item &&
7692 unres->str_snode[u] == snode && unres->module[u] == mod) {
7693 /* duplication can happen when the node contains multiple statements of the same type to check,
7694 * this can happen for example when refinement is being applied, so we just postpone the processing
7695 * and do not duplicate the information */
7696 return EXIT_FAILURE;
7697 }
7698 }
7699
7700 if ((type == UNRES_EXT_FINALIZE) || (type == UNRES_XPATH) || (type == UNRES_MOD_IMPLEMENT)) {
7701 /* extension finalization is not even tried when adding the item into the inres list,
7702 * xpath is not tried because it would hide some potential warnings,
7703 * implementing module must be deferred because some other nodes can be added that will need to be traversed
7704 * and their targets made implemented */
7705 rc = EXIT_FAILURE;
7706 } else {
7707 prev_ly_errno = ly_errno;
7708 ly_ilo_change(ctx, ILO_STORE, &prev_ilo, &prev_eitem);
7709
7710 rc = resolve_unres_schema_item(mod, item, type, snode, unres);
7711 if (rc != EXIT_FAILURE) {
7712 if (type == UNRES_EXT) {
7713 free_ext_data(mod->ctx, (struct unres_ext*)snode);
7714 }
7715 ly_ilo_restore(ctx, prev_ilo, prev_eitem, rc == -1 ? 1 : 0);
7716 if (rc != -1) {
7717 /* print warnings here so that they are actually printed */
7718 if ((type == UNRES_TYPE_DER_TPDF) || (type == UNRES_TYPE_DER)) {
7719 stype = item;
7720 if (stype->der->module && (((stype->base == LY_TYPE_LEAFREF)
7721 && (stype->info.lref.req != stype->der->type.info.lref.req)) || ((stype->base == LY_TYPE_INST)
7722 && (stype->info.inst.req != stype->der->type.info.inst.req)))) {
7723 if (type == UNRES_TYPE_DER_TPDF) {
7724 /* typedef */
7725 LOGWRN(ctx, "Derived typedef \"%s\" is changing the \"require-instance\" property, "
7726 "which is discouraged.", stype->parent->name);
7727 } else {
7728 /* leaf */
7729 LOGWRN(ctx, "Node \"%s\" type is changing the \"require-instance\" property, "
7730 "which is discouraged.", snode->name);
7731 }
7732 }
7733 }
7734 ly_errno = prev_ly_errno;
7735 }
7736
7737 if (type == UNRES_LIST_UNIQ) {
7738 /* free the allocated structure */
7739 free(item);
7740 } else if (rc == -1 && type == UNRES_IFFEAT) {
7741 /* free the allocated resources */
7742 free(*((char **)item));
7743 }
7744 return rc;
7745 } else {
7746 /* erase info about validation errors */
7747 ly_ilo_restore(ctx, prev_ilo, prev_eitem, 0);
7748 ly_errno = prev_ly_errno;
7749 }
7750
7751 print_unres_schema_item_fail(item, type, snode);
7752
7753 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
7754 if (type == UNRES_TYPE_DER || type == UNRES_TYPE_DER_TPDF) {
7755 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
7756 if (!(yin->flags & LY_YANG_STRUCTURE_FLAG)) {
7757 lyxml_unlink_elem(mod->ctx, yin, 1);
7758 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
7759 }
7760 }
7761 }
7762
7763 unres->count++;
7764 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
7765 LY_CHECK_ERR_RETURN(!unres->item, LOGMEM(ctx), -1);
7766 unres->item[unres->count-1] = item;
7767 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
7768 LY_CHECK_ERR_RETURN(!unres->type, LOGMEM(ctx), -1);
7769 unres->type[unres->count-1] = type;
7770 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
7771 LY_CHECK_ERR_RETURN(!unres->str_snode, LOGMEM(ctx), -1);
7772 unres->str_snode[unres->count-1] = snode;
7773 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
7774 LY_CHECK_ERR_RETURN(!unres->module, LOGMEM(ctx), -1);
7775 unres->module[unres->count-1] = mod;
7776
7777 return rc;
7778 }
7779
7780 /**
7781 * @brief Duplicate an unres schema item. Logs indirectly.
7782 *
7783 * @param[in] mod Main module.
7784 * @param[in] unres Unres schema structure to use.
7785 * @param[in] item Old item to be resolved.
7786 * @param[in] type Type of the old unresolved item.
7787 * @param[in] new_item New item to use in the duplicate.
7788 *
7789 * @return EXIT_SUCCESS on success, EXIT_FAILURE if item is not in unres, -1 on error.
7790 */
7791 int
unres_schema_dup(struct lys_module * mod,struct unres_schema * unres,void * item,enum UNRES_ITEM type,void * new_item)7792 unres_schema_dup(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type, void *new_item)
7793 {
7794 int i;
7795 struct unres_list_uniq aux_uniq;
7796 struct unres_iffeat_data *iff_data;
7797
7798 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
7799
7800 /* hack for UNRES_LIST_UNIQ, which stores multiple items behind its item */
7801 if (type == UNRES_LIST_UNIQ) {
7802 aux_uniq.list = item;
7803 aux_uniq.expr = ((struct unres_list_uniq *)new_item)->expr;
7804 item = &aux_uniq;
7805 }
7806 i = unres_schema_find(unres, -1, item, type);
7807
7808 if (i == -1) {
7809 if (type == UNRES_LIST_UNIQ) {
7810 free(new_item);
7811 }
7812 return EXIT_FAILURE;
7813 }
7814
7815 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT) ||
7816 (type == UNRES_FEATURE) || (type == UNRES_LIST_UNIQ)) {
7817 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
7818 LOGINT(mod->ctx);
7819 return -1;
7820 }
7821 } else if (type == UNRES_IFFEAT) {
7822 /* duplicate unres_iffeature_data */
7823 iff_data = malloc(sizeof *iff_data);
7824 LY_CHECK_ERR_RETURN(!iff_data, LOGMEM(mod->ctx), -1);
7825 iff_data->fname = lydict_insert(mod->ctx, ((struct unres_iffeat_data *)unres->str_snode[i])->fname, 0);
7826 iff_data->node = ((struct unres_iffeat_data *)unres->str_snode[i])->node;
7827 iff_data->infeature = ((struct unres_iffeat_data *)unres->str_snode[i])->infeature;
7828 if (unres_schema_add_node(mod, unres, new_item, type, (struct lys_node *)iff_data) == -1) {
7829 LOGINT(mod->ctx);
7830 return -1;
7831 }
7832 } else {
7833 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
7834 LOGINT(mod->ctx);
7835 return -1;
7836 }
7837 }
7838
7839 return EXIT_SUCCESS;
7840 }
7841
7842 /* does not log */
7843 int
unres_schema_find(struct unres_schema * unres,int start_on_backwards,void * item,enum UNRES_ITEM type)7844 unres_schema_find(struct unres_schema *unres, int start_on_backwards, void *item, enum UNRES_ITEM type)
7845 {
7846 int i;
7847 struct unres_list_uniq *aux_uniq1, *aux_uniq2;
7848
7849 if (!unres->count) {
7850 return -1;
7851 }
7852
7853 if (start_on_backwards >= 0) {
7854 i = start_on_backwards;
7855 } else {
7856 i = unres->count - 1;
7857 }
7858 for (; i > -1; i--) {
7859 if (unres->type[i] != type) {
7860 continue;
7861 }
7862 if (type != UNRES_LIST_UNIQ) {
7863 if (unres->item[i] == item) {
7864 break;
7865 }
7866 } else {
7867 aux_uniq1 = (struct unres_list_uniq *)unres->item[i];
7868 aux_uniq2 = (struct unres_list_uniq *)item;
7869 if ((aux_uniq1->list == aux_uniq2->list) && ly_strequal(aux_uniq1->expr, aux_uniq2->expr, 0)) {
7870 break;
7871 }
7872 }
7873 }
7874
7875 return i;
7876 }
7877
7878 static void
unres_schema_free_item(struct ly_ctx * ctx,struct unres_schema * unres,uint32_t i)7879 unres_schema_free_item(struct ly_ctx *ctx, struct unres_schema *unres, uint32_t i)
7880 {
7881 struct lyxml_elem *yin;
7882 struct yang_type *yang;
7883 struct unres_iffeat_data *iff_data;
7884
7885 switch (unres->type[i]) {
7886 case UNRES_TYPE_DER_TPDF:
7887 case UNRES_TYPE_DER:
7888 yin = (struct lyxml_elem *)((struct lys_type *)unres->item[i])->der;
7889 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
7890 yang =(struct yang_type *)yin;
7891 ((struct lys_type *)unres->item[i])->base = yang->base;
7892 lydict_remove(ctx, yang->name);
7893 free(yang);
7894 if (((struct lys_type *)unres->item[i])->base == LY_TYPE_UNION) {
7895 yang_free_type_union(ctx, (struct lys_type *)unres->item[i]);
7896 }
7897 } else {
7898 lyxml_free(ctx, yin);
7899 }
7900 break;
7901 case UNRES_IFFEAT:
7902 iff_data = (struct unres_iffeat_data *)unres->str_snode[i];
7903 lydict_remove(ctx, iff_data->fname);
7904 free(unres->str_snode[i]);
7905 break;
7906 case UNRES_IDENT:
7907 case UNRES_TYPE_IDENTREF:
7908 case UNRES_CHOICE_DFLT:
7909 case UNRES_LIST_KEYS:
7910 lydict_remove(ctx, (const char *)unres->str_snode[i]);
7911 break;
7912 case UNRES_LIST_UNIQ:
7913 free(unres->item[i]);
7914 break;
7915 case UNRES_EXT:
7916 free_ext_data(ctx, unres->str_snode[i]);
7917 break;
7918 case UNRES_EXT_FINALIZE:
7919 free(unres->str_snode[i]);
7920 default:
7921 break;
7922 }
7923 unres->type[i] = UNRES_RESOLVED;
7924 }
7925
7926 void
unres_schema_free(struct lys_module * module,struct unres_schema ** unres,int all)7927 unres_schema_free(struct lys_module *module, struct unres_schema **unres, int all)
7928 {
7929 uint32_t i;
7930 unsigned int unresolved = 0;
7931
7932 if (!unres || !(*unres)) {
7933 return;
7934 }
7935
7936 assert(module || ((*unres)->count == 0));
7937
7938 for (i = 0; i < (*unres)->count; ++i) {
7939 if (!all && ((*unres)->module[i] != module)) {
7940 if ((*unres)->type[i] != UNRES_RESOLVED) {
7941 unresolved++;
7942 }
7943 continue;
7944 }
7945
7946 /* free heap memory for the specific item */
7947 unres_schema_free_item(module->ctx, *unres, i);
7948 }
7949
7950 /* free it all */
7951 if (!module || all || (!unresolved && !module->type)) {
7952 free((*unres)->item);
7953 free((*unres)->type);
7954 free((*unres)->str_snode);
7955 free((*unres)->module);
7956 free((*unres));
7957 (*unres) = NULL;
7958 }
7959 }
7960
7961 /* check whether instance-identifier points outside its data subtree (for operation it is any node
7962 * outside the operation subtree, otherwise it is a node from a foreign model) */
7963 static int
check_instid_ext_dep(const struct lys_node * sleaf,const char * json_instid)7964 check_instid_ext_dep(const struct lys_node *sleaf, const char *json_instid)
7965 {
7966 const struct lys_node *op_node, *first_node;
7967 enum int_log_opts prev_ilo;
7968 char *buf, *tmp;
7969
7970 if (!json_instid || !json_instid[0]) {
7971 /* no/empty value */
7972 return 0;
7973 }
7974
7975 for (op_node = lys_parent(sleaf);
7976 op_node && !(op_node->nodetype & (LYS_NOTIF | LYS_RPC | LYS_ACTION));
7977 op_node = lys_parent(op_node));
7978
7979 if (op_node && lys_parent(op_node)) {
7980 /* nested operation - any absolute path is external */
7981 return 1;
7982 }
7983
7984 /* get the first node from the instid */
7985 tmp = strchr(json_instid + 1, '/');
7986 buf = strndup(json_instid, tmp ? (size_t)(tmp - json_instid) : strlen(json_instid));
7987 if (!buf) {
7988 /* so that we do not have to bother with logging, say it is not external */
7989 return 0;
7990 }
7991
7992 /* find the first schema node, do not log */
7993 ly_ilo_change(NULL, ILO_IGNORE, &prev_ilo, NULL);
7994 first_node = ly_ctx_get_node(NULL, sleaf, buf, 0);
7995 ly_ilo_restore(NULL, prev_ilo, NULL, 0);
7996
7997 free(buf);
7998 if (!first_node) {
7999 /* unknown path, say it is external */
8000 return 1;
8001 }
8002
8003 /* based on the first schema node in the path we can decide whether it points to an external tree or not */
8004
8005 if (op_node) {
8006 if (op_node != first_node) {
8007 /* it is a top-level operation, so we're good if it points somewhere inside it */
8008 return 1;
8009 }
8010 } else {
8011 if (lys_node_module(sleaf) != lys_node_module(first_node)) {
8012 /* modules differ */
8013 return 1;
8014 }
8015 }
8016
8017 return 0;
8018 }
8019
8020 int
resolve_instid(struct lyd_node * data,const char * path,int req_inst,struct lyd_node ** ret)8021 resolve_instid(struct lyd_node *data, const char *path, int req_inst, struct lyd_node **ret)
8022 {
8023 int i = 0, j, parsed, cur_idx;
8024 const struct lys_module *mod, *prev_mod = NULL;
8025 struct ly_ctx *ctx = data->schema->module->ctx;
8026 struct lyd_node *root, *node;
8027 const char *model = NULL, *name;
8028 char *str;
8029 int mod_len, name_len, has_predicate;
8030 struct unres_data node_match;
8031
8032 memset(&node_match, 0, sizeof node_match);
8033 *ret = NULL;
8034
8035 /* we need root to resolve absolute path */
8036 for (root = data; root->parent; root = root->parent);
8037 /* we're still parsing it and the pointer is not correct yet */
8038 if (root->prev) {
8039 for (; root->prev->next; root = root->prev);
8040 }
8041
8042 /* search for the instance node */
8043 while (path[i]) {
8044 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
8045 if (j <= 0) {
8046 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
8047 goto error;
8048 }
8049 i += j;
8050
8051 if (model) {
8052 str = strndup(model, mod_len);
8053 if (!str) {
8054 LOGMEM(ctx);
8055 goto error;
8056 }
8057 mod = ly_ctx_get_module(ctx, str, NULL, 1);
8058 if (ctx->data_clb) {
8059 if (!mod) {
8060 mod = ctx->data_clb(ctx, str, NULL, 0, ctx->data_clb_data);
8061 } else if (!mod->implemented) {
8062 mod = ctx->data_clb(ctx, mod->name, mod->ns, LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
8063 }
8064 }
8065 free(str);
8066
8067 if (!mod || !mod->implemented || mod->disabled) {
8068 break;
8069 }
8070 } else if (!prev_mod) {
8071 /* first iteration and we are missing module name */
8072 LOGVAL(ctx, LYE_INELEM_LEN, LY_VLOG_LYD, data, name_len, name);
8073 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Instance-identifier is missing prefix in the first node.");
8074 goto error;
8075 } else {
8076 mod = prev_mod;
8077 }
8078
8079 if (resolve_data(mod, name, name_len, root, &node_match)) {
8080 /* no instance exists */
8081 break;
8082 }
8083
8084 if (has_predicate) {
8085 /* we have predicate, so the current results must be list or leaf-list */
8086 parsed = j = 0;
8087 /* index of the current node (for lists with position predicates) */
8088 cur_idx = 1;
8089 while (j < (signed)node_match.count) {
8090 node = node_match.node[j];
8091 parsed = resolve_instid_predicate(mod, &path[i], &node, cur_idx);
8092 if (parsed < 1) {
8093 LOGVAL(ctx, LYE_INPRED, LY_VLOG_LYD, data, &path[i - parsed]);
8094 goto error;
8095 }
8096
8097 if (!node) {
8098 /* current node does not satisfy the predicate */
8099 unres_data_del(&node_match, j);
8100 } else {
8101 ++j;
8102 }
8103 ++cur_idx;
8104 }
8105
8106 i += parsed;
8107 } else if (node_match.count) {
8108 /* check that we are not addressing lists */
8109 for (j = 0; (unsigned)j < node_match.count; ++j) {
8110 if (node_match.node[j]->schema->nodetype == LYS_LIST) {
8111 unres_data_del(&node_match, j--);
8112 }
8113 }
8114 if (!node_match.count) {
8115 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYD, data, "Instance identifier is missing list keys.");
8116 }
8117 }
8118
8119 prev_mod = mod;
8120 }
8121
8122 if (!node_match.count) {
8123 /* no instance exists */
8124 if (req_inst > -1) {
8125 LOGVAL(ctx, LYE_NOREQINS, LY_VLOG_LYD, data, path);
8126 return EXIT_FAILURE;
8127 }
8128 LOGVRB("There is no instance of \"%s\", but it is not required.", path);
8129 return EXIT_SUCCESS;
8130 } else if (node_match.count > 1) {
8131 /* instance identifier must resolve to a single node */
8132 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
8133 goto error;
8134 } else {
8135 /* we have required result, remember it and cleanup */
8136 *ret = node_match.node[0];
8137 free(node_match.node);
8138 return EXIT_SUCCESS;
8139 }
8140
8141 error:
8142 /* cleanup */
8143 free(node_match.node);
8144 return -1;
8145 }
8146
8147 int
resolve_leafref(struct lyd_node_leaf_list * leaf,const char * path,int req_inst,struct lyd_node ** ret)8148 resolve_leafref(struct lyd_node_leaf_list *leaf, const char *path, int req_inst, struct lyd_node **ret)
8149 {
8150 struct lyxp_set xp_set;
8151 uint32_t i;
8152
8153 memset(&xp_set, 0, sizeof xp_set);
8154 *ret = NULL;
8155
8156 /* syntax was already checked, so just evaluate the path using standard XPath */
8157 if (lyxp_eval(path, (struct lyd_node *)leaf, LYXP_NODE_ELEM, lyd_node_module((struct lyd_node *)leaf), &xp_set, 0) != EXIT_SUCCESS) {
8158 return -1;
8159 }
8160
8161 if (xp_set.type == LYXP_SET_NODE_SET) {
8162 for (i = 0; i < xp_set.used; ++i) {
8163 if ((xp_set.val.nodes[i].type != LYXP_NODE_ELEM) || !(xp_set.val.nodes[i].node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
8164 continue;
8165 }
8166
8167 /* not that the value is already in canonical form since the parsers does the conversion,
8168 * so we can simply compare just the values */
8169 if (ly_strequal(leaf->value_str, ((struct lyd_node_leaf_list *)xp_set.val.nodes[i].node)->value_str, 1)) {
8170 /* we have the match */
8171 *ret = xp_set.val.nodes[i].node;
8172 break;
8173 }
8174 }
8175 }
8176
8177 lyxp_set_cast(&xp_set, LYXP_SET_EMPTY, (struct lyd_node *)leaf, NULL, 0);
8178
8179 if (!*ret) {
8180 /* reference not found */
8181 if (req_inst > -1) {
8182 LOGVAL(leaf->schema->module->ctx, LYE_NOLEAFREF, LY_VLOG_LYD, leaf, path, leaf->value_str);
8183 return EXIT_FAILURE;
8184 } else {
8185 LOGVRB("There is no leafref \"%s\" with the value \"%s\", but it is not required.", path, leaf->value_str);
8186 }
8187 }
8188
8189 return EXIT_SUCCESS;
8190 }
8191
8192 /* ignore fail because we are parsing edit-config, get, or get-config - but only if the union includes leafref or instid */
8193 int
resolve_union(struct lyd_node_leaf_list * leaf,struct lys_type * type,int store,int ignore_fail,struct lys_type ** resolved_type)8194 resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type, int store, int ignore_fail,
8195 struct lys_type **resolved_type)
8196 {
8197 struct ly_ctx *ctx = leaf->schema->module->ctx;
8198 struct lys_type *t;
8199 struct lyd_node *ret;
8200 enum int_log_opts prev_ilo;
8201 int found, success = 0, ext_dep, req_inst;
8202 const char *json_val = NULL;
8203
8204 assert(type->base == LY_TYPE_UNION);
8205
8206 if ((leaf->value_type == LY_TYPE_UNION) || ((leaf->value_type == LY_TYPE_INST) && (leaf->value_flags & LY_VALUE_UNRES))) {
8207 /* either NULL or instid previously converted to JSON */
8208 json_val = lydict_insert(ctx, leaf->value.string, 0);
8209 }
8210
8211 if (store) {
8212 lyd_free_value(leaf->value, leaf->value_type, leaf->value_flags, &((struct lys_node_leaf *)leaf->schema)->type,
8213 leaf->value_str, NULL, NULL, NULL);
8214 memset(&leaf->value, 0, sizeof leaf->value);
8215 }
8216
8217 /* turn logging off, we are going to try to validate the value with all the types in order */
8218 ly_ilo_change(NULL, ILO_IGNORE, &prev_ilo, 0);
8219
8220 t = NULL;
8221 found = 0;
8222 while ((t = lyp_get_next_union_type(type, t, &found))) {
8223 found = 0;
8224
8225 switch (t->base) {
8226 case LY_TYPE_LEAFREF:
8227 if ((ignore_fail == 1) || ((leaf->schema->flags & LYS_LEAFREF_DEP) && (ignore_fail == 2))) {
8228 req_inst = -1;
8229 } else {
8230 req_inst = t->info.lref.req;
8231 }
8232
8233 if (!resolve_leafref(leaf, t->info.lref.path, req_inst, &ret)) {
8234 if (store) {
8235 if (ret && !(leaf->schema->flags & LYS_LEAFREF_DEP)) {
8236 /* valid resolved */
8237 leaf->value.leafref = ret;
8238 leaf->value_type = LY_TYPE_LEAFREF;
8239 } else {
8240 /* valid unresolved */
8241 ly_ilo_restore(NULL, prev_ilo, NULL, 0);
8242 if (!lyp_parse_value(t, &leaf->value_str, NULL, leaf, NULL, NULL, 1, 0)) {
8243 return -1;
8244 }
8245 ly_ilo_change(NULL, ILO_IGNORE, &prev_ilo, NULL);
8246 }
8247 }
8248
8249 success = 1;
8250 }
8251 break;
8252 case LY_TYPE_INST:
8253 ext_dep = check_instid_ext_dep(leaf->schema, (json_val ? json_val : leaf->value_str));
8254 if ((ignore_fail == 1) || (ext_dep && (ignore_fail == 2))) {
8255 req_inst = -1;
8256 } else {
8257 req_inst = t->info.inst.req;
8258 }
8259
8260 if (!resolve_instid((struct lyd_node *)leaf, (json_val ? json_val : leaf->value_str), req_inst, &ret)) {
8261 if (store) {
8262 if (ret && !ext_dep) {
8263 /* valid resolved */
8264 leaf->value.instance = ret;
8265 leaf->value_type = LY_TYPE_INST;
8266
8267 if (json_val) {
8268 lydict_remove(leaf->schema->module->ctx, leaf->value_str);
8269 leaf->value_str = json_val;
8270 json_val = NULL;
8271 }
8272 } else {
8273 /* valid unresolved */
8274 if (json_val) {
8275 /* put the JSON val back */
8276 leaf->value.string = json_val;
8277 json_val = NULL;
8278 } else {
8279 leaf->value.instance = NULL;
8280 }
8281 leaf->value_type = LY_TYPE_INST;
8282 leaf->value_flags |= LY_VALUE_UNRES;
8283 }
8284 }
8285
8286 success = 1;
8287 }
8288 break;
8289 default:
8290 if (lyp_parse_value(t, &leaf->value_str, NULL, leaf, NULL, NULL, store, 0)) {
8291 success = 1;
8292 }
8293 break;
8294 }
8295
8296 if (success) {
8297 break;
8298 }
8299
8300 /* erase possible present and invalid value data */
8301 if (store) {
8302 lyd_free_value(leaf->value, leaf->value_type, leaf->value_flags, t, leaf->value_str, NULL, NULL, NULL);
8303 memset(&leaf->value, 0, sizeof leaf->value);
8304 }
8305 }
8306
8307 /* turn logging back on */
8308 ly_ilo_restore(NULL, prev_ilo, NULL, 0);
8309
8310 if (json_val) {
8311 if (!success) {
8312 /* put the value back for now */
8313 assert(leaf->value_type == LY_TYPE_UNION);
8314 leaf->value.string = json_val;
8315 } else {
8316 /* value was ultimately useless, but we could not have known */
8317 lydict_remove(leaf->schema->module->ctx, json_val);
8318 }
8319 }
8320
8321 if (success) {
8322 if (resolved_type) {
8323 *resolved_type = t;
8324 }
8325 } else if (!ignore_fail || !type->info.uni.has_ptr_type) {
8326 /* not found and it is required */
8327 LOGVAL(ctx, LYE_INVAL, LY_VLOG_LYD, leaf, leaf->value_str ? leaf->value_str : "", leaf->schema->name);
8328 return EXIT_FAILURE;
8329 }
8330
8331 return EXIT_SUCCESS;
8332
8333 }
8334
8335 /**
8336 * @brief Resolve a single unres data item. Logs directly.
8337 *
8338 * @param[in] node Data node to resolve.
8339 * @param[in] type Type of the unresolved item.
8340 * @param[in] ignore_fail 0 - no, 1 - yes, 2 - yes, but only for external dependencies.
8341 * @param[in] multi_error 0 - no, 1 - yes.
8342 *
8343 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
8344 */
8345 int
resolve_unres_data_item(struct lyd_node * node,enum UNRES_ITEM type,int ignore_fail,int multi_error,struct lys_when ** failed_when)8346 resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type, int ignore_fail, int multi_error,
8347 struct lys_when **failed_when)
8348 {
8349 int rc, req_inst, ext_dep;
8350 struct lyd_node_leaf_list *leaf;
8351 struct lyd_node *ret;
8352 struct lys_node_leaf *sleaf;
8353
8354 leaf = (struct lyd_node_leaf_list *)node;
8355 sleaf = (struct lys_node_leaf *)leaf->schema;
8356
8357 switch (type) {
8358 case UNRES_LEAFREF:
8359 assert(sleaf->type.base == LY_TYPE_LEAFREF);
8360 if (ignore_fail) {
8361 req_inst = -1;
8362 } else {
8363 req_inst = sleaf->type.info.lref.req;
8364 }
8365 if ((leaf->schema->flags & LYS_LEAFREF_DEP) && (ignore_fail == 2)) {
8366 /* do not even try to resolve */
8367 rc = 0;
8368 ret = NULL;
8369 } else {
8370 rc = resolve_leafref(leaf, sleaf->type.info.lref.path, req_inst, &ret);
8371 }
8372 if (!rc) {
8373 if (ret && !(leaf->schema->flags & LYS_LEAFREF_DEP)) {
8374 /* valid resolved */
8375 if (leaf->value_type == LY_TYPE_BITS) {
8376 free(leaf->value.bit);
8377 }
8378 leaf->value.leafref = ret;
8379 leaf->value_type = LY_TYPE_LEAFREF;
8380 leaf->value_flags &= ~LY_VALUE_UNRES;
8381 } else {
8382 /* valid unresolved */
8383 if (!(leaf->value_flags & LY_VALUE_UNRES)) {
8384 if (!lyp_parse_value(&sleaf->type, &leaf->value_str, NULL, leaf, NULL, NULL, 1, 0)) {
8385 return -1;
8386 }
8387 }
8388 }
8389 } else {
8390 return rc;
8391 }
8392 break;
8393
8394 case UNRES_INSTID:
8395 assert(sleaf->type.base == LY_TYPE_INST);
8396 ext_dep = check_instid_ext_dep(leaf->schema, leaf->value_str);
8397 if (ext_dep == -1) {
8398 return -1;
8399 }
8400
8401 if (ignore_fail) {
8402 req_inst = -1;
8403 } else {
8404 req_inst = sleaf->type.info.inst.req;
8405 }
8406 if (ext_dep && (ignore_fail == 2)) {
8407 /* do not even try to resolve */
8408 rc = 0;
8409 ret = NULL;
8410 } else {
8411 rc = resolve_instid(node, leaf->value_str, req_inst, &ret);
8412 }
8413 if (!rc) {
8414 if (ret && !ext_dep) {
8415 /* valid resolved */
8416 leaf->value.instance = ret;
8417 leaf->value_type = LY_TYPE_INST;
8418 leaf->value_flags &= ~LY_VALUE_UNRES;
8419 } else {
8420 /* valid unresolved */
8421 leaf->value.instance = NULL;
8422 leaf->value_type = LY_TYPE_INST;
8423 leaf->value_flags |= LY_VALUE_UNRES;
8424 }
8425 } else {
8426 return rc;
8427 }
8428 break;
8429
8430 case UNRES_UNION:
8431 assert(sleaf->type.base == LY_TYPE_UNION);
8432 return resolve_union(leaf, &sleaf->type, 1, ignore_fail, NULL);
8433
8434 case UNRES_WHEN:
8435 if ((rc = resolve_when(node, ignore_fail, failed_when))) {
8436 return rc;
8437 }
8438 break;
8439
8440 case UNRES_MUST:
8441 if ((rc = resolve_must(node, 0, ignore_fail, multi_error))) {
8442 return rc;
8443 }
8444 break;
8445
8446 case UNRES_MUST_INOUT:
8447 if ((rc = resolve_must(node, 1, ignore_fail, multi_error))) {
8448 return rc;
8449 }
8450 break;
8451
8452 case UNRES_UNIQ_LEAVES:
8453 if (lyv_data_unique(node)) {
8454 return -1;
8455 }
8456 break;
8457
8458 default:
8459 LOGINT(NULL);
8460 return -1;
8461 }
8462
8463 return EXIT_SUCCESS;
8464 }
8465
8466 /**
8467 * @brief add data unres item
8468 *
8469 * @param[in] unres Unres data structure to use.
8470 * @param[in] node Data node to use.
8471 *
8472 * @return 0 on success, -1 on error.
8473 */
8474 int
unres_data_add(struct unres_data * unres,struct lyd_node * node,enum UNRES_ITEM type)8475 unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type)
8476 {
8477 assert(unres && node);
8478 assert((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)
8479 || (type == UNRES_MUST_INOUT) || (type == UNRES_UNION) || (type == UNRES_UNIQ_LEAVES));
8480
8481 unres->count++;
8482 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
8483 LY_CHECK_ERR_RETURN(!unres->node, LOGMEM(NULL), -1);
8484 unres->node[unres->count - 1] = node;
8485 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
8486 LY_CHECK_ERR_RETURN(!unres->type, LOGMEM(NULL), -1);
8487 unres->type[unres->count - 1] = type;
8488
8489 return 0;
8490 }
8491
8492 static void
resolve_unres_data_autodel_diff(struct unres_data * unres,uint32_t unres_i)8493 resolve_unres_data_autodel_diff(struct unres_data *unres, uint32_t unres_i)
8494 {
8495 struct lyd_node *next, *child, *parent;
8496 uint32_t i;
8497
8498 for (i = 0; i < unres->diff_idx; ++i) {
8499 if (unres->diff->type[i] == LYD_DIFF_DELETED) {
8500 /* only leaf(-list) default could be removed and there is nothing to be checked in that case */
8501 continue;
8502 }
8503
8504 if (unres->diff->second[i] == unres->node[unres_i]) {
8505 /* 1) default value was supposed to be created, but is disabled by when
8506 * -> remove it from diff altogether
8507 */
8508 unres_data_diff_rem(unres, i);
8509 /* if diff type is CREATED, the value was just a pointer, it can be freed normally (unlike in 4) */
8510 return;
8511 } else {
8512 parent = unres->diff->second[i]->parent;
8513 while (parent && (parent != unres->node[unres_i])) {
8514 parent = parent->parent;
8515 }
8516 if (parent) {
8517 /* 2) default value was supposed to be created but is disabled by when in some parent
8518 * -> remove this default subtree and add the rest into diff as deleted instead in 4)
8519 */
8520 unres_data_diff_rem(unres, i);
8521 break;
8522 }
8523
8524 LY_TREE_DFS_BEGIN(unres->diff->second[i], next, child) {
8525 if (child == unres->node[unres_i]) {
8526 /* 3) some default child of a default value was supposed to be created but has false when
8527 * -> the subtree will be freed later and automatically disconnected from the diff parent node
8528 */
8529 return;
8530 }
8531
8532 LY_TREE_DFS_END(unres->diff->second[i], next, child);
8533 }
8534 }
8535 }
8536
8537 /* 4) it does not overlap with created default values in any way
8538 * -> just add it into diff as deleted
8539 */
8540 unres_data_diff_new(unres, unres->node[unres_i], unres->node[unres_i]->parent, 0);
8541 lyd_unlink(unres->node[unres_i]);
8542
8543 /* should not be freed anymore */
8544 unres->node[unres_i] = NULL;
8545 }
8546
8547 /**
8548 * @brief Resolve every unres data item in the structure. Logs directly.
8549 *
8550 * If options include #LYD_OPT_TRUSTED, the data are considered trusted (must conditions are not expected,
8551 * unresolved leafrefs/instids are accepted, when conditions are normally resolved because at least some implicit
8552 * non-presence containers may need to be deleted).
8553 *
8554 * If options includes #LYD_OPT_WHENAUTODEL, the non-default nodes with false when conditions are auto-deleted.
8555 *
8556 * @param[in] ctx Context used.
8557 * @param[in] unres Unres data structure to use.
8558 * @param[in,out] root Root node of the data tree, can be changed due to autodeletion.
8559 * @param[in] options Data options as described above.
8560 *
8561 * @return EXIT_SUCCESS on success, -1 on error.
8562 */
8563 int
resolve_unres_data(struct ly_ctx * ctx,struct unres_data * unres,struct lyd_node ** root,int options)8564 resolve_unres_data(struct ly_ctx *ctx, struct unres_data *unres, struct lyd_node **root, int options)
8565 {
8566 uint32_t i, j, first, resolved, del_items, stmt_count;
8567 uint8_t prev_when_status;
8568 int rc, rc2, progress, ignore_fail, multi_error;
8569 enum int_log_opts prev_ilo;
8570 struct ly_err_item *prev_eitem = NULL;
8571 LY_ERR prev_ly_errno = ly_errno;
8572 struct lyd_node *parent;
8573 struct lys_when *when;
8574
8575 assert(root);
8576 assert(unres);
8577
8578 if (!unres->count) {
8579 return EXIT_SUCCESS;
8580 }
8581
8582 if (options & (LYD_OPT_NOTIF_FILTER | LYD_OPT_GET | LYD_OPT_GETCONFIG | LYD_OPT_EDIT)) {
8583 ignore_fail = 1;
8584 } else if (options & LYD_OPT_NOEXTDEPS) {
8585 ignore_fail = 2;
8586 } else {
8587 ignore_fail = 0;
8588 }
8589
8590 multi_error = (options & LYD_OPT_MULTI_ERRORS) ? 1 : 0;
8591
8592 LOGVRB("Resolving unresolved data nodes and their constraints...");
8593 if (!ignore_fail) {
8594 /* remember logging state only if errors are generated and valid */
8595 ly_ilo_change(ctx, ILO_STORE, &prev_ilo, &prev_eitem);
8596 }
8597
8598 /*
8599 * when-stmt first
8600 */
8601 first = 1;
8602 stmt_count = 0;
8603 resolved = 0;
8604 del_items = 0;
8605 do {
8606 if (!ignore_fail) {
8607 ly_err_free_next(ctx, prev_eitem);
8608 }
8609 progress = 0;
8610 for (i = 0; i < unres->count; i++) {
8611 if (unres->type[i] != UNRES_WHEN) {
8612 continue;
8613 }
8614 if (first) {
8615 /* count when-stmt nodes in unres list */
8616 stmt_count++;
8617 }
8618
8619 /* resolve when condition only when all parent when conditions are already resolved */
8620 for (parent = unres->node[i]->parent;
8621 parent && LYD_WHEN_DONE(parent->when_status);
8622 parent = parent->parent) {
8623 if (!parent->parent && (parent->when_status & LYD_WHEN_FALSE)) {
8624 /* the parent node was already unlinked, do not resolve this node,
8625 * it will be removed anyway, so just mark it as resolved
8626 */
8627 unres->node[i]->when_status |= LYD_WHEN_FALSE;
8628 unres->type[i] = UNRES_RESOLVED;
8629 resolved++;
8630 break;
8631 }
8632 }
8633 if (parent) {
8634 continue;
8635 }
8636
8637 prev_when_status = unres->node[i]->when_status;
8638 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail, 0, &when);
8639 if (!rc) {
8640 /* finish with error/delete the node only if when was changed from true to false, an external
8641 * dependency was not required, or it was not provided (the flag would not be passed down otherwise,
8642 * checked in upper functions) */
8643 if ((unres->node[i]->when_status & LYD_WHEN_FALSE)
8644 && (!(when->flags & (LYS_XPCONF_DEP | LYS_XPSTATE_DEP)) || !(options & LYD_OPT_NOEXTDEPS))) {
8645 if ((!(prev_when_status & LYD_WHEN_TRUE) || !(options & LYD_OPT_WHENAUTODEL)) && !unres->node[i]->dflt) {
8646 /* false when condition */
8647 goto error;
8648 } /* follows else */
8649
8650 /* auto-delete */
8651 LOGVRB("Auto-deleting node \"%s\" due to when condition (%s)", ly_errpath(ctx), when->cond);
8652
8653 /* do not delete yet, the subtree can contain another nodes stored in the unres list */
8654 /* if it has parent non-presence containers that would be empty, we should actually
8655 * remove the container
8656 */
8657 for (parent = unres->node[i];
8658 parent->parent && parent->parent->schema->nodetype == LYS_CONTAINER;
8659 parent = parent->parent) {
8660 if (((struct lys_node_container *)parent->parent->schema)->presence) {
8661 /* presence container */
8662 break;
8663 }
8664 if (parent->next || parent->prev != parent) {
8665 /* non empty (the child we are in and we are going to remove is not the only child) */
8666 break;
8667 }
8668 }
8669 unres->node[i] = parent;
8670
8671 if (*root && *root == unres->node[i]) {
8672 *root = (*root)->next;
8673 }
8674
8675 unres->type[i] = UNRES_DELETE;
8676 del_items++;
8677
8678 /* update the rest of unres items */
8679 for (j = 0; j < unres->count; j++) {
8680 if (unres->type[j] == UNRES_RESOLVED || unres->type[j] == UNRES_DELETE) {
8681 continue;
8682 }
8683
8684 /* test if the node is in subtree to be deleted */
8685 for (parent = unres->node[j]; parent; parent = parent->parent) {
8686 if (parent == unres->node[i]) {
8687 /* yes, it is */
8688 unres->type[j] = UNRES_RESOLVED;
8689 resolved++;
8690 break;
8691 }
8692 }
8693 }
8694 } else {
8695 unres->type[i] = UNRES_RESOLVED;
8696 }
8697 if (!ignore_fail) {
8698 ly_err_free_next(ctx, prev_eitem);
8699 }
8700 resolved++;
8701 progress = 1;
8702 } else if (rc == -1) {
8703 goto error;
8704 } /* else forward reference */
8705 }
8706 first = 0;
8707 } while (progress && resolved < stmt_count);
8708
8709 /* do we have some unresolved when-stmt? */
8710 if (stmt_count > resolved) {
8711 goto error;
8712 }
8713
8714 for (i = 0; del_items && i < unres->count; i++) {
8715 /* we had some when-stmt resulted to false, so now we have to sanitize the unres list */
8716 if (unres->type[i] != UNRES_DELETE) {
8717 continue;
8718 }
8719 if (!unres->node[i]) {
8720 unres->type[i] = UNRES_RESOLVED;
8721 del_items--;
8722 continue;
8723 }
8724
8725 if (unres->store_diff) {
8726 resolve_unres_data_autodel_diff(unres, i);
8727 }
8728
8729 /* really remove the complete subtree */
8730 lyd_free(unres->node[i]);
8731 unres->type[i] = UNRES_RESOLVED;
8732 del_items--;
8733 }
8734
8735 /*
8736 * now leafrefs
8737 */
8738 if (options & LYD_OPT_TRUSTED) {
8739 /* we want to attempt to resolve leafrefs */
8740 assert(!ignore_fail);
8741 ignore_fail = 1;
8742
8743 ly_ilo_restore(ctx, prev_ilo, prev_eitem, 0);
8744 ly_errno = prev_ly_errno;
8745 }
8746 first = 1;
8747 stmt_count = 0;
8748 resolved = 0;
8749 do {
8750 progress = 0;
8751 for (i = 0; i < unres->count; i++) {
8752 if (unres->type[i] != UNRES_LEAFREF) {
8753 continue;
8754 }
8755 if (first) {
8756 /* count leafref nodes in unres list */
8757 stmt_count++;
8758 }
8759
8760 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail, 0, NULL);
8761 if (!rc) {
8762 unres->type[i] = UNRES_RESOLVED;
8763 if (!ignore_fail) {
8764 ly_err_free_next(ctx, prev_eitem);
8765 }
8766 resolved++;
8767 progress = 1;
8768 } else if (rc == -1) {
8769 goto error;
8770 } /* else forward reference */
8771 }
8772 first = 0;
8773 } while (progress && resolved < stmt_count);
8774
8775 /* do we have some unresolved leafrefs? */
8776 if (stmt_count > resolved) {
8777 goto error;
8778 }
8779
8780 if (!ignore_fail) {
8781 /* log normally now, throw away irrelevant errors */
8782 ly_ilo_restore(ctx, prev_ilo, prev_eitem, 0);
8783 ly_errno = prev_ly_errno;
8784 }
8785
8786 rc = 0;
8787
8788 /*
8789 * rest
8790 */
8791 for (i = 0; i < unres->count; ++i) {
8792 if (unres->type[i] == UNRES_RESOLVED) {
8793 continue;
8794 }
8795 assert(!(options & LYD_OPT_TRUSTED) || ((unres->type[i] != UNRES_MUST) && (unres->type[i] != UNRES_MUST_INOUT)));
8796
8797 rc2 = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail, multi_error, NULL);
8798 if (rc2) {
8799 if (!multi_error) {
8800 /* since when was already resolved, a forward reference is an error */
8801 return -1;
8802 }
8803 rc = -1;
8804 }
8805
8806 unres->type[i] = UNRES_RESOLVED;
8807 }
8808
8809 LOGVRB("All data nodes and constraints resolved.");
8810 unres->count = 0;
8811 return rc;
8812
8813 error:
8814 if (!ignore_fail) {
8815 /* print all the new errors */
8816 ly_ilo_restore(ctx, prev_ilo, prev_eitem, 1);
8817 /* do not restore ly_errno, it was udpated properly */
8818 }
8819 return -1;
8820 }
8821