blob: b747f9ac06c0125d601f14a9a5021ba0bb3c7030 [file] [log] [blame]
Michal Vasko730dfdf2015-08-11 14:48:05 +02001/**
2 * @file resolve.c
3 * @author Michal Vasko <mvasko@cesnet.cz>
4 * @brief libyang resolve functions
5 *
6 * Copyright (c) 2015 CESNET, z.s.p.o.
7 *
Radek Krejci54f6fb32016-02-24 12:56:39 +01008 * 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
Michal Vasko8de098c2016-02-26 10:00:25 +010011 *
Radek Krejci54f6fb32016-02-24 12:56:39 +010012 * https://opensource.org/licenses/BSD-3-Clause
Michal Vasko730dfdf2015-08-11 14:48:05 +020013 */
14
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020015#define _GNU_SOURCE
16
17#include <stdlib.h>
18#include <assert.h>
19#include <string.h>
20#include <ctype.h>
Michal Vaskoe7fc19c2015-08-05 16:24:39 +020021#include <limits.h>
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020022
23#include "libyang.h"
24#include "resolve.h"
25#include "common.h"
Michal Vaskocf024702015-10-08 15:01:42 +020026#include "xpath.h"
Michal Vasko1dca6882015-10-22 14:29:42 +020027#include "parser.h"
Pavol Vicana0e4e672016-02-24 12:20:04 +010028#include "parser_yang.h"
Michal Vasko88c29542015-11-27 14:57:53 +010029#include "xml_internal.h"
Radek Krejci41912fe2015-10-22 10:22:12 +020030#include "dict_private.h"
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020031#include "tree_internal.h"
32
Michal Vasko730dfdf2015-08-11 14:48:05 +020033/**
Michal Vasko4d1f0482016-09-19 14:35:06 +020034 * @brief Convert a string with a decimal64 value into our representation.
35 * Syntax is expected to be correct.
36 *
37 * @param[in,out] str_num Pointer to the beginning of the decimal64 number, returns the first unparsed character.
38 * @param[in] dig Fraction-digits of the resulting number.
39 * @return Decimal64 base value, fraction-digits equal \p dig.
40 */
41static int64_t
42parse_range_dec64(const char **str_num, uint8_t dig)
43{
44 const char *ptr;
45 int minus = 0;
46 int64_t ret = 0;
47 int8_t str_exp, str_dig = -1;
48
49 ptr = *str_num;
50
51 if (ptr[0] == '-') {
52 minus = 1;
53 ++ptr;
54 }
55
56 for (str_exp = 0; isdigit(ptr[0]) || ((ptr[0] == '.') && (str_dig < 0)); ++ptr) {
57 if (str_exp > 18) {
58 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, *str_num, "range");
59 return 0;
60 }
61
62 if (ptr[0] == '.') {
63 if (ptr[1] == '.') {
64 /* it's the next interval */
65 break;
66 }
67 ++str_dig;
68 } else {
69 ret = ret * 10 + (ptr[0] - 48);
70 if (str_dig > -1) {
71 ++str_dig;
72 }
73 ++str_exp;
74 }
75 }
76 if (str_dig == -1) {
77 /* there are 0 number after the floating point */
78 str_dig = 0;
79 }
80
81 /* it's parsed, now adjust the number based on fraction-digits, if needed */
82 if (str_dig < dig) {
83 if ((str_exp - 1) + (dig - str_dig) > 18) {
84 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, *str_num, "range");
85 return 0;
86 }
87 ret *= dec_pow(dig - str_dig);
88 }
89 if (str_dig > dig) {
90 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, *str_num, "range");
91 return 0;
92 }
93
94 if (minus) {
95 ret *= -1;
96 }
97 *str_num = ptr;
98
99 return ret;
100}
101
102/**
Radek Krejci6dc53a22015-08-17 13:27:59 +0200103 * @brief Parse an identifier.
104 *
105 * ;; An identifier MUST NOT start with (('X'|'x') ('M'|'m') ('L'|'l'))
106 * identifier = (ALPHA / "_")
107 * *(ALPHA / DIGIT / "_" / "-" / ".")
108 *
Michal Vaskobb211122015-08-19 14:03:11 +0200109 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200110 *
111 * @return Number of characters successfully parsed.
112 */
Michal Vasko249e6b52015-08-19 11:08:52 +0200113int
Radek Krejci6dc53a22015-08-17 13:27:59 +0200114parse_identifier(const char *id)
115{
116 int parsed = 0;
117
Michal Vasko1ab90bc2016-03-15 10:40:22 +0100118 assert(id);
119
Radek Krejci6dc53a22015-08-17 13:27:59 +0200120 if (!isalpha(id[0]) && (id[0] != '_')) {
121 return -parsed;
122 }
123
124 ++parsed;
125 ++id;
126
127 while (isalnum(id[0]) || (id[0] == '_') || (id[0] == '-') || (id[0] == '.')) {
128 ++parsed;
129 ++id;
130 }
131
132 return parsed;
133}
134
135/**
136 * @brief Parse a node-identifier.
137 *
Michal Vasko723e50c2015-10-20 15:20:29 +0200138 * node-identifier = [module-name ":"] identifier
Radek Krejci6dc53a22015-08-17 13:27:59 +0200139 *
Michal Vaskobb211122015-08-19 14:03:11 +0200140 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200141 * @param[out] mod_name Points to the module name, NULL if there is not any.
142 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200143 * @param[out] name Points to the node name.
144 * @param[out] nam_len Length of the node name.
145 *
146 * @return Number of characters successfully parsed,
147 * positive on success, negative on failure.
148 */
149static int
Michal Vasko723e50c2015-10-20 15:20:29 +0200150parse_node_identifier(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200151{
152 int parsed = 0, ret;
153
154 assert(id);
Michal Vasko723e50c2015-10-20 15:20:29 +0200155 if (mod_name) {
156 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200157 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200158 if (mod_name_len) {
159 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200160 }
161 if (name) {
162 *name = NULL;
163 }
164 if (nam_len) {
165 *nam_len = 0;
166 }
167
168 if ((ret = parse_identifier(id)) < 1) {
169 return ret;
170 }
171
Michal Vasko723e50c2015-10-20 15:20:29 +0200172 if (mod_name) {
173 *mod_name = id;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200174 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200175 if (mod_name_len) {
176 *mod_name_len = ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200177 }
178
179 parsed += ret;
180 id += ret;
181
182 /* there is prefix */
183 if (id[0] == ':') {
184 ++parsed;
185 ++id;
186
187 /* there isn't */
188 } else {
Michal Vasko723e50c2015-10-20 15:20:29 +0200189 if (name && mod_name) {
190 *name = *mod_name;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200191 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200192 if (mod_name) {
193 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200194 }
195
Michal Vasko723e50c2015-10-20 15:20:29 +0200196 if (nam_len && mod_name_len) {
197 *nam_len = *mod_name_len;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200198 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200199 if (mod_name_len) {
200 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200201 }
202
203 return parsed;
204 }
205
206 /* identifier (node name) */
207 if ((ret = parse_identifier(id)) < 1) {
208 return -parsed+ret;
209 }
210
211 if (name) {
212 *name = id;
213 }
214 if (nam_len) {
215 *nam_len = ret;
216 }
217
218 return parsed+ret;
219}
220
221/**
222 * @brief Parse a path-predicate (leafref).
223 *
224 * path-predicate = "[" *WSP path-equality-expr *WSP "]"
225 * path-equality-expr = node-identifier *WSP "=" *WSP path-key-expr
226 *
Michal Vaskobb211122015-08-19 14:03:11 +0200227 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200228 * @param[out] prefix Points to the prefix, NULL if there is not any.
229 * @param[out] pref_len Length of the prefix, 0 if there is not any.
230 * @param[out] name Points to the node name.
231 * @param[out] nam_len Length of the node name.
232 * @param[out] path_key_expr Points to the path-key-expr.
233 * @param[out] pke_len Length of the path-key-expr.
234 * @param[out] has_predicate Flag to mark whether there is another predicate following.
235 *
236 * @return Number of characters successfully parsed,
237 * positive on success, negative on failure.
238 */
239static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200240parse_path_predicate(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
241 const char **path_key_expr, int *pke_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200242{
243 const char *ptr;
244 int parsed = 0, ret;
245
246 assert(id);
247 if (prefix) {
248 *prefix = NULL;
249 }
250 if (pref_len) {
251 *pref_len = 0;
252 }
253 if (name) {
254 *name = NULL;
255 }
256 if (nam_len) {
257 *nam_len = 0;
258 }
259 if (path_key_expr) {
260 *path_key_expr = NULL;
261 }
262 if (pke_len) {
263 *pke_len = 0;
264 }
265 if (has_predicate) {
266 *has_predicate = 0;
267 }
268
269 if (id[0] != '[') {
270 return -parsed;
271 }
272
273 ++parsed;
274 ++id;
275
276 while (isspace(id[0])) {
277 ++parsed;
278 ++id;
279 }
280
281 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
282 return -parsed+ret;
283 }
284
285 parsed += ret;
286 id += ret;
287
288 while (isspace(id[0])) {
289 ++parsed;
290 ++id;
291 }
292
293 if (id[0] != '=') {
294 return -parsed;
295 }
296
297 ++parsed;
298 ++id;
299
300 while (isspace(id[0])) {
301 ++parsed;
302 ++id;
303 }
304
305 if ((ptr = strchr(id, ']')) == NULL) {
306 return -parsed;
307 }
308
309 --ptr;
310 while (isspace(ptr[0])) {
311 --ptr;
312 }
313 ++ptr;
314
315 ret = ptr-id;
316 if (path_key_expr) {
317 *path_key_expr = id;
318 }
319 if (pke_len) {
320 *pke_len = ret;
321 }
322
323 parsed += ret;
324 id += ret;
325
326 while (isspace(id[0])) {
327 ++parsed;
328 ++id;
329 }
330
331 assert(id[0] == ']');
332
333 if (id[1] == '[') {
334 *has_predicate = 1;
335 }
336
337 return parsed+1;
338}
339
340/**
341 * @brief Parse a path-key-expr (leafref). First call parses "current()", all
342 * the ".." and the first node-identifier, other calls parse a single
343 * node-identifier each.
344 *
345 * path-key-expr = current-function-invocation *WSP "/" *WSP
346 * rel-path-keyexpr
347 * rel-path-keyexpr = 1*(".." *WSP "/" *WSP)
348 * *(node-identifier *WSP "/" *WSP)
349 * node-identifier
350 *
Michal Vaskobb211122015-08-19 14:03:11 +0200351 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200352 * @param[out] prefix Points to the prefix, NULL if there is not any.
353 * @param[out] pref_len Length of the prefix, 0 if there is not any.
354 * @param[out] name Points to the node name.
355 * @param[out] nam_len Length of the node name.
356 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
357 * must not be changed between consecutive calls.
358 * @return Number of characters successfully parsed,
359 * positive on success, negative on failure.
360 */
361static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200362parse_path_key_expr(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
363 int *parent_times)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200364{
365 int parsed = 0, ret, par_times = 0;
366
367 assert(id);
368 assert(parent_times);
369 if (prefix) {
370 *prefix = NULL;
371 }
372 if (pref_len) {
373 *pref_len = 0;
374 }
375 if (name) {
376 *name = NULL;
377 }
378 if (nam_len) {
379 *nam_len = 0;
380 }
381
382 if (!*parent_times) {
383 /* current-function-invocation *WSP "/" *WSP rel-path-keyexpr */
384 if (strncmp(id, "current()", 9)) {
385 return -parsed;
386 }
387
388 parsed += 9;
389 id += 9;
390
391 while (isspace(id[0])) {
392 ++parsed;
393 ++id;
394 }
395
396 if (id[0] != '/') {
397 return -parsed;
398 }
399
400 ++parsed;
401 ++id;
402
403 while (isspace(id[0])) {
404 ++parsed;
405 ++id;
406 }
407
408 /* rel-path-keyexpr */
409 if (strncmp(id, "..", 2)) {
410 return -parsed;
411 }
412 ++par_times;
413
414 parsed += 2;
415 id += 2;
416
417 while (isspace(id[0])) {
418 ++parsed;
419 ++id;
420 }
421 }
422
423 /* 1*(".." *WSP "/" *WSP) *(node-identifier *WSP "/" *WSP) node-identifier
424 *
425 * first parent reference with whitespaces already parsed
426 */
427 if (id[0] != '/') {
428 return -parsed;
429 }
430
431 ++parsed;
432 ++id;
433
434 while (isspace(id[0])) {
435 ++parsed;
436 ++id;
437 }
438
439 while (!strncmp(id, "..", 2) && !*parent_times) {
440 ++par_times;
441
442 parsed += 2;
443 id += 2;
444
445 while (isspace(id[0])) {
446 ++parsed;
447 ++id;
448 }
449
450 if (id[0] != '/') {
451 return -parsed;
452 }
453
454 ++parsed;
455 ++id;
456
457 while (isspace(id[0])) {
458 ++parsed;
459 ++id;
460 }
461 }
462
463 if (!*parent_times) {
464 *parent_times = par_times;
465 }
466
467 /* all parent references must be parsed at this point */
468 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
469 return -parsed+ret;
470 }
471
472 parsed += ret;
473 id += ret;
474
475 return parsed;
476}
477
478/**
479 * @brief Parse path-arg (leafref).
480 *
481 * path-arg = absolute-path / relative-path
482 * absolute-path = 1*("/" (node-identifier *path-predicate))
483 * relative-path = 1*(".." "/") descendant-path
484 *
Michal Vaskobb211122015-08-19 14:03:11 +0200485 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200486 * @param[out] prefix Points to the prefix, NULL if there is not any.
487 * @param[out] pref_len Length of the prefix, 0 if there is not any.
488 * @param[out] name Points to the node name.
489 * @param[out] nam_len Length of the node name.
490 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
491 * must not be changed between consecutive calls. -1 if the
492 * path is relative.
493 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
494 *
495 * @return Number of characters successfully parsed,
496 * positive on success, negative on failure.
497 */
498static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200499parse_path_arg(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len, int *parent_times,
500 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200501{
502 int parsed = 0, ret, par_times = 0;
503
504 assert(id);
505 assert(parent_times);
506 if (prefix) {
507 *prefix = NULL;
508 }
509 if (pref_len) {
510 *pref_len = 0;
511 }
512 if (name) {
513 *name = NULL;
514 }
515 if (nam_len) {
516 *nam_len = 0;
517 }
518 if (has_predicate) {
519 *has_predicate = 0;
520 }
521
522 if (!*parent_times && !strncmp(id, "..", 2)) {
523 ++par_times;
524
525 parsed += 2;
526 id += 2;
527
528 while (!strncmp(id, "/..", 3)) {
529 ++par_times;
530
531 parsed += 3;
532 id += 3;
533 }
534 }
535
536 if (!*parent_times) {
537 if (par_times) {
538 *parent_times = par_times;
539 } else {
540 *parent_times = -1;
541 }
542 }
543
544 if (id[0] != '/') {
545 return -parsed;
546 }
547
548 /* skip '/' */
549 ++parsed;
550 ++id;
551
552 /* node-identifier ([prefix:]identifier) */
553 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
554 return -parsed-ret;
555 }
556
557 parsed += ret;
558 id += ret;
559
560 /* there is no predicate */
561 if ((id[0] == '/') || !id[0]) {
562 return parsed;
563 } else if (id[0] != '[') {
564 return -parsed;
565 }
566
567 if (has_predicate) {
568 *has_predicate = 1;
569 }
570
571 return parsed;
572}
573
574/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200575 * @brief Parse instance-identifier in JSON data format. That means that prefixes
Michal Vaskob2f40be2016-09-08 16:03:48 +0200576 * (which are mandatory for every node-identifier) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200577 *
578 * instance-identifier = 1*("/" (node-identifier *predicate))
579 *
Michal Vaskobb211122015-08-19 14:03:11 +0200580 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200581 * @param[out] model Points to the model name.
582 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200583 * @param[out] name Points to the node name.
584 * @param[out] nam_len Length of the node name.
585 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
586 *
587 * @return Number of characters successfully parsed,
588 * positive on success, negative on failure.
589 */
590static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200591parse_instance_identifier(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
592 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200593{
594 int parsed = 0, ret;
595
Radek Krejci6dc53a22015-08-17 13:27:59 +0200596 if (has_predicate) {
597 *has_predicate = 0;
598 }
599
600 if (id[0] != '/') {
601 return -parsed;
602 }
603
604 ++parsed;
605 ++id;
606
Michal Vaskob2f40be2016-09-08 16:03:48 +0200607 if ((ret = parse_identifier(id)) < 1) {
608 return ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200609 }
610
Michal Vaskob2f40be2016-09-08 16:03:48 +0200611 *model = id;
612 *mod_len = ret;
613
Radek Krejci6dc53a22015-08-17 13:27:59 +0200614 parsed += ret;
615 id += ret;
616
Michal Vaskob2f40be2016-09-08 16:03:48 +0200617 if (id[0] != ':') {
618 return -parsed;
619 }
620
621 ++parsed;
622 ++id;
623
624 if ((ret = parse_identifier(id)) < 1) {
625 return ret;
626 }
627
628 *name = id;
629 *nam_len = ret;
630
631 parsed += ret;
632 id += ret;
633
Radek Krejci4967cb62016-09-14 16:40:28 +0200634 if (id[0] == '[' && has_predicate) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200635 *has_predicate = 1;
636 }
637
638 return parsed;
639}
640
641/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200642 * @brief Parse predicate (instance-identifier) in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200643 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200644 *
645 * predicate = "[" *WSP (predicate-expr / pos) *WSP "]"
646 * predicate-expr = (node-identifier / ".") *WSP "=" *WSP
647 * ((DQUOTE string DQUOTE) /
648 * (SQUOTE string SQUOTE))
649 * pos = non-negative-integer-value
650 *
Michal Vaskobb211122015-08-19 14:03:11 +0200651 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200652 * @param[out] model Points to the model name.
653 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200654 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
655 * @param[out] nam_len Length of the node name.
656 * @param[out] value Value the node-identifier must have (string from the grammar),
657 * NULL if there is not any.
658 * @param[out] val_len Length of the value, 0 if there is not any.
659 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
660 *
661 * @return Number of characters successfully parsed,
662 * positive on success, negative on failure.
663 */
664static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200665parse_predicate(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
666 const char **value, int *val_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200667{
668 const char *ptr;
669 int parsed = 0, ret;
670 char quote;
671
672 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200673 if (model) {
674 *model = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200675 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200676 if (mod_len) {
677 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200678 }
679 if (name) {
680 *name = NULL;
681 }
682 if (nam_len) {
683 *nam_len = 0;
684 }
685 if (value) {
686 *value = NULL;
687 }
688 if (val_len) {
689 *val_len = 0;
690 }
691 if (has_predicate) {
692 *has_predicate = 0;
693 }
694
695 if (id[0] != '[') {
696 return -parsed;
697 }
698
699 ++parsed;
700 ++id;
701
702 while (isspace(id[0])) {
703 ++parsed;
704 ++id;
705 }
706
707 /* pos */
708 if (isdigit(id[0])) {
709 if (name) {
710 *name = id;
711 }
712
713 if (id[0] == '0') {
Michal Vaskof2f28a12016-09-09 12:43:06 +0200714 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200715 }
716
717 while (isdigit(id[0])) {
718 ++parsed;
719 ++id;
720 }
721
722 if (nam_len) {
723 *nam_len = id-(*name);
724 }
725
Michal Vaskof2f28a12016-09-09 12:43:06 +0200726 /* "." or node-identifier */
Radek Krejci6dc53a22015-08-17 13:27:59 +0200727 } else {
Michal Vaskof2f28a12016-09-09 12:43:06 +0200728 if (id[0] == '.') {
729 if (name) {
730 *name = id;
731 }
732 if (nam_len) {
733 *nam_len = 1;
734 }
735
736 ++parsed;
737 ++id;
738
739 } else {
740 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
741 return -parsed+ret;
742 } else if (model && !*model) {
743 return -parsed;
744 }
745
746 parsed += ret;
747 id += ret;
748 }
749
750 while (isspace(id[0])) {
751 ++parsed;
752 ++id;
753 }
754
755 if (id[0] != '=') {
Michal Vasko1f2cc332015-08-19 11:18:32 +0200756 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200757 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200758
Radek Krejci6dc53a22015-08-17 13:27:59 +0200759 ++parsed;
760 ++id;
761
Michal Vaskof2f28a12016-09-09 12:43:06 +0200762 while (isspace(id[0])) {
763 ++parsed;
764 ++id;
765 }
766
767 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
768 if ((id[0] == '\"') || (id[0] == '\'')) {
769 quote = id[0];
770
771 ++parsed;
772 ++id;
773
774 if ((ptr = strchr(id, quote)) == NULL) {
775 return -parsed;
776 }
777 ret = ptr-id;
778
779 if (value) {
780 *value = id;
781 }
782 if (val_len) {
783 *val_len = ret;
784 }
785
786 parsed += ret+1;
787 id += ret+1;
788 } else {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200789 return -parsed;
790 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200791 }
792
793 while (isspace(id[0])) {
794 ++parsed;
795 ++id;
796 }
797
798 if (id[0] != ']') {
799 return -parsed;
800 }
801
802 ++parsed;
803 ++id;
804
805 if ((id[0] == '[') && has_predicate) {
806 *has_predicate = 1;
807 }
808
809 return parsed;
810}
811
812/**
813 * @brief Parse schema-nodeid.
814 *
815 * schema-nodeid = absolute-schema-nodeid /
816 * descendant-schema-nodeid
817 * absolute-schema-nodeid = 1*("/" node-identifier)
Michal Vasko48935352016-03-29 11:52:36 +0200818 * descendant-schema-nodeid = ["." "/"]
Radek Krejci6dc53a22015-08-17 13:27:59 +0200819 * node-identifier
820 * absolute-schema-nodeid
821 *
Michal Vaskobb211122015-08-19 14:03:11 +0200822 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200823 * @param[out] mod_name Points to the module name, NULL if there is not any.
824 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Michal Vasko48935352016-03-29 11:52:36 +0200825 * @param[out] name Points to the node name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200826 * @param[out] nam_len Length of the node name.
827 * @param[out] is_relative Flag to mark whether the nodeid is absolute or descendant. Must be -1
828 * on the first call, must not be changed between consecutive calls.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100829 * @param[out] has_predicate Flag to mark whether there is a predicate specified. It cannot be
830 * based on the grammar, in those cases use NULL.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200831 *
832 * @return Number of characters successfully parsed,
833 * positive on success, negative on failure.
834 */
Michal Vasko22448d32016-03-16 13:17:29 +0100835int
Michal Vasko723e50c2015-10-20 15:20:29 +0200836parse_schema_nodeid(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len,
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100837 int *is_relative, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200838{
839 int parsed = 0, ret;
840
841 assert(id);
842 assert(is_relative);
Michal Vasko723e50c2015-10-20 15:20:29 +0200843 if (mod_name) {
844 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200845 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200846 if (mod_name_len) {
847 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200848 }
849 if (name) {
850 *name = NULL;
851 }
852 if (nam_len) {
853 *nam_len = 0;
854 }
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100855 if (has_predicate) {
856 *has_predicate = 0;
857 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200858
859 if (id[0] != '/') {
860 if (*is_relative != -1) {
861 return -parsed;
862 } else {
863 *is_relative = 1;
864 }
Michal Vasko48935352016-03-29 11:52:36 +0200865 if (!strncmp(id, "./", 2)) {
866 parsed += 2;
867 id += 2;
868 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200869 } else {
870 if (*is_relative == -1) {
871 *is_relative = 0;
872 }
873 ++parsed;
874 ++id;
875 }
876
Michal Vasko723e50c2015-10-20 15:20:29 +0200877 if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200878 return -parsed+ret;
879 }
880
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100881 parsed += ret;
882 id += ret;
883
884 if ((id[0] == '[') && has_predicate) {
885 *has_predicate = 1;
886 }
887
888 return parsed;
889}
890
891/**
892 * @brief Parse schema predicate (special format internally used).
893 *
894 * predicate = "[" *WSP predicate-expr *WSP "]"
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200895 * predicate-expr = "." / identifier / key-with-value
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100896 * key-with-value = identifier *WSP "=" *WSP
897 * ((DQUOTE string DQUOTE) /
898 * (SQUOTE string SQUOTE))
899 *
900 * @param[in] id Identifier to use.
901 * @param[out] name Points to the list key name.
902 * @param[out] nam_len Length of \p name.
Michal Vasko22448d32016-03-16 13:17:29 +0100903 * @param[out] value Points to the key value. If specified, key-with-value is expected.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100904 * @param[out] val_len Length of \p value.
905 * @param[out] has_predicate Flag to mark whether there is another predicate specified.
906 */
Michal Vasko22448d32016-03-16 13:17:29 +0100907int
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200908parse_schema_json_predicate(const char *id, const char **name, int *nam_len, const char **value, int *val_len,
Michal Vasko3547c532016-03-14 09:40:50 +0100909 int *has_predicate)
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100910{
911 const char *ptr;
912 int parsed = 0, ret;
913 char quote;
914
915 assert(id);
916 if (name) {
917 *name = NULL;
918 }
919 if (nam_len) {
920 *nam_len = 0;
921 }
922 if (value) {
923 *value = NULL;
924 }
925 if (val_len) {
926 *val_len = 0;
927 }
928 if (has_predicate) {
929 *has_predicate = 0;
930 }
931
932 if (id[0] != '[') {
933 return -parsed;
934 }
935
936 ++parsed;
937 ++id;
938
939 while (isspace(id[0])) {
940 ++parsed;
941 ++id;
942 }
943
Michal Vasko22448d32016-03-16 13:17:29 +0100944 /* identifier */
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200945 if (id[0] == '.') {
946 ret = 1;
947 } else if ((ret = parse_identifier(id)) < 1) {
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100948 return -parsed + ret;
949 }
950 if (name) {
951 *name = id;
952 }
953 if (nam_len) {
954 *nam_len = ret;
955 }
956
957 parsed += ret;
958 id += ret;
959
960 while (isspace(id[0])) {
961 ++parsed;
962 ++id;
963 }
964
965 /* there is value as well */
966 if (id[0] == '=') {
967 ++parsed;
968 ++id;
969
970 while (isspace(id[0])) {
971 ++parsed;
972 ++id;
973 }
974
975 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
976 if ((id[0] == '\"') || (id[0] == '\'')) {
977 quote = id[0];
978
979 ++parsed;
980 ++id;
981
982 if ((ptr = strchr(id, quote)) == NULL) {
983 return -parsed;
984 }
985 ret = ptr - id;
986
987 if (value) {
988 *value = id;
989 }
990 if (val_len) {
991 *val_len = ret;
992 }
993
994 parsed += ret + 1;
995 id += ret + 1;
996 } else {
997 return -parsed;
998 }
999
1000 while (isspace(id[0])) {
1001 ++parsed;
1002 ++id;
1003 }
Michal Vasko22448d32016-03-16 13:17:29 +01001004 } else if (value) {
1005 /* if value was expected, it's mandatory */
1006 return -parsed;
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001007 }
1008
1009 if (id[0] != ']') {
1010 return -parsed;
1011 }
1012
1013 ++parsed;
1014 ++id;
1015
1016 if ((id[0] == '[') && has_predicate) {
1017 *has_predicate = 1;
1018 }
1019
1020 return parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +02001021}
1022
1023/**
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001024 * @brief Resolve (find) a feature definition. Logs directly.
1025 *
1026 * @param[in] feat_name Feature name to resolve.
1027 * @param[in] len Length of \p feat_name.
1028 * @param[in] node Node with the if-feature expression.
Radek Krejci9ff0a922016-07-14 13:08:05 +02001029 * @param[out] feature Pointer to be set to point to the feature definition, if feature not found
1030 * (return code 1), the pointer is untouched.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001031 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02001032 * @return 0 on success, 1 on forward reference, -1 on error.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001033 */
1034static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001035resolve_feature(const char *feat_name, uint16_t len, const struct lys_node *node, struct lys_feature **feature)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001036{
1037 char *str;
1038 const char *mod_name, *name;
1039 int mod_name_len, nam_len, i, j;
1040 const struct lys_module *module;
1041
Radek Krejci9ff0a922016-07-14 13:08:05 +02001042 assert(feature);
1043
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001044 /* check prefix */
1045 if ((i = parse_node_identifier(feat_name, &mod_name, &mod_name_len, &name, &nam_len)) < 1) {
1046 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, feat_name[-i], &feat_name[-i]);
1047 return -1;
1048 }
1049
1050 module = lys_get_import_module(lys_node_module(node), NULL, 0, mod_name, mod_name_len);
1051 if (!module) {
1052 /* identity refers unknown data model */
1053 LOGVAL(LYE_INMOD_LEN, LY_VLOG_NONE, NULL, mod_name_len, mod_name);
1054 return -1;
1055 }
1056
Radek Krejci9ff0a922016-07-14 13:08:05 +02001057 if (module != node->module && module == lys_node_module(node)) {
1058 /* first, try to search directly in submodule where the feature was mentioned */
1059 for (j = 0; j < node->module->features_size; j++) {
1060 if (!strncmp(name, node->module->features[j].name, nam_len) && !node->module->features[j].name[nam_len]) {
1061 /* check status */
1062 if (lyp_check_status(node->flags, lys_node_module(node), node->name, node->module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001063 node->module->features[j].module, node->module->features[j].name, NULL)) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001064 return -1;
1065 }
1066 *feature = &node->module->features[j];
1067 return 0;
1068 }
1069 }
1070 }
1071
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001072 /* search in the identified module ... */
1073 for (j = 0; j < module->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001074 if (!strncmp(name, module->features[j].name, nam_len) && !module->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001075 /* check status */
1076 if (lyp_check_status(node->flags, lys_node_module(node), node->name, module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001077 module->features[j].module, module->features[j].name, NULL)) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001078 return -1;
1079 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001080 *feature = &module->features[j];
1081 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001082 }
1083 }
1084 /* ... and all its submodules */
1085 for (i = 0; i < module->inc_size; i++) {
1086 if (!module->inc[i].submodule) {
1087 /* not yet resolved */
1088 continue;
1089 }
1090 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001091 if (!strncmp(name, module->inc[i].submodule->features[j].name, nam_len)
1092 && !module->inc[i].submodule->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001093 /* check status */
1094 if (lyp_check_status(node->flags, lys_node_module(node), node->name,
1095 module->inc[i].submodule->features[j].flags,
1096 module->inc[i].submodule->features[j].module,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001097 module->inc[i].submodule->features[j].name, NULL)) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001098 return -1;
1099 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001100 *feature = &module->inc[i].submodule->features[j];
1101 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001102 }
1103 }
1104 }
1105
1106 /* not found */
1107 str = strndup(feat_name, len);
1108 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, "feature", str);
1109 free(str);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001110 return 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001111}
1112
Radek Krejci9ff0a922016-07-14 13:08:05 +02001113/*
1114 * @return
Radek Krejci69b8d922016-07-27 13:13:41 +02001115 * - 1 if enabled
1116 * - 0 if disabled
Radek Krejci9ff0a922016-07-14 13:08:05 +02001117 * - -1 if not usable by its if-feature expression
1118 */
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001119static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001120resolve_feature_value(const struct lys_feature *feat)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001121{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001122 int i;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001123
Radek Krejci9ff0a922016-07-14 13:08:05 +02001124 for (i = 0; i < feat->iffeature_size; i++) {
Radek Krejci69b8d922016-07-27 13:13:41 +02001125 if (!resolve_iffeature(&feat->iffeature[i])) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001126 return -1;
1127 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001128 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001129
Radek Krejci69b8d922016-07-27 13:13:41 +02001130 return feat->flags & LYS_FENABLED ? 1 : 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001131}
1132
1133static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001134resolve_iffeature_recursive(struct lys_iffeature *expr, int *index_e, int *index_f)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001135{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001136 uint8_t op;
1137 int rc, a, b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001138
Radek Krejci9ff0a922016-07-14 13:08:05 +02001139 op = iff_getop(expr->expr, *index_e);
1140 (*index_e)++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001141
Radek Krejci9ff0a922016-07-14 13:08:05 +02001142 switch (op) {
1143 case LYS_IFF_F:
1144 /* resolve feature */
1145 return resolve_feature_value(expr->features[(*index_f)++]);
1146 case LYS_IFF_NOT:
1147 rc = resolve_iffeature_recursive(expr, index_e, index_f);
1148 if (rc == -1) {
1149 /* one of the referenced feature is hidden by its if-feature,
1150 * so this if-feature expression is always false */
1151 return -1;
1152 } else {
1153 /* invert result */
1154 return rc ? 0 : 1;
1155 }
1156 case LYS_IFF_AND:
1157 case LYS_IFF_OR:
1158 a = resolve_iffeature_recursive(expr, index_e, index_f);
1159 b = resolve_iffeature_recursive(expr, index_e, index_f);
1160 if (a == -1 || b == -1) {
1161 /* one of the referenced feature is hidden by its if-feature,
1162 * so this if-feature expression is always false */
1163 return -1;
1164 } else if (op == LYS_IFF_AND) {
1165 return a && b;
1166 } else { /* LYS_IFF_OR */
1167 return a || b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001168 }
1169 }
1170
Radek Krejci9ff0a922016-07-14 13:08:05 +02001171 return -1;
1172}
1173
1174int
1175resolve_iffeature(struct lys_iffeature *expr)
1176{
1177 int rc = -1;
1178 int index_e = 0, index_f = 0;
1179
1180 if (expr->expr) {
1181 rc = resolve_iffeature_recursive(expr, &index_e, &index_f);
1182 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001183 return (rc == 1) ? 1 : 0;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001184}
1185
1186struct iff_stack {
1187 int size;
1188 int index; /* first empty item */
1189 uint8_t *stack;
1190};
1191
1192static int
1193iff_stack_push(struct iff_stack *stack, uint8_t value)
1194{
1195 if (stack->index == stack->size) {
1196 stack->size += 4;
1197 stack->stack = ly_realloc(stack->stack, stack->size * sizeof *stack->stack);
1198 if (!stack->stack) {
1199 LOGMEM;
1200 stack->size = 0;
1201 return EXIT_FAILURE;
1202 }
1203 }
1204
1205 stack->stack[stack->index++] = value;
1206 return EXIT_SUCCESS;
1207}
1208
1209static uint8_t
1210iff_stack_pop(struct iff_stack *stack)
1211{
1212 stack->index--;
1213 return stack->stack[stack->index];
1214}
1215
1216static void
1217iff_stack_clean(struct iff_stack *stack)
1218{
1219 stack->size = 0;
1220 free(stack->stack);
1221}
1222
1223static void
1224iff_setop(uint8_t *list, uint8_t op, int pos)
1225{
1226 uint8_t *item;
1227 uint8_t mask = 3;
1228
1229 assert(pos >= 0);
1230 assert(op <= 3); /* max 2 bits */
1231
1232 item = &list[pos / 4];
1233 mask = mask << 2 * (pos % 4);
1234 *item = (*item) & ~mask;
1235 *item = (*item) | (op << 2 * (pos % 4));
1236}
1237
1238uint8_t
1239iff_getop(uint8_t *list, int pos)
1240{
1241 uint8_t *item;
1242 uint8_t mask = 3, result;
1243
1244 assert(pos >= 0);
1245
1246 item = &list[pos / 4];
1247 result = (*item) & (mask << 2 * (pos % 4));
1248 return result >> 2 * (pos % 4);
1249}
1250
1251#define LYS_IFF_LP 0x04 /* ( */
1252#define LYS_IFF_RP 0x08 /* ) */
1253
Radek Krejcicbb473e2016-09-16 14:48:32 +02001254/* internal structure for passing data for UNRES_IFFEAT */
1255struct unres_iffeat_data {
1256 struct lys_node *node;
1257 const char *fname;
1258};
1259
Radek Krejci9ff0a922016-07-14 13:08:05 +02001260void
1261resolve_iffeature_getsizes(struct lys_iffeature *iffeat, unsigned int *expr_size, unsigned int *feat_size)
1262{
1263 unsigned int e = 0, f = 0, r = 0;
1264 uint8_t op;
1265
1266 assert(iffeat);
1267
1268 if (!iffeat->expr) {
1269 goto result;
1270 }
1271
1272 do {
1273 op = iff_getop(iffeat->expr, e++);
1274 switch (op) {
1275 case LYS_IFF_NOT:
1276 if (!r) {
1277 r += 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001278 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001279 break;
1280 case LYS_IFF_AND:
1281 case LYS_IFF_OR:
1282 if (!r) {
1283 r += 2;
1284 } else {
1285 r += 1;
1286 }
1287 break;
1288 case LYS_IFF_F:
1289 f++;
1290 if (r) {
1291 r--;
1292 }
1293 break;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001294 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001295 } while(r);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001296
Radek Krejci9ff0a922016-07-14 13:08:05 +02001297result:
1298 if (expr_size) {
1299 *expr_size = e;
1300 }
1301 if (feat_size) {
1302 *feat_size = f;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001303 }
1304}
1305
1306int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001307resolve_iffeature_compile(struct lys_iffeature *iffeat_expr, const char *value, struct lys_node *node,
1308 struct unres_schema *unres)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001309{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001310 const char *c = value;
1311 int r, rc = EXIT_FAILURE;
Radek Krejci69b8d922016-07-27 13:13:41 +02001312 int i, j, last_not, checkversion = 0;
1313 unsigned int f_size = 0, expr_size = 0, f_exp = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001314 uint8_t op;
1315 struct iff_stack stack = {0, 0, NULL};
Radek Krejcicbb473e2016-09-16 14:48:32 +02001316 struct unres_iffeat_data *iff_data;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001317
Radek Krejci9ff0a922016-07-14 13:08:05 +02001318 assert(c);
1319
1320 if (isspace(c[0])) {
1321 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, c[0], c);
1322 return EXIT_FAILURE;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001323 }
1324
Radek Krejci9ff0a922016-07-14 13:08:05 +02001325 /* pre-parse the expression to get sizes for arrays, also do some syntax checks of the expression */
1326 for (i = j = last_not = 0; c[i]; i++) {
1327 if (c[i] == '(') {
Radek Krejci69b8d922016-07-27 13:13:41 +02001328 checkversion = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001329 j++;
1330 continue;
1331 } else if (c[i] == ')') {
1332 j--;
1333 continue;
1334 } else if (isspace(c[i])) {
1335 continue;
1336 }
1337
1338 if (!strncmp(&c[i], "not", r = 3) || !strncmp(&c[i], "and", r = 3) || !strncmp(&c[i], "or", r = 2)) {
1339 if (c[i + r] == '\0') {
Radek Krejcia98da3f2016-07-27 14:05:22 +02001340 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
Radek Krejci9ff0a922016-07-14 13:08:05 +02001341 return EXIT_FAILURE;
1342 } else if (!isspace(c[i + r])) {
1343 /* feature name starting with the not/and/or */
1344 last_not = 0;
1345 f_size++;
1346 } else if (c[i] == 'n') { /* not operation */
1347 if (last_not) {
1348 /* double not */
1349 expr_size = expr_size - 2;
1350 last_not = 0;
1351 } else {
1352 last_not = 1;
1353 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001354 } else { /* and, or */
1355 f_exp++;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001356 /* not a not operation */
1357 last_not = 0;
1358 }
1359 i += r;
1360 } else {
1361 f_size++;
1362 last_not = 0;
1363 }
1364 expr_size++;
1365
1366 while (!isspace(c[i])) {
1367 if (!c[i] || c[i] == ')') {
1368 i--;
1369 break;
1370 }
1371 i++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001372 }
1373 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001374 if (j || f_exp != f_size) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001375 /* not matching count of ( and ) */
1376 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1377 return EXIT_FAILURE;
1378 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001379
Radek Krejci69b8d922016-07-27 13:13:41 +02001380 if (checkversion || expr_size > 1) {
1381 /* check that we have 1.1 module */
1382 if (node->module->version != 2) {
1383 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1384 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "YANG 1.1 if-feature expression found in 1.0 module.");
1385 return EXIT_FAILURE;
1386 }
1387 }
1388
Radek Krejci9ff0a922016-07-14 13:08:05 +02001389 /* allocate the memory */
1390 iffeat_expr->expr = calloc((j = (expr_size / 4) + ((expr_size % 4) ? 1 : 0)), sizeof *iffeat_expr->expr);
Radek Krejcicbb473e2016-09-16 14:48:32 +02001391 iffeat_expr->features = calloc(f_size, sizeof *iffeat_expr->features);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001392 stack.size = expr_size;
1393 stack.stack = malloc(expr_size * sizeof *stack.stack);
1394 if (!stack.stack || !iffeat_expr->expr || !iffeat_expr->features) {
1395 LOGMEM;
1396 goto error;
1397 }
1398 f_size--; expr_size--; /* used as indexes from now */
1399
1400 for (i--; i >= 0; i--) {
1401 if (c[i] == ')') {
1402 /* push it on stack */
1403 iff_stack_push(&stack, LYS_IFF_RP);
1404 continue;
1405 } else if (c[i] == '(') {
1406 /* pop from the stack into result all operators until ) */
1407 while((op = iff_stack_pop(&stack)) != LYS_IFF_RP) {
1408 iff_setop(iffeat_expr->expr, op, expr_size--);
1409 }
1410 continue;
1411 } else if (isspace(c[i])) {
1412 continue;
1413 }
1414
1415 /* end operator or operand -> find beginning and get what is it */
1416 j = i + 1;
1417 while (i >= 0 && !isspace(c[i]) && c[i] != '(') {
1418 i--;
1419 }
1420 i++; /* get back by one step */
1421
1422 if (!strncmp(&c[i], "not ", 4)) {
1423 if (stack.index && stack.stack[stack.index - 1] == LYS_IFF_NOT) {
1424 /* double not */
1425 iff_stack_pop(&stack);
1426 } else {
1427 /* not has the highest priority, so do not pop from the stack
1428 * as in case of AND and OR */
1429 iff_stack_push(&stack, LYS_IFF_NOT);
1430 }
1431 } else if (!strncmp(&c[i], "and ", 4)) {
1432 /* as for OR - pop from the stack all operators with the same or higher
1433 * priority and store them to the result, then push the AND to the stack */
1434 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_AND) {
1435 op = iff_stack_pop(&stack);
1436 iff_setop(iffeat_expr->expr, op, expr_size--);
1437 }
1438 iff_stack_push(&stack, LYS_IFF_AND);
1439 } else if (!strncmp(&c[i], "or ", 3)) {
1440 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_OR) {
1441 op = iff_stack_pop(&stack);
1442 iff_setop(iffeat_expr->expr, op, expr_size--);
1443 }
1444 iff_stack_push(&stack, LYS_IFF_OR);
1445 } else {
1446 /* feature name, length is j - i */
1447
1448 /* add it to the result */
1449 iff_setop(iffeat_expr->expr, LYS_IFF_F, expr_size--);
1450
1451 /* now get the link to the feature definition. Since it can be
Radek Krejcicbb473e2016-09-16 14:48:32 +02001452 * forward referenced, we have to keep the feature name in auxiliary
1453 * structure passed into unres */
1454 iff_data = malloc(sizeof *iff_data);
1455 iff_data->node = node;
1456 iff_data->fname = lydict_insert(node->module->ctx, &c[i], j - i);
1457 r = unres_schema_add_node(node->module, unres, &iffeat_expr->features[f_size], UNRES_IFFEAT,
1458 (struct lys_node *)iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001459 f_size--;
1460
1461 if (r == -1) {
1462 goto error;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001463 }
1464 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001465 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001466 while (stack.index) {
1467 op = iff_stack_pop(&stack);
1468 iff_setop(iffeat_expr->expr, op, expr_size--);
1469 }
1470
1471 if (++expr_size || ++f_size) {
1472 /* not all expected operators and operands found */
1473 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1474 rc = EXIT_FAILURE;
1475 } else {
1476 rc = EXIT_SUCCESS;
1477 }
1478
1479error:
1480 /* cleanup */
1481 iff_stack_clean(&stack);
1482
1483 return rc;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001484}
1485
1486/**
Michal Vasko3edeaf72016-02-11 13:17:43 +01001487 * @brief Resolve (find) a data node based on a schema-nodeid.
1488 *
1489 * Used for resolving unique statements - so id is expected to be relative and local (without reference to a different
1490 * module).
1491 *
1492 */
1493struct lyd_node *
1494resolve_data_descendant_schema_nodeid(const char *nodeid, struct lyd_node *start)
1495{
1496 char *str, *token, *p;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001497 struct lyd_node *result = NULL, *iter;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001498 const struct lys_node *schema = NULL;
Radek Krejcicc217a62016-04-08 16:58:11 +02001499 int shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001500
1501 assert(nodeid && start);
1502
1503 if (nodeid[0] == '/') {
1504 return NULL;
1505 }
1506
1507 str = p = strdup(nodeid);
1508 if (!str) {
1509 LOGMEM;
1510 return NULL;
1511 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001512
Michal Vasko3edeaf72016-02-11 13:17:43 +01001513 while (p) {
1514 token = p;
1515 p = strchr(p, '/');
1516 if (p) {
1517 *p = '\0';
1518 p++;
1519 }
1520
Radek Krejci5da4eb62016-04-08 14:45:51 +02001521 if (p) {
1522 /* inner node */
Radek Krejcicc217a62016-04-08 16:58:11 +02001523 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema,
Radek Krejcif3c71de2016-04-11 12:45:46 +02001524 LYS_CONTAINER | LYS_CHOICE | LYS_CASE | LYS_LEAF, 0, 0, &schema)
Radek Krejci5da4eb62016-04-08 14:45:51 +02001525 || !schema) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001526 result = NULL;
1527 break;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001528 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001529
Radek Krejci5da4eb62016-04-08 14:45:51 +02001530 if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
1531 continue;
Michal Vaskodcf98e62016-05-05 17:53:53 +02001532 } else if (lys_parent(schema)->nodetype == LYS_CHOICE) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001533 /* shorthand case */
1534 if (!shorthand) {
1535 shorthand = 1;
Michal Vaskodcf98e62016-05-05 17:53:53 +02001536 schema = lys_parent(schema);
Radek Krejcicc217a62016-04-08 16:58:11 +02001537 continue;
1538 } else {
1539 shorthand = 0;
1540 if (schema->nodetype == LYS_LEAF) {
1541 /* should not be here, since we have leaf, which is not a shorthand nor final node */
1542 result = NULL;
1543 break;
1544 }
1545 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001546 }
1547 } else {
1548 /* final node */
Radek Krejcif3c71de2016-04-11 12:45:46 +02001549 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema, LYS_LEAF,
1550 shorthand ? 0 : 1, 0, &schema)
Radek Krejcicc217a62016-04-08 16:58:11 +02001551 || !schema) {
1552 result = NULL;
1553 break;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001554 }
1555 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001556 LY_TREE_FOR(result ? result->child : start, iter) {
1557 if (iter->schema == schema) {
1558 /* move in data tree according to returned schema */
1559 result = iter;
1560 break;
1561 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001562 }
Radek Krejcicc217a62016-04-08 16:58:11 +02001563 if (!iter) {
1564 /* instance not found */
1565 result = NULL;
1566 break;
1567 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001568 }
1569 free(str);
1570
1571 return result;
1572}
1573
Radek Krejcibdf92362016-04-08 14:43:34 +02001574/*
1575 * 0 - ok (done)
1576 * 1 - continue
1577 * 2 - break
1578 * -1 - error
1579 */
1580static int
Radek Krejcicc217a62016-04-08 16:58:11 +02001581schema_nodeid_siblingcheck(const struct lys_node *sibling, int8_t *shorthand, const char *id,
Radek Krejcibdf92362016-04-08 14:43:34 +02001582 const struct lys_module *module, const char *mod_name, int mod_name_len,
Radek Krejci0fa54e92016-09-14 14:01:05 +02001583 int implemented_mod, const struct lys_node **start)
Radek Krejcibdf92362016-04-08 14:43:34 +02001584{
1585 const struct lys_module *prefix_mod;
Radek Krejcicc217a62016-04-08 16:58:11 +02001586 int sh = 0;
Radek Krejcibdf92362016-04-08 14:43:34 +02001587
1588 /* module check */
1589 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Radek Krejci0fa54e92016-09-14 14:01:05 +02001590 if (implemented_mod) {
1591 prefix_mod = lys_get_implemented_module(prefix_mod);
1592 }
Radek Krejcibdf92362016-04-08 14:43:34 +02001593 if (!prefix_mod) {
1594 return -1;
1595 }
1596 if (prefix_mod != lys_node_module(sibling)) {
1597 return 1;
1598 }
1599
1600 /* check for shorthand cases - then 'start' does not change */
Michal Vaskodcf98e62016-05-05 17:53:53 +02001601 if (lys_parent(sibling) && (lys_parent(sibling)->nodetype == LYS_CHOICE) && (sibling->nodetype != LYS_CASE)) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001602 if (*shorthand != -1) {
1603 *shorthand = *shorthand ? 0 : 1;
1604 }
1605 sh = 1;
Radek Krejcibdf92362016-04-08 14:43:34 +02001606 }
1607
1608 /* the result node? */
1609 if (!id[0]) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001610 if (*shorthand == 1) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001611 return 1;
1612 }
1613 return 0;
1614 }
1615
Radek Krejcicc217a62016-04-08 16:58:11 +02001616 if (!sh) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001617 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02001618 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001619 return -1;
1620 }
1621 *start = sibling->child;
1622 }
1623
1624 return 2;
1625}
1626
Michal Vasko3edeaf72016-02-11 13:17:43 +01001627/* start - relative, module - absolute, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1628int
1629resolve_augment_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_module *module,
1630 const struct lys_node **ret)
1631{
1632 const char *name, *mod_name, *id;
1633 const struct lys_node *sibling;
1634 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001635 int8_t shorthand = 0;
Radek Krejci0fa54e92016-09-14 14:01:05 +02001636 int implemented_search = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001637 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcibdf92362016-04-08 14:43:34 +02001638 const struct lys_module *start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001639
1640 assert(nodeid && (start || module) && !(start && module) && ret);
1641
1642 id = nodeid;
1643
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001644 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001645 return ((id - nodeid) - r) + 1;
1646 }
1647 id += r;
1648
1649 if ((is_relative && !start) || (!is_relative && !module)) {
1650 return -1;
1651 }
1652
1653 /* descendant-schema-nodeid */
1654 if (is_relative) {
Michal Vasko4c06fd82016-02-17 13:43:38 +01001655 module = start_mod = start->module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001656
1657 /* absolute-schema-nodeid */
1658 } else {
1659 start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Radek Krejci0fa54e92016-09-14 14:01:05 +02001660 if (start_mod != lys_main_module(module)) {
1661 /* if the submodule augments the mainmodule (or in general a module augments
1662 * itself, we don't want to search for the implemented module but augments
1663 * the module anyway. But when augmenting another module, we need the implemented
1664 * revision of the module if any */
1665 start_mod = lys_get_implemented_module(start_mod);
1666 implemented_search = 1;
1667 }
Michal Vaskoe2905632016-02-11 15:42:24 +01001668 if (!start_mod) {
1669 return -1;
1670 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001671 start = start_mod->data;
1672 }
1673
1674 while (1) {
1675 sibling = NULL;
1676 while ((sibling = lys_getnext(sibling, lys_parent(start), start_mod,
1677 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
1678 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001679 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001680 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len,
1681 implemented_search, &start);
Radek Krejcibdf92362016-04-08 14:43:34 +02001682 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001683 *ret = sibling;
1684 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001685 } else if (r == 1) {
1686 continue;
1687 } else if (r == 2) {
1688 break;
1689 } else {
1690 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001691 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001692 }
1693 }
1694
1695 /* no match */
1696 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001697 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001698 return EXIT_SUCCESS;
1699 }
1700
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001701 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001702 return ((id - nodeid) - r) + 1;
1703 }
1704 id += r;
1705 }
1706
1707 /* cannot get here */
1708 LOGINT;
1709 return -1;
1710}
1711
Radek Krejcif3c71de2016-04-11 12:45:46 +02001712/* unique, refine,
1713 * >0 - unexpected char on position (ret - 1),
1714 * 0 - ok (but ret can still be NULL),
1715 * -1 - error,
1716 * -2 - violated no_innerlist */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001717int
1718resolve_descendant_schema_nodeid(const char *nodeid, const struct lys_node *start, int ret_nodetype,
Radek Krejcif3c71de2016-04-11 12:45:46 +02001719 int check_shorthand, int no_innerlist, const struct lys_node **ret)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001720{
1721 const char *name, *mod_name, *id;
1722 const struct lys_node *sibling;
1723 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001724 int8_t shorthand = check_shorthand ? 0 : -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001725 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcibdf92362016-04-08 14:43:34 +02001726 const struct lys_module *module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001727
1728 assert(nodeid && start && ret);
1729 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1730
1731 id = nodeid;
1732 module = start->module;
1733
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001734 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001735 return ((id - nodeid) - r) + 1;
1736 }
1737 id += r;
1738
1739 if (!is_relative) {
1740 return -1;
1741 }
1742
1743 while (1) {
1744 sibling = NULL;
1745 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
1746 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE))) {
1747 /* name match */
1748 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001749 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len, 0, &start);
Radek Krejcibdf92362016-04-08 14:43:34 +02001750 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001751 if (!(sibling->nodetype & ret_nodetype)) {
1752 /* wrong node type, too bad */
1753 continue;
1754 }
1755 *ret = sibling;
1756 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001757 } else if (r == 1) {
1758 continue;
1759 } else if (r == 2) {
1760 break;
1761 } else {
1762 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001763 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001764 }
1765 }
1766
1767 /* no match */
1768 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001769 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001770 return EXIT_SUCCESS;
Radek Krejcif3c71de2016-04-11 12:45:46 +02001771 } else if (no_innerlist && sibling->nodetype == LYS_LIST) {
1772 *ret = NULL;
1773 return -2;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001774 }
1775
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001776 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001777 return ((id - nodeid) - r) + 1;
1778 }
1779 id += r;
1780 }
1781
1782 /* cannot get here */
1783 LOGINT;
1784 return -1;
1785}
1786
1787/* choice default */
1788int
1789resolve_choice_default_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node **ret)
1790{
1791 /* cannot actually be a path */
1792 if (strchr(nodeid, '/')) {
1793 return -1;
1794 }
1795
Radek Krejcif3c71de2016-04-11 12:45:46 +02001796 return resolve_descendant_schema_nodeid(nodeid, start, LYS_NO_RPC_NOTIF_NODE, 1, 0, ret);
Michal Vasko3edeaf72016-02-11 13:17:43 +01001797}
1798
1799/* uses, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1800static int
1801resolve_uses_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node_grp **ret)
1802{
1803 const struct lys_module *module;
1804 const char *mod_prefix, *name;
1805 int i, mod_prefix_len, nam_len;
1806
1807 /* parse the identifier, it must be parsed on one call */
1808 if (((i = parse_node_identifier(nodeid, &mod_prefix, &mod_prefix_len, &name, &nam_len)) < 1) || nodeid[i]) {
1809 return -i + 1;
1810 }
1811
1812 module = lys_get_import_module(start->module, mod_prefix, mod_prefix_len, NULL, 0);
1813 if (!module) {
1814 return -1;
1815 }
1816 if (module != start->module) {
1817 start = module->data;
1818 }
1819
1820 *ret = lys_find_grouping_up(name, (struct lys_node *)start);
1821
1822 return EXIT_SUCCESS;
1823}
1824
1825int
1826resolve_absolute_schema_nodeid(const char *nodeid, const struct lys_module *module, int ret_nodetype,
1827 const struct lys_node **ret)
1828{
1829 const char *name, *mod_name, *id;
1830 const struct lys_node *sibling, *start;
1831 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001832 int8_t shorthand = 0;
Radek Krejcibdf92362016-04-08 14:43:34 +02001833 const struct lys_module *abs_start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001834
1835 assert(nodeid && module && ret);
1836 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1837
1838 id = nodeid;
1839 start = module->data;
1840
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001841 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001842 return ((id - nodeid) - r) + 1;
1843 }
1844 id += r;
1845
1846 if (is_relative) {
1847 return -1;
1848 }
1849
1850 abs_start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001851 if (!abs_start_mod) {
1852 return -1;
1853 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001854
1855 while (1) {
1856 sibling = NULL;
1857 while ((sibling = lys_getnext(sibling, lys_parent(start), abs_start_mod, LYS_GETNEXT_WITHCHOICE
1858 | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_WITHGROUPING))) {
1859 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001860 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001861 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len, 0, &start);
Radek Krejcibdf92362016-04-08 14:43:34 +02001862 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001863 if (!(sibling->nodetype & ret_nodetype)) {
1864 /* wrong node type, too bad */
1865 continue;
1866 }
1867 *ret = sibling;
1868 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001869 } else if (r == 1) {
1870 continue;
1871 } else if (r == 2) {
1872 break;
1873 } else {
1874 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001875 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001876 }
1877 }
1878
1879 /* no match */
1880 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001881 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001882 return EXIT_SUCCESS;
1883 }
1884
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001885 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001886 return ((id - nodeid) - r) + 1;
1887 }
1888 id += r;
1889 }
1890
1891 /* cannot get here */
1892 LOGINT;
1893 return -1;
1894}
1895
Michal Vaskoe733d682016-03-14 09:08:27 +01001896static int
Michal Vasko3547c532016-03-14 09:40:50 +01001897resolve_json_schema_list_predicate(const char *predicate, const struct lys_node_list *list, int *parsed)
Michal Vaskoe733d682016-03-14 09:08:27 +01001898{
1899 const char *name;
1900 int nam_len, has_predicate, i;
1901
Michal Vasko7b54f7e2016-05-03 15:07:31 +02001902 if (((i = parse_schema_json_predicate(predicate, &name, &nam_len, NULL, NULL, &has_predicate)) < 1)
1903 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001904 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-i], &predicate[-i]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001905 return -1;
1906 }
1907
1908 predicate += i;
1909 *parsed += i;
1910
1911 for (i = 0; i < list->keys_size; ++i) {
1912 if (!strncmp(list->keys[i]->name, name, nam_len) && !list->keys[i]->name[nam_len]) {
1913 break;
1914 }
1915 }
1916
1917 if (i == list->keys_size) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001918 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskoe733d682016-03-14 09:08:27 +01001919 return -1;
1920 }
1921
1922 /* more predicates? */
1923 if (has_predicate) {
Michal Vasko3547c532016-03-14 09:40:50 +01001924 return resolve_json_schema_list_predicate(predicate, list, parsed);
Michal Vaskoe733d682016-03-14 09:08:27 +01001925 }
1926
1927 return 0;
1928}
1929
Michal Vasko8d26e5c2016-09-08 10:03:49 +02001930/* cannot return LYS_GROUPING, LYS_AUGMENT, LYS_USES, logs directly */
Michal Vaskoe733d682016-03-14 09:08:27 +01001931const struct lys_node *
Michal Vasko8d26e5c2016-09-08 10:03:49 +02001932resolve_json_nodeid(const char *nodeid, struct ly_ctx *ctx, const struct lys_node *start)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001933{
Michal Vasko10728b52016-04-07 14:26:29 +02001934 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001935 const char *name, *mod_name, *id;
Michal Vasko3547c532016-03-14 09:40:50 +01001936 const struct lys_node *sibling;
Radek Krejcibdf92362016-04-08 14:43:34 +02001937 int r, nam_len, mod_name_len, is_relative = -1, has_predicate, shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001938 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vaskoe733d682016-03-14 09:08:27 +01001939 const struct lys_module *prefix_mod, *module, *prev_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001940
Michal Vasko3547c532016-03-14 09:40:50 +01001941 assert(nodeid && (ctx || start));
1942 if (!ctx) {
1943 ctx = start->module->ctx;
1944 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001945
1946 id = nodeid;
1947
Michal Vaskoe733d682016-03-14 09:08:27 +01001948 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate)) < 1) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001949 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001950 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001951 }
1952 id += r;
1953
1954 if (is_relative) {
Michal Vasko3547c532016-03-14 09:40:50 +01001955 assert(start);
1956 start = start->child;
1957 if (!start) {
1958 /* no descendants, fail for sure */
Michal Vasko10728b52016-04-07 14:26:29 +02001959 str = strndup(nodeid, (name + nam_len) - nodeid);
1960 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
1961 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01001962 return NULL;
1963 }
1964 module = start->module;
1965 } else {
1966 if (!mod_name) {
Michal Vasko10728b52016-04-07 14:26:29 +02001967 str = strndup(nodeid, (name + nam_len) - nodeid);
1968 LOGVAL(LYE_PATH_MISSMOD, LY_VLOG_STR, nodeid);
1969 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01001970 return NULL;
Michal Vasko971a3ca2016-04-01 13:09:29 +02001971 } else if (mod_name_len > LY_BUF_SIZE - 1) {
1972 LOGINT;
1973 return NULL;
Michal Vasko3547c532016-03-14 09:40:50 +01001974 }
1975
Michal Vasko971a3ca2016-04-01 13:09:29 +02001976 if (ly_buf_used && module_name[0]) {
1977 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
1978 }
1979 ly_buf_used++;
1980
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02001981 memmove(module_name, mod_name, mod_name_len);
Michal Vasko971a3ca2016-04-01 13:09:29 +02001982 module_name[mod_name_len] = '\0';
1983 module = ly_ctx_get_module(ctx, module_name, NULL);
1984
1985 if (buf_backup) {
1986 /* return previous internal buffer content */
1987 strcpy(module_name, buf_backup);
1988 free(buf_backup);
1989 buf_backup = NULL;
1990 }
1991 ly_buf_used--;
1992
Michal Vasko3547c532016-03-14 09:40:50 +01001993 if (!module) {
Michal Vasko10728b52016-04-07 14:26:29 +02001994 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
1995 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
1996 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01001997 return NULL;
1998 }
1999 start = module->data;
2000
2001 /* now it's as if there was no module name */
2002 mod_name = NULL;
2003 mod_name_len = 0;
Michal Vaskoe733d682016-03-14 09:08:27 +01002004 }
2005
Michal Vaskoe733d682016-03-14 09:08:27 +01002006 prev_mod = module;
2007
Michal Vasko3edeaf72016-02-11 13:17:43 +01002008 while (1) {
2009 sibling = NULL;
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002010 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
2011 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002012 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02002013 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002014 /* module check */
2015 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002016 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko8757e7c2016-03-15 10:41:30 +01002017 LOGINT;
2018 return NULL;
2019 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002020
2021 if (ly_buf_used && module_name[0]) {
2022 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2023 }
2024 ly_buf_used++;
2025
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002026 memmove(module_name, mod_name, mod_name_len);
Michal Vasko8757e7c2016-03-15 10:41:30 +01002027 module_name[mod_name_len] = '\0';
2028 /* will also find an augment module */
2029 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002030
2031 if (buf_backup) {
2032 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002033 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002034 free(buf_backup);
2035 buf_backup = NULL;
2036 }
2037 ly_buf_used--;
2038
Michal Vasko3edeaf72016-02-11 13:17:43 +01002039 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002040 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2041 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2042 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002043 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002044 }
2045 } else {
2046 prefix_mod = prev_mod;
2047 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01002048 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002049 continue;
2050 }
2051
Michal Vaskoe733d682016-03-14 09:08:27 +01002052 /* do we have some predicates on it? */
2053 if (has_predicate) {
2054 r = 0;
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002055 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
2056 if ((r = parse_schema_json_predicate(id, NULL, NULL, NULL, NULL, &has_predicate)) < 1) {
2057 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2058 return NULL;
2059 }
2060 } else if (sibling->nodetype == LYS_LIST) {
2061 if (resolve_json_schema_list_predicate(id, (const struct lys_node_list *)sibling, &r)) {
2062 return NULL;
2063 }
2064 } else {
Michal Vasko43c300e2016-03-22 12:54:27 +01002065 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vaskoe733d682016-03-14 09:08:27 +01002066 return NULL;
Michal Vaskoe733d682016-03-14 09:08:27 +01002067 }
2068 id += r;
2069 }
2070
Radek Krejcibdf92362016-04-08 14:43:34 +02002071 /* check for shorthand cases - then 'start' does not change */
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002072 if (lys_parent(sibling) && (lys_parent(sibling)->nodetype == LYS_CHOICE) && (sibling->nodetype != LYS_CASE)) {
Radek Krejcibdf92362016-04-08 14:43:34 +02002073 shorthand = ~shorthand;
2074 }
2075
Michal Vasko3edeaf72016-02-11 13:17:43 +01002076 /* the result node? */
2077 if (!id[0]) {
Radek Krejcibdf92362016-04-08 14:43:34 +02002078 if (shorthand) {
2079 /* wrong path for shorthand */
Michal Vasko025e0452016-05-17 16:14:20 +02002080 str = strndup(nodeid, (name + nam_len) - nodeid);
2081 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
Michal Vasko3c0f9f52016-05-17 16:38:10 +02002082 LOGVAL(LYE_SPEC, LY_VLOG_STR, str, "Schema shorthand case path must include the virtual case statement.");
Radek Krejci9a5fccc2016-05-18 15:44:58 +02002083 free(str);
Michal Vasko025e0452016-05-17 16:14:20 +02002084 return NULL;
Radek Krejcibdf92362016-04-08 14:43:34 +02002085 }
Michal Vaskoe733d682016-03-14 09:08:27 +01002086 return sibling;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002087 }
2088
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002089 if (!shorthand) {
Michal Vasko7dc71d02016-03-15 10:42:28 +01002090 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002091 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002092 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko7dc71d02016-03-15 10:42:28 +01002093 return NULL;
2094 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01002095 start = sibling->child;
2096 }
2097
2098 /* update prev mod */
2099 prev_mod = start->module;
2100 break;
2101 }
2102 }
2103
2104 /* no match */
2105 if (!sibling) {
Michal Vasko10728b52016-04-07 14:26:29 +02002106 str = strndup(nodeid, (name + nam_len) - nodeid);
2107 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
2108 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002109 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002110 }
2111
Michal Vaskoe733d682016-03-14 09:08:27 +01002112 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate)) < 1) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002113 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002114 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002115 }
2116 id += r;
2117 }
2118
2119 /* cannot get here */
2120 LOGINT;
Michal Vaskoe733d682016-03-14 09:08:27 +01002121 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002122}
2123
Michal Vasko22448d32016-03-16 13:17:29 +01002124static int
2125resolve_partial_json_data_list_predicate(const char *predicate, const char *node_name, struct lyd_node *node, int *parsed)
2126{
2127 const char *name, *value;
2128 int nam_len, val_len, has_predicate = 1, r;
2129 uint16_t i;
Michal Vaskof29903d2016-04-18 13:13:10 +02002130 struct lyd_node_leaf_list *key;
Michal Vasko22448d32016-03-16 13:17:29 +01002131
Radek Krejci61a86c62016-03-24 11:06:44 +01002132 assert(node);
Michal Vasko22448d32016-03-16 13:17:29 +01002133 assert(node->schema->nodetype == LYS_LIST);
2134
Michal Vaskof29903d2016-04-18 13:13:10 +02002135 key = (struct lyd_node_leaf_list *)node->child;
2136 for (i = 0; i < ((struct lys_node_list *)node->schema)->keys_size; ++i) {
2137 if (!key) {
2138 /* invalid data */
2139 LOGINT;
2140 return -1;
2141 }
Michal Vasko22448d32016-03-16 13:17:29 +01002142
Michal Vasko22448d32016-03-16 13:17:29 +01002143 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002144 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, node_name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002145 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002146 }
2147
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002148 if (((r = parse_schema_json_predicate(predicate, &name, &nam_len, &value, &val_len, &has_predicate)) < 1)
2149 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002150 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
Michal Vaskof29903d2016-04-18 13:13:10 +02002151 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002152 }
2153
2154 predicate += r;
2155 *parsed += r;
2156
Michal Vaskof29903d2016-04-18 13:13:10 +02002157 if (strncmp(key->schema->name, name, nam_len) || key->schema->name[nam_len]) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002158 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002159 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002160 }
2161
2162 /* value does not match */
Michal Vaskof29903d2016-04-18 13:13:10 +02002163 if (strncmp(key->value_str, value, val_len) || key->value_str[val_len]) {
Michal Vasko22448d32016-03-16 13:17:29 +01002164 return 1;
2165 }
Michal Vaskof29903d2016-04-18 13:13:10 +02002166
2167 key = (struct lyd_node_leaf_list *)key->next;
Michal Vasko22448d32016-03-16 13:17:29 +01002168 }
2169
2170 if (has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002171 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko22448d32016-03-16 13:17:29 +01002172 return -1;
2173 }
2174
2175 return 0;
2176}
2177
Radek Krejci45826012016-08-24 15:07:57 +02002178/**
2179 * @brief get the closest parent of the node (or the node itself) identified by the nodeid (path)
2180 *
2181 * @param[in] nodeid Node data path to find
2182 * @param[in] llist_value If the \p nodeid identifies leaf-list, this is expected value of the leaf-list instance.
2183 * @param[in] options Bitmask of options flags, see @ref pathoptions.
2184 * @param[out] parsed Number of characters processed in \p id
2185 * @return The closes parent (or the node itself) from the path
2186 */
Michal Vasko22448d32016-03-16 13:17:29 +01002187struct lyd_node *
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002188resolve_partial_json_data_nodeid(const char *nodeid, const char *llist_value, struct lyd_node *start, int options,
2189 int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002190{
Michal Vasko10728b52016-04-07 14:26:29 +02002191 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko22448d32016-03-16 13:17:29 +01002192 const char *id, *mod_name, *name;
2193 int r, ret, mod_name_len, nam_len, is_relative = -1, has_predicate, last_parsed;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002194 struct lyd_node *sibling, *last_match = NULL;
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002195 struct lyd_node_leaf_list *llist;
Michal Vasko22448d32016-03-16 13:17:29 +01002196 const struct lys_module *prefix_mod, *prev_mod;
2197 struct ly_ctx *ctx;
2198
2199 assert(nodeid && start && parsed);
2200
2201 ctx = start->schema->module->ctx;
2202 id = nodeid;
2203
2204 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate)) < 1) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002205 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002206 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002207 return NULL;
2208 }
2209 id += r;
2210 /* add it to parsed only after the data node was actually found */
2211 last_parsed = r;
2212
2213 if (is_relative) {
2214 prev_mod = start->schema->module;
Michal Vasko22448d32016-03-16 13:17:29 +01002215 start = start->child;
2216 } else {
2217 for (; start->parent; start = start->parent);
Michal Vasko22448d32016-03-16 13:17:29 +01002218 prev_mod = start->schema->module;
2219 }
2220
2221 while (1) {
2222 LY_TREE_FOR(start, sibling) {
Michal Vasko2411b942016-03-23 13:50:03 +01002223 /* RPC data check, return simply invalid argument, because the data tree is invalid */
2224 if (lys_parent(sibling->schema)) {
2225 if (options & LYD_PATH_OPT_OUTPUT) {
2226 if (lys_parent(sibling->schema)->nodetype == LYS_INPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002227 LOGERR(LY_EINVAL, "Provided data tree includes some RPC input nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002228 *parsed = -1;
2229 return NULL;
2230 }
2231 } else {
2232 if (lys_parent(sibling->schema)->nodetype == LYS_OUTPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002233 LOGERR(LY_EINVAL, "Provided data tree includes some RPC output nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002234 *parsed = -1;
2235 return NULL;
2236 }
2237 }
2238 }
2239
Michal Vasko22448d32016-03-16 13:17:29 +01002240 /* name match */
2241 if (!strncmp(name, sibling->schema->name, nam_len) && !sibling->schema->name[nam_len]) {
2242
2243 /* module check */
2244 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002245 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko22448d32016-03-16 13:17:29 +01002246 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002247 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002248 return NULL;
2249 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002250
2251 if (ly_buf_used && module_name[0]) {
2252 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2253 }
2254 ly_buf_used++;
2255
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002256 memmove(module_name, mod_name, mod_name_len);
Michal Vasko22448d32016-03-16 13:17:29 +01002257 module_name[mod_name_len] = '\0';
2258 /* will also find an augment module */
2259 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002260
2261 if (buf_backup) {
2262 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002263 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002264 free(buf_backup);
2265 buf_backup = NULL;
2266 }
2267 ly_buf_used--;
2268
Michal Vasko22448d32016-03-16 13:17:29 +01002269 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002270 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2271 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2272 free(str);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002273 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002274 return NULL;
2275 }
2276 } else {
2277 prefix_mod = prev_mod;
2278 }
2279 if (prefix_mod != lys_node_module(sibling->schema)) {
2280 continue;
2281 }
2282
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002283 /* leaf-list, did we find it with the correct value or not? */
Michal Vasko22448d32016-03-16 13:17:29 +01002284 if (sibling->schema->nodetype == LYS_LEAFLIST) {
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002285 llist = (struct lyd_node_leaf_list *)sibling;
2286 if ((!llist_value && llist->value_str && llist->value_str[0])
2287 || (llist_value && strcmp(llist_value, llist->value_str))) {
2288 continue;
2289 }
Radek Krejci45826012016-08-24 15:07:57 +02002290 } else if (sibling->schema->nodetype == LYS_LIST) {
2291 /* list, we need predicates'n'stuff then */
Michal Vasko22448d32016-03-16 13:17:29 +01002292 r = 0;
2293 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002294 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002295 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002296 return NULL;
2297 }
2298 ret = resolve_partial_json_data_list_predicate(id, name, sibling, &r);
2299 if (ret == -1) {
Michal Vasko238bd2f2016-03-23 09:39:01 +01002300 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002301 return NULL;
2302 } else if (ret == 1) {
2303 /* this list instance does not match */
2304 continue;
2305 }
2306 id += r;
2307 last_parsed += r;
2308 }
2309
2310 *parsed += last_parsed;
2311
2312 /* the result node? */
2313 if (!id[0]) {
2314 return sibling;
2315 }
2316
2317 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002318 if (sibling->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002319 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002320 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002321 return NULL;
2322 }
Michal Vaskoc6c52cf2016-03-29 11:53:04 +02002323 last_match = sibling;
Michal Vasko22448d32016-03-16 13:17:29 +01002324 start = sibling->child;
2325 if (start) {
2326 prev_mod = start->schema->module;
2327 }
2328 break;
2329 }
2330 }
2331
2332 /* no match, return last match */
2333 if (!sibling) {
2334 return last_match;
2335 }
2336
2337 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate)) < 1) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002338 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002339 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002340 return NULL;
2341 }
2342 id += r;
2343 last_parsed = r;
2344 }
2345
2346 /* cannot get here */
2347 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002348 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002349 return NULL;
2350}
2351
Michal Vasko3edeaf72016-02-11 13:17:43 +01002352/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02002353 * @brief Resolves length or range intervals. Does not log.
Michal Vaskoaeb51802016-04-11 10:58:47 +02002354 * Syntax is assumed to be correct, *ret MUST be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002355 *
Michal Vaskoaeb51802016-04-11 10:58:47 +02002356 * @param[in] str_restr Restriction as a string.
2357 * @param[in] type Type of the restriction.
2358 * @param[out] ret Final interval structure that starts with
2359 * the interval of the initial type, continues with intervals
2360 * of any superior types derived from the initial one, and
2361 * finishes with intervals from our \p type.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002362 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002363 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002364 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002365int
Michal Vaskoaeb51802016-04-11 10:58:47 +02002366resolve_len_ran_interval(const char *str_restr, struct lys_type *type, struct len_ran_intv **ret)
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002367{
2368 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002369 int kind;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002370 int64_t local_smin, local_smax, local_fmin, local_fmax;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002371 uint64_t local_umin, local_umax;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002372 uint8_t local_fdig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002373 const char *seg_ptr, *ptr;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002374 struct len_ran_intv *local_intv = NULL, *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002375
2376 switch (type->base) {
2377 case LY_TYPE_BINARY:
2378 kind = 0;
2379 local_umin = 0;
2380 local_umax = 18446744073709551615UL;
2381
2382 if (!str_restr && type->info.binary.length) {
2383 str_restr = type->info.binary.length->expr;
2384 }
2385 break;
2386 case LY_TYPE_DEC64:
2387 kind = 2;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002388 local_fmin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2389 local_fmax = __INT64_C(9223372036854775807);
2390 local_fdig = type->info.dec64.dig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002391
2392 if (!str_restr && type->info.dec64.range) {
2393 str_restr = type->info.dec64.range->expr;
2394 }
2395 break;
2396 case LY_TYPE_INT8:
2397 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002398 local_smin = __INT64_C(-128);
2399 local_smax = __INT64_C(127);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002400
2401 if (!str_restr && type->info.num.range) {
2402 str_restr = type->info.num.range->expr;
2403 }
2404 break;
2405 case LY_TYPE_INT16:
2406 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002407 local_smin = __INT64_C(-32768);
2408 local_smax = __INT64_C(32767);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002409
2410 if (!str_restr && type->info.num.range) {
2411 str_restr = type->info.num.range->expr;
2412 }
2413 break;
2414 case LY_TYPE_INT32:
2415 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002416 local_smin = __INT64_C(-2147483648);
2417 local_smax = __INT64_C(2147483647);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002418
2419 if (!str_restr && type->info.num.range) {
2420 str_restr = type->info.num.range->expr;
2421 }
2422 break;
2423 case LY_TYPE_INT64:
2424 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002425 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2426 local_smax = __INT64_C(9223372036854775807);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002427
2428 if (!str_restr && type->info.num.range) {
2429 str_restr = type->info.num.range->expr;
2430 }
2431 break;
2432 case LY_TYPE_UINT8:
2433 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002434 local_umin = __UINT64_C(0);
2435 local_umax = __UINT64_C(255);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002436
2437 if (!str_restr && type->info.num.range) {
2438 str_restr = type->info.num.range->expr;
2439 }
2440 break;
2441 case LY_TYPE_UINT16:
2442 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002443 local_umin = __UINT64_C(0);
2444 local_umax = __UINT64_C(65535);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002445
2446 if (!str_restr && type->info.num.range) {
2447 str_restr = type->info.num.range->expr;
2448 }
2449 break;
2450 case LY_TYPE_UINT32:
2451 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002452 local_umin = __UINT64_C(0);
2453 local_umax = __UINT64_C(4294967295);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002454
2455 if (!str_restr && type->info.num.range) {
2456 str_restr = type->info.num.range->expr;
2457 }
2458 break;
2459 case LY_TYPE_UINT64:
2460 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002461 local_umin = __UINT64_C(0);
2462 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002463
2464 if (!str_restr && type->info.num.range) {
2465 str_restr = type->info.num.range->expr;
2466 }
2467 break;
2468 case LY_TYPE_STRING:
2469 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002470 local_umin = __UINT64_C(0);
2471 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002472
2473 if (!str_restr && type->info.str.length) {
2474 str_restr = type->info.str.length->expr;
2475 }
2476 break;
2477 default:
2478 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002479 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002480 }
2481
2482 /* process superior types */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002483 if (type->der) {
2484 if (resolve_len_ran_interval(NULL, &type->der->type, &intv)) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002485 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002486 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02002487 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002488 assert(!intv || (intv->kind == kind));
2489 }
2490
2491 if (!str_restr) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002492 /* we do not have any restriction, return superior ones */
2493 *ret = intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002494 return EXIT_SUCCESS;
2495 }
2496
2497 /* adjust local min and max */
2498 if (intv) {
2499 tmp_intv = intv;
2500
2501 if (kind == 0) {
2502 local_umin = tmp_intv->value.uval.min;
2503 } else if (kind == 1) {
2504 local_smin = tmp_intv->value.sval.min;
2505 } else if (kind == 2) {
2506 local_fmin = tmp_intv->value.fval.min;
2507 }
2508
2509 while (tmp_intv->next) {
2510 tmp_intv = tmp_intv->next;
2511 }
2512
2513 if (kind == 0) {
2514 local_umax = tmp_intv->value.uval.max;
2515 } else if (kind == 1) {
2516 local_smax = tmp_intv->value.sval.max;
2517 } else if (kind == 2) {
2518 local_fmax = tmp_intv->value.fval.max;
2519 }
2520 }
2521
2522 /* finally parse our restriction */
2523 seg_ptr = str_restr;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002524 tmp_intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002525 while (1) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002526 if (!tmp_local_intv) {
2527 assert(!local_intv);
2528 local_intv = malloc(sizeof *local_intv);
2529 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002530 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002531 tmp_local_intv->next = malloc(sizeof *tmp_local_intv);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002532 tmp_local_intv = tmp_local_intv->next;
2533 }
Michal Vasko253035f2015-12-17 16:58:13 +01002534 if (!tmp_local_intv) {
2535 LOGMEM;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002536 goto error;
Michal Vasko253035f2015-12-17 16:58:13 +01002537 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002538
2539 tmp_local_intv->kind = kind;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002540 tmp_local_intv->type = type;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002541 tmp_local_intv->next = NULL;
2542
2543 /* min */
2544 ptr = seg_ptr;
2545 while (isspace(ptr[0])) {
2546 ++ptr;
2547 }
2548 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2549 if (kind == 0) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002550 tmp_local_intv->value.uval.min = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002551 } else if (kind == 1) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002552 tmp_local_intv->value.sval.min = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002553 } else if (kind == 2) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002554 tmp_local_intv->value.fval.min = parse_range_dec64(&ptr, local_fdig);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002555 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002556 } else if (!strncmp(ptr, "min", 3)) {
2557 if (kind == 0) {
2558 tmp_local_intv->value.uval.min = local_umin;
2559 } else if (kind == 1) {
2560 tmp_local_intv->value.sval.min = local_smin;
2561 } else if (kind == 2) {
2562 tmp_local_intv->value.fval.min = local_fmin;
2563 }
2564
2565 ptr += 3;
2566 } else if (!strncmp(ptr, "max", 3)) {
2567 if (kind == 0) {
2568 tmp_local_intv->value.uval.min = local_umax;
2569 } else if (kind == 1) {
2570 tmp_local_intv->value.sval.min = local_smax;
2571 } else if (kind == 2) {
2572 tmp_local_intv->value.fval.min = local_fmax;
2573 }
2574
2575 ptr += 3;
2576 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002577 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002578 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002579 }
2580
2581 while (isspace(ptr[0])) {
2582 ptr++;
2583 }
2584
2585 /* no interval or interval */
2586 if ((ptr[0] == '|') || !ptr[0]) {
2587 if (kind == 0) {
2588 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
2589 } else if (kind == 1) {
2590 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
2591 } else if (kind == 2) {
2592 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
2593 }
2594 } else if (!strncmp(ptr, "..", 2)) {
2595 /* skip ".." */
2596 ptr += 2;
2597 while (isspace(ptr[0])) {
2598 ++ptr;
2599 }
2600
2601 /* max */
2602 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2603 if (kind == 0) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002604 tmp_local_intv->value.uval.max = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002605 } else if (kind == 1) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002606 tmp_local_intv->value.sval.max = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002607 } else if (kind == 2) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002608 tmp_local_intv->value.fval.max = parse_range_dec64(&ptr, local_fdig);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002609 }
2610 } else if (!strncmp(ptr, "max", 3)) {
2611 if (kind == 0) {
2612 tmp_local_intv->value.uval.max = local_umax;
2613 } else if (kind == 1) {
2614 tmp_local_intv->value.sval.max = local_smax;
2615 } else if (kind == 2) {
2616 tmp_local_intv->value.fval.max = local_fmax;
2617 }
2618 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002619 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002620 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002621 }
2622 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002623 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002624 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002625 }
2626
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002627 /* check min and max in correct order*/
2628 if (kind == 0) {
2629 /* current segment */
2630 if (tmp_local_intv->value.uval.min > tmp_local_intv->value.uval.max) {
2631 goto error;
2632 }
2633 if (tmp_local_intv->value.uval.min < local_umin || tmp_local_intv->value.uval.max > local_umax) {
2634 goto error;
2635 }
2636 /* segments sholud be ascending order */
Pavol Vican69f62c92016-08-30 09:06:25 +02002637 if (tmp_intv && (tmp_intv->value.uval.max >= tmp_local_intv->value.uval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002638 goto error;
2639 }
2640 } else if (kind == 1) {
2641 if (tmp_local_intv->value.sval.min > tmp_local_intv->value.sval.max) {
2642 goto error;
2643 }
2644 if (tmp_local_intv->value.sval.min < local_smin || tmp_local_intv->value.sval.max > local_smax) {
2645 goto error;
2646 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002647 if (tmp_intv && (tmp_intv->value.sval.max >= tmp_local_intv->value.sval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002648 goto error;
2649 }
2650 } else if (kind == 2) {
2651 if (tmp_local_intv->value.fval.min > tmp_local_intv->value.fval.max) {
2652 goto error;
2653 }
2654 if (tmp_local_intv->value.fval.min < local_fmin || tmp_local_intv->value.fval.max > local_fmax) {
2655 goto error;
2656 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002657 if (tmp_intv && (tmp_intv->value.fval.max >= tmp_local_intv->value.fval.min)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002658 /* fraction-digits value is always the same (it cannot be changed in derived types) */
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002659 goto error;
2660 }
2661 }
2662
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002663 /* next segment (next OR) */
2664 seg_ptr = strchr(seg_ptr, '|');
2665 if (!seg_ptr) {
2666 break;
2667 }
2668 seg_ptr++;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002669 tmp_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002670 }
2671
2672 /* check local restrictions against superior ones */
2673 if (intv) {
2674 tmp_intv = intv;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002675 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002676
2677 while (tmp_local_intv && tmp_intv) {
2678 /* reuse local variables */
2679 if (kind == 0) {
2680 local_umin = tmp_local_intv->value.uval.min;
2681 local_umax = tmp_local_intv->value.uval.max;
2682
2683 /* it must be in this interval */
2684 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
2685 /* this interval is covered, next one */
2686 if (local_umax <= tmp_intv->value.uval.max) {
2687 tmp_local_intv = tmp_local_intv->next;
2688 continue;
2689 /* ascending order of restrictions -> fail */
2690 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002691 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002692 }
2693 }
2694 } else if (kind == 1) {
2695 local_smin = tmp_local_intv->value.sval.min;
2696 local_smax = tmp_local_intv->value.sval.max;
2697
2698 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
2699 if (local_smax <= tmp_intv->value.sval.max) {
2700 tmp_local_intv = tmp_local_intv->next;
2701 continue;
2702 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002703 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002704 }
2705 }
2706 } else if (kind == 2) {
2707 local_fmin = tmp_local_intv->value.fval.min;
2708 local_fmax = tmp_local_intv->value.fval.max;
2709
Michal Vasko4d1f0482016-09-19 14:35:06 +02002710 if ((dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.min, local_fdig) > -1)
2711 && (dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.max, local_fdig) > 1)) {
2712 if (dec64cmp(local_fmax, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002713 tmp_local_intv = tmp_local_intv->next;
2714 continue;
2715 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002716 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002717 }
2718 }
2719 }
2720
2721 tmp_intv = tmp_intv->next;
2722 }
2723
2724 /* some interval left uncovered -> fail */
2725 if (tmp_local_intv) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002726 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002727 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002728 }
2729
Michal Vaskoaeb51802016-04-11 10:58:47 +02002730 /* append the local intervals to all the intervals of the superior types, return it all */
2731 if (intv) {
2732 for (tmp_intv = intv; tmp_intv->next; tmp_intv = tmp_intv->next);
2733 tmp_intv->next = local_intv;
2734 } else {
2735 intv = local_intv;
2736 }
2737 *ret = intv;
2738
2739 return EXIT_SUCCESS;
2740
2741error:
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002742 while (intv) {
2743 tmp_intv = intv->next;
2744 free(intv);
2745 intv = tmp_intv;
2746 }
Michal Vaskoaeb51802016-04-11 10:58:47 +02002747 while (local_intv) {
2748 tmp_local_intv = local_intv->next;
2749 free(local_intv);
2750 local_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002751 }
2752
Michal Vaskoaeb51802016-04-11 10:58:47 +02002753 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002754}
2755
Michal Vasko730dfdf2015-08-11 14:48:05 +02002756/**
Michal Vasko01c6fd22016-05-20 11:43:05 +02002757 * @brief Resolve a typedef, return only resolved typedefs if derived. If leafref, it must be
2758 * resolved for this function to return it. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002759 *
2760 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02002761 * @param[in] mod_name Typedef name module name.
2762 * @param[in] module Main module.
2763 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002764 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002765 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002766 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002767 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002768int
Michal Vasko1e62a092015-12-01 12:27:20 +01002769resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
2770 const struct lys_node *parent, struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002771{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002772 int i, j;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002773 struct lys_tpdf *tpdf, *match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002774 int tpdf_size;
2775
Michal Vasko1dca6882015-10-22 14:29:42 +02002776 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002777 /* no prefix, try built-in types */
2778 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
2779 if (!strcmp(ly_types[i].def->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002780 if (ret) {
2781 *ret = ly_types[i].def;
2782 }
2783 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002784 }
2785 }
2786 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02002787 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002788 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02002789 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002790 }
2791 }
2792
Michal Vasko1dca6882015-10-22 14:29:42 +02002793 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002794 /* search in local typedefs */
2795 while (parent) {
2796 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02002797 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02002798 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
2799 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002800 break;
2801
Radek Krejci76512572015-08-04 09:47:08 +02002802 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02002803 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
2804 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002805 break;
2806
Radek Krejci76512572015-08-04 09:47:08 +02002807 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02002808 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
2809 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002810 break;
2811
Radek Krejci76512572015-08-04 09:47:08 +02002812 case LYS_RPC:
Michal Vasko44fb6382016-06-29 11:12:27 +02002813 case LYS_ACTION:
2814 tpdf_size = ((struct lys_node_rpc_action *)parent)->tpdf_size;
2815 tpdf = ((struct lys_node_rpc_action *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002816 break;
2817
Radek Krejci76512572015-08-04 09:47:08 +02002818 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02002819 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
2820 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002821 break;
2822
Radek Krejci76512572015-08-04 09:47:08 +02002823 case LYS_INPUT:
2824 case LYS_OUTPUT:
Michal Vasko44fb6382016-06-29 11:12:27 +02002825 tpdf_size = ((struct lys_node_inout *)parent)->tpdf_size;
2826 tpdf = ((struct lys_node_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002827 break;
2828
2829 default:
Michal Vaskodcf98e62016-05-05 17:53:53 +02002830 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002831 continue;
2832 }
2833
2834 for (i = 0; i < tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002835 if (!strcmp(tpdf[i].name, name) && tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002836 match = &tpdf[i];
2837 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002838 }
2839 }
2840
Michal Vaskodcf98e62016-05-05 17:53:53 +02002841 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002842 }
Radek Krejcic071c542016-01-27 14:57:51 +01002843 } else {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002844 /* get module where to search */
Michal Vaskob6729c62015-10-21 12:09:47 +02002845 module = lys_get_import_module(module, NULL, 0, mod_name, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02002846 if (!module) {
2847 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002848 }
2849 }
2850
2851 /* search in top level typedefs */
2852 for (i = 0; i < module->tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002853 if (!strcmp(module->tpdf[i].name, name) && module->tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002854 match = &module->tpdf[i];
2855 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002856 }
2857 }
2858
2859 /* search in submodules */
Radek Krejcic071c542016-01-27 14:57:51 +01002860 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002861 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002862 if (!strcmp(module->inc[i].submodule->tpdf[j].name, name) && module->inc[i].submodule->tpdf[j].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002863 match = &module->inc[i].submodule->tpdf[j];
2864 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002865 }
2866 }
2867 }
2868
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002869 return EXIT_FAILURE;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002870
2871check_leafref:
2872 if (ret) {
2873 *ret = match;
2874 }
2875 if (match->type.base == LY_TYPE_LEAFREF) {
2876 while (!match->type.info.lref.path) {
2877 match = match->type.der;
2878 assert(match);
2879 }
Michal Vasko01c6fd22016-05-20 11:43:05 +02002880 }
2881 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002882}
2883
Michal Vasko1dca6882015-10-22 14:29:42 +02002884/**
2885 * @brief Check the default \p value of the \p type. Logs directly.
2886 *
2887 * @param[in] type Type definition to use.
2888 * @param[in] value Default value to check.
Michal Vasko56826402016-03-02 11:11:37 +01002889 * @param[in] module Type module.
Michal Vasko1dca6882015-10-22 14:29:42 +02002890 *
2891 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
2892 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002893static int
Radek Krejci48464ed2016-03-17 15:44:09 +01002894check_default(struct lys_type *type, const char *value, struct lys_module *module)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002895{
Radek Krejcibad2f172016-08-02 11:04:15 +02002896 struct lys_tpdf *base_tpdf = NULL;
Michal Vasko1dca6882015-10-22 14:29:42 +02002897 struct lyd_node_leaf_list node;
Radek Krejci37b756f2016-01-18 10:15:03 +01002898 int ret = EXIT_SUCCESS;
Michal Vasko1dca6882015-10-22 14:29:42 +02002899
Radek Krejcic13db382016-08-16 10:52:42 +02002900 if (type->base <= LY_TYPE_DER) {
Michal Vasko478c4652016-07-21 12:55:01 +02002901 /* the type was not resolved yet, nothing to do for now */
2902 return EXIT_FAILURE;
2903 }
2904
2905 if (!value) {
2906 /* we do not have a new default value, so is there any to check even, in some base type? */
2907 for (base_tpdf = type->der; base_tpdf->type.der; base_tpdf = base_tpdf->type.der) {
2908 if (base_tpdf->dflt) {
2909 value = base_tpdf->dflt;
2910 break;
2911 }
2912 }
2913
2914 if (!value) {
2915 /* no default value, nothing to check, all is well */
2916 return EXIT_SUCCESS;
2917 }
2918
2919 /* 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)? */
2920 switch (type->base) {
Michal Vasko478c4652016-07-21 12:55:01 +02002921 case LY_TYPE_IDENT:
2922 case LY_TYPE_INST:
2923 case LY_TYPE_LEAFREF:
2924 case LY_TYPE_BOOL:
2925 case LY_TYPE_EMPTY:
2926 /* these have no restrictions, so we would do the exact same work as the unres in the base typedef */
2927 return EXIT_SUCCESS;
Radek Krejcibad2f172016-08-02 11:04:15 +02002928 case LY_TYPE_BITS:
2929 /* the default value must match the restricted list of values, if the type was restricted */
2930 if (type->info.bits.count) {
2931 break;
2932 }
2933 return EXIT_SUCCESS;
2934 case LY_TYPE_ENUM:
2935 /* the default value must match the restricted list of values, if the type was restricted */
2936 if (type->info.enums.count) {
2937 break;
2938 }
2939 return EXIT_SUCCESS;
Michal Vasko478c4652016-07-21 12:55:01 +02002940 case LY_TYPE_DEC64:
2941 if (type->info.dec64.range) {
2942 break;
2943 }
2944 return EXIT_SUCCESS;
2945 case LY_TYPE_BINARY:
2946 if (type->info.binary.length) {
2947 break;
2948 }
2949 return EXIT_SUCCESS;
2950 case LY_TYPE_INT8:
2951 case LY_TYPE_INT16:
2952 case LY_TYPE_INT32:
2953 case LY_TYPE_INT64:
2954 case LY_TYPE_UINT8:
2955 case LY_TYPE_UINT16:
2956 case LY_TYPE_UINT32:
2957 case LY_TYPE_UINT64:
2958 if (type->info.num.range) {
2959 break;
2960 }
2961 return EXIT_SUCCESS;
2962 case LY_TYPE_STRING:
2963 if (type->info.str.length || type->info.str.patterns) {
2964 break;
2965 }
2966 return EXIT_SUCCESS;
2967 case LY_TYPE_UNION:
2968 /* way too much trouble learning whether we need to check the default again, so just do it */
2969 break;
2970 default:
2971 LOGINT;
2972 return -1;
2973 }
Radek Krejci55a161c2016-09-05 17:13:25 +02002974 } else if (type->base == LY_TYPE_EMPTY) {
2975 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "default", type->parent->name);
2976 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"empty\" data type cannot have a default value.");
2977 return -1;
Michal Vasko478c4652016-07-21 12:55:01 +02002978 }
2979
Michal Vasko1dca6882015-10-22 14:29:42 +02002980 /* dummy leaf */
Radek Krejci4fe36bd2016-03-17 16:47:16 +01002981 memset(&node, 0, sizeof node);
Michal Vasko1dca6882015-10-22 14:29:42 +02002982 node.value_str = value;
2983 node.value_type = type->base;
Radek Krejci37b756f2016-01-18 10:15:03 +01002984 node.schema = calloc(1, sizeof (struct lys_node_leaf));
Michal Vasko253035f2015-12-17 16:58:13 +01002985 if (!node.schema) {
2986 LOGMEM;
2987 return -1;
2988 }
Radek Krejcibad2f172016-08-02 11:04:15 +02002989 node.schema->name = strdup("fake-default");
Michal Vasko253035f2015-12-17 16:58:13 +01002990 if (!node.schema->name) {
2991 LOGMEM;
Michal Vaskof49eda02016-07-21 12:17:01 +02002992 free(node.schema);
Michal Vasko253035f2015-12-17 16:58:13 +01002993 return -1;
2994 }
Michal Vasko56826402016-03-02 11:11:37 +01002995 node.schema->module = module;
Radek Krejci37b756f2016-01-18 10:15:03 +01002996 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
Michal Vasko1dca6882015-10-22 14:29:42 +02002997
Radek Krejci37b756f2016-01-18 10:15:03 +01002998 if (type->base == LY_TYPE_LEAFREF) {
Michal Vasko1dca6882015-10-22 14:29:42 +02002999 if (!type->info.lref.target) {
3000 ret = EXIT_FAILURE;
3001 goto finish;
3002 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003003 ret = check_default(&type->info.lref.target->type, value, module);
Michal Vasko1dca6882015-10-22 14:29:42 +02003004
3005 } else if ((type->base == LY_TYPE_INST) || (type->base == LY_TYPE_IDENT)) {
3006 /* it was converted to JSON format before, nothing else sensible we can do */
3007
3008 } else {
Michal Vasko3767fb22016-07-21 12:10:57 +02003009 if (lyp_parse_value(&node, NULL, 1)) {
3010 ret = -1;
Radek Krejcibad2f172016-08-02 11:04:15 +02003011 if (base_tpdf) {
3012 /* default value was is defined in some base typedef */
3013 if ((type->base == LY_TYPE_BITS && type->der->type.der) ||
3014 (type->base == LY_TYPE_ENUM && type->der->type.der)) {
3015 /* we have refined bits/enums */
3016 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
3017 "Invalid value \"%s\" of the default statement inherited to \"%s\" from \"%s\" base type.",
3018 value, type->parent->name, base_tpdf->name);
3019 }
3020 }
Michal Vasko3767fb22016-07-21 12:10:57 +02003021 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003022 }
3023
3024finish:
3025 if (node.value_type == LY_TYPE_BITS) {
3026 free(node.value.bit);
3027 }
3028 free((char *)node.schema->name);
3029 free(node.schema);
3030
3031 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003032}
3033
Michal Vasko730dfdf2015-08-11 14:48:05 +02003034/**
3035 * @brief Check a key for mandatory attributes. Logs directly.
3036 *
3037 * @param[in] key The key to check.
3038 * @param[in] flags What flags to check.
3039 * @param[in] list The list of all the keys.
3040 * @param[in] index Index of the key in the key list.
3041 * @param[in] name The name of the keys.
3042 * @param[in] len The name length.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003043 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003044 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003045 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003046static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003047check_key(struct lys_node_list *list, int index, const char *name, int len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003048{
Radek Krejciadb57612016-02-16 13:34:34 +01003049 struct lys_node_leaf *key = list->keys[index];
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003050 char *dup = NULL;
3051 int j;
3052
3053 /* existence */
3054 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02003055 if (name[len] != '\0') {
3056 dup = strdup(name);
Michal Vasko253035f2015-12-17 16:58:13 +01003057 if (!dup) {
3058 LOGMEM;
3059 return -1;
3060 }
Michal Vaskof02e3742015-08-05 16:27:02 +02003061 dup[len] = '\0';
3062 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003063 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003064 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, list, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003065 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003066 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003067 }
3068
3069 /* uniqueness */
3070 for (j = index - 1; j >= 0; j--) {
Radek Krejciadb57612016-02-16 13:34:34 +01003071 if (key == list->keys[j]) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003072 LOGVAL(LYE_KEY_DUP, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003073 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003074 }
3075 }
3076
3077 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02003078 if (key->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003079 LOGVAL(LYE_KEY_NLEAF, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003080 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003081 }
3082
3083 /* type of the leaf is not built-in empty */
Radek Krejcic3738db2016-09-15 15:51:21 +02003084 if (key->type.base == LY_TYPE_EMPTY && key->module->version < 2) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003085 LOGVAL(LYE_KEY_TYPE, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003086 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003087 }
3088
3089 /* config attribute is the same as of the list */
Radek Krejciadb57612016-02-16 13:34:34 +01003090 if ((list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003091 LOGVAL(LYE_KEY_CONFIG, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003092 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003093 }
3094
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003095 /* key is not placed from augment */
3096 if (key->parent->nodetype == LYS_AUGMENT) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003097 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, key, key->name);
3098 LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key inserted from augment.");
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003099 return -1;
3100 }
3101
Radek Krejci3f21ada2016-08-01 13:34:31 +02003102 /* key is not when/if-feature -conditional */
3103 j = 0;
3104 if (key->when || (key->iffeature_size && (j = 1))) {
3105 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, key, j ? "if-feature" : "when", "leaf");
3106 LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key definition cannot depend on a \"%s\" condition.",
3107 j ? "if-feature" : "when");
Radek Krejci581ce772015-11-10 17:22:40 +01003108 return -1;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003109 }
3110
Michal Vasko0b85aa82016-03-07 14:37:43 +01003111 return EXIT_SUCCESS;
Michal Vasko184521f2015-09-24 13:14:26 +02003112}
Michal Vasko730dfdf2015-08-11 14:48:05 +02003113
3114/**
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003115 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003116 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003117 * @param[in] parent The parent node of the unique structure.
Michal Vasko0b85aa82016-03-07 14:37:43 +01003118 * @param[in] uniq_str_path One path from the unique string.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003119 *
3120 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
3121 */
3122int
Radek Krejcid09d1a52016-08-11 14:05:45 +02003123resolve_unique(struct lys_node *parent, const char *uniq_str_path, uint8_t *trg_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003124{
Radek Krejci581ce772015-11-10 17:22:40 +01003125 int rc;
Michal Vasko1e62a092015-12-01 12:27:20 +01003126 const struct lys_node *leaf = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003127
Radek Krejcif3c71de2016-04-11 12:45:46 +02003128 rc = resolve_descendant_schema_nodeid(uniq_str_path, parent->child, LYS_LEAF, 1, 1, &leaf);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003129 if (rc || !leaf) {
Michal Vasko0b85aa82016-03-07 14:37:43 +01003130 if (rc) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003131 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003132 if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003133 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, parent, uniq_str_path[rc - 1], &uniq_str_path[rc - 1]);
Radek Krejcif3c71de2016-04-11 12:45:46 +02003134 } else if (rc == -2) {
Michal Vaskoc66c6d82016-04-12 11:37:31 +02003135 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Unique argument references list.");
Radek Krejci581ce772015-11-10 17:22:40 +01003136 }
Michal Vasko0b85aa82016-03-07 14:37:43 +01003137 rc = -1;
Michal Vasko0b85aa82016-03-07 14:37:43 +01003138 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01003139 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3140 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target leaf not found.");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003141 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003142 }
Radek Krejci581ce772015-11-10 17:22:40 +01003143 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003144 }
Michal Vasko9bb061b2016-02-12 11:00:19 +01003145 if (leaf->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003146 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3147 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target is not a leaf.");
Radek Krejcid09d1a52016-08-11 14:05:45 +02003148 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003149 }
3150
Radek Krejcicf509982015-12-15 09:22:44 +01003151 /* check status */
Radek Krejci48464ed2016-03-17 15:44:09 +01003152 if (lyp_check_status(parent->flags, parent->module, parent->name, leaf->flags, leaf->module, leaf->name, leaf)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003153 return -1;
3154 }
3155
Radek Krejcid09d1a52016-08-11 14:05:45 +02003156 /* check that all unique's targets are of the same config type */
3157 if (*trg_type) {
3158 if (((*trg_type == 1) && (leaf->flags & LYS_CONFIG_R)) || ((*trg_type == 2) && (leaf->flags & LYS_CONFIG_W))) {
3159 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3160 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent,
3161 "Leaf \"%s\" referenced in unique statement is config %s, but previous referenced leaf is config %s.",
3162 uniq_str_path, *trg_type == 1 ? "false" : "true", *trg_type == 1 ? "true" : "false");
3163 return -1;
3164 }
3165 } else {
3166 /* first unique */
3167 if (leaf->flags & LYS_CONFIG_W) {
3168 *trg_type = 1;
3169 } else {
3170 *trg_type = 2;
3171 }
3172 }
3173
Radek Krejcica7efb72016-01-18 13:06:01 +01003174 /* set leaf's unique flag */
3175 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
3176
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003177 return EXIT_SUCCESS;
3178
3179error:
3180
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003181 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003182}
3183
Radek Krejci0c0086a2016-03-24 15:20:28 +01003184void
Michal Vasko23b61ec2015-08-19 11:19:50 +02003185unres_data_del(struct unres_data *unres, uint32_t i)
3186{
3187 /* there are items after the one deleted */
3188 if (i+1 < unres->count) {
3189 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02003190 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003191
3192 /* deleting the last item */
3193 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02003194 free(unres->node);
3195 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003196 }
3197
3198 /* if there are no items after and it is not the last one, just move the counter */
3199 --unres->count;
3200}
3201
Michal Vasko0491ab32015-08-19 14:28:29 +02003202/**
3203 * @brief Resolve (find) a data node from a specific module. Does not log.
3204 *
3205 * @param[in] mod Module to search in.
3206 * @param[in] name Name of the data node.
3207 * @param[in] nam_len Length of the name.
3208 * @param[in] start Data node to start the search from.
3209 * @param[in,out] parents Resolved nodes. If there are some parents,
3210 * they are replaced (!!) with the resolvents.
3211 *
Michal Vasko2471e7f2016-04-11 11:00:15 +02003212 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko0491ab32015-08-19 14:28:29 +02003213 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003214static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003215resolve_data(const struct lys_module *mod, const char *name, int nam_len, struct lyd_node *start, struct unres_data *parents)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003216{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003217 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02003218 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003219 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003220
Michal Vasko23b61ec2015-08-19 11:19:50 +02003221 if (!parents->count) {
3222 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003223 parents->node = malloc(sizeof *parents->node);
Michal Vasko253035f2015-12-17 16:58:13 +01003224 if (!parents->node) {
3225 LOGMEM;
Michal Vasko2471e7f2016-04-11 11:00:15 +02003226 return -1;
Michal Vasko253035f2015-12-17 16:58:13 +01003227 }
Michal Vaskocf024702015-10-08 15:01:42 +02003228 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003229 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003230 for (i = 0; i < parents->count;) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02003231 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003232 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003233 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003234 continue;
3235 }
3236 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02003237 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003238 if (node->schema->module == mod && !strncmp(node->schema->name, name, nam_len)
3239 && node->schema->name[nam_len] == '\0') {
3240 /* matching target */
3241 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02003242 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02003243 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003244 flag = 1;
3245 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02003246 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003247 ++parents->count;
Michal Vasko253035f2015-12-17 16:58:13 +01003248 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
3249 if (!parents->node) {
3250 return EXIT_FAILURE;
3251 }
Michal Vaskocf024702015-10-08 15:01:42 +02003252 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003253 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003254 }
3255 }
3256 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003257
3258 if (!flag) {
3259 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003260 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02003261 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003262 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02003263 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003264 }
3265
Michal Vasko0491ab32015-08-19 14:28:29 +02003266 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02003267}
3268
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003269/**
3270 * @brief Resolve (find) a data node. Does not log.
3271 *
Radek Krejci581ce772015-11-10 17:22:40 +01003272 * @param[in] mod_name Module name of the data node.
3273 * @param[in] mod_name_len Length of the module name.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003274 * @param[in] name Name of the data node.
3275 * @param[in] nam_len Length of the name.
3276 * @param[in] start Data node to start the search from.
3277 * @param[in,out] parents Resolved nodes. If there are some parents,
3278 * they are replaced (!!) with the resolvents.
3279 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003280 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003281 */
Radek Krejcic5090c32015-08-12 09:46:19 +02003282static int
Radek Krejci581ce772015-11-10 17:22:40 +01003283resolve_data_node(const char *mod_name, int mod_name_len, const char *name, int name_len, struct lyd_node *start,
Michal Vasko23b61ec2015-08-19 11:19:50 +02003284 struct unres_data *parents)
Radek Krejcic5090c32015-08-12 09:46:19 +02003285{
Michal Vasko1e62a092015-12-01 12:27:20 +01003286 const struct lys_module *mod;
Michal Vasko31fc3672015-10-21 12:08:13 +02003287 char *str;
Radek Krejcic5090c32015-08-12 09:46:19 +02003288
Michal Vasko23b61ec2015-08-19 11:19:50 +02003289 assert(start);
3290
Michal Vasko31fc3672015-10-21 12:08:13 +02003291 if (mod_name) {
3292 /* we have mod_name, find appropriate module */
3293 str = strndup(mod_name, mod_name_len);
Michal Vasko253035f2015-12-17 16:58:13 +01003294 if (!str) {
3295 LOGMEM;
3296 return -1;
3297 }
Michal Vasko31fc3672015-10-21 12:08:13 +02003298 mod = ly_ctx_get_module(start->schema->module->ctx, str, NULL);
3299 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02003300 if (!mod) {
3301 /* invalid prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003302 return -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02003303 }
3304 } else {
3305 /* no prefix, module is the same as of current node */
3306 mod = start->schema->module;
3307 }
3308
3309 return resolve_data(mod, name, name_len, start, parents);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003310}
3311
Michal Vasko730dfdf2015-08-11 14:48:05 +02003312/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003313 * @brief Resolve a path predicate (leafref) in JSON data context. Logs directly
Radek Krejci48464ed2016-03-17 15:44:09 +01003314 * only specific errors, general no-resolvent error is left to the caller.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003315 *
Michal Vaskobb211122015-08-19 14:03:11 +02003316 * @param[in] pred Predicate to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003317 * @param[in] node Node from which the predicate is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02003318 * @param[in,out] node_match Nodes satisfying the restriction
3319 * without the predicate. Nodes not
3320 * satisfying the predicate are removed.
Michal Vasko0491ab32015-08-19 14:28:29 +02003321 * @param[out] parsed Number of characters parsed, negative on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003322 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003323 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003324 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003325static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003326resolve_path_predicate_data(const char *pred, struct lyd_node *node, struct unres_data *node_match,
Radek Krejci010e54b2016-03-15 09:40:34 +01003327 int *parsed)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003328{
Michal Vasko730dfdf2015-08-11 14:48:05 +02003329 /* ... /node[source = destination] ... */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003330 struct unres_data source_match, dest_match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003331 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vasko0491ab32015-08-19 14:28:29 +02003332 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed_loc = 0, pke_parsed = 0;
3333 int has_predicate, dest_parent_times, i, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003334 uint32_t j;
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003335 struct lyd_node_leaf_list *leaf_dst, *leaf_src;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003336
3337 source_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003338 source_match.node = malloc(sizeof *source_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003339 if (!source_match.node) {
3340 LOGMEM;
3341 return -1;
3342 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003343 dest_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003344 dest_match.node = malloc(sizeof *dest_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003345 if (!dest_match.node) {
3346 LOGMEM;
3347 return -1;
3348 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003349
3350 do {
3351 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
3352 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003353 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, pred[-i], &pred[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003354 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003355 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003356 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003357 parsed_loc += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003358 pred += i;
3359
Michal Vasko23b61ec2015-08-19 11:19:50 +02003360 for (j = 0; j < node_match->count;) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003361 /* source */
Michal Vaskocf024702015-10-08 15:01:42 +02003362 source_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02003363
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003364 /* must be leaf (key of a list) */
Radek Krejci581ce772015-11-10 17:22:40 +01003365 if ((rc = resolve_data_node(sour_pref, sour_pref_len, source, sour_len, node_match->node[j],
Michal Vaskocf024702015-10-08 15:01:42 +02003366 &source_match)) || (source_match.count != 1) || (source_match.node[0]->schema->nodetype != LYS_LEAF)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003367 i = 0;
3368 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003369 }
3370
3371 /* destination */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003372 dest_match.node[0] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003373 dest_parent_times = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003374 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3375 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003376 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003377 rc = -1;
3378 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003379 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003380 pke_parsed = i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003381 for (i = 0; i < dest_parent_times; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02003382 dest_match.node[0] = dest_match.node[0]->parent;
3383 if (!dest_match.node[0]) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003384 i = 0;
Michal Vasko0491ab32015-08-19 14:28:29 +02003385 rc = EXIT_FAILURE;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003386 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003387 }
3388 }
3389 while (1) {
Radek Krejci581ce772015-11-10 17:22:40 +01003390 if ((rc = resolve_data_node(dest_pref, dest_pref_len, dest, dest_len, dest_match.node[0],
Michal Vasko0491ab32015-08-19 14:28:29 +02003391 &dest_match)) || (dest_match.count != 1)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003392 i = 0;
3393 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003394 }
3395
3396 if (pke_len == pke_parsed) {
3397 break;
3398 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003399 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003400 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003401 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003402 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003403 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003404 }
3405 pke_parsed += i;
3406 }
3407
3408 /* check match between source and destination nodes */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003409 leaf_dst = (struct lyd_node_leaf_list *)dest_match.node[0];
3410 while (leaf_dst->value_type == LY_TYPE_LEAFREF) {
3411 leaf_dst = (struct lyd_node_leaf_list *)leaf_dst->value.leafref;
3412 }
3413 leaf_src = (struct lyd_node_leaf_list *)source_match.node[0];
3414 while (leaf_src->value_type == LY_TYPE_LEAFREF) {
3415 leaf_src = (struct lyd_node_leaf_list *)leaf_src->value.leafref;
3416 }
3417 if (leaf_src->value_type != leaf_dst->value_type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003418 goto remove_leafref;
3419 }
3420
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003421 if (!ly_strequal(leaf_src->value_str, leaf_dst->value_str, 1)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003422 goto remove_leafref;
3423 }
3424
3425 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003426 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003427 continue;
3428
3429remove_leafref:
3430 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003431 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003432 }
3433 } while (has_predicate);
3434
Michal Vaskocf024702015-10-08 15:01:42 +02003435 free(source_match.node);
3436 free(dest_match.node);
Michal Vasko0491ab32015-08-19 14:28:29 +02003437 if (parsed) {
3438 *parsed = parsed_loc;
3439 }
3440 return EXIT_SUCCESS;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003441
3442error:
3443
3444 if (source_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003445 free(source_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003446 }
3447 if (dest_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003448 free(dest_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003449 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003450 if (parsed) {
3451 *parsed = -parsed_loc+i;
3452 }
3453 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003454}
3455
Michal Vasko730dfdf2015-08-11 14:48:05 +02003456/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003457 * @brief Resolve a path (leafref) in JSON data context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003458 *
Michal Vaskocf024702015-10-08 15:01:42 +02003459 * @param[in] node Leafref data node.
Michal Vasko23b61ec2015-08-19 11:19:50 +02003460 * @param[in] path Path of the leafref.
Radek Krejci48464ed2016-03-17 15:44:09 +01003461 * @param[out] ret Matching nodes. Expects an empty, but allocated structure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003462 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003463 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003464 */
Michal Vasko184521f2015-09-24 13:14:26 +02003465static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003466resolve_path_arg_data(struct lyd_node *node, const char *path, struct unres_data *ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003467{
Radek Krejci71b795b2015-08-10 16:20:39 +02003468 struct lyd_node *data = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003469 const char *prefix, *name;
Michal Vasko0491ab32015-08-19 14:28:29 +02003470 int pref_len, nam_len, has_predicate, parent_times, i, parsed, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003471 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003472
Michal Vaskocf024702015-10-08 15:01:42 +02003473 assert(node && path && ret && !ret->count);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003474
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003475 parent_times = 0;
Michal Vaskod9173342015-08-17 14:35:36 +02003476 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003477
3478 /* searching for nodeset */
3479 do {
3480 if ((i = parse_path_arg(path, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003481 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path[-i], &path[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003482 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003483 goto error;
3484 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003485 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003486 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003487
Michal Vasko23b61ec2015-08-19 11:19:50 +02003488 if (!ret->count) {
Michal Vaskobfd98e62016-09-02 09:50:05 +02003489 if (parent_times > 0) {
3490 data = node;
3491 for (i = 1; i < parent_times; ++i) {
3492 data = data->parent;
Michal Vasko253035f2015-12-17 16:58:13 +01003493 }
Michal Vaskobfd98e62016-09-02 09:50:05 +02003494 } else if (!parent_times) {
3495 data = node->child;
3496 } else {
3497 /* absolute path */
3498 for (data = node; data->parent; data = data->parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003499 }
3500
Michal Vaskobfd98e62016-09-02 09:50:05 +02003501 /* we may still be parsing it and the pointer is not correct yet */
3502 if (data->prev) {
3503 while (data->prev->next) {
3504 data = data->prev;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003505 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003506 }
3507 }
3508
3509 /* node identifier */
Radek Krejci581ce772015-11-10 17:22:40 +01003510 if ((rc = resolve_data_node(prefix, pref_len, name, nam_len, data, ret))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003511 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003512 LOGVAL(LYE_INELEM_LEN, LY_VLOG_LYD, node, nam_len, name);
Michal Vasko184521f2015-09-24 13:14:26 +02003513 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003514 goto error;
3515 }
3516
3517 if (has_predicate) {
3518 /* we have predicate, so the current results must be lists */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003519 for (j = 0; j < ret->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02003520 if (ret->node[j]->schema->nodetype == LYS_LIST &&
3521 ((struct lys_node_list *)ret->node[0]->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003522 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003523 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003524 continue;
3525 }
3526
3527 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003528 unres_data_del(ret, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003529 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003530 if ((rc = resolve_path_predicate_data(path, node, ret, &i))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003531 if (rc == -1) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003532 LOGVAL(LYE_NORESOLV, LY_VLOG_LYD, node, "leafref", path);
Michal Vasko184521f2015-09-24 13:14:26 +02003533 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003534 goto error;
3535 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003536 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003537 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003538
Michal Vasko23b61ec2015-08-19 11:19:50 +02003539 if (!ret->count) {
Michal Vasko0491ab32015-08-19 14:28:29 +02003540 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003541 goto error;
3542 }
3543 }
3544 } while (path[0] != '\0');
3545
Michal Vaskof02e3742015-08-05 16:27:02 +02003546 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003547
3548error:
3549
Michal Vaskocf024702015-10-08 15:01:42 +02003550 free(ret->node);
3551 ret->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003552 ret->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003553
Michal Vasko0491ab32015-08-19 14:28:29 +02003554 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003555}
3556
Michal Vasko730dfdf2015-08-11 14:48:05 +02003557/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003558 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003559 *
Michal Vaskobb211122015-08-19 14:03:11 +02003560 * @param[in] path Path to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003561 * @param[in] context_node Predicate context node (where the predicate is placed).
3562 * @param[in] parent Path context node (where the path begins/is placed).
Michal Vasko730dfdf2015-08-11 14:48:05 +02003563 *
Michal Vasko184521f2015-09-24 13:14:26 +02003564 * @return 0 on forward reference, otherwise the number
3565 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003566 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003567 */
Michal Vasko1f76a282015-08-04 16:16:53 +02003568static int
Radek Krejciadb57612016-02-16 13:34:34 +01003569resolve_path_predicate_schema(const char *path, const struct lys_node *context_node,
Radek Krejci48464ed2016-03-17 15:44:09 +01003570 struct lys_node *parent)
Michal Vasko1f76a282015-08-04 16:16:53 +02003571{
Michal Vasko1e62a092015-12-01 12:27:20 +01003572 const struct lys_node *src_node, *dst_node;
Michal Vasko1f76a282015-08-04 16:16:53 +02003573 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
3574 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed = 0, pke_parsed = 0;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003575 int has_predicate, dest_parent_times = 0, i, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02003576
3577 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02003578 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02003579 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003580 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003581 return -parsed+i;
3582 }
3583 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003584 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02003585
Michal Vasko58090902015-08-13 14:04:15 +02003586 /* source (must be leaf) */
Michal Vasko36cbaa42015-12-14 13:15:48 +01003587 if (!sour_pref) {
Radek Krejciadb57612016-02-16 13:34:34 +01003588 sour_pref = context_node->module->name;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003589 }
Radek Krejciadb57612016-02-16 13:34:34 +01003590 rc = lys_get_sibling(context_node->child, sour_pref, sour_pref_len, source, sour_len,
Michal Vasko59ad4582016-09-16 13:15:41 +02003591 LYS_LEAF | LYS_LEAFLIST | LYS_AUGMENT, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003592 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003593 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02003594 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003595 }
3596
3597 /* destination */
3598 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3599 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003600 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path_key_expr[-i], path_key_expr-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003601 return -parsed;
3602 }
3603 pke_parsed += i;
3604
Radek Krejciadb57612016-02-16 13:34:34 +01003605 for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
Michal Vasko1f76a282015-08-04 16:16:53 +02003606 if (!dst_node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003607 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003608 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003609 }
Radek Krejci3a5501d2016-07-18 22:03:34 +02003610 /* path is supposed to be evaluated in data tree, so we have to skip
3611 * all schema nodes that cannot be instantiated in data tree */
3612 for (dst_node = lys_parent(dst_node);
3613 dst_node && !(dst_node->nodetype & (LYS_CONTAINER | LYS_LIST));
3614 dst_node = lys_parent(dst_node));
Michal Vasko1f76a282015-08-04 16:16:53 +02003615 }
3616 while (1) {
Michal Vasko36cbaa42015-12-14 13:15:48 +01003617 if (!dest_pref) {
3618 dest_pref = dst_node->module->name;
3619 }
3620 rc = lys_get_sibling(dst_node->child, dest_pref, dest_pref_len, dest, dest_len,
Michal Vasko165dc4a2015-10-23 09:44:27 +02003621 LYS_CONTAINER | LYS_LIST | LYS_LEAF | LYS_AUGMENT, &dst_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003622 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003623 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003624 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003625 }
3626
3627 if (pke_len == pke_parsed) {
3628 break;
3629 }
3630
3631 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
3632 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003633 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent,
Radek Krejciadb57612016-02-16 13:34:34 +01003634 (path_key_expr+pke_parsed)[-i], (path_key_expr+pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003635 return -parsed;
3636 }
3637 pke_parsed += i;
3638 }
3639
3640 /* check source - dest match */
Michal Vasko59ad4582016-09-16 13:15:41 +02003641 if (dst_node->nodetype != src_node->nodetype) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003642 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko59ad4582016-09-16 13:15:41 +02003643 LOGVAL(LYE_SPEC, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "Destination node is not a %s, but a %s.",
3644 strnodetype(src_node->nodetype), strnodetype(dst_node->nodetype));
Michal Vasko184521f2015-09-24 13:14:26 +02003645 return -parsed;
3646 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003647 } while (has_predicate);
3648
3649 return parsed;
3650}
3651
Michal Vasko730dfdf2015-08-11 14:48:05 +02003652/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003653 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003654 *
Michal Vaskobb211122015-08-19 14:03:11 +02003655 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003656 * @param[in] parent_node Parent of the leafref.
Radek Krejci2f12f852016-01-08 12:59:57 +01003657 * @param[in] parent_tpdf Flag if the parent node is actually typedef, in that case the path
3658 * has to contain absolute path
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003659 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003660 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003661 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003662 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003663static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003664resolve_path_arg_schema(const char *path, struct lys_node *parent, int parent_tpdf,
Michal Vasko36cbaa42015-12-14 13:15:48 +01003665 const struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02003666{
Michal Vasko1e62a092015-12-01 12:27:20 +01003667 const struct lys_node *node;
Radek Krejci27fe55e2016-09-13 17:13:35 +02003668 const struct lys_module *mod, *mod2;
Michal Vasko1f76a282015-08-04 16:16:53 +02003669 const char *id, *prefix, *name;
3670 int pref_len, nam_len, parent_times, has_predicate;
Michal Vasko184521f2015-09-24 13:14:26 +02003671 int i, first_iter, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02003672
Michal Vasko184521f2015-09-24 13:14:26 +02003673 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003674 parent_times = 0;
3675 id = path;
3676
Radek Krejci27fe55e2016-09-13 17:13:35 +02003677 mod2 = lys_node_module(parent);
Michal Vasko1f76a282015-08-04 16:16:53 +02003678 do {
3679 if ((i = parse_path_arg(id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003680 LOGVAL(LYE_INCHAR, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, id[-i], &id[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003681 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003682 }
3683 id += i;
3684
Michal Vasko184521f2015-09-24 13:14:26 +02003685 if (first_iter) {
Michal Vasko1f76a282015-08-04 16:16:53 +02003686 if (parent_times == -1) {
Radek Krejcic071c542016-01-27 14:57:51 +01003687 /* resolve prefix of the module */
Radek Krejciadb57612016-02-16 13:34:34 +01003688 mod = lys_get_import_module(parent->module, NULL, 0, prefix, pref_len);
Radek Krejci0fa54e92016-09-14 14:01:05 +02003689 mod = lys_get_implemented_module(mod);
Radek Krejcic071c542016-01-27 14:57:51 +01003690 /* get start node */
3691 node = mod ? mod->data : NULL;
Michal Vasko58090902015-08-13 14:04:15 +02003692 if (!node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003693 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3694 "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003695 return EXIT_FAILURE;
Michal Vasko58090902015-08-13 14:04:15 +02003696 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003697 } else if (parent_times > 0) {
Radek Krejci2f12f852016-01-08 12:59:57 +01003698 if (parent_tpdf) {
3699 /* the path is not allowed to contain relative path since we are in top level typedef */
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003700 LOGVAL(LYE_NORESOLV, 0, NULL, "leafref", path);
Radek Krejci2f12f852016-01-08 12:59:57 +01003701 return -1;
3702 }
3703
Michal Vaskodf053d12016-07-21 13:33:31 +02003704 /* node is the parent already, skip one ".." */
3705 for (i = 1, node = parent; i < parent_times; i++) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02003706 /* path is supposed to be evaluated in data tree, so we have to skip
3707 * all schema nodes that cannot be instantiated in data tree */
3708 for (node = lys_parent(node);
3709 node && !(node->nodetype & (LYS_CONTAINER | LYS_LIST));
3710 node = lys_parent(node));
3711
Michal Vasko1f76a282015-08-04 16:16:53 +02003712 if (!node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003713 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3714 "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003715 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003716 }
Michal Vasko58090902015-08-13 14:04:15 +02003717
Michal Vasko1f76a282015-08-04 16:16:53 +02003718 }
Michal Vaskoe01eca52015-08-13 14:42:02 +02003719 } else {
3720 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003721 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003722 }
Michal Vasko36cbaa42015-12-14 13:15:48 +01003723
Michal Vasko184521f2015-09-24 13:14:26 +02003724 first_iter = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003725 } else {
Michal Vasko7dc71d02016-03-15 10:42:28 +01003726 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02003727 if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko2f5aceb2016-03-22 10:24:14 +01003728 LOGVAL(LYE_INCHAR, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, name[0], name);
Michal Vasko7dc71d02016-03-15 10:42:28 +01003729 return -1;
3730 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003731 node = node->child;
3732 }
3733
Michal Vasko4f0dad02016-02-15 14:08:23 +01003734 if (!prefix) {
Radek Krejciadb57612016-02-16 13:34:34 +01003735 prefix = lys_node_module(parent)->name;
Michal Vasko4f0dad02016-02-15 14:08:23 +01003736 }
3737
Michal Vasko36cbaa42015-12-14 13:15:48 +01003738 rc = lys_get_sibling(node, prefix, pref_len, name, nam_len, LYS_ANY & ~(LYS_USES | LYS_GROUPING), &node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003739 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003740 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko7a55bea2016-05-02 14:51:20 +02003741 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003742 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003743
3744 if (has_predicate) {
3745 /* we have predicate, so the current result must be list */
3746 if (node->nodetype != LYS_LIST) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003747 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003748 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003749 }
3750
Radek Krejci48464ed2016-03-17 15:44:09 +01003751 i = resolve_path_predicate_schema(id, node, parent);
Radek Krejci27fe55e2016-09-13 17:13:35 +02003752 if (i <= 0) {
3753 if (i == 0) {
3754 return EXIT_FAILURE;
3755 } else { /* i < 0 */
3756 return -1;
3757 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003758 }
3759 id += i;
3760 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02003761 mod = lys_node_module(node);
3762 if (!mod->implemented && mod != mod2) {
3763 /* set the module implemented */
3764 if (lys_set_implemented(mod)) {
3765 return -1;
3766 }
3767 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003768 } while (id[0]);
3769
Michal Vaskoca917682016-07-25 11:00:37 +02003770 /* the target must be leaf or leaf-list (in YANG 1.1 only) */
3771 if ((node->nodetype != LYS_LEAF) && ((lys_node_module(parent)->version != 2) || (node->nodetype != LYS_LEAFLIST))) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003772 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Radek Krejcid47daf62016-08-22 16:23:38 +02003773 LOGVAL(LYE_SPEC, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3774 "Leafref target \"%s\" is not a leaf%s.", path,
3775 lys_node_module(parent)->version != 2 ? "" : " nor a leaf-list");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003776 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02003777 }
3778
Radek Krejcicf509982015-12-15 09:22:44 +01003779 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01003780 if (lyp_check_status(parent->flags, parent->module, parent->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01003781 node->flags, node->module, node->name, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003782 return -1;
3783 }
3784
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003785 if (ret) {
3786 *ret = node;
3787 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02003788
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003789 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02003790}
3791
Michal Vasko730dfdf2015-08-11 14:48:05 +02003792/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003793 * @brief Resolve instance-identifier predicate in JSON data format.
3794 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003795 *
Michal Vaskobb211122015-08-19 14:03:11 +02003796 * @param[in] pred Predicate to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003797 * @param[in,out] node_match Nodes matching the restriction without
3798 * the predicate. Nodes not satisfying
3799 * the predicate are removed.
3800 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003801 * @return Number of characters successfully parsed,
3802 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003803 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003804static int
Michal Vaskof39142b2015-10-21 11:40:05 +02003805resolve_predicate(const char *pred, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003806{
Michal Vasko730dfdf2015-08-11 14:48:05 +02003807 /* ... /node[target = value] ... */
Michal Vaskob2f40be2016-09-08 16:03:48 +02003808 struct lyd_node *target;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003809 const char *model, *name, *value;
Michal Vaskob2f40be2016-09-08 16:03:48 +02003810 int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed, pred_iter, k;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003811 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003812
Michal Vasko1f2cc332015-08-19 11:18:32 +02003813 assert(pred && node_match->count);
3814
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003815 idx = -1;
3816 parsed = 0;
3817
Michal Vaskob2f40be2016-09-08 16:03:48 +02003818 pred_iter = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003819 do {
Michal Vaskof39142b2015-10-21 11:40:05 +02003820 if ((i = parse_predicate(pred, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003821 return -parsed+i;
3822 }
3823 parsed += i;
3824 pred += i;
3825
3826 if (isdigit(name[0])) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02003827 /* pos */
3828 assert(!value);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003829 idx = atoi(name);
Michal Vaskob2f40be2016-09-08 16:03:48 +02003830 } else if (name[0] != '.') {
3831 /* list keys */
3832 if (pred_iter < 0) {
3833 pred_iter = 1;
3834 } else {
3835 ++pred_iter;
3836 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003837 }
3838
Michal Vaskof2f28a12016-09-09 12:43:06 +02003839 for (cur_idx = 1, j = 0; j < node_match->count; ++cur_idx) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003840 /* target */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003841 if (name[0] == '.') {
Michal Vaskob2f40be2016-09-08 16:03:48 +02003842 /* leaf-list value */
Michal Vaskocf024702015-10-08 15:01:42 +02003843 if (node_match->node[j]->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003844 goto remove_instid;
3845 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02003846
3847 target = node_match->node[j];
3848 /* check the value */
3849 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
3850 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
3851 goto remove_instid;
3852 }
3853
3854 } else if (!value) {
3855 /* keyless list position */
3856 if ((node_match->node[j]->schema->nodetype != LYS_LIST)
3857 || ((struct lys_node_list *)node_match->node[j]->schema)->keys) {
3858 goto remove_instid;
3859 }
3860
3861 if (idx != cur_idx) {
3862 goto remove_instid;
3863 }
3864
3865 } else {
3866 /* list key value */
Michal Vaskocf024702015-10-08 15:01:42 +02003867 if (node_match->node[j]->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003868 goto remove_instid;
3869 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02003870
3871 /* key module must match the list module */
3872 if (strncmp(node_match->node[j]->schema->module->name, model, mod_len)
3873 || node_match->node[j]->schema->module->name[mod_len]) {
3874 goto remove_instid;
3875 }
3876 /* find the key leaf */
Michal Vasko045182c2016-09-09 12:44:07 +02003877 for (k = 1, target = node_match->node[j]->child; target && (k < pred_iter); k++, target = target->next);
Michal Vaskob2f40be2016-09-08 16:03:48 +02003878 if (!target) {
3879 goto remove_instid;
3880 }
3881 if ((struct lys_node_leaf *)target->schema !=
3882 ((struct lys_node_list *)node_match->node[j]->schema)->keys[pred_iter - 1]) {
3883 goto remove_instid;
3884 }
3885
3886 /* check the value */
3887 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
3888 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
3889 goto remove_instid;
3890 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003891 }
3892
Michal Vaskob2f40be2016-09-08 16:03:48 +02003893 /* instid is ok, continue check with the next one */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003894 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003895 continue;
3896
3897remove_instid:
Michal Vaskob2f40be2016-09-08 16:03:48 +02003898 /* does not fulfill conditions, remove instid record */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003899 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003900 }
3901 } while (has_predicate);
3902
Michal Vaskob2f40be2016-09-08 16:03:48 +02003903 /* check that all list keys were specified */
3904 if ((pred_iter > 0) && node_match->count) {
Michal Vasko045182c2016-09-09 12:44:07 +02003905 j = 0;
3906 while (j < node_match->count) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02003907 assert(node_match->node[j]->schema->nodetype == LYS_LIST);
3908 if (pred_iter < ((struct lys_node_list *)node_match->node[j]->schema)->keys_size) {
3909 /* not enough predicates, just remove the list instance */
3910 unres_data_del(node_match, j);
Michal Vasko045182c2016-09-09 12:44:07 +02003911 } else {
3912 ++j;
Michal Vaskob2f40be2016-09-08 16:03:48 +02003913 }
3914 }
3915
3916 if (!node_match->count) {
3917 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier is missing some list keys.");
3918 }
3919 }
3920
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003921 return parsed;
3922}
3923
Michal Vasko730dfdf2015-08-11 14:48:05 +02003924/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003925 * @brief Resolve instance-identifier in JSON data format. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003926 *
Radek Krejciadb57612016-02-16 13:34:34 +01003927 * @param[in] data Data node where the path is used
Michal Vasko730dfdf2015-08-11 14:48:05 +02003928 * @param[in] path Instance-identifier node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003929 *
Radek Krejcic5090c32015-08-12 09:46:19 +02003930 * @return Matching node or NULL if no such a node exists. If error occurs, NULL is returned and ly_errno is set.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003931 */
Michal Vasko184521f2015-09-24 13:14:26 +02003932static struct lyd_node *
Radek Krejci48464ed2016-03-17 15:44:09 +01003933resolve_instid(struct lyd_node *data, const char *path)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003934{
Radek Krejcic5090c32015-08-12 09:46:19 +02003935 int i = 0, j;
3936 struct lyd_node *result = NULL;
Michal Vaskob2f40be2016-09-08 16:03:48 +02003937 const struct lys_module *mod;
Radek Krejcic5090c32015-08-12 09:46:19 +02003938 struct ly_ctx *ctx = data->schema->module->ctx;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003939 const char *model, *name;
Radek Krejcic5090c32015-08-12 09:46:19 +02003940 char *str;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003941 int mod_len, name_len, has_predicate;
3942 struct unres_data node_match;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003943
3944 memset(&node_match, 0, sizeof node_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003945
Radek Krejcic5090c32015-08-12 09:46:19 +02003946 /* we need root to resolve absolute path */
3947 for (; data->parent; data = data->parent);
Michal Vaskodb9323c2015-10-16 10:32:44 +02003948 /* we're still parsing it and the pointer is not correct yet */
Michal Vasko0491ab32015-08-19 14:28:29 +02003949 if (data->prev) {
3950 for (; data->prev->next; data = data->prev);
3951 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003952
Radek Krejcic5090c32015-08-12 09:46:19 +02003953 /* search for the instance node */
3954 while (path[i]) {
Michal Vaskof39142b2015-10-21 11:40:05 +02003955 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
Radek Krejcic5090c32015-08-12 09:46:19 +02003956 if (j <= 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003957 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003958 goto error;
3959 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003960 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02003961
Michal Vaskob2f40be2016-09-08 16:03:48 +02003962 str = strndup(model, mod_len);
3963 if (!str) {
3964 LOGMEM;
3965 goto error;
Radek Krejcic5090c32015-08-12 09:46:19 +02003966 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02003967 mod = ly_ctx_get_module(ctx, str, NULL);
3968 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02003969
Michal Vasko1f2cc332015-08-19 11:18:32 +02003970 if (resolve_data(mod, name, name_len, data, &node_match)) {
Radek Krejcic5090c32015-08-12 09:46:19 +02003971 /* no instance exists */
3972 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003973 }
3974
3975 if (has_predicate) {
3976 /* we have predicate, so the current results must be list or leaf-list */
Michal Vaskof39142b2015-10-21 11:40:05 +02003977 j = resolve_predicate(&path[i], &node_match);
Radek Krejcic5090c32015-08-12 09:46:19 +02003978 if (j < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003979 LOGVAL(LYE_INPRED, LY_VLOG_LYD, data, &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003980 goto error;
3981 }
Michal Vasko1f2cc332015-08-19 11:18:32 +02003982 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02003983
Michal Vasko1f2cc332015-08-19 11:18:32 +02003984 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02003985 /* no instance exists */
3986 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003987 }
3988 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003989 }
3990
Michal Vasko1f2cc332015-08-19 11:18:32 +02003991 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02003992 /* no instance exists */
3993 return NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003994 } else if (node_match.count > 1) {
Radek Krejcic5090c32015-08-12 09:46:19 +02003995 /* instance identifier must resolve to a single node */
Radek Krejci48464ed2016-03-17 15:44:09 +01003996 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
Michal Vaskod6adbaa2016-04-11 11:01:09 +02003997 goto error;
Radek Krejcic5090c32015-08-12 09:46:19 +02003998 } else {
3999 /* we have required result, remember it and cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02004000 result = node_match.node[0];
4001 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02004002 return result;
4003 }
4004
4005error:
Radek Krejcic5090c32015-08-12 09:46:19 +02004006 /* cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02004007 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02004008 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004009}
4010
Michal Vasko730dfdf2015-08-11 14:48:05 +02004011/**
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004012 * @brief Passes config flag down to children, skips nodes without config flags.
4013 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004014 *
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004015 * @param[in] node Siblings and their children to have flags changed.
Michal Vaskoe022a562016-09-27 14:24:15 +02004016 * @param[in] clear Flag to clear all config flags if parent is LYS_NOTIF, LYS_INPUT, LYS_OUTPUT, LYS_RPC.
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004017 * @param[in] flags Flags to assign to all the nodes.
Michal Vaskoa86508c2016-08-26 14:30:19 +02004018 *
4019 * @return 0 on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004020 */
Michal Vaskoa86508c2016-08-26 14:30:19 +02004021static int
Michal Vaskoe022a562016-09-27 14:24:15 +02004022inherit_config_flag(struct lys_node *node, int flags, int clear, int check_list)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004023{
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004024 assert(!(flags ^ (flags & LYS_CONFIG_MASK)));
Radek Krejci1d82ef62015-08-07 14:44:40 +02004025 LY_TREE_FOR(node, node) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004026 if (clear) {
4027 node->flags &= ~LYS_CONFIG_MASK;
4028 assert(!(node->flags & LYS_CONFIG_SET));
4029 } else {
4030 if (node->flags & LYS_CONFIG_SET) {
4031 /* skip nodes with an explicit config value */
4032 if ((flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
4033 LOGVAL(LYE_INARG, LY_VLOG_LYS, node, "true", "config");
4034 LOGVAL(LYE_SPEC, LY_VLOG_LYS, node, "State nodes cannot have configuration nodes as children.");
4035 return -1;
4036 }
4037 continue;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004038 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004039
4040 if (!(node->nodetype & (LYS_USES | LYS_GROUPING))) {
4041 node->flags = (node->flags & ~LYS_CONFIG_MASK) | flags;
4042 /* check that configuration lists have keys */
4043 if (check_list && (node->nodetype == LYS_LIST)
4044 && (node->flags & LYS_CONFIG_W) && !((struct lys_node_list *)node)->keys_size) {
4045 LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_LYS, node, "key", "list");
4046 return -1;
4047 }
4048 }
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004049 }
Radek Krejcibf2abff2016-08-23 15:51:52 +02004050 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004051 if (inherit_config_flag(node->child, flags, clear, check_list)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004052 return -1;
4053 }
Radek Krejci3a5501d2016-07-18 22:03:34 +02004054 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004055 }
Michal Vaskoa86508c2016-08-26 14:30:19 +02004056
4057 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004058}
4059
Michal Vasko730dfdf2015-08-11 14:48:05 +02004060/**
Michal Vasko7178e692016-02-12 15:58:05 +01004061 * @brief Resolve augment target. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004062 *
Michal Vaskobb211122015-08-19 14:03:11 +02004063 * @param[in] aug Augment to use.
Michal Vasko3edeaf72016-02-11 13:17:43 +01004064 * @param[in] siblings Nodes where to start the search in. If set, uses augment, if not, standalone augment.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004065 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004066 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004067 */
Michal Vasko7178e692016-02-12 15:58:05 +01004068static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004069resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004070{
Michal Vaskoe022a562016-09-27 14:24:15 +02004071 int rc, clear_config;
Michal Vasko1d87a922015-08-21 12:57:16 +02004072 struct lys_node *sub;
Pavol Vican47319932016-08-29 09:14:47 +02004073 const struct lys_node *aug_target, *parent;
Radek Krejci27fe55e2016-09-13 17:13:35 +02004074 struct lys_module *mod;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004075
Michal Vasko15b36692016-08-26 15:29:54 +02004076 assert(aug && !aug->target);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004077
Michal Vasko15b36692016-08-26 15:29:54 +02004078 /* resolve target node */
4079 rc = resolve_augment_schema_nodeid(aug->target_name, siblings, (siblings ? NULL : aug->module), &aug_target);
4080 if (rc == -1) {
4081 return -1;
4082 }
4083 if (rc > 0) {
4084 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, aug, aug->target_name[rc - 1], &aug->target_name[rc - 1]);
4085 return -1;
4086 }
4087 if (!aug_target) {
4088 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
4089 return EXIT_FAILURE;
4090 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004091
Radek Krejci27fe55e2016-09-13 17:13:35 +02004092 /* check that we want to connect augment into its target */
4093 mod = lys_main_module(aug->module);
4094 if (!mod->implemented) {
4095 /* it must be augment only to the same module,
4096 * otherwise we do not apply augment in not-implemented
4097 * module. If the module is set to be implemented in future,
4098 * the augment is being resolved and checked again */
4099 for (sub = aug->target; sub; sub = lys_parent(sub)) {
4100 if (lys_node_module(sub) != mod) {
4101 /* this is not an implemented module and the augment
4102 * target some other module, so avoid its connecting
4103 * to the target */
4104 return EXIT_SUCCESS;
4105 }
4106 }
4107 }
4108
Michal Vasko15b36692016-08-26 15:29:54 +02004109 if (!aug->child) {
4110 /* nothing to do */
4111 LOGWRN("Augment \"%s\" without children.", aug->target_name);
Radek Krejci27fe55e2016-09-13 17:13:35 +02004112 goto success;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004113 }
4114
Michal Vaskod58d5962016-03-02 14:29:41 +01004115 /* check for mandatory nodes - if the target node is in another module
4116 * the added nodes cannot be mandatory
4117 */
Michal Vasko15b36692016-08-26 15:29:54 +02004118 if (!aug->parent && (lys_node_module((struct lys_node *)aug) != lys_node_module(aug_target))
Radek Krejcie00d2312016-08-12 15:27:49 +02004119 && (rc = lyp_check_mandatory_augment(aug))) {
4120 return rc;
Michal Vaskod58d5962016-03-02 14:29:41 +01004121 }
4122
Michal Vasko07e89ef2016-03-03 13:28:57 +01004123 /* check augment target type and then augment nodes type */
Michal Vasko15b36692016-08-26 15:29:54 +02004124 if (aug_target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF)) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004125 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004126 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES | LYS_CHOICE))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004127 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4128 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko15b36692016-08-26 15:29:54 +02004129 strnodetype(aug_target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004130 return -1;
4131 }
4132 }
Michal Vasko15b36692016-08-26 15:29:54 +02004133 } else if (aug_target->nodetype == LYS_CHOICE) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004134 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004135 if (!(sub->nodetype & (LYS_CASE | LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004136 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4137 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko15b36692016-08-26 15:29:54 +02004138 strnodetype(aug_target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004139 return -1;
4140 }
4141 }
4142 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01004143 LOGVAL(LYE_INARG, LY_VLOG_LYS, aug, aug->target_name, "target-node");
Michal Vasko15b36692016-08-26 15:29:54 +02004144 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Invalid augment target node type \"%s\".", strnodetype(aug_target->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004145 return -1;
4146 }
4147
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004148 /* inherit config information from actual parent */
Michal Vaskoe022a562016-09-27 14:24:15 +02004149 for(parent = aug_target; parent && !(parent->nodetype & (LYS_NOTIF | LYS_INPUT | LYS_OUTPUT | LYS_RPC)); parent = lys_parent(parent));
4150 clear_config = (parent) ? 1 : 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004151 LY_TREE_FOR(aug->child, sub) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004152 if (inherit_config_flag(sub, aug_target->flags & LYS_CONFIG_MASK, clear_config, 1)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004153 return -1;
4154 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004155 }
4156
Radek Krejcic071c542016-01-27 14:57:51 +01004157 /* check identifier uniqueness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02004158 LY_TREE_FOR(aug->child, sub) {
Michal Vasko15b36692016-08-26 15:29:54 +02004159 if (lys_check_id(sub, (struct lys_node *)aug_target, NULL)) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02004160 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02004161 }
4162 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004163
Michal Vasko15b36692016-08-26 15:29:54 +02004164 /* finally reconnect augmenting data into the target - add them to the target child list,
4165 * by setting aug->target we know the augment is fully resolved now */
4166 aug->target = (struct lys_node *)aug_target;
4167 if (aug->target->child) {
4168 sub = aug->target->child->prev; /* remember current target's last node */
4169 sub->next = aug->child; /* connect augmenting data after target's last node */
4170 aug->target->child->prev = aug->child->prev; /* new target's last node is last augmenting node */
4171 aug->child->prev = sub; /* finish connecting of both child lists */
4172 } else {
4173 aug->target->child = aug->child;
4174 }
4175
Radek Krejci27fe55e2016-09-13 17:13:35 +02004176success:
4177 if (mod->implemented) {
4178 /* make target modules also implemented */
4179 for (sub = aug->target; sub; sub = lys_parent(sub)) {
4180 if (lys_set_implemented(sub->module)) {
4181 return -1;
4182 }
4183 }
4184 }
4185
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004186 return EXIT_SUCCESS;
4187}
4188
Michal Vasko730dfdf2015-08-11 14:48:05 +02004189/**
Pavol Vican855ca622016-09-05 13:07:54 +02004190 * @brief Resolve (find) choice default case. Does not log.
4191 *
4192 * @param[in] choic Choice to use.
4193 * @param[in] dflt Name of the default case.
4194 *
4195 * @return Pointer to the default node or NULL.
4196 */
4197static struct lys_node *
4198resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
4199{
4200 struct lys_node *child, *ret;
4201
4202 LY_TREE_FOR(choic->child, child) {
4203 if (child->nodetype == LYS_USES) {
4204 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
4205 if (ret) {
4206 return ret;
4207 }
4208 }
4209
4210 if (ly_strequal(child->name, dflt, 1) && (child->nodetype & (LYS_ANYDATA | LYS_CASE
Radek Krejci2f792db2016-09-12 10:52:33 +02004211 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE))) {
Pavol Vican855ca622016-09-05 13:07:54 +02004212 return child;
4213 }
4214 }
4215
4216 return NULL;
4217}
4218
4219/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02004220 * @brief Resolve uses, apply augments, refines. Logs directly.
4221 *
Michal Vaskobb211122015-08-19 14:03:11 +02004222 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004223 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004224 *
Michal Vaskodef0db12015-10-07 13:22:48 +02004225 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004226 */
Michal Vasko184521f2015-09-24 13:14:26 +02004227static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004228resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004229{
4230 struct ly_ctx *ctx;
Pavol Vican855ca622016-09-05 13:07:54 +02004231 struct lys_node *node = NULL, *next, *iter, **refine_nodes = NULL;
Pavol Vican55abd332016-07-12 15:54:49 +02004232 struct lys_node *node_aux, *parent, *tmp;
Radek Krejci200bf712016-08-16 17:11:04 +02004233 struct lys_node_leaflist *llist;
4234 struct lys_node_leaf *leaf;
Radek Krejci76512572015-08-04 09:47:08 +02004235 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004236 struct lys_restr *must, **old_must;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004237 struct lys_iffeature *iff, **old_iff;
Michal Vaskoe022a562016-09-27 14:24:15 +02004238 int i, j, k, rc, parent_config, clear_config, check_list;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004239 uint8_t size, *old_size;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004240 unsigned int usize, usize1, usize2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004241
Michal Vasko71e1aa82015-08-12 12:17:51 +02004242 assert(uses->grp);
Michal Vaskoe7708512016-03-11 10:26:55 +01004243 /* HACK just check that the grouping is resolved */
Michal Vaskodef0db12015-10-07 13:22:48 +02004244 assert(!uses->grp->nacm);
Michal Vasko71e1aa82015-08-12 12:17:51 +02004245
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004246 if (!uses->grp->child) {
4247 /* grouping without children, warning was already displayed */
4248 return EXIT_SUCCESS;
4249 }
4250
4251 /* get proper parent (config) flags */
4252 for (node_aux = lys_parent((struct lys_node *)uses); node_aux && (node_aux->nodetype == LYS_USES); node_aux = lys_parent(node_aux));
4253 if (node_aux) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004254 parent_config = node_aux->flags & LYS_CONFIG_MASK;
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004255 } else {
4256 /* default */
Michal Vaskoa86508c2016-08-26 14:30:19 +02004257 parent_config = LYS_CONFIG_W;
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004258 }
4259
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004260 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01004261 LY_TREE_FOR(uses->grp->child, node_aux) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004262 node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, uses->nacm, unres, 0);
Michal Vasko1e62a092015-12-01 12:27:20 +01004263 if (!node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004264 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, uses->grp->name, "uses");
4265 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Copying data from grouping failed.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004266 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004267 }
Pavol Vican55abd332016-07-12 15:54:49 +02004268 /* test the name of siblings */
4269 LY_TREE_FOR((uses->parent) ? uses->parent->child : lys_main_module(uses->module)->data, tmp) {
Pavol Vican2510ddc2016-07-18 16:23:44 +02004270 if (!(tmp->nodetype & (LYS_USES | LYS_GROUPING | LYS_CASE)) && ly_strequal(tmp->name, node_aux->name, 1)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004271 goto fail;
Pavol Vican55abd332016-07-12 15:54:49 +02004272 }
4273 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004274 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004275
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004276 ctx = uses->module->ctx;
Michal Vaskoe022a562016-09-27 14:24:15 +02004277 for (parent = node; parent && !(parent->nodetype & (LYS_NOTIF | LYS_INPUT | LYS_OUTPUT | LYS_RPC | LYS_GROUPING));
4278 parent = lys_parent(parent));
4279 if (parent) {
4280 if (parent->nodetype == LYS_GROUPING) {
4281 /* we are still in some other unresolved grouping, unable to check lists */
4282 check_list = 0;
4283 clear_config = 0;
4284 } else {
4285 check_list = 0;
4286 clear_config = 1;
4287 }
4288 } else {
4289 check_list = 1;
4290 clear_config = 0;
4291 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004292
Michal Vaskoa86508c2016-08-26 14:30:19 +02004293 if (parent_config) {
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004294 assert(uses->child);
Michal Vaskoe022a562016-09-27 14:24:15 +02004295 if (inherit_config_flag(uses->child, parent_config, clear_config, check_list)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004296 goto fail;
4297 }
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004298 }
4299
Michal Vaskodef0db12015-10-07 13:22:48 +02004300 /* we managed to copy the grouping, the rest must be possible to resolve */
4301
Pavol Vican855ca622016-09-05 13:07:54 +02004302 if (uses->refine_size) {
4303 refine_nodes = malloc(uses->refine_size * sizeof *refine_nodes);
4304 if (!refine_nodes) {
4305 LOGMEM;
4306 goto fail;
4307 }
4308 }
4309
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004310 /* apply refines */
4311 for (i = 0; i < uses->refine_size; i++) {
4312 rfn = &uses->refine[i];
Michal Vasko3edeaf72016-02-11 13:17:43 +01004313 rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child, LYS_NO_RPC_NOTIF_NODE,
Radek Krejcif3c71de2016-04-11 12:45:46 +02004314 1, 0, (const struct lys_node **)&node);
Michal Vasko9bb061b2016-02-12 11:00:19 +01004315 if (rc || !node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004316 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004317 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004318 }
4319
Radek Krejci1d82ef62015-08-07 14:44:40 +02004320 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004321 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
4322 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Refine substatements not applicable to the target-node.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004323 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004324 }
Pavol Vican855ca622016-09-05 13:07:54 +02004325 refine_nodes[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004326
4327 /* description on any nodetype */
4328 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004329 lydict_remove(ctx, node->dsc);
4330 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004331 }
4332
4333 /* reference on any nodetype */
4334 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004335 lydict_remove(ctx, node->ref);
4336 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004337 }
4338
4339 /* config on any nodetype */
Michal Vaskoe022a562016-09-27 14:24:15 +02004340 if ((rfn->flags & LYS_CONFIG_MASK) && !clear_config) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004341 node->flags &= ~LYS_CONFIG_MASK;
4342 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004343 }
4344
4345 /* default value ... */
Radek Krejci200bf712016-08-16 17:11:04 +02004346 if (rfn->dflt_size) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004347 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004348 /* leaf */
Radek Krejci200bf712016-08-16 17:11:04 +02004349 leaf = (struct lys_node_leaf *)node;
4350
4351 lydict_remove(ctx, leaf->dflt);
4352 leaf->dflt = lydict_insert(ctx, rfn->dflt[0], 0);
4353
4354 /* check the default value */
4355 if (unres_schema_add_str(leaf->module, unres, &leaf->type, UNRES_TYPE_DFLT, leaf->dflt) == -1) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004356 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004357 }
Radek Krejci200bf712016-08-16 17:11:04 +02004358 } else if (node->nodetype == LYS_LEAFLIST) {
4359 /* leaf-list */
4360 llist = (struct lys_node_leaflist *)node;
4361
4362 /* remove complete set of defaults in target */
4363 for (i = 0; i < llist->dflt_size; i++) {
4364 lydict_remove(ctx, llist->dflt[i]);
4365 }
4366 free(llist->dflt);
4367
4368 /* copy the default set from refine */
4369 llist->dflt_size = rfn->dflt_size;
4370 llist->dflt = malloc(llist->dflt_size * sizeof *llist->dflt);
4371 for (i = 0; i < llist->dflt_size; i++) {
4372 llist->dflt[i] = lydict_insert(ctx, rfn->dflt[i], 0);
4373 }
4374
4375 /* check default value */
4376 for (i = 0; i < llist->dflt_size; i++) {
4377 if (unres_schema_add_str(llist->module, unres, &llist->type, UNRES_TYPE_DFLT, llist->dflt[i]) == -1) {
Pavol Vican855ca622016-09-05 13:07:54 +02004378 goto fail;
Radek Krejci200bf712016-08-16 17:11:04 +02004379 }
4380 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004381 }
4382 }
4383
4384 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02004385 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004386 if (node->nodetype & (LYS_LEAF | LYS_ANYDATA | LYS_CHOICE)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004387 /* remove current value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004388 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004389
4390 /* set new value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004391 node->flags |= (rfn->flags & LYS_MAND_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004392 }
Pavol Vican855ca622016-09-05 13:07:54 +02004393 if (rfn->flags & LYS_MAND_TRUE) {
4394 /* check if node has default value */
4395 if ((node->nodetype & LYS_LEAF) && ((struct lys_node_leaf *)node)->dflt) {
4396 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"mandatory\" statement is forbidden on leaf with \"default\".");
4397 goto fail;
4398 }
4399 if ((node->nodetype & LYS_CHOICE) && ((struct lys_node_choice *)node)->dflt) {
4400 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"mandatory\" statement is forbidden on choices with \"default\".");
4401 goto fail;
4402 }
4403 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004404 }
4405
4406 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004407 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
4408 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
4409 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004410 }
4411
4412 /* min/max-elements on list or leaf-list */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004413 if (node->nodetype == LYS_LIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004414 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004415 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004416 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004417 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004418 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004419 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02004420 } else if (node->nodetype == LYS_LEAFLIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004421 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004422 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004423 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004424 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004425 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004426 }
4427 }
4428
4429 /* must in leaf, leaf-list, list, container or anyxml */
4430 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004431 switch (node->nodetype) {
4432 case LYS_LEAF:
4433 old_size = &((struct lys_node_leaf *)node)->must_size;
4434 old_must = &((struct lys_node_leaf *)node)->must;
4435 break;
4436 case LYS_LEAFLIST:
4437 old_size = &((struct lys_node_leaflist *)node)->must_size;
4438 old_must = &((struct lys_node_leaflist *)node)->must;
4439 break;
4440 case LYS_LIST:
4441 old_size = &((struct lys_node_list *)node)->must_size;
4442 old_must = &((struct lys_node_list *)node)->must;
4443 break;
4444 case LYS_CONTAINER:
4445 old_size = &((struct lys_node_container *)node)->must_size;
4446 old_must = &((struct lys_node_container *)node)->must;
4447 break;
4448 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02004449 case LYS_ANYDATA:
4450 old_size = &((struct lys_node_anydata *)node)->must_size;
4451 old_must = &((struct lys_node_anydata *)node)->must;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004452 break;
4453 default:
4454 LOGINT;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004455 goto fail;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004456 }
4457
4458 size = *old_size + rfn->must_size;
4459 must = realloc(*old_must, size * sizeof *rfn->must);
4460 if (!must) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004461 LOGMEM;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004462 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004463 }
Pavol Vican855ca622016-09-05 13:07:54 +02004464 for (k = 0, j = *old_size; k < rfn->must_size; k++, j++) {
4465 must[j].expr = lydict_insert(ctx, rfn->must[k].expr, 0);
4466 must[j].dsc = lydict_insert(ctx, rfn->must[k].dsc, 0);
4467 must[j].ref = lydict_insert(ctx, rfn->must[k].ref, 0);
4468 must[j].eapptag = lydict_insert(ctx, rfn->must[k].eapptag, 0);
4469 must[j].emsg = lydict_insert(ctx, rfn->must[k].emsg, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004470 }
4471
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004472 *old_must = must;
4473 *old_size = size;
Michal Vasko508a50d2016-09-07 14:50:33 +02004474
4475 /* check XPath dependencies again */
4476 if (unres_schema_add_node(node->module, unres, node, UNRES_XPATH, NULL) == -1) {
4477 goto fail;
4478 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004479 }
Radek Krejci363bd4a2016-07-29 14:30:20 +02004480
4481 /* if-feature in leaf, leaf-list, list, container or anyxml */
4482 if (rfn->iffeature_size) {
4483 old_size = &node->iffeature_size;
4484 old_iff = &node->iffeature;
4485
4486 size = *old_size + rfn->iffeature_size;
4487 iff = realloc(*old_iff, size * sizeof *rfn->iffeature);
4488 if (!iff) {
4489 LOGMEM;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004490 goto fail;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004491 }
Pavol Vican855ca622016-09-05 13:07:54 +02004492 for (k = 0, j = *old_size; k < rfn->iffeature_size; k++, j++) {
4493 resolve_iffeature_getsizes(&rfn->iffeature[k], &usize1, &usize2);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004494 if (usize1) {
4495 /* there is something to duplicate */
4496 /* duplicate compiled expression */
4497 usize = (usize1 / 4) + (usize1 % 4) ? 1 : 0;
4498 iff[j].expr = malloc(usize * sizeof *iff[j].expr);
Pavol Vican855ca622016-09-05 13:07:54 +02004499 memcpy(iff[j].expr, rfn->iffeature[k].expr, usize * sizeof *iff[j].expr);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004500
4501 /* duplicate list of feature pointers */
Pavol Vican855ca622016-09-05 13:07:54 +02004502 iff[j].features = malloc(usize2 * sizeof *iff[k].features);
4503 memcpy(iff[j].features, rfn->iffeature[k].features, usize2 * sizeof *iff[j].features);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004504 }
4505 }
4506
4507 *old_iff = iff;
4508 *old_size = size;
4509 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004510 }
4511
4512 /* apply augments */
4513 for (i = 0; i < uses->augment_size; i++) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004514 rc = resolve_augment(&uses->augment[i], uses->child);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004515 if (rc) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004516 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004517 }
4518 }
4519
Pavol Vican855ca622016-09-05 13:07:54 +02004520 /* check refines */
4521 for (i = 0; i < uses->refine_size; i++) {
4522 node = refine_nodes[i];
4523 rfn = &uses->refine[i];
4524
4525 /* config on any nodetype */
Michal Vaskoe022a562016-09-27 14:24:15 +02004526 if ((rfn->flags & LYS_CONFIG_MASK) && !clear_config) {
Pavol Vican855ca622016-09-05 13:07:54 +02004527 for (parent = lys_parent(node); parent && parent->nodetype == LYS_USES; parent = lys_parent(parent));
4528 if (parent && parent->nodetype != LYS_GROUPING &&
4529 ((parent->flags & LYS_CONFIG_MASK) != (rfn->flags & LYS_CONFIG_MASK)) &&
4530 (rfn->flags & LYS_CONFIG_W)) {
4531 /* setting config true under config false is prohibited */
4532 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
4533 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4534 "changing config from 'false' to 'true' is prohibited while "
4535 "the target's parent is still config 'false'.");
4536 goto fail;
4537 }
4538
4539 /* inherit config change to the target children */
4540 LY_TREE_DFS_BEGIN(node->child, next, iter) {
4541 if (rfn->flags & LYS_CONFIG_W) {
4542 if (iter->flags & LYS_CONFIG_SET) {
4543 /* config is set explicitely, go to next sibling */
4544 next = NULL;
4545 goto nextsibling;
4546 }
4547 } else { /* LYS_CONFIG_R */
4548 if ((iter->flags & LYS_CONFIG_SET) && (iter->flags & LYS_CONFIG_W)) {
4549 /* error - we would have config data under status data */
4550 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
4551 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4552 "changing config from 'true' to 'false' is prohibited while the target "
4553 "has still a children with explicit config 'true'.");
4554 goto fail;
4555 }
4556 }
4557 /* change config */
4558 iter->flags &= ~LYS_CONFIG_MASK;
4559 iter->flags |= (rfn->flags & LYS_CONFIG_MASK);
4560
4561 /* select next iter - modified LY_TREE_DFS_END */
4562 if (iter->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
4563 next = NULL;
4564 } else {
4565 next = iter->child;
4566 }
4567nextsibling:
4568 if (!next) {
4569 /* try siblings */
4570 next = iter->next;
4571 }
4572 while (!next) {
4573 /* parent is already processed, go to its sibling */
4574 iter = lys_parent(iter);
4575
4576 /* no siblings, go back through parents */
4577 if (iter == node) {
4578 /* we are done, no next element to process */
4579 break;
4580 }
4581 next = iter->next;
4582 }
4583 }
4584 }
4585
4586 /* default value */
4587 if (rfn->dflt_size && node->nodetype == LYS_CHOICE) {
4588 /* choice */
4589
4590 ((struct lys_node_choice *)node)->dflt = resolve_choice_dflt((struct lys_node_choice *)node,
4591 rfn->dflt[0]);
4592 if (!((struct lys_node_choice *)node)->dflt) {
4593 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->dflt[0], "default");
4594 goto fail;
4595 }
4596 if (lyp_check_mandatory_choice(node)) {
4597 goto fail;
4598 }
4599 }
4600
4601 /* min/max-elements on list or leaf-list */
4602 if (node->nodetype == LYS_LIST) {
4603 if (((struct lys_node_list *)node)->min > ((struct lys_node_list *)node)->max) {
4604 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
4605 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "\"min-elements\" is bigger than \"max-elements\".");
4606 goto fail;
4607 }
4608 } else if (node->nodetype == LYS_LEAFLIST) {
4609 if (((struct lys_node_leaflist *)node)->min > ((struct lys_node_leaflist *)node)->max) {
4610 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
4611 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "\"min-elements\" is bigger than \"max-elements\".");
4612 goto fail;
4613 }
4614 }
4615
4616 /* additional checks */
4617 if (node->nodetype == LYS_LEAFLIST) {
4618 llist = (struct lys_node_leaflist *)node;
4619 if (llist->dflt_size && llist->min) {
4620 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, rfn->dflt_size ? "default" : "min-elements", "refine");
4621 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
4622 "The \"min-elements\" statement with non-zero value is forbidden on leaf-lists with the \"default\" statement.");
4623 goto fail;
4624 }
4625 }
4626 if ((rfn->flags & LYS_MAND_TRUE) || rfn->mod.list.min) {
4627 /* check for mandatory node in default case, first find the closest parent choice to the changed node */
4628 for (parent = node->parent;
4629 parent && !(parent->nodetype & (LYS_CHOICE | LYS_GROUPING | LYS_ACTION | LYS_USES));
4630 parent = parent->parent) {
4631 if (parent->nodetype == LYS_CONTAINER && ((struct lys_node_container *)parent)->presence) {
4632 /* stop also on presence containers */
4633 break;
4634 }
4635 }
4636 /* and if it is a choice with the default case, check it for presence of a mandatory node in it */
4637 if (parent && parent->nodetype == LYS_CHOICE && ((struct lys_node_choice *)parent)->dflt) {
4638 if (lyp_check_mandatory_choice(parent)) {
4639 goto fail;
4640 }
4641 }
4642 }
4643 }
4644 free(refine_nodes);
4645
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004646 return EXIT_SUCCESS;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004647
4648fail:
4649 LY_TREE_FOR_SAFE(uses->child, next, iter) {
4650 lys_node_free(iter, NULL, 0);
4651 }
Pavol Vican855ca622016-09-05 13:07:54 +02004652 free(refine_nodes);
Michal Vaskoa86508c2016-08-26 14:30:19 +02004653 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004654}
4655
Radek Krejci018f1f52016-08-03 16:01:20 +02004656static int
4657identity_backlink_update(struct lys_ident *der, struct lys_ident *base)
4658{
4659 int i;
4660
4661 assert(der && base);
4662
4663 base->der = ly_realloc(base->der, (base->der_size + 1) * sizeof *(base->der));
4664 if (!base->der) {
4665 LOGMEM;
4666 return EXIT_FAILURE;
4667 }
4668 base->der[base->der_size++] = der;
4669
4670 for (i = 0; i < base->base_size; i++) {
4671 if (identity_backlink_update(der, base->base[i])) {
4672 return EXIT_FAILURE;
4673 }
4674 }
4675
4676 return EXIT_SUCCESS;
4677}
4678
Michal Vasko730dfdf2015-08-11 14:48:05 +02004679/**
4680 * @brief Resolve base identity recursively. Does not log.
4681 *
4682 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004683 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004684 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004685 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004686 *
Radek Krejci219fa612016-08-15 10:36:51 +02004687 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on crucial error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004688 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004689static int
Michal Vasko1e62a092015-12-01 12:27:20 +01004690resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Radek Krejci018f1f52016-08-03 16:01:20 +02004691 struct unres_schema *unres, struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004692{
Michal Vaskof02e3742015-08-05 16:27:02 +02004693 uint32_t i, j;
Radek Krejci018f1f52016-08-03 16:01:20 +02004694 struct lys_ident *base = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004695
Radek Krejcicf509982015-12-15 09:22:44 +01004696 assert(ret);
4697
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004698 /* search module */
4699 for (i = 0; i < module->ident_size; i++) {
4700 if (!strcmp(basename, module->ident[i].name)) {
4701
4702 if (!ident) {
4703 /* just search for type, so do not modify anything, just return
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004704 * the base identity pointer */
Radek Krejcicf509982015-12-15 09:22:44 +01004705 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004706 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004707 }
4708
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004709 base = &module->ident[i];
4710 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004711 }
4712 }
4713
4714 /* search submodules */
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004715 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
4716 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
4717 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004718
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004719 if (!ident) {
4720 *ret = &module->inc[j].submodule->ident[i];
4721 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004722 }
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004723
4724 base = &module->inc[j].submodule->ident[i];
4725 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004726 }
4727 }
4728 }
4729
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004730matchfound:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004731 /* we found it somewhere */
Radek Krejcibabbff82016-02-19 13:31:37 +01004732 if (base) {
Radek Krejci018f1f52016-08-03 16:01:20 +02004733 /* is it already completely resolved? */
4734 for (i = 0; i < unres->count; i++) {
Radek Krejciba7b1cc2016-08-08 13:44:43 +02004735 if ((unres->item[i] == base) && (unres->type[i] == UNRES_IDENT)) {
Radek Krejci018f1f52016-08-03 16:01:20 +02004736 /* identity found, but not yet resolved, so do not return it in *res and try it again later */
4737
4738 /* simple check for circular reference,
4739 * the complete check is done as a side effect of using only completely
4740 * resolved identities (previous check of unres content) */
4741 if (ly_strequal((const char *)unres->str_snode[i], ident->name, 1)) {
4742 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, basename, "base");
4743 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Circular reference of \"%s\" identity.", basename);
Radek Krejci219fa612016-08-15 10:36:51 +02004744 return -1;
Radek Krejci018f1f52016-08-03 16:01:20 +02004745 }
4746
Radek Krejci06f64ed2016-08-15 11:07:44 +02004747 return EXIT_FAILURE;
Radek Krejcibabbff82016-02-19 13:31:37 +01004748 }
4749 }
Radek Krejci018f1f52016-08-03 16:01:20 +02004750
Radek Krejcibabbff82016-02-19 13:31:37 +01004751 /* checks done, store the result */
Radek Krejci018f1f52016-08-03 16:01:20 +02004752 *ret = base;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02004753 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004754 }
4755
Radek Krejci219fa612016-08-15 10:36:51 +02004756 /* base not found (maybe a forward reference) */
4757 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004758}
4759
Michal Vasko730dfdf2015-08-11 14:48:05 +02004760/**
4761 * @brief Resolve base identity. Logs directly.
4762 *
4763 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004764 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004765 * @param[in] basename Base name of the identity.
Radek Krejcibabbff82016-02-19 13:31:37 +01004766 * @param[in] parent Either "type" or "identity".
Radek Krejcicf509982015-12-15 09:22:44 +01004767 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004768 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004769 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004770 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004771static int
Michal Vaskof2d43962016-09-02 11:10:16 +02004772resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char *parent,
Radek Krejci018f1f52016-08-03 16:01:20 +02004773 struct lys_type *type, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004774{
4775 const char *name;
Radek Krejci219fa612016-08-15 10:36:51 +02004776 int mod_name_len = 0, rc;
Radek Krejcicf509982015-12-15 09:22:44 +01004777 struct lys_ident *target, **ret;
Radek Krejci4372b4e2016-04-14 17:42:16 +02004778 uint16_t flags;
Radek Krejcicf509982015-12-15 09:22:44 +01004779 struct lys_module *mod;
4780
4781 assert((ident && !type) || (!ident && type));
4782
4783 if (!type) {
4784 /* have ident to resolve */
4785 ret = &target;
4786 flags = ident->flags;
4787 mod = ident->module;
4788 } else {
4789 /* have type to fill */
Michal Vaskof2d43962016-09-02 11:10:16 +02004790 ++type->info.ident.count;
4791 type->info.ident.ref = ly_realloc(type->info.ident.ref, type->info.ident.count * sizeof *type->info.ident.ref);
4792 if (!type->info.ident.ref) {
4793 LOGMEM;
4794 return -1;
4795 }
4796
4797 ret = &type->info.ident.ref[type->info.ident.count - 1];
Radek Krejcicf509982015-12-15 09:22:44 +01004798 flags = type->parent->flags;
4799 mod = type->parent->module;
4800 }
Michal Vaskof2006002016-04-21 16:28:15 +02004801 *ret = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004802
4803 /* search for the base identity */
4804 name = strchr(basename, ':');
4805 if (name) {
4806 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02004807 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004808 name++;
4809
Michal Vasko2d851a92015-10-20 16:16:36 +02004810 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004811 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02004812 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004813 }
4814 } else {
4815 name = basename;
4816 }
4817
Radek Krejcic071c542016-01-27 14:57:51 +01004818 /* get module where to search */
4819 module = lys_get_import_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len);
4820 if (!module) {
4821 /* identity refers unknown data model */
Radek Krejci02a04992016-03-17 16:06:37 +01004822 LOGVAL(LYE_INMOD, LY_VLOG_NONE, NULL, basename);
Radek Krejcic071c542016-01-27 14:57:51 +01004823 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004824 }
4825
Radek Krejcic071c542016-01-27 14:57:51 +01004826 /* search in the identified module ... */
Radek Krejci219fa612016-08-15 10:36:51 +02004827 rc = resolve_base_ident_sub(module, ident, name, unres, ret);
4828 if (!rc) {
4829 assert(*ret);
4830
4831 /* check status */
4832 if (lyp_check_status(flags, mod, ident ? ident->name : "of type",
4833 (*ret)->flags, (*ret)->module, (*ret)->name, NULL)) {
4834 rc = -1;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02004835 } else {
4836 if (ident) {
4837 ident->base[ident->base_size++] = *ret;
4838
4839 /* maintain backlinks to the derived identities */
4840 rc = identity_backlink_update(ident, *ret) ? -1 : EXIT_SUCCESS;
4841 }
Radek Krejci219fa612016-08-15 10:36:51 +02004842 }
4843 } else if (rc == EXIT_FAILURE) {
4844 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, parent, basename);
Pavol Vican053a2882016-09-05 14:40:33 +02004845 if (type) {
4846 --type->info.ident.count;
4847 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004848 }
4849
Radek Krejci219fa612016-08-15 10:36:51 +02004850 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004851}
4852
Michal Vasko730dfdf2015-08-11 14:48:05 +02004853/**
Michal Vaskof39142b2015-10-21 11:40:05 +02004854 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004855 *
Michal Vaskof2d43962016-09-02 11:10:16 +02004856 * @param[in] type Identityref type.
Michal Vaskofb0873c2015-08-21 09:00:07 +02004857 * @param[in] ident_name Identityref name.
Radek Krejciadb57612016-02-16 13:34:34 +01004858 * @param[in] node Node where the identityref is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02004859 *
4860 * @return Pointer to the identity resolvent, NULL on error.
4861 */
Radek Krejcia52656e2015-08-05 13:41:50 +02004862struct lys_ident *
Michal Vaskof2d43962016-09-02 11:10:16 +02004863resolve_identref(struct lys_type *type, const char *ident_name, struct lyd_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004864{
Michal Vaskoc633ca02015-08-21 14:03:51 +02004865 const char *mod_name, *name;
Michal Vaskof2d43962016-09-02 11:10:16 +02004866 int mod_name_len, rc, i, j;
4867 struct lys_ident *der, *cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004868
Michal Vaskof2d43962016-09-02 11:10:16 +02004869 if (!type || (!type->info.ident.count && !type->der) || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004870 return NULL;
4871 }
4872
Michal Vaskoc633ca02015-08-21 14:03:51 +02004873 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, NULL);
Michal Vaskob43bb3c2016-03-17 15:00:27 +01004874 if (rc < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004875 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02004876 return NULL;
Michal Vaskob43bb3c2016-03-17 15:00:27 +01004877 } else if (rc < (signed)strlen(ident_name)) {
Radek Krejci02a04992016-03-17 16:06:37 +01004878 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[rc], &ident_name[rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02004879 return NULL;
4880 }
4881
Michal Vaskof2d43962016-09-02 11:10:16 +02004882 /* go through all the bases in all the derived types */
4883 while (type->der) {
4884 for (i = 0; i < type->info.ident.count; ++i) {
4885 cur = type->info.ident.ref[i];
4886 if (!strcmp(cur->name, name) && (!mod_name
4887 || (!strncmp(cur->module->name, mod_name, mod_name_len) && !cur->module->name[mod_name_len]))) {
4888 goto match;
4889 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02004890
Michal Vaskof2d43962016-09-02 11:10:16 +02004891 for (j = 0; j < cur->der_size; j++) {
4892 der = cur->der[j]; /* shortcut */
4893 if (!strcmp(der->name, name) &&
4894 (!mod_name || (!strncmp(der->module->name, mod_name, mod_name_len) && !der->module->name[mod_name_len]))) {
4895 /* we have match */
4896 cur = der;
4897 goto match;
4898 }
4899 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004900 }
Michal Vaskof2d43962016-09-02 11:10:16 +02004901 type = &type->der->type;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004902 }
4903
Radek Krejci48464ed2016-03-17 15:44:09 +01004904 LOGVAL(LYE_INRESOLV, LY_VLOG_LYD, node, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004905 return NULL;
Radek Krejcif1ee2e22016-08-02 16:36:48 +02004906
4907match:
Michal Vaskof2d43962016-09-02 11:10:16 +02004908 for (i = 0; i < cur->iffeature_size; i++) {
4909 if (!resolve_iffeature(&cur->iffeature[i])) {
4910 LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, cur->name, node->schema->name);
Radek Krejcif1ee2e22016-08-02 16:36:48 +02004911 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, "Identity \"%s\" is disabled by its if-feature condition.",
Michal Vaskof2d43962016-09-02 11:10:16 +02004912 cur->name);
Radek Krejcif1ee2e22016-08-02 16:36:48 +02004913 return NULL;
4914 }
4915 }
Michal Vaskof2d43962016-09-02 11:10:16 +02004916 return cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004917}
4918
Michal Vasko730dfdf2015-08-11 14:48:05 +02004919/**
Michal Vaskobb211122015-08-19 14:03:11 +02004920 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004921 *
Michal Vaskobb211122015-08-19 14:03:11 +02004922 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004923 * @param[in] unres Specific unres item.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004924 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004925 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004926 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004927static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004928resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004929{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004930 int rc;
Radek Krejci010e54b2016-03-15 09:40:34 +01004931 struct lys_node *par_grp;
Michal Vaskoe91afce2015-08-12 12:21:00 +02004932
Radek Krejci010e54b2016-03-15 09:40:34 +01004933 /* HACK: when a grouping has uses inside, all such uses have to be resolved before the grouping itself
4934 * is used in some uses. When we see such a uses, the grouping's nacm member (not used in grouping)
4935 * is used to store number of so far unresolved uses. The grouping cannot be used unless the nacm
4936 * value is decreased back to 0. To remember that the uses already increased grouping's nacm, the
4937 * LYS_USESGRP flag is used. */
Michal Vaskodcf98e62016-05-05 17:53:53 +02004938 for (par_grp = lys_parent((struct lys_node *)uses); par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
Michal Vaskoe91afce2015-08-12 12:21:00 +02004939
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004940 if (!uses->grp) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01004941 rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
4942 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004943 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "grouping", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01004944 return -1;
4945 } else if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004946 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01004947 return -1;
4948 } else if (!uses->grp) {
Radek Krejci010e54b2016-03-15 09:40:34 +01004949 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02004950 /* hack - in contrast to lys_node, lys_node_grp has bigger nacm field
4951 * (and smaller flags - it uses only a limited set of flags)
4952 */
4953 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci010e54b2016-03-15 09:40:34 +01004954 uses->flags |= LYS_USESGRP;
Michal Vasko407f1bb2015-09-23 15:51:07 +02004955 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01004956 return EXIT_FAILURE;
Michal Vasko12e30842015-08-04 11:54:00 +02004957 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004958 }
4959
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004960 if (uses->grp->nacm) {
Radek Krejci010e54b2016-03-15 09:40:34 +01004961 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02004962 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci010e54b2016-03-15 09:40:34 +01004963 uses->flags |= LYS_USESGRP;
Radek Krejcie00d2312016-08-12 15:27:49 +02004964 } else {
4965 /* instantiate grouping only when it is completely resolved */
4966 uses->grp = NULL;
Michal Vasko407f1bb2015-09-23 15:51:07 +02004967 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004968 return EXIT_FAILURE;
4969 }
4970
Radek Krejci48464ed2016-03-17 15:44:09 +01004971 rc = resolve_uses(uses, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004972 if (!rc) {
4973 /* decrease unres count only if not first try */
Radek Krejci010e54b2016-03-15 09:40:34 +01004974 if (par_grp && (uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02004975 if (!((struct lys_node_grp *)par_grp)->nacm) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004976 LOGINT;
4977 return -1;
4978 }
Radek Krejci4372b4e2016-04-14 17:42:16 +02004979 ((struct lys_node_grp *)par_grp)->nacm--;
Radek Krejci010e54b2016-03-15 09:40:34 +01004980 uses->flags &= ~LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004981 }
Radek Krejcicf509982015-12-15 09:22:44 +01004982
4983 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01004984 if (lyp_check_status(uses->flags, uses->module, "of uses",
Radek Krejciadb57612016-02-16 13:34:34 +01004985 uses->grp->flags, uses->grp->module, uses->grp->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01004986 (struct lys_node *)uses)) {
Radek Krejcicf509982015-12-15 09:22:44 +01004987 return -1;
4988 }
4989
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004990 return EXIT_SUCCESS;
Radek Krejci010e54b2016-03-15 09:40:34 +01004991 } else if ((rc == EXIT_FAILURE) && par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02004992 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci010e54b2016-03-15 09:40:34 +01004993 uses->flags |= LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004994 }
4995
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004996 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004997}
4998
Michal Vasko730dfdf2015-08-11 14:48:05 +02004999/**
Michal Vasko9957e592015-08-17 15:04:09 +02005000 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005001 *
Michal Vaskobb211122015-08-19 14:03:11 +02005002 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005003 * @param[in] keys_str Keys node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005004 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005005 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005006 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005007static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005008resolve_list_keys(struct lys_node_list *list, const char *keys_str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005009{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005010 int i, len, rc;
Michal Vasko4f0dad02016-02-15 14:08:23 +01005011 const char *value;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005012
5013 for (i = 0; i < list->keys_size; ++i) {
5014 /* get the key name */
5015 if ((value = strpbrk(keys_str, " \t\n"))) {
5016 len = value - keys_str;
5017 while (isspace(value[0])) {
5018 value++;
5019 }
5020 } else {
5021 len = strlen(keys_str);
5022 }
5023
Radek Krejcic4283442016-04-22 09:19:27 +02005024 rc = lys_get_sibling(list->child, lys_main_module(list->module)->name, 0, keys_str, len, LYS_LEAF, (const struct lys_node **)&list->keys[i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005025 if (rc) {
Michal Vasko7a55bea2016-05-02 14:51:20 +02005026 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
5027 return EXIT_FAILURE;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005028 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005029
Radek Krejci48464ed2016-03-17 15:44:09 +01005030 if (check_key(list, i, keys_str, len)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005031 /* check_key logs */
5032 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005033 }
5034
Radek Krejcicf509982015-12-15 09:22:44 +01005035 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005036 if (lyp_check_status(list->flags, list->module, list->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005037 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
5038 (struct lys_node *)list->keys[i])) {
Radek Krejcicf509982015-12-15 09:22:44 +01005039 return -1;
5040 }
5041
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005042 /* prepare for next iteration */
5043 while (value && isspace(value[0])) {
5044 value++;
5045 }
5046 keys_str = value;
5047 }
5048
Michal Vaskof02e3742015-08-05 16:27:02 +02005049 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005050}
5051
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005052/**
Michal Vaskobf19d252015-10-08 15:39:17 +02005053 * @brief Resolve (check) all must conditions of \p node.
5054 * Logs directly.
5055 *
5056 * @param[in] node Data node with optional must statements.
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005057 * @param[in] inout_parent If set, must in input or output parent of node->schema will be resolved.
Michal Vaskobf19d252015-10-08 15:39:17 +02005058 *
5059 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
5060 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005061static int
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005062resolve_must(struct lyd_node *node, int inout_parent)
Michal Vaskof02e3742015-08-05 16:27:02 +02005063{
Michal Vaskobf19d252015-10-08 15:39:17 +02005064 uint8_t i, must_size;
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005065 struct lys_node *schema;
Michal Vaskobf19d252015-10-08 15:39:17 +02005066 struct lys_restr *must;
5067 struct lyxp_set set;
5068
5069 assert(node);
5070 memset(&set, 0, sizeof set);
5071
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005072 if (inout_parent) {
5073 for (schema = lys_parent(node->schema);
5074 schema && (schema->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES));
5075 schema = lys_parent(schema));
5076 if (!schema || !(schema->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5077 LOGINT;
5078 return -1;
5079 }
5080 must_size = ((struct lys_node_inout *)schema)->must_size;
5081 must = ((struct lys_node_inout *)schema)->must;
5082
5083 /* context node is the RPC/action */
5084 node = node->parent;
5085 if (!(node->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
5086 LOGINT;
5087 return -1;
5088 }
5089 } else {
5090 switch (node->schema->nodetype) {
5091 case LYS_CONTAINER:
5092 must_size = ((struct lys_node_container *)node->schema)->must_size;
5093 must = ((struct lys_node_container *)node->schema)->must;
5094 break;
5095 case LYS_LEAF:
5096 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
5097 must = ((struct lys_node_leaf *)node->schema)->must;
5098 break;
5099 case LYS_LEAFLIST:
5100 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
5101 must = ((struct lys_node_leaflist *)node->schema)->must;
5102 break;
5103 case LYS_LIST:
5104 must_size = ((struct lys_node_list *)node->schema)->must_size;
5105 must = ((struct lys_node_list *)node->schema)->must;
5106 break;
5107 case LYS_ANYXML:
5108 case LYS_ANYDATA:
5109 must_size = ((struct lys_node_anydata *)node->schema)->must_size;
5110 must = ((struct lys_node_anydata *)node->schema)->must;
5111 break;
5112 case LYS_NOTIF:
5113 must_size = ((struct lys_node_notif *)node->schema)->must_size;
5114 must = ((struct lys_node_notif *)node->schema)->must;
5115 break;
5116 default:
5117 must_size = 0;
5118 break;
5119 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005120 }
5121
5122 for (i = 0; i < must_size; ++i) {
Michal Vaskoa59495d2016-08-22 09:18:58 +02005123 if (lyxp_eval(must[i].expr, node, LYXP_NODE_ELEM, &set, LYXP_MUST)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02005124 return -1;
5125 }
5126
Michal Vasko944a5642016-03-21 11:48:58 +01005127 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, LYXP_MUST);
Michal Vaskobf19d252015-10-08 15:39:17 +02005128
Michal Vasko8146d4c2016-05-09 15:50:29 +02005129 if (!set.val.bool) {
Michal Vasko6ac68282016-04-11 10:56:47 +02005130 LOGVAL(LYE_NOMUST, LY_VLOG_LYD, node, must[i].expr);
5131 if (must[i].emsg) {
5132 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, must[i].emsg);
5133 }
5134 if (must[i].eapptag) {
5135 strncpy(((struct ly_err *)&ly_errno)->apptag, must[i].eapptag, LY_APPTAG_LEN - 1);
5136 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005137 return 1;
5138 }
5139 }
5140
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005141 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02005142}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005143
Michal Vaskobf19d252015-10-08 15:39:17 +02005144/**
Michal Vasko508a50d2016-09-07 14:50:33 +02005145 * @brief Resolve (find) when condition schema context node. Does not log.
5146 *
5147 * @param[in] schema Schema node with the when condition.
5148 * @param[out] ctx_snode When schema context node.
5149 * @param[out] ctx_snode_type Schema context node type.
5150 */
5151void
5152resolve_when_ctx_snode(const struct lys_node *schema, struct lys_node **ctx_snode, enum lyxp_node_type *ctx_snode_type)
5153{
5154 const struct lys_node *sparent;
5155
5156 /* find a not schema-only node */
5157 *ctx_snode_type = LYXP_NODE_ELEM;
5158 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
5159 if (schema->nodetype == LYS_AUGMENT) {
5160 sparent = ((struct lys_node_augment *)schema)->target;
5161 } else {
5162 sparent = schema->parent;
5163 }
5164 if (!sparent) {
5165 /* context node is the document root (fake root in our case) */
5166 if (schema->flags & LYS_CONFIG_W) {
5167 *ctx_snode_type = LYXP_NODE_ROOT_CONFIG;
5168 } else {
Michal Vaskob94a5e42016-09-08 14:01:56 +02005169 *ctx_snode_type = LYXP_NODE_ROOT;
Michal Vasko508a50d2016-09-07 14:50:33 +02005170 }
Michal Vasko2d2aec12016-09-08 11:42:50 +02005171 /* we need the first top-level sibling, but no uses or groupings */
Michal Vaskob94a5e42016-09-08 14:01:56 +02005172 schema = lys_getnext(NULL, NULL, lys_node_module(schema), 0);
Michal Vasko508a50d2016-09-07 14:50:33 +02005173 break;
5174 }
5175 schema = sparent;
5176 }
5177
5178 *ctx_snode = (struct lys_node *)schema;
5179}
5180
5181/**
Michal Vaskocf024702015-10-08 15:01:42 +02005182 * @brief Resolve (find) when condition context node. Does not log.
5183 *
5184 * @param[in] node Data node, whose conditional definition is being decided.
Michal Vasko508a50d2016-09-07 14:50:33 +02005185 * @param[in] schema Schema node with the when condition.
Michal Vaskoa59495d2016-08-22 09:18:58 +02005186 * @param[out] ctx_node Context node.
5187 * @param[out] ctx_node_type Context node type.
Michal Vaskocf024702015-10-08 15:01:42 +02005188 *
Michal Vaskoa59495d2016-08-22 09:18:58 +02005189 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vaskocf024702015-10-08 15:01:42 +02005190 */
Michal Vaskoa59495d2016-08-22 09:18:58 +02005191static int
5192resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema, struct lyd_node **ctx_node,
5193 enum lyxp_node_type *ctx_node_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005194{
Michal Vaskocf024702015-10-08 15:01:42 +02005195 struct lyd_node *parent;
5196 struct lys_node *sparent;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005197 enum lyxp_node_type node_type;
Michal Vaskocf024702015-10-08 15:01:42 +02005198 uint16_t i, data_depth, schema_depth;
5199
Michal Vasko508a50d2016-09-07 14:50:33 +02005200 resolve_when_ctx_snode(schema, &schema, &node_type);
Michal Vaskocf024702015-10-08 15:01:42 +02005201
Michal Vaskofe989752016-09-08 08:47:26 +02005202 if (node_type == LYXP_NODE_ELEM) {
5203 /* standard element context node */
5204 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
5205 for (sparent = schema, schema_depth = 0;
5206 sparent;
5207 sparent = (sparent->nodetype == LYS_AUGMENT ? ((struct lys_node_augment *)sparent)->target : sparent->parent)) {
5208 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_NOTIF | LYS_RPC)) {
5209 ++schema_depth;
5210 }
Michal Vaskocf024702015-10-08 15:01:42 +02005211 }
Michal Vaskofe989752016-09-08 08:47:26 +02005212 if (data_depth < schema_depth) {
5213 return -1;
5214 }
Michal Vaskocf024702015-10-08 15:01:42 +02005215
Michal Vasko956e8542016-08-26 09:43:35 +02005216 /* find the corresponding data node */
5217 for (i = 0; i < data_depth - schema_depth; ++i) {
5218 node = node->parent;
5219 }
Michal Vaskoa59495d2016-08-22 09:18:58 +02005220 if (node->schema != schema) {
5221 return -1;
5222 }
Michal Vaskofe989752016-09-08 08:47:26 +02005223 } else {
5224 /* root context node */
5225 while (node->parent) {
5226 node = node->parent;
5227 }
5228 while (node->prev->next) {
5229 node = node->prev;
5230 }
Michal Vaskocf024702015-10-08 15:01:42 +02005231 }
5232
Michal Vaskoa59495d2016-08-22 09:18:58 +02005233 *ctx_node = node;
5234 *ctx_node_type = node_type;
5235 return EXIT_SUCCESS;
Michal Vaskocf024702015-10-08 15:01:42 +02005236}
5237
Michal Vasko76c3bd32016-08-24 16:02:52 +02005238/**
5239 * @brief Temporarily unlink nodes as per YANG 1.1 RFC section 7.21.5 for when XPath evaluation.
5240 * The context nodes is adjusted if needed.
5241 *
5242 * @param[in] snode Schema node, whose children instances need to be unlinked.
5243 * @param[in,out] node Data siblings where to look for the children of \p snode. If it is unlinked,
5244 * it is moved to point to another sibling still in the original tree.
5245 * @param[in,out] ctx_node When context node, adjusted if needed.
5246 * @param[in] ctx_node_type Context node type, just for information to detect invalid situations.
5247 * @param[out] unlinked_nodes Unlinked siblings. Can be safely appended to \p node afterwards.
5248 * Ordering may change, but there will be no semantic change.
5249 *
5250 * @return EXIT_SUCCESS on success, -1 on error.
5251 */
5252static int
5253resolve_when_unlink_nodes(struct lys_node *snode, struct lyd_node **node, struct lyd_node **ctx_node,
5254 enum lyxp_node_type ctx_node_type, struct lyd_node **unlinked_nodes)
5255{
5256 struct lyd_node *next, *elem;
5257
5258 switch (snode->nodetype) {
5259 case LYS_AUGMENT:
5260 case LYS_USES:
5261 case LYS_CHOICE:
5262 case LYS_CASE:
5263 LY_TREE_FOR(snode->child, snode) {
5264 if (resolve_when_unlink_nodes(snode, node, ctx_node, ctx_node_type, unlinked_nodes)) {
5265 return -1;
5266 }
5267 }
5268 break;
5269 case LYS_CONTAINER:
5270 case LYS_LIST:
5271 case LYS_LEAF:
5272 case LYS_LEAFLIST:
5273 case LYS_ANYXML:
5274 case LYS_ANYDATA:
5275 LY_TREE_FOR_SAFE(lyd_first_sibling(*node), next, elem) {
5276 if (elem->schema == snode) {
5277
5278 if (elem == *ctx_node) {
5279 /* We are going to unlink our context node! This normally cannot happen,
5280 * but we use normal top-level data nodes for faking a document root node,
5281 * so if this is the context node, we just use the next top-level node.
5282 * Additionally, it can even happen that there are no top-level data nodes left,
5283 * all were unlinked, so in this case we pass NULL as the context node/data tree,
5284 * lyxp_eval() can handle this special situation.
5285 */
5286 if (ctx_node_type == LYXP_NODE_ELEM) {
5287 LOGINT;
5288 return -1;
5289 }
5290
5291 if (elem->prev == elem) {
5292 /* unlinking last top-level element, use an empty data tree */
5293 *ctx_node = NULL;
5294 } else {
5295 /* in this case just use the previous/last top-level data node */
5296 *ctx_node = elem->prev;
5297 }
5298 } else if (elem == *node) {
5299 /* We are going to unlink the currently processed node. This does not matter that
5300 * much, but we would lose access to the original data tree, so just move our
5301 * pointer somewhere still inside it.
5302 */
5303 if ((*node)->prev != *node) {
5304 *node = (*node)->prev;
5305 } else {
5306 /* the processed node with sibings were all unlinked, oh well */
5307 *node = NULL;
5308 }
5309 }
5310
5311 /* temporarily unlink the node */
5312 lyd_unlink(elem);
5313 if (*unlinked_nodes) {
5314 if (lyd_insert_after(*unlinked_nodes, elem)) {
5315 LOGINT;
5316 return -1;
5317 }
5318 } else {
5319 *unlinked_nodes = elem;
5320 }
5321
5322 if (snode->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_ANYDATA)) {
5323 /* there can be only one instance */
5324 break;
5325 }
5326 }
5327 }
5328 break;
5329 default:
5330 LOGINT;
5331 return -1;
5332 }
5333
5334 return EXIT_SUCCESS;
5335}
5336
5337/**
5338 * @brief Relink the unlinked nodes back.
5339 *
5340 * @param[in] node Data node to link the nodes back to. It can actually be the adjusted context node,
5341 * we simply need a sibling from the original data tree.
5342 * @param[in] unlinked_nodes Unlinked nodes to relink to \p node.
5343 * @param[in] ctx_node_type Context node type to distinguish between \p node being the parent
5344 * or the sibling of \p unlinked_nodes.
5345 *
5346 * @return EXIT_SUCCESS on success, -1 on error.
5347 */
5348static int
5349resolve_when_relink_nodes(struct lyd_node *node, struct lyd_node *unlinked_nodes, enum lyxp_node_type ctx_node_type)
5350{
5351 struct lyd_node *elem;
5352
5353 LY_TREE_FOR_SAFE(unlinked_nodes, unlinked_nodes, elem) {
5354 if (ctx_node_type == LYXP_NODE_ELEM) {
5355 if (lyd_insert(node, elem)) {
5356 return -1;
5357 }
5358 } else {
5359 if (lyd_insert_after(node, elem)) {
5360 return -1;
5361 }
5362 }
5363 }
5364
5365 return EXIT_SUCCESS;
5366}
5367
Radek Krejci03b71f72016-03-16 11:10:09 +01005368int
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005369resolve_applies_must(const struct lyd_node *node)
Radek Krejci01696bf2016-03-18 13:19:36 +01005370{
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005371 int ret = 0;
5372 uint8_t must_size;
5373 struct lys_node *schema, *iter;
Radek Krejci46165822016-08-26 14:06:27 +02005374
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005375 assert(node);
5376
5377 schema = node->schema;
5378
5379 /* their own must */
Radek Krejci46165822016-08-26 14:06:27 +02005380 switch (schema->nodetype) {
Radek Krejci01696bf2016-03-18 13:19:36 +01005381 case LYS_CONTAINER:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005382 must_size = ((struct lys_node_container *)schema)->must_size;
5383 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005384 case LYS_LEAF:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005385 must_size = ((struct lys_node_leaf *)schema)->must_size;
5386 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005387 case LYS_LEAFLIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005388 must_size = ((struct lys_node_leaflist *)schema)->must_size;
5389 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005390 case LYS_LIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005391 must_size = ((struct lys_node_list *)schema)->must_size;
5392 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005393 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02005394 case LYS_ANYDATA:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005395 must_size = ((struct lys_node_anydata *)schema)->must_size;
5396 break;
5397 case LYS_NOTIF:
5398 must_size = ((struct lys_node_notif *)schema)->must_size;
5399 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005400 default:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005401 must_size = 0;
5402 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005403 }
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005404
5405 if (must_size) {
5406 ++ret;
5407 }
5408
5409 /* schema may be a direct data child of input/output with must (but it must be first, it needs to be evaluated only once) */
5410 if (!node->prev->next) {
5411 for (iter = lys_parent(schema); iter && (iter->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES)); iter = lys_parent(iter));
5412 if (iter && (iter->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5413 ret += 0x2;
5414 }
5415 }
5416
5417 return ret;
Radek Krejci01696bf2016-03-18 13:19:36 +01005418}
5419
5420int
Radek Krejci46165822016-08-26 14:06:27 +02005421resolve_applies_when(const struct lys_node *schema, int mode, const struct lys_node *stop)
Radek Krejci03b71f72016-03-16 11:10:09 +01005422{
Radek Krejci46165822016-08-26 14:06:27 +02005423 const struct lys_node *parent;
Radek Krejci03b71f72016-03-16 11:10:09 +01005424
Radek Krejci46165822016-08-26 14:06:27 +02005425 assert(schema);
Radek Krejci03b71f72016-03-16 11:10:09 +01005426
Radek Krejci46165822016-08-26 14:06:27 +02005427 if (!(schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)schema)->when)) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005428 return 1;
5429 }
5430
Radek Krejci46165822016-08-26 14:06:27 +02005431 parent = schema;
Radek Krejci03b71f72016-03-16 11:10:09 +01005432 goto check_augment;
5433
Radek Krejci46165822016-08-26 14:06:27 +02005434 while (parent) {
5435 /* stop conditions */
5436 if (!mode) {
5437 /* stop on node that can be instantiated in data tree */
5438 if (!(parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
5439 break;
5440 }
5441 } else {
5442 /* stop on the specified node */
5443 if (parent == stop) {
5444 break;
5445 }
5446 }
5447
5448 if (((const struct lys_node_uses *)parent)->when) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005449 return 1;
5450 }
5451check_augment:
5452
5453 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) &&
Radek Krejci46165822016-08-26 14:06:27 +02005454 (((const struct lys_node_augment *)parent->parent)->when))) {
Michal Vaskoe3655562016-08-24 15:56:17 +02005455 return 1;
Radek Krejci03b71f72016-03-16 11:10:09 +01005456 }
5457 parent = lys_parent(parent);
5458 }
5459
5460 return 0;
5461}
5462
Michal Vaskocf024702015-10-08 15:01:42 +02005463/**
5464 * @brief Resolve (check) all when conditions relevant for \p node.
5465 * Logs directly.
5466 *
5467 * @param[in] node Data node, whose conditional reference, if such, is being decided.
Michal Vaskocf024702015-10-08 15:01:42 +02005468 *
Radek Krejci03b71f72016-03-16 11:10:09 +01005469 * @return
5470 * -1 - error, ly_errno is set
5471 * 0 - true "when" statement
Radek Krejci46165822016-08-26 14:06:27 +02005472 * 0, ly_vecode = LYVE_NOWHEN - false "when" statement
Radek Krejci03b71f72016-03-16 11:10:09 +01005473 * 1, ly_vecode = LYVE_INWHEN - nodes needed to resolve are conditional and not yet resolved (under another "when")
Michal Vaskocf024702015-10-08 15:01:42 +02005474 */
Radek Krejci46165822016-08-26 14:06:27 +02005475int
5476resolve_when(struct lyd_node *node, int *result)
Michal Vaskocf024702015-10-08 15:01:42 +02005477{
Michal Vasko76c3bd32016-08-24 16:02:52 +02005478 struct lyd_node *ctx_node = NULL, *unlinked_nodes, *tmp_node;
Michal Vasko90fc2a32016-08-24 15:58:58 +02005479 struct lys_node *sparent;
Michal Vaskocf024702015-10-08 15:01:42 +02005480 struct lyxp_set set;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005481 enum lyxp_node_type ctx_node_type;
Radek Krejci51093642016-03-29 10:14:59 +02005482 int rc = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02005483
5484 assert(node);
5485 memset(&set, 0, sizeof set);
5486
5487 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)node->schema)->when)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005488 /* make the node dummy for the evaluation */
5489 node->validity |= LYD_VAL_INUSE;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005490 rc = lyxp_eval(((struct lys_node_container *)node->schema)->when->cond, node, LYXP_NODE_ELEM, &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005491 node->validity &= ~LYD_VAL_INUSE;
Radek Krejci03b71f72016-03-16 11:10:09 +01005492 if (rc) {
5493 if (rc == 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005494 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005495 }
Radek Krejci51093642016-03-29 10:14:59 +02005496 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005497 }
5498
Radek Krejci03b71f72016-03-16 11:10:09 +01005499 /* set boolean result of the condition */
Michal Vasko944a5642016-03-21 11:48:58 +01005500 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02005501 if (!set.val.bool) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005502 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci0b7704f2016-03-18 12:16:14 +01005503 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02005504 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005505 }
Radek Krejci51093642016-03-29 10:14:59 +02005506
5507 /* free xpath set content */
5508 lyxp_set_cast(&set, LYXP_SET_EMPTY, node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005509 }
5510
Michal Vasko90fc2a32016-08-24 15:58:58 +02005511 sparent = node->schema;
Michal Vaskocf024702015-10-08 15:01:42 +02005512 goto check_augment;
5513
5514 /* check when in every schema node that affects node */
Michal Vasko90fc2a32016-08-24 15:58:58 +02005515 while (sparent && (sparent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
5516 if (((struct lys_node_uses *)sparent)->when) {
Michal Vaskocf024702015-10-08 15:01:42 +02005517 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005518 rc = resolve_when_ctx_node(node, sparent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02005519 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02005520 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02005521 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005522 }
5523 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02005524
5525 unlinked_nodes = NULL;
5526 /* we do not want our node pointer to change */
5527 tmp_node = node;
5528 rc = resolve_when_unlink_nodes(sparent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
5529 if (rc) {
5530 goto cleanup;
5531 }
5532
5533 rc = lyxp_eval(((struct lys_node_uses *)sparent)->when->cond, ctx_node, ctx_node_type, &set, LYXP_WHEN);
5534
5535 if (unlinked_nodes && ctx_node) {
5536 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
5537 rc = -1;
5538 goto cleanup;
5539 }
5540 }
5541
Radek Krejci03b71f72016-03-16 11:10:09 +01005542 if (rc) {
5543 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005544 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005545 }
Radek Krejci51093642016-03-29 10:14:59 +02005546 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005547 }
5548
Michal Vasko944a5642016-03-21 11:48:58 +01005549 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02005550 if (!set.val.bool) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005551 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Radek Krejci0b7704f2016-03-18 12:16:14 +01005552 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02005553 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005554 }
Radek Krejci51093642016-03-29 10:14:59 +02005555
5556 /* free xpath set content */
5557 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005558 }
5559
5560check_augment:
Michal Vasko90fc2a32016-08-24 15:58:58 +02005561 if ((sparent->parent && (sparent->parent->nodetype == LYS_AUGMENT) && (((struct lys_node_augment *)sparent->parent)->when))) {
Michal Vaskocf024702015-10-08 15:01:42 +02005562 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005563 rc = resolve_when_ctx_node(node, sparent->parent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02005564 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02005565 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02005566 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005567 }
5568 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02005569
5570 unlinked_nodes = NULL;
5571 tmp_node = node;
5572 rc = resolve_when_unlink_nodes(sparent->parent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
5573 if (rc) {
5574 goto cleanup;
5575 }
5576
5577 rc = lyxp_eval(((struct lys_node_augment *)sparent->parent)->when->cond, ctx_node, ctx_node_type, &set, LYXP_WHEN);
5578
5579 /* reconnect nodes, if ctx_node is NULL then all the nodes were unlinked, but linked together,
5580 * so the tree did not actually change and there is nothing for us to do
5581 */
5582 if (unlinked_nodes && ctx_node) {
5583 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
5584 rc = -1;
5585 goto cleanup;
5586 }
5587 }
5588
Radek Krejci03b71f72016-03-16 11:10:09 +01005589 if (rc) {
5590 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005591 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005592 }
Radek Krejci51093642016-03-29 10:14:59 +02005593 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005594 }
5595
Michal Vasko944a5642016-03-21 11:48:58 +01005596 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, LYXP_WHEN);
Michal Vaskocf024702015-10-08 15:01:42 +02005597
Michal Vasko8146d4c2016-05-09 15:50:29 +02005598 if (!set.val.bool) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005599 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Radek Krejci0b7704f2016-03-18 12:16:14 +01005600 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02005601 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005602 }
Radek Krejci51093642016-03-29 10:14:59 +02005603
5604 /* free xpath set content */
5605 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005606 }
5607
Michal Vasko90fc2a32016-08-24 15:58:58 +02005608 sparent = lys_parent(sparent);
Michal Vaskocf024702015-10-08 15:01:42 +02005609 }
5610
Radek Krejci0b7704f2016-03-18 12:16:14 +01005611 node->when_status |= LYD_WHEN_TRUE;
Radek Krejci03b71f72016-03-16 11:10:09 +01005612
Radek Krejci51093642016-03-29 10:14:59 +02005613cleanup:
Radek Krejci51093642016-03-29 10:14:59 +02005614 /* free xpath set content */
5615 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node ? ctx_node : node, 0);
5616
Radek Krejci46165822016-08-26 14:06:27 +02005617 if (result) {
5618 if (node->when_status & LYD_WHEN_TRUE) {
5619 *result = 1;
5620 } else {
5621 *result = 0;
5622 }
5623 }
5624
Radek Krejci51093642016-03-29 10:14:59 +02005625 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005626}
5627
Radek Krejcicbb473e2016-09-16 14:48:32 +02005628static int
5629check_leafref_features(struct lys_type *type)
5630{
5631 struct lys_node *iter;
5632 struct ly_set *src_parents, *trg_parents, *features;
5633 unsigned int i, j, size, x;
5634 int ret = EXIT_SUCCESS;
5635
5636 assert(type->parent);
5637
5638 src_parents = ly_set_new();
5639 trg_parents = ly_set_new();
5640 features = ly_set_new();
5641
5642 /* get parents chain of source (leafref) */
5643 for (iter = (struct lys_node *)type->parent; iter; iter = iter->parent) {
5644 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
5645 continue;
5646 }
5647 ly_set_add(src_parents, iter, LY_SET_OPT_USEASLIST);
5648 }
5649 /* get parents chain of target */
5650 for (iter = (struct lys_node *)type->info.lref.target; iter; iter = iter->parent) {
5651 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
5652 continue;
5653 }
5654 ly_set_add(trg_parents, iter, LY_SET_OPT_USEASLIST);
5655 }
5656
5657 /* compare the features used in if-feature statements in the rest of both
5658 * chains of parents. The set of features used for target must be a subset
5659 * of features used for the leafref. This is not a perfect, we should compare
5660 * the truth tables but it could require too much resources, so we simplify that */
5661 for (i = 0; i < src_parents->number; i++) {
5662 iter = src_parents->set.s[i]; /* shortcut */
5663 if (!iter->iffeature_size) {
5664 continue;
5665 }
5666 for (j = 0; j < iter->iffeature_size; j++) {
5667 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
5668 for (; size; size--) {
5669 if (!iter->iffeature[j].features[size - 1]) {
5670 /* not yet resolved feature, postpone this check */
5671 ret = EXIT_FAILURE;
5672 goto cleanup;
5673 }
5674 ly_set_add(features, iter->iffeature[j].features[size - 1], 0);
5675 }
5676 }
5677 }
5678 x = features->number;
5679 for (i = 0; i < trg_parents->number; i++) {
5680 iter = trg_parents->set.s[i]; /* shortcut */
5681 if (!iter->iffeature_size) {
5682 continue;
5683 }
5684 for (j = 0; j < iter->iffeature_size; j++) {
5685 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
5686 for (; size; size--) {
5687 if (!iter->iffeature[j].features[size - 1]) {
5688 /* not yet resolved feature, postpone this check */
5689 ret = EXIT_FAILURE;
5690 goto cleanup;
5691 }
5692 if ((unsigned int)ly_set_add(features, iter->iffeature[j].features[size - 1], 0) >= x) {
5693 /* the feature is not present in features set of target's parents chain */
5694 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, type->parent, "leafref", type->info.lref.path);
5695 LOGVAL(LYE_SPEC, LY_VLOG_LYS, type->parent,
5696 "Leafref is not conditional based on \"%s\" feature as its target.",
5697 iter->iffeature[j].features[size - 1]->name);
5698 ret = -1;
5699 goto cleanup;
5700 }
5701 }
5702 }
5703 }
5704
5705cleanup:
5706 ly_set_free(features);
5707 ly_set_free(src_parents);
5708 ly_set_free(trg_parents);
5709
5710 return ret;
5711}
5712
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005713/**
Michal Vasko508a50d2016-09-07 14:50:33 +02005714 * @brief Check all XPath expressions of a node (when and must), set LYS_XPATH_DEP flag if required.
5715 *
5716 * @param[in] node Node to examine.
5717 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
5718 */
5719static int
5720check_xpath(struct lys_node *node)
5721{
5722 struct lys_node *parent, *elem;
5723 struct lyxp_set set;
5724 uint32_t i;
5725 int rc;
5726
5727 parent = node;
5728 while (parent) {
5729 if (parent->nodetype == LYS_GROUPING) {
5730 /* unresolved grouping, skip for now */
5731 return 0;
5732 }
5733 if (parent->nodetype == LYS_AUGMENT) {
5734 if (!((struct lys_node_augment *)parent)->target) {
5735 /* uresolved augment skip for now */
5736 return 0;
5737 } else {
5738 parent = ((struct lys_node_augment *)parent)->target;
5739 continue;
5740 }
5741 }
5742 parent = parent->parent;
5743 }
5744
5745 rc = lyxp_node_atomize(node, &set);
5746 if (rc) {
5747 return rc;
5748 }
5749
5750 /* RPC, action can have neither must nor when */
Michal Vasko6b44d712016-09-12 16:25:46 +02005751 for (parent = node; parent && !(parent->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); parent = lys_parent(parent));
Michal Vasko508a50d2016-09-07 14:50:33 +02005752
Michal Vaskoab423092016-09-19 13:54:36 +02005753 for (i = 0; i < set.used; ++i) {
5754 /* skip roots'n'stuff */
5755 if (set.val.snodes[i].type == LYXP_NODE_ELEM) {
5756 /* XPath expression cannot reference "lower" status than the node that has the definition */
5757 if (lyp_check_status(node->flags, lys_node_module(node), node->name, set.val.snodes[i].snode->flags,
5758 lys_node_module(set.val.snodes[i].snode), set.val.snodes[i].snode->name, node)) {
5759 return -1;
5760 }
5761
5762 if (parent) {
Michal Vasko99e93fc2016-09-09 11:12:25 +02005763 for (elem = set.val.snodes[i].snode; elem && (elem != parent); elem = lys_parent(elem));
5764 if (!elem) {
5765 /* not in node's RPC or notification subtree, set the flag */
5766 node->flags |= LYS_XPATH_DEP;
5767 break;
5768 }
Michal Vasko508a50d2016-09-07 14:50:33 +02005769 }
5770 }
5771 }
5772
5773 free(set.val.snodes);
5774 return EXIT_SUCCESS;
5775}
5776
5777/**
Michal Vaskobb211122015-08-19 14:03:11 +02005778 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005779 *
5780 * @param[in] mod Main module.
5781 * @param[in] item Item to resolve. Type determined by \p type.
5782 * @param[in] type Type of the unresolved item.
5783 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02005784 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005785 *
5786 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
5787 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005788static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02005789resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Radek Krejci48464ed2016-03-17 15:44:09 +01005790 struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005791{
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005792 /* has_str - whether the str_snode is a string in a dictionary that needs to be freed */
Radek Krejcic79c6b12016-07-26 15:11:49 +02005793 int rc = -1, has_str = 0, tpdf_flag = 0, i, k;
5794 unsigned int j;
Radek Krejcic13db382016-08-16 10:52:42 +02005795 struct lys_node *node, *par_grp;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005796 const char *expr;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005797
Radek Krejcic79c6b12016-07-26 15:11:49 +02005798 struct ly_set *refs, *procs;
5799 struct lys_feature *ref, *feat;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005800 struct lys_ident *ident;
5801 struct lys_type *stype;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005802 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01005803 struct lyxml_elem *yin;
Pavol Vicana0e4e672016-02-24 12:20:04 +01005804 struct yang_type *yang;
Radek Krejcid09d1a52016-08-11 14:05:45 +02005805 struct unres_list_uniq *unique_info;
Radek Krejcicbb473e2016-09-16 14:48:32 +02005806 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005807
5808 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005809 case UNRES_IDENT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005810 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01005811 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005812 ident = item;
5813
Radek Krejci018f1f52016-08-03 16:01:20 +02005814 rc = resolve_base_ident(mod, ident, expr, "identity", NULL, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005815 break;
5816 case UNRES_TYPE_IDENTREF:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005817 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01005818 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005819 stype = item;
5820
Radek Krejci018f1f52016-08-03 16:01:20 +02005821 rc = resolve_base_ident(mod, NULL, expr, "type", stype, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005822 break;
5823 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02005824 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005825 stype = item;
5826
Radek Krejci2f12f852016-01-08 12:59:57 +01005827 /* HACK - when there is no parent, we are in top level typedef and in that
5828 * case, the path has to contain absolute path, so we let the resolve_path_arg_schema()
5829 * know it via tpdf_flag */
5830 if (!node) {
Radek Krejci4f78b532016-02-17 13:43:00 +01005831 tpdf_flag = 1;
Radek Krejci2f12f852016-01-08 12:59:57 +01005832 node = (struct lys_node *)stype->parent;
5833 }
5834
Radek Krejci27fe55e2016-09-13 17:13:35 +02005835 if (!lys_node_module(node)->implemented) {
5836 /* not implemented module, don't bother with resolving the leafref
5837 * if the module is set to be implemented, tha path will be resolved then */
5838 rc = 0;
5839 break;
5840 }
Radek Krejci48464ed2016-03-17 15:44:09 +01005841 rc = resolve_path_arg_schema(stype->info.lref.path, node, tpdf_flag,
Michal Vasko1e62a092015-12-01 12:27:20 +01005842 (const struct lys_node **)&stype->info.lref.target);
Michal Vasko01c6fd22016-05-20 11:43:05 +02005843 if (!tpdf_flag && !rc) {
5844 assert(stype->info.lref.target);
Radek Krejcicbb473e2016-09-16 14:48:32 +02005845 /* check if leafref and its target are under a common if-features */
5846 rc = check_leafref_features(stype);
5847 if (rc) {
5848 break;
5849 }
5850
Radek Krejci46c4cd72016-01-21 15:13:52 +01005851 /* store the backlink from leafref target */
Michal Vasko01c6fd22016-05-20 11:43:05 +02005852 if (lys_leaf_add_leafref_target(stype->info.lref.target, (struct lys_node *)stype->parent)) {
5853 rc = -1;
Radek Krejci46c4cd72016-01-21 15:13:52 +01005854 }
Radek Krejci46c4cd72016-01-21 15:13:52 +01005855 }
5856
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005857 break;
Radek Krejci3a5501d2016-07-18 22:03:34 +02005858 case UNRES_TYPE_DER_TPDF:
5859 tpdf_flag = 1;
5860 /* no break */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005861 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01005862 /* parent */
5863 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005864 stype = item;
5865
Michal Vasko88c29542015-11-27 14:57:53 +01005866 /* HACK type->der is temporarily unparsed type statement */
5867 yin = (struct lyxml_elem *)stype->der;
5868 stype->der = NULL;
5869
Pavol Vicana0e4e672016-02-24 12:20:04 +01005870 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
5871 yang = (struct yang_type *)yin;
Radek Krejci3a5501d2016-07-18 22:03:34 +02005872 rc = yang_check_type(mod, node, yang, tpdf_flag, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01005873
5874 if (rc) {
Pavol Vican8bd72e42016-08-29 09:53:05 +02005875 /* may try again later */
5876 stype->der = (struct lys_tpdf *)yang;
Pavol Vicand01d8ae2016-03-01 10:45:59 +01005877 } else {
5878 /* we need to always be able to free this, it's safe only in this case */
Pavol Vican5f0316a2016-04-05 21:21:11 +02005879 lydict_remove(mod->ctx, yang->name);
Pavol Vicand01d8ae2016-03-01 10:45:59 +01005880 free(yang);
Pavol Vicana0e4e672016-02-24 12:20:04 +01005881 }
5882
Michal Vasko88c29542015-11-27 14:57:53 +01005883 } else {
Radek Krejci3a5501d2016-07-18 22:03:34 +02005884 rc = fill_yin_type(mod, node, yin, stype, tpdf_flag, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01005885 if (!rc) {
5886 /* we need to always be able to free this, it's safe only in this case */
5887 lyxml_free(mod->ctx, yin);
5888 } else {
5889 /* may try again later, put all back how it was */
5890 stype->der = (struct lys_tpdf *)yin;
5891 }
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005892 }
Radek Krejcic13db382016-08-16 10:52:42 +02005893 if (rc == EXIT_SUCCESS) {
Radek Krejci2c2fce82016-08-01 13:52:26 +02005894 /* it does not make sense to have leaf-list of empty type */
5895 if (!tpdf_flag && node->nodetype == LYS_LEAFLIST && stype->base == LY_TYPE_EMPTY) {
5896 LOGWRN("The leaf-list \"%s\" is of \"empty\" type, which does not make sense.", node->name);
5897 }
Radek Krejci9b6aad22016-09-20 15:55:51 +02005898 } else if (rc == EXIT_FAILURE && stype->base != LY_TYPE_ERR) {
Radek Krejcic13db382016-08-16 10:52:42 +02005899 /* forward reference - in case the type is in grouping, we have to make the grouping unusable
5900 * by uses statement until the type is resolved. We do that the same way as uses statements inside
5901 * grouping - the grouping's nacm member (not used un grouping) is used to increase the number of
5902 * so far unresolved items (uses and types). The grouping cannot be used unless the nacm value is 0.
Radek Krejci9b6aad22016-09-20 15:55:51 +02005903 * To remember that the grouping already increased grouping's nacm, the LY_TYPE_ERR is used as value
Radek Krejcic13db382016-08-16 10:52:42 +02005904 * of the type's base member. */
5905 for (par_grp = node; par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
5906 if (par_grp) {
5907 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci9b6aad22016-09-20 15:55:51 +02005908 stype->base = LY_TYPE_ERR;
Radek Krejcic13db382016-08-16 10:52:42 +02005909 }
Radek Krejci2c2fce82016-08-01 13:52:26 +02005910 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005911 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005912 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02005913 iff_data = str_snode;
5914 rc = resolve_feature(iff_data->fname, strlen(iff_data->fname), iff_data->node, item);
Radek Krejci9ff0a922016-07-14 13:08:05 +02005915 if (!rc) {
5916 /* success */
Radek Krejcicbb473e2016-09-16 14:48:32 +02005917 lydict_remove(mod->ctx, iff_data->fname);
5918 free(iff_data);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005919 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005920 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02005921 case UNRES_FEATURE:
5922 feat = (struct lys_feature *)item;
5923
5924 if (feat->iffeature_size) {
5925 refs = ly_set_new();
5926 procs = ly_set_new();
5927 ly_set_add(procs, feat, 0);
5928
5929 while (procs->number) {
5930 ref = procs->set.g[procs->number - 1];
5931 ly_set_rm_index(procs, procs->number - 1);
5932
5933 for (i = 0; i < ref->iffeature_size; i++) {
5934 resolve_iffeature_getsizes(&ref->iffeature[i], NULL, &j);
5935 for (; j > 0 ; j--) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02005936 if (ref->iffeature[i].features[j - 1]) {
Radek Krejcic79c6b12016-07-26 15:11:49 +02005937 if (ref->iffeature[i].features[j - 1] == feat) {
5938 LOGVAL(LYE_CIRC_FEATURES, LY_VLOG_NONE, NULL, feat->name);
5939 goto featurecheckdone;
5940 }
5941
5942 if (ref->iffeature[i].features[j - 1]->iffeature_size) {
5943 k = refs->number;
5944 if (ly_set_add(refs, ref->iffeature[i].features[j - 1], 0) == k) {
5945 /* not yet seen feature, add it for processing */
5946 ly_set_add(procs, ref->iffeature[i].features[j - 1], 0);
5947 }
5948 }
5949 } else {
5950 /* forward reference */
5951 rc = EXIT_FAILURE;
5952 goto featurecheckdone;
5953 }
5954 }
5955
5956 }
5957 }
5958 rc = EXIT_SUCCESS;
5959
5960featurecheckdone:
5961 ly_set_free(refs);
5962 ly_set_free(procs);
5963 }
5964
5965 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005966 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01005967 rc = resolve_unres_schema_uses(item, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005968 break;
5969 case UNRES_TYPE_DFLT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005970 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01005971 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005972 stype = item;
5973
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005974 rc = check_default(stype, expr, mod);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005975 break;
5976 case UNRES_CHOICE_DFLT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005977 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01005978 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005979 choic = item;
5980
Radek Krejcie00d2312016-08-12 15:27:49 +02005981 if (!choic->dflt) {
5982 choic->dflt = resolve_choice_dflt(choic, expr);
5983 }
Michal Vasko7955b362015-09-04 14:18:15 +02005984 if (choic->dflt) {
Radek Krejcie00d2312016-08-12 15:27:49 +02005985 rc = lyp_check_mandatory_choice((struct lys_node *)choic);
Michal Vasko7955b362015-09-04 14:18:15 +02005986 } else {
5987 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005988 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005989 break;
5990 case UNRES_LIST_KEYS:
Radek Krejci4f78b532016-02-17 13:43:00 +01005991 has_str = 1;
Radek Krejci48464ed2016-03-17 15:44:09 +01005992 rc = resolve_list_keys(item, str_snode);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005993 break;
5994 case UNRES_LIST_UNIQ:
Radek Krejcid09d1a52016-08-11 14:05:45 +02005995 unique_info = (struct unres_list_uniq *)item;
5996 rc = resolve_unique(unique_info->list, unique_info->expr, unique_info->trg_type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005997 break;
Michal Vasko7178e692016-02-12 15:58:05 +01005998 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01005999 rc = resolve_augment(item, NULL);
Michal Vasko7178e692016-02-12 15:58:05 +01006000 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006001 case UNRES_XPATH:
6002 node = (struct lys_node *)item;
6003 rc = check_xpath(node);
6004 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006005 default:
6006 LOGINT;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006007 break;
6008 }
6009
Radek Krejci54081ce2016-08-12 15:21:47 +02006010 if (has_str && !rc) {
6011 /* the string is no more needed in case of success.
6012 * In case of forward reference, we will try to resolve the string later */
Radek Krejci4f78b532016-02-17 13:43:00 +01006013 lydict_remove(mod->ctx, str_snode);
6014 }
6015
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006016 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006017}
6018
Michal Vaskof02e3742015-08-05 16:27:02 +02006019/* logs directly */
6020static void
Radek Krejci48464ed2016-03-17 15:44:09 +01006021print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006022{
Michal Vaskocb34dc62016-05-20 14:38:37 +02006023 struct lyxml_elem *xml;
6024 struct lyxml_attr *attr;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006025 struct unres_iffeat_data *iff_data;
Radek Krejci76e15e12016-06-22 11:02:24 +02006026 const char *type_name = NULL;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006027
Michal Vaskof02e3742015-08-05 16:27:02 +02006028 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02006029 case UNRES_IDENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006030 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identity", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006031 break;
6032 case UNRES_TYPE_IDENTREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006033 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identityref", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006034 break;
6035 case UNRES_TYPE_LEAFREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006036 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "leafref",
6037 ((struct lys_type *)item)->info.lref.path);
Michal Vaskof02e3742015-08-05 16:27:02 +02006038 break;
Radek Krejci3a5501d2016-07-18 22:03:34 +02006039 case UNRES_TYPE_DER_TPDF:
Michal Vaskof02e3742015-08-05 16:27:02 +02006040 case UNRES_TYPE_DER:
Michal Vaskocb34dc62016-05-20 14:38:37 +02006041 xml = (struct lyxml_elem *)((struct lys_type *)item)->der;
6042 if (xml->flags & LY_YANG_STRUCTURE_FLAG) {
6043 type_name = ((struct yang_type *)xml)->name;
6044 } else {
6045 LY_TREE_FOR(xml->attr, attr) {
6046 if ((attr->type == LYXML_ATTR_STD) && !strcmp(attr->name, "name")) {
6047 type_name = attr->value;
6048 break;
6049 }
6050 }
6051 assert(attr);
6052 }
6053 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "derived type", type_name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006054 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006055 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006056 iff_data = str_node;
6057 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "if-feature", iff_data->fname);
Michal Vaskof02e3742015-08-05 16:27:02 +02006058 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006059 case UNRES_FEATURE:
6060 LOGVRB("There are unresolved if-features for \"%s\" feature circular dependency check, it will be attempted later",
6061 ((struct lys_feature *)item)->name);
6062 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006063 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006064 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "uses", ((struct lys_node_uses *)item)->name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006065 break;
6066 case UNRES_TYPE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006067 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "type default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006068 break;
6069 case UNRES_CHOICE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006070 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "choice default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006071 break;
6072 case UNRES_LIST_KEYS:
Radek Krejci48464ed2016-03-17 15:44:09 +01006073 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list keys", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006074 break;
6075 case UNRES_LIST_UNIQ:
Radek Krejci48464ed2016-03-17 15:44:09 +01006076 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list unique", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006077 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006078 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006079 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "augment target",
6080 ((struct lys_node_augment *)item)->target_name);
Michal Vasko7178e692016-02-12 15:58:05 +01006081 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006082 case UNRES_XPATH:
6083 LOGVRB("Resolving %s \"%s\" with the context node \"%s\" failed, it will be attempted later.", "XPath",
6084 (char *)str_node, ((struct lys_node *)item)->name);
6085 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006086 default:
6087 LOGINT;
Michal Vaskof02e3742015-08-05 16:27:02 +02006088 break;
6089 }
6090}
6091
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006092/**
Michal Vaskobb211122015-08-19 14:03:11 +02006093 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006094 *
6095 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006096 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006097 *
Michal Vasko92b8a382015-08-19 14:03:49 +02006098 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006099 */
Michal Vaskof02e3742015-08-05 16:27:02 +02006100int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006101resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02006102{
Radek Krejci010e54b2016-03-15 09:40:34 +01006103 uint32_t i, resolved = 0, unres_count, res_count;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006104 int rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006105
6106 assert(unres);
6107
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02006108 LOGVRB("Resolving unresolved schema nodes and their constraints...");
Radek Krejci010e54b2016-03-15 09:40:34 +01006109 ly_vlog_hide(1);
Michal Vasko51054ca2015-08-12 12:20:00 +02006110
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006111 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02006112 do {
Michal Vasko88c29542015-11-27 14:57:53 +01006113 unres_count = 0;
6114 res_count = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02006115
6116 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006117 /* UNRES_TYPE_LEAFREF must be resolved (for storing leafref target pointers);
Radek Krejcic79c6b12016-07-26 15:11:49 +02006118 * if-features are resolved here to make sure that we will have all if-features for
6119 * later check of feature circular dependency */
Radek Krejci018f1f52016-08-03 16:01:20 +02006120 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006121 continue;
6122 }
Radek Krejci018f1f52016-08-03 16:01:20 +02006123 /* processes UNRES_USES, UNRES_IFFEAT, UNRES_TYPE_DER, UNRES_TYPE_DER_TPDF, UNRES_TYPE_LEAFREF,
Radek Krejcie00d2312016-08-12 15:27:49 +02006124 * UNRES_CHOICE_DFLT and UNRES_IDENT */
Michal Vasko51054ca2015-08-12 12:20:00 +02006125
Michal Vasko88c29542015-11-27 14:57:53 +01006126 ++unres_count;
Radek Krejci48464ed2016-03-17 15:44:09 +01006127 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006128 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006129 unres->type[i] = UNRES_RESOLVED;
6130 ++resolved;
Michal Vasko88c29542015-11-27 14:57:53 +01006131 ++res_count;
Michal Vasko89e15322015-08-17 15:46:55 +02006132 } else if (rc == -1) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006133 ly_vlog_hide(0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02006134 /* print the error */
6135 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006136 return -1;
Radek Krejcic2a180f2016-06-22 13:28:16 +02006137 } else {
6138 /* forward reference, erase ly_errno */
6139 ly_errno = LY_SUCCESS;
6140 ly_vecode = LYVE_SUCCESS;
Michal Vasko51054ca2015-08-12 12:20:00 +02006141 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006142 }
Michal Vasko88c29542015-11-27 14:57:53 +01006143 } while (res_count && (res_count < unres_count));
Michal Vasko51054ca2015-08-12 12:20:00 +02006144
Michal Vasko88c29542015-11-27 14:57:53 +01006145 if (res_count < unres_count) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006146 /* just print the errors */
6147 ly_vlog_hide(0);
6148
6149 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006150 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006151 continue;
6152 }
6153 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
6154 }
Michal Vasko92b8a382015-08-19 14:03:49 +02006155 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006156 }
6157
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006158 /* the rest */
6159 for (i = 0; i < unres->count; ++i) {
6160 if (unres->type[i] == UNRES_RESOLVED) {
6161 continue;
6162 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02006163
Radek Krejci48464ed2016-03-17 15:44:09 +01006164 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01006165 if (rc == 0) {
Pavol Vican88e16c92016-09-07 15:41:50 +02006166 if (unres->type[i] == UNRES_LIST_UNIQ) {
6167 /* free the allocated structure */
6168 free(unres->item[i]);
6169 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006170 unres->type[i] = UNRES_RESOLVED;
6171 ++resolved;
6172 } else if (rc == -1) {
6173 ly_vlog_hide(0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02006174 /* print the error */
6175 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
6176 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006177 }
6178 }
6179
Radek Krejci010e54b2016-03-15 09:40:34 +01006180 ly_vlog_hide(0);
6181
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006182 if (resolved < unres->count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006183 /* try to resolve the unresolved nodes again, it will not resolve anything, but it will print
6184 * all the validation errors
6185 */
6186 for (i = 0; i < unres->count; ++i) {
6187 if (unres->type[i] == UNRES_RESOLVED) {
6188 continue;
6189 }
Radek Krejci48464ed2016-03-17 15:44:09 +01006190 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01006191 }
Michal Vasko92b8a382015-08-19 14:03:49 +02006192 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006193 }
6194
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02006195 LOGVRB("All schema nodes and constraints resolved.");
Radek Krejcic071c542016-01-27 14:57:51 +01006196 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006197 return EXIT_SUCCESS;
6198}
6199
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006200/**
Michal Vaskobb211122015-08-19 14:03:11 +02006201 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006202 *
6203 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006204 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006205 * @param[in] item Item to resolve. Type determined by \p type.
6206 * @param[in] type Type of the unresolved item.
6207 * @param[in] str String argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006208 *
Michal Vasko3767fb22016-07-21 12:10:57 +02006209 * @return EXIT_SUCCESS on success, EXIT_FAILURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006210 */
6211int
Radek Krejci48464ed2016-03-17 15:44:09 +01006212unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
6213 const char *str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006214{
Radek Krejci54081ce2016-08-12 15:21:47 +02006215 int rc;
6216 const char *dictstr;
6217
6218 dictstr = lydict_insert(mod->ctx, str, 0);
6219 rc = unres_schema_add_node(mod, unres, item, type, (struct lys_node *)dictstr);
6220
6221 if (rc == -1) {
6222 lydict_remove(mod->ctx, dictstr);
6223 }
6224 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006225}
6226
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006227/**
Michal Vaskobb211122015-08-19 14:03:11 +02006228 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006229 *
6230 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006231 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006232 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01006233 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006234 * @param[in] snode Schema node argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006235 *
Michal Vasko3767fb22016-07-21 12:10:57 +02006236 * @return EXIT_SUCCESS on success, EXIT_FIALURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006237 */
6238int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006239unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Radek Krejci48464ed2016-03-17 15:44:09 +01006240 struct lys_node *snode)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006241{
Michal Vaskoef486d72016-09-27 12:10:44 +02006242 int rc, log_hidden;
Michal Vasko88c29542015-11-27 14:57:53 +01006243 struct lyxml_elem *yin;
Radek Krejci010e54b2016-03-15 09:40:34 +01006244 char *path, *msg;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006245
Michal Vasko9bf425b2015-10-22 11:42:03 +02006246 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
6247 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006248
Michal Vaskoef486d72016-09-27 12:10:44 +02006249 if (*ly_vlog_hide_location()) {
6250 log_hidden = 1;
6251 } else {
6252 log_hidden = 0;
6253 ly_vlog_hide(1);
6254 }
Radek Krejci48464ed2016-03-17 15:44:09 +01006255 rc = resolve_unres_schema_item(mod, item, type, snode, unres);
Michal Vaskoef486d72016-09-27 12:10:44 +02006256 if (!log_hidden) {
6257 ly_vlog_hide(0);
6258 }
6259
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006260 if (rc != EXIT_FAILURE) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006261 if (rc == -1 && ly_errno == LY_EVALID) {
Radek Krejci76e15e12016-06-22 11:02:24 +02006262 if (ly_log_level >= LY_LLERR) {
6263 path = strdup(ly_errpath());
6264 msg = strdup(ly_errmsg());
6265 LOGERR(LY_EVALID, "%s%s%s%s", msg, path[0] ? " (path: " : "", path[0] ? path : "", path[0] ? ")" : "");
6266 free(path);
6267 free(msg);
6268 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006269 }
Radek Krejcid09d1a52016-08-11 14:05:45 +02006270 if (type == UNRES_LIST_UNIQ) {
6271 /* free the allocated structure */
6272 free(item);
Pavol Vican88e16c92016-09-07 15:41:50 +02006273 } else if (rc == -1 && type == UNRES_IFFEAT) {
6274 /* free the allocated resources */
6275 free(*((char **)item));
6276 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006277 return rc;
Radek Krejcif347abc2016-06-22 10:18:47 +02006278 } else {
6279 /* erase info about validation errors */
6280 ly_errno = LY_SUCCESS;
6281 ly_vecode = LYVE_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006282 }
6283
Radek Krejci48464ed2016-03-17 15:44:09 +01006284 print_unres_schema_item_fail(item, type, snode);
Michal Vaskof02e3742015-08-05 16:27:02 +02006285
Michal Vasko88c29542015-11-27 14:57:53 +01006286 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
Radek Krejci3a5501d2016-07-18 22:03:34 +02006287 if (type == UNRES_TYPE_DER || type == UNRES_TYPE_DER_TPDF) {
Michal Vasko88c29542015-11-27 14:57:53 +01006288 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
Pavol Vicana0e4e672016-02-24 12:20:04 +01006289 if (!(yin->flags & LY_YANG_STRUCTURE_FLAG)) {
6290 lyxml_unlink_elem(mod->ctx, yin, 1);
6291 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
6292 }
Michal Vasko88c29542015-11-27 14:57:53 +01006293 }
6294
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006295 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01006296 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
6297 if (!unres->item) {
6298 LOGMEM;
6299 return -1;
6300 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006301 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01006302 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
6303 if (!unres->type) {
6304 LOGMEM;
6305 return -1;
6306 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006307 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01006308 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
6309 if (!unres->str_snode) {
6310 LOGMEM;
6311 return -1;
6312 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006313 unres->str_snode[unres->count-1] = snode;
Radek Krejcic071c542016-01-27 14:57:51 +01006314 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
6315 if (!unres->module) {
6316 LOGMEM;
6317 return -1;
6318 }
6319 unres->module[unres->count-1] = mod;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006320
Michal Vasko3767fb22016-07-21 12:10:57 +02006321 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006322}
6323
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006324/**
Michal Vaskobb211122015-08-19 14:03:11 +02006325 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006326 *
6327 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006328 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006329 * @param[in] item Old item to be resolved.
6330 * @param[in] type Type of the old unresolved item.
6331 * @param[in] new_item New item to use in the duplicate.
6332 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02006333 * @return EXIT_SUCCESS on success, EXIT_FAILURE if item is not in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006334 */
Michal Vaskodad19402015-08-06 09:51:53 +02006335int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006336unres_schema_dup(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type, void *new_item)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006337{
6338 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006339 struct unres_list_uniq aux_uniq;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006340 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006341
Michal Vaskocf024702015-10-08 15:01:42 +02006342 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006343
Radek Krejcid09d1a52016-08-11 14:05:45 +02006344 /* hack for UNRES_LIST_UNIQ, which stores multiple items behind its item */
6345 if (type == UNRES_LIST_UNIQ) {
6346 aux_uniq.list = item;
6347 aux_uniq.expr = ((struct unres_list_uniq *)new_item)->expr;
6348 item = &aux_uniq;
6349 }
Michal Vasko878e38d2016-09-05 12:17:53 +02006350 i = unres_schema_find(unres, -1, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006351
6352 if (i == -1) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006353 if (type == UNRES_LIST_UNIQ) {
6354 free(new_item);
6355 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02006356 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006357 }
6358
Radek Krejcic79c6b12016-07-26 15:11:49 +02006359 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT) ||
Radek Krejcib69f3232016-09-16 17:41:07 +02006360 (type == UNRES_FEATURE) || (type == UNRES_LIST_UNIQ)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01006361 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006362 LOGINT;
6363 return -1;
6364 }
Radek Krejcicbb473e2016-09-16 14:48:32 +02006365 } else if (type == UNRES_IFFEAT) {
6366 /* duplicate unres_iffeature_data */
6367 iff_data = malloc(sizeof *iff_data);
6368 iff_data->fname = lydict_insert(mod->ctx, ((struct unres_iffeat_data *)unres->str_snode[i])->fname, 0);
6369 iff_data->node = ((struct unres_iffeat_data *)unres->str_snode[i])->node;
6370 if (unres_schema_add_node(mod, unres, new_item, type, (struct lys_node *)iff_data) == -1) {
6371 LOGINT;
6372 return -1;
6373 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006374 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01006375 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006376 LOGINT;
6377 return -1;
6378 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006379 }
Michal Vaskodad19402015-08-06 09:51:53 +02006380
6381 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006382}
6383
Michal Vaskof02e3742015-08-05 16:27:02 +02006384/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006385int
Michal Vasko878e38d2016-09-05 12:17:53 +02006386unres_schema_find(struct unres_schema *unres, int start_on_backwards, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006387{
Michal Vasko878e38d2016-09-05 12:17:53 +02006388 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006389 struct unres_list_uniq *aux_uniq1, *aux_uniq2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006390
Michal Vasko878e38d2016-09-05 12:17:53 +02006391 if (start_on_backwards > 0) {
6392 i = start_on_backwards;
6393 } else {
6394 i = unres->count - 1;
6395 }
6396 for (; i > -1; i--) {
6397 if (unres->type[i] != type) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006398 continue;
6399 }
6400 if (type != UNRES_LIST_UNIQ) {
Michal Vasko878e38d2016-09-05 12:17:53 +02006401 if (unres->item[i] == item) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006402 break;
6403 }
6404 } else {
6405 aux_uniq1 = (struct unres_list_uniq *)unres->item[i - 1];
6406 aux_uniq2 = (struct unres_list_uniq *)item;
6407 if ((aux_uniq1->list == aux_uniq2->list) && ly_strequal(aux_uniq1->expr, aux_uniq2->expr, 0)) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006408 break;
6409 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006410 }
6411 }
6412
Michal Vasko878e38d2016-09-05 12:17:53 +02006413 return i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006414}
Michal Vasko8bcdf292015-08-19 14:04:43 +02006415
Michal Vaskoede9c472016-06-07 09:38:15 +02006416static void
6417unres_schema_free_item(struct ly_ctx *ctx, struct unres_schema *unres, uint32_t i)
6418{
6419 struct lyxml_elem *yin;
6420 struct yang_type *yang;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006421 struct unres_iffeat_data *iff_data;
Michal Vaskoede9c472016-06-07 09:38:15 +02006422
6423 switch (unres->type[i]) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02006424 case UNRES_TYPE_DER_TPDF:
Michal Vaskoede9c472016-06-07 09:38:15 +02006425 case UNRES_TYPE_DER:
6426 yin = (struct lyxml_elem *)((struct lys_type *)unres->item[i])->der;
6427 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6428 yang =(struct yang_type *)yin;
6429 yang->type->base = yang->base;
6430 lydict_remove(ctx, yang->name);
6431 free(yang);
6432 } else {
6433 lyxml_free(ctx, yin);
6434 }
6435 break;
Pavol Vican88e16c92016-09-07 15:41:50 +02006436 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006437 iff_data = (struct unres_iffeat_data *)unres->str_snode[i];
6438 lydict_remove(ctx, iff_data->fname);
6439 free(unres->str_snode[i]);
Pavol Vican88e16c92016-09-07 15:41:50 +02006440 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02006441 case UNRES_IDENT:
6442 case UNRES_TYPE_IDENTREF:
Michal Vaskoede9c472016-06-07 09:38:15 +02006443 case UNRES_TYPE_DFLT:
6444 case UNRES_CHOICE_DFLT:
6445 case UNRES_LIST_KEYS:
Michal Vaskoede9c472016-06-07 09:38:15 +02006446 lydict_remove(ctx, (const char *)unres->str_snode[i]);
6447 break;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006448 case UNRES_LIST_UNIQ:
6449 free(unres->item[i]);
6450 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02006451 default:
6452 break;
6453 }
6454 unres->type[i] = UNRES_RESOLVED;
6455}
6456
Michal Vasko88c29542015-11-27 14:57:53 +01006457void
Radek Krejcic071c542016-01-27 14:57:51 +01006458unres_schema_free(struct lys_module *module, struct unres_schema **unres)
Michal Vasko88c29542015-11-27 14:57:53 +01006459{
6460 uint32_t i;
Radek Krejcic071c542016-01-27 14:57:51 +01006461 unsigned int unresolved = 0;
Michal Vasko88c29542015-11-27 14:57:53 +01006462
Radek Krejcic071c542016-01-27 14:57:51 +01006463 if (!unres || !(*unres)) {
6464 return;
Michal Vasko88c29542015-11-27 14:57:53 +01006465 }
6466
Radek Krejcic071c542016-01-27 14:57:51 +01006467 assert(module || (*unres)->count == 0);
6468
6469 for (i = 0; i < (*unres)->count; ++i) {
6470 if ((*unres)->module[i] != module) {
6471 if ((*unres)->type[i] != UNRES_RESOLVED) {
6472 unresolved++;
6473 }
6474 continue;
6475 }
Michal Vaskoede9c472016-06-07 09:38:15 +02006476
6477 /* free heap memory for the specific item */
6478 unres_schema_free_item(module->ctx, *unres, i);
Radek Krejcic071c542016-01-27 14:57:51 +01006479 }
6480
Michal Vaskoede9c472016-06-07 09:38:15 +02006481 /* free it all */
Radek Krejcic071c542016-01-27 14:57:51 +01006482 if (!module || (!unresolved && !module->type)) {
6483 free((*unres)->item);
6484 free((*unres)->type);
6485 free((*unres)->str_snode);
6486 free((*unres)->module);
Radek Krejcic071c542016-01-27 14:57:51 +01006487 free((*unres));
6488 (*unres) = NULL;
6489 }
Michal Vasko88c29542015-11-27 14:57:53 +01006490}
6491
Radek Krejci9b6aad22016-09-20 15:55:51 +02006492static int resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type);
6493
Radek Krejci7de36cf2016-09-12 16:18:50 +02006494static int
Radek Krejci9b6aad22016-09-20 15:55:51 +02006495resolve_leafref(struct lyd_node_leaf_list *leaf, struct lys_type *type)
Radek Krejci7de36cf2016-09-12 16:18:50 +02006496{
Radek Krejci7de36cf2016-09-12 16:18:50 +02006497 struct unres_data matches;
6498 uint32_t i;
6499
Radek Krejci9b6aad22016-09-20 15:55:51 +02006500 assert(type->base == LY_TYPE_LEAFREF);
6501
6502 /* init */
Radek Krejci7de36cf2016-09-12 16:18:50 +02006503 memset(&matches, 0, sizeof matches);
Radek Krejci7de36cf2016-09-12 16:18:50 +02006504
6505 /* EXIT_FAILURE return keeps leaf->value.lefref NULL, handled later */
Radek Krejci9b6aad22016-09-20 15:55:51 +02006506 if (resolve_path_arg_data((struct lyd_node *)leaf, type->info.lref.path, &matches) == -1) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02006507 return -1;
6508 }
6509
6510 /* check that value matches */
6511 for (i = 0; i < matches.count; ++i) {
6512 if (ly_strequal(leaf->value_str, ((struct lyd_node_leaf_list *)matches.node[i])->value_str, 1)) {
6513 leaf->value.leafref = matches.node[i];
6514 break;
6515 }
6516 }
6517
6518 free(matches.node);
6519
6520 if (!leaf->value.leafref) {
6521 /* reference not found */
6522 if (type->info.lref.req > -1) {
6523 LOGVAL(LYE_NOLEAFREF, LY_VLOG_LYD, leaf, type->info.lref.path, leaf->value_str);
6524 return EXIT_FAILURE;
6525 } else {
6526 LOGVRB("There is no leafref with the value \"%s\", but it is not required.", leaf->value_str);
6527 }
6528 }
6529
6530 return EXIT_SUCCESS;
6531}
6532
Radek Krejci9b6aad22016-09-20 15:55:51 +02006533API LY_DATA_TYPE
6534lyd_leaf_type(const struct lyd_node_leaf_list *leaf)
6535{
6536 struct lyd_node *node;
6537 struct lys_type *type, *type_iter;
6538 lyd_val value;
6539 int f = 0, r;
6540
6541 if (!leaf || !(leaf->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
6542 return LY_TYPE_ERR;
6543 }
6544
6545 if (leaf->value_type > 0 && (leaf->value_type & LY_DATA_TYPE_MASK) != LY_TYPE_UNION &&
6546 (leaf->value_type & LY_DATA_TYPE_MASK) != LY_TYPE_LEAFREF) {
6547 /* we can get the type directly from the data node (it was already resolved) */
6548 return leaf->value_type & LY_DATA_TYPE_MASK;
6549 }
6550
6551 /* init */
6552 type = &((struct lys_node_leaf *)leaf->schema)->type;
6553 value = leaf->value;
6554 ly_vlog_hide(1);
6555
6556 /* resolve until we get the real data type */
6557 while (1) {
6558 /* get the correct data type from schema */
6559 switch (type->base) {
6560 case LY_TYPE_LEAFREF:
6561 type = &type->info.lref.target->type;
6562 break; /* continue in while loop */
6563 case LY_TYPE_UNION:
6564 type_iter = NULL;
6565 while ((type_iter = lyp_get_next_union_type(type, type_iter, &f))) {
6566 if (type_iter->base == LY_TYPE_LEAFREF) {
6567 if (type_iter->info.lref.req == -1) {
6568 /* target not required, so it always succeeds */
6569 break;
6570 } else {
6571 /* try to resolve leafref */
6572 memset(&((struct lyd_node_leaf_list *)leaf)->value, 0, sizeof leaf->value);
6573 r = resolve_leafref((struct lyd_node_leaf_list *)leaf, type_iter);
6574 /* revert leaf's content affected by resolve_leafref */
6575 ((struct lyd_node_leaf_list *)leaf)->value = value;
6576 if (!r) {
6577 /* success, we can continue with the leafref type */
6578 break;
6579 }
6580 }
6581 } else if (type_iter->base == LY_TYPE_INST) {
6582 if (type_iter->info.inst.req == -1) {
6583 /* target not required, so it always succeeds */
6584 return LY_TYPE_INST;
6585 } else {
6586 /* try to resolve instance-identifier */
6587 ly_errno = 0;
6588 node = resolve_instid((struct lyd_node *)leaf, leaf->value_str);
6589 if (!ly_errno && node) {
6590 /* the real type is instance-identifier */
6591 return LY_TYPE_INST;
6592 }
6593 }
6594 } else {
6595 r = lyp_parse_value_type((struct lyd_node_leaf_list *)leaf, type_iter, 1);
6596 /* revert leaf's content affected by resolve_leafref */
6597 ((struct lyd_node_leaf_list *)leaf)->value = value;
6598 if (!r) {
6599 /* we have the real type */
6600 return type_iter->base;
6601 }
6602 }
6603 f = 0;
6604 }
6605 /* erase ly_errno and ly_vecode */
6606 ly_errno = LY_SUCCESS;
6607 ly_vecode = LYVE_SUCCESS;
6608
6609 if (!type_iter) {
6610 LOGERR(LY_EINVAL, "Unable to get type from union \"%s\" with no valid type.", type->parent->name)
6611 return LY_TYPE_ERR;
6612 }
6613 type = type_iter;
6614 break;
6615 default:
6616 /* we have the real type */
6617 ly_vlog_hide(0);
6618 return type->base;
6619 }
6620 }
6621
6622 ly_vlog_hide(0);
6623 return LY_TYPE_ERR;
6624}
6625
6626static int
6627resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type)
6628{
6629 struct lys_type *datatype = NULL;
6630 int f = 0;
6631
6632 assert(type->base == LY_TYPE_UNION);
6633
6634 memset(&leaf->value, 0, sizeof leaf->value);
6635 while ((datatype = lyp_get_next_union_type(type, datatype, &f))) {
6636 leaf->value_type = datatype->base;
6637
6638 if (datatype->base == LY_TYPE_LEAFREF) {
6639 /* try to resolve leafref */
6640 if (!resolve_leafref(leaf, datatype)) {
6641 /* success */
6642 break;
6643 }
6644 } else if (datatype->base == LY_TYPE_INST) {
6645 /* try to resolve instance-identifier */
6646 ly_errno = 0;
6647 leaf->value.instance = resolve_instid((struct lyd_node *)leaf, leaf->value_str);
6648 if (!ly_errno && (leaf->value.instance || datatype->info.inst.req == -1)) {
6649 /* success */
6650 break;
6651 }
6652 } else {
6653 if (!lyp_parse_value_type(leaf, datatype, 1)) {
6654 /* success */
6655 break;
6656 }
6657 }
6658 f = 0;
6659 }
6660 /* erase ly_errno and ly_vecode */
6661 ly_errno = LY_SUCCESS;
6662 ly_vecode = LYVE_SUCCESS;
6663
6664 if (!datatype) {
6665 /* failure */
6666 LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, (leaf->value_str ? leaf->value_str : ""), leaf->schema->name);
6667 return EXIT_FAILURE;
6668 }
6669
6670 return EXIT_SUCCESS;
6671}
6672
Michal Vasko8bcdf292015-08-19 14:04:43 +02006673/**
6674 * @brief Resolve a single unres data item. Logs directly.
6675 *
Michal Vaskocf024702015-10-08 15:01:42 +02006676 * @param[in] node Data node to resolve.
Michal Vaskocf024702015-10-08 15:01:42 +02006677 * @param[in] type Type of the unresolved item.
Michal Vasko8bcdf292015-08-19 14:04:43 +02006678 *
6679 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
6680 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02006681int
Radek Krejci48464ed2016-03-17 15:44:09 +01006682resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02006683{
Michal Vasko0491ab32015-08-19 14:28:29 +02006684 int rc;
Michal Vasko83a6c462015-10-08 16:43:53 +02006685 struct lyd_node_leaf_list *leaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006686 struct lys_node_leaf *sleaf;
Michal Vaskoc4280842016-04-19 16:10:42 +02006687 struct lyd_node *parent;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006688
Michal Vasko83a6c462015-10-08 16:43:53 +02006689 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02006690 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006691
Michal Vaskocf024702015-10-08 15:01:42 +02006692 switch (type) {
6693 case UNRES_LEAFREF:
6694 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Radek Krejci9b6aad22016-09-20 15:55:51 +02006695 return resolve_leafref(leaf, &sleaf->type);
Michal Vasko8bcdf292015-08-19 14:04:43 +02006696
Michal Vaskocf024702015-10-08 15:01:42 +02006697 case UNRES_INSTID:
Radek Krejci7de36cf2016-09-12 16:18:50 +02006698 assert(sleaf->type.base == LY_TYPE_INST);
Michal Vasko8bcdf292015-08-19 14:04:43 +02006699 ly_errno = 0;
Radek Krejci48464ed2016-03-17 15:44:09 +01006700 leaf->value.instance = resolve_instid(node, leaf->value_str);
Radek Krejci40f17b92016-02-03 14:30:43 +01006701 if (!leaf->value.instance) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02006702 if (ly_errno) {
6703 return -1;
6704 } else if (sleaf->type.info.inst.req > -1) {
Michal Vasko6ac68282016-04-11 10:56:47 +02006705 LOGVAL(LYE_NOREQINS, LY_VLOG_LYD, leaf, leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02006706 return EXIT_FAILURE;
6707 } else {
Michal Vasko9925e282016-09-02 12:45:14 +02006708 LOGVRB("There is no instance identifier \"%s\", but it is not required.", leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02006709 }
6710 }
Michal Vaskocf024702015-10-08 15:01:42 +02006711 break;
6712
Radek Krejci7de36cf2016-09-12 16:18:50 +02006713 case UNRES_UNION:
6714 assert(sleaf->type.base == LY_TYPE_UNION);
Radek Krejci9b6aad22016-09-20 15:55:51 +02006715 return resolve_union(leaf, &sleaf->type);
Radek Krejci7de36cf2016-09-12 16:18:50 +02006716
Michal Vaskocf024702015-10-08 15:01:42 +02006717 case UNRES_WHEN:
Radek Krejci46165822016-08-26 14:06:27 +02006718 if ((rc = resolve_when(node, NULL))) {
Michal Vaskocf024702015-10-08 15:01:42 +02006719 return rc;
6720 }
6721 break;
6722
Michal Vaskobf19d252015-10-08 15:39:17 +02006723 case UNRES_MUST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006724 if ((rc = resolve_must(node, 0))) {
6725 return rc;
6726 }
6727 break;
6728
6729 case UNRES_MUST_INOUT:
6730 if ((rc = resolve_must(node, 1))) {
Michal Vaskobf19d252015-10-08 15:39:17 +02006731 return rc;
6732 }
6733 break;
6734
Michal Vaskoc4280842016-04-19 16:10:42 +02006735 case UNRES_EMPTYCONT:
6736 do {
6737 parent = node->parent;
6738 lyd_free(node);
6739 node = parent;
6740 } while (node && (node->schema->nodetype == LYS_CONTAINER) && !node->child
6741 && !((struct lys_node_container *)node->schema)->presence);
6742 break;
6743
Michal Vaskocf024702015-10-08 15:01:42 +02006744 default:
Michal Vasko8bcdf292015-08-19 14:04:43 +02006745 LOGINT;
6746 return -1;
6747 }
6748
6749 return EXIT_SUCCESS;
6750}
6751
6752/**
Radek Krejci0b7704f2016-03-18 12:16:14 +01006753 * @brief add data unres item
Michal Vasko8bcdf292015-08-19 14:04:43 +02006754 *
6755 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02006756 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02006757 *
Radek Krejci0b7704f2016-03-18 12:16:14 +01006758 * @return 0 on success, -1 on error.
Michal Vasko8bcdf292015-08-19 14:04:43 +02006759 */
6760int
Radek Krejci0b7704f2016-03-18 12:16:14 +01006761unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02006762{
Radek Krejci03b71f72016-03-16 11:10:09 +01006763 assert(unres && node);
Michal Vaskoc4280842016-04-19 16:10:42 +02006764 assert((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006765 || (type == UNRES_MUST_INOUT) || (type == UNRES_UNION) || (type == UNRES_EMPTYCONT));
Michal Vasko8bcdf292015-08-19 14:04:43 +02006766
Radek Krejci03b71f72016-03-16 11:10:09 +01006767 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01006768 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
6769 if (!unres->node) {
6770 LOGMEM;
6771 return -1;
6772 }
Michal Vaskocf024702015-10-08 15:01:42 +02006773 unres->node[unres->count - 1] = node;
Michal Vasko253035f2015-12-17 16:58:13 +01006774 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
6775 if (!unres->type) {
6776 LOGMEM;
6777 return -1;
6778 }
Michal Vaskocf024702015-10-08 15:01:42 +02006779 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006780
Radek Krejci0b7704f2016-03-18 12:16:14 +01006781 if (type == UNRES_WHEN) {
6782 /* remove previous result */
6783 node->when_status = LYD_WHEN;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006784 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006785
6786 return EXIT_SUCCESS;
6787}
6788
6789/**
6790 * @brief Resolve every unres data item in the structure. Logs directly.
6791 *
6792 * @param[in] unres Unres data structure to use.
Radek Krejci03b71f72016-03-16 11:10:09 +01006793 * @param[in,out] root Root node of the data tree. If not NULL, auto-delete is performed on false when condition. If
6794 * NULL and when condition is false the error is raised.
Michal Vasko6df94132016-09-22 11:08:09 +02006795 * @param[in] trusted Whether the data are considered trusted (when, must conditions are not expected, unresolved
6796 * leafrefs/instids are accepted).
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006797 *
6798 * @return EXIT_SUCCESS on success, -1 on error.
6799 */
6800int
Michal Vasko6df94132016-09-22 11:08:09 +02006801resolve_unres_data(struct unres_data *unres, struct lyd_node **root, int trusted)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006802{
Radek Krejci0c0086a2016-03-24 15:20:28 +01006803 uint32_t i, j, first = 1, resolved = 0, del_items = 0, when_stmt = 0;
Radek Krejci010e54b2016-03-15 09:40:34 +01006804 int rc, progress;
Radek Krejci03b71f72016-03-16 11:10:09 +01006805 char *msg, *path;
Radek Krejci0b7704f2016-03-18 12:16:14 +01006806 struct lyd_node *parent;
Radek Krejci7de36cf2016-09-12 16:18:50 +02006807 struct lyd_node_leaf_list *leaf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006808
Radek Krejci03b71f72016-03-16 11:10:09 +01006809 assert(unres);
Radek Krejci03b71f72016-03-16 11:10:09 +01006810
6811 if (!unres->count) {
6812 return EXIT_SUCCESS;
6813 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006814
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02006815 LOGVRB("Resolving unresolved data nodes and their constraints...");
Radek Krejci010e54b2016-03-15 09:40:34 +01006816 ly_vlog_hide(1);
6817
Radek Krejci0b7704f2016-03-18 12:16:14 +01006818 /* when-stmt first */
Radek Krejci03b71f72016-03-16 11:10:09 +01006819 ly_errno = LY_SUCCESS;
6820 ly_vecode = LYVE_SUCCESS;
Radek Krejci010e54b2016-03-15 09:40:34 +01006821 do {
6822 progress = 0;
Michal Vasko6df94132016-09-22 11:08:09 +02006823 for (i = 0; i < unres->count; i++) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006824 if (unres->type[i] != UNRES_WHEN) {
6825 continue;
6826 }
Michal Vasko6df94132016-09-22 11:08:09 +02006827 assert(!trusted);
Radek Krejci0c0086a2016-03-24 15:20:28 +01006828 if (first) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006829 /* count when-stmt nodes in unres list */
6830 when_stmt++;
6831 }
6832
6833 /* resolve when condition only when all parent when conditions are already resolved */
6834 for (parent = unres->node[i]->parent;
6835 parent && LYD_WHEN_DONE(parent->when_status);
6836 parent = parent->parent) {
6837 if (!parent->parent && (parent->when_status & LYD_WHEN_FALSE)) {
6838 /* the parent node was already unlinked, do not resolve this node,
6839 * it will be removed anyway, so just mark it as resolved
6840 */
6841 unres->node[i]->when_status |= LYD_WHEN_FALSE;
6842 unres->type[i] = UNRES_RESOLVED;
6843 resolved++;
6844 break;
6845 }
6846 }
6847 if (parent) {
6848 continue;
6849 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006850
Radek Krejci48464ed2016-03-17 15:44:09 +01006851 rc = resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01006852 if (!rc) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006853 if (unres->node[i]->when_status & LYD_WHEN_FALSE) {
6854 if (!root) {
Radek Krejci03b71f72016-03-16 11:10:09 +01006855 /* false when condition */
6856 ly_vlog_hide(0);
Radek Krejci76e15e12016-06-22 11:02:24 +02006857 if (ly_log_level >= LY_LLERR) {
6858 path = strdup(ly_errpath());
6859 msg = strdup(ly_errmsg());
6860 LOGERR(LY_EVALID, "%s%s%s%s", msg,
6861 path[0] ? " (path: " : "", path[0] ? path : "", path[0] ? ")" : "");
6862 free(path);
6863 free(msg);
6864 }
Radek Krejci03b71f72016-03-16 11:10:09 +01006865 return -1;
Radek Krejci0b7704f2016-03-18 12:16:14 +01006866 } /* follows else */
6867
Radek Krejci0c0086a2016-03-24 15:20:28 +01006868 /* only unlink now, the subtree can contain another nodes stored in the unres list */
6869 /* if it has parent non-presence containers that would be empty, we should actually
6870 * remove the container
6871 */
Radek Krejci2537fd32016-09-07 16:22:41 +02006872 for (parent = unres->node[i];
6873 parent->parent && parent->parent->schema->nodetype == LYS_CONTAINER;
6874 parent = parent->parent) {
6875 if (((struct lys_node_container *)parent->parent->schema)->presence) {
6876 /* presence container */
6877 break;
Radek Krejci0c0086a2016-03-24 15:20:28 +01006878 }
Radek Krejci2537fd32016-09-07 16:22:41 +02006879 if (parent->next || parent->prev != parent) {
6880 /* non empty (the child we are in and we are going to remove is not the only child) */
6881 break;
6882 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01006883 }
Radek Krejci2537fd32016-09-07 16:22:41 +02006884 unres->node[i] = parent;
Radek Krejci0c0086a2016-03-24 15:20:28 +01006885
Radek Krejci0b7704f2016-03-18 12:16:14 +01006886 /* auto-delete */
6887 LOGVRB("auto-delete node \"%s\" due to when condition (%s)", ly_errpath(),
6888 ((struct lys_node_leaf *)unres->node[i]->schema)->when->cond);
Radek Krejci0c0086a2016-03-24 15:20:28 +01006889 if (*root && *root == unres->node[i]) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006890 *root = (*root)->next;
Radek Krejci03b71f72016-03-16 11:10:09 +01006891 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01006892
Radek Krejci0b7704f2016-03-18 12:16:14 +01006893 lyd_unlink(unres->node[i]);
6894 unres->type[i] = UNRES_DELETE;
6895 del_items++;
Radek Krejci51fd8162016-03-24 15:49:51 +01006896
6897 /* update the rest of unres items */
6898 for (j = 0; j < unres->count; j++) {
Radek Krejci3db819b2016-03-24 16:29:48 +01006899 if (unres->type[j] == UNRES_RESOLVED || unres->type[j] == UNRES_DELETE) {
Radek Krejci51fd8162016-03-24 15:49:51 +01006900 continue;
6901 }
6902
6903 /* test if the node is in subtree to be deleted */
6904 for (parent = unres->node[j]; parent; parent = parent->parent) {
6905 if (parent == unres->node[i]) {
6906 /* yes, it is */
6907 unres->type[j] = UNRES_RESOLVED;
6908 resolved++;
6909 break;
6910 }
6911 }
6912 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01006913 } else {
6914 unres->type[i] = UNRES_RESOLVED;
Radek Krejci03b71f72016-03-16 11:10:09 +01006915 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01006916 ly_errno = LY_SUCCESS;
6917 ly_vecode = LYVE_SUCCESS;
Radek Krejci010e54b2016-03-15 09:40:34 +01006918 resolved++;
6919 progress = 1;
6920 } else if (rc == -1) {
6921 ly_vlog_hide(0);
Michal Vasko76e73402016-08-24 16:00:13 +02006922 /* print only this last error */
6923 resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01006924 return -1;
Radek Krejcic2a180f2016-06-22 13:28:16 +02006925 } else {
6926 /* forward reference, erase ly_errno */
6927 ly_errno = LY_SUCCESS;
Radek Krejci010e54b2016-03-15 09:40:34 +01006928 }
6929 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01006930 first = 0;
Radek Krejci0b7704f2016-03-18 12:16:14 +01006931 } while (progress && resolved < when_stmt);
Radek Krejci010e54b2016-03-15 09:40:34 +01006932
Radek Krejci0b7704f2016-03-18 12:16:14 +01006933 /* do we have some unresolved when-stmt? */
Radek Krejcid940d732016-03-24 16:02:28 +01006934 if (when_stmt > resolved) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006935 ly_vlog_hide(0);
Radek Krejci76e15e12016-06-22 11:02:24 +02006936 if (ly_log_level >= LY_LLERR) {
6937 path = strdup(ly_errpath());
6938 msg = strdup(ly_errmsg());
6939 LOGERR(LY_EVALID, "%s%s%s%s", msg, path[0] ? " (path: " : "", path[0] ? path : "", path[0] ? ")" : "");
6940 free(path);
6941 free(msg);
6942 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01006943 return -1;
6944 }
6945
6946 for (i = 0; del_items && i < unres->count; i++) {
6947 /* we had some when-stmt resulted to false, so now we have to sanitize the unres list */
6948 if (unres->type[i] != UNRES_DELETE) {
6949 continue;
6950 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01006951 if (!unres->node[i]) {
6952 unres->type[i] = UNRES_RESOLVED;
6953 del_items--;
6954 continue;
Radek Krejci0b7704f2016-03-18 12:16:14 +01006955 }
6956
6957 /* really remove the complete subtree */
6958 lyd_free(unres->node[i]);
6959 unres->type[i] = UNRES_RESOLVED;
6960 del_items--;
6961 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006962
6963 /* rest */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006964 for (i = 0; i < unres->count; ++i) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006965 if (unres->type[i] == UNRES_RESOLVED) {
6966 continue;
6967 }
Michal Vasko6df94132016-09-22 11:08:09 +02006968 assert(!trusted || ((unres->type[i] != UNRES_MUST) && (unres->type[i] != UNRES_MUST_INOUT)));
Radek Krejci010e54b2016-03-15 09:40:34 +01006969
Radek Krejci48464ed2016-03-17 15:44:09 +01006970 rc = resolve_unres_data_item(unres->node[i], unres->type[i]);
Michal Vasko6df94132016-09-22 11:08:09 +02006971 if (rc == -1) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006972 ly_vlog_hide(0);
Michal Vasko96b846c2016-05-18 13:28:58 +02006973 /* print only this last error */
6974 resolve_unres_data_item(unres->node[i], unres->type[i]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006975 return -1;
Michal Vasko6df94132016-09-22 11:08:09 +02006976 } else if ((rc == 0) || (trusted && ((unres->type[i] == UNRES_LEAFREF) || (unres->type[i] == UNRES_INSTID)))) {
6977 unres->type[i] = UNRES_RESOLVED;
6978 resolved++;
6979 if (trusted) {
6980 /* accept it in this case */
6981 if (unres->type[i] == UNRES_LEAFREF) {
6982 LOGVRB("Leafref \"%s\" with value \"%s\" failed to be resolved.",
6983 ((struct lys_node_leaf *)unres->node[i]->schema)->type.info.lref.path,
6984 ((struct lyd_node_leaf_list *)unres->node[i])->value_str);
6985 } else {
6986 LOGVRB("Instance identifier \"%s\" failed to be resolved.",
6987 ((struct lyd_node_leaf_list *)unres->node[i])->value_str);
6988 }
6989 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006990 }
6991 }
6992
Radek Krejci010e54b2016-03-15 09:40:34 +01006993 ly_vlog_hide(0);
6994 if (resolved < unres->count) {
6995 /* try to resolve the unresolved data again, it will not resolve anything, but it will print
6996 * all the validation errors
6997 */
6998 for (i = 0; i < unres->count; ++i) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02006999 if (unres->type[i] == UNRES_UNION) {
7000 /* does not make sense to print specific errors for all
7001 * the data types, just print that the value is invalid */
7002 leaf = (struct lyd_node_leaf_list *)unres->node[i];
7003 LOGVAL(LYE_INVAL, LY_VLOG_LYD, unres->node[i], (leaf->value_str ? leaf->value_str : ""),
7004 leaf->schema->name);
7005 } else if (unres->type[i] != UNRES_RESOLVED) {
7006 resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01007007 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007008 }
7009 return -1;
7010 }
7011
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02007012 LOGVRB("All data nodes and constraints resolved.");
Radek Krejci010e54b2016-03-15 09:40:34 +01007013 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007014 return EXIT_SUCCESS;
7015}