blob: e3607feef293412b7fc3dd97801df6c47cf69c70 [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 Vasko6966ea62016-10-21 15:19:30 +020033static int resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type);
34
Michal Vaskod24dd012016-09-30 12:20:22 +020035int
36parse_range_dec64(const char **str_num, uint8_t dig, int64_t *num)
Michal Vasko4d1f0482016-09-19 14:35:06 +020037{
38 const char *ptr;
39 int minus = 0;
40 int64_t ret = 0;
41 int8_t str_exp, str_dig = -1;
42
43 ptr = *str_num;
44
45 if (ptr[0] == '-') {
46 minus = 1;
47 ++ptr;
48 }
49
Michal Vaskod24dd012016-09-30 12:20:22 +020050 if (!isdigit(ptr[0])) {
51 /* there must be at least one */
52 return 1;
53 }
54
Michal Vasko4d1f0482016-09-19 14:35:06 +020055 for (str_exp = 0; isdigit(ptr[0]) || ((ptr[0] == '.') && (str_dig < 0)); ++ptr) {
56 if (str_exp > 18) {
Michal Vaskod24dd012016-09-30 12:20:22 +020057 return 1;
Michal Vasko4d1f0482016-09-19 14:35:06 +020058 }
59
60 if (ptr[0] == '.') {
61 if (ptr[1] == '.') {
62 /* it's the next interval */
63 break;
64 }
65 ++str_dig;
66 } else {
67 ret = ret * 10 + (ptr[0] - 48);
68 if (str_dig > -1) {
69 ++str_dig;
70 }
71 ++str_exp;
72 }
73 }
Michal Vaskod24dd012016-09-30 12:20:22 +020074 if (str_dig == 0) {
75 /* no digits after '.' */
76 return 1;
77 } else if (str_dig == -1) {
78 /* there are 0 numbers after the floating point */
Michal Vasko4d1f0482016-09-19 14:35:06 +020079 str_dig = 0;
80 }
81
82 /* it's parsed, now adjust the number based on fraction-digits, if needed */
83 if (str_dig < dig) {
84 if ((str_exp - 1) + (dig - str_dig) > 18) {
Michal Vaskod24dd012016-09-30 12:20:22 +020085 return 1;
Michal Vasko4d1f0482016-09-19 14:35:06 +020086 }
87 ret *= dec_pow(dig - str_dig);
88 }
89 if (str_dig > dig) {
Michal Vaskod24dd012016-09-30 12:20:22 +020090 return 1;
Michal Vasko4d1f0482016-09-19 14:35:06 +020091 }
92
93 if (minus) {
94 ret *= -1;
95 }
96 *str_num = ptr;
Michal Vaskod24dd012016-09-30 12:20:22 +020097 *num = ret;
Michal Vasko4d1f0482016-09-19 14:35:06 +020098
Michal Vaskod24dd012016-09-30 12:20:22 +020099 return 0;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200100}
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;
Radek Krejci9de2c042016-10-19 16:53:06 +02001258 int infeature;
Radek Krejcicbb473e2016-09-16 14:48:32 +02001259};
1260
Radek Krejci9ff0a922016-07-14 13:08:05 +02001261void
1262resolve_iffeature_getsizes(struct lys_iffeature *iffeat, unsigned int *expr_size, unsigned int *feat_size)
1263{
1264 unsigned int e = 0, f = 0, r = 0;
1265 uint8_t op;
1266
1267 assert(iffeat);
1268
1269 if (!iffeat->expr) {
1270 goto result;
1271 }
1272
1273 do {
1274 op = iff_getop(iffeat->expr, e++);
1275 switch (op) {
1276 case LYS_IFF_NOT:
1277 if (!r) {
1278 r += 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001279 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001280 break;
1281 case LYS_IFF_AND:
1282 case LYS_IFF_OR:
1283 if (!r) {
1284 r += 2;
1285 } else {
1286 r += 1;
1287 }
1288 break;
1289 case LYS_IFF_F:
1290 f++;
1291 if (r) {
1292 r--;
1293 }
1294 break;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001295 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001296 } while(r);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001297
Radek Krejci9ff0a922016-07-14 13:08:05 +02001298result:
1299 if (expr_size) {
1300 *expr_size = e;
1301 }
1302 if (feat_size) {
1303 *feat_size = f;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001304 }
1305}
1306
1307int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001308resolve_iffeature_compile(struct lys_iffeature *iffeat_expr, const char *value, struct lys_node *node,
Radek Krejci9de2c042016-10-19 16:53:06 +02001309 int infeature, struct unres_schema *unres)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001310{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001311 const char *c = value;
1312 int r, rc = EXIT_FAILURE;
Radek Krejci69b8d922016-07-27 13:13:41 +02001313 int i, j, last_not, checkversion = 0;
1314 unsigned int f_size = 0, expr_size = 0, f_exp = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001315 uint8_t op;
1316 struct iff_stack stack = {0, 0, NULL};
Radek Krejcicbb473e2016-09-16 14:48:32 +02001317 struct unres_iffeat_data *iff_data;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001318
Radek Krejci9ff0a922016-07-14 13:08:05 +02001319 assert(c);
1320
1321 if (isspace(c[0])) {
1322 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, c[0], c);
1323 return EXIT_FAILURE;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001324 }
1325
Radek Krejci9ff0a922016-07-14 13:08:05 +02001326 /* pre-parse the expression to get sizes for arrays, also do some syntax checks of the expression */
1327 for (i = j = last_not = 0; c[i]; i++) {
1328 if (c[i] == '(') {
Radek Krejci69b8d922016-07-27 13:13:41 +02001329 checkversion = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001330 j++;
1331 continue;
1332 } else if (c[i] == ')') {
1333 j--;
1334 continue;
1335 } else if (isspace(c[i])) {
1336 continue;
1337 }
1338
1339 if (!strncmp(&c[i], "not", r = 3) || !strncmp(&c[i], "and", r = 3) || !strncmp(&c[i], "or", r = 2)) {
1340 if (c[i + r] == '\0') {
Radek Krejcia98da3f2016-07-27 14:05:22 +02001341 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
Radek Krejci9ff0a922016-07-14 13:08:05 +02001342 return EXIT_FAILURE;
1343 } else if (!isspace(c[i + r])) {
1344 /* feature name starting with the not/and/or */
1345 last_not = 0;
1346 f_size++;
1347 } else if (c[i] == 'n') { /* not operation */
1348 if (last_not) {
1349 /* double not */
1350 expr_size = expr_size - 2;
1351 last_not = 0;
1352 } else {
1353 last_not = 1;
1354 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001355 } else { /* and, or */
1356 f_exp++;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001357 /* not a not operation */
1358 last_not = 0;
1359 }
1360 i += r;
1361 } else {
1362 f_size++;
1363 last_not = 0;
1364 }
1365 expr_size++;
1366
1367 while (!isspace(c[i])) {
1368 if (!c[i] || c[i] == ')') {
1369 i--;
1370 break;
1371 }
1372 i++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001373 }
1374 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001375 if (j || f_exp != f_size) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001376 /* not matching count of ( and ) */
1377 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1378 return EXIT_FAILURE;
1379 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001380
Radek Krejci69b8d922016-07-27 13:13:41 +02001381 if (checkversion || expr_size > 1) {
1382 /* check that we have 1.1 module */
1383 if (node->module->version != 2) {
1384 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1385 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "YANG 1.1 if-feature expression found in 1.0 module.");
1386 return EXIT_FAILURE;
1387 }
1388 }
1389
Radek Krejci9ff0a922016-07-14 13:08:05 +02001390 /* allocate the memory */
1391 iffeat_expr->expr = calloc((j = (expr_size / 4) + ((expr_size % 4) ? 1 : 0)), sizeof *iffeat_expr->expr);
Radek Krejcicbb473e2016-09-16 14:48:32 +02001392 iffeat_expr->features = calloc(f_size, sizeof *iffeat_expr->features);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001393 stack.size = expr_size;
1394 stack.stack = malloc(expr_size * sizeof *stack.stack);
1395 if (!stack.stack || !iffeat_expr->expr || !iffeat_expr->features) {
1396 LOGMEM;
1397 goto error;
1398 }
1399 f_size--; expr_size--; /* used as indexes from now */
1400
1401 for (i--; i >= 0; i--) {
1402 if (c[i] == ')') {
1403 /* push it on stack */
1404 iff_stack_push(&stack, LYS_IFF_RP);
1405 continue;
1406 } else if (c[i] == '(') {
1407 /* pop from the stack into result all operators until ) */
1408 while((op = iff_stack_pop(&stack)) != LYS_IFF_RP) {
1409 iff_setop(iffeat_expr->expr, op, expr_size--);
1410 }
1411 continue;
1412 } else if (isspace(c[i])) {
1413 continue;
1414 }
1415
1416 /* end operator or operand -> find beginning and get what is it */
1417 j = i + 1;
1418 while (i >= 0 && !isspace(c[i]) && c[i] != '(') {
1419 i--;
1420 }
1421 i++; /* get back by one step */
1422
1423 if (!strncmp(&c[i], "not ", 4)) {
1424 if (stack.index && stack.stack[stack.index - 1] == LYS_IFF_NOT) {
1425 /* double not */
1426 iff_stack_pop(&stack);
1427 } else {
1428 /* not has the highest priority, so do not pop from the stack
1429 * as in case of AND and OR */
1430 iff_stack_push(&stack, LYS_IFF_NOT);
1431 }
1432 } else if (!strncmp(&c[i], "and ", 4)) {
1433 /* as for OR - pop from the stack all operators with the same or higher
1434 * priority and store them to the result, then push the AND to the stack */
1435 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_AND) {
1436 op = iff_stack_pop(&stack);
1437 iff_setop(iffeat_expr->expr, op, expr_size--);
1438 }
1439 iff_stack_push(&stack, LYS_IFF_AND);
1440 } else if (!strncmp(&c[i], "or ", 3)) {
1441 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_OR) {
1442 op = iff_stack_pop(&stack);
1443 iff_setop(iffeat_expr->expr, op, expr_size--);
1444 }
1445 iff_stack_push(&stack, LYS_IFF_OR);
1446 } else {
1447 /* feature name, length is j - i */
1448
1449 /* add it to the result */
1450 iff_setop(iffeat_expr->expr, LYS_IFF_F, expr_size--);
1451
1452 /* now get the link to the feature definition. Since it can be
Radek Krejcicbb473e2016-09-16 14:48:32 +02001453 * forward referenced, we have to keep the feature name in auxiliary
1454 * structure passed into unres */
1455 iff_data = malloc(sizeof *iff_data);
1456 iff_data->node = node;
1457 iff_data->fname = lydict_insert(node->module->ctx, &c[i], j - i);
Radek Krejci9de2c042016-10-19 16:53:06 +02001458 iff_data->infeature = infeature;
Radek Krejcicbb473e2016-09-16 14:48:32 +02001459 r = unres_schema_add_node(node->module, unres, &iffeat_expr->features[f_size], UNRES_IFFEAT,
1460 (struct lys_node *)iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001461 f_size--;
1462
1463 if (r == -1) {
Pavol Vican4d084512016-09-29 16:38:12 +02001464 free(iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001465 goto error;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001466 }
1467 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001468 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001469 while (stack.index) {
1470 op = iff_stack_pop(&stack);
1471 iff_setop(iffeat_expr->expr, op, expr_size--);
1472 }
1473
1474 if (++expr_size || ++f_size) {
1475 /* not all expected operators and operands found */
1476 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1477 rc = EXIT_FAILURE;
1478 } else {
1479 rc = EXIT_SUCCESS;
1480 }
1481
1482error:
1483 /* cleanup */
1484 iff_stack_clean(&stack);
1485
1486 return rc;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001487}
1488
1489/**
Michal Vasko3edeaf72016-02-11 13:17:43 +01001490 * @brief Resolve (find) a data node based on a schema-nodeid.
1491 *
1492 * Used for resolving unique statements - so id is expected to be relative and local (without reference to a different
1493 * module).
1494 *
1495 */
1496struct lyd_node *
1497resolve_data_descendant_schema_nodeid(const char *nodeid, struct lyd_node *start)
1498{
1499 char *str, *token, *p;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001500 struct lyd_node *result = NULL, *iter;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001501 const struct lys_node *schema = NULL;
Radek Krejcicc217a62016-04-08 16:58:11 +02001502 int shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001503
1504 assert(nodeid && start);
1505
1506 if (nodeid[0] == '/') {
1507 return NULL;
1508 }
1509
1510 str = p = strdup(nodeid);
1511 if (!str) {
1512 LOGMEM;
1513 return NULL;
1514 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001515
Michal Vasko3edeaf72016-02-11 13:17:43 +01001516 while (p) {
1517 token = p;
1518 p = strchr(p, '/');
1519 if (p) {
1520 *p = '\0';
1521 p++;
1522 }
1523
Radek Krejci5da4eb62016-04-08 14:45:51 +02001524 if (p) {
1525 /* inner node */
Radek Krejcicc217a62016-04-08 16:58:11 +02001526 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema,
Radek Krejcif3c71de2016-04-11 12:45:46 +02001527 LYS_CONTAINER | LYS_CHOICE | LYS_CASE | LYS_LEAF, 0, 0, &schema)
Radek Krejci5da4eb62016-04-08 14:45:51 +02001528 || !schema) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001529 result = NULL;
1530 break;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001531 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001532
Radek Krejci5da4eb62016-04-08 14:45:51 +02001533 if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
1534 continue;
Michal Vaskodcf98e62016-05-05 17:53:53 +02001535 } else if (lys_parent(schema)->nodetype == LYS_CHOICE) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001536 /* shorthand case */
1537 if (!shorthand) {
1538 shorthand = 1;
Michal Vaskodcf98e62016-05-05 17:53:53 +02001539 schema = lys_parent(schema);
Radek Krejcicc217a62016-04-08 16:58:11 +02001540 continue;
1541 } else {
1542 shorthand = 0;
1543 if (schema->nodetype == LYS_LEAF) {
1544 /* should not be here, since we have leaf, which is not a shorthand nor final node */
1545 result = NULL;
1546 break;
1547 }
1548 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001549 }
1550 } else {
1551 /* final node */
Radek Krejcif3c71de2016-04-11 12:45:46 +02001552 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema, LYS_LEAF,
1553 shorthand ? 0 : 1, 0, &schema)
Radek Krejcicc217a62016-04-08 16:58:11 +02001554 || !schema) {
1555 result = NULL;
1556 break;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001557 }
1558 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001559 LY_TREE_FOR(result ? result->child : start, iter) {
1560 if (iter->schema == schema) {
1561 /* move in data tree according to returned schema */
1562 result = iter;
1563 break;
1564 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001565 }
Radek Krejcicc217a62016-04-08 16:58:11 +02001566 if (!iter) {
1567 /* instance not found */
1568 result = NULL;
1569 break;
1570 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001571 }
1572 free(str);
1573
1574 return result;
1575}
1576
Radek Krejcibdf92362016-04-08 14:43:34 +02001577/*
1578 * 0 - ok (done)
1579 * 1 - continue
1580 * 2 - break
1581 * -1 - error
1582 */
1583static int
Radek Krejcicc217a62016-04-08 16:58:11 +02001584schema_nodeid_siblingcheck(const struct lys_node *sibling, int8_t *shorthand, const char *id,
Radek Krejcibdf92362016-04-08 14:43:34 +02001585 const struct lys_module *module, const char *mod_name, int mod_name_len,
Radek Krejci0fa54e92016-09-14 14:01:05 +02001586 int implemented_mod, const struct lys_node **start)
Radek Krejcibdf92362016-04-08 14:43:34 +02001587{
1588 const struct lys_module *prefix_mod;
Radek Krejcicc217a62016-04-08 16:58:11 +02001589 int sh = 0;
Radek Krejcibdf92362016-04-08 14:43:34 +02001590
1591 /* module check */
1592 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Radek Krejci0fa54e92016-09-14 14:01:05 +02001593 if (implemented_mod) {
1594 prefix_mod = lys_get_implemented_module(prefix_mod);
1595 }
Radek Krejcibdf92362016-04-08 14:43:34 +02001596 if (!prefix_mod) {
1597 return -1;
1598 }
1599 if (prefix_mod != lys_node_module(sibling)) {
1600 return 1;
1601 }
1602
1603 /* check for shorthand cases - then 'start' does not change */
Michal Vaskodcf98e62016-05-05 17:53:53 +02001604 if (lys_parent(sibling) && (lys_parent(sibling)->nodetype == LYS_CHOICE) && (sibling->nodetype != LYS_CASE)) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001605 if (*shorthand != -1) {
1606 *shorthand = *shorthand ? 0 : 1;
1607 }
1608 sh = 1;
Radek Krejcibdf92362016-04-08 14:43:34 +02001609 }
1610
1611 /* the result node? */
1612 if (!id[0]) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001613 if (*shorthand == 1) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001614 return 1;
1615 }
1616 return 0;
1617 }
1618
Radek Krejcicc217a62016-04-08 16:58:11 +02001619 if (!sh) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001620 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02001621 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001622 return -1;
1623 }
1624 *start = sibling->child;
1625 }
1626
1627 return 2;
1628}
1629
Michal Vasko3edeaf72016-02-11 13:17:43 +01001630/* start - relative, module - absolute, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1631int
1632resolve_augment_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_module *module,
1633 const struct lys_node **ret)
1634{
1635 const char *name, *mod_name, *id;
1636 const struct lys_node *sibling;
1637 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001638 int8_t shorthand = 0;
Radek Krejci0fa54e92016-09-14 14:01:05 +02001639 int implemented_search = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001640 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcibdf92362016-04-08 14:43:34 +02001641 const struct lys_module *start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001642
1643 assert(nodeid && (start || module) && !(start && module) && ret);
1644
1645 id = nodeid;
1646
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001647 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 +01001648 return ((id - nodeid) - r) + 1;
1649 }
1650 id += r;
1651
1652 if ((is_relative && !start) || (!is_relative && !module)) {
1653 return -1;
1654 }
1655
1656 /* descendant-schema-nodeid */
1657 if (is_relative) {
Michal Vasko4c06fd82016-02-17 13:43:38 +01001658 module = start_mod = start->module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001659
1660 /* absolute-schema-nodeid */
1661 } else {
1662 start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Radek Krejci0fa54e92016-09-14 14:01:05 +02001663 if (start_mod != lys_main_module(module)) {
1664 /* if the submodule augments the mainmodule (or in general a module augments
1665 * itself, we don't want to search for the implemented module but augments
1666 * the module anyway. But when augmenting another module, we need the implemented
1667 * revision of the module if any */
1668 start_mod = lys_get_implemented_module(start_mod);
1669 implemented_search = 1;
1670 }
Michal Vaskoe2905632016-02-11 15:42:24 +01001671 if (!start_mod) {
1672 return -1;
1673 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001674 start = start_mod->data;
1675 }
1676
1677 while (1) {
1678 sibling = NULL;
1679 while ((sibling = lys_getnext(sibling, lys_parent(start), start_mod,
1680 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
1681 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001682 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001683 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len,
1684 implemented_search, &start);
Radek Krejcibdf92362016-04-08 14:43:34 +02001685 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001686 *ret = sibling;
1687 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001688 } else if (r == 1) {
1689 continue;
1690 } else if (r == 2) {
1691 break;
1692 } else {
1693 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001694 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001695 }
1696 }
1697
1698 /* no match */
1699 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001700 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001701 return EXIT_SUCCESS;
1702 }
1703
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001704 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 +01001705 return ((id - nodeid) - r) + 1;
1706 }
1707 id += r;
1708 }
1709
1710 /* cannot get here */
1711 LOGINT;
1712 return -1;
1713}
1714
Radek Krejcif3c71de2016-04-11 12:45:46 +02001715/* unique, refine,
1716 * >0 - unexpected char on position (ret - 1),
1717 * 0 - ok (but ret can still be NULL),
1718 * -1 - error,
1719 * -2 - violated no_innerlist */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001720int
1721resolve_descendant_schema_nodeid(const char *nodeid, const struct lys_node *start, int ret_nodetype,
Radek Krejcif3c71de2016-04-11 12:45:46 +02001722 int check_shorthand, int no_innerlist, const struct lys_node **ret)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001723{
1724 const char *name, *mod_name, *id;
1725 const struct lys_node *sibling;
1726 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001727 int8_t shorthand = check_shorthand ? 0 : -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001728 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcibdf92362016-04-08 14:43:34 +02001729 const struct lys_module *module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001730
1731 assert(nodeid && start && ret);
1732 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1733
1734 id = nodeid;
1735 module = start->module;
1736
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001737 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 +01001738 return ((id - nodeid) - r) + 1;
1739 }
1740 id += r;
1741
1742 if (!is_relative) {
1743 return -1;
1744 }
1745
1746 while (1) {
1747 sibling = NULL;
1748 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
1749 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE))) {
1750 /* name match */
1751 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001752 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len, 0, &start);
Radek Krejcibdf92362016-04-08 14:43:34 +02001753 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001754 if (!(sibling->nodetype & ret_nodetype)) {
1755 /* wrong node type, too bad */
1756 continue;
1757 }
1758 *ret = sibling;
1759 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001760 } else if (r == 1) {
1761 continue;
1762 } else if (r == 2) {
1763 break;
1764 } else {
1765 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001766 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001767 }
1768 }
1769
1770 /* no match */
1771 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001772 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001773 return EXIT_SUCCESS;
Radek Krejcif3c71de2016-04-11 12:45:46 +02001774 } else if (no_innerlist && sibling->nodetype == LYS_LIST) {
1775 *ret = NULL;
1776 return -2;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001777 }
1778
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001779 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 +01001780 return ((id - nodeid) - r) + 1;
1781 }
1782 id += r;
1783 }
1784
1785 /* cannot get here */
1786 LOGINT;
1787 return -1;
1788}
1789
1790/* choice default */
1791int
1792resolve_choice_default_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node **ret)
1793{
1794 /* cannot actually be a path */
1795 if (strchr(nodeid, '/')) {
1796 return -1;
1797 }
1798
Radek Krejcif3c71de2016-04-11 12:45:46 +02001799 return resolve_descendant_schema_nodeid(nodeid, start, LYS_NO_RPC_NOTIF_NODE, 1, 0, ret);
Michal Vasko3edeaf72016-02-11 13:17:43 +01001800}
1801
1802/* uses, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1803static int
1804resolve_uses_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node_grp **ret)
1805{
1806 const struct lys_module *module;
1807 const char *mod_prefix, *name;
1808 int i, mod_prefix_len, nam_len;
1809
1810 /* parse the identifier, it must be parsed on one call */
1811 if (((i = parse_node_identifier(nodeid, &mod_prefix, &mod_prefix_len, &name, &nam_len)) < 1) || nodeid[i]) {
1812 return -i + 1;
1813 }
1814
1815 module = lys_get_import_module(start->module, mod_prefix, mod_prefix_len, NULL, 0);
1816 if (!module) {
1817 return -1;
1818 }
1819 if (module != start->module) {
1820 start = module->data;
1821 }
1822
1823 *ret = lys_find_grouping_up(name, (struct lys_node *)start);
1824
1825 return EXIT_SUCCESS;
1826}
1827
1828int
1829resolve_absolute_schema_nodeid(const char *nodeid, const struct lys_module *module, int ret_nodetype,
1830 const struct lys_node **ret)
1831{
1832 const char *name, *mod_name, *id;
1833 const struct lys_node *sibling, *start;
1834 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001835 int8_t shorthand = 0;
Radek Krejcibdf92362016-04-08 14:43:34 +02001836 const struct lys_module *abs_start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001837
1838 assert(nodeid && module && ret);
1839 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1840
1841 id = nodeid;
1842 start = module->data;
1843
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001844 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 +01001845 return ((id - nodeid) - r) + 1;
1846 }
1847 id += r;
1848
1849 if (is_relative) {
1850 return -1;
1851 }
1852
1853 abs_start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001854 if (!abs_start_mod) {
1855 return -1;
1856 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001857
1858 while (1) {
1859 sibling = NULL;
1860 while ((sibling = lys_getnext(sibling, lys_parent(start), abs_start_mod, LYS_GETNEXT_WITHCHOICE
1861 | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_WITHGROUPING))) {
1862 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001863 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001864 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len, 0, &start);
Radek Krejcibdf92362016-04-08 14:43:34 +02001865 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001866 if (!(sibling->nodetype & ret_nodetype)) {
1867 /* wrong node type, too bad */
1868 continue;
1869 }
1870 *ret = sibling;
1871 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001872 } else if (r == 1) {
1873 continue;
1874 } else if (r == 2) {
1875 break;
1876 } else {
1877 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001878 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001879 }
1880 }
1881
1882 /* no match */
1883 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001884 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001885 return EXIT_SUCCESS;
1886 }
1887
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001888 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 +01001889 return ((id - nodeid) - r) + 1;
1890 }
1891 id += r;
1892 }
1893
1894 /* cannot get here */
1895 LOGINT;
1896 return -1;
1897}
1898
Michal Vaskoe733d682016-03-14 09:08:27 +01001899static int
Michal Vasko3547c532016-03-14 09:40:50 +01001900resolve_json_schema_list_predicate(const char *predicate, const struct lys_node_list *list, int *parsed)
Michal Vaskoe733d682016-03-14 09:08:27 +01001901{
1902 const char *name;
1903 int nam_len, has_predicate, i;
1904
Michal Vasko7b54f7e2016-05-03 15:07:31 +02001905 if (((i = parse_schema_json_predicate(predicate, &name, &nam_len, NULL, NULL, &has_predicate)) < 1)
1906 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001907 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-i], &predicate[-i]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001908 return -1;
1909 }
1910
1911 predicate += i;
1912 *parsed += i;
1913
1914 for (i = 0; i < list->keys_size; ++i) {
1915 if (!strncmp(list->keys[i]->name, name, nam_len) && !list->keys[i]->name[nam_len]) {
1916 break;
1917 }
1918 }
1919
1920 if (i == list->keys_size) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001921 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskoe733d682016-03-14 09:08:27 +01001922 return -1;
1923 }
1924
1925 /* more predicates? */
1926 if (has_predicate) {
Michal Vasko3547c532016-03-14 09:40:50 +01001927 return resolve_json_schema_list_predicate(predicate, list, parsed);
Michal Vaskoe733d682016-03-14 09:08:27 +01001928 }
1929
1930 return 0;
1931}
1932
Michal Vasko8d26e5c2016-09-08 10:03:49 +02001933/* cannot return LYS_GROUPING, LYS_AUGMENT, LYS_USES, logs directly */
Michal Vaskoe733d682016-03-14 09:08:27 +01001934const struct lys_node *
Michal Vasko8d26e5c2016-09-08 10:03:49 +02001935resolve_json_nodeid(const char *nodeid, struct ly_ctx *ctx, const struct lys_node *start)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001936{
Michal Vasko10728b52016-04-07 14:26:29 +02001937 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001938 const char *name, *mod_name, *id;
Michal Vasko3547c532016-03-14 09:40:50 +01001939 const struct lys_node *sibling;
Radek Krejcibdf92362016-04-08 14:43:34 +02001940 int r, nam_len, mod_name_len, is_relative = -1, has_predicate, shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001941 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vaskoe733d682016-03-14 09:08:27 +01001942 const struct lys_module *prefix_mod, *module, *prev_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001943
Michal Vasko3547c532016-03-14 09:40:50 +01001944 assert(nodeid && (ctx || start));
1945 if (!ctx) {
1946 ctx = start->module->ctx;
1947 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001948
1949 id = nodeid;
1950
Michal Vaskoe733d682016-03-14 09:08:27 +01001951 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 +01001952 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001953 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001954 }
1955 id += r;
1956
1957 if (is_relative) {
Michal Vasko3547c532016-03-14 09:40:50 +01001958 assert(start);
1959 start = start->child;
1960 if (!start) {
1961 /* no descendants, fail for sure */
Michal Vasko10728b52016-04-07 14:26:29 +02001962 str = strndup(nodeid, (name + nam_len) - nodeid);
1963 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
1964 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01001965 return NULL;
1966 }
1967 module = start->module;
1968 } else {
1969 if (!mod_name) {
Michal Vasko10728b52016-04-07 14:26:29 +02001970 str = strndup(nodeid, (name + nam_len) - nodeid);
1971 LOGVAL(LYE_PATH_MISSMOD, LY_VLOG_STR, nodeid);
1972 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01001973 return NULL;
Michal Vasko971a3ca2016-04-01 13:09:29 +02001974 } else if (mod_name_len > LY_BUF_SIZE - 1) {
1975 LOGINT;
1976 return NULL;
Michal Vasko3547c532016-03-14 09:40:50 +01001977 }
1978
Michal Vasko971a3ca2016-04-01 13:09:29 +02001979 if (ly_buf_used && module_name[0]) {
1980 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
1981 }
1982 ly_buf_used++;
1983
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02001984 memmove(module_name, mod_name, mod_name_len);
Michal Vasko971a3ca2016-04-01 13:09:29 +02001985 module_name[mod_name_len] = '\0';
1986 module = ly_ctx_get_module(ctx, module_name, NULL);
1987
1988 if (buf_backup) {
1989 /* return previous internal buffer content */
1990 strcpy(module_name, buf_backup);
1991 free(buf_backup);
1992 buf_backup = NULL;
1993 }
1994 ly_buf_used--;
1995
Michal Vasko3547c532016-03-14 09:40:50 +01001996 if (!module) {
Michal Vasko10728b52016-04-07 14:26:29 +02001997 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
1998 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
1999 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002000 return NULL;
2001 }
2002 start = module->data;
2003
2004 /* now it's as if there was no module name */
2005 mod_name = NULL;
2006 mod_name_len = 0;
Michal Vaskoe733d682016-03-14 09:08:27 +01002007 }
2008
Michal Vaskoe733d682016-03-14 09:08:27 +01002009 prev_mod = module;
2010
Michal Vasko3edeaf72016-02-11 13:17:43 +01002011 while (1) {
2012 sibling = NULL;
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002013 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
2014 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002015 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02002016 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002017 /* module check */
2018 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002019 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko8757e7c2016-03-15 10:41:30 +01002020 LOGINT;
2021 return NULL;
2022 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002023
2024 if (ly_buf_used && module_name[0]) {
2025 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2026 }
2027 ly_buf_used++;
2028
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002029 memmove(module_name, mod_name, mod_name_len);
Michal Vasko8757e7c2016-03-15 10:41:30 +01002030 module_name[mod_name_len] = '\0';
2031 /* will also find an augment module */
2032 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002033
2034 if (buf_backup) {
2035 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002036 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002037 free(buf_backup);
2038 buf_backup = NULL;
2039 }
2040 ly_buf_used--;
2041
Michal Vasko3edeaf72016-02-11 13:17:43 +01002042 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002043 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2044 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2045 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002046 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002047 }
2048 } else {
2049 prefix_mod = prev_mod;
2050 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01002051 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002052 continue;
2053 }
2054
Michal Vaskoe733d682016-03-14 09:08:27 +01002055 /* do we have some predicates on it? */
2056 if (has_predicate) {
2057 r = 0;
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002058 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
2059 if ((r = parse_schema_json_predicate(id, NULL, NULL, NULL, NULL, &has_predicate)) < 1) {
2060 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2061 return NULL;
2062 }
2063 } else if (sibling->nodetype == LYS_LIST) {
2064 if (resolve_json_schema_list_predicate(id, (const struct lys_node_list *)sibling, &r)) {
2065 return NULL;
2066 }
2067 } else {
Michal Vasko43c300e2016-03-22 12:54:27 +01002068 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vaskoe733d682016-03-14 09:08:27 +01002069 return NULL;
Michal Vaskoe733d682016-03-14 09:08:27 +01002070 }
2071 id += r;
2072 }
2073
Radek Krejcibdf92362016-04-08 14:43:34 +02002074 /* check for shorthand cases - then 'start' does not change */
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002075 if (lys_parent(sibling) && (lys_parent(sibling)->nodetype == LYS_CHOICE) && (sibling->nodetype != LYS_CASE)) {
Radek Krejcibdf92362016-04-08 14:43:34 +02002076 shorthand = ~shorthand;
2077 }
2078
Michal Vasko3edeaf72016-02-11 13:17:43 +01002079 /* the result node? */
2080 if (!id[0]) {
Radek Krejcibdf92362016-04-08 14:43:34 +02002081 if (shorthand) {
2082 /* wrong path for shorthand */
Michal Vasko025e0452016-05-17 16:14:20 +02002083 str = strndup(nodeid, (name + nam_len) - nodeid);
2084 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
Michal Vasko3c0f9f52016-05-17 16:38:10 +02002085 LOGVAL(LYE_SPEC, LY_VLOG_STR, str, "Schema shorthand case path must include the virtual case statement.");
Radek Krejci9a5fccc2016-05-18 15:44:58 +02002086 free(str);
Michal Vasko025e0452016-05-17 16:14:20 +02002087 return NULL;
Radek Krejcibdf92362016-04-08 14:43:34 +02002088 }
Michal Vaskoe733d682016-03-14 09:08:27 +01002089 return sibling;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002090 }
2091
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002092 if (!shorthand) {
Michal Vasko7dc71d02016-03-15 10:42:28 +01002093 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002094 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002095 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko7dc71d02016-03-15 10:42:28 +01002096 return NULL;
2097 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01002098 start = sibling->child;
2099 }
2100
2101 /* update prev mod */
2102 prev_mod = start->module;
2103 break;
2104 }
2105 }
2106
2107 /* no match */
2108 if (!sibling) {
Michal Vasko10728b52016-04-07 14:26:29 +02002109 str = strndup(nodeid, (name + nam_len) - nodeid);
2110 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
2111 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002112 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002113 }
2114
Michal Vaskoe733d682016-03-14 09:08:27 +01002115 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 +01002116 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002117 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002118 }
2119 id += r;
2120 }
2121
2122 /* cannot get here */
2123 LOGINT;
Michal Vaskoe733d682016-03-14 09:08:27 +01002124 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002125}
2126
Michal Vasko22448d32016-03-16 13:17:29 +01002127static int
2128resolve_partial_json_data_list_predicate(const char *predicate, const char *node_name, struct lyd_node *node, int *parsed)
2129{
2130 const char *name, *value;
2131 int nam_len, val_len, has_predicate = 1, r;
2132 uint16_t i;
Michal Vaskof29903d2016-04-18 13:13:10 +02002133 struct lyd_node_leaf_list *key;
Michal Vasko22448d32016-03-16 13:17:29 +01002134
Radek Krejci61a86c62016-03-24 11:06:44 +01002135 assert(node);
Michal Vasko22448d32016-03-16 13:17:29 +01002136 assert(node->schema->nodetype == LYS_LIST);
2137
Michal Vaskof29903d2016-04-18 13:13:10 +02002138 key = (struct lyd_node_leaf_list *)node->child;
2139 for (i = 0; i < ((struct lys_node_list *)node->schema)->keys_size; ++i) {
2140 if (!key) {
2141 /* invalid data */
2142 LOGINT;
2143 return -1;
2144 }
Michal Vasko22448d32016-03-16 13:17:29 +01002145
Michal Vasko22448d32016-03-16 13:17:29 +01002146 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002147 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, node_name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002148 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002149 }
2150
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002151 if (((r = parse_schema_json_predicate(predicate, &name, &nam_len, &value, &val_len, &has_predicate)) < 1)
2152 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002153 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
Michal Vaskof29903d2016-04-18 13:13:10 +02002154 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002155 }
2156
2157 predicate += r;
2158 *parsed += r;
2159
Michal Vaskof29903d2016-04-18 13:13:10 +02002160 if (strncmp(key->schema->name, name, nam_len) || key->schema->name[nam_len]) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002161 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002162 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002163 }
2164
2165 /* value does not match */
Michal Vaskof29903d2016-04-18 13:13:10 +02002166 if (strncmp(key->value_str, value, val_len) || key->value_str[val_len]) {
Michal Vasko22448d32016-03-16 13:17:29 +01002167 return 1;
2168 }
Michal Vaskof29903d2016-04-18 13:13:10 +02002169
2170 key = (struct lyd_node_leaf_list *)key->next;
Michal Vasko22448d32016-03-16 13:17:29 +01002171 }
2172
2173 if (has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002174 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko22448d32016-03-16 13:17:29 +01002175 return -1;
2176 }
2177
2178 return 0;
2179}
2180
Radek Krejci45826012016-08-24 15:07:57 +02002181/**
2182 * @brief get the closest parent of the node (or the node itself) identified by the nodeid (path)
2183 *
2184 * @param[in] nodeid Node data path to find
2185 * @param[in] llist_value If the \p nodeid identifies leaf-list, this is expected value of the leaf-list instance.
2186 * @param[in] options Bitmask of options flags, see @ref pathoptions.
2187 * @param[out] parsed Number of characters processed in \p id
2188 * @return The closes parent (or the node itself) from the path
2189 */
Michal Vasko22448d32016-03-16 13:17:29 +01002190struct lyd_node *
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002191resolve_partial_json_data_nodeid(const char *nodeid, const char *llist_value, struct lyd_node *start, int options,
2192 int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002193{
Michal Vasko10728b52016-04-07 14:26:29 +02002194 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vaskoee385fa2016-10-19 15:51:36 +02002195 const char *id, *mod_name, *name, *pred_name;
2196 int r, ret, mod_name_len, nam_len, is_relative = -1;
2197 int has_predicate, last_parsed, val_len, pred_name_len, last_has_pred;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002198 struct lyd_node *sibling, *last_match = NULL;
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002199 struct lyd_node_leaf_list *llist;
Michal Vasko22448d32016-03-16 13:17:29 +01002200 const struct lys_module *prefix_mod, *prev_mod;
2201 struct ly_ctx *ctx;
2202
2203 assert(nodeid && start && parsed);
2204
2205 ctx = start->schema->module->ctx;
2206 id = nodeid;
2207
2208 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 +01002209 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002210 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002211 return NULL;
2212 }
2213 id += r;
2214 /* add it to parsed only after the data node was actually found */
2215 last_parsed = r;
2216
2217 if (is_relative) {
2218 prev_mod = start->schema->module;
Michal Vasko22448d32016-03-16 13:17:29 +01002219 start = start->child;
2220 } else {
2221 for (; start->parent; start = start->parent);
Michal Vasko22448d32016-03-16 13:17:29 +01002222 prev_mod = start->schema->module;
2223 }
2224
2225 while (1) {
2226 LY_TREE_FOR(start, sibling) {
Michal Vasko945b96b2016-10-18 11:49:12 +02002227 /* RPC/action data check, return simply invalid argument, because the data tree is invalid */
Michal Vasko2411b942016-03-23 13:50:03 +01002228 if (lys_parent(sibling->schema)) {
2229 if (options & LYD_PATH_OPT_OUTPUT) {
2230 if (lys_parent(sibling->schema)->nodetype == LYS_INPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002231 LOGERR(LY_EINVAL, "Provided data tree includes some RPC input nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002232 *parsed = -1;
2233 return NULL;
2234 }
2235 } else {
2236 if (lys_parent(sibling->schema)->nodetype == LYS_OUTPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002237 LOGERR(LY_EINVAL, "Provided data tree includes some RPC output nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002238 *parsed = -1;
2239 return NULL;
2240 }
2241 }
2242 }
2243
Michal Vasko22448d32016-03-16 13:17:29 +01002244 /* name match */
2245 if (!strncmp(name, sibling->schema->name, nam_len) && !sibling->schema->name[nam_len]) {
2246
2247 /* module check */
2248 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002249 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko22448d32016-03-16 13:17:29 +01002250 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002251 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002252 return NULL;
2253 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002254
2255 if (ly_buf_used && module_name[0]) {
2256 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2257 }
2258 ly_buf_used++;
2259
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002260 memmove(module_name, mod_name, mod_name_len);
Michal Vasko22448d32016-03-16 13:17:29 +01002261 module_name[mod_name_len] = '\0';
2262 /* will also find an augment module */
2263 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002264
2265 if (buf_backup) {
2266 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002267 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002268 free(buf_backup);
2269 buf_backup = NULL;
2270 }
2271 ly_buf_used--;
2272
Michal Vasko22448d32016-03-16 13:17:29 +01002273 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002274 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2275 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2276 free(str);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002277 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002278 return NULL;
2279 }
2280 } else {
2281 prefix_mod = prev_mod;
2282 }
2283 if (prefix_mod != lys_node_module(sibling->schema)) {
2284 continue;
2285 }
2286
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002287 /* leaf-list, did we find it with the correct value or not? */
Michal Vasko22448d32016-03-16 13:17:29 +01002288 if (sibling->schema->nodetype == LYS_LEAFLIST) {
Michal Vaskoee385fa2016-10-19 15:51:36 +02002289 last_has_pred = 0;
Michal Vaskoacb87b62016-10-19 11:33:55 +02002290 if (has_predicate) {
Michal Vaskoee385fa2016-10-19 15:51:36 +02002291 if ((r = parse_schema_json_predicate(id, &pred_name, &pred_name_len, &llist_value, &val_len, &last_has_pred)) < 1) {
Michal Vaskoacb87b62016-10-19 11:33:55 +02002292 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2293 *parsed = -1;
2294 return NULL;
2295 }
Michal Vaskoee385fa2016-10-19 15:51:36 +02002296 if ((pred_name[0] != '.') || (pred_name_len != 1)) {
2297 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[1], id + 1);
2298 *parsed = -1;
2299 return NULL;
2300 }
Michal Vaskoacb87b62016-10-19 11:33:55 +02002301 } else {
2302 r = 0;
2303 if (llist_value) {
2304 val_len = strlen(llist_value);
2305 } else {
2306 val_len = 0;
2307 }
2308 }
2309
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002310 llist = (struct lyd_node_leaf_list *)sibling;
Michal Vaskoacb87b62016-10-19 11:33:55 +02002311 if ((!val_len && llist->value_str && llist->value_str[0])
2312 || (val_len && (strncmp(llist_value, llist->value_str, val_len) || llist->value_str[val_len]))) {
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002313 continue;
2314 }
Michal Vaskoacb87b62016-10-19 11:33:55 +02002315 id += r;
2316 last_parsed += r;
Michal Vaskoee385fa2016-10-19 15:51:36 +02002317 has_predicate = last_has_pred;
Michal Vaskoacb87b62016-10-19 11:33:55 +02002318
Radek Krejci45826012016-08-24 15:07:57 +02002319 } else if (sibling->schema->nodetype == LYS_LIST) {
2320 /* list, we need predicates'n'stuff then */
Michal Vasko22448d32016-03-16 13:17:29 +01002321 r = 0;
2322 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002323 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002324 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002325 return NULL;
2326 }
2327 ret = resolve_partial_json_data_list_predicate(id, name, sibling, &r);
2328 if (ret == -1) {
Michal Vasko238bd2f2016-03-23 09:39:01 +01002329 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002330 return NULL;
2331 } else if (ret == 1) {
2332 /* this list instance does not match */
2333 continue;
2334 }
2335 id += r;
2336 last_parsed += r;
2337 }
2338
2339 *parsed += last_parsed;
2340
2341 /* the result node? */
2342 if (!id[0]) {
2343 return sibling;
2344 }
2345
2346 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002347 if (sibling->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002348 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002349 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002350 return NULL;
2351 }
Michal Vaskoc6c52cf2016-03-29 11:53:04 +02002352 last_match = sibling;
Michal Vasko22448d32016-03-16 13:17:29 +01002353 start = sibling->child;
2354 if (start) {
2355 prev_mod = start->schema->module;
2356 }
2357 break;
2358 }
2359 }
2360
2361 /* no match, return last match */
2362 if (!sibling) {
2363 return last_match;
2364 }
2365
2366 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 +01002367 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002368 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002369 return NULL;
2370 }
2371 id += r;
2372 last_parsed = r;
2373 }
2374
2375 /* cannot get here */
2376 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002377 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002378 return NULL;
2379}
2380
Michal Vasko3edeaf72016-02-11 13:17:43 +01002381/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02002382 * @brief Resolves length or range intervals. Does not log.
Michal Vaskoaeb51802016-04-11 10:58:47 +02002383 * Syntax is assumed to be correct, *ret MUST be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002384 *
Michal Vaskoaeb51802016-04-11 10:58:47 +02002385 * @param[in] str_restr Restriction as a string.
2386 * @param[in] type Type of the restriction.
2387 * @param[out] ret Final interval structure that starts with
2388 * the interval of the initial type, continues with intervals
2389 * of any superior types derived from the initial one, and
2390 * finishes with intervals from our \p type.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002391 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002392 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002393 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002394int
Michal Vaskoaeb51802016-04-11 10:58:47 +02002395resolve_len_ran_interval(const char *str_restr, struct lys_type *type, struct len_ran_intv **ret)
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002396{
2397 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002398 int kind;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002399 int64_t local_smin, local_smax, local_fmin, local_fmax;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002400 uint64_t local_umin, local_umax;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002401 uint8_t local_fdig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002402 const char *seg_ptr, *ptr;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002403 struct len_ran_intv *local_intv = NULL, *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002404
2405 switch (type->base) {
2406 case LY_TYPE_BINARY:
2407 kind = 0;
2408 local_umin = 0;
2409 local_umax = 18446744073709551615UL;
2410
2411 if (!str_restr && type->info.binary.length) {
2412 str_restr = type->info.binary.length->expr;
2413 }
2414 break;
2415 case LY_TYPE_DEC64:
2416 kind = 2;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002417 local_fmin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2418 local_fmax = __INT64_C(9223372036854775807);
2419 local_fdig = type->info.dec64.dig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002420
2421 if (!str_restr && type->info.dec64.range) {
2422 str_restr = type->info.dec64.range->expr;
2423 }
2424 break;
2425 case LY_TYPE_INT8:
2426 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002427 local_smin = __INT64_C(-128);
2428 local_smax = __INT64_C(127);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002429
2430 if (!str_restr && type->info.num.range) {
2431 str_restr = type->info.num.range->expr;
2432 }
2433 break;
2434 case LY_TYPE_INT16:
2435 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002436 local_smin = __INT64_C(-32768);
2437 local_smax = __INT64_C(32767);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002438
2439 if (!str_restr && type->info.num.range) {
2440 str_restr = type->info.num.range->expr;
2441 }
2442 break;
2443 case LY_TYPE_INT32:
2444 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002445 local_smin = __INT64_C(-2147483648);
2446 local_smax = __INT64_C(2147483647);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002447
2448 if (!str_restr && type->info.num.range) {
2449 str_restr = type->info.num.range->expr;
2450 }
2451 break;
2452 case LY_TYPE_INT64:
2453 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002454 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2455 local_smax = __INT64_C(9223372036854775807);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002456
2457 if (!str_restr && type->info.num.range) {
2458 str_restr = type->info.num.range->expr;
2459 }
2460 break;
2461 case LY_TYPE_UINT8:
2462 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002463 local_umin = __UINT64_C(0);
2464 local_umax = __UINT64_C(255);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002465
2466 if (!str_restr && type->info.num.range) {
2467 str_restr = type->info.num.range->expr;
2468 }
2469 break;
2470 case LY_TYPE_UINT16:
2471 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002472 local_umin = __UINT64_C(0);
2473 local_umax = __UINT64_C(65535);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002474
2475 if (!str_restr && type->info.num.range) {
2476 str_restr = type->info.num.range->expr;
2477 }
2478 break;
2479 case LY_TYPE_UINT32:
2480 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002481 local_umin = __UINT64_C(0);
2482 local_umax = __UINT64_C(4294967295);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002483
2484 if (!str_restr && type->info.num.range) {
2485 str_restr = type->info.num.range->expr;
2486 }
2487 break;
2488 case LY_TYPE_UINT64:
2489 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002490 local_umin = __UINT64_C(0);
2491 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002492
2493 if (!str_restr && type->info.num.range) {
2494 str_restr = type->info.num.range->expr;
2495 }
2496 break;
2497 case LY_TYPE_STRING:
2498 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002499 local_umin = __UINT64_C(0);
2500 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002501
2502 if (!str_restr && type->info.str.length) {
2503 str_restr = type->info.str.length->expr;
2504 }
2505 break;
2506 default:
2507 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002508 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002509 }
2510
2511 /* process superior types */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002512 if (type->der) {
2513 if (resolve_len_ran_interval(NULL, &type->der->type, &intv)) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002514 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002515 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02002516 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002517 assert(!intv || (intv->kind == kind));
2518 }
2519
2520 if (!str_restr) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002521 /* we do not have any restriction, return superior ones */
2522 *ret = intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002523 return EXIT_SUCCESS;
2524 }
2525
2526 /* adjust local min and max */
2527 if (intv) {
2528 tmp_intv = intv;
2529
2530 if (kind == 0) {
2531 local_umin = tmp_intv->value.uval.min;
2532 } else if (kind == 1) {
2533 local_smin = tmp_intv->value.sval.min;
2534 } else if (kind == 2) {
2535 local_fmin = tmp_intv->value.fval.min;
2536 }
2537
2538 while (tmp_intv->next) {
2539 tmp_intv = tmp_intv->next;
2540 }
2541
2542 if (kind == 0) {
2543 local_umax = tmp_intv->value.uval.max;
2544 } else if (kind == 1) {
2545 local_smax = tmp_intv->value.sval.max;
2546 } else if (kind == 2) {
2547 local_fmax = tmp_intv->value.fval.max;
2548 }
2549 }
2550
2551 /* finally parse our restriction */
2552 seg_ptr = str_restr;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002553 tmp_intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002554 while (1) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002555 if (!tmp_local_intv) {
2556 assert(!local_intv);
2557 local_intv = malloc(sizeof *local_intv);
2558 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002559 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002560 tmp_local_intv->next = malloc(sizeof *tmp_local_intv);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002561 tmp_local_intv = tmp_local_intv->next;
2562 }
Michal Vasko253035f2015-12-17 16:58:13 +01002563 if (!tmp_local_intv) {
2564 LOGMEM;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002565 goto error;
Michal Vasko253035f2015-12-17 16:58:13 +01002566 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002567
2568 tmp_local_intv->kind = kind;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002569 tmp_local_intv->type = type;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002570 tmp_local_intv->next = NULL;
2571
2572 /* min */
2573 ptr = seg_ptr;
2574 while (isspace(ptr[0])) {
2575 ++ptr;
2576 }
2577 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2578 if (kind == 0) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002579 tmp_local_intv->value.uval.min = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002580 } else if (kind == 1) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002581 tmp_local_intv->value.sval.min = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002582 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002583 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.min)) {
2584 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2585 goto error;
2586 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002587 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002588 } else if (!strncmp(ptr, "min", 3)) {
2589 if (kind == 0) {
2590 tmp_local_intv->value.uval.min = local_umin;
2591 } else if (kind == 1) {
2592 tmp_local_intv->value.sval.min = local_smin;
2593 } else if (kind == 2) {
2594 tmp_local_intv->value.fval.min = local_fmin;
2595 }
2596
2597 ptr += 3;
2598 } else if (!strncmp(ptr, "max", 3)) {
2599 if (kind == 0) {
2600 tmp_local_intv->value.uval.min = local_umax;
2601 } else if (kind == 1) {
2602 tmp_local_intv->value.sval.min = local_smax;
2603 } else if (kind == 2) {
2604 tmp_local_intv->value.fval.min = local_fmax;
2605 }
2606
2607 ptr += 3;
2608 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002609 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002610 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002611 }
2612
2613 while (isspace(ptr[0])) {
2614 ptr++;
2615 }
2616
2617 /* no interval or interval */
2618 if ((ptr[0] == '|') || !ptr[0]) {
2619 if (kind == 0) {
2620 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
2621 } else if (kind == 1) {
2622 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
2623 } else if (kind == 2) {
2624 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
2625 }
2626 } else if (!strncmp(ptr, "..", 2)) {
2627 /* skip ".." */
2628 ptr += 2;
2629 while (isspace(ptr[0])) {
2630 ++ptr;
2631 }
2632
2633 /* max */
2634 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2635 if (kind == 0) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002636 tmp_local_intv->value.uval.max = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002637 } else if (kind == 1) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002638 tmp_local_intv->value.sval.max = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002639 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002640 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.max)) {
2641 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2642 goto error;
2643 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002644 }
2645 } else if (!strncmp(ptr, "max", 3)) {
2646 if (kind == 0) {
2647 tmp_local_intv->value.uval.max = local_umax;
2648 } else if (kind == 1) {
2649 tmp_local_intv->value.sval.max = local_smax;
2650 } else if (kind == 2) {
2651 tmp_local_intv->value.fval.max = local_fmax;
2652 }
2653 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002654 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002655 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002656 }
2657 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002658 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002659 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002660 }
2661
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002662 /* check min and max in correct order*/
2663 if (kind == 0) {
2664 /* current segment */
2665 if (tmp_local_intv->value.uval.min > tmp_local_intv->value.uval.max) {
2666 goto error;
2667 }
2668 if (tmp_local_intv->value.uval.min < local_umin || tmp_local_intv->value.uval.max > local_umax) {
2669 goto error;
2670 }
2671 /* segments sholud be ascending order */
Pavol Vican69f62c92016-08-30 09:06:25 +02002672 if (tmp_intv && (tmp_intv->value.uval.max >= tmp_local_intv->value.uval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002673 goto error;
2674 }
2675 } else if (kind == 1) {
2676 if (tmp_local_intv->value.sval.min > tmp_local_intv->value.sval.max) {
2677 goto error;
2678 }
2679 if (tmp_local_intv->value.sval.min < local_smin || tmp_local_intv->value.sval.max > local_smax) {
2680 goto error;
2681 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002682 if (tmp_intv && (tmp_intv->value.sval.max >= tmp_local_intv->value.sval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002683 goto error;
2684 }
2685 } else if (kind == 2) {
2686 if (tmp_local_intv->value.fval.min > tmp_local_intv->value.fval.max) {
2687 goto error;
2688 }
2689 if (tmp_local_intv->value.fval.min < local_fmin || tmp_local_intv->value.fval.max > local_fmax) {
2690 goto error;
2691 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002692 if (tmp_intv && (tmp_intv->value.fval.max >= tmp_local_intv->value.fval.min)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002693 /* fraction-digits value is always the same (it cannot be changed in derived types) */
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002694 goto error;
2695 }
2696 }
2697
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002698 /* next segment (next OR) */
2699 seg_ptr = strchr(seg_ptr, '|');
2700 if (!seg_ptr) {
2701 break;
2702 }
2703 seg_ptr++;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002704 tmp_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002705 }
2706
2707 /* check local restrictions against superior ones */
2708 if (intv) {
2709 tmp_intv = intv;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002710 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002711
2712 while (tmp_local_intv && tmp_intv) {
2713 /* reuse local variables */
2714 if (kind == 0) {
2715 local_umin = tmp_local_intv->value.uval.min;
2716 local_umax = tmp_local_intv->value.uval.max;
2717
2718 /* it must be in this interval */
2719 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
2720 /* this interval is covered, next one */
2721 if (local_umax <= tmp_intv->value.uval.max) {
2722 tmp_local_intv = tmp_local_intv->next;
2723 continue;
2724 /* ascending order of restrictions -> fail */
2725 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002726 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002727 }
2728 }
2729 } else if (kind == 1) {
2730 local_smin = tmp_local_intv->value.sval.min;
2731 local_smax = tmp_local_intv->value.sval.max;
2732
2733 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
2734 if (local_smax <= tmp_intv->value.sval.max) {
2735 tmp_local_intv = tmp_local_intv->next;
2736 continue;
2737 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002738 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002739 }
2740 }
2741 } else if (kind == 2) {
2742 local_fmin = tmp_local_intv->value.fval.min;
2743 local_fmax = tmp_local_intv->value.fval.max;
2744
Michal Vasko4d1f0482016-09-19 14:35:06 +02002745 if ((dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.min, local_fdig) > -1)
Pavol Vican3c8ee2b2016-09-29 13:18:13 +02002746 && (dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002747 if (dec64cmp(local_fmax, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002748 tmp_local_intv = tmp_local_intv->next;
2749 continue;
2750 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002751 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002752 }
2753 }
2754 }
2755
2756 tmp_intv = tmp_intv->next;
2757 }
2758
2759 /* some interval left uncovered -> fail */
2760 if (tmp_local_intv) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002761 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002762 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002763 }
2764
Michal Vaskoaeb51802016-04-11 10:58:47 +02002765 /* append the local intervals to all the intervals of the superior types, return it all */
2766 if (intv) {
2767 for (tmp_intv = intv; tmp_intv->next; tmp_intv = tmp_intv->next);
2768 tmp_intv->next = local_intv;
2769 } else {
2770 intv = local_intv;
2771 }
2772 *ret = intv;
2773
2774 return EXIT_SUCCESS;
2775
2776error:
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002777 while (intv) {
2778 tmp_intv = intv->next;
2779 free(intv);
2780 intv = tmp_intv;
2781 }
Michal Vaskoaeb51802016-04-11 10:58:47 +02002782 while (local_intv) {
2783 tmp_local_intv = local_intv->next;
2784 free(local_intv);
2785 local_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002786 }
2787
Michal Vaskoaeb51802016-04-11 10:58:47 +02002788 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002789}
2790
Michal Vasko730dfdf2015-08-11 14:48:05 +02002791/**
Michal Vasko01c6fd22016-05-20 11:43:05 +02002792 * @brief Resolve a typedef, return only resolved typedefs if derived. If leafref, it must be
2793 * resolved for this function to return it. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002794 *
2795 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02002796 * @param[in] mod_name Typedef name module name.
2797 * @param[in] module Main module.
2798 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002799 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002800 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002801 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002802 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002803int
Michal Vasko1e62a092015-12-01 12:27:20 +01002804resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
2805 const struct lys_node *parent, struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002806{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002807 int i, j;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002808 struct lys_tpdf *tpdf, *match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002809 int tpdf_size;
2810
Michal Vasko1dca6882015-10-22 14:29:42 +02002811 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002812 /* no prefix, try built-in types */
2813 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
2814 if (!strcmp(ly_types[i].def->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002815 if (ret) {
2816 *ret = ly_types[i].def;
2817 }
2818 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002819 }
2820 }
2821 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02002822 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002823 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02002824 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002825 }
2826 }
2827
Michal Vasko1dca6882015-10-22 14:29:42 +02002828 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002829 /* search in local typedefs */
2830 while (parent) {
2831 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02002832 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02002833 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
2834 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002835 break;
2836
Radek Krejci76512572015-08-04 09:47:08 +02002837 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02002838 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
2839 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002840 break;
2841
Radek Krejci76512572015-08-04 09:47:08 +02002842 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02002843 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
2844 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002845 break;
2846
Radek Krejci76512572015-08-04 09:47:08 +02002847 case LYS_RPC:
Michal Vasko44fb6382016-06-29 11:12:27 +02002848 case LYS_ACTION:
2849 tpdf_size = ((struct lys_node_rpc_action *)parent)->tpdf_size;
2850 tpdf = ((struct lys_node_rpc_action *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002851 break;
2852
Radek Krejci76512572015-08-04 09:47:08 +02002853 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02002854 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
2855 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002856 break;
2857
Radek Krejci76512572015-08-04 09:47:08 +02002858 case LYS_INPUT:
2859 case LYS_OUTPUT:
Michal Vasko44fb6382016-06-29 11:12:27 +02002860 tpdf_size = ((struct lys_node_inout *)parent)->tpdf_size;
2861 tpdf = ((struct lys_node_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002862 break;
2863
2864 default:
Michal Vaskodcf98e62016-05-05 17:53:53 +02002865 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002866 continue;
2867 }
2868
2869 for (i = 0; i < tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002870 if (!strcmp(tpdf[i].name, name) && tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002871 match = &tpdf[i];
2872 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002873 }
2874 }
2875
Michal Vaskodcf98e62016-05-05 17:53:53 +02002876 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002877 }
Radek Krejcic071c542016-01-27 14:57:51 +01002878 } else {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002879 /* get module where to search */
Michal Vaskob6729c62015-10-21 12:09:47 +02002880 module = lys_get_import_module(module, NULL, 0, mod_name, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02002881 if (!module) {
2882 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002883 }
2884 }
2885
2886 /* search in top level typedefs */
2887 for (i = 0; i < module->tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002888 if (!strcmp(module->tpdf[i].name, name) && module->tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002889 match = &module->tpdf[i];
2890 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002891 }
2892 }
2893
2894 /* search in submodules */
Radek Krejcic071c542016-01-27 14:57:51 +01002895 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002896 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002897 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 +02002898 match = &module->inc[i].submodule->tpdf[j];
2899 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002900 }
2901 }
2902 }
2903
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002904 return EXIT_FAILURE;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002905
2906check_leafref:
2907 if (ret) {
2908 *ret = match;
2909 }
2910 if (match->type.base == LY_TYPE_LEAFREF) {
2911 while (!match->type.info.lref.path) {
2912 match = match->type.der;
2913 assert(match);
2914 }
Michal Vasko01c6fd22016-05-20 11:43:05 +02002915 }
2916 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002917}
2918
Michal Vasko1dca6882015-10-22 14:29:42 +02002919/**
2920 * @brief Check the default \p value of the \p type. Logs directly.
2921 *
2922 * @param[in] type Type definition to use.
2923 * @param[in] value Default value to check.
Michal Vasko56826402016-03-02 11:11:37 +01002924 * @param[in] module Type module.
Michal Vasko1dca6882015-10-22 14:29:42 +02002925 *
2926 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
2927 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002928static int
Radek Krejci48464ed2016-03-17 15:44:09 +01002929check_default(struct lys_type *type, const char *value, struct lys_module *module)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002930{
Radek Krejcibad2f172016-08-02 11:04:15 +02002931 struct lys_tpdf *base_tpdf = NULL;
Michal Vasko1dca6882015-10-22 14:29:42 +02002932 struct lyd_node_leaf_list node;
Radek Krejci37b756f2016-01-18 10:15:03 +01002933 int ret = EXIT_SUCCESS;
Michal Vasko1dca6882015-10-22 14:29:42 +02002934
Radek Krejcic13db382016-08-16 10:52:42 +02002935 if (type->base <= LY_TYPE_DER) {
Michal Vasko478c4652016-07-21 12:55:01 +02002936 /* the type was not resolved yet, nothing to do for now */
2937 return EXIT_FAILURE;
2938 }
2939
2940 if (!value) {
2941 /* we do not have a new default value, so is there any to check even, in some base type? */
2942 for (base_tpdf = type->der; base_tpdf->type.der; base_tpdf = base_tpdf->type.der) {
2943 if (base_tpdf->dflt) {
2944 value = base_tpdf->dflt;
2945 break;
2946 }
2947 }
2948
2949 if (!value) {
2950 /* no default value, nothing to check, all is well */
2951 return EXIT_SUCCESS;
2952 }
2953
2954 /* 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)? */
2955 switch (type->base) {
Michal Vasko478c4652016-07-21 12:55:01 +02002956 case LY_TYPE_IDENT:
2957 case LY_TYPE_INST:
2958 case LY_TYPE_LEAFREF:
2959 case LY_TYPE_BOOL:
2960 case LY_TYPE_EMPTY:
2961 /* these have no restrictions, so we would do the exact same work as the unres in the base typedef */
2962 return EXIT_SUCCESS;
Radek Krejcibad2f172016-08-02 11:04:15 +02002963 case LY_TYPE_BITS:
2964 /* the default value must match the restricted list of values, if the type was restricted */
2965 if (type->info.bits.count) {
2966 break;
2967 }
2968 return EXIT_SUCCESS;
2969 case LY_TYPE_ENUM:
2970 /* the default value must match the restricted list of values, if the type was restricted */
2971 if (type->info.enums.count) {
2972 break;
2973 }
2974 return EXIT_SUCCESS;
Michal Vasko478c4652016-07-21 12:55:01 +02002975 case LY_TYPE_DEC64:
2976 if (type->info.dec64.range) {
2977 break;
2978 }
2979 return EXIT_SUCCESS;
2980 case LY_TYPE_BINARY:
2981 if (type->info.binary.length) {
2982 break;
2983 }
2984 return EXIT_SUCCESS;
2985 case LY_TYPE_INT8:
2986 case LY_TYPE_INT16:
2987 case LY_TYPE_INT32:
2988 case LY_TYPE_INT64:
2989 case LY_TYPE_UINT8:
2990 case LY_TYPE_UINT16:
2991 case LY_TYPE_UINT32:
2992 case LY_TYPE_UINT64:
2993 if (type->info.num.range) {
2994 break;
2995 }
2996 return EXIT_SUCCESS;
2997 case LY_TYPE_STRING:
2998 if (type->info.str.length || type->info.str.patterns) {
2999 break;
3000 }
3001 return EXIT_SUCCESS;
3002 case LY_TYPE_UNION:
3003 /* way too much trouble learning whether we need to check the default again, so just do it */
3004 break;
3005 default:
3006 LOGINT;
3007 return -1;
3008 }
Radek Krejci55a161c2016-09-05 17:13:25 +02003009 } else if (type->base == LY_TYPE_EMPTY) {
3010 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "default", type->parent->name);
3011 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"empty\" data type cannot have a default value.");
3012 return -1;
Michal Vasko478c4652016-07-21 12:55:01 +02003013 }
3014
Michal Vasko1dca6882015-10-22 14:29:42 +02003015 /* dummy leaf */
Radek Krejci4fe36bd2016-03-17 16:47:16 +01003016 memset(&node, 0, sizeof node);
Michal Vasko1dca6882015-10-22 14:29:42 +02003017 node.value_str = value;
3018 node.value_type = type->base;
Radek Krejci37b756f2016-01-18 10:15:03 +01003019 node.schema = calloc(1, sizeof (struct lys_node_leaf));
Michal Vasko253035f2015-12-17 16:58:13 +01003020 if (!node.schema) {
3021 LOGMEM;
3022 return -1;
3023 }
Radek Krejcibad2f172016-08-02 11:04:15 +02003024 node.schema->name = strdup("fake-default");
Michal Vasko253035f2015-12-17 16:58:13 +01003025 if (!node.schema->name) {
3026 LOGMEM;
Michal Vaskof49eda02016-07-21 12:17:01 +02003027 free(node.schema);
Michal Vasko253035f2015-12-17 16:58:13 +01003028 return -1;
3029 }
Michal Vasko56826402016-03-02 11:11:37 +01003030 node.schema->module = module;
Radek Krejci37b756f2016-01-18 10:15:03 +01003031 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
Michal Vasko1dca6882015-10-22 14:29:42 +02003032
Radek Krejci37b756f2016-01-18 10:15:03 +01003033 if (type->base == LY_TYPE_LEAFREF) {
Michal Vasko1dca6882015-10-22 14:29:42 +02003034 if (!type->info.lref.target) {
3035 ret = EXIT_FAILURE;
3036 goto finish;
3037 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003038 ret = check_default(&type->info.lref.target->type, value, module);
Michal Vasko1dca6882015-10-22 14:29:42 +02003039
3040 } else if ((type->base == LY_TYPE_INST) || (type->base == LY_TYPE_IDENT)) {
3041 /* it was converted to JSON format before, nothing else sensible we can do */
3042
3043 } else {
Michal Vasko3767fb22016-07-21 12:10:57 +02003044 if (lyp_parse_value(&node, NULL, 1)) {
3045 ret = -1;
Radek Krejcibad2f172016-08-02 11:04:15 +02003046 if (base_tpdf) {
3047 /* default value was is defined in some base typedef */
3048 if ((type->base == LY_TYPE_BITS && type->der->type.der) ||
3049 (type->base == LY_TYPE_ENUM && type->der->type.der)) {
3050 /* we have refined bits/enums */
3051 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
3052 "Invalid value \"%s\" of the default statement inherited to \"%s\" from \"%s\" base type.",
3053 value, type->parent->name, base_tpdf->name);
3054 }
3055 }
Michal Vasko3767fb22016-07-21 12:10:57 +02003056 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003057 }
3058
3059finish:
3060 if (node.value_type == LY_TYPE_BITS) {
3061 free(node.value.bit);
3062 }
3063 free((char *)node.schema->name);
3064 free(node.schema);
3065
3066 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003067}
3068
Michal Vasko730dfdf2015-08-11 14:48:05 +02003069/**
3070 * @brief Check a key for mandatory attributes. Logs directly.
3071 *
3072 * @param[in] key The key to check.
3073 * @param[in] flags What flags to check.
3074 * @param[in] list The list of all the keys.
3075 * @param[in] index Index of the key in the key list.
3076 * @param[in] name The name of the keys.
3077 * @param[in] len The name length.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003078 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003079 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003080 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003081static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003082check_key(struct lys_node_list *list, int index, const char *name, int len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003083{
Radek Krejciadb57612016-02-16 13:34:34 +01003084 struct lys_node_leaf *key = list->keys[index];
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003085 char *dup = NULL;
3086 int j;
3087
3088 /* existence */
3089 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02003090 if (name[len] != '\0') {
3091 dup = strdup(name);
Michal Vasko253035f2015-12-17 16:58:13 +01003092 if (!dup) {
3093 LOGMEM;
3094 return -1;
3095 }
Michal Vaskof02e3742015-08-05 16:27:02 +02003096 dup[len] = '\0';
3097 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003098 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003099 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, list, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003100 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003101 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003102 }
3103
3104 /* uniqueness */
3105 for (j = index - 1; j >= 0; j--) {
Radek Krejciadb57612016-02-16 13:34:34 +01003106 if (key == list->keys[j]) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003107 LOGVAL(LYE_KEY_DUP, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003108 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003109 }
3110 }
3111
3112 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02003113 if (key->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003114 LOGVAL(LYE_KEY_NLEAF, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003115 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003116 }
3117
3118 /* type of the leaf is not built-in empty */
Radek Krejcic3738db2016-09-15 15:51:21 +02003119 if (key->type.base == LY_TYPE_EMPTY && key->module->version < 2) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003120 LOGVAL(LYE_KEY_TYPE, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003121 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003122 }
3123
3124 /* config attribute is the same as of the list */
Radek Krejciadb57612016-02-16 13:34:34 +01003125 if ((list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003126 LOGVAL(LYE_KEY_CONFIG, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003127 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003128 }
3129
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003130 /* key is not placed from augment */
3131 if (key->parent->nodetype == LYS_AUGMENT) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003132 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, key, key->name);
3133 LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key inserted from augment.");
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003134 return -1;
3135 }
3136
Radek Krejci3f21ada2016-08-01 13:34:31 +02003137 /* key is not when/if-feature -conditional */
3138 j = 0;
3139 if (key->when || (key->iffeature_size && (j = 1))) {
3140 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, key, j ? "if-feature" : "when", "leaf");
3141 LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key definition cannot depend on a \"%s\" condition.",
3142 j ? "if-feature" : "when");
Radek Krejci581ce772015-11-10 17:22:40 +01003143 return -1;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003144 }
3145
Michal Vasko0b85aa82016-03-07 14:37:43 +01003146 return EXIT_SUCCESS;
Michal Vasko184521f2015-09-24 13:14:26 +02003147}
Michal Vasko730dfdf2015-08-11 14:48:05 +02003148
3149/**
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003150 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003151 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003152 * @param[in] parent The parent node of the unique structure.
Michal Vasko0b85aa82016-03-07 14:37:43 +01003153 * @param[in] uniq_str_path One path from the unique string.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003154 *
3155 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
3156 */
3157int
Radek Krejcid09d1a52016-08-11 14:05:45 +02003158resolve_unique(struct lys_node *parent, const char *uniq_str_path, uint8_t *trg_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003159{
Radek Krejci581ce772015-11-10 17:22:40 +01003160 int rc;
Michal Vasko1e62a092015-12-01 12:27:20 +01003161 const struct lys_node *leaf = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003162
Radek Krejcif3c71de2016-04-11 12:45:46 +02003163 rc = resolve_descendant_schema_nodeid(uniq_str_path, parent->child, LYS_LEAF, 1, 1, &leaf);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003164 if (rc || !leaf) {
Michal Vasko0b85aa82016-03-07 14:37:43 +01003165 if (rc) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003166 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003167 if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003168 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, parent, uniq_str_path[rc - 1], &uniq_str_path[rc - 1]);
Radek Krejcif3c71de2016-04-11 12:45:46 +02003169 } else if (rc == -2) {
Michal Vaskoc66c6d82016-04-12 11:37:31 +02003170 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Unique argument references list.");
Radek Krejci581ce772015-11-10 17:22:40 +01003171 }
Michal Vasko0b85aa82016-03-07 14:37:43 +01003172 rc = -1;
Michal Vasko0b85aa82016-03-07 14:37:43 +01003173 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01003174 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3175 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target leaf not found.");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003176 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003177 }
Radek Krejci581ce772015-11-10 17:22:40 +01003178 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003179 }
Michal Vasko9bb061b2016-02-12 11:00:19 +01003180 if (leaf->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003181 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3182 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target is not a leaf.");
Radek Krejcid09d1a52016-08-11 14:05:45 +02003183 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003184 }
3185
Radek Krejcicf509982015-12-15 09:22:44 +01003186 /* check status */
Radek Krejci48464ed2016-03-17 15:44:09 +01003187 if (lyp_check_status(parent->flags, parent->module, parent->name, leaf->flags, leaf->module, leaf->name, leaf)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003188 return -1;
3189 }
3190
Radek Krejcid09d1a52016-08-11 14:05:45 +02003191 /* check that all unique's targets are of the same config type */
3192 if (*trg_type) {
3193 if (((*trg_type == 1) && (leaf->flags & LYS_CONFIG_R)) || ((*trg_type == 2) && (leaf->flags & LYS_CONFIG_W))) {
3194 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3195 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent,
3196 "Leaf \"%s\" referenced in unique statement is config %s, but previous referenced leaf is config %s.",
3197 uniq_str_path, *trg_type == 1 ? "false" : "true", *trg_type == 1 ? "true" : "false");
3198 return -1;
3199 }
3200 } else {
3201 /* first unique */
3202 if (leaf->flags & LYS_CONFIG_W) {
3203 *trg_type = 1;
3204 } else {
3205 *trg_type = 2;
3206 }
3207 }
3208
Radek Krejcica7efb72016-01-18 13:06:01 +01003209 /* set leaf's unique flag */
3210 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
3211
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003212 return EXIT_SUCCESS;
3213
3214error:
3215
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003216 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003217}
3218
Radek Krejci0c0086a2016-03-24 15:20:28 +01003219void
Michal Vasko23b61ec2015-08-19 11:19:50 +02003220unres_data_del(struct unres_data *unres, uint32_t i)
3221{
3222 /* there are items after the one deleted */
3223 if (i+1 < unres->count) {
3224 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02003225 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003226
3227 /* deleting the last item */
3228 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02003229 free(unres->node);
3230 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003231 }
3232
3233 /* if there are no items after and it is not the last one, just move the counter */
3234 --unres->count;
3235}
3236
Michal Vasko0491ab32015-08-19 14:28:29 +02003237/**
3238 * @brief Resolve (find) a data node from a specific module. Does not log.
3239 *
3240 * @param[in] mod Module to search in.
3241 * @param[in] name Name of the data node.
3242 * @param[in] nam_len Length of the name.
3243 * @param[in] start Data node to start the search from.
3244 * @param[in,out] parents Resolved nodes. If there are some parents,
3245 * they are replaced (!!) with the resolvents.
3246 *
Michal Vasko2471e7f2016-04-11 11:00:15 +02003247 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko0491ab32015-08-19 14:28:29 +02003248 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003249static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003250resolve_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 +02003251{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003252 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02003253 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003254 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003255
Michal Vasko23b61ec2015-08-19 11:19:50 +02003256 if (!parents->count) {
3257 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003258 parents->node = malloc(sizeof *parents->node);
Michal Vasko253035f2015-12-17 16:58:13 +01003259 if (!parents->node) {
3260 LOGMEM;
Michal Vasko2471e7f2016-04-11 11:00:15 +02003261 return -1;
Michal Vasko253035f2015-12-17 16:58:13 +01003262 }
Michal Vaskocf024702015-10-08 15:01:42 +02003263 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003264 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003265 for (i = 0; i < parents->count;) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02003266 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003267 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003268 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003269 continue;
3270 }
3271 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02003272 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003273 if (node->schema->module == mod && !strncmp(node->schema->name, name, nam_len)
3274 && node->schema->name[nam_len] == '\0') {
3275 /* matching target */
3276 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02003277 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02003278 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003279 flag = 1;
3280 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02003281 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003282 ++parents->count;
Michal Vasko253035f2015-12-17 16:58:13 +01003283 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
3284 if (!parents->node) {
3285 return EXIT_FAILURE;
3286 }
Michal Vaskocf024702015-10-08 15:01:42 +02003287 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003288 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003289 }
3290 }
3291 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003292
3293 if (!flag) {
3294 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003295 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02003296 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003297 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02003298 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003299 }
3300
Michal Vasko0491ab32015-08-19 14:28:29 +02003301 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02003302}
3303
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003304/**
3305 * @brief Resolve (find) a data node. Does not log.
3306 *
Radek Krejci581ce772015-11-10 17:22:40 +01003307 * @param[in] mod_name Module name of the data node.
3308 * @param[in] mod_name_len Length of the module name.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003309 * @param[in] name Name of the data node.
3310 * @param[in] nam_len Length of the name.
3311 * @param[in] start Data node to start the search from.
3312 * @param[in,out] parents Resolved nodes. If there are some parents,
3313 * they are replaced (!!) with the resolvents.
3314 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003315 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003316 */
Radek Krejcic5090c32015-08-12 09:46:19 +02003317static int
Radek Krejci581ce772015-11-10 17:22:40 +01003318resolve_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 +02003319 struct unres_data *parents)
Radek Krejcic5090c32015-08-12 09:46:19 +02003320{
Michal Vasko1e62a092015-12-01 12:27:20 +01003321 const struct lys_module *mod;
Michal Vasko31fc3672015-10-21 12:08:13 +02003322 char *str;
Radek Krejcic5090c32015-08-12 09:46:19 +02003323
Michal Vasko23b61ec2015-08-19 11:19:50 +02003324 assert(start);
3325
Michal Vasko31fc3672015-10-21 12:08:13 +02003326 if (mod_name) {
3327 /* we have mod_name, find appropriate module */
3328 str = strndup(mod_name, mod_name_len);
Michal Vasko253035f2015-12-17 16:58:13 +01003329 if (!str) {
3330 LOGMEM;
3331 return -1;
3332 }
Michal Vasko31fc3672015-10-21 12:08:13 +02003333 mod = ly_ctx_get_module(start->schema->module->ctx, str, NULL);
3334 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02003335 if (!mod) {
3336 /* invalid prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003337 return -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02003338 }
3339 } else {
3340 /* no prefix, module is the same as of current node */
3341 mod = start->schema->module;
3342 }
3343
3344 return resolve_data(mod, name, name_len, start, parents);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003345}
3346
Michal Vasko730dfdf2015-08-11 14:48:05 +02003347/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003348 * @brief Resolve a path predicate (leafref) in JSON data context. Logs directly
Radek Krejci48464ed2016-03-17 15:44:09 +01003349 * only specific errors, general no-resolvent error is left to the caller.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003350 *
Michal Vaskobb211122015-08-19 14:03:11 +02003351 * @param[in] pred Predicate to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003352 * @param[in] node Node from which the predicate is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02003353 * @param[in,out] node_match Nodes satisfying the restriction
3354 * without the predicate. Nodes not
3355 * satisfying the predicate are removed.
Michal Vasko0491ab32015-08-19 14:28:29 +02003356 * @param[out] parsed Number of characters parsed, negative on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003357 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003358 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003359 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003360static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003361resolve_path_predicate_data(const char *pred, struct lyd_node *node, struct unres_data *node_match,
Radek Krejci010e54b2016-03-15 09:40:34 +01003362 int *parsed)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003363{
Michal Vasko730dfdf2015-08-11 14:48:05 +02003364 /* ... /node[source = destination] ... */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003365 struct unres_data source_match, dest_match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003366 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vasko0491ab32015-08-19 14:28:29 +02003367 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed_loc = 0, pke_parsed = 0;
3368 int has_predicate, dest_parent_times, i, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003369 uint32_t j;
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003370 struct lyd_node_leaf_list *leaf_dst, *leaf_src;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003371
3372 source_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003373 source_match.node = malloc(sizeof *source_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003374 if (!source_match.node) {
3375 LOGMEM;
3376 return -1;
3377 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003378 dest_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003379 dest_match.node = malloc(sizeof *dest_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003380 if (!dest_match.node) {
3381 LOGMEM;
3382 return -1;
3383 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003384
3385 do {
3386 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
3387 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003388 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, pred[-i], &pred[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003389 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003390 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003391 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003392 parsed_loc += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003393 pred += i;
3394
Michal Vasko23b61ec2015-08-19 11:19:50 +02003395 for (j = 0; j < node_match->count;) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003396 /* source */
Michal Vaskocf024702015-10-08 15:01:42 +02003397 source_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02003398
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003399 /* must be leaf (key of a list) */
Radek Krejci581ce772015-11-10 17:22:40 +01003400 if ((rc = resolve_data_node(sour_pref, sour_pref_len, source, sour_len, node_match->node[j],
Michal Vaskocf024702015-10-08 15:01:42 +02003401 &source_match)) || (source_match.count != 1) || (source_match.node[0]->schema->nodetype != LYS_LEAF)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003402 i = 0;
3403 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003404 }
3405
3406 /* destination */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003407 dest_match.node[0] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003408 dest_parent_times = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003409 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3410 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003411 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003412 rc = -1;
3413 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003414 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003415 pke_parsed = i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003416 for (i = 0; i < dest_parent_times; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02003417 dest_match.node[0] = dest_match.node[0]->parent;
3418 if (!dest_match.node[0]) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003419 i = 0;
Michal Vasko0491ab32015-08-19 14:28:29 +02003420 rc = EXIT_FAILURE;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003421 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003422 }
3423 }
3424 while (1) {
Radek Krejci581ce772015-11-10 17:22:40 +01003425 if ((rc = resolve_data_node(dest_pref, dest_pref_len, dest, dest_len, dest_match.node[0],
Michal Vasko0491ab32015-08-19 14:28:29 +02003426 &dest_match)) || (dest_match.count != 1)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003427 i = 0;
3428 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003429 }
3430
3431 if (pke_len == pke_parsed) {
3432 break;
3433 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003434 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 +02003435 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003436 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003437 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003438 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003439 }
3440 pke_parsed += i;
3441 }
3442
3443 /* check match between source and destination nodes */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003444 leaf_dst = (struct lyd_node_leaf_list *)dest_match.node[0];
3445 while (leaf_dst->value_type == LY_TYPE_LEAFREF) {
3446 leaf_dst = (struct lyd_node_leaf_list *)leaf_dst->value.leafref;
3447 }
3448 leaf_src = (struct lyd_node_leaf_list *)source_match.node[0];
3449 while (leaf_src->value_type == LY_TYPE_LEAFREF) {
3450 leaf_src = (struct lyd_node_leaf_list *)leaf_src->value.leafref;
3451 }
3452 if (leaf_src->value_type != leaf_dst->value_type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003453 goto remove_leafref;
3454 }
3455
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003456 if (!ly_strequal(leaf_src->value_str, leaf_dst->value_str, 1)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003457 goto remove_leafref;
3458 }
3459
3460 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003461 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003462 continue;
3463
3464remove_leafref:
3465 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003466 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003467 }
3468 } while (has_predicate);
3469
Michal Vaskocf024702015-10-08 15:01:42 +02003470 free(source_match.node);
3471 free(dest_match.node);
Michal Vasko0491ab32015-08-19 14:28:29 +02003472 if (parsed) {
3473 *parsed = parsed_loc;
3474 }
3475 return EXIT_SUCCESS;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003476
3477error:
3478
3479 if (source_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003480 free(source_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003481 }
3482 if (dest_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003483 free(dest_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003484 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003485 if (parsed) {
3486 *parsed = -parsed_loc+i;
3487 }
3488 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003489}
3490
Michal Vasko730dfdf2015-08-11 14:48:05 +02003491/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003492 * @brief Resolve a path (leafref) in JSON data context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003493 *
Michal Vaskocf024702015-10-08 15:01:42 +02003494 * @param[in] node Leafref data node.
Michal Vasko23b61ec2015-08-19 11:19:50 +02003495 * @param[in] path Path of the leafref.
Radek Krejci48464ed2016-03-17 15:44:09 +01003496 * @param[out] ret Matching nodes. Expects an empty, but allocated structure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003497 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003498 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003499 */
Michal Vasko184521f2015-09-24 13:14:26 +02003500static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003501resolve_path_arg_data(struct lyd_node *node, const char *path, struct unres_data *ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003502{
Radek Krejci71b795b2015-08-10 16:20:39 +02003503 struct lyd_node *data = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003504 const char *prefix, *name;
Michal Vasko0491ab32015-08-19 14:28:29 +02003505 int pref_len, nam_len, has_predicate, parent_times, i, parsed, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003506 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003507
Michal Vaskocf024702015-10-08 15:01:42 +02003508 assert(node && path && ret && !ret->count);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003509
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003510 parent_times = 0;
Michal Vaskod9173342015-08-17 14:35:36 +02003511 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003512
3513 /* searching for nodeset */
3514 do {
3515 if ((i = parse_path_arg(path, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003516 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path[-i], &path[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003517 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003518 goto error;
3519 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003520 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003521 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003522
Michal Vasko23b61ec2015-08-19 11:19:50 +02003523 if (!ret->count) {
Michal Vaskobfd98e62016-09-02 09:50:05 +02003524 if (parent_times > 0) {
3525 data = node;
3526 for (i = 1; i < parent_times; ++i) {
3527 data = data->parent;
Michal Vasko253035f2015-12-17 16:58:13 +01003528 }
Michal Vaskobfd98e62016-09-02 09:50:05 +02003529 } else if (!parent_times) {
3530 data = node->child;
3531 } else {
3532 /* absolute path */
3533 for (data = node; data->parent; data = data->parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003534 }
3535
Michal Vaskobfd98e62016-09-02 09:50:05 +02003536 /* we may still be parsing it and the pointer is not correct yet */
3537 if (data->prev) {
3538 while (data->prev->next) {
3539 data = data->prev;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003540 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003541 }
3542 }
3543
3544 /* node identifier */
Radek Krejci581ce772015-11-10 17:22:40 +01003545 if ((rc = resolve_data_node(prefix, pref_len, name, nam_len, data, ret))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003546 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003547 LOGVAL(LYE_INELEM_LEN, LY_VLOG_LYD, node, nam_len, name);
Michal Vasko184521f2015-09-24 13:14:26 +02003548 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003549 goto error;
3550 }
3551
3552 if (has_predicate) {
3553 /* we have predicate, so the current results must be lists */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003554 for (j = 0; j < ret->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02003555 if (ret->node[j]->schema->nodetype == LYS_LIST &&
3556 ((struct lys_node_list *)ret->node[0]->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003557 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003558 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003559 continue;
3560 }
3561
3562 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003563 unres_data_del(ret, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003564 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003565 if ((rc = resolve_path_predicate_data(path, node, ret, &i))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003566 if (rc == -1) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003567 LOGVAL(LYE_NORESOLV, LY_VLOG_LYD, node, "leafref", path);
Michal Vasko184521f2015-09-24 13:14:26 +02003568 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003569 goto error;
3570 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003571 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003572 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003573
Michal Vasko23b61ec2015-08-19 11:19:50 +02003574 if (!ret->count) {
Michal Vasko0491ab32015-08-19 14:28:29 +02003575 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003576 goto error;
3577 }
3578 }
3579 } while (path[0] != '\0');
3580
Michal Vaskof02e3742015-08-05 16:27:02 +02003581 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003582
3583error:
3584
Michal Vaskocf024702015-10-08 15:01:42 +02003585 free(ret->node);
3586 ret->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003587 ret->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003588
Michal Vasko0491ab32015-08-19 14:28:29 +02003589 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003590}
3591
Michal Vaskoe27516a2016-10-10 17:55:31 +00003592static int
3593resolve_path_arg_schema_valid_dep_flag(const struct lys_node *op_node, const struct lys_node *first_node, int abs_path)
3594{
3595 int dep1, dep2;
3596 const struct lys_node *node;
3597
3598 if (lys_parent(op_node)) {
3599 /* inner operation (notif/action) */
3600 if (abs_path) {
3601 return 1;
3602 } else {
3603 /* compare depth of both nodes */
3604 for (dep1 = 0, node = op_node; lys_parent(node); node = lys_parent(node));
3605 for (dep2 = 0, node = first_node; lys_parent(node); node = lys_parent(node));
3606 if ((dep2 > dep1) || ((dep2 == dep1) && (op_node != first_node))) {
3607 return 1;
3608 }
3609 }
3610 } else {
3611 /* top-level operation (notif/rpc) */
3612 if (op_node != first_node) {
3613 return 1;
3614 }
3615 }
3616
3617 return 0;
3618}
3619
Michal Vasko730dfdf2015-08-11 14:48:05 +02003620/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003621 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003622 *
Michal Vaskobb211122015-08-19 14:03:11 +02003623 * @param[in] path Path to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003624 * @param[in] context_node Predicate context node (where the predicate is placed).
3625 * @param[in] parent Path context node (where the path begins/is placed).
Michal Vaskoe27516a2016-10-10 17:55:31 +00003626 * @param[in] op_node Optional node if the leafref is in an operation (action/rpc/notif).
Michal Vasko730dfdf2015-08-11 14:48:05 +02003627 *
Michal Vasko184521f2015-09-24 13:14:26 +02003628 * @return 0 on forward reference, otherwise the number
3629 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003630 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003631 */
Michal Vasko1f76a282015-08-04 16:16:53 +02003632static int
Radek Krejciadb57612016-02-16 13:34:34 +01003633resolve_path_predicate_schema(const char *path, const struct lys_node *context_node,
Michal Vaskoe27516a2016-10-10 17:55:31 +00003634 struct lys_node *parent, const struct lys_node *op_node)
Michal Vasko1f76a282015-08-04 16:16:53 +02003635{
Michal Vasko1e62a092015-12-01 12:27:20 +01003636 const struct lys_node *src_node, *dst_node;
Michal Vasko1f76a282015-08-04 16:16:53 +02003637 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vasko6966ea62016-10-21 15:19:30 +02003638 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, pke_parsed, parsed = 0;
3639 int has_predicate, dest_parent_times, i, rc, first_iter;
Michal Vasko1f76a282015-08-04 16:16:53 +02003640
3641 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02003642 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02003643 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003644 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003645 return -parsed+i;
3646 }
3647 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003648 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02003649
Michal Vasko58090902015-08-13 14:04:15 +02003650 /* source (must be leaf) */
Michal Vasko36cbaa42015-12-14 13:15:48 +01003651 if (!sour_pref) {
Radek Krejciadb57612016-02-16 13:34:34 +01003652 sour_pref = context_node->module->name;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003653 }
Radek Krejciadb57612016-02-16 13:34:34 +01003654 rc = lys_get_sibling(context_node->child, sour_pref, sour_pref_len, source, sour_len,
Michal Vasko59ad4582016-09-16 13:15:41 +02003655 LYS_LEAF | LYS_LEAFLIST | LYS_AUGMENT, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003656 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003657 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02003658 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003659 }
3660
3661 /* destination */
Michal Vasko6966ea62016-10-21 15:19:30 +02003662 dest_parent_times = 0;
3663 pke_parsed = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003664 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3665 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003666 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 +02003667 return -parsed;
3668 }
3669 pke_parsed += i;
3670
Radek Krejciadb57612016-02-16 13:34:34 +01003671 for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
Michal Vaskofbaead72016-10-07 10:54:48 +02003672 /* path is supposed to be evaluated in data tree, so we have to skip
3673 * all schema nodes that cannot be instantiated in data tree */
3674 for (dst_node = lys_parent(dst_node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003675 dst_node && !(dst_node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Michal Vaskofbaead72016-10-07 10:54:48 +02003676 dst_node = lys_parent(dst_node));
3677
Michal Vasko1f76a282015-08-04 16:16:53 +02003678 if (!dst_node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003679 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003680 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003681 }
3682 }
Michal Vaskoe27516a2016-10-10 17:55:31 +00003683 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003684 while (1) {
Michal Vasko36cbaa42015-12-14 13:15:48 +01003685 if (!dest_pref) {
3686 dest_pref = dst_node->module->name;
3687 }
3688 rc = lys_get_sibling(dst_node->child, dest_pref, dest_pref_len, dest, dest_len,
Michal Vasko165dc4a2015-10-23 09:44:27 +02003689 LYS_CONTAINER | LYS_LIST | LYS_LEAF | LYS_AUGMENT, &dst_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003690 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003691 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003692 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003693 }
3694
Michal Vaskoe27516a2016-10-10 17:55:31 +00003695 if (first_iter) {
3696 if (resolve_path_arg_schema_valid_dep_flag(op_node, dst_node, 0)) {
3697 parent->flags |= LYS_VALID_DEP;
3698 }
3699 first_iter = 0;
3700 }
3701
Michal Vasko1f76a282015-08-04 16:16:53 +02003702 if (pke_len == pke_parsed) {
3703 break;
3704 }
3705
3706 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
3707 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003708 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent,
Radek Krejciadb57612016-02-16 13:34:34 +01003709 (path_key_expr+pke_parsed)[-i], (path_key_expr+pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003710 return -parsed;
3711 }
3712 pke_parsed += i;
3713 }
3714
3715 /* check source - dest match */
Michal Vasko59ad4582016-09-16 13:15:41 +02003716 if (dst_node->nodetype != src_node->nodetype) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003717 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko59ad4582016-09-16 13:15:41 +02003718 LOGVAL(LYE_SPEC, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "Destination node is not a %s, but a %s.",
3719 strnodetype(src_node->nodetype), strnodetype(dst_node->nodetype));
Michal Vasko184521f2015-09-24 13:14:26 +02003720 return -parsed;
3721 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003722 } while (has_predicate);
3723
3724 return parsed;
3725}
3726
Michal Vasko730dfdf2015-08-11 14:48:05 +02003727/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003728 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003729 *
Michal Vaskobb211122015-08-19 14:03:11 +02003730 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003731 * @param[in] parent_node Parent of the leafref.
Radek Krejci2f12f852016-01-08 12:59:57 +01003732 * @param[in] parent_tpdf Flag if the parent node is actually typedef, in that case the path
3733 * has to contain absolute path
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003734 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003735 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003736 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003737 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003738static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003739resolve_path_arg_schema(const char *path, struct lys_node *parent, int parent_tpdf,
Michal Vasko36cbaa42015-12-14 13:15:48 +01003740 const struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02003741{
Michal Vaskoe27516a2016-10-10 17:55:31 +00003742 const struct lys_node *node, *op_node = NULL;
Radek Krejci27fe55e2016-09-13 17:13:35 +02003743 const struct lys_module *mod, *mod2;
Michal Vasko1f76a282015-08-04 16:16:53 +02003744 const char *id, *prefix, *name;
3745 int pref_len, nam_len, parent_times, has_predicate;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003746 int i, first_iter, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02003747
Michal Vasko184521f2015-09-24 13:14:26 +02003748 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003749 parent_times = 0;
3750 id = path;
3751
Michal Vaskoe27516a2016-10-10 17:55:31 +00003752 /* find operation schema we are in, if applicable */
Michal Vaskoe9914d12016-10-07 14:32:37 +02003753 if (!parent_tpdf) {
Michal Vaskoe27516a2016-10-10 17:55:31 +00003754 for (op_node = lys_parent(parent);
3755 op_node && !(op_node->nodetype & (LYS_ACTION | LYS_NOTIF | LYS_RPC));
3756 op_node = lys_parent(op_node));
Michal Vaskoe9914d12016-10-07 14:32:37 +02003757 }
3758
Radek Krejci27fe55e2016-09-13 17:13:35 +02003759 mod2 = lys_node_module(parent);
Michal Vasko1f76a282015-08-04 16:16:53 +02003760 do {
3761 if ((i = parse_path_arg(id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003762 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 +02003763 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003764 }
3765 id += i;
3766
Michal Vasko184521f2015-09-24 13:14:26 +02003767 if (first_iter) {
Michal Vasko1f76a282015-08-04 16:16:53 +02003768 if (parent_times == -1) {
Radek Krejcic071c542016-01-27 14:57:51 +01003769 /* resolve prefix of the module */
Radek Krejciadb57612016-02-16 13:34:34 +01003770 mod = lys_get_import_module(parent->module, NULL, 0, prefix, pref_len);
Radek Krejci0fa54e92016-09-14 14:01:05 +02003771 mod = lys_get_implemented_module(mod);
Radek Krejcic071c542016-01-27 14:57:51 +01003772 /* get start node */
3773 node = mod ? mod->data : NULL;
Michal Vasko58090902015-08-13 14:04:15 +02003774 if (!node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003775 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3776 "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003777 return EXIT_FAILURE;
Michal Vasko58090902015-08-13 14:04:15 +02003778 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003779 } else if (parent_times > 0) {
Radek Krejci2f12f852016-01-08 12:59:57 +01003780 if (parent_tpdf) {
3781 /* the path is not allowed to contain relative path since we are in top level typedef */
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003782 LOGVAL(LYE_NORESOLV, 0, NULL, "leafref", path);
Radek Krejci2f12f852016-01-08 12:59:57 +01003783 return -1;
3784 }
3785
Michal Vasko94458082016-10-07 14:34:36 +02003786 /* we are looking for a sibling of a node, node it's parent (that is why parent_times - 1) */
3787 for (i = 0, node = parent; i < parent_times - 1; i++) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02003788 /* path is supposed to be evaluated in data tree, so we have to skip
3789 * all schema nodes that cannot be instantiated in data tree */
3790 for (node = lys_parent(node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003791 node && !(node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Radek Krejci3a5501d2016-07-18 22:03:34 +02003792 node = lys_parent(node));
3793
Michal Vasko1f76a282015-08-04 16:16:53 +02003794 if (!node) {
Michal Vaskoe9914d12016-10-07 14:32:37 +02003795 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003796 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003797 }
3798 }
Michal Vaskoe01eca52015-08-13 14:42:02 +02003799 } else {
3800 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003801 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003802 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003803 } else {
Michal Vasko7dc71d02016-03-15 10:42:28 +01003804 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02003805 if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko2f5aceb2016-03-22 10:24:14 +01003806 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 +01003807 return -1;
3808 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003809 node = node->child;
Radek Krejci6892c272016-10-18 20:40:06 +02003810 if (!node) {
3811 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3812 "leafref", path);
3813 return EXIT_FAILURE;
3814 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003815 }
3816
Michal Vasko4f0dad02016-02-15 14:08:23 +01003817 if (!prefix) {
Radek Krejciadb57612016-02-16 13:34:34 +01003818 prefix = lys_node_module(parent)->name;
Michal Vasko4f0dad02016-02-15 14:08:23 +01003819 }
3820
Michal Vasko36cbaa42015-12-14 13:15:48 +01003821 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 +02003822 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003823 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko7a55bea2016-05-02 14:51:20 +02003824 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003825 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003826
Michal Vaskoe27516a2016-10-10 17:55:31 +00003827 if (first_iter) {
3828 /* set external dependency flag, we can decide based on the first found node */
3829 if (!parent_tpdf && op_node && parent_times &&
3830 resolve_path_arg_schema_valid_dep_flag(op_node, node, (parent_times == -1 ? 1 : 0))) {
3831 parent->flags |= LYS_VALID_DEP;
3832 }
3833 first_iter = 0;
3834 }
3835
Michal Vasko1f76a282015-08-04 16:16:53 +02003836 if (has_predicate) {
3837 /* we have predicate, so the current result must be list */
3838 if (node->nodetype != LYS_LIST) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003839 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003840 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003841 }
3842
Michal Vaskoe27516a2016-10-10 17:55:31 +00003843 i = resolve_path_predicate_schema(id, node, parent, op_node);
Radek Krejci27fe55e2016-09-13 17:13:35 +02003844 if (i <= 0) {
3845 if (i == 0) {
3846 return EXIT_FAILURE;
3847 } else { /* i < 0 */
3848 return -1;
3849 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003850 }
3851 id += i;
Michal Vasko6966ea62016-10-21 15:19:30 +02003852 has_predicate = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003853 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02003854 mod = lys_node_module(node);
3855 if (!mod->implemented && mod != mod2) {
3856 /* set the module implemented */
3857 if (lys_set_implemented(mod)) {
3858 return -1;
3859 }
3860 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003861 } while (id[0]);
3862
Michal Vaskoca917682016-07-25 11:00:37 +02003863 /* the target must be leaf or leaf-list (in YANG 1.1 only) */
3864 if ((node->nodetype != LYS_LEAF) && ((lys_node_module(parent)->version != 2) || (node->nodetype != LYS_LEAFLIST))) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003865 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Radek Krejcid47daf62016-08-22 16:23:38 +02003866 LOGVAL(LYE_SPEC, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3867 "Leafref target \"%s\" is not a leaf%s.", path,
3868 lys_node_module(parent)->version != 2 ? "" : " nor a leaf-list");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003869 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02003870 }
3871
Radek Krejcicf509982015-12-15 09:22:44 +01003872 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01003873 if (lyp_check_status(parent->flags, parent->module, parent->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01003874 node->flags, node->module, node->name, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003875 return -1;
3876 }
3877
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003878 if (ret) {
3879 *ret = node;
3880 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02003881
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003882 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02003883}
3884
Michal Vasko730dfdf2015-08-11 14:48:05 +02003885/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003886 * @brief Resolve instance-identifier predicate in JSON data format.
3887 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003888 *
Michal Vaskobb211122015-08-19 14:03:11 +02003889 * @param[in] pred Predicate to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003890 * @param[in,out] node_match Nodes matching the restriction without
3891 * the predicate. Nodes not satisfying
3892 * the predicate are removed.
3893 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003894 * @return Number of characters successfully parsed,
3895 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003896 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003897static int
Michal Vaskof39142b2015-10-21 11:40:05 +02003898resolve_predicate(const char *pred, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003899{
Michal Vasko730dfdf2015-08-11 14:48:05 +02003900 /* ... /node[target = value] ... */
Michal Vaskob2f40be2016-09-08 16:03:48 +02003901 struct lyd_node *target;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003902 const char *model, *name, *value;
Michal Vaskob2f40be2016-09-08 16:03:48 +02003903 int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed, pred_iter, k;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003904 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003905
Michal Vasko1f2cc332015-08-19 11:18:32 +02003906 assert(pred && node_match->count);
3907
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003908 idx = -1;
3909 parsed = 0;
3910
Michal Vaskob2f40be2016-09-08 16:03:48 +02003911 pred_iter = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003912 do {
Michal Vaskof39142b2015-10-21 11:40:05 +02003913 if ((i = parse_predicate(pred, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003914 return -parsed+i;
3915 }
3916 parsed += i;
3917 pred += i;
3918
3919 if (isdigit(name[0])) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02003920 /* pos */
3921 assert(!value);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003922 idx = atoi(name);
Michal Vaskob2f40be2016-09-08 16:03:48 +02003923 } else if (name[0] != '.') {
3924 /* list keys */
3925 if (pred_iter < 0) {
3926 pred_iter = 1;
3927 } else {
3928 ++pred_iter;
3929 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003930 }
3931
Michal Vaskof2f28a12016-09-09 12:43:06 +02003932 for (cur_idx = 1, j = 0; j < node_match->count; ++cur_idx) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003933 /* target */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003934 if (name[0] == '.') {
Michal Vaskob2f40be2016-09-08 16:03:48 +02003935 /* leaf-list value */
Michal Vaskocf024702015-10-08 15:01:42 +02003936 if (node_match->node[j]->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003937 goto remove_instid;
3938 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02003939
3940 target = node_match->node[j];
3941 /* check the value */
3942 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
3943 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
3944 goto remove_instid;
3945 }
3946
3947 } else if (!value) {
3948 /* keyless list position */
3949 if ((node_match->node[j]->schema->nodetype != LYS_LIST)
3950 || ((struct lys_node_list *)node_match->node[j]->schema)->keys) {
3951 goto remove_instid;
3952 }
3953
3954 if (idx != cur_idx) {
3955 goto remove_instid;
3956 }
3957
3958 } else {
3959 /* list key value */
Michal Vaskocf024702015-10-08 15:01:42 +02003960 if (node_match->node[j]->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003961 goto remove_instid;
3962 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02003963
3964 /* key module must match the list module */
3965 if (strncmp(node_match->node[j]->schema->module->name, model, mod_len)
3966 || node_match->node[j]->schema->module->name[mod_len]) {
3967 goto remove_instid;
3968 }
3969 /* find the key leaf */
Michal Vasko045182c2016-09-09 12:44:07 +02003970 for (k = 1, target = node_match->node[j]->child; target && (k < pred_iter); k++, target = target->next);
Michal Vaskob2f40be2016-09-08 16:03:48 +02003971 if (!target) {
3972 goto remove_instid;
3973 }
3974 if ((struct lys_node_leaf *)target->schema !=
3975 ((struct lys_node_list *)node_match->node[j]->schema)->keys[pred_iter - 1]) {
3976 goto remove_instid;
3977 }
3978
3979 /* check the value */
3980 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
3981 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
3982 goto remove_instid;
3983 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003984 }
3985
Michal Vaskob2f40be2016-09-08 16:03:48 +02003986 /* instid is ok, continue check with the next one */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003987 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003988 continue;
3989
3990remove_instid:
Michal Vaskob2f40be2016-09-08 16:03:48 +02003991 /* does not fulfill conditions, remove instid record */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003992 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003993 }
3994 } while (has_predicate);
3995
Michal Vaskob2f40be2016-09-08 16:03:48 +02003996 /* check that all list keys were specified */
3997 if ((pred_iter > 0) && node_match->count) {
Michal Vasko045182c2016-09-09 12:44:07 +02003998 j = 0;
3999 while (j < node_match->count) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004000 assert(node_match->node[j]->schema->nodetype == LYS_LIST);
4001 if (pred_iter < ((struct lys_node_list *)node_match->node[j]->schema)->keys_size) {
4002 /* not enough predicates, just remove the list instance */
4003 unres_data_del(node_match, j);
Michal Vasko045182c2016-09-09 12:44:07 +02004004 } else {
4005 ++j;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004006 }
4007 }
4008
4009 if (!node_match->count) {
4010 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier is missing some list keys.");
4011 }
4012 }
4013
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004014 return parsed;
4015}
4016
Michal Vasko730dfdf2015-08-11 14:48:05 +02004017/**
Michal Vaskof39142b2015-10-21 11:40:05 +02004018 * @brief Resolve instance-identifier in JSON data format. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004019 *
Radek Krejciadb57612016-02-16 13:34:34 +01004020 * @param[in] data Data node where the path is used
Michal Vasko730dfdf2015-08-11 14:48:05 +02004021 * @param[in] path Instance-identifier node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004022 *
Radek Krejcic5090c32015-08-12 09:46:19 +02004023 * @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 +02004024 */
Michal Vasko184521f2015-09-24 13:14:26 +02004025static struct lyd_node *
Radek Krejci48464ed2016-03-17 15:44:09 +01004026resolve_instid(struct lyd_node *data, const char *path)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004027{
Radek Krejcic5090c32015-08-12 09:46:19 +02004028 int i = 0, j;
4029 struct lyd_node *result = NULL;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004030 const struct lys_module *mod;
Radek Krejcic5090c32015-08-12 09:46:19 +02004031 struct ly_ctx *ctx = data->schema->module->ctx;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004032 const char *model, *name;
Radek Krejcic5090c32015-08-12 09:46:19 +02004033 char *str;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004034 int mod_len, name_len, has_predicate;
4035 struct unres_data node_match;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004036
4037 memset(&node_match, 0, sizeof node_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004038
Radek Krejcic5090c32015-08-12 09:46:19 +02004039 /* we need root to resolve absolute path */
4040 for (; data->parent; data = data->parent);
Michal Vaskodb9323c2015-10-16 10:32:44 +02004041 /* we're still parsing it and the pointer is not correct yet */
Michal Vasko0491ab32015-08-19 14:28:29 +02004042 if (data->prev) {
4043 for (; data->prev->next; data = data->prev);
4044 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004045
Radek Krejcic5090c32015-08-12 09:46:19 +02004046 /* search for the instance node */
4047 while (path[i]) {
Michal Vaskof39142b2015-10-21 11:40:05 +02004048 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
Radek Krejcic5090c32015-08-12 09:46:19 +02004049 if (j <= 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004050 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004051 goto error;
4052 }
Radek Krejcic5090c32015-08-12 09:46:19 +02004053 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02004054
Michal Vaskob2f40be2016-09-08 16:03:48 +02004055 str = strndup(model, mod_len);
4056 if (!str) {
4057 LOGMEM;
4058 goto error;
Radek Krejcic5090c32015-08-12 09:46:19 +02004059 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004060 mod = ly_ctx_get_module(ctx, str, NULL);
4061 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02004062
Michal Vasko1f2cc332015-08-19 11:18:32 +02004063 if (resolve_data(mod, name, name_len, data, &node_match)) {
Radek Krejcic5090c32015-08-12 09:46:19 +02004064 /* no instance exists */
4065 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004066 }
4067
4068 if (has_predicate) {
4069 /* we have predicate, so the current results must be list or leaf-list */
Michal Vaskof39142b2015-10-21 11:40:05 +02004070 j = resolve_predicate(&path[i], &node_match);
Radek Krejcic5090c32015-08-12 09:46:19 +02004071 if (j < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004072 LOGVAL(LYE_INPRED, LY_VLOG_LYD, data, &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004073 goto error;
4074 }
Michal Vasko1f2cc332015-08-19 11:18:32 +02004075 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02004076
Michal Vasko1f2cc332015-08-19 11:18:32 +02004077 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02004078 /* no instance exists */
4079 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004080 }
4081 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004082 }
4083
Michal Vasko1f2cc332015-08-19 11:18:32 +02004084 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02004085 /* no instance exists */
4086 return NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02004087 } else if (node_match.count > 1) {
Radek Krejcic5090c32015-08-12 09:46:19 +02004088 /* instance identifier must resolve to a single node */
Radek Krejci48464ed2016-03-17 15:44:09 +01004089 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
Michal Vaskod6adbaa2016-04-11 11:01:09 +02004090 goto error;
Radek Krejcic5090c32015-08-12 09:46:19 +02004091 } else {
4092 /* we have required result, remember it and cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02004093 result = node_match.node[0];
4094 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02004095 return result;
4096 }
4097
4098error:
Radek Krejcic5090c32015-08-12 09:46:19 +02004099 /* cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02004100 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02004101 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004102}
4103
Michal Vasko730dfdf2015-08-11 14:48:05 +02004104/**
Michal Vasko9e635ac2016-10-17 11:44:09 +02004105 * @brief Check all XPath expressions of a node (when and must), set LYS_XPATH_DEP flag if required.
4106 *
4107 * @param[in] node Node to examine.
4108 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
4109 */
4110static int
4111check_node_xpath(struct lys_node *node)
4112{
4113 struct lys_node *parent, *elem;
4114 struct lyxp_set set;
4115 uint32_t i;
4116 int rc;
4117
4118 parent = node;
4119 while (parent) {
4120 if (parent->nodetype == LYS_GROUPING) {
4121 /* unresolved grouping, skip for now (will be checked later) */
4122 return EXIT_SUCCESS;
4123 }
4124 if (parent->nodetype == LYS_AUGMENT) {
4125 if (!((struct lys_node_augment *)parent)->target) {
4126 /* uresolved augment, skip for now (will be checked later) */
4127 return EXIT_SUCCESS;
4128 } else {
4129 parent = ((struct lys_node_augment *)parent)->target;
4130 continue;
4131 }
4132 }
4133 parent = parent->parent;
4134 }
4135
4136 rc = lyxp_node_atomize(node, &set);
4137 if (rc) {
4138 return rc;
4139 }
4140
4141 for (parent = node; parent && !(parent->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); parent = lys_parent(parent));
4142
4143 for (i = 0; i < set.used; ++i) {
4144 /* skip roots'n'stuff */
4145 if (set.val.snodes[i].type == LYXP_NODE_ELEM) {
4146 /* XPath expression cannot reference "lower" status than the node that has the definition */
4147 if (lyp_check_status(node->flags, lys_node_module(node), node->name, set.val.snodes[i].snode->flags,
4148 lys_node_module(set.val.snodes[i].snode), set.val.snodes[i].snode->name, node)) {
4149 return -1;
4150 }
4151
4152 if (parent) {
4153 for (elem = set.val.snodes[i].snode; elem && (elem != parent); elem = lys_parent(elem));
4154 if (!elem) {
4155 /* not in node's RPC or notification subtree, set the flag */
4156 node->flags |= LYS_VALID_DEP;
4157 break;
4158 }
4159 }
4160 }
4161 }
4162
4163 free(set.val.snodes);
4164 return EXIT_SUCCESS;
4165}
4166
4167/**
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004168 * @brief Passes config flag down to children, skips nodes without config flags.
4169 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004170 *
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004171 * @param[in] node Siblings and their children to have flags changed.
Michal Vaskoe022a562016-09-27 14:24:15 +02004172 * @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 +02004173 * @param[in] flags Flags to assign to all the nodes.
Michal Vaskoa86508c2016-08-26 14:30:19 +02004174 *
4175 * @return 0 on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004176 */
Michal Vaskoa86508c2016-08-26 14:30:19 +02004177static int
Michal Vasko9e635ac2016-10-17 11:44:09 +02004178inherit_config_flag(struct lys_node *node, int flags, int clear, int check_list, int check_xpath)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004179{
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004180 assert(!(flags ^ (flags & LYS_CONFIG_MASK)));
Radek Krejci1d82ef62015-08-07 14:44:40 +02004181 LY_TREE_FOR(node, node) {
Michal Vasko9e635ac2016-10-17 11:44:09 +02004182 if (check_xpath && check_node_xpath(node)) {
4183 return -1;
4184 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004185 if (clear) {
4186 node->flags &= ~LYS_CONFIG_MASK;
Michal Vaskoc2a8d362016-09-29 08:50:13 +02004187 node->flags &= ~LYS_CONFIG_SET;
Michal Vaskoe022a562016-09-27 14:24:15 +02004188 } else {
4189 if (node->flags & LYS_CONFIG_SET) {
4190 /* skip nodes with an explicit config value */
4191 if ((flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
4192 LOGVAL(LYE_INARG, LY_VLOG_LYS, node, "true", "config");
4193 LOGVAL(LYE_SPEC, LY_VLOG_LYS, node, "State nodes cannot have configuration nodes as children.");
4194 return -1;
4195 }
4196 continue;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004197 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004198
4199 if (!(node->nodetype & (LYS_USES | LYS_GROUPING))) {
4200 node->flags = (node->flags & ~LYS_CONFIG_MASK) | flags;
4201 /* check that configuration lists have keys */
4202 if (check_list && (node->nodetype == LYS_LIST)
4203 && (node->flags & LYS_CONFIG_W) && !((struct lys_node_list *)node)->keys_size) {
4204 LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_LYS, node, "key", "list");
4205 return -1;
4206 }
4207 }
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004208 }
Radek Krejcibf2abff2016-08-23 15:51:52 +02004209 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vasko9e635ac2016-10-17 11:44:09 +02004210 if (inherit_config_flag(node->child, flags, clear, check_list, check_xpath)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004211 return -1;
4212 }
Radek Krejci3a5501d2016-07-18 22:03:34 +02004213 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004214 }
Michal Vaskoa86508c2016-08-26 14:30:19 +02004215
4216 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004217}
4218
Michal Vasko730dfdf2015-08-11 14:48:05 +02004219/**
Michal Vasko7178e692016-02-12 15:58:05 +01004220 * @brief Resolve augment target. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004221 *
Michal Vaskobb211122015-08-19 14:03:11 +02004222 * @param[in] aug Augment to use.
Michal Vasko3edeaf72016-02-11 13:17:43 +01004223 * @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 +02004224 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004225 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004226 */
Michal Vasko7178e692016-02-12 15:58:05 +01004227static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004228resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004229{
Michal Vaskoe022a562016-09-27 14:24:15 +02004230 int rc, clear_config;
Michal Vasko1d87a922015-08-21 12:57:16 +02004231 struct lys_node *sub;
Pavol Vican47319932016-08-29 09:14:47 +02004232 const struct lys_node *aug_target, *parent;
Radek Krejci27fe55e2016-09-13 17:13:35 +02004233 struct lys_module *mod;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004234
Michal Vasko15b36692016-08-26 15:29:54 +02004235 assert(aug && !aug->target);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004236
Michal Vasko15b36692016-08-26 15:29:54 +02004237 /* resolve target node */
4238 rc = resolve_augment_schema_nodeid(aug->target_name, siblings, (siblings ? NULL : aug->module), &aug_target);
4239 if (rc == -1) {
4240 return -1;
4241 }
4242 if (rc > 0) {
4243 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, aug, aug->target_name[rc - 1], &aug->target_name[rc - 1]);
4244 return -1;
4245 }
4246 if (!aug_target) {
4247 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
4248 return EXIT_FAILURE;
4249 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004250
Radek Krejci27fe55e2016-09-13 17:13:35 +02004251 /* check that we want to connect augment into its target */
4252 mod = lys_main_module(aug->module);
4253 if (!mod->implemented) {
4254 /* it must be augment only to the same module,
4255 * otherwise we do not apply augment in not-implemented
4256 * module. If the module is set to be implemented in future,
4257 * the augment is being resolved and checked again */
4258 for (sub = aug->target; sub; sub = lys_parent(sub)) {
4259 if (lys_node_module(sub) != mod) {
4260 /* this is not an implemented module and the augment
4261 * target some other module, so avoid its connecting
4262 * to the target */
4263 return EXIT_SUCCESS;
4264 }
4265 }
4266 }
4267
Michal Vasko15b36692016-08-26 15:29:54 +02004268 if (!aug->child) {
4269 /* nothing to do */
4270 LOGWRN("Augment \"%s\" without children.", aug->target_name);
Radek Krejci27fe55e2016-09-13 17:13:35 +02004271 goto success;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004272 }
4273
Michal Vaskod58d5962016-03-02 14:29:41 +01004274 /* check for mandatory nodes - if the target node is in another module
4275 * the added nodes cannot be mandatory
4276 */
Michal Vasko15b36692016-08-26 15:29:54 +02004277 if (!aug->parent && (lys_node_module((struct lys_node *)aug) != lys_node_module(aug_target))
Radek Krejcie00d2312016-08-12 15:27:49 +02004278 && (rc = lyp_check_mandatory_augment(aug))) {
4279 return rc;
Michal Vaskod58d5962016-03-02 14:29:41 +01004280 }
4281
Michal Vasko07e89ef2016-03-03 13:28:57 +01004282 /* check augment target type and then augment nodes type */
Michal Vasko15b36692016-08-26 15:29:54 +02004283 if (aug_target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF)) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004284 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004285 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES | LYS_CHOICE))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004286 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4287 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko15b36692016-08-26 15:29:54 +02004288 strnodetype(aug_target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004289 return -1;
4290 }
4291 }
Michal Vasko15b36692016-08-26 15:29:54 +02004292 } else if (aug_target->nodetype == LYS_CHOICE) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004293 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004294 if (!(sub->nodetype & (LYS_CASE | LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004295 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4296 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko15b36692016-08-26 15:29:54 +02004297 strnodetype(aug_target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004298 return -1;
4299 }
4300 }
4301 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01004302 LOGVAL(LYE_INARG, LY_VLOG_LYS, aug, aug->target_name, "target-node");
Michal Vasko15b36692016-08-26 15:29:54 +02004303 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Invalid augment target node type \"%s\".", strnodetype(aug_target->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004304 return -1;
4305 }
4306
Radek Krejcic071c542016-01-27 14:57:51 +01004307 /* check identifier uniqueness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02004308 LY_TREE_FOR(aug->child, sub) {
Michal Vasko15b36692016-08-26 15:29:54 +02004309 if (lys_check_id(sub, (struct lys_node *)aug_target, NULL)) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02004310 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02004311 }
4312 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004313
Michal Vasko15b36692016-08-26 15:29:54 +02004314 /* finally reconnect augmenting data into the target - add them to the target child list,
4315 * by setting aug->target we know the augment is fully resolved now */
4316 aug->target = (struct lys_node *)aug_target;
4317 if (aug->target->child) {
4318 sub = aug->target->child->prev; /* remember current target's last node */
4319 sub->next = aug->child; /* connect augmenting data after target's last node */
4320 aug->target->child->prev = aug->child->prev; /* new target's last node is last augmenting node */
4321 aug->child->prev = sub; /* finish connecting of both child lists */
4322 } else {
4323 aug->target->child = aug->child;
4324 }
4325
Michal Vasko9e635ac2016-10-17 11:44:09 +02004326 /* inherit config information from actual parent */
4327 for(parent = aug_target; parent && !(parent->nodetype & (LYS_NOTIF | LYS_INPUT | LYS_OUTPUT | LYS_RPC)); parent = lys_parent(parent));
4328 clear_config = (parent) ? 1 : 0;
4329 LY_TREE_FOR(aug->child, sub) {
4330 if (inherit_config_flag(sub, aug_target->flags & LYS_CONFIG_MASK, clear_config, 1, 1)) {
4331 return -1;
4332 }
4333 }
4334
Radek Krejci27fe55e2016-09-13 17:13:35 +02004335success:
4336 if (mod->implemented) {
4337 /* make target modules also implemented */
4338 for (sub = aug->target; sub; sub = lys_parent(sub)) {
4339 if (lys_set_implemented(sub->module)) {
4340 return -1;
4341 }
4342 }
4343 }
4344
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004345 return EXIT_SUCCESS;
4346}
4347
Michal Vasko730dfdf2015-08-11 14:48:05 +02004348/**
Pavol Vican855ca622016-09-05 13:07:54 +02004349 * @brief Resolve (find) choice default case. Does not log.
4350 *
4351 * @param[in] choic Choice to use.
4352 * @param[in] dflt Name of the default case.
4353 *
4354 * @return Pointer to the default node or NULL.
4355 */
4356static struct lys_node *
4357resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
4358{
4359 struct lys_node *child, *ret;
4360
4361 LY_TREE_FOR(choic->child, child) {
4362 if (child->nodetype == LYS_USES) {
4363 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
4364 if (ret) {
4365 return ret;
4366 }
4367 }
4368
4369 if (ly_strequal(child->name, dflt, 1) && (child->nodetype & (LYS_ANYDATA | LYS_CASE
Radek Krejci2f792db2016-09-12 10:52:33 +02004370 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE))) {
Pavol Vican855ca622016-09-05 13:07:54 +02004371 return child;
4372 }
4373 }
4374
4375 return NULL;
4376}
4377
4378/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02004379 * @brief Resolve uses, apply augments, refines. Logs directly.
4380 *
Michal Vaskobb211122015-08-19 14:03:11 +02004381 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004382 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004383 *
Michal Vaskodef0db12015-10-07 13:22:48 +02004384 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004385 */
Michal Vasko184521f2015-09-24 13:14:26 +02004386static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004387resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004388{
4389 struct ly_ctx *ctx;
Pavol Vican855ca622016-09-05 13:07:54 +02004390 struct lys_node *node = NULL, *next, *iter, **refine_nodes = NULL;
Pavol Vican55abd332016-07-12 15:54:49 +02004391 struct lys_node *node_aux, *parent, *tmp;
Radek Krejci200bf712016-08-16 17:11:04 +02004392 struct lys_node_leaflist *llist;
4393 struct lys_node_leaf *leaf;
Radek Krejci76512572015-08-04 09:47:08 +02004394 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004395 struct lys_restr *must, **old_must;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004396 struct lys_iffeature *iff, **old_iff;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004397 int i, j, k, rc, parent_config, clear_config, check_list, check_xpath;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004398 uint8_t size, *old_size;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004399 unsigned int usize, usize1, usize2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004400
Michal Vasko71e1aa82015-08-12 12:17:51 +02004401 assert(uses->grp);
Michal Vaskoe7708512016-03-11 10:26:55 +01004402 /* HACK just check that the grouping is resolved */
Michal Vaskodef0db12015-10-07 13:22:48 +02004403 assert(!uses->grp->nacm);
Michal Vasko71e1aa82015-08-12 12:17:51 +02004404
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004405 if (!uses->grp->child) {
4406 /* grouping without children, warning was already displayed */
4407 return EXIT_SUCCESS;
4408 }
4409
4410 /* get proper parent (config) flags */
4411 for (node_aux = lys_parent((struct lys_node *)uses); node_aux && (node_aux->nodetype == LYS_USES); node_aux = lys_parent(node_aux));
4412 if (node_aux) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004413 parent_config = node_aux->flags & LYS_CONFIG_MASK;
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004414 } else {
4415 /* default */
Michal Vaskoa86508c2016-08-26 14:30:19 +02004416 parent_config = LYS_CONFIG_W;
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004417 }
4418
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004419 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01004420 LY_TREE_FOR(uses->grp->child, node_aux) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004421 node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, uses->nacm, unres, 0);
Michal Vasko1e62a092015-12-01 12:27:20 +01004422 if (!node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004423 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, uses->grp->name, "uses");
4424 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Copying data from grouping failed.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004425 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004426 }
Pavol Vican55abd332016-07-12 15:54:49 +02004427 /* test the name of siblings */
4428 LY_TREE_FOR((uses->parent) ? uses->parent->child : lys_main_module(uses->module)->data, tmp) {
Pavol Vican2510ddc2016-07-18 16:23:44 +02004429 if (!(tmp->nodetype & (LYS_USES | LYS_GROUPING | LYS_CASE)) && ly_strequal(tmp->name, node_aux->name, 1)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004430 goto fail;
Pavol Vican55abd332016-07-12 15:54:49 +02004431 }
4432 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004433 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004434
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004435 ctx = uses->module->ctx;
Michal Vasko4bc590c2016-09-30 12:19:51 +02004436
4437 parent = node;
4438 while (parent && !(parent->nodetype & (LYS_NOTIF | LYS_INPUT | LYS_OUTPUT | LYS_RPC | LYS_GROUPING))) {
4439 if (parent->nodetype == LYS_AUGMENT) {
4440 if (!((struct lys_node_augment *)parent)->target) {
4441 break;
4442 } else {
4443 parent = ((struct lys_node_augment *)parent)->target;
4444 }
4445 } else {
4446 parent = parent->parent;
4447 }
4448 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004449 if (parent) {
Michal Vasko4bc590c2016-09-30 12:19:51 +02004450 if (parent->nodetype & (LYS_GROUPING | LYS_AUGMENT)) {
4451 /* we are still in some other unresolved grouping or augment, unable to check lists */
Michal Vaskoe022a562016-09-27 14:24:15 +02004452 check_list = 0;
4453 clear_config = 0;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004454 check_xpath = 0;
Michal Vaskoe022a562016-09-27 14:24:15 +02004455 } else {
4456 check_list = 0;
4457 clear_config = 1;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004458 check_xpath = 1;
Michal Vaskoe022a562016-09-27 14:24:15 +02004459 }
4460 } else {
4461 check_list = 1;
4462 clear_config = 0;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004463 check_xpath = 1;
Michal Vaskoe022a562016-09-27 14:24:15 +02004464 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004465
Michal Vaskoa86508c2016-08-26 14:30:19 +02004466 if (parent_config) {
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004467 assert(uses->child);
Michal Vasko9e635ac2016-10-17 11:44:09 +02004468 if (inherit_config_flag(uses->child, parent_config, clear_config, check_list, check_xpath)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004469 goto fail;
4470 }
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004471 }
4472
Michal Vaskodef0db12015-10-07 13:22:48 +02004473 /* we managed to copy the grouping, the rest must be possible to resolve */
4474
Pavol Vican855ca622016-09-05 13:07:54 +02004475 if (uses->refine_size) {
4476 refine_nodes = malloc(uses->refine_size * sizeof *refine_nodes);
4477 if (!refine_nodes) {
4478 LOGMEM;
4479 goto fail;
4480 }
4481 }
4482
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004483 /* apply refines */
4484 for (i = 0; i < uses->refine_size; i++) {
4485 rfn = &uses->refine[i];
Michal Vasko3edeaf72016-02-11 13:17:43 +01004486 rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child, LYS_NO_RPC_NOTIF_NODE,
Radek Krejcif3c71de2016-04-11 12:45:46 +02004487 1, 0, (const struct lys_node **)&node);
Michal Vasko9bb061b2016-02-12 11:00:19 +01004488 if (rc || !node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004489 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004490 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004491 }
4492
Radek Krejci1d82ef62015-08-07 14:44:40 +02004493 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004494 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
4495 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Refine substatements not applicable to the target-node.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004496 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004497 }
Pavol Vican855ca622016-09-05 13:07:54 +02004498 refine_nodes[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004499
4500 /* description on any nodetype */
4501 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004502 lydict_remove(ctx, node->dsc);
4503 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004504 }
4505
4506 /* reference on any nodetype */
4507 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004508 lydict_remove(ctx, node->ref);
4509 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004510 }
4511
4512 /* config on any nodetype */
Michal Vaskoe022a562016-09-27 14:24:15 +02004513 if ((rfn->flags & LYS_CONFIG_MASK) && !clear_config) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004514 node->flags &= ~LYS_CONFIG_MASK;
4515 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004516 }
4517
4518 /* default value ... */
Radek Krejci200bf712016-08-16 17:11:04 +02004519 if (rfn->dflt_size) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004520 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004521 /* leaf */
Radek Krejci200bf712016-08-16 17:11:04 +02004522 leaf = (struct lys_node_leaf *)node;
4523
4524 lydict_remove(ctx, leaf->dflt);
4525 leaf->dflt = lydict_insert(ctx, rfn->dflt[0], 0);
4526
4527 /* check the default value */
4528 if (unres_schema_add_str(leaf->module, unres, &leaf->type, UNRES_TYPE_DFLT, leaf->dflt) == -1) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004529 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004530 }
Radek Krejci200bf712016-08-16 17:11:04 +02004531 } else if (node->nodetype == LYS_LEAFLIST) {
4532 /* leaf-list */
4533 llist = (struct lys_node_leaflist *)node;
4534
4535 /* remove complete set of defaults in target */
4536 for (i = 0; i < llist->dflt_size; i++) {
4537 lydict_remove(ctx, llist->dflt[i]);
4538 }
4539 free(llist->dflt);
4540
4541 /* copy the default set from refine */
4542 llist->dflt_size = rfn->dflt_size;
4543 llist->dflt = malloc(llist->dflt_size * sizeof *llist->dflt);
4544 for (i = 0; i < llist->dflt_size; i++) {
4545 llist->dflt[i] = lydict_insert(ctx, rfn->dflt[i], 0);
4546 }
4547
4548 /* check default value */
4549 for (i = 0; i < llist->dflt_size; i++) {
4550 if (unres_schema_add_str(llist->module, unres, &llist->type, UNRES_TYPE_DFLT, llist->dflt[i]) == -1) {
Pavol Vican855ca622016-09-05 13:07:54 +02004551 goto fail;
Radek Krejci200bf712016-08-16 17:11:04 +02004552 }
4553 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004554 }
4555 }
4556
4557 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02004558 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004559 if (node->nodetype & (LYS_LEAF | LYS_ANYDATA | LYS_CHOICE)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004560 /* remove current value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004561 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004562
4563 /* set new value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004564 node->flags |= (rfn->flags & LYS_MAND_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004565 }
Pavol Vican855ca622016-09-05 13:07:54 +02004566 if (rfn->flags & LYS_MAND_TRUE) {
4567 /* check if node has default value */
4568 if ((node->nodetype & LYS_LEAF) && ((struct lys_node_leaf *)node)->dflt) {
4569 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"mandatory\" statement is forbidden on leaf with \"default\".");
4570 goto fail;
4571 }
4572 if ((node->nodetype & LYS_CHOICE) && ((struct lys_node_choice *)node)->dflt) {
4573 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"mandatory\" statement is forbidden on choices with \"default\".");
4574 goto fail;
4575 }
4576 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004577 }
4578
4579 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004580 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
4581 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
4582 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004583 }
4584
4585 /* min/max-elements on list or leaf-list */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004586 if (node->nodetype == LYS_LIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004587 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004588 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004589 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004590 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004591 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004592 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02004593 } else if (node->nodetype == LYS_LEAFLIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004594 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004595 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004596 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004597 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004598 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004599 }
4600 }
4601
4602 /* must in leaf, leaf-list, list, container or anyxml */
4603 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004604 switch (node->nodetype) {
4605 case LYS_LEAF:
4606 old_size = &((struct lys_node_leaf *)node)->must_size;
4607 old_must = &((struct lys_node_leaf *)node)->must;
4608 break;
4609 case LYS_LEAFLIST:
4610 old_size = &((struct lys_node_leaflist *)node)->must_size;
4611 old_must = &((struct lys_node_leaflist *)node)->must;
4612 break;
4613 case LYS_LIST:
4614 old_size = &((struct lys_node_list *)node)->must_size;
4615 old_must = &((struct lys_node_list *)node)->must;
4616 break;
4617 case LYS_CONTAINER:
4618 old_size = &((struct lys_node_container *)node)->must_size;
4619 old_must = &((struct lys_node_container *)node)->must;
4620 break;
4621 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02004622 case LYS_ANYDATA:
4623 old_size = &((struct lys_node_anydata *)node)->must_size;
4624 old_must = &((struct lys_node_anydata *)node)->must;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004625 break;
4626 default:
4627 LOGINT;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004628 goto fail;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004629 }
4630
4631 size = *old_size + rfn->must_size;
4632 must = realloc(*old_must, size * sizeof *rfn->must);
4633 if (!must) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004634 LOGMEM;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004635 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004636 }
Pavol Vican855ca622016-09-05 13:07:54 +02004637 for (k = 0, j = *old_size; k < rfn->must_size; k++, j++) {
4638 must[j].expr = lydict_insert(ctx, rfn->must[k].expr, 0);
4639 must[j].dsc = lydict_insert(ctx, rfn->must[k].dsc, 0);
4640 must[j].ref = lydict_insert(ctx, rfn->must[k].ref, 0);
4641 must[j].eapptag = lydict_insert(ctx, rfn->must[k].eapptag, 0);
4642 must[j].emsg = lydict_insert(ctx, rfn->must[k].emsg, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004643 }
4644
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004645 *old_must = must;
4646 *old_size = size;
Michal Vasko508a50d2016-09-07 14:50:33 +02004647
4648 /* check XPath dependencies again */
4649 if (unres_schema_add_node(node->module, unres, node, UNRES_XPATH, NULL) == -1) {
4650 goto fail;
4651 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004652 }
Radek Krejci363bd4a2016-07-29 14:30:20 +02004653
4654 /* if-feature in leaf, leaf-list, list, container or anyxml */
4655 if (rfn->iffeature_size) {
4656 old_size = &node->iffeature_size;
4657 old_iff = &node->iffeature;
4658
4659 size = *old_size + rfn->iffeature_size;
4660 iff = realloc(*old_iff, size * sizeof *rfn->iffeature);
4661 if (!iff) {
4662 LOGMEM;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004663 goto fail;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004664 }
Pavol Vican855ca622016-09-05 13:07:54 +02004665 for (k = 0, j = *old_size; k < rfn->iffeature_size; k++, j++) {
4666 resolve_iffeature_getsizes(&rfn->iffeature[k], &usize1, &usize2);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004667 if (usize1) {
4668 /* there is something to duplicate */
4669 /* duplicate compiled expression */
4670 usize = (usize1 / 4) + (usize1 % 4) ? 1 : 0;
4671 iff[j].expr = malloc(usize * sizeof *iff[j].expr);
Pavol Vican855ca622016-09-05 13:07:54 +02004672 memcpy(iff[j].expr, rfn->iffeature[k].expr, usize * sizeof *iff[j].expr);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004673
4674 /* duplicate list of feature pointers */
Pavol Vican855ca622016-09-05 13:07:54 +02004675 iff[j].features = malloc(usize2 * sizeof *iff[k].features);
4676 memcpy(iff[j].features, rfn->iffeature[k].features, usize2 * sizeof *iff[j].features);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004677 }
4678 }
4679
4680 *old_iff = iff;
4681 *old_size = size;
4682 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004683 }
4684
4685 /* apply augments */
4686 for (i = 0; i < uses->augment_size; i++) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004687 rc = resolve_augment(&uses->augment[i], uses->child);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004688 if (rc) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004689 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004690 }
4691 }
4692
Pavol Vican855ca622016-09-05 13:07:54 +02004693 /* check refines */
4694 for (i = 0; i < uses->refine_size; i++) {
4695 node = refine_nodes[i];
4696 rfn = &uses->refine[i];
4697
4698 /* config on any nodetype */
Michal Vaskoe022a562016-09-27 14:24:15 +02004699 if ((rfn->flags & LYS_CONFIG_MASK) && !clear_config) {
Pavol Vican855ca622016-09-05 13:07:54 +02004700 for (parent = lys_parent(node); parent && parent->nodetype == LYS_USES; parent = lys_parent(parent));
4701 if (parent && parent->nodetype != LYS_GROUPING &&
4702 ((parent->flags & LYS_CONFIG_MASK) != (rfn->flags & LYS_CONFIG_MASK)) &&
4703 (rfn->flags & LYS_CONFIG_W)) {
4704 /* setting config true under config false is prohibited */
4705 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
4706 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4707 "changing config from 'false' to 'true' is prohibited while "
4708 "the target's parent is still config 'false'.");
4709 goto fail;
4710 }
4711
4712 /* inherit config change to the target children */
4713 LY_TREE_DFS_BEGIN(node->child, next, iter) {
4714 if (rfn->flags & LYS_CONFIG_W) {
4715 if (iter->flags & LYS_CONFIG_SET) {
4716 /* config is set explicitely, go to next sibling */
4717 next = NULL;
4718 goto nextsibling;
4719 }
4720 } else { /* LYS_CONFIG_R */
4721 if ((iter->flags & LYS_CONFIG_SET) && (iter->flags & LYS_CONFIG_W)) {
4722 /* error - we would have config data under status data */
4723 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
4724 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4725 "changing config from 'true' to 'false' is prohibited while the target "
4726 "has still a children with explicit config 'true'.");
4727 goto fail;
4728 }
4729 }
4730 /* change config */
4731 iter->flags &= ~LYS_CONFIG_MASK;
4732 iter->flags |= (rfn->flags & LYS_CONFIG_MASK);
4733
4734 /* select next iter - modified LY_TREE_DFS_END */
4735 if (iter->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
4736 next = NULL;
4737 } else {
4738 next = iter->child;
4739 }
4740nextsibling:
4741 if (!next) {
4742 /* try siblings */
4743 next = iter->next;
4744 }
4745 while (!next) {
4746 /* parent is already processed, go to its sibling */
4747 iter = lys_parent(iter);
4748
4749 /* no siblings, go back through parents */
4750 if (iter == node) {
4751 /* we are done, no next element to process */
4752 break;
4753 }
4754 next = iter->next;
4755 }
4756 }
4757 }
4758
4759 /* default value */
4760 if (rfn->dflt_size && node->nodetype == LYS_CHOICE) {
4761 /* choice */
4762
4763 ((struct lys_node_choice *)node)->dflt = resolve_choice_dflt((struct lys_node_choice *)node,
4764 rfn->dflt[0]);
4765 if (!((struct lys_node_choice *)node)->dflt) {
4766 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->dflt[0], "default");
4767 goto fail;
4768 }
4769 if (lyp_check_mandatory_choice(node)) {
4770 goto fail;
4771 }
4772 }
4773
4774 /* min/max-elements on list or leaf-list */
4775 if (node->nodetype == LYS_LIST) {
4776 if (((struct lys_node_list *)node)->min > ((struct lys_node_list *)node)->max) {
4777 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
4778 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "\"min-elements\" is bigger than \"max-elements\".");
4779 goto fail;
4780 }
4781 } else if (node->nodetype == LYS_LEAFLIST) {
4782 if (((struct lys_node_leaflist *)node)->min > ((struct lys_node_leaflist *)node)->max) {
4783 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
4784 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "\"min-elements\" is bigger than \"max-elements\".");
4785 goto fail;
4786 }
4787 }
4788
4789 /* additional checks */
4790 if (node->nodetype == LYS_LEAFLIST) {
4791 llist = (struct lys_node_leaflist *)node;
4792 if (llist->dflt_size && llist->min) {
4793 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, rfn->dflt_size ? "default" : "min-elements", "refine");
4794 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
4795 "The \"min-elements\" statement with non-zero value is forbidden on leaf-lists with the \"default\" statement.");
4796 goto fail;
4797 }
4798 }
4799 if ((rfn->flags & LYS_MAND_TRUE) || rfn->mod.list.min) {
4800 /* check for mandatory node in default case, first find the closest parent choice to the changed node */
4801 for (parent = node->parent;
4802 parent && !(parent->nodetype & (LYS_CHOICE | LYS_GROUPING | LYS_ACTION | LYS_USES));
4803 parent = parent->parent) {
4804 if (parent->nodetype == LYS_CONTAINER && ((struct lys_node_container *)parent)->presence) {
4805 /* stop also on presence containers */
4806 break;
4807 }
4808 }
4809 /* and if it is a choice with the default case, check it for presence of a mandatory node in it */
4810 if (parent && parent->nodetype == LYS_CHOICE && ((struct lys_node_choice *)parent)->dflt) {
4811 if (lyp_check_mandatory_choice(parent)) {
4812 goto fail;
4813 }
4814 }
4815 }
4816 }
4817 free(refine_nodes);
4818
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004819 return EXIT_SUCCESS;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004820
4821fail:
4822 LY_TREE_FOR_SAFE(uses->child, next, iter) {
4823 lys_node_free(iter, NULL, 0);
4824 }
Pavol Vican855ca622016-09-05 13:07:54 +02004825 free(refine_nodes);
Michal Vaskoa86508c2016-08-26 14:30:19 +02004826 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004827}
4828
Radek Krejci018f1f52016-08-03 16:01:20 +02004829static int
4830identity_backlink_update(struct lys_ident *der, struct lys_ident *base)
4831{
4832 int i;
4833
4834 assert(der && base);
4835
Radek Krejci018f1f52016-08-03 16:01:20 +02004836 if (!base->der) {
Radek Krejci85a54be2016-10-20 12:39:56 +02004837 /* create a set for backlinks if it does not exist */
4838 base->der = ly_set_new();
Radek Krejci018f1f52016-08-03 16:01:20 +02004839 }
Radek Krejci85a54be2016-10-20 12:39:56 +02004840 /* store backlink */
4841 ly_set_add(base->der, der, LY_SET_OPT_USEASLIST);
Radek Krejci018f1f52016-08-03 16:01:20 +02004842
Radek Krejci85a54be2016-10-20 12:39:56 +02004843 /* do it recursively */
Radek Krejci018f1f52016-08-03 16:01:20 +02004844 for (i = 0; i < base->base_size; i++) {
4845 if (identity_backlink_update(der, base->base[i])) {
4846 return EXIT_FAILURE;
4847 }
4848 }
4849
4850 return EXIT_SUCCESS;
4851}
4852
Michal Vasko730dfdf2015-08-11 14:48:05 +02004853/**
4854 * @brief Resolve base identity recursively. Does not log.
4855 *
4856 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004857 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004858 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004859 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004860 *
Radek Krejci219fa612016-08-15 10:36:51 +02004861 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on crucial error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004862 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004863static int
Michal Vasko1e62a092015-12-01 12:27:20 +01004864resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Radek Krejci018f1f52016-08-03 16:01:20 +02004865 struct unres_schema *unres, struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004866{
Michal Vaskof02e3742015-08-05 16:27:02 +02004867 uint32_t i, j;
Radek Krejci018f1f52016-08-03 16:01:20 +02004868 struct lys_ident *base = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004869
Radek Krejcicf509982015-12-15 09:22:44 +01004870 assert(ret);
4871
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004872 /* search module */
4873 for (i = 0; i < module->ident_size; i++) {
4874 if (!strcmp(basename, module->ident[i].name)) {
4875
4876 if (!ident) {
4877 /* just search for type, so do not modify anything, just return
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004878 * the base identity pointer */
Radek Krejcicf509982015-12-15 09:22:44 +01004879 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004880 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004881 }
4882
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004883 base = &module->ident[i];
4884 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004885 }
4886 }
4887
4888 /* search submodules */
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004889 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
4890 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
4891 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004892
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004893 if (!ident) {
4894 *ret = &module->inc[j].submodule->ident[i];
4895 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004896 }
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004897
4898 base = &module->inc[j].submodule->ident[i];
4899 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004900 }
4901 }
4902 }
4903
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004904matchfound:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004905 /* we found it somewhere */
Radek Krejcibabbff82016-02-19 13:31:37 +01004906 if (base) {
Radek Krejci018f1f52016-08-03 16:01:20 +02004907 /* is it already completely resolved? */
4908 for (i = 0; i < unres->count; i++) {
Radek Krejciba7b1cc2016-08-08 13:44:43 +02004909 if ((unres->item[i] == base) && (unres->type[i] == UNRES_IDENT)) {
Radek Krejci018f1f52016-08-03 16:01:20 +02004910 /* identity found, but not yet resolved, so do not return it in *res and try it again later */
4911
4912 /* simple check for circular reference,
4913 * the complete check is done as a side effect of using only completely
4914 * resolved identities (previous check of unres content) */
4915 if (ly_strequal((const char *)unres->str_snode[i], ident->name, 1)) {
4916 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, basename, "base");
4917 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Circular reference of \"%s\" identity.", basename);
Radek Krejci219fa612016-08-15 10:36:51 +02004918 return -1;
Radek Krejci018f1f52016-08-03 16:01:20 +02004919 }
4920
Radek Krejci06f64ed2016-08-15 11:07:44 +02004921 return EXIT_FAILURE;
Radek Krejcibabbff82016-02-19 13:31:37 +01004922 }
4923 }
Radek Krejci018f1f52016-08-03 16:01:20 +02004924
Radek Krejcibabbff82016-02-19 13:31:37 +01004925 /* checks done, store the result */
Radek Krejci018f1f52016-08-03 16:01:20 +02004926 *ret = base;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02004927 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004928 }
4929
Radek Krejci219fa612016-08-15 10:36:51 +02004930 /* base not found (maybe a forward reference) */
4931 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004932}
4933
Michal Vasko730dfdf2015-08-11 14:48:05 +02004934/**
4935 * @brief Resolve base identity. Logs directly.
4936 *
4937 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004938 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004939 * @param[in] basename Base name of the identity.
Radek Krejcibabbff82016-02-19 13:31:37 +01004940 * @param[in] parent Either "type" or "identity".
Radek Krejcicf509982015-12-15 09:22:44 +01004941 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004942 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004943 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004944 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004945static int
Michal Vaskof2d43962016-09-02 11:10:16 +02004946resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char *parent,
Radek Krejci018f1f52016-08-03 16:01:20 +02004947 struct lys_type *type, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004948{
4949 const char *name;
Radek Krejci219fa612016-08-15 10:36:51 +02004950 int mod_name_len = 0, rc;
Radek Krejcicf509982015-12-15 09:22:44 +01004951 struct lys_ident *target, **ret;
Radek Krejci4372b4e2016-04-14 17:42:16 +02004952 uint16_t flags;
Radek Krejcicf509982015-12-15 09:22:44 +01004953 struct lys_module *mod;
4954
4955 assert((ident && !type) || (!ident && type));
4956
4957 if (!type) {
4958 /* have ident to resolve */
4959 ret = &target;
4960 flags = ident->flags;
4961 mod = ident->module;
4962 } else {
4963 /* have type to fill */
Michal Vaskof2d43962016-09-02 11:10:16 +02004964 ++type->info.ident.count;
4965 type->info.ident.ref = ly_realloc(type->info.ident.ref, type->info.ident.count * sizeof *type->info.ident.ref);
4966 if (!type->info.ident.ref) {
4967 LOGMEM;
4968 return -1;
4969 }
4970
4971 ret = &type->info.ident.ref[type->info.ident.count - 1];
Radek Krejcicf509982015-12-15 09:22:44 +01004972 flags = type->parent->flags;
4973 mod = type->parent->module;
4974 }
Michal Vaskof2006002016-04-21 16:28:15 +02004975 *ret = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004976
4977 /* search for the base identity */
4978 name = strchr(basename, ':');
4979 if (name) {
4980 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02004981 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004982 name++;
4983
Michal Vasko2d851a92015-10-20 16:16:36 +02004984 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004985 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02004986 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004987 }
4988 } else {
4989 name = basename;
4990 }
4991
Radek Krejcic071c542016-01-27 14:57:51 +01004992 /* get module where to search */
4993 module = lys_get_import_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len);
4994 if (!module) {
4995 /* identity refers unknown data model */
Radek Krejci02a04992016-03-17 16:06:37 +01004996 LOGVAL(LYE_INMOD, LY_VLOG_NONE, NULL, basename);
Radek Krejcic071c542016-01-27 14:57:51 +01004997 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004998 }
4999
Radek Krejcic071c542016-01-27 14:57:51 +01005000 /* search in the identified module ... */
Radek Krejci219fa612016-08-15 10:36:51 +02005001 rc = resolve_base_ident_sub(module, ident, name, unres, ret);
5002 if (!rc) {
5003 assert(*ret);
5004
5005 /* check status */
5006 if (lyp_check_status(flags, mod, ident ? ident->name : "of type",
5007 (*ret)->flags, (*ret)->module, (*ret)->name, NULL)) {
5008 rc = -1;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02005009 } else {
5010 if (ident) {
5011 ident->base[ident->base_size++] = *ret;
5012
5013 /* maintain backlinks to the derived identities */
5014 rc = identity_backlink_update(ident, *ret) ? -1 : EXIT_SUCCESS;
5015 }
Radek Krejci219fa612016-08-15 10:36:51 +02005016 }
5017 } else if (rc == EXIT_FAILURE) {
5018 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, parent, basename);
Pavol Vican053a2882016-09-05 14:40:33 +02005019 if (type) {
5020 --type->info.ident.count;
5021 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005022 }
5023
Radek Krejci219fa612016-08-15 10:36:51 +02005024 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005025}
5026
Michal Vasko730dfdf2015-08-11 14:48:05 +02005027/**
Michal Vaskof39142b2015-10-21 11:40:05 +02005028 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005029 *
Michal Vaskof2d43962016-09-02 11:10:16 +02005030 * @param[in] type Identityref type.
Michal Vaskofb0873c2015-08-21 09:00:07 +02005031 * @param[in] ident_name Identityref name.
Radek Krejciadb57612016-02-16 13:34:34 +01005032 * @param[in] node Node where the identityref is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02005033 *
5034 * @return Pointer to the identity resolvent, NULL on error.
5035 */
Radek Krejcia52656e2015-08-05 13:41:50 +02005036struct lys_ident *
Michal Vaskof2d43962016-09-02 11:10:16 +02005037resolve_identref(struct lys_type *type, const char *ident_name, struct lyd_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005038{
Michal Vaskoc633ca02015-08-21 14:03:51 +02005039 const char *mod_name, *name;
Radek Krejci85a54be2016-10-20 12:39:56 +02005040 int mod_name_len, rc, i;
5041 unsigned int u;
Michal Vaskof2d43962016-09-02 11:10:16 +02005042 struct lys_ident *der, *cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005043
Michal Vaskof2d43962016-09-02 11:10:16 +02005044 if (!type || (!type->info.ident.count && !type->der) || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005045 return NULL;
5046 }
5047
Michal Vaskoc633ca02015-08-21 14:03:51 +02005048 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, NULL);
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005049 if (rc < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005050 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005051 return NULL;
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005052 } else if (rc < (signed)strlen(ident_name)) {
Radek Krejci02a04992016-03-17 16:06:37 +01005053 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[rc], &ident_name[rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005054 return NULL;
5055 }
5056
Michal Vaskof2d43962016-09-02 11:10:16 +02005057 /* go through all the bases in all the derived types */
5058 while (type->der) {
5059 for (i = 0; i < type->info.ident.count; ++i) {
5060 cur = type->info.ident.ref[i];
5061 if (!strcmp(cur->name, name) && (!mod_name
5062 || (!strncmp(cur->module->name, mod_name, mod_name_len) && !cur->module->name[mod_name_len]))) {
5063 goto match;
5064 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02005065
Radek Krejci85a54be2016-10-20 12:39:56 +02005066 if (cur->der) {
5067 /* there are also some derived identities */
5068 for (u = 0; u < cur->der->number; u++) {
5069 der = (struct lys_ident *)cur->der->set.g[u]; /* shortcut */
5070 if (!strcmp(der->name, name) &&
5071 (!mod_name || (!strncmp(der->module->name, mod_name, mod_name_len) && !der->module->name[mod_name_len]))) {
5072 /* we have match */
5073 cur = der;
5074 goto match;
5075 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005076 }
5077 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005078 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005079 type = &type->der->type;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005080 }
5081
Radek Krejci48464ed2016-03-17 15:44:09 +01005082 LOGVAL(LYE_INRESOLV, LY_VLOG_LYD, node, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005083 return NULL;
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005084
5085match:
Michal Vaskof2d43962016-09-02 11:10:16 +02005086 for (i = 0; i < cur->iffeature_size; i++) {
5087 if (!resolve_iffeature(&cur->iffeature[i])) {
5088 LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, cur->name, node->schema->name);
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005089 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, "Identity \"%s\" is disabled by its if-feature condition.",
Michal Vaskof2d43962016-09-02 11:10:16 +02005090 cur->name);
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005091 return NULL;
5092 }
5093 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005094 return cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005095}
5096
Michal Vasko730dfdf2015-08-11 14:48:05 +02005097/**
Michal Vaskobb211122015-08-19 14:03:11 +02005098 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005099 *
Michal Vaskobb211122015-08-19 14:03:11 +02005100 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005101 * @param[in] unres Specific unres item.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005102 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005103 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005104 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005105static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005106resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005107{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005108 int rc;
Radek Krejci010e54b2016-03-15 09:40:34 +01005109 struct lys_node *par_grp;
Michal Vaskoe91afce2015-08-12 12:21:00 +02005110
Radek Krejci010e54b2016-03-15 09:40:34 +01005111 /* HACK: when a grouping has uses inside, all such uses have to be resolved before the grouping itself
5112 * is used in some uses. When we see such a uses, the grouping's nacm member (not used in grouping)
5113 * is used to store number of so far unresolved uses. The grouping cannot be used unless the nacm
5114 * value is decreased back to 0. To remember that the uses already increased grouping's nacm, the
5115 * LYS_USESGRP flag is used. */
Michal Vaskodcf98e62016-05-05 17:53:53 +02005116 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 +02005117
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005118 if (!uses->grp) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01005119 rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
5120 if (rc == -1) {
Michal Vasko92981a62016-10-14 10:25:16 +02005121 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005122 return -1;
5123 } else if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005124 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005125 return -1;
5126 } else if (!uses->grp) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005127 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005128 /* hack - in contrast to lys_node, lys_node_grp has bigger nacm field
5129 * (and smaller flags - it uses only a limited set of flags)
5130 */
5131 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci010e54b2016-03-15 09:40:34 +01005132 uses->flags |= LYS_USESGRP;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005133 }
Michal Vasko92981a62016-10-14 10:25:16 +02005134 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005135 return EXIT_FAILURE;
Michal Vasko12e30842015-08-04 11:54:00 +02005136 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005137 }
5138
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005139 if (uses->grp->nacm) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005140 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005141 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci010e54b2016-03-15 09:40:34 +01005142 uses->flags |= LYS_USESGRP;
Radek Krejcie00d2312016-08-12 15:27:49 +02005143 } else {
5144 /* instantiate grouping only when it is completely resolved */
5145 uses->grp = NULL;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005146 }
Michal Vasko92981a62016-10-14 10:25:16 +02005147 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005148 return EXIT_FAILURE;
5149 }
5150
Radek Krejci48464ed2016-03-17 15:44:09 +01005151 rc = resolve_uses(uses, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005152 if (!rc) {
5153 /* decrease unres count only if not first try */
Radek Krejci010e54b2016-03-15 09:40:34 +01005154 if (par_grp && (uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005155 if (!((struct lys_node_grp *)par_grp)->nacm) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005156 LOGINT;
5157 return -1;
5158 }
Radek Krejci4372b4e2016-04-14 17:42:16 +02005159 ((struct lys_node_grp *)par_grp)->nacm--;
Radek Krejci010e54b2016-03-15 09:40:34 +01005160 uses->flags &= ~LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005161 }
Radek Krejcicf509982015-12-15 09:22:44 +01005162
5163 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005164 if (lyp_check_status(uses->flags, uses->module, "of uses",
Radek Krejciadb57612016-02-16 13:34:34 +01005165 uses->grp->flags, uses->grp->module, uses->grp->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005166 (struct lys_node *)uses)) {
Radek Krejcicf509982015-12-15 09:22:44 +01005167 return -1;
5168 }
5169
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005170 return EXIT_SUCCESS;
5171 }
5172
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005173 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005174}
5175
Michal Vasko730dfdf2015-08-11 14:48:05 +02005176/**
Michal Vasko9957e592015-08-17 15:04:09 +02005177 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005178 *
Michal Vaskobb211122015-08-19 14:03:11 +02005179 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005180 * @param[in] keys_str Keys node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005181 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005182 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005183 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005184static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005185resolve_list_keys(struct lys_node_list *list, const char *keys_str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005186{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005187 int i, len, rc;
Michal Vasko4f0dad02016-02-15 14:08:23 +01005188 const char *value;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005189
5190 for (i = 0; i < list->keys_size; ++i) {
5191 /* get the key name */
5192 if ((value = strpbrk(keys_str, " \t\n"))) {
5193 len = value - keys_str;
5194 while (isspace(value[0])) {
5195 value++;
5196 }
5197 } else {
5198 len = strlen(keys_str);
5199 }
5200
Radek Krejcic4283442016-04-22 09:19:27 +02005201 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 +02005202 if (rc) {
Michal Vasko7a55bea2016-05-02 14:51:20 +02005203 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
5204 return EXIT_FAILURE;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005205 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005206
Radek Krejci48464ed2016-03-17 15:44:09 +01005207 if (check_key(list, i, keys_str, len)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005208 /* check_key logs */
5209 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005210 }
5211
Radek Krejcicf509982015-12-15 09:22:44 +01005212 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005213 if (lyp_check_status(list->flags, list->module, list->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005214 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
5215 (struct lys_node *)list->keys[i])) {
Radek Krejcicf509982015-12-15 09:22:44 +01005216 return -1;
5217 }
5218
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005219 /* prepare for next iteration */
5220 while (value && isspace(value[0])) {
5221 value++;
5222 }
5223 keys_str = value;
5224 }
5225
Michal Vaskof02e3742015-08-05 16:27:02 +02005226 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005227}
5228
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005229/**
Michal Vaskobf19d252015-10-08 15:39:17 +02005230 * @brief Resolve (check) all must conditions of \p node.
5231 * Logs directly.
5232 *
5233 * @param[in] node Data node with optional must statements.
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005234 * @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 +02005235 *
5236 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
5237 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005238static int
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005239resolve_must(struct lyd_node *node, int inout_parent)
Michal Vaskof02e3742015-08-05 16:27:02 +02005240{
Michal Vaskobf19d252015-10-08 15:39:17 +02005241 uint8_t i, must_size;
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005242 struct lys_node *schema;
Michal Vaskobf19d252015-10-08 15:39:17 +02005243 struct lys_restr *must;
5244 struct lyxp_set set;
5245
5246 assert(node);
5247 memset(&set, 0, sizeof set);
5248
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005249 if (inout_parent) {
5250 for (schema = lys_parent(node->schema);
5251 schema && (schema->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES));
5252 schema = lys_parent(schema));
5253 if (!schema || !(schema->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5254 LOGINT;
5255 return -1;
5256 }
5257 must_size = ((struct lys_node_inout *)schema)->must_size;
5258 must = ((struct lys_node_inout *)schema)->must;
5259
5260 /* context node is the RPC/action */
5261 node = node->parent;
5262 if (!(node->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
5263 LOGINT;
5264 return -1;
5265 }
5266 } else {
5267 switch (node->schema->nodetype) {
5268 case LYS_CONTAINER:
5269 must_size = ((struct lys_node_container *)node->schema)->must_size;
5270 must = ((struct lys_node_container *)node->schema)->must;
5271 break;
5272 case LYS_LEAF:
5273 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
5274 must = ((struct lys_node_leaf *)node->schema)->must;
5275 break;
5276 case LYS_LEAFLIST:
5277 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
5278 must = ((struct lys_node_leaflist *)node->schema)->must;
5279 break;
5280 case LYS_LIST:
5281 must_size = ((struct lys_node_list *)node->schema)->must_size;
5282 must = ((struct lys_node_list *)node->schema)->must;
5283 break;
5284 case LYS_ANYXML:
5285 case LYS_ANYDATA:
5286 must_size = ((struct lys_node_anydata *)node->schema)->must_size;
5287 must = ((struct lys_node_anydata *)node->schema)->must;
5288 break;
5289 case LYS_NOTIF:
5290 must_size = ((struct lys_node_notif *)node->schema)->must_size;
5291 must = ((struct lys_node_notif *)node->schema)->must;
5292 break;
5293 default:
5294 must_size = 0;
5295 break;
5296 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005297 }
5298
5299 for (i = 0; i < must_size; ++i) {
Michal Vaskoa59495d2016-08-22 09:18:58 +02005300 if (lyxp_eval(must[i].expr, node, LYXP_NODE_ELEM, &set, LYXP_MUST)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02005301 return -1;
5302 }
5303
Michal Vasko944a5642016-03-21 11:48:58 +01005304 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, LYXP_MUST);
Michal Vaskobf19d252015-10-08 15:39:17 +02005305
Michal Vasko8146d4c2016-05-09 15:50:29 +02005306 if (!set.val.bool) {
Michal Vasko6ac68282016-04-11 10:56:47 +02005307 LOGVAL(LYE_NOMUST, LY_VLOG_LYD, node, must[i].expr);
5308 if (must[i].emsg) {
5309 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, must[i].emsg);
5310 }
5311 if (must[i].eapptag) {
5312 strncpy(((struct ly_err *)&ly_errno)->apptag, must[i].eapptag, LY_APPTAG_LEN - 1);
5313 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005314 return 1;
5315 }
5316 }
5317
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005318 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02005319}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005320
Michal Vaskobf19d252015-10-08 15:39:17 +02005321/**
Michal Vasko508a50d2016-09-07 14:50:33 +02005322 * @brief Resolve (find) when condition schema context node. Does not log.
5323 *
5324 * @param[in] schema Schema node with the when condition.
5325 * @param[out] ctx_snode When schema context node.
5326 * @param[out] ctx_snode_type Schema context node type.
5327 */
5328void
5329resolve_when_ctx_snode(const struct lys_node *schema, struct lys_node **ctx_snode, enum lyxp_node_type *ctx_snode_type)
5330{
5331 const struct lys_node *sparent;
5332
5333 /* find a not schema-only node */
5334 *ctx_snode_type = LYXP_NODE_ELEM;
5335 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
5336 if (schema->nodetype == LYS_AUGMENT) {
5337 sparent = ((struct lys_node_augment *)schema)->target;
5338 } else {
5339 sparent = schema->parent;
5340 }
5341 if (!sparent) {
5342 /* context node is the document root (fake root in our case) */
5343 if (schema->flags & LYS_CONFIG_W) {
5344 *ctx_snode_type = LYXP_NODE_ROOT_CONFIG;
5345 } else {
Michal Vaskob94a5e42016-09-08 14:01:56 +02005346 *ctx_snode_type = LYXP_NODE_ROOT;
Michal Vasko508a50d2016-09-07 14:50:33 +02005347 }
Michal Vasko2d2aec12016-09-08 11:42:50 +02005348 /* we need the first top-level sibling, but no uses or groupings */
Michal Vaskob94a5e42016-09-08 14:01:56 +02005349 schema = lys_getnext(NULL, NULL, lys_node_module(schema), 0);
Michal Vasko508a50d2016-09-07 14:50:33 +02005350 break;
5351 }
5352 schema = sparent;
5353 }
5354
5355 *ctx_snode = (struct lys_node *)schema;
5356}
5357
5358/**
Michal Vaskocf024702015-10-08 15:01:42 +02005359 * @brief Resolve (find) when condition context node. Does not log.
5360 *
5361 * @param[in] node Data node, whose conditional definition is being decided.
Michal Vasko508a50d2016-09-07 14:50:33 +02005362 * @param[in] schema Schema node with the when condition.
Michal Vaskoa59495d2016-08-22 09:18:58 +02005363 * @param[out] ctx_node Context node.
5364 * @param[out] ctx_node_type Context node type.
Michal Vaskocf024702015-10-08 15:01:42 +02005365 *
Michal Vaskoa59495d2016-08-22 09:18:58 +02005366 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vaskocf024702015-10-08 15:01:42 +02005367 */
Michal Vaskoa59495d2016-08-22 09:18:58 +02005368static int
5369resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema, struct lyd_node **ctx_node,
5370 enum lyxp_node_type *ctx_node_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005371{
Michal Vaskocf024702015-10-08 15:01:42 +02005372 struct lyd_node *parent;
5373 struct lys_node *sparent;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005374 enum lyxp_node_type node_type;
Michal Vaskocf024702015-10-08 15:01:42 +02005375 uint16_t i, data_depth, schema_depth;
5376
Michal Vasko508a50d2016-09-07 14:50:33 +02005377 resolve_when_ctx_snode(schema, &schema, &node_type);
Michal Vaskocf024702015-10-08 15:01:42 +02005378
Michal Vaskofe989752016-09-08 08:47:26 +02005379 if (node_type == LYXP_NODE_ELEM) {
5380 /* standard element context node */
5381 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
5382 for (sparent = schema, schema_depth = 0;
5383 sparent;
5384 sparent = (sparent->nodetype == LYS_AUGMENT ? ((struct lys_node_augment *)sparent)->target : sparent->parent)) {
5385 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_NOTIF | LYS_RPC)) {
5386 ++schema_depth;
5387 }
Michal Vaskocf024702015-10-08 15:01:42 +02005388 }
Michal Vaskofe989752016-09-08 08:47:26 +02005389 if (data_depth < schema_depth) {
5390 return -1;
5391 }
Michal Vaskocf024702015-10-08 15:01:42 +02005392
Michal Vasko956e8542016-08-26 09:43:35 +02005393 /* find the corresponding data node */
5394 for (i = 0; i < data_depth - schema_depth; ++i) {
5395 node = node->parent;
5396 }
Michal Vaskoa59495d2016-08-22 09:18:58 +02005397 if (node->schema != schema) {
5398 return -1;
5399 }
Michal Vaskofe989752016-09-08 08:47:26 +02005400 } else {
5401 /* root context node */
5402 while (node->parent) {
5403 node = node->parent;
5404 }
5405 while (node->prev->next) {
5406 node = node->prev;
5407 }
Michal Vaskocf024702015-10-08 15:01:42 +02005408 }
5409
Michal Vaskoa59495d2016-08-22 09:18:58 +02005410 *ctx_node = node;
5411 *ctx_node_type = node_type;
5412 return EXIT_SUCCESS;
Michal Vaskocf024702015-10-08 15:01:42 +02005413}
5414
Michal Vasko76c3bd32016-08-24 16:02:52 +02005415/**
5416 * @brief Temporarily unlink nodes as per YANG 1.1 RFC section 7.21.5 for when XPath evaluation.
5417 * The context nodes is adjusted if needed.
5418 *
5419 * @param[in] snode Schema node, whose children instances need to be unlinked.
5420 * @param[in,out] node Data siblings where to look for the children of \p snode. If it is unlinked,
5421 * it is moved to point to another sibling still in the original tree.
5422 * @param[in,out] ctx_node When context node, adjusted if needed.
5423 * @param[in] ctx_node_type Context node type, just for information to detect invalid situations.
5424 * @param[out] unlinked_nodes Unlinked siblings. Can be safely appended to \p node afterwards.
5425 * Ordering may change, but there will be no semantic change.
5426 *
5427 * @return EXIT_SUCCESS on success, -1 on error.
5428 */
5429static int
5430resolve_when_unlink_nodes(struct lys_node *snode, struct lyd_node **node, struct lyd_node **ctx_node,
5431 enum lyxp_node_type ctx_node_type, struct lyd_node **unlinked_nodes)
5432{
5433 struct lyd_node *next, *elem;
5434
5435 switch (snode->nodetype) {
5436 case LYS_AUGMENT:
5437 case LYS_USES:
5438 case LYS_CHOICE:
5439 case LYS_CASE:
5440 LY_TREE_FOR(snode->child, snode) {
5441 if (resolve_when_unlink_nodes(snode, node, ctx_node, ctx_node_type, unlinked_nodes)) {
5442 return -1;
5443 }
5444 }
5445 break;
5446 case LYS_CONTAINER:
5447 case LYS_LIST:
5448 case LYS_LEAF:
5449 case LYS_LEAFLIST:
5450 case LYS_ANYXML:
5451 case LYS_ANYDATA:
5452 LY_TREE_FOR_SAFE(lyd_first_sibling(*node), next, elem) {
5453 if (elem->schema == snode) {
5454
5455 if (elem == *ctx_node) {
5456 /* We are going to unlink our context node! This normally cannot happen,
5457 * but we use normal top-level data nodes for faking a document root node,
5458 * so if this is the context node, we just use the next top-level node.
5459 * Additionally, it can even happen that there are no top-level data nodes left,
5460 * all were unlinked, so in this case we pass NULL as the context node/data tree,
5461 * lyxp_eval() can handle this special situation.
5462 */
5463 if (ctx_node_type == LYXP_NODE_ELEM) {
5464 LOGINT;
5465 return -1;
5466 }
5467
5468 if (elem->prev == elem) {
5469 /* unlinking last top-level element, use an empty data tree */
5470 *ctx_node = NULL;
5471 } else {
5472 /* in this case just use the previous/last top-level data node */
5473 *ctx_node = elem->prev;
5474 }
5475 } else if (elem == *node) {
5476 /* We are going to unlink the currently processed node. This does not matter that
5477 * much, but we would lose access to the original data tree, so just move our
5478 * pointer somewhere still inside it.
5479 */
5480 if ((*node)->prev != *node) {
5481 *node = (*node)->prev;
5482 } else {
5483 /* the processed node with sibings were all unlinked, oh well */
5484 *node = NULL;
5485 }
5486 }
5487
5488 /* temporarily unlink the node */
5489 lyd_unlink(elem);
5490 if (*unlinked_nodes) {
5491 if (lyd_insert_after(*unlinked_nodes, elem)) {
5492 LOGINT;
5493 return -1;
5494 }
5495 } else {
5496 *unlinked_nodes = elem;
5497 }
5498
5499 if (snode->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_ANYDATA)) {
5500 /* there can be only one instance */
5501 break;
5502 }
5503 }
5504 }
5505 break;
5506 default:
5507 LOGINT;
5508 return -1;
5509 }
5510
5511 return EXIT_SUCCESS;
5512}
5513
5514/**
5515 * @brief Relink the unlinked nodes back.
5516 *
5517 * @param[in] node Data node to link the nodes back to. It can actually be the adjusted context node,
5518 * we simply need a sibling from the original data tree.
5519 * @param[in] unlinked_nodes Unlinked nodes to relink to \p node.
5520 * @param[in] ctx_node_type Context node type to distinguish between \p node being the parent
5521 * or the sibling of \p unlinked_nodes.
5522 *
5523 * @return EXIT_SUCCESS on success, -1 on error.
5524 */
5525static int
5526resolve_when_relink_nodes(struct lyd_node *node, struct lyd_node *unlinked_nodes, enum lyxp_node_type ctx_node_type)
5527{
5528 struct lyd_node *elem;
5529
5530 LY_TREE_FOR_SAFE(unlinked_nodes, unlinked_nodes, elem) {
5531 if (ctx_node_type == LYXP_NODE_ELEM) {
5532 if (lyd_insert(node, elem)) {
5533 return -1;
5534 }
5535 } else {
5536 if (lyd_insert_after(node, elem)) {
5537 return -1;
5538 }
5539 }
5540 }
5541
5542 return EXIT_SUCCESS;
5543}
5544
Radek Krejci03b71f72016-03-16 11:10:09 +01005545int
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005546resolve_applies_must(const struct lyd_node *node)
Radek Krejci01696bf2016-03-18 13:19:36 +01005547{
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005548 int ret = 0;
5549 uint8_t must_size;
5550 struct lys_node *schema, *iter;
Radek Krejci46165822016-08-26 14:06:27 +02005551
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005552 assert(node);
5553
5554 schema = node->schema;
5555
5556 /* their own must */
Radek Krejci46165822016-08-26 14:06:27 +02005557 switch (schema->nodetype) {
Radek Krejci01696bf2016-03-18 13:19:36 +01005558 case LYS_CONTAINER:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005559 must_size = ((struct lys_node_container *)schema)->must_size;
5560 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005561 case LYS_LEAF:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005562 must_size = ((struct lys_node_leaf *)schema)->must_size;
5563 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005564 case LYS_LEAFLIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005565 must_size = ((struct lys_node_leaflist *)schema)->must_size;
5566 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005567 case LYS_LIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005568 must_size = ((struct lys_node_list *)schema)->must_size;
5569 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005570 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02005571 case LYS_ANYDATA:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005572 must_size = ((struct lys_node_anydata *)schema)->must_size;
5573 break;
5574 case LYS_NOTIF:
5575 must_size = ((struct lys_node_notif *)schema)->must_size;
5576 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005577 default:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005578 must_size = 0;
5579 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005580 }
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005581
5582 if (must_size) {
5583 ++ret;
5584 }
5585
5586 /* schema may be a direct data child of input/output with must (but it must be first, it needs to be evaluated only once) */
5587 if (!node->prev->next) {
5588 for (iter = lys_parent(schema); iter && (iter->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES)); iter = lys_parent(iter));
5589 if (iter && (iter->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5590 ret += 0x2;
5591 }
5592 }
5593
5594 return ret;
Radek Krejci01696bf2016-03-18 13:19:36 +01005595}
5596
5597int
Radek Krejci46165822016-08-26 14:06:27 +02005598resolve_applies_when(const struct lys_node *schema, int mode, const struct lys_node *stop)
Radek Krejci03b71f72016-03-16 11:10:09 +01005599{
Radek Krejci46165822016-08-26 14:06:27 +02005600 const struct lys_node *parent;
Radek Krejci03b71f72016-03-16 11:10:09 +01005601
Radek Krejci46165822016-08-26 14:06:27 +02005602 assert(schema);
Radek Krejci03b71f72016-03-16 11:10:09 +01005603
Radek Krejci46165822016-08-26 14:06:27 +02005604 if (!(schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)schema)->when)) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005605 return 1;
5606 }
5607
Radek Krejci46165822016-08-26 14:06:27 +02005608 parent = schema;
Radek Krejci03b71f72016-03-16 11:10:09 +01005609 goto check_augment;
5610
Radek Krejci46165822016-08-26 14:06:27 +02005611 while (parent) {
5612 /* stop conditions */
5613 if (!mode) {
5614 /* stop on node that can be instantiated in data tree */
5615 if (!(parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
5616 break;
5617 }
5618 } else {
5619 /* stop on the specified node */
5620 if (parent == stop) {
5621 break;
5622 }
5623 }
5624
5625 if (((const struct lys_node_uses *)parent)->when) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005626 return 1;
5627 }
5628check_augment:
5629
5630 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) &&
Radek Krejci46165822016-08-26 14:06:27 +02005631 (((const struct lys_node_augment *)parent->parent)->when))) {
Michal Vaskoe3655562016-08-24 15:56:17 +02005632 return 1;
Radek Krejci03b71f72016-03-16 11:10:09 +01005633 }
5634 parent = lys_parent(parent);
5635 }
5636
5637 return 0;
5638}
5639
Michal Vaskocf024702015-10-08 15:01:42 +02005640/**
5641 * @brief Resolve (check) all when conditions relevant for \p node.
5642 * Logs directly.
5643 *
5644 * @param[in] node Data node, whose conditional reference, if such, is being decided.
Michal Vaskocf024702015-10-08 15:01:42 +02005645 *
Radek Krejci03b71f72016-03-16 11:10:09 +01005646 * @return
5647 * -1 - error, ly_errno is set
5648 * 0 - true "when" statement
Radek Krejci46165822016-08-26 14:06:27 +02005649 * 0, ly_vecode = LYVE_NOWHEN - false "when" statement
Radek Krejci03b71f72016-03-16 11:10:09 +01005650 * 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 +02005651 */
Radek Krejci46165822016-08-26 14:06:27 +02005652int
5653resolve_when(struct lyd_node *node, int *result)
Michal Vaskocf024702015-10-08 15:01:42 +02005654{
Michal Vasko76c3bd32016-08-24 16:02:52 +02005655 struct lyd_node *ctx_node = NULL, *unlinked_nodes, *tmp_node;
Michal Vasko90fc2a32016-08-24 15:58:58 +02005656 struct lys_node *sparent;
Michal Vaskocf024702015-10-08 15:01:42 +02005657 struct lyxp_set set;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005658 enum lyxp_node_type ctx_node_type;
Radek Krejci51093642016-03-29 10:14:59 +02005659 int rc = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02005660
5661 assert(node);
5662 memset(&set, 0, sizeof set);
5663
5664 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)node->schema)->when)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005665 /* make the node dummy for the evaluation */
5666 node->validity |= LYD_VAL_INUSE;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005667 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 +02005668 node->validity &= ~LYD_VAL_INUSE;
Radek Krejci03b71f72016-03-16 11:10:09 +01005669 if (rc) {
5670 if (rc == 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005671 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005672 }
Radek Krejci51093642016-03-29 10:14:59 +02005673 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005674 }
5675
Radek Krejci03b71f72016-03-16 11:10:09 +01005676 /* set boolean result of the condition */
Michal Vasko944a5642016-03-21 11:48:58 +01005677 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02005678 if (!set.val.bool) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005679 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci0b7704f2016-03-18 12:16:14 +01005680 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02005681 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005682 }
Radek Krejci51093642016-03-29 10:14:59 +02005683
5684 /* free xpath set content */
5685 lyxp_set_cast(&set, LYXP_SET_EMPTY, node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005686 }
5687
Michal Vasko90fc2a32016-08-24 15:58:58 +02005688 sparent = node->schema;
Michal Vaskocf024702015-10-08 15:01:42 +02005689 goto check_augment;
5690
5691 /* check when in every schema node that affects node */
Michal Vasko90fc2a32016-08-24 15:58:58 +02005692 while (sparent && (sparent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
5693 if (((struct lys_node_uses *)sparent)->when) {
Michal Vaskocf024702015-10-08 15:01:42 +02005694 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005695 rc = resolve_when_ctx_node(node, sparent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02005696 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02005697 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02005698 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005699 }
5700 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02005701
5702 unlinked_nodes = NULL;
5703 /* we do not want our node pointer to change */
5704 tmp_node = node;
5705 rc = resolve_when_unlink_nodes(sparent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
5706 if (rc) {
5707 goto cleanup;
5708 }
5709
5710 rc = lyxp_eval(((struct lys_node_uses *)sparent)->when->cond, ctx_node, ctx_node_type, &set, LYXP_WHEN);
5711
5712 if (unlinked_nodes && ctx_node) {
5713 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
5714 rc = -1;
5715 goto cleanup;
5716 }
5717 }
5718
Radek Krejci03b71f72016-03-16 11:10:09 +01005719 if (rc) {
5720 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005721 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005722 }
Radek Krejci51093642016-03-29 10:14:59 +02005723 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005724 }
5725
Michal Vasko944a5642016-03-21 11:48:58 +01005726 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02005727 if (!set.val.bool) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005728 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Radek Krejci0b7704f2016-03-18 12:16:14 +01005729 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02005730 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005731 }
Radek Krejci51093642016-03-29 10:14:59 +02005732
5733 /* free xpath set content */
5734 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005735 }
5736
5737check_augment:
Michal Vasko90fc2a32016-08-24 15:58:58 +02005738 if ((sparent->parent && (sparent->parent->nodetype == LYS_AUGMENT) && (((struct lys_node_augment *)sparent->parent)->when))) {
Michal Vaskocf024702015-10-08 15:01:42 +02005739 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005740 rc = resolve_when_ctx_node(node, sparent->parent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02005741 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02005742 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02005743 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005744 }
5745 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02005746
5747 unlinked_nodes = NULL;
5748 tmp_node = node;
5749 rc = resolve_when_unlink_nodes(sparent->parent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
5750 if (rc) {
5751 goto cleanup;
5752 }
5753
5754 rc = lyxp_eval(((struct lys_node_augment *)sparent->parent)->when->cond, ctx_node, ctx_node_type, &set, LYXP_WHEN);
5755
5756 /* reconnect nodes, if ctx_node is NULL then all the nodes were unlinked, but linked together,
5757 * so the tree did not actually change and there is nothing for us to do
5758 */
5759 if (unlinked_nodes && ctx_node) {
5760 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
5761 rc = -1;
5762 goto cleanup;
5763 }
5764 }
5765
Radek Krejci03b71f72016-03-16 11:10:09 +01005766 if (rc) {
5767 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005768 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005769 }
Radek Krejci51093642016-03-29 10:14:59 +02005770 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005771 }
5772
Michal Vasko944a5642016-03-21 11:48:58 +01005773 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, LYXP_WHEN);
Michal Vaskocf024702015-10-08 15:01:42 +02005774
Michal Vasko8146d4c2016-05-09 15:50:29 +02005775 if (!set.val.bool) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005776 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Radek Krejci0b7704f2016-03-18 12:16:14 +01005777 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02005778 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005779 }
Radek Krejci51093642016-03-29 10:14:59 +02005780
5781 /* free xpath set content */
5782 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005783 }
5784
Michal Vasko90fc2a32016-08-24 15:58:58 +02005785 sparent = lys_parent(sparent);
Michal Vaskocf024702015-10-08 15:01:42 +02005786 }
5787
Radek Krejci0b7704f2016-03-18 12:16:14 +01005788 node->when_status |= LYD_WHEN_TRUE;
Radek Krejci03b71f72016-03-16 11:10:09 +01005789
Radek Krejci51093642016-03-29 10:14:59 +02005790cleanup:
Radek Krejci51093642016-03-29 10:14:59 +02005791 /* free xpath set content */
5792 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node ? ctx_node : node, 0);
5793
Radek Krejci46165822016-08-26 14:06:27 +02005794 if (result) {
5795 if (node->when_status & LYD_WHEN_TRUE) {
5796 *result = 1;
5797 } else {
5798 *result = 0;
5799 }
5800 }
5801
Radek Krejci51093642016-03-29 10:14:59 +02005802 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005803}
5804
Radek Krejcicbb473e2016-09-16 14:48:32 +02005805static int
5806check_leafref_features(struct lys_type *type)
5807{
5808 struct lys_node *iter;
5809 struct ly_set *src_parents, *trg_parents, *features;
5810 unsigned int i, j, size, x;
5811 int ret = EXIT_SUCCESS;
5812
5813 assert(type->parent);
5814
5815 src_parents = ly_set_new();
5816 trg_parents = ly_set_new();
5817 features = ly_set_new();
5818
5819 /* get parents chain of source (leafref) */
5820 for (iter = (struct lys_node *)type->parent; iter; iter = iter->parent) {
5821 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
5822 continue;
5823 }
5824 ly_set_add(src_parents, iter, LY_SET_OPT_USEASLIST);
5825 }
5826 /* get parents chain of target */
5827 for (iter = (struct lys_node *)type->info.lref.target; iter; iter = iter->parent) {
5828 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
5829 continue;
5830 }
5831 ly_set_add(trg_parents, iter, LY_SET_OPT_USEASLIST);
5832 }
5833
5834 /* compare the features used in if-feature statements in the rest of both
5835 * chains of parents. The set of features used for target must be a subset
5836 * of features used for the leafref. This is not a perfect, we should compare
5837 * the truth tables but it could require too much resources, so we simplify that */
5838 for (i = 0; i < src_parents->number; i++) {
5839 iter = src_parents->set.s[i]; /* shortcut */
5840 if (!iter->iffeature_size) {
5841 continue;
5842 }
5843 for (j = 0; j < iter->iffeature_size; j++) {
5844 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
5845 for (; size; size--) {
5846 if (!iter->iffeature[j].features[size - 1]) {
5847 /* not yet resolved feature, postpone this check */
5848 ret = EXIT_FAILURE;
5849 goto cleanup;
5850 }
5851 ly_set_add(features, iter->iffeature[j].features[size - 1], 0);
5852 }
5853 }
5854 }
5855 x = features->number;
5856 for (i = 0; i < trg_parents->number; i++) {
5857 iter = trg_parents->set.s[i]; /* shortcut */
5858 if (!iter->iffeature_size) {
5859 continue;
5860 }
5861 for (j = 0; j < iter->iffeature_size; j++) {
5862 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
5863 for (; size; size--) {
5864 if (!iter->iffeature[j].features[size - 1]) {
5865 /* not yet resolved feature, postpone this check */
5866 ret = EXIT_FAILURE;
5867 goto cleanup;
5868 }
5869 if ((unsigned int)ly_set_add(features, iter->iffeature[j].features[size - 1], 0) >= x) {
5870 /* the feature is not present in features set of target's parents chain */
5871 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, type->parent, "leafref", type->info.lref.path);
5872 LOGVAL(LYE_SPEC, LY_VLOG_LYS, type->parent,
5873 "Leafref is not conditional based on \"%s\" feature as its target.",
5874 iter->iffeature[j].features[size - 1]->name);
5875 ret = -1;
5876 goto cleanup;
5877 }
5878 }
5879 }
5880 }
5881
5882cleanup:
5883 ly_set_free(features);
5884 ly_set_free(src_parents);
5885 ly_set_free(trg_parents);
5886
5887 return ret;
5888}
5889
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005890/**
Michal Vaskobb211122015-08-19 14:03:11 +02005891 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005892 *
5893 * @param[in] mod Main module.
5894 * @param[in] item Item to resolve. Type determined by \p type.
5895 * @param[in] type Type of the unresolved item.
5896 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02005897 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005898 *
5899 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
5900 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005901static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02005902resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Radek Krejci48464ed2016-03-17 15:44:09 +01005903 struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005904{
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005905 /* has_str - whether the str_snode is a string in a dictionary that needs to be freed */
Radek Krejcic79c6b12016-07-26 15:11:49 +02005906 int rc = -1, has_str = 0, tpdf_flag = 0, i, k;
5907 unsigned int j;
Radek Krejcic13db382016-08-16 10:52:42 +02005908 struct lys_node *node, *par_grp;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005909 const char *expr;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005910
Radek Krejcic79c6b12016-07-26 15:11:49 +02005911 struct ly_set *refs, *procs;
5912 struct lys_feature *ref, *feat;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005913 struct lys_ident *ident;
5914 struct lys_type *stype;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005915 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01005916 struct lyxml_elem *yin;
Pavol Vicana0e4e672016-02-24 12:20:04 +01005917 struct yang_type *yang;
Radek Krejcid09d1a52016-08-11 14:05:45 +02005918 struct unres_list_uniq *unique_info;
Radek Krejcicbb473e2016-09-16 14:48:32 +02005919 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005920
5921 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005922 case UNRES_IDENT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005923 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01005924 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005925 ident = item;
5926
Radek Krejci018f1f52016-08-03 16:01:20 +02005927 rc = resolve_base_ident(mod, ident, expr, "identity", NULL, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005928 break;
5929 case UNRES_TYPE_IDENTREF:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005930 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01005931 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005932 stype = item;
5933
Radek Krejci018f1f52016-08-03 16:01:20 +02005934 rc = resolve_base_ident(mod, NULL, expr, "type", stype, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005935 break;
5936 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02005937 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005938 stype = item;
5939
Radek Krejci2f12f852016-01-08 12:59:57 +01005940 /* HACK - when there is no parent, we are in top level typedef and in that
5941 * case, the path has to contain absolute path, so we let the resolve_path_arg_schema()
5942 * know it via tpdf_flag */
5943 if (!node) {
Radek Krejci4f78b532016-02-17 13:43:00 +01005944 tpdf_flag = 1;
Radek Krejci2f12f852016-01-08 12:59:57 +01005945 node = (struct lys_node *)stype->parent;
5946 }
5947
Radek Krejci27fe55e2016-09-13 17:13:35 +02005948 if (!lys_node_module(node)->implemented) {
5949 /* not implemented module, don't bother with resolving the leafref
5950 * if the module is set to be implemented, tha path will be resolved then */
5951 rc = 0;
5952 break;
5953 }
Radek Krejci48464ed2016-03-17 15:44:09 +01005954 rc = resolve_path_arg_schema(stype->info.lref.path, node, tpdf_flag,
Michal Vasko1e62a092015-12-01 12:27:20 +01005955 (const struct lys_node **)&stype->info.lref.target);
Michal Vasko01c6fd22016-05-20 11:43:05 +02005956 if (!tpdf_flag && !rc) {
5957 assert(stype->info.lref.target);
Radek Krejcicbb473e2016-09-16 14:48:32 +02005958 /* check if leafref and its target are under a common if-features */
5959 rc = check_leafref_features(stype);
5960 if (rc) {
5961 break;
5962 }
5963
Radek Krejci46c4cd72016-01-21 15:13:52 +01005964 /* store the backlink from leafref target */
Michal Vasko01c6fd22016-05-20 11:43:05 +02005965 if (lys_leaf_add_leafref_target(stype->info.lref.target, (struct lys_node *)stype->parent)) {
5966 rc = -1;
Radek Krejci46c4cd72016-01-21 15:13:52 +01005967 }
Radek Krejci46c4cd72016-01-21 15:13:52 +01005968 }
5969
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005970 break;
Radek Krejci3a5501d2016-07-18 22:03:34 +02005971 case UNRES_TYPE_DER_TPDF:
5972 tpdf_flag = 1;
5973 /* no break */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005974 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01005975 /* parent */
5976 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005977 stype = item;
5978
Michal Vasko88c29542015-11-27 14:57:53 +01005979 /* HACK type->der is temporarily unparsed type statement */
5980 yin = (struct lyxml_elem *)stype->der;
5981 stype->der = NULL;
5982
Pavol Vicana0e4e672016-02-24 12:20:04 +01005983 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
5984 yang = (struct yang_type *)yin;
Radek Krejci3a5501d2016-07-18 22:03:34 +02005985 rc = yang_check_type(mod, node, yang, tpdf_flag, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01005986
5987 if (rc) {
Pavol Vican8bd72e42016-08-29 09:53:05 +02005988 /* may try again later */
5989 stype->der = (struct lys_tpdf *)yang;
Pavol Vicand01d8ae2016-03-01 10:45:59 +01005990 } else {
5991 /* we need to always be able to free this, it's safe only in this case */
Pavol Vican5f0316a2016-04-05 21:21:11 +02005992 lydict_remove(mod->ctx, yang->name);
Pavol Vicand01d8ae2016-03-01 10:45:59 +01005993 free(yang);
Pavol Vicana0e4e672016-02-24 12:20:04 +01005994 }
5995
Michal Vasko88c29542015-11-27 14:57:53 +01005996 } else {
Radek Krejci3a5501d2016-07-18 22:03:34 +02005997 rc = fill_yin_type(mod, node, yin, stype, tpdf_flag, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01005998 if (!rc) {
5999 /* we need to always be able to free this, it's safe only in this case */
6000 lyxml_free(mod->ctx, yin);
6001 } else {
6002 /* may try again later, put all back how it was */
6003 stype->der = (struct lys_tpdf *)yin;
6004 }
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006005 }
Radek Krejcic13db382016-08-16 10:52:42 +02006006 if (rc == EXIT_SUCCESS) {
Radek Krejci2c2fce82016-08-01 13:52:26 +02006007 /* it does not make sense to have leaf-list of empty type */
6008 if (!tpdf_flag && node->nodetype == LYS_LEAFLIST && stype->base == LY_TYPE_EMPTY) {
6009 LOGWRN("The leaf-list \"%s\" is of \"empty\" type, which does not make sense.", node->name);
6010 }
Radek Krejci9b6aad22016-09-20 15:55:51 +02006011 } else if (rc == EXIT_FAILURE && stype->base != LY_TYPE_ERR) {
Radek Krejcic13db382016-08-16 10:52:42 +02006012 /* forward reference - in case the type is in grouping, we have to make the grouping unusable
6013 * by uses statement until the type is resolved. We do that the same way as uses statements inside
6014 * grouping - the grouping's nacm member (not used un grouping) is used to increase the number of
6015 * 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 +02006016 * 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 +02006017 * of the type's base member. */
6018 for (par_grp = node; par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
6019 if (par_grp) {
6020 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci9b6aad22016-09-20 15:55:51 +02006021 stype->base = LY_TYPE_ERR;
Radek Krejcic13db382016-08-16 10:52:42 +02006022 }
Radek Krejci2c2fce82016-08-01 13:52:26 +02006023 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006024 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006025 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006026 iff_data = str_snode;
6027 rc = resolve_feature(iff_data->fname, strlen(iff_data->fname), iff_data->node, item);
Radek Krejci9ff0a922016-07-14 13:08:05 +02006028 if (!rc) {
6029 /* success */
Radek Krejci9de2c042016-10-19 16:53:06 +02006030 if (iff_data->infeature) {
6031 /* store backlink into the target feature to allow reverse changes in case of changing feature status */
6032 feat = *((struct lys_feature **)item);
6033 if (!feat->depfeatures) {
6034 feat->depfeatures = ly_set_new();
6035 }
Radek Krejci85a54be2016-10-20 12:39:56 +02006036 ly_set_add(feat->depfeatures, iff_data->node, LY_SET_OPT_USEASLIST);
Radek Krejci9de2c042016-10-19 16:53:06 +02006037 }
6038 /* cleanup temporary data */
Radek Krejcicbb473e2016-09-16 14:48:32 +02006039 lydict_remove(mod->ctx, iff_data->fname);
6040 free(iff_data);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006041 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006042 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006043 case UNRES_FEATURE:
6044 feat = (struct lys_feature *)item;
6045
6046 if (feat->iffeature_size) {
6047 refs = ly_set_new();
6048 procs = ly_set_new();
6049 ly_set_add(procs, feat, 0);
6050
6051 while (procs->number) {
6052 ref = procs->set.g[procs->number - 1];
6053 ly_set_rm_index(procs, procs->number - 1);
6054
6055 for (i = 0; i < ref->iffeature_size; i++) {
6056 resolve_iffeature_getsizes(&ref->iffeature[i], NULL, &j);
6057 for (; j > 0 ; j--) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006058 if (ref->iffeature[i].features[j - 1]) {
Radek Krejcic79c6b12016-07-26 15:11:49 +02006059 if (ref->iffeature[i].features[j - 1] == feat) {
6060 LOGVAL(LYE_CIRC_FEATURES, LY_VLOG_NONE, NULL, feat->name);
6061 goto featurecheckdone;
6062 }
6063
6064 if (ref->iffeature[i].features[j - 1]->iffeature_size) {
6065 k = refs->number;
6066 if (ly_set_add(refs, ref->iffeature[i].features[j - 1], 0) == k) {
6067 /* not yet seen feature, add it for processing */
6068 ly_set_add(procs, ref->iffeature[i].features[j - 1], 0);
6069 }
6070 }
6071 } else {
6072 /* forward reference */
6073 rc = EXIT_FAILURE;
6074 goto featurecheckdone;
6075 }
6076 }
6077
6078 }
6079 }
6080 rc = EXIT_SUCCESS;
6081
6082featurecheckdone:
6083 ly_set_free(refs);
6084 ly_set_free(procs);
6085 }
6086
6087 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006088 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006089 rc = resolve_unres_schema_uses(item, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006090 break;
6091 case UNRES_TYPE_DFLT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006092 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006093 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006094 stype = item;
6095
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006096 rc = check_default(stype, expr, mod);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006097 break;
6098 case UNRES_CHOICE_DFLT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006099 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006100 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006101 choic = item;
6102
Radek Krejcie00d2312016-08-12 15:27:49 +02006103 if (!choic->dflt) {
6104 choic->dflt = resolve_choice_dflt(choic, expr);
6105 }
Michal Vasko7955b362015-09-04 14:18:15 +02006106 if (choic->dflt) {
Radek Krejcie00d2312016-08-12 15:27:49 +02006107 rc = lyp_check_mandatory_choice((struct lys_node *)choic);
Michal Vasko7955b362015-09-04 14:18:15 +02006108 } else {
6109 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006110 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006111 break;
6112 case UNRES_LIST_KEYS:
Radek Krejci4f78b532016-02-17 13:43:00 +01006113 has_str = 1;
Radek Krejci48464ed2016-03-17 15:44:09 +01006114 rc = resolve_list_keys(item, str_snode);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006115 break;
6116 case UNRES_LIST_UNIQ:
Radek Krejcid09d1a52016-08-11 14:05:45 +02006117 unique_info = (struct unres_list_uniq *)item;
6118 rc = resolve_unique(unique_info->list, unique_info->expr, unique_info->trg_type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006119 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006120 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006121 rc = resolve_augment(item, NULL);
Michal Vasko7178e692016-02-12 15:58:05 +01006122 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006123 case UNRES_XPATH:
6124 node = (struct lys_node *)item;
Michal Vasko9e635ac2016-10-17 11:44:09 +02006125 rc = check_node_xpath(node);
Michal Vasko508a50d2016-09-07 14:50:33 +02006126 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006127 default:
6128 LOGINT;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006129 break;
6130 }
6131
Radek Krejci54081ce2016-08-12 15:21:47 +02006132 if (has_str && !rc) {
6133 /* the string is no more needed in case of success.
6134 * In case of forward reference, we will try to resolve the string later */
Radek Krejci4f78b532016-02-17 13:43:00 +01006135 lydict_remove(mod->ctx, str_snode);
6136 }
6137
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006138 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006139}
6140
Michal Vaskof02e3742015-08-05 16:27:02 +02006141/* logs directly */
6142static void
Radek Krejci48464ed2016-03-17 15:44:09 +01006143print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006144{
Michal Vaskocb34dc62016-05-20 14:38:37 +02006145 struct lyxml_elem *xml;
6146 struct lyxml_attr *attr;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006147 struct unres_iffeat_data *iff_data;
Radek Krejci76e15e12016-06-22 11:02:24 +02006148 const char *type_name = NULL;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006149
Michal Vaskof02e3742015-08-05 16:27:02 +02006150 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02006151 case UNRES_IDENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006152 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identity", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006153 break;
6154 case UNRES_TYPE_IDENTREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006155 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identityref", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006156 break;
6157 case UNRES_TYPE_LEAFREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006158 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "leafref",
6159 ((struct lys_type *)item)->info.lref.path);
Michal Vaskof02e3742015-08-05 16:27:02 +02006160 break;
Radek Krejci3a5501d2016-07-18 22:03:34 +02006161 case UNRES_TYPE_DER_TPDF:
Michal Vaskof02e3742015-08-05 16:27:02 +02006162 case UNRES_TYPE_DER:
Michal Vaskocb34dc62016-05-20 14:38:37 +02006163 xml = (struct lyxml_elem *)((struct lys_type *)item)->der;
6164 if (xml->flags & LY_YANG_STRUCTURE_FLAG) {
6165 type_name = ((struct yang_type *)xml)->name;
6166 } else {
6167 LY_TREE_FOR(xml->attr, attr) {
6168 if ((attr->type == LYXML_ATTR_STD) && !strcmp(attr->name, "name")) {
6169 type_name = attr->value;
6170 break;
6171 }
6172 }
6173 assert(attr);
6174 }
6175 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "derived type", type_name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006176 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006177 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006178 iff_data = str_node;
6179 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "if-feature", iff_data->fname);
Michal Vaskof02e3742015-08-05 16:27:02 +02006180 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006181 case UNRES_FEATURE:
6182 LOGVRB("There are unresolved if-features for \"%s\" feature circular dependency check, it will be attempted later",
6183 ((struct lys_feature *)item)->name);
6184 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006185 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006186 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "uses", ((struct lys_node_uses *)item)->name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006187 break;
6188 case UNRES_TYPE_DFLT:
Radek Krejci2e2de832016-10-13 16:12:26 +02006189 if (str_node) {
6190 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "type default", (char *)str_node);
6191 } /* else no default value in the type itself, but we are checking some restrictions against
6192 * possible default value of some base type. The failure is caused by not resolved base type,
6193 * so it was already reported */
Michal Vaskof02e3742015-08-05 16:27:02 +02006194 break;
6195 case UNRES_CHOICE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006196 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "choice default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006197 break;
6198 case UNRES_LIST_KEYS:
Radek Krejci48464ed2016-03-17 15:44:09 +01006199 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list keys", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006200 break;
6201 case UNRES_LIST_UNIQ:
Radek Krejci48464ed2016-03-17 15:44:09 +01006202 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list unique", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006203 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006204 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006205 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "augment target",
6206 ((struct lys_node_augment *)item)->target_name);
Michal Vasko7178e692016-02-12 15:58:05 +01006207 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006208 case UNRES_XPATH:
6209 LOGVRB("Resolving %s \"%s\" with the context node \"%s\" failed, it will be attempted later.", "XPath",
6210 (char *)str_node, ((struct lys_node *)item)->name);
6211 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006212 default:
6213 LOGINT;
Michal Vaskof02e3742015-08-05 16:27:02 +02006214 break;
6215 }
6216}
6217
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006218/**
Michal Vaskobb211122015-08-19 14:03:11 +02006219 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006220 *
6221 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006222 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006223 *
Michal Vasko92b8a382015-08-19 14:03:49 +02006224 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006225 */
Michal Vaskof02e3742015-08-05 16:27:02 +02006226int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006227resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02006228{
Radek Krejci010e54b2016-03-15 09:40:34 +01006229 uint32_t i, resolved = 0, unres_count, res_count;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006230 int rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006231
6232 assert(unres);
6233
Michal Vaskoe8734262016-09-29 14:12:06 +02006234 LOGVRB("Resolving \"%s\" unresolved schema nodes and their constraints...", mod->name);
Radek Krejci010e54b2016-03-15 09:40:34 +01006235 ly_vlog_hide(1);
Michal Vasko51054ca2015-08-12 12:20:00 +02006236
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006237 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02006238 do {
Michal Vasko88c29542015-11-27 14:57:53 +01006239 unres_count = 0;
6240 res_count = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02006241
6242 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006243 /* UNRES_TYPE_LEAFREF must be resolved (for storing leafref target pointers);
Radek Krejcic79c6b12016-07-26 15:11:49 +02006244 * if-features are resolved here to make sure that we will have all if-features for
6245 * later check of feature circular dependency */
Radek Krejci018f1f52016-08-03 16:01:20 +02006246 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006247 continue;
6248 }
Radek Krejci018f1f52016-08-03 16:01:20 +02006249 /* processes UNRES_USES, UNRES_IFFEAT, UNRES_TYPE_DER, UNRES_TYPE_DER_TPDF, UNRES_TYPE_LEAFREF,
Radek Krejcie00d2312016-08-12 15:27:49 +02006250 * UNRES_CHOICE_DFLT and UNRES_IDENT */
Michal Vasko51054ca2015-08-12 12:20:00 +02006251
Michal Vasko88c29542015-11-27 14:57:53 +01006252 ++unres_count;
Radek Krejci48464ed2016-03-17 15:44:09 +01006253 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006254 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006255 unres->type[i] = UNRES_RESOLVED;
6256 ++resolved;
Michal Vasko88c29542015-11-27 14:57:53 +01006257 ++res_count;
Michal Vasko89e15322015-08-17 15:46:55 +02006258 } else if (rc == -1) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006259 ly_vlog_hide(0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02006260 /* print the error */
6261 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006262 return -1;
Radek Krejcic2a180f2016-06-22 13:28:16 +02006263 } else {
6264 /* forward reference, erase ly_errno */
6265 ly_errno = LY_SUCCESS;
6266 ly_vecode = LYVE_SUCCESS;
Michal Vasko51054ca2015-08-12 12:20:00 +02006267 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006268 }
Michal Vasko88c29542015-11-27 14:57:53 +01006269 } while (res_count && (res_count < unres_count));
Michal Vasko51054ca2015-08-12 12:20:00 +02006270
Michal Vasko88c29542015-11-27 14:57:53 +01006271 if (res_count < unres_count) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006272 /* just print the errors */
6273 ly_vlog_hide(0);
6274
6275 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006276 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006277 continue;
6278 }
6279 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
6280 }
Michal Vasko92b8a382015-08-19 14:03:49 +02006281 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006282 }
6283
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006284 /* the rest */
6285 for (i = 0; i < unres->count; ++i) {
6286 if (unres->type[i] == UNRES_RESOLVED) {
6287 continue;
6288 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02006289
Radek Krejci48464ed2016-03-17 15:44:09 +01006290 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01006291 if (rc == 0) {
Pavol Vican88e16c92016-09-07 15:41:50 +02006292 if (unres->type[i] == UNRES_LIST_UNIQ) {
6293 /* free the allocated structure */
6294 free(unres->item[i]);
6295 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006296 unres->type[i] = UNRES_RESOLVED;
6297 ++resolved;
6298 } else if (rc == -1) {
6299 ly_vlog_hide(0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02006300 /* print the error */
6301 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
6302 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006303 }
6304 }
6305
Radek Krejci010e54b2016-03-15 09:40:34 +01006306 ly_vlog_hide(0);
6307
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006308 if (resolved < unres->count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006309 /* try to resolve the unresolved nodes again, it will not resolve anything, but it will print
6310 * all the validation errors
6311 */
6312 for (i = 0; i < unres->count; ++i) {
6313 if (unres->type[i] == UNRES_RESOLVED) {
6314 continue;
6315 }
Radek Krejci48464ed2016-03-17 15:44:09 +01006316 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01006317 }
Michal Vasko92b8a382015-08-19 14:03:49 +02006318 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006319 }
6320
Michal Vaskoe8734262016-09-29 14:12:06 +02006321 LOGVRB("All \"%s\" schema nodes and constraints resolved.", mod->name);
Radek Krejcic071c542016-01-27 14:57:51 +01006322 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006323 return EXIT_SUCCESS;
6324}
6325
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006326/**
Michal Vaskobb211122015-08-19 14:03:11 +02006327 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006328 *
6329 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006330 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006331 * @param[in] item Item to resolve. Type determined by \p type.
6332 * @param[in] type Type of the unresolved item.
6333 * @param[in] str String argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006334 *
Michal Vasko3767fb22016-07-21 12:10:57 +02006335 * @return EXIT_SUCCESS on success, EXIT_FAILURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006336 */
6337int
Radek Krejci48464ed2016-03-17 15:44:09 +01006338unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
6339 const char *str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006340{
Radek Krejci54081ce2016-08-12 15:21:47 +02006341 int rc;
6342 const char *dictstr;
6343
6344 dictstr = lydict_insert(mod->ctx, str, 0);
6345 rc = unres_schema_add_node(mod, unres, item, type, (struct lys_node *)dictstr);
6346
6347 if (rc == -1) {
6348 lydict_remove(mod->ctx, dictstr);
6349 }
6350 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006351}
6352
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006353/**
Michal Vaskobb211122015-08-19 14:03:11 +02006354 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006355 *
6356 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006357 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006358 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01006359 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006360 * @param[in] snode Schema node argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006361 *
Michal Vasko3767fb22016-07-21 12:10:57 +02006362 * @return EXIT_SUCCESS on success, EXIT_FIALURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006363 */
6364int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006365unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Radek Krejci48464ed2016-03-17 15:44:09 +01006366 struct lys_node *snode)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006367{
Michal Vaskoef486d72016-09-27 12:10:44 +02006368 int rc, log_hidden;
Michal Vasko88c29542015-11-27 14:57:53 +01006369 struct lyxml_elem *yin;
Radek Krejci010e54b2016-03-15 09:40:34 +01006370 char *path, *msg;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006371
Michal Vasko9bf425b2015-10-22 11:42:03 +02006372 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
6373 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006374
Michal Vaskoef486d72016-09-27 12:10:44 +02006375 if (*ly_vlog_hide_location()) {
6376 log_hidden = 1;
6377 } else {
6378 log_hidden = 0;
6379 ly_vlog_hide(1);
6380 }
Radek Krejci48464ed2016-03-17 15:44:09 +01006381 rc = resolve_unres_schema_item(mod, item, type, snode, unres);
Michal Vaskoef486d72016-09-27 12:10:44 +02006382 if (!log_hidden) {
6383 ly_vlog_hide(0);
6384 }
6385
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006386 if (rc != EXIT_FAILURE) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006387 if (rc == -1 && ly_errno == LY_EVALID) {
Radek Krejci76e15e12016-06-22 11:02:24 +02006388 if (ly_log_level >= LY_LLERR) {
6389 path = strdup(ly_errpath());
6390 msg = strdup(ly_errmsg());
6391 LOGERR(LY_EVALID, "%s%s%s%s", msg, path[0] ? " (path: " : "", path[0] ? path : "", path[0] ? ")" : "");
6392 free(path);
6393 free(msg);
6394 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006395 }
Radek Krejcid09d1a52016-08-11 14:05:45 +02006396 if (type == UNRES_LIST_UNIQ) {
6397 /* free the allocated structure */
6398 free(item);
Pavol Vican88e16c92016-09-07 15:41:50 +02006399 } else if (rc == -1 && type == UNRES_IFFEAT) {
6400 /* free the allocated resources */
6401 free(*((char **)item));
6402 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006403 return rc;
Radek Krejcif347abc2016-06-22 10:18:47 +02006404 } else {
6405 /* erase info about validation errors */
6406 ly_errno = LY_SUCCESS;
6407 ly_vecode = LYVE_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006408 }
6409
Radek Krejci48464ed2016-03-17 15:44:09 +01006410 print_unres_schema_item_fail(item, type, snode);
Michal Vaskof02e3742015-08-05 16:27:02 +02006411
Michal Vasko88c29542015-11-27 14:57:53 +01006412 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
Radek Krejci3a5501d2016-07-18 22:03:34 +02006413 if (type == UNRES_TYPE_DER || type == UNRES_TYPE_DER_TPDF) {
Michal Vasko88c29542015-11-27 14:57:53 +01006414 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
Pavol Vicana0e4e672016-02-24 12:20:04 +01006415 if (!(yin->flags & LY_YANG_STRUCTURE_FLAG)) {
6416 lyxml_unlink_elem(mod->ctx, yin, 1);
6417 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
6418 }
Michal Vasko88c29542015-11-27 14:57:53 +01006419 }
6420
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006421 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01006422 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
6423 if (!unres->item) {
6424 LOGMEM;
6425 return -1;
6426 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006427 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01006428 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
6429 if (!unres->type) {
6430 LOGMEM;
6431 return -1;
6432 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006433 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01006434 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
6435 if (!unres->str_snode) {
6436 LOGMEM;
6437 return -1;
6438 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006439 unres->str_snode[unres->count-1] = snode;
Radek Krejcic071c542016-01-27 14:57:51 +01006440 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
6441 if (!unres->module) {
6442 LOGMEM;
6443 return -1;
6444 }
6445 unres->module[unres->count-1] = mod;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006446
Michal Vasko3767fb22016-07-21 12:10:57 +02006447 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006448}
6449
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006450/**
Michal Vaskobb211122015-08-19 14:03:11 +02006451 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006452 *
6453 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006454 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006455 * @param[in] item Old item to be resolved.
6456 * @param[in] type Type of the old unresolved item.
6457 * @param[in] new_item New item to use in the duplicate.
6458 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02006459 * @return EXIT_SUCCESS on success, EXIT_FAILURE if item is not in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006460 */
Michal Vaskodad19402015-08-06 09:51:53 +02006461int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006462unres_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 +02006463{
6464 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006465 struct unres_list_uniq aux_uniq;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006466 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006467
Michal Vaskocf024702015-10-08 15:01:42 +02006468 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006469
Radek Krejcid09d1a52016-08-11 14:05:45 +02006470 /* hack for UNRES_LIST_UNIQ, which stores multiple items behind its item */
6471 if (type == UNRES_LIST_UNIQ) {
6472 aux_uniq.list = item;
6473 aux_uniq.expr = ((struct unres_list_uniq *)new_item)->expr;
6474 item = &aux_uniq;
6475 }
Michal Vasko878e38d2016-09-05 12:17:53 +02006476 i = unres_schema_find(unres, -1, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006477
6478 if (i == -1) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006479 if (type == UNRES_LIST_UNIQ) {
6480 free(new_item);
6481 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02006482 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006483 }
6484
Radek Krejcic79c6b12016-07-26 15:11:49 +02006485 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT) ||
Radek Krejcib69f3232016-09-16 17:41:07 +02006486 (type == UNRES_FEATURE) || (type == UNRES_LIST_UNIQ)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01006487 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006488 LOGINT;
6489 return -1;
6490 }
Radek Krejcicbb473e2016-09-16 14:48:32 +02006491 } else if (type == UNRES_IFFEAT) {
6492 /* duplicate unres_iffeature_data */
6493 iff_data = malloc(sizeof *iff_data);
6494 iff_data->fname = lydict_insert(mod->ctx, ((struct unres_iffeat_data *)unres->str_snode[i])->fname, 0);
6495 iff_data->node = ((struct unres_iffeat_data *)unres->str_snode[i])->node;
6496 if (unres_schema_add_node(mod, unres, new_item, type, (struct lys_node *)iff_data) == -1) {
6497 LOGINT;
6498 return -1;
6499 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006500 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01006501 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006502 LOGINT;
6503 return -1;
6504 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006505 }
Michal Vaskodad19402015-08-06 09:51:53 +02006506
6507 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006508}
6509
Michal Vaskof02e3742015-08-05 16:27:02 +02006510/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006511int
Michal Vasko878e38d2016-09-05 12:17:53 +02006512unres_schema_find(struct unres_schema *unres, int start_on_backwards, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006513{
Michal Vasko878e38d2016-09-05 12:17:53 +02006514 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006515 struct unres_list_uniq *aux_uniq1, *aux_uniq2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006516
Michal Vasko878e38d2016-09-05 12:17:53 +02006517 if (start_on_backwards > 0) {
6518 i = start_on_backwards;
6519 } else {
6520 i = unres->count - 1;
6521 }
6522 for (; i > -1; i--) {
6523 if (unres->type[i] != type) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006524 continue;
6525 }
6526 if (type != UNRES_LIST_UNIQ) {
Michal Vasko878e38d2016-09-05 12:17:53 +02006527 if (unres->item[i] == item) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006528 break;
6529 }
6530 } else {
6531 aux_uniq1 = (struct unres_list_uniq *)unres->item[i - 1];
6532 aux_uniq2 = (struct unres_list_uniq *)item;
6533 if ((aux_uniq1->list == aux_uniq2->list) && ly_strequal(aux_uniq1->expr, aux_uniq2->expr, 0)) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006534 break;
6535 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006536 }
6537 }
6538
Michal Vasko878e38d2016-09-05 12:17:53 +02006539 return i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006540}
Michal Vasko8bcdf292015-08-19 14:04:43 +02006541
Michal Vaskoede9c472016-06-07 09:38:15 +02006542static void
6543unres_schema_free_item(struct ly_ctx *ctx, struct unres_schema *unres, uint32_t i)
6544{
6545 struct lyxml_elem *yin;
6546 struct yang_type *yang;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006547 struct unres_iffeat_data *iff_data;
Michal Vaskoede9c472016-06-07 09:38:15 +02006548
6549 switch (unres->type[i]) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02006550 case UNRES_TYPE_DER_TPDF:
Michal Vaskoede9c472016-06-07 09:38:15 +02006551 case UNRES_TYPE_DER:
6552 yin = (struct lyxml_elem *)((struct lys_type *)unres->item[i])->der;
6553 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6554 yang =(struct yang_type *)yin;
6555 yang->type->base = yang->base;
6556 lydict_remove(ctx, yang->name);
6557 free(yang);
6558 } else {
6559 lyxml_free(ctx, yin);
6560 }
6561 break;
Pavol Vican88e16c92016-09-07 15:41:50 +02006562 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006563 iff_data = (struct unres_iffeat_data *)unres->str_snode[i];
6564 lydict_remove(ctx, iff_data->fname);
6565 free(unres->str_snode[i]);
Pavol Vican88e16c92016-09-07 15:41:50 +02006566 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02006567 case UNRES_IDENT:
6568 case UNRES_TYPE_IDENTREF:
Michal Vaskoede9c472016-06-07 09:38:15 +02006569 case UNRES_TYPE_DFLT:
6570 case UNRES_CHOICE_DFLT:
6571 case UNRES_LIST_KEYS:
Michal Vaskoede9c472016-06-07 09:38:15 +02006572 lydict_remove(ctx, (const char *)unres->str_snode[i]);
6573 break;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006574 case UNRES_LIST_UNIQ:
6575 free(unres->item[i]);
6576 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02006577 default:
6578 break;
6579 }
6580 unres->type[i] = UNRES_RESOLVED;
6581}
6582
Michal Vasko88c29542015-11-27 14:57:53 +01006583void
Radek Krejcic071c542016-01-27 14:57:51 +01006584unres_schema_free(struct lys_module *module, struct unres_schema **unres)
Michal Vasko88c29542015-11-27 14:57:53 +01006585{
6586 uint32_t i;
Radek Krejcic071c542016-01-27 14:57:51 +01006587 unsigned int unresolved = 0;
Michal Vasko88c29542015-11-27 14:57:53 +01006588
Radek Krejcic071c542016-01-27 14:57:51 +01006589 if (!unres || !(*unres)) {
6590 return;
Michal Vasko88c29542015-11-27 14:57:53 +01006591 }
6592
Radek Krejcic071c542016-01-27 14:57:51 +01006593 assert(module || (*unres)->count == 0);
6594
6595 for (i = 0; i < (*unres)->count; ++i) {
6596 if ((*unres)->module[i] != module) {
6597 if ((*unres)->type[i] != UNRES_RESOLVED) {
6598 unresolved++;
6599 }
6600 continue;
6601 }
Michal Vaskoede9c472016-06-07 09:38:15 +02006602
6603 /* free heap memory for the specific item */
6604 unres_schema_free_item(module->ctx, *unres, i);
Radek Krejcic071c542016-01-27 14:57:51 +01006605 }
6606
Michal Vaskoede9c472016-06-07 09:38:15 +02006607 /* free it all */
Radek Krejcic071c542016-01-27 14:57:51 +01006608 if (!module || (!unresolved && !module->type)) {
6609 free((*unres)->item);
6610 free((*unres)->type);
6611 free((*unres)->str_snode);
6612 free((*unres)->module);
Radek Krejcic071c542016-01-27 14:57:51 +01006613 free((*unres));
6614 (*unres) = NULL;
6615 }
Michal Vasko88c29542015-11-27 14:57:53 +01006616}
6617
Radek Krejci7de36cf2016-09-12 16:18:50 +02006618static int
Radek Krejci9b6aad22016-09-20 15:55:51 +02006619resolve_leafref(struct lyd_node_leaf_list *leaf, struct lys_type *type)
Radek Krejci7de36cf2016-09-12 16:18:50 +02006620{
Radek Krejci7de36cf2016-09-12 16:18:50 +02006621 struct unres_data matches;
6622 uint32_t i;
6623
Radek Krejci9b6aad22016-09-20 15:55:51 +02006624 assert(type->base == LY_TYPE_LEAFREF);
6625
6626 /* init */
Radek Krejci7de36cf2016-09-12 16:18:50 +02006627 memset(&matches, 0, sizeof matches);
Radek Krejci7de36cf2016-09-12 16:18:50 +02006628
6629 /* EXIT_FAILURE return keeps leaf->value.lefref NULL, handled later */
Radek Krejci9b6aad22016-09-20 15:55:51 +02006630 if (resolve_path_arg_data((struct lyd_node *)leaf, type->info.lref.path, &matches) == -1) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02006631 return -1;
6632 }
6633
6634 /* check that value matches */
6635 for (i = 0; i < matches.count; ++i) {
6636 if (ly_strequal(leaf->value_str, ((struct lyd_node_leaf_list *)matches.node[i])->value_str, 1)) {
6637 leaf->value.leafref = matches.node[i];
6638 break;
6639 }
6640 }
6641
6642 free(matches.node);
6643
6644 if (!leaf->value.leafref) {
6645 /* reference not found */
6646 if (type->info.lref.req > -1) {
6647 LOGVAL(LYE_NOLEAFREF, LY_VLOG_LYD, leaf, type->info.lref.path, leaf->value_str);
6648 return EXIT_FAILURE;
6649 } else {
6650 LOGVRB("There is no leafref with the value \"%s\", but it is not required.", leaf->value_str);
6651 }
6652 }
6653
6654 return EXIT_SUCCESS;
6655}
6656
Radek Krejci9b6aad22016-09-20 15:55:51 +02006657API LY_DATA_TYPE
6658lyd_leaf_type(const struct lyd_node_leaf_list *leaf)
6659{
6660 struct lyd_node *node;
6661 struct lys_type *type, *type_iter;
6662 lyd_val value;
6663 int f = 0, r;
6664
6665 if (!leaf || !(leaf->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
6666 return LY_TYPE_ERR;
6667 }
6668
6669 if (leaf->value_type > 0 && (leaf->value_type & LY_DATA_TYPE_MASK) != LY_TYPE_UNION &&
6670 (leaf->value_type & LY_DATA_TYPE_MASK) != LY_TYPE_LEAFREF) {
6671 /* we can get the type directly from the data node (it was already resolved) */
6672 return leaf->value_type & LY_DATA_TYPE_MASK;
6673 }
6674
6675 /* init */
6676 type = &((struct lys_node_leaf *)leaf->schema)->type;
6677 value = leaf->value;
6678 ly_vlog_hide(1);
6679
6680 /* resolve until we get the real data type */
6681 while (1) {
6682 /* get the correct data type from schema */
6683 switch (type->base) {
6684 case LY_TYPE_LEAFREF:
6685 type = &type->info.lref.target->type;
6686 break; /* continue in while loop */
6687 case LY_TYPE_UNION:
6688 type_iter = NULL;
6689 while ((type_iter = lyp_get_next_union_type(type, type_iter, &f))) {
6690 if (type_iter->base == LY_TYPE_LEAFREF) {
6691 if (type_iter->info.lref.req == -1) {
6692 /* target not required, so it always succeeds */
6693 break;
6694 } else {
6695 /* try to resolve leafref */
6696 memset(&((struct lyd_node_leaf_list *)leaf)->value, 0, sizeof leaf->value);
6697 r = resolve_leafref((struct lyd_node_leaf_list *)leaf, type_iter);
6698 /* revert leaf's content affected by resolve_leafref */
6699 ((struct lyd_node_leaf_list *)leaf)->value = value;
6700 if (!r) {
6701 /* success, we can continue with the leafref type */
6702 break;
6703 }
6704 }
6705 } else if (type_iter->base == LY_TYPE_INST) {
6706 if (type_iter->info.inst.req == -1) {
6707 /* target not required, so it always succeeds */
6708 return LY_TYPE_INST;
6709 } else {
6710 /* try to resolve instance-identifier */
6711 ly_errno = 0;
6712 node = resolve_instid((struct lyd_node *)leaf, leaf->value_str);
6713 if (!ly_errno && node) {
6714 /* the real type is instance-identifier */
6715 return LY_TYPE_INST;
6716 }
6717 }
6718 } else {
6719 r = lyp_parse_value_type((struct lyd_node_leaf_list *)leaf, type_iter, 1);
6720 /* revert leaf's content affected by resolve_leafref */
6721 ((struct lyd_node_leaf_list *)leaf)->value = value;
6722 if (!r) {
6723 /* we have the real type */
6724 return type_iter->base;
6725 }
6726 }
6727 f = 0;
6728 }
6729 /* erase ly_errno and ly_vecode */
6730 ly_errno = LY_SUCCESS;
6731 ly_vecode = LYVE_SUCCESS;
6732
6733 if (!type_iter) {
6734 LOGERR(LY_EINVAL, "Unable to get type from union \"%s\" with no valid type.", type->parent->name)
6735 return LY_TYPE_ERR;
6736 }
6737 type = type_iter;
6738 break;
6739 default:
6740 /* we have the real type */
6741 ly_vlog_hide(0);
6742 return type->base;
6743 }
6744 }
6745
6746 ly_vlog_hide(0);
6747 return LY_TYPE_ERR;
6748}
6749
6750static int
6751resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type)
6752{
6753 struct lys_type *datatype = NULL;
6754 int f = 0;
6755
6756 assert(type->base == LY_TYPE_UNION);
6757
6758 memset(&leaf->value, 0, sizeof leaf->value);
6759 while ((datatype = lyp_get_next_union_type(type, datatype, &f))) {
6760 leaf->value_type = datatype->base;
6761
6762 if (datatype->base == LY_TYPE_LEAFREF) {
6763 /* try to resolve leafref */
6764 if (!resolve_leafref(leaf, datatype)) {
6765 /* success */
6766 break;
6767 }
6768 } else if (datatype->base == LY_TYPE_INST) {
6769 /* try to resolve instance-identifier */
6770 ly_errno = 0;
6771 leaf->value.instance = resolve_instid((struct lyd_node *)leaf, leaf->value_str);
6772 if (!ly_errno && (leaf->value.instance || datatype->info.inst.req == -1)) {
6773 /* success */
6774 break;
6775 }
6776 } else {
6777 if (!lyp_parse_value_type(leaf, datatype, 1)) {
6778 /* success */
6779 break;
6780 }
6781 }
6782 f = 0;
6783 }
6784 /* erase ly_errno and ly_vecode */
6785 ly_errno = LY_SUCCESS;
6786 ly_vecode = LYVE_SUCCESS;
6787
6788 if (!datatype) {
6789 /* failure */
6790 LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, (leaf->value_str ? leaf->value_str : ""), leaf->schema->name);
6791 return EXIT_FAILURE;
6792 }
6793
6794 return EXIT_SUCCESS;
6795}
6796
Michal Vasko8bcdf292015-08-19 14:04:43 +02006797/**
6798 * @brief Resolve a single unres data item. Logs directly.
6799 *
Michal Vaskocf024702015-10-08 15:01:42 +02006800 * @param[in] node Data node to resolve.
Michal Vaskocf024702015-10-08 15:01:42 +02006801 * @param[in] type Type of the unresolved item.
Michal Vasko8bcdf292015-08-19 14:04:43 +02006802 *
6803 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
6804 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02006805int
Radek Krejci48464ed2016-03-17 15:44:09 +01006806resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02006807{
Michal Vasko0491ab32015-08-19 14:28:29 +02006808 int rc;
Michal Vasko83a6c462015-10-08 16:43:53 +02006809 struct lyd_node_leaf_list *leaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006810 struct lys_node_leaf *sleaf;
Michal Vaskoc4280842016-04-19 16:10:42 +02006811 struct lyd_node *parent;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006812
Michal Vasko83a6c462015-10-08 16:43:53 +02006813 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02006814 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006815
Michal Vaskocf024702015-10-08 15:01:42 +02006816 switch (type) {
6817 case UNRES_LEAFREF:
6818 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Radek Krejci9b6aad22016-09-20 15:55:51 +02006819 return resolve_leafref(leaf, &sleaf->type);
Michal Vasko8bcdf292015-08-19 14:04:43 +02006820
Michal Vaskocf024702015-10-08 15:01:42 +02006821 case UNRES_INSTID:
Radek Krejci7de36cf2016-09-12 16:18:50 +02006822 assert(sleaf->type.base == LY_TYPE_INST);
Michal Vasko8bcdf292015-08-19 14:04:43 +02006823 ly_errno = 0;
Radek Krejci48464ed2016-03-17 15:44:09 +01006824 leaf->value.instance = resolve_instid(node, leaf->value_str);
Radek Krejci40f17b92016-02-03 14:30:43 +01006825 if (!leaf->value.instance) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02006826 if (ly_errno) {
6827 return -1;
6828 } else if (sleaf->type.info.inst.req > -1) {
Michal Vasko6ac68282016-04-11 10:56:47 +02006829 LOGVAL(LYE_NOREQINS, LY_VLOG_LYD, leaf, leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02006830 return EXIT_FAILURE;
6831 } else {
Michal Vasko9925e282016-09-02 12:45:14 +02006832 LOGVRB("There is no instance identifier \"%s\", but it is not required.", leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02006833 }
6834 }
Michal Vaskocf024702015-10-08 15:01:42 +02006835 break;
6836
Radek Krejci7de36cf2016-09-12 16:18:50 +02006837 case UNRES_UNION:
6838 assert(sleaf->type.base == LY_TYPE_UNION);
Radek Krejci9b6aad22016-09-20 15:55:51 +02006839 return resolve_union(leaf, &sleaf->type);
Radek Krejci7de36cf2016-09-12 16:18:50 +02006840
Michal Vaskocf024702015-10-08 15:01:42 +02006841 case UNRES_WHEN:
Radek Krejci46165822016-08-26 14:06:27 +02006842 if ((rc = resolve_when(node, NULL))) {
Michal Vaskocf024702015-10-08 15:01:42 +02006843 return rc;
6844 }
6845 break;
6846
Michal Vaskobf19d252015-10-08 15:39:17 +02006847 case UNRES_MUST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006848 if ((rc = resolve_must(node, 0))) {
6849 return rc;
6850 }
6851 break;
6852
6853 case UNRES_MUST_INOUT:
6854 if ((rc = resolve_must(node, 1))) {
Michal Vaskobf19d252015-10-08 15:39:17 +02006855 return rc;
6856 }
6857 break;
6858
Michal Vaskoc4280842016-04-19 16:10:42 +02006859 case UNRES_EMPTYCONT:
6860 do {
6861 parent = node->parent;
6862 lyd_free(node);
6863 node = parent;
6864 } while (node && (node->schema->nodetype == LYS_CONTAINER) && !node->child
6865 && !((struct lys_node_container *)node->schema)->presence);
6866 break;
6867
Michal Vaskocf024702015-10-08 15:01:42 +02006868 default:
Michal Vasko8bcdf292015-08-19 14:04:43 +02006869 LOGINT;
6870 return -1;
6871 }
6872
6873 return EXIT_SUCCESS;
6874}
6875
6876/**
Radek Krejci0b7704f2016-03-18 12:16:14 +01006877 * @brief add data unres item
Michal Vasko8bcdf292015-08-19 14:04:43 +02006878 *
6879 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02006880 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02006881 *
Radek Krejci0b7704f2016-03-18 12:16:14 +01006882 * @return 0 on success, -1 on error.
Michal Vasko8bcdf292015-08-19 14:04:43 +02006883 */
6884int
Radek Krejci0b7704f2016-03-18 12:16:14 +01006885unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02006886{
Radek Krejci03b71f72016-03-16 11:10:09 +01006887 assert(unres && node);
Michal Vaskoc4280842016-04-19 16:10:42 +02006888 assert((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006889 || (type == UNRES_MUST_INOUT) || (type == UNRES_UNION) || (type == UNRES_EMPTYCONT));
Michal Vasko8bcdf292015-08-19 14:04:43 +02006890
Radek Krejci03b71f72016-03-16 11:10:09 +01006891 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01006892 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
6893 if (!unres->node) {
6894 LOGMEM;
6895 return -1;
6896 }
Michal Vaskocf024702015-10-08 15:01:42 +02006897 unres->node[unres->count - 1] = node;
Michal Vasko253035f2015-12-17 16:58:13 +01006898 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
6899 if (!unres->type) {
6900 LOGMEM;
6901 return -1;
6902 }
Michal Vaskocf024702015-10-08 15:01:42 +02006903 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006904
Radek Krejci0b7704f2016-03-18 12:16:14 +01006905 if (type == UNRES_WHEN) {
6906 /* remove previous result */
6907 node->when_status = LYD_WHEN;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006908 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006909
6910 return EXIT_SUCCESS;
6911}
6912
6913/**
6914 * @brief Resolve every unres data item in the structure. Logs directly.
6915 *
Radek Krejci082c84f2016-10-17 16:33:06 +02006916 * If options includes LYD_OPT_TRUSTED, the data are considered trusted (when, must conditions are not expected,
6917 * unresolved leafrefs/instids are accepted).
6918 *
6919 * If options includes LYD_OPT_NOAUTODEL, the false resulting when condition on non-default nodes, the error is raised.
6920 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006921 * @param[in] unres Unres data structure to use.
Radek Krejci082c84f2016-10-17 16:33:06 +02006922 * @param[in,out] root Root node of the data tree, can be changed due to autodeletion.
6923 * @param[in] options Data options as described above.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006924 *
6925 * @return EXIT_SUCCESS on success, -1 on error.
6926 */
6927int
Radek Krejci082c84f2016-10-17 16:33:06 +02006928resolve_unres_data(struct unres_data *unres, struct lyd_node **root, int options)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006929{
Radek Krejci0c0086a2016-03-24 15:20:28 +01006930 uint32_t i, j, first = 1, resolved = 0, del_items = 0, when_stmt = 0;
Radek Krejci010e54b2016-03-15 09:40:34 +01006931 int rc, progress;
Radek Krejci03b71f72016-03-16 11:10:09 +01006932 char *msg, *path;
Radek Krejci0b7704f2016-03-18 12:16:14 +01006933 struct lyd_node *parent;
Radek Krejci7de36cf2016-09-12 16:18:50 +02006934 struct lyd_node_leaf_list *leaf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006935
Radek Krejci082c84f2016-10-17 16:33:06 +02006936 assert(root);
Radek Krejci03b71f72016-03-16 11:10:09 +01006937 assert(unres);
Radek Krejci03b71f72016-03-16 11:10:09 +01006938
6939 if (!unres->count) {
6940 return EXIT_SUCCESS;
6941 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006942
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02006943 LOGVRB("Resolving unresolved data nodes and their constraints...");
Radek Krejci010e54b2016-03-15 09:40:34 +01006944 ly_vlog_hide(1);
6945
Radek Krejci0b7704f2016-03-18 12:16:14 +01006946 /* when-stmt first */
Radek Krejci03b71f72016-03-16 11:10:09 +01006947 ly_errno = LY_SUCCESS;
6948 ly_vecode = LYVE_SUCCESS;
Radek Krejci010e54b2016-03-15 09:40:34 +01006949 do {
6950 progress = 0;
Michal Vasko6df94132016-09-22 11:08:09 +02006951 for (i = 0; i < unres->count; i++) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006952 if (unres->type[i] != UNRES_WHEN) {
6953 continue;
6954 }
Radek Krejci082c84f2016-10-17 16:33:06 +02006955 assert(!(options & LYD_OPT_TRUSTED));
Radek Krejci0c0086a2016-03-24 15:20:28 +01006956 if (first) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006957 /* count when-stmt nodes in unres list */
6958 when_stmt++;
6959 }
6960
6961 /* resolve when condition only when all parent when conditions are already resolved */
6962 for (parent = unres->node[i]->parent;
6963 parent && LYD_WHEN_DONE(parent->when_status);
6964 parent = parent->parent) {
6965 if (!parent->parent && (parent->when_status & LYD_WHEN_FALSE)) {
6966 /* the parent node was already unlinked, do not resolve this node,
6967 * it will be removed anyway, so just mark it as resolved
6968 */
6969 unres->node[i]->when_status |= LYD_WHEN_FALSE;
6970 unres->type[i] = UNRES_RESOLVED;
6971 resolved++;
6972 break;
6973 }
6974 }
6975 if (parent) {
6976 continue;
6977 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006978
Radek Krejci48464ed2016-03-17 15:44:09 +01006979 rc = resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01006980 if (!rc) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006981 if (unres->node[i]->when_status & LYD_WHEN_FALSE) {
Radek Krejci082c84f2016-10-17 16:33:06 +02006982 if ((options & LYD_OPT_NOAUTODEL) && !unres->node[i]->dflt) {
Radek Krejci03b71f72016-03-16 11:10:09 +01006983 /* false when condition */
6984 ly_vlog_hide(0);
Radek Krejci76e15e12016-06-22 11:02:24 +02006985 if (ly_log_level >= LY_LLERR) {
6986 path = strdup(ly_errpath());
6987 msg = strdup(ly_errmsg());
6988 LOGERR(LY_EVALID, "%s%s%s%s", msg,
6989 path[0] ? " (path: " : "", path[0] ? path : "", path[0] ? ")" : "");
6990 free(path);
6991 free(msg);
6992 }
Radek Krejci03b71f72016-03-16 11:10:09 +01006993 return -1;
Radek Krejci0b7704f2016-03-18 12:16:14 +01006994 } /* follows else */
6995
Radek Krejci0c0086a2016-03-24 15:20:28 +01006996 /* only unlink now, the subtree can contain another nodes stored in the unres list */
6997 /* if it has parent non-presence containers that would be empty, we should actually
6998 * remove the container
6999 */
Radek Krejci2537fd32016-09-07 16:22:41 +02007000 for (parent = unres->node[i];
7001 parent->parent && parent->parent->schema->nodetype == LYS_CONTAINER;
7002 parent = parent->parent) {
7003 if (((struct lys_node_container *)parent->parent->schema)->presence) {
7004 /* presence container */
7005 break;
Radek Krejci0c0086a2016-03-24 15:20:28 +01007006 }
Radek Krejci2537fd32016-09-07 16:22:41 +02007007 if (parent->next || parent->prev != parent) {
7008 /* non empty (the child we are in and we are going to remove is not the only child) */
7009 break;
7010 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007011 }
Radek Krejci2537fd32016-09-07 16:22:41 +02007012 unres->node[i] = parent;
Radek Krejci0c0086a2016-03-24 15:20:28 +01007013
Radek Krejci0b7704f2016-03-18 12:16:14 +01007014 /* auto-delete */
7015 LOGVRB("auto-delete node \"%s\" due to when condition (%s)", ly_errpath(),
7016 ((struct lys_node_leaf *)unres->node[i]->schema)->when->cond);
Radek Krejci0c0086a2016-03-24 15:20:28 +01007017 if (*root && *root == unres->node[i]) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007018 *root = (*root)->next;
Radek Krejci03b71f72016-03-16 11:10:09 +01007019 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007020
Radek Krejci0b7704f2016-03-18 12:16:14 +01007021 lyd_unlink(unres->node[i]);
7022 unres->type[i] = UNRES_DELETE;
7023 del_items++;
Radek Krejci51fd8162016-03-24 15:49:51 +01007024
7025 /* update the rest of unres items */
7026 for (j = 0; j < unres->count; j++) {
Radek Krejci3db819b2016-03-24 16:29:48 +01007027 if (unres->type[j] == UNRES_RESOLVED || unres->type[j] == UNRES_DELETE) {
Radek Krejci51fd8162016-03-24 15:49:51 +01007028 continue;
7029 }
7030
7031 /* test if the node is in subtree to be deleted */
7032 for (parent = unres->node[j]; parent; parent = parent->parent) {
7033 if (parent == unres->node[i]) {
7034 /* yes, it is */
7035 unres->type[j] = UNRES_RESOLVED;
7036 resolved++;
7037 break;
7038 }
7039 }
7040 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007041 } else {
7042 unres->type[i] = UNRES_RESOLVED;
Radek Krejci03b71f72016-03-16 11:10:09 +01007043 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007044 ly_errno = LY_SUCCESS;
7045 ly_vecode = LYVE_SUCCESS;
Radek Krejci010e54b2016-03-15 09:40:34 +01007046 resolved++;
7047 progress = 1;
7048 } else if (rc == -1) {
7049 ly_vlog_hide(0);
Michal Vasko76e73402016-08-24 16:00:13 +02007050 /* print only this last error */
7051 resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01007052 return -1;
Radek Krejcic2a180f2016-06-22 13:28:16 +02007053 } else {
7054 /* forward reference, erase ly_errno */
7055 ly_errno = LY_SUCCESS;
Radek Krejci010e54b2016-03-15 09:40:34 +01007056 }
7057 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007058 first = 0;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007059 } while (progress && resolved < when_stmt);
Radek Krejci010e54b2016-03-15 09:40:34 +01007060
Radek Krejci0b7704f2016-03-18 12:16:14 +01007061 /* do we have some unresolved when-stmt? */
Radek Krejcid940d732016-03-24 16:02:28 +01007062 if (when_stmt > resolved) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007063 ly_vlog_hide(0);
Radek Krejci76e15e12016-06-22 11:02:24 +02007064 if (ly_log_level >= LY_LLERR) {
7065 path = strdup(ly_errpath());
7066 msg = strdup(ly_errmsg());
7067 LOGERR(LY_EVALID, "%s%s%s%s", msg, path[0] ? " (path: " : "", path[0] ? path : "", path[0] ? ")" : "");
7068 free(path);
7069 free(msg);
7070 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007071 return -1;
7072 }
7073
7074 for (i = 0; del_items && i < unres->count; i++) {
7075 /* we had some when-stmt resulted to false, so now we have to sanitize the unres list */
7076 if (unres->type[i] != UNRES_DELETE) {
7077 continue;
7078 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007079 if (!unres->node[i]) {
7080 unres->type[i] = UNRES_RESOLVED;
7081 del_items--;
7082 continue;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007083 }
7084
7085 /* really remove the complete subtree */
7086 lyd_free(unres->node[i]);
7087 unres->type[i] = UNRES_RESOLVED;
7088 del_items--;
7089 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007090
7091 /* rest */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007092 for (i = 0; i < unres->count; ++i) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007093 if (unres->type[i] == UNRES_RESOLVED) {
7094 continue;
7095 }
Radek Krejci082c84f2016-10-17 16:33:06 +02007096 assert(!(options & LYD_OPT_TRUSTED) || ((unres->type[i] != UNRES_MUST) && (unres->type[i] != UNRES_MUST_INOUT)));
Radek Krejci010e54b2016-03-15 09:40:34 +01007097
Radek Krejci48464ed2016-03-17 15:44:09 +01007098 rc = resolve_unres_data_item(unres->node[i], unres->type[i]);
Michal Vasko6df94132016-09-22 11:08:09 +02007099 if (rc == -1) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007100 ly_vlog_hide(0);
Michal Vasko96b846c2016-05-18 13:28:58 +02007101 /* print only this last error */
7102 resolve_unres_data_item(unres->node[i], unres->type[i]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007103 return -1;
Radek Krejci082c84f2016-10-17 16:33:06 +02007104 } else if ((rc == 0) || ((options & LYD_OPT_TRUSTED) && ((unres->type[i] == UNRES_LEAFREF) || (unres->type[i] == UNRES_INSTID)))) {
Michal Vasko6df94132016-09-22 11:08:09 +02007105 unres->type[i] = UNRES_RESOLVED;
7106 resolved++;
Radek Krejci082c84f2016-10-17 16:33:06 +02007107 if (options & LYD_OPT_TRUSTED) {
Michal Vasko6df94132016-09-22 11:08:09 +02007108 /* accept it in this case */
7109 if (unres->type[i] == UNRES_LEAFREF) {
7110 LOGVRB("Leafref \"%s\" with value \"%s\" failed to be resolved.",
7111 ((struct lys_node_leaf *)unres->node[i]->schema)->type.info.lref.path,
7112 ((struct lyd_node_leaf_list *)unres->node[i])->value_str);
7113 } else {
7114 LOGVRB("Instance identifier \"%s\" failed to be resolved.",
7115 ((struct lyd_node_leaf_list *)unres->node[i])->value_str);
7116 }
7117 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007118 }
7119 }
7120
Radek Krejci010e54b2016-03-15 09:40:34 +01007121 ly_vlog_hide(0);
7122 if (resolved < unres->count) {
7123 /* try to resolve the unresolved data again, it will not resolve anything, but it will print
7124 * all the validation errors
7125 */
7126 for (i = 0; i < unres->count; ++i) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02007127 if (unres->type[i] == UNRES_UNION) {
7128 /* does not make sense to print specific errors for all
7129 * the data types, just print that the value is invalid */
7130 leaf = (struct lyd_node_leaf_list *)unres->node[i];
7131 LOGVAL(LYE_INVAL, LY_VLOG_LYD, unres->node[i], (leaf->value_str ? leaf->value_str : ""),
7132 leaf->schema->name);
7133 } else if (unres->type[i] != UNRES_RESOLVED) {
7134 resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01007135 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007136 }
7137 return -1;
7138 }
7139
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02007140 LOGVRB("All data nodes and constraints resolved.");
Radek Krejci010e54b2016-03-15 09:40:34 +01007141 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007142 return EXIT_SUCCESS;
7143}