blob: 771a055dd9b3504d66c73d961e48d7dbfb6a5d53 [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 Vaskof9b35d92016-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 *
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200485 * @param[in] mod Module of the context node to get correct prefix in case it is not explicitly specified
Michal Vaskobb211122015-08-19 14:03:11 +0200486 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200487 * @param[out] prefix Points to the prefix, NULL if there is not any.
488 * @param[out] pref_len Length of the prefix, 0 if there is not any.
489 * @param[out] name Points to the node name.
490 * @param[out] nam_len Length of the node name.
491 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
492 * must not be changed between consecutive calls. -1 if the
493 * path is relative.
494 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
495 *
496 * @return Number of characters successfully parsed,
497 * positive on success, negative on failure.
498 */
499static int
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200500parse_path_arg(struct lys_module *mod, const char *id, const char **prefix, int *pref_len,
501 const char **name, int *nam_len, int *parent_times, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200502{
503 int parsed = 0, ret, par_times = 0;
504
505 assert(id);
506 assert(parent_times);
507 if (prefix) {
508 *prefix = NULL;
509 }
510 if (pref_len) {
511 *pref_len = 0;
512 }
513 if (name) {
514 *name = NULL;
515 }
516 if (nam_len) {
517 *nam_len = 0;
518 }
519 if (has_predicate) {
520 *has_predicate = 0;
521 }
522
523 if (!*parent_times && !strncmp(id, "..", 2)) {
524 ++par_times;
525
526 parsed += 2;
527 id += 2;
528
529 while (!strncmp(id, "/..", 3)) {
530 ++par_times;
531
532 parsed += 3;
533 id += 3;
534 }
535 }
536
537 if (!*parent_times) {
538 if (par_times) {
539 *parent_times = par_times;
540 } else {
541 *parent_times = -1;
542 }
543 }
544
545 if (id[0] != '/') {
546 return -parsed;
547 }
548
549 /* skip '/' */
550 ++parsed;
551 ++id;
552
553 /* node-identifier ([prefix:]identifier) */
554 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
555 return -parsed-ret;
556 }
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200557 if (!(*prefix)) {
558 /* actually we always need prefix even it is not specified */
559 *prefix = lys_main_module(mod)->name;
560 *pref_len = strlen(*prefix);
561 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200562
563 parsed += ret;
564 id += ret;
565
566 /* there is no predicate */
567 if ((id[0] == '/') || !id[0]) {
568 return parsed;
569 } else if (id[0] != '[') {
570 return -parsed;
571 }
572
573 if (has_predicate) {
574 *has_predicate = 1;
575 }
576
577 return parsed;
578}
579
580/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200581 * @brief Parse instance-identifier in JSON data format. That means that prefixes
Michal Vaskob2f40be2016-09-08 16:03:48 +0200582 * (which are mandatory for every node-identifier) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200583 *
584 * instance-identifier = 1*("/" (node-identifier *predicate))
585 *
Michal Vaskobb211122015-08-19 14:03:11 +0200586 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200587 * @param[out] model Points to the model name.
588 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200589 * @param[out] name Points to the node name.
590 * @param[out] nam_len Length of the node name.
591 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
592 *
593 * @return Number of characters successfully parsed,
594 * positive on success, negative on failure.
595 */
596static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200597parse_instance_identifier(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
598 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200599{
600 int parsed = 0, ret;
601
Radek Krejci6dc53a22015-08-17 13:27:59 +0200602 if (has_predicate) {
603 *has_predicate = 0;
604 }
605
606 if (id[0] != '/') {
607 return -parsed;
608 }
609
610 ++parsed;
611 ++id;
612
Michal Vaskob2f40be2016-09-08 16:03:48 +0200613 if ((ret = parse_identifier(id)) < 1) {
614 return ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200615 }
616
Michal Vaskob2f40be2016-09-08 16:03:48 +0200617 *model = id;
618 *mod_len = ret;
619
Radek Krejci6dc53a22015-08-17 13:27:59 +0200620 parsed += ret;
621 id += ret;
622
Michal Vaskob2f40be2016-09-08 16:03:48 +0200623 if (id[0] != ':') {
624 return -parsed;
625 }
626
627 ++parsed;
628 ++id;
629
630 if ((ret = parse_identifier(id)) < 1) {
631 return ret;
632 }
633
634 *name = id;
635 *nam_len = ret;
636
637 parsed += ret;
638 id += ret;
639
Radek Krejci4967cb62016-09-14 16:40:28 +0200640 if (id[0] == '[' && has_predicate) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200641 *has_predicate = 1;
642 }
643
644 return parsed;
645}
646
647/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200648 * @brief Parse predicate (instance-identifier) in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200649 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200650 *
651 * predicate = "[" *WSP (predicate-expr / pos) *WSP "]"
652 * predicate-expr = (node-identifier / ".") *WSP "=" *WSP
653 * ((DQUOTE string DQUOTE) /
654 * (SQUOTE string SQUOTE))
655 * pos = non-negative-integer-value
656 *
Michal Vaskobb211122015-08-19 14:03:11 +0200657 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200658 * @param[out] model Points to the model name.
659 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200660 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
661 * @param[out] nam_len Length of the node name.
662 * @param[out] value Value the node-identifier must have (string from the grammar),
663 * NULL if there is not any.
664 * @param[out] val_len Length of the value, 0 if there is not any.
665 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
666 *
667 * @return Number of characters successfully parsed,
668 * positive on success, negative on failure.
669 */
670static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200671parse_predicate(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
672 const char **value, int *val_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200673{
674 const char *ptr;
675 int parsed = 0, ret;
676 char quote;
677
678 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200679 if (model) {
680 *model = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200681 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200682 if (mod_len) {
683 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200684 }
685 if (name) {
686 *name = NULL;
687 }
688 if (nam_len) {
689 *nam_len = 0;
690 }
691 if (value) {
692 *value = NULL;
693 }
694 if (val_len) {
695 *val_len = 0;
696 }
697 if (has_predicate) {
698 *has_predicate = 0;
699 }
700
701 if (id[0] != '[') {
702 return -parsed;
703 }
704
705 ++parsed;
706 ++id;
707
708 while (isspace(id[0])) {
709 ++parsed;
710 ++id;
711 }
712
713 /* pos */
714 if (isdigit(id[0])) {
715 if (name) {
716 *name = id;
717 }
718
719 if (id[0] == '0') {
Michal Vaskof2f28a12016-09-09 12:43:06 +0200720 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200721 }
722
723 while (isdigit(id[0])) {
724 ++parsed;
725 ++id;
726 }
727
728 if (nam_len) {
729 *nam_len = id-(*name);
730 }
731
Michal Vaskof2f28a12016-09-09 12:43:06 +0200732 /* "." or node-identifier */
Radek Krejci6dc53a22015-08-17 13:27:59 +0200733 } else {
Michal Vaskof2f28a12016-09-09 12:43:06 +0200734 if (id[0] == '.') {
735 if (name) {
736 *name = id;
737 }
738 if (nam_len) {
739 *nam_len = 1;
740 }
741
742 ++parsed;
743 ++id;
744
745 } else {
746 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
747 return -parsed+ret;
748 } else if (model && !*model) {
749 return -parsed;
750 }
751
752 parsed += ret;
753 id += ret;
754 }
755
756 while (isspace(id[0])) {
757 ++parsed;
758 ++id;
759 }
760
761 if (id[0] != '=') {
Michal Vasko1f2cc332015-08-19 11:18:32 +0200762 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200763 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200764
Radek Krejci6dc53a22015-08-17 13:27:59 +0200765 ++parsed;
766 ++id;
767
Michal Vaskof2f28a12016-09-09 12:43:06 +0200768 while (isspace(id[0])) {
769 ++parsed;
770 ++id;
771 }
772
773 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
774 if ((id[0] == '\"') || (id[0] == '\'')) {
775 quote = id[0];
776
777 ++parsed;
778 ++id;
779
780 if ((ptr = strchr(id, quote)) == NULL) {
781 return -parsed;
782 }
783 ret = ptr-id;
784
785 if (value) {
786 *value = id;
787 }
788 if (val_len) {
789 *val_len = ret;
790 }
791
792 parsed += ret+1;
793 id += ret+1;
794 } else {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200795 return -parsed;
796 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200797 }
798
799 while (isspace(id[0])) {
800 ++parsed;
801 ++id;
802 }
803
804 if (id[0] != ']') {
805 return -parsed;
806 }
807
808 ++parsed;
809 ++id;
810
811 if ((id[0] == '[') && has_predicate) {
812 *has_predicate = 1;
813 }
814
815 return parsed;
816}
817
818/**
819 * @brief Parse schema-nodeid.
820 *
821 * schema-nodeid = absolute-schema-nodeid /
822 * descendant-schema-nodeid
823 * absolute-schema-nodeid = 1*("/" node-identifier)
Michal Vasko48935352016-03-29 11:52:36 +0200824 * descendant-schema-nodeid = ["." "/"]
Radek Krejci6dc53a22015-08-17 13:27:59 +0200825 * node-identifier
826 * absolute-schema-nodeid
827 *
Michal Vaskobb211122015-08-19 14:03:11 +0200828 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200829 * @param[out] mod_name Points to the module name, NULL if there is not any.
830 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Michal Vasko48935352016-03-29 11:52:36 +0200831 * @param[out] name Points to the node name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200832 * @param[out] nam_len Length of the node name.
833 * @param[out] is_relative Flag to mark whether the nodeid is absolute or descendant. Must be -1
834 * on the first call, must not be changed between consecutive calls.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100835 * @param[out] has_predicate Flag to mark whether there is a predicate specified. It cannot be
836 * based on the grammar, in those cases use NULL.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200837 *
838 * @return Number of characters successfully parsed,
839 * positive on success, negative on failure.
840 */
Michal Vasko22448d32016-03-16 13:17:29 +0100841int
Michal Vasko723e50c2015-10-20 15:20:29 +0200842parse_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 +0100843 int *is_relative, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200844{
845 int parsed = 0, ret;
846
847 assert(id);
848 assert(is_relative);
Michal Vasko723e50c2015-10-20 15:20:29 +0200849 if (mod_name) {
850 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200851 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200852 if (mod_name_len) {
853 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200854 }
855 if (name) {
856 *name = NULL;
857 }
858 if (nam_len) {
859 *nam_len = 0;
860 }
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100861 if (has_predicate) {
862 *has_predicate = 0;
863 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200864
865 if (id[0] != '/') {
866 if (*is_relative != -1) {
867 return -parsed;
868 } else {
869 *is_relative = 1;
870 }
Michal Vasko48935352016-03-29 11:52:36 +0200871 if (!strncmp(id, "./", 2)) {
872 parsed += 2;
873 id += 2;
874 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200875 } else {
876 if (*is_relative == -1) {
877 *is_relative = 0;
878 }
879 ++parsed;
880 ++id;
881 }
882
Michal Vasko723e50c2015-10-20 15:20:29 +0200883 if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200884 return -parsed+ret;
885 }
886
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100887 parsed += ret;
888 id += ret;
889
890 if ((id[0] == '[') && has_predicate) {
891 *has_predicate = 1;
892 }
893
894 return parsed;
895}
896
897/**
898 * @brief Parse schema predicate (special format internally used).
899 *
900 * predicate = "[" *WSP predicate-expr *WSP "]"
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200901 * predicate-expr = "." / identifier / key-with-value
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100902 * key-with-value = identifier *WSP "=" *WSP
903 * ((DQUOTE string DQUOTE) /
904 * (SQUOTE string SQUOTE))
905 *
906 * @param[in] id Identifier to use.
907 * @param[out] name Points to the list key name.
908 * @param[out] nam_len Length of \p name.
Michal Vasko22448d32016-03-16 13:17:29 +0100909 * @param[out] value Points to the key value. If specified, key-with-value is expected.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100910 * @param[out] val_len Length of \p value.
911 * @param[out] has_predicate Flag to mark whether there is another predicate specified.
912 */
Michal Vasko22448d32016-03-16 13:17:29 +0100913int
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200914parse_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 +0100915 int *has_predicate)
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100916{
917 const char *ptr;
918 int parsed = 0, ret;
919 char quote;
920
921 assert(id);
922 if (name) {
923 *name = NULL;
924 }
925 if (nam_len) {
926 *nam_len = 0;
927 }
928 if (value) {
929 *value = NULL;
930 }
931 if (val_len) {
932 *val_len = 0;
933 }
934 if (has_predicate) {
935 *has_predicate = 0;
936 }
937
938 if (id[0] != '[') {
939 return -parsed;
940 }
941
942 ++parsed;
943 ++id;
944
945 while (isspace(id[0])) {
946 ++parsed;
947 ++id;
948 }
949
Michal Vasko22448d32016-03-16 13:17:29 +0100950 /* identifier */
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200951 if (id[0] == '.') {
952 ret = 1;
953 } else if ((ret = parse_identifier(id)) < 1) {
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100954 return -parsed + ret;
955 }
956 if (name) {
957 *name = id;
958 }
959 if (nam_len) {
960 *nam_len = ret;
961 }
962
963 parsed += ret;
964 id += ret;
965
966 while (isspace(id[0])) {
967 ++parsed;
968 ++id;
969 }
970
971 /* there is value as well */
972 if (id[0] == '=') {
973 ++parsed;
974 ++id;
975
976 while (isspace(id[0])) {
977 ++parsed;
978 ++id;
979 }
980
981 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
982 if ((id[0] == '\"') || (id[0] == '\'')) {
983 quote = id[0];
984
985 ++parsed;
986 ++id;
987
988 if ((ptr = strchr(id, quote)) == NULL) {
989 return -parsed;
990 }
991 ret = ptr - id;
992
993 if (value) {
994 *value = id;
995 }
996 if (val_len) {
997 *val_len = ret;
998 }
999
1000 parsed += ret + 1;
1001 id += ret + 1;
1002 } else {
1003 return -parsed;
1004 }
1005
1006 while (isspace(id[0])) {
1007 ++parsed;
1008 ++id;
1009 }
Michal Vasko22448d32016-03-16 13:17:29 +01001010 } else if (value) {
1011 /* if value was expected, it's mandatory */
1012 return -parsed;
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001013 }
1014
1015 if (id[0] != ']') {
1016 return -parsed;
1017 }
1018
1019 ++parsed;
1020 ++id;
1021
1022 if ((id[0] == '[') && has_predicate) {
1023 *has_predicate = 1;
1024 }
1025
1026 return parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +02001027}
1028
1029/**
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001030 * @brief Resolve (find) a feature definition. Logs directly.
1031 *
1032 * @param[in] feat_name Feature name to resolve.
1033 * @param[in] len Length of \p feat_name.
1034 * @param[in] node Node with the if-feature expression.
Radek Krejci9ff0a922016-07-14 13:08:05 +02001035 * @param[out] feature Pointer to be set to point to the feature definition, if feature not found
1036 * (return code 1), the pointer is untouched.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001037 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02001038 * @return 0 on success, 1 on forward reference, -1 on error.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001039 */
1040static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001041resolve_feature(const char *feat_name, uint16_t len, const struct lys_node *node, struct lys_feature **feature)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001042{
1043 char *str;
1044 const char *mod_name, *name;
1045 int mod_name_len, nam_len, i, j;
1046 const struct lys_module *module;
1047
Radek Krejci9ff0a922016-07-14 13:08:05 +02001048 assert(feature);
1049
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001050 /* check prefix */
1051 if ((i = parse_node_identifier(feat_name, &mod_name, &mod_name_len, &name, &nam_len)) < 1) {
1052 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, feat_name[-i], &feat_name[-i]);
1053 return -1;
1054 }
1055
1056 module = lys_get_import_module(lys_node_module(node), NULL, 0, mod_name, mod_name_len);
1057 if (!module) {
1058 /* identity refers unknown data model */
1059 LOGVAL(LYE_INMOD_LEN, LY_VLOG_NONE, NULL, mod_name_len, mod_name);
1060 return -1;
1061 }
1062
Radek Krejci9ff0a922016-07-14 13:08:05 +02001063 if (module != node->module && module == lys_node_module(node)) {
1064 /* first, try to search directly in submodule where the feature was mentioned */
1065 for (j = 0; j < node->module->features_size; j++) {
1066 if (!strncmp(name, node->module->features[j].name, nam_len) && !node->module->features[j].name[nam_len]) {
1067 /* check status */
1068 if (lyp_check_status(node->flags, lys_node_module(node), node->name, node->module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001069 node->module->features[j].module, node->module->features[j].name, NULL)) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001070 return -1;
1071 }
1072 *feature = &node->module->features[j];
1073 return 0;
1074 }
1075 }
1076 }
1077
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001078 /* search in the identified module ... */
1079 for (j = 0; j < module->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001080 if (!strncmp(name, module->features[j].name, nam_len) && !module->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001081 /* check status */
1082 if (lyp_check_status(node->flags, lys_node_module(node), node->name, module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001083 module->features[j].module, module->features[j].name, NULL)) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001084 return -1;
1085 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001086 *feature = &module->features[j];
1087 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001088 }
1089 }
1090 /* ... and all its submodules */
1091 for (i = 0; i < module->inc_size; i++) {
1092 if (!module->inc[i].submodule) {
1093 /* not yet resolved */
1094 continue;
1095 }
1096 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001097 if (!strncmp(name, module->inc[i].submodule->features[j].name, nam_len)
1098 && !module->inc[i].submodule->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001099 /* check status */
1100 if (lyp_check_status(node->flags, lys_node_module(node), node->name,
1101 module->inc[i].submodule->features[j].flags,
1102 module->inc[i].submodule->features[j].module,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001103 module->inc[i].submodule->features[j].name, NULL)) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001104 return -1;
1105 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001106 *feature = &module->inc[i].submodule->features[j];
1107 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001108 }
1109 }
1110 }
1111
1112 /* not found */
1113 str = strndup(feat_name, len);
1114 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, "feature", str);
1115 free(str);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001116 return 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001117}
1118
Radek Krejci9ff0a922016-07-14 13:08:05 +02001119/*
1120 * @return
Radek Krejci69b8d922016-07-27 13:13:41 +02001121 * - 1 if enabled
1122 * - 0 if disabled
Radek Krejci9ff0a922016-07-14 13:08:05 +02001123 * - -1 if not usable by its if-feature expression
1124 */
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001125static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001126resolve_feature_value(const struct lys_feature *feat)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001127{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001128 int i;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001129
Radek Krejci9ff0a922016-07-14 13:08:05 +02001130 for (i = 0; i < feat->iffeature_size; i++) {
Radek Krejci69b8d922016-07-27 13:13:41 +02001131 if (!resolve_iffeature(&feat->iffeature[i])) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001132 return -1;
1133 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001134 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001135
Radek Krejci69b8d922016-07-27 13:13:41 +02001136 return feat->flags & LYS_FENABLED ? 1 : 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001137}
1138
1139static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001140resolve_iffeature_recursive(struct lys_iffeature *expr, int *index_e, int *index_f)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001141{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001142 uint8_t op;
1143 int rc, a, b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001144
Radek Krejci9ff0a922016-07-14 13:08:05 +02001145 op = iff_getop(expr->expr, *index_e);
1146 (*index_e)++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001147
Radek Krejci9ff0a922016-07-14 13:08:05 +02001148 switch (op) {
1149 case LYS_IFF_F:
1150 /* resolve feature */
1151 return resolve_feature_value(expr->features[(*index_f)++]);
1152 case LYS_IFF_NOT:
1153 rc = resolve_iffeature_recursive(expr, index_e, index_f);
1154 if (rc == -1) {
1155 /* one of the referenced feature is hidden by its if-feature,
1156 * so this if-feature expression is always false */
1157 return -1;
1158 } else {
1159 /* invert result */
1160 return rc ? 0 : 1;
1161 }
1162 case LYS_IFF_AND:
1163 case LYS_IFF_OR:
1164 a = resolve_iffeature_recursive(expr, index_e, index_f);
1165 b = resolve_iffeature_recursive(expr, index_e, index_f);
1166 if (a == -1 || b == -1) {
1167 /* one of the referenced feature is hidden by its if-feature,
1168 * so this if-feature expression is always false */
1169 return -1;
1170 } else if (op == LYS_IFF_AND) {
1171 return a && b;
1172 } else { /* LYS_IFF_OR */
1173 return a || b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001174 }
1175 }
1176
Radek Krejci9ff0a922016-07-14 13:08:05 +02001177 return -1;
1178}
1179
1180int
1181resolve_iffeature(struct lys_iffeature *expr)
1182{
1183 int rc = -1;
1184 int index_e = 0, index_f = 0;
1185
1186 if (expr->expr) {
1187 rc = resolve_iffeature_recursive(expr, &index_e, &index_f);
1188 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001189 return (rc == 1) ? 1 : 0;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001190}
1191
1192struct iff_stack {
1193 int size;
1194 int index; /* first empty item */
1195 uint8_t *stack;
1196};
1197
1198static int
1199iff_stack_push(struct iff_stack *stack, uint8_t value)
1200{
1201 if (stack->index == stack->size) {
1202 stack->size += 4;
1203 stack->stack = ly_realloc(stack->stack, stack->size * sizeof *stack->stack);
1204 if (!stack->stack) {
1205 LOGMEM;
1206 stack->size = 0;
1207 return EXIT_FAILURE;
1208 }
1209 }
1210
1211 stack->stack[stack->index++] = value;
1212 return EXIT_SUCCESS;
1213}
1214
1215static uint8_t
1216iff_stack_pop(struct iff_stack *stack)
1217{
1218 stack->index--;
1219 return stack->stack[stack->index];
1220}
1221
1222static void
1223iff_stack_clean(struct iff_stack *stack)
1224{
1225 stack->size = 0;
1226 free(stack->stack);
1227}
1228
1229static void
1230iff_setop(uint8_t *list, uint8_t op, int pos)
1231{
1232 uint8_t *item;
1233 uint8_t mask = 3;
1234
1235 assert(pos >= 0);
1236 assert(op <= 3); /* max 2 bits */
1237
1238 item = &list[pos / 4];
1239 mask = mask << 2 * (pos % 4);
1240 *item = (*item) & ~mask;
1241 *item = (*item) | (op << 2 * (pos % 4));
1242}
1243
1244uint8_t
1245iff_getop(uint8_t *list, int pos)
1246{
1247 uint8_t *item;
1248 uint8_t mask = 3, result;
1249
1250 assert(pos >= 0);
1251
1252 item = &list[pos / 4];
1253 result = (*item) & (mask << 2 * (pos % 4));
1254 return result >> 2 * (pos % 4);
1255}
1256
1257#define LYS_IFF_LP 0x04 /* ( */
1258#define LYS_IFF_RP 0x08 /* ) */
1259
Radek Krejcicbb473e2016-09-16 14:48:32 +02001260/* internal structure for passing data for UNRES_IFFEAT */
1261struct unres_iffeat_data {
1262 struct lys_node *node;
1263 const char *fname;
1264};
1265
Radek Krejci9ff0a922016-07-14 13:08:05 +02001266void
1267resolve_iffeature_getsizes(struct lys_iffeature *iffeat, unsigned int *expr_size, unsigned int *feat_size)
1268{
1269 unsigned int e = 0, f = 0, r = 0;
1270 uint8_t op;
1271
1272 assert(iffeat);
1273
1274 if (!iffeat->expr) {
1275 goto result;
1276 }
1277
1278 do {
1279 op = iff_getop(iffeat->expr, e++);
1280 switch (op) {
1281 case LYS_IFF_NOT:
1282 if (!r) {
1283 r += 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001284 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001285 break;
1286 case LYS_IFF_AND:
1287 case LYS_IFF_OR:
1288 if (!r) {
1289 r += 2;
1290 } else {
1291 r += 1;
1292 }
1293 break;
1294 case LYS_IFF_F:
1295 f++;
1296 if (r) {
1297 r--;
1298 }
1299 break;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001300 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001301 } while(r);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001302
Radek Krejci9ff0a922016-07-14 13:08:05 +02001303result:
1304 if (expr_size) {
1305 *expr_size = e;
1306 }
1307 if (feat_size) {
1308 *feat_size = f;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001309 }
1310}
1311
1312int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001313resolve_iffeature_compile(struct lys_iffeature *iffeat_expr, const char *value, struct lys_node *node,
1314 struct unres_schema *unres)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001315{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001316 const char *c = value;
1317 int r, rc = EXIT_FAILURE;
Radek Krejci69b8d922016-07-27 13:13:41 +02001318 int i, j, last_not, checkversion = 0;
1319 unsigned int f_size = 0, expr_size = 0, f_exp = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001320 uint8_t op;
1321 struct iff_stack stack = {0, 0, NULL};
Radek Krejcicbb473e2016-09-16 14:48:32 +02001322 struct unres_iffeat_data *iff_data;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001323
Radek Krejci9ff0a922016-07-14 13:08:05 +02001324 assert(c);
1325
1326 if (isspace(c[0])) {
1327 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, c[0], c);
1328 return EXIT_FAILURE;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001329 }
1330
Radek Krejci9ff0a922016-07-14 13:08:05 +02001331 /* pre-parse the expression to get sizes for arrays, also do some syntax checks of the expression */
1332 for (i = j = last_not = 0; c[i]; i++) {
1333 if (c[i] == '(') {
Radek Krejci69b8d922016-07-27 13:13:41 +02001334 checkversion = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001335 j++;
1336 continue;
1337 } else if (c[i] == ')') {
1338 j--;
1339 continue;
1340 } else if (isspace(c[i])) {
1341 continue;
1342 }
1343
1344 if (!strncmp(&c[i], "not", r = 3) || !strncmp(&c[i], "and", r = 3) || !strncmp(&c[i], "or", r = 2)) {
1345 if (c[i + r] == '\0') {
Radek Krejcia98da3f2016-07-27 14:05:22 +02001346 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
Radek Krejci9ff0a922016-07-14 13:08:05 +02001347 return EXIT_FAILURE;
1348 } else if (!isspace(c[i + r])) {
1349 /* feature name starting with the not/and/or */
1350 last_not = 0;
1351 f_size++;
1352 } else if (c[i] == 'n') { /* not operation */
1353 if (last_not) {
1354 /* double not */
1355 expr_size = expr_size - 2;
1356 last_not = 0;
1357 } else {
1358 last_not = 1;
1359 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001360 } else { /* and, or */
1361 f_exp++;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001362 /* not a not operation */
1363 last_not = 0;
1364 }
1365 i += r;
1366 } else {
1367 f_size++;
1368 last_not = 0;
1369 }
1370 expr_size++;
1371
1372 while (!isspace(c[i])) {
1373 if (!c[i] || c[i] == ')') {
1374 i--;
1375 break;
1376 }
1377 i++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001378 }
1379 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001380 if (j || f_exp != f_size) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001381 /* not matching count of ( and ) */
1382 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1383 return EXIT_FAILURE;
1384 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001385
Radek Krejci69b8d922016-07-27 13:13:41 +02001386 if (checkversion || expr_size > 1) {
1387 /* check that we have 1.1 module */
1388 if (node->module->version != 2) {
1389 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1390 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "YANG 1.1 if-feature expression found in 1.0 module.");
1391 return EXIT_FAILURE;
1392 }
1393 }
1394
Radek Krejci9ff0a922016-07-14 13:08:05 +02001395 /* allocate the memory */
1396 iffeat_expr->expr = calloc((j = (expr_size / 4) + ((expr_size % 4) ? 1 : 0)), sizeof *iffeat_expr->expr);
Radek Krejcicbb473e2016-09-16 14:48:32 +02001397 iffeat_expr->features = calloc(f_size, sizeof *iffeat_expr->features);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001398 stack.size = expr_size;
1399 stack.stack = malloc(expr_size * sizeof *stack.stack);
1400 if (!stack.stack || !iffeat_expr->expr || !iffeat_expr->features) {
1401 LOGMEM;
1402 goto error;
1403 }
1404 f_size--; expr_size--; /* used as indexes from now */
1405
1406 for (i--; i >= 0; i--) {
1407 if (c[i] == ')') {
1408 /* push it on stack */
1409 iff_stack_push(&stack, LYS_IFF_RP);
1410 continue;
1411 } else if (c[i] == '(') {
1412 /* pop from the stack into result all operators until ) */
1413 while((op = iff_stack_pop(&stack)) != LYS_IFF_RP) {
1414 iff_setop(iffeat_expr->expr, op, expr_size--);
1415 }
1416 continue;
1417 } else if (isspace(c[i])) {
1418 continue;
1419 }
1420
1421 /* end operator or operand -> find beginning and get what is it */
1422 j = i + 1;
1423 while (i >= 0 && !isspace(c[i]) && c[i] != '(') {
1424 i--;
1425 }
1426 i++; /* get back by one step */
1427
1428 if (!strncmp(&c[i], "not ", 4)) {
1429 if (stack.index && stack.stack[stack.index - 1] == LYS_IFF_NOT) {
1430 /* double not */
1431 iff_stack_pop(&stack);
1432 } else {
1433 /* not has the highest priority, so do not pop from the stack
1434 * as in case of AND and OR */
1435 iff_stack_push(&stack, LYS_IFF_NOT);
1436 }
1437 } else if (!strncmp(&c[i], "and ", 4)) {
1438 /* as for OR - pop from the stack all operators with the same or higher
1439 * priority and store them to the result, then push the AND to the stack */
1440 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_AND) {
1441 op = iff_stack_pop(&stack);
1442 iff_setop(iffeat_expr->expr, op, expr_size--);
1443 }
1444 iff_stack_push(&stack, LYS_IFF_AND);
1445 } else if (!strncmp(&c[i], "or ", 3)) {
1446 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_OR) {
1447 op = iff_stack_pop(&stack);
1448 iff_setop(iffeat_expr->expr, op, expr_size--);
1449 }
1450 iff_stack_push(&stack, LYS_IFF_OR);
1451 } else {
1452 /* feature name, length is j - i */
1453
1454 /* add it to the result */
1455 iff_setop(iffeat_expr->expr, LYS_IFF_F, expr_size--);
1456
1457 /* now get the link to the feature definition. Since it can be
Radek Krejcicbb473e2016-09-16 14:48:32 +02001458 * forward referenced, we have to keep the feature name in auxiliary
1459 * structure passed into unres */
1460 iff_data = malloc(sizeof *iff_data);
1461 iff_data->node = node;
1462 iff_data->fname = lydict_insert(node->module->ctx, &c[i], j - i);
1463 r = unres_schema_add_node(node->module, unres, &iffeat_expr->features[f_size], UNRES_IFFEAT,
1464 (struct lys_node *)iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001465 f_size--;
1466
1467 if (r == -1) {
Pavol Vican4d084512016-09-29 16:38:12 +02001468 free(iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001469 goto error;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001470 }
1471 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001472 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001473 while (stack.index) {
1474 op = iff_stack_pop(&stack);
1475 iff_setop(iffeat_expr->expr, op, expr_size--);
1476 }
1477
1478 if (++expr_size || ++f_size) {
1479 /* not all expected operators and operands found */
1480 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1481 rc = EXIT_FAILURE;
1482 } else {
1483 rc = EXIT_SUCCESS;
1484 }
1485
1486error:
1487 /* cleanup */
1488 iff_stack_clean(&stack);
1489
1490 return rc;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001491}
1492
1493/**
Michal Vasko3edeaf72016-02-11 13:17:43 +01001494 * @brief Resolve (find) a data node based on a schema-nodeid.
1495 *
1496 * Used for resolving unique statements - so id is expected to be relative and local (without reference to a different
1497 * module).
1498 *
1499 */
1500struct lyd_node *
1501resolve_data_descendant_schema_nodeid(const char *nodeid, struct lyd_node *start)
1502{
1503 char *str, *token, *p;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001504 struct lyd_node *result = NULL, *iter;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001505 const struct lys_node *schema = NULL;
Radek Krejcicc217a62016-04-08 16:58:11 +02001506 int shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001507
1508 assert(nodeid && start);
1509
1510 if (nodeid[0] == '/') {
1511 return NULL;
1512 }
1513
1514 str = p = strdup(nodeid);
1515 if (!str) {
1516 LOGMEM;
1517 return NULL;
1518 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001519
Michal Vasko3edeaf72016-02-11 13:17:43 +01001520 while (p) {
1521 token = p;
1522 p = strchr(p, '/');
1523 if (p) {
1524 *p = '\0';
1525 p++;
1526 }
1527
Radek Krejci5da4eb62016-04-08 14:45:51 +02001528 if (p) {
1529 /* inner node */
Radek Krejcicc217a62016-04-08 16:58:11 +02001530 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema,
Radek Krejcif3c71de2016-04-11 12:45:46 +02001531 LYS_CONTAINER | LYS_CHOICE | LYS_CASE | LYS_LEAF, 0, 0, &schema)
Radek Krejci5da4eb62016-04-08 14:45:51 +02001532 || !schema) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001533 result = NULL;
1534 break;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001535 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001536
Radek Krejci5da4eb62016-04-08 14:45:51 +02001537 if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
1538 continue;
Michal Vaskodcf98e62016-05-05 17:53:53 +02001539 } else if (lys_parent(schema)->nodetype == LYS_CHOICE) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001540 /* shorthand case */
1541 if (!shorthand) {
1542 shorthand = 1;
Michal Vaskodcf98e62016-05-05 17:53:53 +02001543 schema = lys_parent(schema);
Radek Krejcicc217a62016-04-08 16:58:11 +02001544 continue;
1545 } else {
1546 shorthand = 0;
1547 if (schema->nodetype == LYS_LEAF) {
1548 /* should not be here, since we have leaf, which is not a shorthand nor final node */
1549 result = NULL;
1550 break;
1551 }
1552 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001553 }
1554 } else {
1555 /* final node */
Radek Krejcif3c71de2016-04-11 12:45:46 +02001556 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema, LYS_LEAF,
1557 shorthand ? 0 : 1, 0, &schema)
Radek Krejcicc217a62016-04-08 16:58:11 +02001558 || !schema) {
1559 result = NULL;
1560 break;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001561 }
1562 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001563 LY_TREE_FOR(result ? result->child : start, iter) {
1564 if (iter->schema == schema) {
1565 /* move in data tree according to returned schema */
1566 result = iter;
1567 break;
1568 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001569 }
Radek Krejcicc217a62016-04-08 16:58:11 +02001570 if (!iter) {
1571 /* instance not found */
1572 result = NULL;
1573 break;
1574 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001575 }
1576 free(str);
1577
1578 return result;
1579}
1580
Radek Krejcibdf92362016-04-08 14:43:34 +02001581/*
1582 * 0 - ok (done)
1583 * 1 - continue
1584 * 2 - break
1585 * -1 - error
1586 */
1587static int
Radek Krejcicc217a62016-04-08 16:58:11 +02001588schema_nodeid_siblingcheck(const struct lys_node *sibling, int8_t *shorthand, const char *id,
Radek Krejcibdf92362016-04-08 14:43:34 +02001589 const struct lys_module *module, const char *mod_name, int mod_name_len,
Radek Krejci0fa54e92016-09-14 14:01:05 +02001590 int implemented_mod, const struct lys_node **start)
Radek Krejcibdf92362016-04-08 14:43:34 +02001591{
1592 const struct lys_module *prefix_mod;
Radek Krejcicc217a62016-04-08 16:58:11 +02001593 int sh = 0;
Radek Krejcibdf92362016-04-08 14:43:34 +02001594
1595 /* module check */
1596 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Radek Krejci0fa54e92016-09-14 14:01:05 +02001597 if (implemented_mod) {
1598 prefix_mod = lys_get_implemented_module(prefix_mod);
1599 }
Radek Krejcibdf92362016-04-08 14:43:34 +02001600 if (!prefix_mod) {
1601 return -1;
1602 }
1603 if (prefix_mod != lys_node_module(sibling)) {
1604 return 1;
1605 }
1606
1607 /* check for shorthand cases - then 'start' does not change */
Michal Vaskodcf98e62016-05-05 17:53:53 +02001608 if (lys_parent(sibling) && (lys_parent(sibling)->nodetype == LYS_CHOICE) && (sibling->nodetype != LYS_CASE)) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001609 if (*shorthand != -1) {
1610 *shorthand = *shorthand ? 0 : 1;
1611 }
1612 sh = 1;
Radek Krejcibdf92362016-04-08 14:43:34 +02001613 }
1614
1615 /* the result node? */
1616 if (!id[0]) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001617 if (*shorthand == 1) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001618 return 1;
1619 }
1620 return 0;
1621 }
1622
Radek Krejcicc217a62016-04-08 16:58:11 +02001623 if (!sh) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001624 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02001625 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001626 return -1;
1627 }
1628 *start = sibling->child;
1629 }
1630
1631 return 2;
1632}
1633
Michal Vasko3edeaf72016-02-11 13:17:43 +01001634/* start - relative, module - absolute, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1635int
1636resolve_augment_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_module *module,
1637 const struct lys_node **ret)
1638{
1639 const char *name, *mod_name, *id;
1640 const struct lys_node *sibling;
1641 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001642 int8_t shorthand = 0;
Radek Krejci0fa54e92016-09-14 14:01:05 +02001643 int implemented_search = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001644 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcibdf92362016-04-08 14:43:34 +02001645 const struct lys_module *start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001646
1647 assert(nodeid && (start || module) && !(start && module) && ret);
1648
1649 id = nodeid;
1650
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001651 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 +01001652 return ((id - nodeid) - r) + 1;
1653 }
1654 id += r;
1655
1656 if ((is_relative && !start) || (!is_relative && !module)) {
1657 return -1;
1658 }
1659
1660 /* descendant-schema-nodeid */
1661 if (is_relative) {
Michal Vasko4c06fd82016-02-17 13:43:38 +01001662 module = start_mod = start->module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001663
1664 /* absolute-schema-nodeid */
1665 } else {
1666 start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Radek Krejci0fa54e92016-09-14 14:01:05 +02001667 if (start_mod != lys_main_module(module)) {
1668 /* if the submodule augments the mainmodule (or in general a module augments
1669 * itself, we don't want to search for the implemented module but augments
1670 * the module anyway. But when augmenting another module, we need the implemented
1671 * revision of the module if any */
1672 start_mod = lys_get_implemented_module(start_mod);
1673 implemented_search = 1;
1674 }
Michal Vaskoe2905632016-02-11 15:42:24 +01001675 if (!start_mod) {
1676 return -1;
1677 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001678 start = start_mod->data;
1679 }
1680
1681 while (1) {
1682 sibling = NULL;
1683 while ((sibling = lys_getnext(sibling, lys_parent(start), start_mod,
1684 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
1685 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001686 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001687 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len,
1688 implemented_search, &start);
Radek Krejcibdf92362016-04-08 14:43:34 +02001689 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001690 *ret = sibling;
1691 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001692 } else if (r == 1) {
1693 continue;
1694 } else if (r == 2) {
1695 break;
1696 } else {
1697 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001698 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001699 }
1700 }
1701
1702 /* no match */
1703 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001704 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001705 return EXIT_SUCCESS;
1706 }
1707
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001708 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 +01001709 return ((id - nodeid) - r) + 1;
1710 }
1711 id += r;
1712 }
1713
1714 /* cannot get here */
1715 LOGINT;
1716 return -1;
1717}
1718
Radek Krejcif3c71de2016-04-11 12:45:46 +02001719/* unique, refine,
1720 * >0 - unexpected char on position (ret - 1),
1721 * 0 - ok (but ret can still be NULL),
1722 * -1 - error,
1723 * -2 - violated no_innerlist */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001724int
1725resolve_descendant_schema_nodeid(const char *nodeid, const struct lys_node *start, int ret_nodetype,
Radek Krejcif3c71de2016-04-11 12:45:46 +02001726 int check_shorthand, int no_innerlist, const struct lys_node **ret)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001727{
1728 const char *name, *mod_name, *id;
1729 const struct lys_node *sibling;
1730 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001731 int8_t shorthand = check_shorthand ? 0 : -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001732 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcibdf92362016-04-08 14:43:34 +02001733 const struct lys_module *module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001734
1735 assert(nodeid && start && ret);
1736 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1737
1738 id = nodeid;
1739 module = start->module;
1740
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001741 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 +01001742 return ((id - nodeid) - r) + 1;
1743 }
1744 id += r;
1745
1746 if (!is_relative) {
1747 return -1;
1748 }
1749
1750 while (1) {
1751 sibling = NULL;
1752 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
1753 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE))) {
1754 /* name match */
1755 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001756 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len, 0, &start);
Radek Krejcibdf92362016-04-08 14:43:34 +02001757 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001758 if (!(sibling->nodetype & ret_nodetype)) {
1759 /* wrong node type, too bad */
1760 continue;
1761 }
1762 *ret = sibling;
1763 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001764 } else if (r == 1) {
1765 continue;
1766 } else if (r == 2) {
1767 break;
1768 } else {
1769 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001770 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001771 }
1772 }
1773
1774 /* no match */
1775 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001776 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001777 return EXIT_SUCCESS;
Radek Krejcif3c71de2016-04-11 12:45:46 +02001778 } else if (no_innerlist && sibling->nodetype == LYS_LIST) {
1779 *ret = NULL;
1780 return -2;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001781 }
1782
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001783 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 +01001784 return ((id - nodeid) - r) + 1;
1785 }
1786 id += r;
1787 }
1788
1789 /* cannot get here */
1790 LOGINT;
1791 return -1;
1792}
1793
1794/* choice default */
1795int
1796resolve_choice_default_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node **ret)
1797{
1798 /* cannot actually be a path */
1799 if (strchr(nodeid, '/')) {
1800 return -1;
1801 }
1802
Radek Krejcif3c71de2016-04-11 12:45:46 +02001803 return resolve_descendant_schema_nodeid(nodeid, start, LYS_NO_RPC_NOTIF_NODE, 1, 0, ret);
Michal Vasko3edeaf72016-02-11 13:17:43 +01001804}
1805
1806/* uses, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1807static int
1808resolve_uses_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node_grp **ret)
1809{
1810 const struct lys_module *module;
1811 const char *mod_prefix, *name;
1812 int i, mod_prefix_len, nam_len;
1813
1814 /* parse the identifier, it must be parsed on one call */
1815 if (((i = parse_node_identifier(nodeid, &mod_prefix, &mod_prefix_len, &name, &nam_len)) < 1) || nodeid[i]) {
1816 return -i + 1;
1817 }
1818
1819 module = lys_get_import_module(start->module, mod_prefix, mod_prefix_len, NULL, 0);
1820 if (!module) {
1821 return -1;
1822 }
1823 if (module != start->module) {
1824 start = module->data;
1825 }
1826
1827 *ret = lys_find_grouping_up(name, (struct lys_node *)start);
1828
1829 return EXIT_SUCCESS;
1830}
1831
1832int
1833resolve_absolute_schema_nodeid(const char *nodeid, const struct lys_module *module, int ret_nodetype,
1834 const struct lys_node **ret)
1835{
1836 const char *name, *mod_name, *id;
1837 const struct lys_node *sibling, *start;
1838 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001839 int8_t shorthand = 0;
Radek Krejcibdf92362016-04-08 14:43:34 +02001840 const struct lys_module *abs_start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001841
1842 assert(nodeid && module && ret);
1843 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1844
1845 id = nodeid;
1846 start = module->data;
1847
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001848 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 +01001849 return ((id - nodeid) - r) + 1;
1850 }
1851 id += r;
1852
1853 if (is_relative) {
1854 return -1;
1855 }
1856
1857 abs_start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001858 if (!abs_start_mod) {
1859 return -1;
1860 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001861
1862 while (1) {
1863 sibling = NULL;
1864 while ((sibling = lys_getnext(sibling, lys_parent(start), abs_start_mod, LYS_GETNEXT_WITHCHOICE
1865 | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_WITHGROUPING))) {
1866 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001867 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001868 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len, 0, &start);
Radek Krejcibdf92362016-04-08 14:43:34 +02001869 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001870 if (!(sibling->nodetype & ret_nodetype)) {
1871 /* wrong node type, too bad */
1872 continue;
1873 }
1874 *ret = sibling;
1875 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001876 } else if (r == 1) {
1877 continue;
1878 } else if (r == 2) {
1879 break;
1880 } else {
1881 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001882 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001883 }
1884 }
1885
1886 /* no match */
1887 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001888 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001889 return EXIT_SUCCESS;
1890 }
1891
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001892 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 +01001893 return ((id - nodeid) - r) + 1;
1894 }
1895 id += r;
1896 }
1897
1898 /* cannot get here */
1899 LOGINT;
1900 return -1;
1901}
1902
Michal Vaskoe733d682016-03-14 09:08:27 +01001903static int
Michal Vasko3547c532016-03-14 09:40:50 +01001904resolve_json_schema_list_predicate(const char *predicate, const struct lys_node_list *list, int *parsed)
Michal Vaskoe733d682016-03-14 09:08:27 +01001905{
1906 const char *name;
1907 int nam_len, has_predicate, i;
1908
Michal Vasko7b54f7e2016-05-03 15:07:31 +02001909 if (((i = parse_schema_json_predicate(predicate, &name, &nam_len, NULL, NULL, &has_predicate)) < 1)
1910 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001911 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-i], &predicate[-i]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001912 return -1;
1913 }
1914
1915 predicate += i;
1916 *parsed += i;
1917
1918 for (i = 0; i < list->keys_size; ++i) {
1919 if (!strncmp(list->keys[i]->name, name, nam_len) && !list->keys[i]->name[nam_len]) {
1920 break;
1921 }
1922 }
1923
1924 if (i == list->keys_size) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001925 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskoe733d682016-03-14 09:08:27 +01001926 return -1;
1927 }
1928
1929 /* more predicates? */
1930 if (has_predicate) {
Michal Vasko3547c532016-03-14 09:40:50 +01001931 return resolve_json_schema_list_predicate(predicate, list, parsed);
Michal Vaskoe733d682016-03-14 09:08:27 +01001932 }
1933
1934 return 0;
1935}
1936
Michal Vasko8d26e5c2016-09-08 10:03:49 +02001937/* cannot return LYS_GROUPING, LYS_AUGMENT, LYS_USES, logs directly */
Michal Vaskoe733d682016-03-14 09:08:27 +01001938const struct lys_node *
Michal Vasko8d26e5c2016-09-08 10:03:49 +02001939resolve_json_nodeid(const char *nodeid, struct ly_ctx *ctx, const struct lys_node *start)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001940{
Michal Vasko10728b52016-04-07 14:26:29 +02001941 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001942 const char *name, *mod_name, *id;
Michal Vasko3547c532016-03-14 09:40:50 +01001943 const struct lys_node *sibling;
Radek Krejcibdf92362016-04-08 14:43:34 +02001944 int r, nam_len, mod_name_len, is_relative = -1, has_predicate, shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001945 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vaskoe733d682016-03-14 09:08:27 +01001946 const struct lys_module *prefix_mod, *module, *prev_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001947
Michal Vasko3547c532016-03-14 09:40:50 +01001948 assert(nodeid && (ctx || start));
1949 if (!ctx) {
1950 ctx = start->module->ctx;
1951 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001952
1953 id = nodeid;
1954
Michal Vaskoe733d682016-03-14 09:08:27 +01001955 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 +01001956 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001957 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001958 }
1959 id += r;
1960
1961 if (is_relative) {
Michal Vasko3547c532016-03-14 09:40:50 +01001962 assert(start);
1963 start = start->child;
1964 if (!start) {
1965 /* no descendants, fail for sure */
Michal Vasko10728b52016-04-07 14:26:29 +02001966 str = strndup(nodeid, (name + nam_len) - nodeid);
1967 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
1968 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01001969 return NULL;
1970 }
1971 module = start->module;
1972 } else {
1973 if (!mod_name) {
Michal Vasko10728b52016-04-07 14:26:29 +02001974 str = strndup(nodeid, (name + nam_len) - nodeid);
1975 LOGVAL(LYE_PATH_MISSMOD, LY_VLOG_STR, nodeid);
1976 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01001977 return NULL;
Michal Vasko971a3ca2016-04-01 13:09:29 +02001978 } else if (mod_name_len > LY_BUF_SIZE - 1) {
1979 LOGINT;
1980 return NULL;
Michal Vasko3547c532016-03-14 09:40:50 +01001981 }
1982
Michal Vasko971a3ca2016-04-01 13:09:29 +02001983 if (ly_buf_used && module_name[0]) {
1984 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
1985 }
1986 ly_buf_used++;
1987
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02001988 memmove(module_name, mod_name, mod_name_len);
Michal Vasko971a3ca2016-04-01 13:09:29 +02001989 module_name[mod_name_len] = '\0';
1990 module = ly_ctx_get_module(ctx, module_name, NULL);
1991
1992 if (buf_backup) {
1993 /* return previous internal buffer content */
1994 strcpy(module_name, buf_backup);
1995 free(buf_backup);
1996 buf_backup = NULL;
1997 }
1998 ly_buf_used--;
1999
Michal Vasko3547c532016-03-14 09:40:50 +01002000 if (!module) {
Michal Vasko10728b52016-04-07 14:26:29 +02002001 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2002 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2003 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002004 return NULL;
2005 }
2006 start = module->data;
2007
2008 /* now it's as if there was no module name */
2009 mod_name = NULL;
2010 mod_name_len = 0;
Michal Vaskoe733d682016-03-14 09:08:27 +01002011 }
2012
Michal Vaskoe733d682016-03-14 09:08:27 +01002013 prev_mod = module;
2014
Michal Vasko3edeaf72016-02-11 13:17:43 +01002015 while (1) {
2016 sibling = NULL;
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002017 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
2018 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002019 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02002020 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002021 /* module check */
2022 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002023 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko8757e7c2016-03-15 10:41:30 +01002024 LOGINT;
2025 return NULL;
2026 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002027
2028 if (ly_buf_used && module_name[0]) {
2029 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2030 }
2031 ly_buf_used++;
2032
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002033 memmove(module_name, mod_name, mod_name_len);
Michal Vasko8757e7c2016-03-15 10:41:30 +01002034 module_name[mod_name_len] = '\0';
2035 /* will also find an augment module */
2036 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002037
2038 if (buf_backup) {
2039 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002040 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002041 free(buf_backup);
2042 buf_backup = NULL;
2043 }
2044 ly_buf_used--;
2045
Michal Vasko3edeaf72016-02-11 13:17:43 +01002046 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002047 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2048 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2049 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002050 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002051 }
2052 } else {
2053 prefix_mod = prev_mod;
2054 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01002055 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002056 continue;
2057 }
2058
Michal Vaskoe733d682016-03-14 09:08:27 +01002059 /* do we have some predicates on it? */
2060 if (has_predicate) {
2061 r = 0;
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002062 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
2063 if ((r = parse_schema_json_predicate(id, NULL, NULL, NULL, NULL, &has_predicate)) < 1) {
2064 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2065 return NULL;
2066 }
2067 } else if (sibling->nodetype == LYS_LIST) {
2068 if (resolve_json_schema_list_predicate(id, (const struct lys_node_list *)sibling, &r)) {
2069 return NULL;
2070 }
2071 } else {
Michal Vasko43c300e2016-03-22 12:54:27 +01002072 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vaskoe733d682016-03-14 09:08:27 +01002073 return NULL;
Michal Vaskoe733d682016-03-14 09:08:27 +01002074 }
2075 id += r;
2076 }
2077
Radek Krejcibdf92362016-04-08 14:43:34 +02002078 /* check for shorthand cases - then 'start' does not change */
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002079 if (lys_parent(sibling) && (lys_parent(sibling)->nodetype == LYS_CHOICE) && (sibling->nodetype != LYS_CASE)) {
Radek Krejcibdf92362016-04-08 14:43:34 +02002080 shorthand = ~shorthand;
2081 }
2082
Michal Vasko3edeaf72016-02-11 13:17:43 +01002083 /* the result node? */
2084 if (!id[0]) {
Radek Krejcibdf92362016-04-08 14:43:34 +02002085 if (shorthand) {
2086 /* wrong path for shorthand */
Michal Vasko025e0452016-05-17 16:14:20 +02002087 str = strndup(nodeid, (name + nam_len) - nodeid);
2088 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
Michal Vasko3c0f9f52016-05-17 16:38:10 +02002089 LOGVAL(LYE_SPEC, LY_VLOG_STR, str, "Schema shorthand case path must include the virtual case statement.");
Radek Krejci9a5fccc2016-05-18 15:44:58 +02002090 free(str);
Michal Vasko025e0452016-05-17 16:14:20 +02002091 return NULL;
Radek Krejcibdf92362016-04-08 14:43:34 +02002092 }
Michal Vaskoe733d682016-03-14 09:08:27 +01002093 return sibling;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002094 }
2095
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002096 if (!shorthand) {
Michal Vasko7dc71d02016-03-15 10:42:28 +01002097 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002098 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002099 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko7dc71d02016-03-15 10:42:28 +01002100 return NULL;
2101 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01002102 start = sibling->child;
2103 }
2104
2105 /* update prev mod */
2106 prev_mod = start->module;
2107 break;
2108 }
2109 }
2110
2111 /* no match */
2112 if (!sibling) {
Michal Vasko10728b52016-04-07 14:26:29 +02002113 str = strndup(nodeid, (name + nam_len) - nodeid);
2114 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
2115 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002116 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002117 }
2118
Michal Vaskoe733d682016-03-14 09:08:27 +01002119 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 +01002120 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002121 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002122 }
2123 id += r;
2124 }
2125
2126 /* cannot get here */
2127 LOGINT;
Michal Vaskoe733d682016-03-14 09:08:27 +01002128 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002129}
2130
Michal Vasko22448d32016-03-16 13:17:29 +01002131static int
2132resolve_partial_json_data_list_predicate(const char *predicate, const char *node_name, struct lyd_node *node, int *parsed)
2133{
2134 const char *name, *value;
2135 int nam_len, val_len, has_predicate = 1, r;
2136 uint16_t i;
Michal Vaskof29903d2016-04-18 13:13:10 +02002137 struct lyd_node_leaf_list *key;
Michal Vasko22448d32016-03-16 13:17:29 +01002138
Radek Krejci61a86c62016-03-24 11:06:44 +01002139 assert(node);
Michal Vasko22448d32016-03-16 13:17:29 +01002140 assert(node->schema->nodetype == LYS_LIST);
2141
Michal Vaskof29903d2016-04-18 13:13:10 +02002142 key = (struct lyd_node_leaf_list *)node->child;
2143 for (i = 0; i < ((struct lys_node_list *)node->schema)->keys_size; ++i) {
2144 if (!key) {
2145 /* invalid data */
2146 LOGINT;
2147 return -1;
2148 }
Michal Vasko22448d32016-03-16 13:17:29 +01002149
Michal Vasko22448d32016-03-16 13:17:29 +01002150 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002151 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, node_name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002152 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002153 }
2154
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002155 if (((r = parse_schema_json_predicate(predicate, &name, &nam_len, &value, &val_len, &has_predicate)) < 1)
2156 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002157 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
Michal Vaskof29903d2016-04-18 13:13:10 +02002158 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002159 }
2160
2161 predicate += r;
2162 *parsed += r;
2163
Michal Vaskof29903d2016-04-18 13:13:10 +02002164 if (strncmp(key->schema->name, name, nam_len) || key->schema->name[nam_len]) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002165 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002166 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002167 }
2168
2169 /* value does not match */
Michal Vaskof29903d2016-04-18 13:13:10 +02002170 if (strncmp(key->value_str, value, val_len) || key->value_str[val_len]) {
Michal Vasko22448d32016-03-16 13:17:29 +01002171 return 1;
2172 }
Michal Vaskof29903d2016-04-18 13:13:10 +02002173
2174 key = (struct lyd_node_leaf_list *)key->next;
Michal Vasko22448d32016-03-16 13:17:29 +01002175 }
2176
2177 if (has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002178 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko22448d32016-03-16 13:17:29 +01002179 return -1;
2180 }
2181
2182 return 0;
2183}
2184
Radek Krejci45826012016-08-24 15:07:57 +02002185/**
2186 * @brief get the closest parent of the node (or the node itself) identified by the nodeid (path)
2187 *
2188 * @param[in] nodeid Node data path to find
2189 * @param[in] llist_value If the \p nodeid identifies leaf-list, this is expected value of the leaf-list instance.
2190 * @param[in] options Bitmask of options flags, see @ref pathoptions.
2191 * @param[out] parsed Number of characters processed in \p id
2192 * @return The closes parent (or the node itself) from the path
2193 */
Michal Vasko22448d32016-03-16 13:17:29 +01002194struct lyd_node *
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002195resolve_partial_json_data_nodeid(const char *nodeid, const char *llist_value, struct lyd_node *start, int options,
2196 int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002197{
Michal Vasko10728b52016-04-07 14:26:29 +02002198 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002199 const char *id, *mod_name, *name, *pred_name;
2200 int r, ret, mod_name_len, nam_len, is_relative = -1;
2201 int has_predicate, last_parsed, val_len, pred_name_len, last_has_pred;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002202 struct lyd_node *sibling, *last_match = NULL;
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002203 struct lyd_node_leaf_list *llist;
Michal Vasko22448d32016-03-16 13:17:29 +01002204 const struct lys_module *prefix_mod, *prev_mod;
2205 struct ly_ctx *ctx;
2206
2207 assert(nodeid && start && parsed);
2208
2209 ctx = start->schema->module->ctx;
2210 id = nodeid;
2211
2212 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 +01002213 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002214 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002215 return NULL;
2216 }
2217 id += r;
2218 /* add it to parsed only after the data node was actually found */
2219 last_parsed = r;
2220
2221 if (is_relative) {
2222 prev_mod = start->schema->module;
Michal Vasko22448d32016-03-16 13:17:29 +01002223 start = start->child;
2224 } else {
2225 for (; start->parent; start = start->parent);
Michal Vasko22448d32016-03-16 13:17:29 +01002226 prev_mod = start->schema->module;
2227 }
2228
2229 while (1) {
2230 LY_TREE_FOR(start, sibling) {
Michal Vasko2411b942016-03-23 13:50:03 +01002231 /* RPC data check, return simply invalid argument, because the data tree is invalid */
2232 if (lys_parent(sibling->schema)) {
2233 if (options & LYD_PATH_OPT_OUTPUT) {
2234 if (lys_parent(sibling->schema)->nodetype == LYS_INPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002235 LOGERR(LY_EINVAL, "Provided data tree includes some RPC input nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002236 *parsed = -1;
2237 return NULL;
2238 }
2239 } else {
2240 if (lys_parent(sibling->schema)->nodetype == LYS_OUTPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002241 LOGERR(LY_EINVAL, "Provided data tree includes some RPC output nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002242 *parsed = -1;
2243 return NULL;
2244 }
2245 }
2246 }
2247
Michal Vasko22448d32016-03-16 13:17:29 +01002248 /* name match */
2249 if (!strncmp(name, sibling->schema->name, nam_len) && !sibling->schema->name[nam_len]) {
2250
2251 /* module check */
2252 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002253 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko22448d32016-03-16 13:17:29 +01002254 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002255 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002256 return NULL;
2257 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002258
2259 if (ly_buf_used && module_name[0]) {
2260 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2261 }
2262 ly_buf_used++;
2263
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002264 memmove(module_name, mod_name, mod_name_len);
Michal Vasko22448d32016-03-16 13:17:29 +01002265 module_name[mod_name_len] = '\0';
2266 /* will also find an augment module */
2267 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002268
2269 if (buf_backup) {
2270 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002271 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002272 free(buf_backup);
2273 buf_backup = NULL;
2274 }
2275 ly_buf_used--;
2276
Michal Vasko22448d32016-03-16 13:17:29 +01002277 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002278 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2279 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2280 free(str);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002281 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002282 return NULL;
2283 }
2284 } else {
2285 prefix_mod = prev_mod;
2286 }
2287 if (prefix_mod != lys_node_module(sibling->schema)) {
2288 continue;
2289 }
2290
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002291 /* leaf-list, did we find it with the correct value or not? */
Michal Vasko22448d32016-03-16 13:17:29 +01002292 if (sibling->schema->nodetype == LYS_LEAFLIST) {
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002293 last_has_pred = 0;
Michal Vaskof0a50972016-10-19 11:33:55 +02002294 if (has_predicate) {
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002295 if ((r = parse_schema_json_predicate(id, &pred_name, &pred_name_len, &llist_value, &val_len, &last_has_pred)) < 1) {
Michal Vaskof0a50972016-10-19 11:33:55 +02002296 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2297 *parsed = -1;
2298 return NULL;
2299 }
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002300 if ((pred_name[0] != '.') || (pred_name_len != 1)) {
2301 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[1], id + 1);
2302 *parsed = -1;
2303 return NULL;
2304 }
Michal Vaskof0a50972016-10-19 11:33:55 +02002305 } else {
2306 r = 0;
2307 if (llist_value) {
2308 val_len = strlen(llist_value);
2309 } else {
2310 val_len = 0;
2311 }
2312 }
2313
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002314 llist = (struct lyd_node_leaf_list *)sibling;
Michal Vaskof0a50972016-10-19 11:33:55 +02002315 if ((!val_len && llist->value_str && llist->value_str[0])
2316 || (val_len && (strncmp(llist_value, llist->value_str, val_len) || llist->value_str[val_len]))) {
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002317 continue;
2318 }
Michal Vaskof0a50972016-10-19 11:33:55 +02002319 id += r;
2320 last_parsed += r;
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002321 has_predicate = last_has_pred;
Michal Vaskof0a50972016-10-19 11:33:55 +02002322
Radek Krejci45826012016-08-24 15:07:57 +02002323 } else if (sibling->schema->nodetype == LYS_LIST) {
2324 /* list, we need predicates'n'stuff then */
Michal Vasko22448d32016-03-16 13:17:29 +01002325 r = 0;
2326 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002327 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002328 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002329 return NULL;
2330 }
2331 ret = resolve_partial_json_data_list_predicate(id, name, sibling, &r);
2332 if (ret == -1) {
Michal Vasko238bd2f2016-03-23 09:39:01 +01002333 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002334 return NULL;
2335 } else if (ret == 1) {
2336 /* this list instance does not match */
2337 continue;
2338 }
2339 id += r;
2340 last_parsed += r;
2341 }
2342
2343 *parsed += last_parsed;
2344
2345 /* the result node? */
2346 if (!id[0]) {
2347 return sibling;
2348 }
2349
2350 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002351 if (sibling->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002352 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002353 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002354 return NULL;
2355 }
Michal Vaskoc6c52cf2016-03-29 11:53:04 +02002356 last_match = sibling;
Michal Vasko22448d32016-03-16 13:17:29 +01002357 start = sibling->child;
2358 if (start) {
2359 prev_mod = start->schema->module;
2360 }
2361 break;
2362 }
2363 }
2364
2365 /* no match, return last match */
2366 if (!sibling) {
2367 return last_match;
2368 }
2369
2370 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 +01002371 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002372 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002373 return NULL;
2374 }
2375 id += r;
2376 last_parsed = r;
2377 }
2378
2379 /* cannot get here */
2380 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002381 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002382 return NULL;
2383}
2384
Michal Vasko3edeaf72016-02-11 13:17:43 +01002385/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02002386 * @brief Resolves length or range intervals. Does not log.
Michal Vaskoaeb51802016-04-11 10:58:47 +02002387 * Syntax is assumed to be correct, *ret MUST be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002388 *
Michal Vaskoaeb51802016-04-11 10:58:47 +02002389 * @param[in] str_restr Restriction as a string.
2390 * @param[in] type Type of the restriction.
2391 * @param[out] ret Final interval structure that starts with
2392 * the interval of the initial type, continues with intervals
2393 * of any superior types derived from the initial one, and
2394 * finishes with intervals from our \p type.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002395 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002396 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002397 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002398int
Michal Vaskoaeb51802016-04-11 10:58:47 +02002399resolve_len_ran_interval(const char *str_restr, struct lys_type *type, struct len_ran_intv **ret)
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002400{
2401 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002402 int kind;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002403 int64_t local_smin, local_smax, local_fmin, local_fmax;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002404 uint64_t local_umin, local_umax;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002405 uint8_t local_fdig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002406 const char *seg_ptr, *ptr;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002407 struct len_ran_intv *local_intv = NULL, *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002408
2409 switch (type->base) {
2410 case LY_TYPE_BINARY:
2411 kind = 0;
2412 local_umin = 0;
2413 local_umax = 18446744073709551615UL;
2414
2415 if (!str_restr && type->info.binary.length) {
2416 str_restr = type->info.binary.length->expr;
2417 }
2418 break;
2419 case LY_TYPE_DEC64:
2420 kind = 2;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002421 local_fmin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2422 local_fmax = __INT64_C(9223372036854775807);
2423 local_fdig = type->info.dec64.dig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002424
2425 if (!str_restr && type->info.dec64.range) {
2426 str_restr = type->info.dec64.range->expr;
2427 }
2428 break;
2429 case LY_TYPE_INT8:
2430 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002431 local_smin = __INT64_C(-128);
2432 local_smax = __INT64_C(127);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002433
2434 if (!str_restr && type->info.num.range) {
2435 str_restr = type->info.num.range->expr;
2436 }
2437 break;
2438 case LY_TYPE_INT16:
2439 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002440 local_smin = __INT64_C(-32768);
2441 local_smax = __INT64_C(32767);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002442
2443 if (!str_restr && type->info.num.range) {
2444 str_restr = type->info.num.range->expr;
2445 }
2446 break;
2447 case LY_TYPE_INT32:
2448 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002449 local_smin = __INT64_C(-2147483648);
2450 local_smax = __INT64_C(2147483647);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002451
2452 if (!str_restr && type->info.num.range) {
2453 str_restr = type->info.num.range->expr;
2454 }
2455 break;
2456 case LY_TYPE_INT64:
2457 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002458 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2459 local_smax = __INT64_C(9223372036854775807);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002460
2461 if (!str_restr && type->info.num.range) {
2462 str_restr = type->info.num.range->expr;
2463 }
2464 break;
2465 case LY_TYPE_UINT8:
2466 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002467 local_umin = __UINT64_C(0);
2468 local_umax = __UINT64_C(255);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002469
2470 if (!str_restr && type->info.num.range) {
2471 str_restr = type->info.num.range->expr;
2472 }
2473 break;
2474 case LY_TYPE_UINT16:
2475 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002476 local_umin = __UINT64_C(0);
2477 local_umax = __UINT64_C(65535);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002478
2479 if (!str_restr && type->info.num.range) {
2480 str_restr = type->info.num.range->expr;
2481 }
2482 break;
2483 case LY_TYPE_UINT32:
2484 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002485 local_umin = __UINT64_C(0);
2486 local_umax = __UINT64_C(4294967295);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002487
2488 if (!str_restr && type->info.num.range) {
2489 str_restr = type->info.num.range->expr;
2490 }
2491 break;
2492 case LY_TYPE_UINT64:
2493 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002494 local_umin = __UINT64_C(0);
2495 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002496
2497 if (!str_restr && type->info.num.range) {
2498 str_restr = type->info.num.range->expr;
2499 }
2500 break;
2501 case LY_TYPE_STRING:
2502 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002503 local_umin = __UINT64_C(0);
2504 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002505
2506 if (!str_restr && type->info.str.length) {
2507 str_restr = type->info.str.length->expr;
2508 }
2509 break;
2510 default:
2511 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002512 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002513 }
2514
2515 /* process superior types */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002516 if (type->der) {
2517 if (resolve_len_ran_interval(NULL, &type->der->type, &intv)) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002518 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002519 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02002520 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002521 assert(!intv || (intv->kind == kind));
2522 }
2523
2524 if (!str_restr) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002525 /* we do not have any restriction, return superior ones */
2526 *ret = intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002527 return EXIT_SUCCESS;
2528 }
2529
2530 /* adjust local min and max */
2531 if (intv) {
2532 tmp_intv = intv;
2533
2534 if (kind == 0) {
2535 local_umin = tmp_intv->value.uval.min;
2536 } else if (kind == 1) {
2537 local_smin = tmp_intv->value.sval.min;
2538 } else if (kind == 2) {
2539 local_fmin = tmp_intv->value.fval.min;
2540 }
2541
2542 while (tmp_intv->next) {
2543 tmp_intv = tmp_intv->next;
2544 }
2545
2546 if (kind == 0) {
2547 local_umax = tmp_intv->value.uval.max;
2548 } else if (kind == 1) {
2549 local_smax = tmp_intv->value.sval.max;
2550 } else if (kind == 2) {
2551 local_fmax = tmp_intv->value.fval.max;
2552 }
2553 }
2554
2555 /* finally parse our restriction */
2556 seg_ptr = str_restr;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002557 tmp_intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002558 while (1) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002559 if (!tmp_local_intv) {
2560 assert(!local_intv);
2561 local_intv = malloc(sizeof *local_intv);
2562 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002563 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002564 tmp_local_intv->next = malloc(sizeof *tmp_local_intv);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002565 tmp_local_intv = tmp_local_intv->next;
2566 }
Michal Vasko253035f2015-12-17 16:58:13 +01002567 if (!tmp_local_intv) {
2568 LOGMEM;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002569 goto error;
Michal Vasko253035f2015-12-17 16:58:13 +01002570 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002571
2572 tmp_local_intv->kind = kind;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002573 tmp_local_intv->type = type;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002574 tmp_local_intv->next = NULL;
2575
2576 /* min */
2577 ptr = seg_ptr;
2578 while (isspace(ptr[0])) {
2579 ++ptr;
2580 }
2581 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2582 if (kind == 0) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002583 tmp_local_intv->value.uval.min = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002584 } else if (kind == 1) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002585 tmp_local_intv->value.sval.min = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002586 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002587 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.min)) {
2588 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2589 goto error;
2590 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002591 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002592 } else if (!strncmp(ptr, "min", 3)) {
2593 if (kind == 0) {
2594 tmp_local_intv->value.uval.min = local_umin;
2595 } else if (kind == 1) {
2596 tmp_local_intv->value.sval.min = local_smin;
2597 } else if (kind == 2) {
2598 tmp_local_intv->value.fval.min = local_fmin;
2599 }
2600
2601 ptr += 3;
2602 } else if (!strncmp(ptr, "max", 3)) {
2603 if (kind == 0) {
2604 tmp_local_intv->value.uval.min = local_umax;
2605 } else if (kind == 1) {
2606 tmp_local_intv->value.sval.min = local_smax;
2607 } else if (kind == 2) {
2608 tmp_local_intv->value.fval.min = local_fmax;
2609 }
2610
2611 ptr += 3;
2612 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002613 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002614 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002615 }
2616
2617 while (isspace(ptr[0])) {
2618 ptr++;
2619 }
2620
2621 /* no interval or interval */
2622 if ((ptr[0] == '|') || !ptr[0]) {
2623 if (kind == 0) {
2624 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
2625 } else if (kind == 1) {
2626 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
2627 } else if (kind == 2) {
2628 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
2629 }
2630 } else if (!strncmp(ptr, "..", 2)) {
2631 /* skip ".." */
2632 ptr += 2;
2633 while (isspace(ptr[0])) {
2634 ++ptr;
2635 }
2636
2637 /* max */
2638 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2639 if (kind == 0) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002640 tmp_local_intv->value.uval.max = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002641 } else if (kind == 1) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002642 tmp_local_intv->value.sval.max = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002643 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002644 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.max)) {
2645 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2646 goto error;
2647 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002648 }
2649 } else if (!strncmp(ptr, "max", 3)) {
2650 if (kind == 0) {
2651 tmp_local_intv->value.uval.max = local_umax;
2652 } else if (kind == 1) {
2653 tmp_local_intv->value.sval.max = local_smax;
2654 } else if (kind == 2) {
2655 tmp_local_intv->value.fval.max = local_fmax;
2656 }
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 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002662 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002663 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002664 }
2665
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002666 /* check min and max in correct order*/
2667 if (kind == 0) {
2668 /* current segment */
2669 if (tmp_local_intv->value.uval.min > tmp_local_intv->value.uval.max) {
2670 goto error;
2671 }
2672 if (tmp_local_intv->value.uval.min < local_umin || tmp_local_intv->value.uval.max > local_umax) {
2673 goto error;
2674 }
2675 /* segments sholud be ascending order */
Pavol Vican69f62c92016-08-30 09:06:25 +02002676 if (tmp_intv && (tmp_intv->value.uval.max >= tmp_local_intv->value.uval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002677 goto error;
2678 }
2679 } else if (kind == 1) {
2680 if (tmp_local_intv->value.sval.min > tmp_local_intv->value.sval.max) {
2681 goto error;
2682 }
2683 if (tmp_local_intv->value.sval.min < local_smin || tmp_local_intv->value.sval.max > local_smax) {
2684 goto error;
2685 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002686 if (tmp_intv && (tmp_intv->value.sval.max >= tmp_local_intv->value.sval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002687 goto error;
2688 }
2689 } else if (kind == 2) {
2690 if (tmp_local_intv->value.fval.min > tmp_local_intv->value.fval.max) {
2691 goto error;
2692 }
2693 if (tmp_local_intv->value.fval.min < local_fmin || tmp_local_intv->value.fval.max > local_fmax) {
2694 goto error;
2695 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002696 if (tmp_intv && (tmp_intv->value.fval.max >= tmp_local_intv->value.fval.min)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002697 /* fraction-digits value is always the same (it cannot be changed in derived types) */
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002698 goto error;
2699 }
2700 }
2701
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002702 /* next segment (next OR) */
2703 seg_ptr = strchr(seg_ptr, '|');
2704 if (!seg_ptr) {
2705 break;
2706 }
2707 seg_ptr++;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002708 tmp_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002709 }
2710
2711 /* check local restrictions against superior ones */
2712 if (intv) {
2713 tmp_intv = intv;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002714 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002715
2716 while (tmp_local_intv && tmp_intv) {
2717 /* reuse local variables */
2718 if (kind == 0) {
2719 local_umin = tmp_local_intv->value.uval.min;
2720 local_umax = tmp_local_intv->value.uval.max;
2721
2722 /* it must be in this interval */
2723 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
2724 /* this interval is covered, next one */
2725 if (local_umax <= tmp_intv->value.uval.max) {
2726 tmp_local_intv = tmp_local_intv->next;
2727 continue;
2728 /* ascending order of restrictions -> fail */
2729 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002730 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002731 }
2732 }
2733 } else if (kind == 1) {
2734 local_smin = tmp_local_intv->value.sval.min;
2735 local_smax = tmp_local_intv->value.sval.max;
2736
2737 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
2738 if (local_smax <= tmp_intv->value.sval.max) {
2739 tmp_local_intv = tmp_local_intv->next;
2740 continue;
2741 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002742 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002743 }
2744 }
2745 } else if (kind == 2) {
2746 local_fmin = tmp_local_intv->value.fval.min;
2747 local_fmax = tmp_local_intv->value.fval.max;
2748
Michal Vasko4d1f0482016-09-19 14:35:06 +02002749 if ((dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.min, local_fdig) > -1)
Pavol Vican3c8ee2b2016-09-29 13:18:13 +02002750 && (dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002751 if (dec64cmp(local_fmax, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002752 tmp_local_intv = tmp_local_intv->next;
2753 continue;
2754 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002755 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002756 }
2757 }
2758 }
2759
2760 tmp_intv = tmp_intv->next;
2761 }
2762
2763 /* some interval left uncovered -> fail */
2764 if (tmp_local_intv) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002765 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002766 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002767 }
2768
Michal Vaskoaeb51802016-04-11 10:58:47 +02002769 /* append the local intervals to all the intervals of the superior types, return it all */
2770 if (intv) {
2771 for (tmp_intv = intv; tmp_intv->next; tmp_intv = tmp_intv->next);
2772 tmp_intv->next = local_intv;
2773 } else {
2774 intv = local_intv;
2775 }
2776 *ret = intv;
2777
2778 return EXIT_SUCCESS;
2779
2780error:
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002781 while (intv) {
2782 tmp_intv = intv->next;
2783 free(intv);
2784 intv = tmp_intv;
2785 }
Michal Vaskoaeb51802016-04-11 10:58:47 +02002786 while (local_intv) {
2787 tmp_local_intv = local_intv->next;
2788 free(local_intv);
2789 local_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002790 }
2791
Michal Vaskoaeb51802016-04-11 10:58:47 +02002792 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002793}
2794
Michal Vasko730dfdf2015-08-11 14:48:05 +02002795/**
Michal Vasko01c6fd22016-05-20 11:43:05 +02002796 * @brief Resolve a typedef, return only resolved typedefs if derived. If leafref, it must be
2797 * resolved for this function to return it. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002798 *
2799 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02002800 * @param[in] mod_name Typedef name module name.
2801 * @param[in] module Main module.
2802 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002803 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002804 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002805 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002806 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002807int
Michal Vasko1e62a092015-12-01 12:27:20 +01002808resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
2809 const struct lys_node *parent, struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002810{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002811 int i, j;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002812 struct lys_tpdf *tpdf, *match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002813 int tpdf_size;
2814
Michal Vasko1dca6882015-10-22 14:29:42 +02002815 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002816 /* no prefix, try built-in types */
2817 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
2818 if (!strcmp(ly_types[i].def->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002819 if (ret) {
2820 *ret = ly_types[i].def;
2821 }
2822 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002823 }
2824 }
2825 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02002826 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002827 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02002828 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002829 }
2830 }
2831
Michal Vasko1dca6882015-10-22 14:29:42 +02002832 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002833 /* search in local typedefs */
2834 while (parent) {
2835 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02002836 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02002837 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
2838 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002839 break;
2840
Radek Krejci76512572015-08-04 09:47:08 +02002841 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02002842 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
2843 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002844 break;
2845
Radek Krejci76512572015-08-04 09:47:08 +02002846 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02002847 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
2848 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002849 break;
2850
Radek Krejci76512572015-08-04 09:47:08 +02002851 case LYS_RPC:
Michal Vasko44fb6382016-06-29 11:12:27 +02002852 case LYS_ACTION:
2853 tpdf_size = ((struct lys_node_rpc_action *)parent)->tpdf_size;
2854 tpdf = ((struct lys_node_rpc_action *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002855 break;
2856
Radek Krejci76512572015-08-04 09:47:08 +02002857 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02002858 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
2859 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002860 break;
2861
Radek Krejci76512572015-08-04 09:47:08 +02002862 case LYS_INPUT:
2863 case LYS_OUTPUT:
Michal Vasko44fb6382016-06-29 11:12:27 +02002864 tpdf_size = ((struct lys_node_inout *)parent)->tpdf_size;
2865 tpdf = ((struct lys_node_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002866 break;
2867
2868 default:
Michal Vaskodcf98e62016-05-05 17:53:53 +02002869 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002870 continue;
2871 }
2872
2873 for (i = 0; i < tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002874 if (!strcmp(tpdf[i].name, name) && tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002875 match = &tpdf[i];
2876 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002877 }
2878 }
2879
Michal Vaskodcf98e62016-05-05 17:53:53 +02002880 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002881 }
Radek Krejcic071c542016-01-27 14:57:51 +01002882 } else {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002883 /* get module where to search */
Michal Vaskob6729c62015-10-21 12:09:47 +02002884 module = lys_get_import_module(module, NULL, 0, mod_name, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02002885 if (!module) {
2886 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002887 }
2888 }
2889
2890 /* search in top level typedefs */
2891 for (i = 0; i < module->tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002892 if (!strcmp(module->tpdf[i].name, name) && module->tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002893 match = &module->tpdf[i];
2894 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002895 }
2896 }
2897
2898 /* search in submodules */
Radek Krejcic071c542016-01-27 14:57:51 +01002899 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002900 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002901 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 +02002902 match = &module->inc[i].submodule->tpdf[j];
2903 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002904 }
2905 }
2906 }
2907
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002908 return EXIT_FAILURE;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002909
2910check_leafref:
2911 if (ret) {
2912 *ret = match;
2913 }
2914 if (match->type.base == LY_TYPE_LEAFREF) {
2915 while (!match->type.info.lref.path) {
2916 match = match->type.der;
2917 assert(match);
2918 }
Michal Vasko01c6fd22016-05-20 11:43:05 +02002919 }
2920 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002921}
2922
Michal Vasko1dca6882015-10-22 14:29:42 +02002923/**
2924 * @brief Check the default \p value of the \p type. Logs directly.
2925 *
2926 * @param[in] type Type definition to use.
2927 * @param[in] value Default value to check.
Michal Vasko56826402016-03-02 11:11:37 +01002928 * @param[in] module Type module.
Michal Vasko1dca6882015-10-22 14:29:42 +02002929 *
2930 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
2931 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002932static int
Radek Krejci48464ed2016-03-17 15:44:09 +01002933check_default(struct lys_type *type, const char *value, struct lys_module *module)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002934{
Radek Krejcibad2f172016-08-02 11:04:15 +02002935 struct lys_tpdf *base_tpdf = NULL;
Michal Vasko1dca6882015-10-22 14:29:42 +02002936 struct lyd_node_leaf_list node;
Radek Krejci37b756f2016-01-18 10:15:03 +01002937 int ret = EXIT_SUCCESS;
Michal Vasko1dca6882015-10-22 14:29:42 +02002938
Radek Krejcic13db382016-08-16 10:52:42 +02002939 if (type->base <= LY_TYPE_DER) {
Michal Vasko478c4652016-07-21 12:55:01 +02002940 /* the type was not resolved yet, nothing to do for now */
2941 return EXIT_FAILURE;
2942 }
2943
2944 if (!value) {
2945 /* we do not have a new default value, so is there any to check even, in some base type? */
2946 for (base_tpdf = type->der; base_tpdf->type.der; base_tpdf = base_tpdf->type.der) {
2947 if (base_tpdf->dflt) {
2948 value = base_tpdf->dflt;
2949 break;
2950 }
2951 }
2952
2953 if (!value) {
2954 /* no default value, nothing to check, all is well */
2955 return EXIT_SUCCESS;
2956 }
2957
2958 /* 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)? */
2959 switch (type->base) {
Michal Vasko478c4652016-07-21 12:55:01 +02002960 case LY_TYPE_IDENT:
2961 case LY_TYPE_INST:
2962 case LY_TYPE_LEAFREF:
2963 case LY_TYPE_BOOL:
2964 case LY_TYPE_EMPTY:
2965 /* these have no restrictions, so we would do the exact same work as the unres in the base typedef */
2966 return EXIT_SUCCESS;
Radek Krejcibad2f172016-08-02 11:04:15 +02002967 case LY_TYPE_BITS:
2968 /* the default value must match the restricted list of values, if the type was restricted */
2969 if (type->info.bits.count) {
2970 break;
2971 }
2972 return EXIT_SUCCESS;
2973 case LY_TYPE_ENUM:
2974 /* the default value must match the restricted list of values, if the type was restricted */
2975 if (type->info.enums.count) {
2976 break;
2977 }
2978 return EXIT_SUCCESS;
Michal Vasko478c4652016-07-21 12:55:01 +02002979 case LY_TYPE_DEC64:
2980 if (type->info.dec64.range) {
2981 break;
2982 }
2983 return EXIT_SUCCESS;
2984 case LY_TYPE_BINARY:
2985 if (type->info.binary.length) {
2986 break;
2987 }
2988 return EXIT_SUCCESS;
2989 case LY_TYPE_INT8:
2990 case LY_TYPE_INT16:
2991 case LY_TYPE_INT32:
2992 case LY_TYPE_INT64:
2993 case LY_TYPE_UINT8:
2994 case LY_TYPE_UINT16:
2995 case LY_TYPE_UINT32:
2996 case LY_TYPE_UINT64:
2997 if (type->info.num.range) {
2998 break;
2999 }
3000 return EXIT_SUCCESS;
3001 case LY_TYPE_STRING:
3002 if (type->info.str.length || type->info.str.patterns) {
3003 break;
3004 }
3005 return EXIT_SUCCESS;
3006 case LY_TYPE_UNION:
3007 /* way too much trouble learning whether we need to check the default again, so just do it */
3008 break;
3009 default:
3010 LOGINT;
3011 return -1;
3012 }
Radek Krejci55a161c2016-09-05 17:13:25 +02003013 } else if (type->base == LY_TYPE_EMPTY) {
3014 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "default", type->parent->name);
3015 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"empty\" data type cannot have a default value.");
3016 return -1;
Michal Vasko478c4652016-07-21 12:55:01 +02003017 }
3018
Michal Vasko1dca6882015-10-22 14:29:42 +02003019 /* dummy leaf */
Radek Krejci4fe36bd2016-03-17 16:47:16 +01003020 memset(&node, 0, sizeof node);
Michal Vasko1dca6882015-10-22 14:29:42 +02003021 node.value_str = value;
3022 node.value_type = type->base;
Radek Krejci37b756f2016-01-18 10:15:03 +01003023 node.schema = calloc(1, sizeof (struct lys_node_leaf));
Michal Vasko253035f2015-12-17 16:58:13 +01003024 if (!node.schema) {
3025 LOGMEM;
3026 return -1;
3027 }
Radek Krejcibad2f172016-08-02 11:04:15 +02003028 node.schema->name = strdup("fake-default");
Michal Vasko253035f2015-12-17 16:58:13 +01003029 if (!node.schema->name) {
3030 LOGMEM;
Michal Vaskof49eda02016-07-21 12:17:01 +02003031 free(node.schema);
Michal Vasko253035f2015-12-17 16:58:13 +01003032 return -1;
3033 }
Michal Vasko56826402016-03-02 11:11:37 +01003034 node.schema->module = module;
Radek Krejci37b756f2016-01-18 10:15:03 +01003035 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
Michal Vasko1dca6882015-10-22 14:29:42 +02003036
Radek Krejci37b756f2016-01-18 10:15:03 +01003037 if (type->base == LY_TYPE_LEAFREF) {
Michal Vasko1dca6882015-10-22 14:29:42 +02003038 if (!type->info.lref.target) {
3039 ret = EXIT_FAILURE;
3040 goto finish;
3041 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003042 ret = check_default(&type->info.lref.target->type, value, module);
Michal Vasko1dca6882015-10-22 14:29:42 +02003043
3044 } else if ((type->base == LY_TYPE_INST) || (type->base == LY_TYPE_IDENT)) {
3045 /* it was converted to JSON format before, nothing else sensible we can do */
3046
3047 } else {
Michal Vasko3767fb22016-07-21 12:10:57 +02003048 if (lyp_parse_value(&node, NULL, 1)) {
3049 ret = -1;
Radek Krejcibad2f172016-08-02 11:04:15 +02003050 if (base_tpdf) {
3051 /* default value was is defined in some base typedef */
3052 if ((type->base == LY_TYPE_BITS && type->der->type.der) ||
3053 (type->base == LY_TYPE_ENUM && type->der->type.der)) {
3054 /* we have refined bits/enums */
3055 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
3056 "Invalid value \"%s\" of the default statement inherited to \"%s\" from \"%s\" base type.",
3057 value, type->parent->name, base_tpdf->name);
3058 }
3059 }
Michal Vasko3767fb22016-07-21 12:10:57 +02003060 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003061 }
3062
3063finish:
3064 if (node.value_type == LY_TYPE_BITS) {
3065 free(node.value.bit);
3066 }
3067 free((char *)node.schema->name);
3068 free(node.schema);
3069
3070 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003071}
3072
Michal Vasko730dfdf2015-08-11 14:48:05 +02003073/**
3074 * @brief Check a key for mandatory attributes. Logs directly.
3075 *
3076 * @param[in] key The key to check.
3077 * @param[in] flags What flags to check.
3078 * @param[in] list The list of all the keys.
3079 * @param[in] index Index of the key in the key list.
3080 * @param[in] name The name of the keys.
3081 * @param[in] len The name length.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003082 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003083 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003084 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003085static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003086check_key(struct lys_node_list *list, int index, const char *name, int len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003087{
Radek Krejciadb57612016-02-16 13:34:34 +01003088 struct lys_node_leaf *key = list->keys[index];
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003089 char *dup = NULL;
3090 int j;
3091
3092 /* existence */
3093 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02003094 if (name[len] != '\0') {
3095 dup = strdup(name);
Michal Vasko253035f2015-12-17 16:58:13 +01003096 if (!dup) {
3097 LOGMEM;
3098 return -1;
3099 }
Michal Vaskof02e3742015-08-05 16:27:02 +02003100 dup[len] = '\0';
3101 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003102 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003103 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, list, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003104 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003105 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003106 }
3107
3108 /* uniqueness */
3109 for (j = index - 1; j >= 0; j--) {
Radek Krejciadb57612016-02-16 13:34:34 +01003110 if (key == list->keys[j]) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003111 LOGVAL(LYE_KEY_DUP, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003112 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003113 }
3114 }
3115
3116 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02003117 if (key->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003118 LOGVAL(LYE_KEY_NLEAF, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003119 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003120 }
3121
3122 /* type of the leaf is not built-in empty */
Radek Krejcic3738db2016-09-15 15:51:21 +02003123 if (key->type.base == LY_TYPE_EMPTY && key->module->version < 2) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003124 LOGVAL(LYE_KEY_TYPE, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003125 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003126 }
3127
3128 /* config attribute is the same as of the list */
Radek Krejciadb57612016-02-16 13:34:34 +01003129 if ((list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003130 LOGVAL(LYE_KEY_CONFIG, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003131 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003132 }
3133
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003134 /* key is not placed from augment */
3135 if (key->parent->nodetype == LYS_AUGMENT) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003136 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, key, key->name);
3137 LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key inserted from augment.");
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003138 return -1;
3139 }
3140
Radek Krejci3f21ada2016-08-01 13:34:31 +02003141 /* key is not when/if-feature -conditional */
3142 j = 0;
3143 if (key->when || (key->iffeature_size && (j = 1))) {
3144 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, key, j ? "if-feature" : "when", "leaf");
3145 LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key definition cannot depend on a \"%s\" condition.",
3146 j ? "if-feature" : "when");
Radek Krejci581ce772015-11-10 17:22:40 +01003147 return -1;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003148 }
3149
Michal Vasko0b85aa82016-03-07 14:37:43 +01003150 return EXIT_SUCCESS;
Michal Vasko184521f2015-09-24 13:14:26 +02003151}
Michal Vasko730dfdf2015-08-11 14:48:05 +02003152
3153/**
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003154 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003155 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003156 * @param[in] parent The parent node of the unique structure.
Michal Vasko0b85aa82016-03-07 14:37:43 +01003157 * @param[in] uniq_str_path One path from the unique string.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003158 *
3159 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
3160 */
3161int
Radek Krejcid09d1a52016-08-11 14:05:45 +02003162resolve_unique(struct lys_node *parent, const char *uniq_str_path, uint8_t *trg_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003163{
Radek Krejci581ce772015-11-10 17:22:40 +01003164 int rc;
Michal Vasko1e62a092015-12-01 12:27:20 +01003165 const struct lys_node *leaf = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003166
Radek Krejcif3c71de2016-04-11 12:45:46 +02003167 rc = resolve_descendant_schema_nodeid(uniq_str_path, parent->child, LYS_LEAF, 1, 1, &leaf);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003168 if (rc || !leaf) {
Michal Vasko0b85aa82016-03-07 14:37:43 +01003169 if (rc) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003170 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003171 if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003172 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, parent, uniq_str_path[rc - 1], &uniq_str_path[rc - 1]);
Radek Krejcif3c71de2016-04-11 12:45:46 +02003173 } else if (rc == -2) {
Michal Vaskoc66c6d82016-04-12 11:37:31 +02003174 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Unique argument references list.");
Radek Krejci581ce772015-11-10 17:22:40 +01003175 }
Michal Vasko0b85aa82016-03-07 14:37:43 +01003176 rc = -1;
Michal Vasko0b85aa82016-03-07 14:37:43 +01003177 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01003178 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3179 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target leaf not found.");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003180 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003181 }
Radek Krejci581ce772015-11-10 17:22:40 +01003182 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003183 }
Michal Vasko9bb061b2016-02-12 11:00:19 +01003184 if (leaf->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003185 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3186 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target is not a leaf.");
Radek Krejcid09d1a52016-08-11 14:05:45 +02003187 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003188 }
3189
Radek Krejcicf509982015-12-15 09:22:44 +01003190 /* check status */
Radek Krejci48464ed2016-03-17 15:44:09 +01003191 if (lyp_check_status(parent->flags, parent->module, parent->name, leaf->flags, leaf->module, leaf->name, leaf)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003192 return -1;
3193 }
3194
Radek Krejcid09d1a52016-08-11 14:05:45 +02003195 /* check that all unique's targets are of the same config type */
3196 if (*trg_type) {
3197 if (((*trg_type == 1) && (leaf->flags & LYS_CONFIG_R)) || ((*trg_type == 2) && (leaf->flags & LYS_CONFIG_W))) {
3198 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3199 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent,
3200 "Leaf \"%s\" referenced in unique statement is config %s, but previous referenced leaf is config %s.",
3201 uniq_str_path, *trg_type == 1 ? "false" : "true", *trg_type == 1 ? "true" : "false");
3202 return -1;
3203 }
3204 } else {
3205 /* first unique */
3206 if (leaf->flags & LYS_CONFIG_W) {
3207 *trg_type = 1;
3208 } else {
3209 *trg_type = 2;
3210 }
3211 }
3212
Radek Krejcica7efb72016-01-18 13:06:01 +01003213 /* set leaf's unique flag */
3214 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
3215
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003216 return EXIT_SUCCESS;
3217
3218error:
3219
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003220 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003221}
3222
Radek Krejci0c0086a2016-03-24 15:20:28 +01003223void
Michal Vasko23b61ec2015-08-19 11:19:50 +02003224unres_data_del(struct unres_data *unres, uint32_t i)
3225{
3226 /* there are items after the one deleted */
3227 if (i+1 < unres->count) {
3228 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02003229 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003230
3231 /* deleting the last item */
3232 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02003233 free(unres->node);
3234 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003235 }
3236
3237 /* if there are no items after and it is not the last one, just move the counter */
3238 --unres->count;
3239}
3240
Michal Vasko0491ab32015-08-19 14:28:29 +02003241/**
3242 * @brief Resolve (find) a data node from a specific module. Does not log.
3243 *
3244 * @param[in] mod Module to search in.
3245 * @param[in] name Name of the data node.
3246 * @param[in] nam_len Length of the name.
3247 * @param[in] start Data node to start the search from.
3248 * @param[in,out] parents Resolved nodes. If there are some parents,
3249 * they are replaced (!!) with the resolvents.
3250 *
Michal Vasko2471e7f2016-04-11 11:00:15 +02003251 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko0491ab32015-08-19 14:28:29 +02003252 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003253static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003254resolve_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 +02003255{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003256 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02003257 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003258 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003259
Michal Vasko23b61ec2015-08-19 11:19:50 +02003260 if (!parents->count) {
3261 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003262 parents->node = malloc(sizeof *parents->node);
Michal Vasko253035f2015-12-17 16:58:13 +01003263 if (!parents->node) {
3264 LOGMEM;
Michal Vasko2471e7f2016-04-11 11:00:15 +02003265 return -1;
Michal Vasko253035f2015-12-17 16:58:13 +01003266 }
Michal Vaskocf024702015-10-08 15:01:42 +02003267 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003268 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003269 for (i = 0; i < parents->count;) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02003270 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003271 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003272 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003273 continue;
3274 }
3275 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02003276 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003277 if (node->schema->module == mod && !strncmp(node->schema->name, name, nam_len)
3278 && node->schema->name[nam_len] == '\0') {
3279 /* matching target */
3280 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02003281 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02003282 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003283 flag = 1;
3284 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02003285 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003286 ++parents->count;
Michal Vasko253035f2015-12-17 16:58:13 +01003287 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
3288 if (!parents->node) {
3289 return EXIT_FAILURE;
3290 }
Michal Vaskocf024702015-10-08 15:01:42 +02003291 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003292 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003293 }
3294 }
3295 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003296
3297 if (!flag) {
3298 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003299 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02003300 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003301 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02003302 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003303 }
3304
Michal Vasko0491ab32015-08-19 14:28:29 +02003305 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02003306}
3307
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003308/**
3309 * @brief Resolve (find) a data node. Does not log.
3310 *
Radek Krejci581ce772015-11-10 17:22:40 +01003311 * @param[in] mod_name Module name of the data node.
3312 * @param[in] mod_name_len Length of the module name.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003313 * @param[in] name Name of the data node.
3314 * @param[in] nam_len Length of the name.
3315 * @param[in] start Data node to start the search from.
3316 * @param[in,out] parents Resolved nodes. If there are some parents,
3317 * they are replaced (!!) with the resolvents.
3318 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003319 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003320 */
Radek Krejcic5090c32015-08-12 09:46:19 +02003321static int
Radek Krejci581ce772015-11-10 17:22:40 +01003322resolve_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 +02003323 struct unres_data *parents)
Radek Krejcic5090c32015-08-12 09:46:19 +02003324{
Michal Vasko1e62a092015-12-01 12:27:20 +01003325 const struct lys_module *mod;
Michal Vasko31fc3672015-10-21 12:08:13 +02003326 char *str;
Radek Krejcic5090c32015-08-12 09:46:19 +02003327
Michal Vasko23b61ec2015-08-19 11:19:50 +02003328 assert(start);
3329
Michal Vasko31fc3672015-10-21 12:08:13 +02003330 if (mod_name) {
3331 /* we have mod_name, find appropriate module */
3332 str = strndup(mod_name, mod_name_len);
Michal Vasko253035f2015-12-17 16:58:13 +01003333 if (!str) {
3334 LOGMEM;
3335 return -1;
3336 }
Michal Vasko31fc3672015-10-21 12:08:13 +02003337 mod = ly_ctx_get_module(start->schema->module->ctx, str, NULL);
3338 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02003339 if (!mod) {
3340 /* invalid prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003341 return -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02003342 }
3343 } else {
3344 /* no prefix, module is the same as of current node */
3345 mod = start->schema->module;
3346 }
3347
3348 return resolve_data(mod, name, name_len, start, parents);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003349}
3350
Michal Vasko730dfdf2015-08-11 14:48:05 +02003351/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003352 * @brief Resolve a path predicate (leafref) in JSON data context. Logs directly
Radek Krejci48464ed2016-03-17 15:44:09 +01003353 * only specific errors, general no-resolvent error is left to the caller.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003354 *
Michal Vaskobb211122015-08-19 14:03:11 +02003355 * @param[in] pred Predicate to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003356 * @param[in] node Node from which the predicate is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02003357 * @param[in,out] node_match Nodes satisfying the restriction
3358 * without the predicate. Nodes not
3359 * satisfying the predicate are removed.
Michal Vasko0491ab32015-08-19 14:28:29 +02003360 * @param[out] parsed Number of characters parsed, negative on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003361 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003362 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003363 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003364static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003365resolve_path_predicate_data(const char *pred, struct lyd_node *node, struct unres_data *node_match,
Radek Krejci010e54b2016-03-15 09:40:34 +01003366 int *parsed)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003367{
Michal Vasko730dfdf2015-08-11 14:48:05 +02003368 /* ... /node[source = destination] ... */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003369 struct unres_data source_match, dest_match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003370 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vasko0491ab32015-08-19 14:28:29 +02003371 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed_loc = 0, pke_parsed = 0;
3372 int has_predicate, dest_parent_times, i, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003373 uint32_t j;
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003374 struct lyd_node_leaf_list *leaf_dst, *leaf_src;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003375
3376 source_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003377 source_match.node = malloc(sizeof *source_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003378 if (!source_match.node) {
3379 LOGMEM;
3380 return -1;
3381 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003382 dest_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003383 dest_match.node = malloc(sizeof *dest_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003384 if (!dest_match.node) {
3385 LOGMEM;
3386 return -1;
3387 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003388
3389 do {
3390 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
3391 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003392 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, pred[-i], &pred[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003393 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003394 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003395 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003396 parsed_loc += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003397 pred += i;
3398
Michal Vasko23b61ec2015-08-19 11:19:50 +02003399 for (j = 0; j < node_match->count;) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003400 /* source */
Michal Vaskocf024702015-10-08 15:01:42 +02003401 source_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02003402
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003403 /* must be leaf (key of a list) */
Radek Krejci581ce772015-11-10 17:22:40 +01003404 if ((rc = resolve_data_node(sour_pref, sour_pref_len, source, sour_len, node_match->node[j],
Michal Vaskocf024702015-10-08 15:01:42 +02003405 &source_match)) || (source_match.count != 1) || (source_match.node[0]->schema->nodetype != LYS_LEAF)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003406 i = 0;
3407 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003408 }
3409
3410 /* destination */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003411 dest_match.node[0] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003412 dest_parent_times = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003413 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3414 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003415 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003416 rc = -1;
3417 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003418 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003419 pke_parsed = i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003420 for (i = 0; i < dest_parent_times; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02003421 dest_match.node[0] = dest_match.node[0]->parent;
3422 if (!dest_match.node[0]) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003423 i = 0;
Michal Vasko0491ab32015-08-19 14:28:29 +02003424 rc = EXIT_FAILURE;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003425 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003426 }
3427 }
3428 while (1) {
Radek Krejci581ce772015-11-10 17:22:40 +01003429 if ((rc = resolve_data_node(dest_pref, dest_pref_len, dest, dest_len, dest_match.node[0],
Michal Vasko0491ab32015-08-19 14:28:29 +02003430 &dest_match)) || (dest_match.count != 1)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003431 i = 0;
3432 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003433 }
3434
3435 if (pke_len == pke_parsed) {
3436 break;
3437 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003438 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 +02003439 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003440 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003441 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003442 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003443 }
3444 pke_parsed += i;
3445 }
3446
3447 /* check match between source and destination nodes */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003448 leaf_dst = (struct lyd_node_leaf_list *)dest_match.node[0];
3449 while (leaf_dst->value_type == LY_TYPE_LEAFREF) {
3450 leaf_dst = (struct lyd_node_leaf_list *)leaf_dst->value.leafref;
3451 }
3452 leaf_src = (struct lyd_node_leaf_list *)source_match.node[0];
3453 while (leaf_src->value_type == LY_TYPE_LEAFREF) {
3454 leaf_src = (struct lyd_node_leaf_list *)leaf_src->value.leafref;
3455 }
3456 if (leaf_src->value_type != leaf_dst->value_type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003457 goto remove_leafref;
3458 }
3459
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003460 if (!ly_strequal(leaf_src->value_str, leaf_dst->value_str, 1)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003461 goto remove_leafref;
3462 }
3463
3464 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003465 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003466 continue;
3467
3468remove_leafref:
3469 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003470 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003471 }
3472 } while (has_predicate);
3473
Michal Vaskocf024702015-10-08 15:01:42 +02003474 free(source_match.node);
3475 free(dest_match.node);
Michal Vasko0491ab32015-08-19 14:28:29 +02003476 if (parsed) {
3477 *parsed = parsed_loc;
3478 }
3479 return EXIT_SUCCESS;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003480
3481error:
3482
3483 if (source_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003484 free(source_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003485 }
3486 if (dest_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003487 free(dest_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003488 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003489 if (parsed) {
3490 *parsed = -parsed_loc+i;
3491 }
3492 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003493}
3494
Michal Vasko730dfdf2015-08-11 14:48:05 +02003495/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003496 * @brief Resolve a path (leafref) in JSON data context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003497 *
Michal Vaskocf024702015-10-08 15:01:42 +02003498 * @param[in] node Leafref data node.
Michal Vasko23b61ec2015-08-19 11:19:50 +02003499 * @param[in] path Path of the leafref.
Radek Krejci48464ed2016-03-17 15:44:09 +01003500 * @param[out] ret Matching nodes. Expects an empty, but allocated structure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003501 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003502 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003503 */
Michal Vasko184521f2015-09-24 13:14:26 +02003504static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003505resolve_path_arg_data(struct lyd_node *node, const char *path, struct unres_data *ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003506{
Radek Krejci71b795b2015-08-10 16:20:39 +02003507 struct lyd_node *data = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003508 const char *prefix, *name;
Michal Vasko0491ab32015-08-19 14:28:29 +02003509 int pref_len, nam_len, has_predicate, parent_times, i, parsed, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003510 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003511
Michal Vaskocf024702015-10-08 15:01:42 +02003512 assert(node && path && ret && !ret->count);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003513
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003514 parent_times = 0;
Michal Vaskod9173342015-08-17 14:35:36 +02003515 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003516
3517 /* searching for nodeset */
3518 do {
Radek Krejcif7ed4c32016-10-27 16:20:03 +02003519 if ((i = parse_path_arg(node->schema->module, path, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003520 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path[-i], &path[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003521 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003522 goto error;
3523 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003524 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003525 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003526
Michal Vasko23b61ec2015-08-19 11:19:50 +02003527 if (!ret->count) {
Michal Vaskobfd98e62016-09-02 09:50:05 +02003528 if (parent_times > 0) {
3529 data = node;
3530 for (i = 1; i < parent_times; ++i) {
3531 data = data->parent;
Michal Vasko253035f2015-12-17 16:58:13 +01003532 }
Michal Vaskobfd98e62016-09-02 09:50:05 +02003533 } else if (!parent_times) {
3534 data = node->child;
3535 } else {
3536 /* absolute path */
3537 for (data = node; data->parent; data = data->parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003538 }
3539
Michal Vaskobfd98e62016-09-02 09:50:05 +02003540 /* we may still be parsing it and the pointer is not correct yet */
3541 if (data->prev) {
3542 while (data->prev->next) {
3543 data = data->prev;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003544 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003545 }
3546 }
3547
3548 /* node identifier */
Radek Krejci581ce772015-11-10 17:22:40 +01003549 if ((rc = resolve_data_node(prefix, pref_len, name, nam_len, data, ret))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003550 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003551 LOGVAL(LYE_INELEM_LEN, LY_VLOG_LYD, node, nam_len, name);
Michal Vasko184521f2015-09-24 13:14:26 +02003552 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003553 goto error;
3554 }
3555
3556 if (has_predicate) {
3557 /* we have predicate, so the current results must be lists */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003558 for (j = 0; j < ret->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02003559 if (ret->node[j]->schema->nodetype == LYS_LIST &&
3560 ((struct lys_node_list *)ret->node[0]->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003561 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003562 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003563 continue;
3564 }
3565
3566 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003567 unres_data_del(ret, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003568 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003569 if ((rc = resolve_path_predicate_data(path, node, ret, &i))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003570 if (rc == -1) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003571 LOGVAL(LYE_NORESOLV, LY_VLOG_LYD, node, "leafref", path);
Michal Vasko184521f2015-09-24 13:14:26 +02003572 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003573 goto error;
3574 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003575 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003576 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003577
Michal Vasko23b61ec2015-08-19 11:19:50 +02003578 if (!ret->count) {
Michal Vasko0491ab32015-08-19 14:28:29 +02003579 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003580 goto error;
3581 }
3582 }
3583 } while (path[0] != '\0');
3584
Michal Vaskof02e3742015-08-05 16:27:02 +02003585 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003586
3587error:
3588
Michal Vaskocf024702015-10-08 15:01:42 +02003589 free(ret->node);
3590 ret->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003591 ret->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003592
Michal Vasko0491ab32015-08-19 14:28:29 +02003593 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003594}
3595
Michal Vaskoe27516a2016-10-10 17:55:31 +00003596static int
3597resolve_path_arg_schema_valid_dep_flag(const struct lys_node *op_node, const struct lys_node *first_node, int abs_path)
3598{
3599 int dep1, dep2;
3600 const struct lys_node *node;
3601
3602 if (lys_parent(op_node)) {
3603 /* inner operation (notif/action) */
3604 if (abs_path) {
3605 return 1;
3606 } else {
3607 /* compare depth of both nodes */
3608 for (dep1 = 0, node = op_node; lys_parent(node); node = lys_parent(node));
3609 for (dep2 = 0, node = first_node; lys_parent(node); node = lys_parent(node));
3610 if ((dep2 > dep1) || ((dep2 == dep1) && (op_node != first_node))) {
3611 return 1;
3612 }
3613 }
3614 } else {
3615 /* top-level operation (notif/rpc) */
3616 if (op_node != first_node) {
3617 return 1;
3618 }
3619 }
3620
3621 return 0;
3622}
3623
Michal Vasko730dfdf2015-08-11 14:48:05 +02003624/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003625 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003626 *
Michal Vaskobb211122015-08-19 14:03:11 +02003627 * @param[in] path Path to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003628 * @param[in] context_node Predicate context node (where the predicate is placed).
3629 * @param[in] parent Path context node (where the path begins/is placed).
Michal Vaskoe27516a2016-10-10 17:55:31 +00003630 * @param[in] op_node Optional node if the leafref is in an operation (action/rpc/notif).
Michal Vasko730dfdf2015-08-11 14:48:05 +02003631 *
Michal Vasko184521f2015-09-24 13:14:26 +02003632 * @return 0 on forward reference, otherwise the number
3633 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003634 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003635 */
Michal Vasko1f76a282015-08-04 16:16:53 +02003636static int
Radek Krejciadb57612016-02-16 13:34:34 +01003637resolve_path_predicate_schema(const char *path, const struct lys_node *context_node,
Michal Vaskoe27516a2016-10-10 17:55:31 +00003638 struct lys_node *parent, const struct lys_node *op_node)
Michal Vasko1f76a282015-08-04 16:16:53 +02003639{
Michal Vasko1e62a092015-12-01 12:27:20 +01003640 const struct lys_node *src_node, *dst_node;
Michal Vasko1f76a282015-08-04 16:16:53 +02003641 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vaskof9b35d92016-10-21 15:19:30 +02003642 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, pke_parsed, parsed = 0;
3643 int has_predicate, dest_parent_times, i, rc, first_iter;
Michal Vasko1f76a282015-08-04 16:16:53 +02003644
3645 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02003646 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02003647 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003648 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003649 return -parsed+i;
3650 }
3651 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003652 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02003653
Michal Vasko58090902015-08-13 14:04:15 +02003654 /* source (must be leaf) */
Michal Vasko36cbaa42015-12-14 13:15:48 +01003655 if (!sour_pref) {
Radek Krejciadb57612016-02-16 13:34:34 +01003656 sour_pref = context_node->module->name;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003657 }
Radek Krejciadb57612016-02-16 13:34:34 +01003658 rc = lys_get_sibling(context_node->child, sour_pref, sour_pref_len, source, sour_len,
Michal Vasko59ad4582016-09-16 13:15:41 +02003659 LYS_LEAF | LYS_LEAFLIST | LYS_AUGMENT, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003660 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003661 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02003662 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003663 }
3664
3665 /* destination */
Michal Vaskof9b35d92016-10-21 15:19:30 +02003666 dest_parent_times = 0;
3667 pke_parsed = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003668 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3669 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003670 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 +02003671 return -parsed;
3672 }
3673 pke_parsed += i;
3674
Radek Krejciadb57612016-02-16 13:34:34 +01003675 for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
Michal Vaskofbaead72016-10-07 10:54:48 +02003676 /* path is supposed to be evaluated in data tree, so we have to skip
3677 * all schema nodes that cannot be instantiated in data tree */
3678 for (dst_node = lys_parent(dst_node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003679 dst_node && !(dst_node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Michal Vaskofbaead72016-10-07 10:54:48 +02003680 dst_node = lys_parent(dst_node));
3681
Michal Vasko1f76a282015-08-04 16:16:53 +02003682 if (!dst_node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003683 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003684 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003685 }
3686 }
Michal Vaskoe27516a2016-10-10 17:55:31 +00003687 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003688 while (1) {
Michal Vasko36cbaa42015-12-14 13:15:48 +01003689 if (!dest_pref) {
3690 dest_pref = dst_node->module->name;
3691 }
3692 rc = lys_get_sibling(dst_node->child, dest_pref, dest_pref_len, dest, dest_len,
Michal Vasko165dc4a2015-10-23 09:44:27 +02003693 LYS_CONTAINER | LYS_LIST | LYS_LEAF | LYS_AUGMENT, &dst_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003694 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003695 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003696 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003697 }
3698
Michal Vaskoe27516a2016-10-10 17:55:31 +00003699 if (first_iter) {
3700 if (resolve_path_arg_schema_valid_dep_flag(op_node, dst_node, 0)) {
3701 parent->flags |= LYS_VALID_DEP;
3702 }
3703 first_iter = 0;
3704 }
3705
Michal Vasko1f76a282015-08-04 16:16:53 +02003706 if (pke_len == pke_parsed) {
3707 break;
3708 }
3709
3710 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
3711 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003712 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent,
Radek Krejciadb57612016-02-16 13:34:34 +01003713 (path_key_expr+pke_parsed)[-i], (path_key_expr+pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003714 return -parsed;
3715 }
3716 pke_parsed += i;
3717 }
3718
3719 /* check source - dest match */
Michal Vasko59ad4582016-09-16 13:15:41 +02003720 if (dst_node->nodetype != src_node->nodetype) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003721 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko59ad4582016-09-16 13:15:41 +02003722 LOGVAL(LYE_SPEC, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "Destination node is not a %s, but a %s.",
3723 strnodetype(src_node->nodetype), strnodetype(dst_node->nodetype));
Michal Vasko184521f2015-09-24 13:14:26 +02003724 return -parsed;
3725 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003726 } while (has_predicate);
3727
3728 return parsed;
3729}
3730
Michal Vasko730dfdf2015-08-11 14:48:05 +02003731/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003732 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003733 *
Michal Vaskobb211122015-08-19 14:03:11 +02003734 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003735 * @param[in] parent_node Parent of the leafref.
Radek Krejci2f12f852016-01-08 12:59:57 +01003736 * @param[in] parent_tpdf Flag if the parent node is actually typedef, in that case the path
3737 * has to contain absolute path
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003738 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003739 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003740 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003741 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003742static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003743resolve_path_arg_schema(const char *path, struct lys_node *parent, int parent_tpdf,
Michal Vasko36cbaa42015-12-14 13:15:48 +01003744 const struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02003745{
Michal Vaskoe27516a2016-10-10 17:55:31 +00003746 const struct lys_node *node, *op_node = NULL;
Radek Krejci27fe55e2016-09-13 17:13:35 +02003747 const struct lys_module *mod, *mod2;
Michal Vasko1f76a282015-08-04 16:16:53 +02003748 const char *id, *prefix, *name;
3749 int pref_len, nam_len, parent_times, has_predicate;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003750 int i, first_iter, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02003751
Michal Vasko184521f2015-09-24 13:14:26 +02003752 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003753 parent_times = 0;
3754 id = path;
3755
Michal Vaskoe27516a2016-10-10 17:55:31 +00003756 /* find operation schema we are in, if applicable */
Michal Vaskoe9914d12016-10-07 14:32:37 +02003757 if (!parent_tpdf) {
Michal Vaskoe27516a2016-10-10 17:55:31 +00003758 for (op_node = lys_parent(parent);
3759 op_node && !(op_node->nodetype & (LYS_ACTION | LYS_NOTIF | LYS_RPC));
3760 op_node = lys_parent(op_node));
Michal Vaskoe9914d12016-10-07 14:32:37 +02003761 }
3762
Radek Krejci27fe55e2016-09-13 17:13:35 +02003763 mod2 = lys_node_module(parent);
Michal Vasko1f76a282015-08-04 16:16:53 +02003764 do {
Radek Krejcif7ed4c32016-10-27 16:20:03 +02003765 if ((i = parse_path_arg(parent->module, id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003766 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 +02003767 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003768 }
3769 id += i;
3770
Michal Vasko184521f2015-09-24 13:14:26 +02003771 if (first_iter) {
Michal Vasko1f76a282015-08-04 16:16:53 +02003772 if (parent_times == -1) {
Radek Krejcic071c542016-01-27 14:57:51 +01003773 /* resolve prefix of the module */
Radek Krejciadb57612016-02-16 13:34:34 +01003774 mod = lys_get_import_module(parent->module, NULL, 0, prefix, pref_len);
Radek Krejci0fa54e92016-09-14 14:01:05 +02003775 mod = lys_get_implemented_module(mod);
Radek Krejcic071c542016-01-27 14:57:51 +01003776 /* get start node */
3777 node = mod ? mod->data : NULL;
Michal Vasko58090902015-08-13 14:04:15 +02003778 if (!node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003779 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3780 "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003781 return EXIT_FAILURE;
Michal Vasko58090902015-08-13 14:04:15 +02003782 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003783 } else if (parent_times > 0) {
Radek Krejci2f12f852016-01-08 12:59:57 +01003784 if (parent_tpdf) {
3785 /* the path is not allowed to contain relative path since we are in top level typedef */
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003786 LOGVAL(LYE_NORESOLV, 0, NULL, "leafref", path);
Radek Krejci2f12f852016-01-08 12:59:57 +01003787 return -1;
3788 }
3789
Michal Vasko94458082016-10-07 14:34:36 +02003790 /* we are looking for a sibling of a node, node it's parent (that is why parent_times - 1) */
3791 for (i = 0, node = parent; i < parent_times - 1; i++) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02003792 /* path is supposed to be evaluated in data tree, so we have to skip
3793 * all schema nodes that cannot be instantiated in data tree */
3794 for (node = lys_parent(node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003795 node && !(node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Radek Krejci3a5501d2016-07-18 22:03:34 +02003796 node = lys_parent(node));
3797
Michal Vasko1f76a282015-08-04 16:16:53 +02003798 if (!node) {
Michal Vaskoe9914d12016-10-07 14:32:37 +02003799 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003800 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003801 }
3802 }
Michal Vaskoe01eca52015-08-13 14:42:02 +02003803 } else {
3804 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003805 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003806 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003807 } else {
Michal Vasko7dc71d02016-03-15 10:42:28 +01003808 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02003809 if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko2f5aceb2016-03-22 10:24:14 +01003810 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 +01003811 return -1;
3812 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003813 node = node->child;
Radek Krejci43ccc4c2016-10-18 20:40:06 +02003814 if (!node) {
3815 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3816 "leafref", path);
3817 return EXIT_FAILURE;
3818 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003819 }
3820
Michal Vasko4f0dad02016-02-15 14:08:23 +01003821 if (!prefix) {
Radek Krejciadb57612016-02-16 13:34:34 +01003822 prefix = lys_node_module(parent)->name;
Michal Vasko4f0dad02016-02-15 14:08:23 +01003823 }
3824
Michal Vasko36cbaa42015-12-14 13:15:48 +01003825 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 +02003826 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003827 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko7a55bea2016-05-02 14:51:20 +02003828 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003829 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003830
Michal Vaskoe27516a2016-10-10 17:55:31 +00003831 if (first_iter) {
3832 /* set external dependency flag, we can decide based on the first found node */
3833 if (!parent_tpdf && op_node && parent_times &&
3834 resolve_path_arg_schema_valid_dep_flag(op_node, node, (parent_times == -1 ? 1 : 0))) {
3835 parent->flags |= LYS_VALID_DEP;
3836 }
3837 first_iter = 0;
3838 }
3839
Michal Vasko1f76a282015-08-04 16:16:53 +02003840 if (has_predicate) {
3841 /* we have predicate, so the current result must be list */
3842 if (node->nodetype != LYS_LIST) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003843 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003844 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003845 }
3846
Michal Vaskoe27516a2016-10-10 17:55:31 +00003847 i = resolve_path_predicate_schema(id, node, parent, op_node);
Radek Krejci27fe55e2016-09-13 17:13:35 +02003848 if (i <= 0) {
3849 if (i == 0) {
3850 return EXIT_FAILURE;
3851 } else { /* i < 0 */
3852 return -1;
3853 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003854 }
3855 id += i;
Michal Vaskof9b35d92016-10-21 15:19:30 +02003856 has_predicate = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003857 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02003858 mod = lys_node_module(node);
3859 if (!mod->implemented && mod != mod2) {
3860 /* set the module implemented */
3861 if (lys_set_implemented(mod)) {
3862 return -1;
3863 }
3864 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003865 } while (id[0]);
3866
Michal Vaskoca917682016-07-25 11:00:37 +02003867 /* the target must be leaf or leaf-list (in YANG 1.1 only) */
3868 if ((node->nodetype != LYS_LEAF) && ((lys_node_module(parent)->version != 2) || (node->nodetype != LYS_LEAFLIST))) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003869 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Radek Krejcid47daf62016-08-22 16:23:38 +02003870 LOGVAL(LYE_SPEC, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3871 "Leafref target \"%s\" is not a leaf%s.", path,
3872 lys_node_module(parent)->version != 2 ? "" : " nor a leaf-list");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003873 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02003874 }
3875
Radek Krejcicf509982015-12-15 09:22:44 +01003876 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01003877 if (lyp_check_status(parent->flags, parent->module, parent->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01003878 node->flags, node->module, node->name, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003879 return -1;
3880 }
3881
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003882 if (ret) {
3883 *ret = node;
3884 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02003885
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003886 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02003887}
3888
Michal Vasko730dfdf2015-08-11 14:48:05 +02003889/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003890 * @brief Resolve instance-identifier predicate in JSON data format.
3891 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003892 *
Michal Vaskobb211122015-08-19 14:03:11 +02003893 * @param[in] pred Predicate to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003894 * @param[in,out] node_match Nodes matching the restriction without
3895 * the predicate. Nodes not satisfying
3896 * the predicate are removed.
3897 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003898 * @return Number of characters successfully parsed,
3899 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003900 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003901static int
Michal Vaskof39142b2015-10-21 11:40:05 +02003902resolve_predicate(const char *pred, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003903{
Michal Vasko730dfdf2015-08-11 14:48:05 +02003904 /* ... /node[target = value] ... */
Michal Vaskob2f40be2016-09-08 16:03:48 +02003905 struct lyd_node *target;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003906 const char *model, *name, *value;
Michal Vaskob2f40be2016-09-08 16:03:48 +02003907 int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed, pred_iter, k;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003908 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003909
Michal Vasko1f2cc332015-08-19 11:18:32 +02003910 assert(pred && node_match->count);
3911
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003912 idx = -1;
3913 parsed = 0;
3914
Michal Vaskob2f40be2016-09-08 16:03:48 +02003915 pred_iter = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003916 do {
Michal Vaskof39142b2015-10-21 11:40:05 +02003917 if ((i = parse_predicate(pred, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003918 return -parsed+i;
3919 }
3920 parsed += i;
3921 pred += i;
3922
3923 if (isdigit(name[0])) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02003924 /* pos */
3925 assert(!value);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003926 idx = atoi(name);
Michal Vaskob2f40be2016-09-08 16:03:48 +02003927 } else if (name[0] != '.') {
3928 /* list keys */
3929 if (pred_iter < 0) {
3930 pred_iter = 1;
3931 } else {
3932 ++pred_iter;
3933 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003934 }
3935
Michal Vaskof2f28a12016-09-09 12:43:06 +02003936 for (cur_idx = 1, j = 0; j < node_match->count; ++cur_idx) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003937 /* target */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003938 if (name[0] == '.') {
Michal Vaskob2f40be2016-09-08 16:03:48 +02003939 /* leaf-list value */
Michal Vaskocf024702015-10-08 15:01:42 +02003940 if (node_match->node[j]->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003941 goto remove_instid;
3942 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02003943
3944 target = node_match->node[j];
3945 /* check the value */
3946 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
3947 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
3948 goto remove_instid;
3949 }
3950
3951 } else if (!value) {
3952 /* keyless list position */
3953 if ((node_match->node[j]->schema->nodetype != LYS_LIST)
3954 || ((struct lys_node_list *)node_match->node[j]->schema)->keys) {
3955 goto remove_instid;
3956 }
3957
3958 if (idx != cur_idx) {
3959 goto remove_instid;
3960 }
3961
3962 } else {
3963 /* list key value */
Michal Vaskocf024702015-10-08 15:01:42 +02003964 if (node_match->node[j]->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003965 goto remove_instid;
3966 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02003967
3968 /* key module must match the list module */
3969 if (strncmp(node_match->node[j]->schema->module->name, model, mod_len)
3970 || node_match->node[j]->schema->module->name[mod_len]) {
3971 goto remove_instid;
3972 }
3973 /* find the key leaf */
Michal Vasko045182c2016-09-09 12:44:07 +02003974 for (k = 1, target = node_match->node[j]->child; target && (k < pred_iter); k++, target = target->next);
Michal Vaskob2f40be2016-09-08 16:03:48 +02003975 if (!target) {
3976 goto remove_instid;
3977 }
3978 if ((struct lys_node_leaf *)target->schema !=
3979 ((struct lys_node_list *)node_match->node[j]->schema)->keys[pred_iter - 1]) {
3980 goto remove_instid;
3981 }
3982
3983 /* check the value */
3984 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
3985 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
3986 goto remove_instid;
3987 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003988 }
3989
Michal Vaskob2f40be2016-09-08 16:03:48 +02003990 /* instid is ok, continue check with the next one */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003991 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003992 continue;
3993
3994remove_instid:
Michal Vaskob2f40be2016-09-08 16:03:48 +02003995 /* does not fulfill conditions, remove instid record */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003996 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003997 }
3998 } while (has_predicate);
3999
Michal Vaskob2f40be2016-09-08 16:03:48 +02004000 /* check that all list keys were specified */
4001 if ((pred_iter > 0) && node_match->count) {
Michal Vasko045182c2016-09-09 12:44:07 +02004002 j = 0;
4003 while (j < node_match->count) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004004 assert(node_match->node[j]->schema->nodetype == LYS_LIST);
4005 if (pred_iter < ((struct lys_node_list *)node_match->node[j]->schema)->keys_size) {
4006 /* not enough predicates, just remove the list instance */
4007 unres_data_del(node_match, j);
Michal Vasko045182c2016-09-09 12:44:07 +02004008 } else {
4009 ++j;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004010 }
4011 }
4012
4013 if (!node_match->count) {
4014 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier is missing some list keys.");
4015 }
4016 }
4017
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004018 return parsed;
4019}
4020
Michal Vasko730dfdf2015-08-11 14:48:05 +02004021/**
Michal Vaskof39142b2015-10-21 11:40:05 +02004022 * @brief Resolve instance-identifier in JSON data format. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004023 *
Radek Krejciadb57612016-02-16 13:34:34 +01004024 * @param[in] data Data node where the path is used
Michal Vasko730dfdf2015-08-11 14:48:05 +02004025 * @param[in] path Instance-identifier node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004026 *
Radek Krejcic5090c32015-08-12 09:46:19 +02004027 * @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 +02004028 */
Michal Vasko184521f2015-09-24 13:14:26 +02004029static struct lyd_node *
Radek Krejci48464ed2016-03-17 15:44:09 +01004030resolve_instid(struct lyd_node *data, const char *path)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004031{
Radek Krejcic5090c32015-08-12 09:46:19 +02004032 int i = 0, j;
4033 struct lyd_node *result = NULL;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004034 const struct lys_module *mod;
Radek Krejcic5090c32015-08-12 09:46:19 +02004035 struct ly_ctx *ctx = data->schema->module->ctx;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004036 const char *model, *name;
Radek Krejcic5090c32015-08-12 09:46:19 +02004037 char *str;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004038 int mod_len, name_len, has_predicate;
4039 struct unres_data node_match;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004040
4041 memset(&node_match, 0, sizeof node_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004042
Radek Krejcic5090c32015-08-12 09:46:19 +02004043 /* we need root to resolve absolute path */
4044 for (; data->parent; data = data->parent);
Michal Vaskodb9323c2015-10-16 10:32:44 +02004045 /* we're still parsing it and the pointer is not correct yet */
Michal Vasko0491ab32015-08-19 14:28:29 +02004046 if (data->prev) {
4047 for (; data->prev->next; data = data->prev);
4048 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004049
Radek Krejcic5090c32015-08-12 09:46:19 +02004050 /* search for the instance node */
4051 while (path[i]) {
Michal Vaskof39142b2015-10-21 11:40:05 +02004052 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
Radek Krejcic5090c32015-08-12 09:46:19 +02004053 if (j <= 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004054 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004055 goto error;
4056 }
Radek Krejcic5090c32015-08-12 09:46:19 +02004057 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02004058
Michal Vaskob2f40be2016-09-08 16:03:48 +02004059 str = strndup(model, mod_len);
4060 if (!str) {
4061 LOGMEM;
4062 goto error;
Radek Krejcic5090c32015-08-12 09:46:19 +02004063 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004064 mod = ly_ctx_get_module(ctx, str, NULL);
4065 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02004066
Michal Vasko1f2cc332015-08-19 11:18:32 +02004067 if (resolve_data(mod, name, name_len, data, &node_match)) {
Radek Krejcic5090c32015-08-12 09:46:19 +02004068 /* no instance exists */
4069 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004070 }
4071
4072 if (has_predicate) {
4073 /* we have predicate, so the current results must be list or leaf-list */
Michal Vaskof39142b2015-10-21 11:40:05 +02004074 j = resolve_predicate(&path[i], &node_match);
Radek Krejcic5090c32015-08-12 09:46:19 +02004075 if (j < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004076 LOGVAL(LYE_INPRED, LY_VLOG_LYD, data, &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004077 goto error;
4078 }
Michal Vasko1f2cc332015-08-19 11:18:32 +02004079 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02004080
Michal Vasko1f2cc332015-08-19 11:18:32 +02004081 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02004082 /* no instance exists */
4083 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004084 }
4085 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004086 }
4087
Michal Vasko1f2cc332015-08-19 11:18:32 +02004088 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02004089 /* no instance exists */
4090 return NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02004091 } else if (node_match.count > 1) {
Radek Krejcic5090c32015-08-12 09:46:19 +02004092 /* instance identifier must resolve to a single node */
Radek Krejci48464ed2016-03-17 15:44:09 +01004093 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
Michal Vaskod6adbaa2016-04-11 11:01:09 +02004094 goto error;
Radek Krejcic5090c32015-08-12 09:46:19 +02004095 } else {
4096 /* we have required result, remember it and cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02004097 result = node_match.node[0];
4098 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02004099 return result;
4100 }
4101
4102error:
Radek Krejcic5090c32015-08-12 09:46:19 +02004103 /* cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02004104 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02004105 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004106}
4107
Michal Vasko730dfdf2015-08-11 14:48:05 +02004108/**
Michal Vasko9e635ac2016-10-17 11:44:09 +02004109 * @brief Check all XPath expressions of a node (when and must), set LYS_XPATH_DEP flag if required.
4110 *
4111 * @param[in] node Node to examine.
4112 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
4113 */
4114static int
4115check_node_xpath(struct lys_node *node)
4116{
4117 struct lys_node *parent, *elem;
4118 struct lyxp_set set;
4119 uint32_t i;
4120 int rc;
4121
4122 parent = node;
4123 while (parent) {
4124 if (parent->nodetype == LYS_GROUPING) {
4125 /* unresolved grouping, skip for now (will be checked later) */
4126 return EXIT_SUCCESS;
4127 }
4128 if (parent->nodetype == LYS_AUGMENT) {
4129 if (!((struct lys_node_augment *)parent)->target) {
4130 /* uresolved augment, skip for now (will be checked later) */
4131 return EXIT_SUCCESS;
4132 } else {
4133 parent = ((struct lys_node_augment *)parent)->target;
4134 continue;
4135 }
4136 }
4137 parent = parent->parent;
4138 }
4139
4140 rc = lyxp_node_atomize(node, &set);
4141 if (rc) {
4142 return rc;
4143 }
4144
4145 for (parent = node; parent && !(parent->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); parent = lys_parent(parent));
4146
4147 for (i = 0; i < set.used; ++i) {
4148 /* skip roots'n'stuff */
4149 if (set.val.snodes[i].type == LYXP_NODE_ELEM) {
4150 /* XPath expression cannot reference "lower" status than the node that has the definition */
4151 if (lyp_check_status(node->flags, lys_node_module(node), node->name, set.val.snodes[i].snode->flags,
4152 lys_node_module(set.val.snodes[i].snode), set.val.snodes[i].snode->name, node)) {
4153 return -1;
4154 }
4155
4156 if (parent) {
4157 for (elem = set.val.snodes[i].snode; elem && (elem != parent); elem = lys_parent(elem));
4158 if (!elem) {
4159 /* not in node's RPC or notification subtree, set the flag */
4160 node->flags |= LYS_VALID_DEP;
4161 break;
4162 }
4163 }
4164 }
4165 }
4166
4167 free(set.val.snodes);
4168 return EXIT_SUCCESS;
4169}
4170
4171/**
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004172 * @brief Passes config flag down to children, skips nodes without config flags.
4173 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004174 *
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004175 * @param[in] node Siblings and their children to have flags changed.
Michal Vaskoe022a562016-09-27 14:24:15 +02004176 * @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 +02004177 * @param[in] flags Flags to assign to all the nodes.
Michal Vaskoa86508c2016-08-26 14:30:19 +02004178 *
4179 * @return 0 on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004180 */
Michal Vaskoa86508c2016-08-26 14:30:19 +02004181static int
Michal Vasko9e635ac2016-10-17 11:44:09 +02004182inherit_config_flag(struct lys_node *node, int flags, int clear, int check_list, int check_xpath)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004183{
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004184 assert(!(flags ^ (flags & LYS_CONFIG_MASK)));
Radek Krejci1d82ef62015-08-07 14:44:40 +02004185 LY_TREE_FOR(node, node) {
Michal Vasko9e635ac2016-10-17 11:44:09 +02004186 if (check_xpath && check_node_xpath(node)) {
4187 return -1;
4188 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004189 if (clear) {
4190 node->flags &= ~LYS_CONFIG_MASK;
Michal Vaskoc2a8d362016-09-29 08:50:13 +02004191 node->flags &= ~LYS_CONFIG_SET;
Michal Vaskoe022a562016-09-27 14:24:15 +02004192 } else {
4193 if (node->flags & LYS_CONFIG_SET) {
4194 /* skip nodes with an explicit config value */
4195 if ((flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
4196 LOGVAL(LYE_INARG, LY_VLOG_LYS, node, "true", "config");
4197 LOGVAL(LYE_SPEC, LY_VLOG_LYS, node, "State nodes cannot have configuration nodes as children.");
4198 return -1;
4199 }
4200 continue;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004201 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004202
4203 if (!(node->nodetype & (LYS_USES | LYS_GROUPING))) {
4204 node->flags = (node->flags & ~LYS_CONFIG_MASK) | flags;
4205 /* check that configuration lists have keys */
4206 if (check_list && (node->nodetype == LYS_LIST)
4207 && (node->flags & LYS_CONFIG_W) && !((struct lys_node_list *)node)->keys_size) {
4208 LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_LYS, node, "key", "list");
4209 return -1;
4210 }
4211 }
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004212 }
Radek Krejcibf2abff2016-08-23 15:51:52 +02004213 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vasko9e635ac2016-10-17 11:44:09 +02004214 if (inherit_config_flag(node->child, flags, clear, check_list, check_xpath)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004215 return -1;
4216 }
Radek Krejci3a5501d2016-07-18 22:03:34 +02004217 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004218 }
Michal Vaskoa86508c2016-08-26 14:30:19 +02004219
4220 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004221}
4222
Michal Vasko730dfdf2015-08-11 14:48:05 +02004223/**
Michal Vasko7178e692016-02-12 15:58:05 +01004224 * @brief Resolve augment target. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004225 *
Michal Vaskobb211122015-08-19 14:03:11 +02004226 * @param[in] aug Augment to use.
Michal Vasko3edeaf72016-02-11 13:17:43 +01004227 * @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 +02004228 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004229 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004230 */
Michal Vasko7178e692016-02-12 15:58:05 +01004231static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004232resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004233{
Michal Vaskoe022a562016-09-27 14:24:15 +02004234 int rc, clear_config;
Michal Vasko1d87a922015-08-21 12:57:16 +02004235 struct lys_node *sub;
Pavol Vican47319932016-08-29 09:14:47 +02004236 const struct lys_node *aug_target, *parent;
Radek Krejci27fe55e2016-09-13 17:13:35 +02004237 struct lys_module *mod;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004238
Michal Vasko15b36692016-08-26 15:29:54 +02004239 assert(aug && !aug->target);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004240
Michal Vasko15b36692016-08-26 15:29:54 +02004241 /* resolve target node */
4242 rc = resolve_augment_schema_nodeid(aug->target_name, siblings, (siblings ? NULL : aug->module), &aug_target);
4243 if (rc == -1) {
4244 return -1;
4245 }
4246 if (rc > 0) {
4247 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, aug, aug->target_name[rc - 1], &aug->target_name[rc - 1]);
4248 return -1;
4249 }
4250 if (!aug_target) {
4251 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
4252 return EXIT_FAILURE;
4253 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004254
Radek Krejci27fe55e2016-09-13 17:13:35 +02004255 /* check that we want to connect augment into its target */
4256 mod = lys_main_module(aug->module);
4257 if (!mod->implemented) {
4258 /* it must be augment only to the same module,
4259 * otherwise we do not apply augment in not-implemented
4260 * module. If the module is set to be implemented in future,
4261 * the augment is being resolved and checked again */
4262 for (sub = aug->target; sub; sub = lys_parent(sub)) {
4263 if (lys_node_module(sub) != mod) {
4264 /* this is not an implemented module and the augment
4265 * target some other module, so avoid its connecting
4266 * to the target */
4267 return EXIT_SUCCESS;
4268 }
4269 }
4270 }
4271
Michal Vasko15b36692016-08-26 15:29:54 +02004272 if (!aug->child) {
4273 /* nothing to do */
4274 LOGWRN("Augment \"%s\" without children.", aug->target_name);
Radek Krejci27fe55e2016-09-13 17:13:35 +02004275 goto success;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004276 }
4277
Michal Vaskod58d5962016-03-02 14:29:41 +01004278 /* check for mandatory nodes - if the target node is in another module
4279 * the added nodes cannot be mandatory
4280 */
Michal Vasko15b36692016-08-26 15:29:54 +02004281 if (!aug->parent && (lys_node_module((struct lys_node *)aug) != lys_node_module(aug_target))
Radek Krejcie00d2312016-08-12 15:27:49 +02004282 && (rc = lyp_check_mandatory_augment(aug))) {
4283 return rc;
Michal Vaskod58d5962016-03-02 14:29:41 +01004284 }
4285
Michal Vasko07e89ef2016-03-03 13:28:57 +01004286 /* check augment target type and then augment nodes type */
Michal Vasko15b36692016-08-26 15:29:54 +02004287 if (aug_target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF)) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004288 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004289 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES | LYS_CHOICE))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004290 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4291 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko15b36692016-08-26 15:29:54 +02004292 strnodetype(aug_target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004293 return -1;
4294 }
4295 }
Michal Vasko15b36692016-08-26 15:29:54 +02004296 } else if (aug_target->nodetype == LYS_CHOICE) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004297 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004298 if (!(sub->nodetype & (LYS_CASE | LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004299 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4300 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko15b36692016-08-26 15:29:54 +02004301 strnodetype(aug_target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004302 return -1;
4303 }
4304 }
4305 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01004306 LOGVAL(LYE_INARG, LY_VLOG_LYS, aug, aug->target_name, "target-node");
Michal Vasko15b36692016-08-26 15:29:54 +02004307 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Invalid augment target node type \"%s\".", strnodetype(aug_target->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004308 return -1;
4309 }
4310
Radek Krejcic071c542016-01-27 14:57:51 +01004311 /* check identifier uniqueness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02004312 LY_TREE_FOR(aug->child, sub) {
Michal Vasko15b36692016-08-26 15:29:54 +02004313 if (lys_check_id(sub, (struct lys_node *)aug_target, NULL)) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02004314 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02004315 }
4316 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004317
Michal Vasko15b36692016-08-26 15:29:54 +02004318 /* finally reconnect augmenting data into the target - add them to the target child list,
4319 * by setting aug->target we know the augment is fully resolved now */
4320 aug->target = (struct lys_node *)aug_target;
4321 if (aug->target->child) {
4322 sub = aug->target->child->prev; /* remember current target's last node */
4323 sub->next = aug->child; /* connect augmenting data after target's last node */
4324 aug->target->child->prev = aug->child->prev; /* new target's last node is last augmenting node */
4325 aug->child->prev = sub; /* finish connecting of both child lists */
4326 } else {
4327 aug->target->child = aug->child;
4328 }
4329
Michal Vasko9e635ac2016-10-17 11:44:09 +02004330 /* inherit config information from actual parent */
4331 for(parent = aug_target; parent && !(parent->nodetype & (LYS_NOTIF | LYS_INPUT | LYS_OUTPUT | LYS_RPC)); parent = lys_parent(parent));
4332 clear_config = (parent) ? 1 : 0;
4333 LY_TREE_FOR(aug->child, sub) {
4334 if (inherit_config_flag(sub, aug_target->flags & LYS_CONFIG_MASK, clear_config, 1, 1)) {
4335 return -1;
4336 }
4337 }
4338
Radek Krejci27fe55e2016-09-13 17:13:35 +02004339success:
4340 if (mod->implemented) {
4341 /* make target modules also implemented */
4342 for (sub = aug->target; sub; sub = lys_parent(sub)) {
4343 if (lys_set_implemented(sub->module)) {
4344 return -1;
4345 }
4346 }
4347 }
4348
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004349 return EXIT_SUCCESS;
4350}
4351
Michal Vasko730dfdf2015-08-11 14:48:05 +02004352/**
Pavol Vican855ca622016-09-05 13:07:54 +02004353 * @brief Resolve (find) choice default case. Does not log.
4354 *
4355 * @param[in] choic Choice to use.
4356 * @param[in] dflt Name of the default case.
4357 *
4358 * @return Pointer to the default node or NULL.
4359 */
4360static struct lys_node *
4361resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
4362{
4363 struct lys_node *child, *ret;
4364
4365 LY_TREE_FOR(choic->child, child) {
4366 if (child->nodetype == LYS_USES) {
4367 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
4368 if (ret) {
4369 return ret;
4370 }
4371 }
4372
4373 if (ly_strequal(child->name, dflt, 1) && (child->nodetype & (LYS_ANYDATA | LYS_CASE
Radek Krejci2f792db2016-09-12 10:52:33 +02004374 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE))) {
Pavol Vican855ca622016-09-05 13:07:54 +02004375 return child;
4376 }
4377 }
4378
4379 return NULL;
4380}
4381
4382/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02004383 * @brief Resolve uses, apply augments, refines. Logs directly.
4384 *
Michal Vaskobb211122015-08-19 14:03:11 +02004385 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004386 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004387 *
Michal Vaskodef0db12015-10-07 13:22:48 +02004388 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004389 */
Michal Vasko184521f2015-09-24 13:14:26 +02004390static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004391resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004392{
4393 struct ly_ctx *ctx;
Pavol Vican855ca622016-09-05 13:07:54 +02004394 struct lys_node *node = NULL, *next, *iter, **refine_nodes = NULL;
Pavol Vican55abd332016-07-12 15:54:49 +02004395 struct lys_node *node_aux, *parent, *tmp;
Radek Krejci200bf712016-08-16 17:11:04 +02004396 struct lys_node_leaflist *llist;
4397 struct lys_node_leaf *leaf;
Radek Krejci76512572015-08-04 09:47:08 +02004398 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004399 struct lys_restr *must, **old_must;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004400 struct lys_iffeature *iff, **old_iff;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004401 int i, j, k, rc, parent_config, clear_config, check_list, check_xpath;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004402 uint8_t size, *old_size;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004403 unsigned int usize, usize1, usize2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004404
Michal Vasko71e1aa82015-08-12 12:17:51 +02004405 assert(uses->grp);
Michal Vaskoe7708512016-03-11 10:26:55 +01004406 /* HACK just check that the grouping is resolved */
Michal Vaskodef0db12015-10-07 13:22:48 +02004407 assert(!uses->grp->nacm);
Michal Vasko71e1aa82015-08-12 12:17:51 +02004408
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004409 if (!uses->grp->child) {
4410 /* grouping without children, warning was already displayed */
4411 return EXIT_SUCCESS;
4412 }
4413
4414 /* get proper parent (config) flags */
4415 for (node_aux = lys_parent((struct lys_node *)uses); node_aux && (node_aux->nodetype == LYS_USES); node_aux = lys_parent(node_aux));
4416 if (node_aux) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004417 parent_config = node_aux->flags & LYS_CONFIG_MASK;
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004418 } else {
4419 /* default */
Michal Vaskoa86508c2016-08-26 14:30:19 +02004420 parent_config = LYS_CONFIG_W;
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004421 }
4422
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004423 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01004424 LY_TREE_FOR(uses->grp->child, node_aux) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004425 node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, uses->nacm, unres, 0);
Michal Vasko1e62a092015-12-01 12:27:20 +01004426 if (!node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004427 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, uses->grp->name, "uses");
4428 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Copying data from grouping failed.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004429 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004430 }
Pavol Vican55abd332016-07-12 15:54:49 +02004431 /* test the name of siblings */
4432 LY_TREE_FOR((uses->parent) ? uses->parent->child : lys_main_module(uses->module)->data, tmp) {
Pavol Vican2510ddc2016-07-18 16:23:44 +02004433 if (!(tmp->nodetype & (LYS_USES | LYS_GROUPING | LYS_CASE)) && ly_strequal(tmp->name, node_aux->name, 1)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004434 goto fail;
Pavol Vican55abd332016-07-12 15:54:49 +02004435 }
4436 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004437 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004438
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004439 ctx = uses->module->ctx;
Michal Vasko4bc590c2016-09-30 12:19:51 +02004440
4441 parent = node;
4442 while (parent && !(parent->nodetype & (LYS_NOTIF | LYS_INPUT | LYS_OUTPUT | LYS_RPC | LYS_GROUPING))) {
4443 if (parent->nodetype == LYS_AUGMENT) {
4444 if (!((struct lys_node_augment *)parent)->target) {
4445 break;
4446 } else {
4447 parent = ((struct lys_node_augment *)parent)->target;
4448 }
4449 } else {
4450 parent = parent->parent;
4451 }
4452 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004453 if (parent) {
Michal Vasko4bc590c2016-09-30 12:19:51 +02004454 if (parent->nodetype & (LYS_GROUPING | LYS_AUGMENT)) {
4455 /* we are still in some other unresolved grouping or augment, unable to check lists */
Michal Vaskoe022a562016-09-27 14:24:15 +02004456 check_list = 0;
4457 clear_config = 0;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004458 check_xpath = 0;
Michal Vaskoe022a562016-09-27 14:24:15 +02004459 } else {
4460 check_list = 0;
4461 clear_config = 1;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004462 check_xpath = 1;
Michal Vaskoe022a562016-09-27 14:24:15 +02004463 }
4464 } else {
4465 check_list = 1;
4466 clear_config = 0;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004467 check_xpath = 1;
Michal Vaskoe022a562016-09-27 14:24:15 +02004468 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004469
Michal Vaskoa86508c2016-08-26 14:30:19 +02004470 if (parent_config) {
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004471 assert(uses->child);
Michal Vasko9e635ac2016-10-17 11:44:09 +02004472 if (inherit_config_flag(uses->child, parent_config, clear_config, check_list, check_xpath)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004473 goto fail;
4474 }
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004475 }
4476
Michal Vaskodef0db12015-10-07 13:22:48 +02004477 /* we managed to copy the grouping, the rest must be possible to resolve */
4478
Pavol Vican855ca622016-09-05 13:07:54 +02004479 if (uses->refine_size) {
4480 refine_nodes = malloc(uses->refine_size * sizeof *refine_nodes);
4481 if (!refine_nodes) {
4482 LOGMEM;
4483 goto fail;
4484 }
4485 }
4486
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004487 /* apply refines */
4488 for (i = 0; i < uses->refine_size; i++) {
4489 rfn = &uses->refine[i];
Michal Vasko3edeaf72016-02-11 13:17:43 +01004490 rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child, LYS_NO_RPC_NOTIF_NODE,
Radek Krejcif3c71de2016-04-11 12:45:46 +02004491 1, 0, (const struct lys_node **)&node);
Michal Vasko9bb061b2016-02-12 11:00:19 +01004492 if (rc || !node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004493 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004494 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004495 }
4496
Radek Krejci1d82ef62015-08-07 14:44:40 +02004497 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004498 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
4499 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Refine substatements not applicable to the target-node.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004500 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004501 }
Pavol Vican855ca622016-09-05 13:07:54 +02004502 refine_nodes[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004503
4504 /* description on any nodetype */
4505 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004506 lydict_remove(ctx, node->dsc);
4507 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004508 }
4509
4510 /* reference on any nodetype */
4511 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004512 lydict_remove(ctx, node->ref);
4513 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004514 }
4515
4516 /* config on any nodetype */
Michal Vaskoe022a562016-09-27 14:24:15 +02004517 if ((rfn->flags & LYS_CONFIG_MASK) && !clear_config) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004518 node->flags &= ~LYS_CONFIG_MASK;
4519 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004520 }
4521
4522 /* default value ... */
Radek Krejci200bf712016-08-16 17:11:04 +02004523 if (rfn->dflt_size) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004524 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004525 /* leaf */
Radek Krejci200bf712016-08-16 17:11:04 +02004526 leaf = (struct lys_node_leaf *)node;
4527
4528 lydict_remove(ctx, leaf->dflt);
4529 leaf->dflt = lydict_insert(ctx, rfn->dflt[0], 0);
4530
4531 /* check the default value */
4532 if (unres_schema_add_str(leaf->module, unres, &leaf->type, UNRES_TYPE_DFLT, leaf->dflt) == -1) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004533 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004534 }
Radek Krejci200bf712016-08-16 17:11:04 +02004535 } else if (node->nodetype == LYS_LEAFLIST) {
4536 /* leaf-list */
4537 llist = (struct lys_node_leaflist *)node;
4538
4539 /* remove complete set of defaults in target */
4540 for (i = 0; i < llist->dflt_size; i++) {
4541 lydict_remove(ctx, llist->dflt[i]);
4542 }
4543 free(llist->dflt);
4544
4545 /* copy the default set from refine */
4546 llist->dflt_size = rfn->dflt_size;
4547 llist->dflt = malloc(llist->dflt_size * sizeof *llist->dflt);
4548 for (i = 0; i < llist->dflt_size; i++) {
4549 llist->dflt[i] = lydict_insert(ctx, rfn->dflt[i], 0);
4550 }
4551
4552 /* check default value */
4553 for (i = 0; i < llist->dflt_size; i++) {
4554 if (unres_schema_add_str(llist->module, unres, &llist->type, UNRES_TYPE_DFLT, llist->dflt[i]) == -1) {
Pavol Vican855ca622016-09-05 13:07:54 +02004555 goto fail;
Radek Krejci200bf712016-08-16 17:11:04 +02004556 }
4557 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004558 }
4559 }
4560
4561 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02004562 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004563 if (node->nodetype & (LYS_LEAF | LYS_ANYDATA | LYS_CHOICE)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004564 /* remove current value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004565 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004566
4567 /* set new value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004568 node->flags |= (rfn->flags & LYS_MAND_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004569 }
Pavol Vican855ca622016-09-05 13:07:54 +02004570 if (rfn->flags & LYS_MAND_TRUE) {
4571 /* check if node has default value */
4572 if ((node->nodetype & LYS_LEAF) && ((struct lys_node_leaf *)node)->dflt) {
4573 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"mandatory\" statement is forbidden on leaf with \"default\".");
4574 goto fail;
4575 }
4576 if ((node->nodetype & LYS_CHOICE) && ((struct lys_node_choice *)node)->dflt) {
4577 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"mandatory\" statement is forbidden on choices with \"default\".");
4578 goto fail;
4579 }
4580 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004581 }
4582
4583 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004584 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
4585 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
4586 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004587 }
4588
4589 /* min/max-elements on list or leaf-list */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004590 if (node->nodetype == LYS_LIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004591 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004592 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004593 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004594 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004595 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004596 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02004597 } else if (node->nodetype == LYS_LEAFLIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004598 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004599 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004600 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004601 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004602 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004603 }
4604 }
4605
4606 /* must in leaf, leaf-list, list, container or anyxml */
4607 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004608 switch (node->nodetype) {
4609 case LYS_LEAF:
4610 old_size = &((struct lys_node_leaf *)node)->must_size;
4611 old_must = &((struct lys_node_leaf *)node)->must;
4612 break;
4613 case LYS_LEAFLIST:
4614 old_size = &((struct lys_node_leaflist *)node)->must_size;
4615 old_must = &((struct lys_node_leaflist *)node)->must;
4616 break;
4617 case LYS_LIST:
4618 old_size = &((struct lys_node_list *)node)->must_size;
4619 old_must = &((struct lys_node_list *)node)->must;
4620 break;
4621 case LYS_CONTAINER:
4622 old_size = &((struct lys_node_container *)node)->must_size;
4623 old_must = &((struct lys_node_container *)node)->must;
4624 break;
4625 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02004626 case LYS_ANYDATA:
4627 old_size = &((struct lys_node_anydata *)node)->must_size;
4628 old_must = &((struct lys_node_anydata *)node)->must;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004629 break;
4630 default:
4631 LOGINT;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004632 goto fail;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004633 }
4634
4635 size = *old_size + rfn->must_size;
4636 must = realloc(*old_must, size * sizeof *rfn->must);
4637 if (!must) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004638 LOGMEM;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004639 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004640 }
Pavol Vican855ca622016-09-05 13:07:54 +02004641 for (k = 0, j = *old_size; k < rfn->must_size; k++, j++) {
4642 must[j].expr = lydict_insert(ctx, rfn->must[k].expr, 0);
4643 must[j].dsc = lydict_insert(ctx, rfn->must[k].dsc, 0);
4644 must[j].ref = lydict_insert(ctx, rfn->must[k].ref, 0);
4645 must[j].eapptag = lydict_insert(ctx, rfn->must[k].eapptag, 0);
4646 must[j].emsg = lydict_insert(ctx, rfn->must[k].emsg, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004647 }
4648
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004649 *old_must = must;
4650 *old_size = size;
Michal Vasko508a50d2016-09-07 14:50:33 +02004651
4652 /* check XPath dependencies again */
4653 if (unres_schema_add_node(node->module, unres, node, UNRES_XPATH, NULL) == -1) {
4654 goto fail;
4655 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004656 }
Radek Krejci363bd4a2016-07-29 14:30:20 +02004657
4658 /* if-feature in leaf, leaf-list, list, container or anyxml */
4659 if (rfn->iffeature_size) {
4660 old_size = &node->iffeature_size;
4661 old_iff = &node->iffeature;
4662
4663 size = *old_size + rfn->iffeature_size;
4664 iff = realloc(*old_iff, size * sizeof *rfn->iffeature);
4665 if (!iff) {
4666 LOGMEM;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004667 goto fail;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004668 }
Pavol Vican855ca622016-09-05 13:07:54 +02004669 for (k = 0, j = *old_size; k < rfn->iffeature_size; k++, j++) {
4670 resolve_iffeature_getsizes(&rfn->iffeature[k], &usize1, &usize2);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004671 if (usize1) {
4672 /* there is something to duplicate */
4673 /* duplicate compiled expression */
4674 usize = (usize1 / 4) + (usize1 % 4) ? 1 : 0;
4675 iff[j].expr = malloc(usize * sizeof *iff[j].expr);
Pavol Vican855ca622016-09-05 13:07:54 +02004676 memcpy(iff[j].expr, rfn->iffeature[k].expr, usize * sizeof *iff[j].expr);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004677
4678 /* duplicate list of feature pointers */
Pavol Vican855ca622016-09-05 13:07:54 +02004679 iff[j].features = malloc(usize2 * sizeof *iff[k].features);
4680 memcpy(iff[j].features, rfn->iffeature[k].features, usize2 * sizeof *iff[j].features);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004681 }
4682 }
4683
4684 *old_iff = iff;
4685 *old_size = size;
4686 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004687 }
4688
4689 /* apply augments */
4690 for (i = 0; i < uses->augment_size; i++) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004691 rc = resolve_augment(&uses->augment[i], uses->child);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004692 if (rc) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004693 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004694 }
4695 }
4696
Pavol Vican855ca622016-09-05 13:07:54 +02004697 /* check refines */
4698 for (i = 0; i < uses->refine_size; i++) {
4699 node = refine_nodes[i];
4700 rfn = &uses->refine[i];
4701
4702 /* config on any nodetype */
Michal Vaskoe022a562016-09-27 14:24:15 +02004703 if ((rfn->flags & LYS_CONFIG_MASK) && !clear_config) {
Pavol Vican855ca622016-09-05 13:07:54 +02004704 for (parent = lys_parent(node); parent && parent->nodetype == LYS_USES; parent = lys_parent(parent));
4705 if (parent && parent->nodetype != LYS_GROUPING &&
4706 ((parent->flags & LYS_CONFIG_MASK) != (rfn->flags & LYS_CONFIG_MASK)) &&
4707 (rfn->flags & LYS_CONFIG_W)) {
4708 /* setting config true under config false is prohibited */
4709 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
4710 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4711 "changing config from 'false' to 'true' is prohibited while "
4712 "the target's parent is still config 'false'.");
4713 goto fail;
4714 }
4715
4716 /* inherit config change to the target children */
4717 LY_TREE_DFS_BEGIN(node->child, next, iter) {
4718 if (rfn->flags & LYS_CONFIG_W) {
4719 if (iter->flags & LYS_CONFIG_SET) {
4720 /* config is set explicitely, go to next sibling */
4721 next = NULL;
4722 goto nextsibling;
4723 }
4724 } else { /* LYS_CONFIG_R */
4725 if ((iter->flags & LYS_CONFIG_SET) && (iter->flags & LYS_CONFIG_W)) {
4726 /* error - we would have config data under status data */
4727 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
4728 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4729 "changing config from 'true' to 'false' is prohibited while the target "
4730 "has still a children with explicit config 'true'.");
4731 goto fail;
4732 }
4733 }
4734 /* change config */
4735 iter->flags &= ~LYS_CONFIG_MASK;
4736 iter->flags |= (rfn->flags & LYS_CONFIG_MASK);
4737
4738 /* select next iter - modified LY_TREE_DFS_END */
4739 if (iter->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
4740 next = NULL;
4741 } else {
4742 next = iter->child;
4743 }
4744nextsibling:
4745 if (!next) {
4746 /* try siblings */
4747 next = iter->next;
4748 }
4749 while (!next) {
4750 /* parent is already processed, go to its sibling */
4751 iter = lys_parent(iter);
4752
4753 /* no siblings, go back through parents */
4754 if (iter == node) {
4755 /* we are done, no next element to process */
4756 break;
4757 }
4758 next = iter->next;
4759 }
4760 }
4761 }
4762
4763 /* default value */
4764 if (rfn->dflt_size && node->nodetype == LYS_CHOICE) {
4765 /* choice */
4766
4767 ((struct lys_node_choice *)node)->dflt = resolve_choice_dflt((struct lys_node_choice *)node,
4768 rfn->dflt[0]);
4769 if (!((struct lys_node_choice *)node)->dflt) {
4770 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->dflt[0], "default");
4771 goto fail;
4772 }
4773 if (lyp_check_mandatory_choice(node)) {
4774 goto fail;
4775 }
4776 }
4777
4778 /* min/max-elements on list or leaf-list */
4779 if (node->nodetype == LYS_LIST) {
4780 if (((struct lys_node_list *)node)->min > ((struct lys_node_list *)node)->max) {
4781 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
4782 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "\"min-elements\" is bigger than \"max-elements\".");
4783 goto fail;
4784 }
4785 } else if (node->nodetype == LYS_LEAFLIST) {
4786 if (((struct lys_node_leaflist *)node)->min > ((struct lys_node_leaflist *)node)->max) {
4787 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
4788 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "\"min-elements\" is bigger than \"max-elements\".");
4789 goto fail;
4790 }
4791 }
4792
4793 /* additional checks */
4794 if (node->nodetype == LYS_LEAFLIST) {
4795 llist = (struct lys_node_leaflist *)node;
4796 if (llist->dflt_size && llist->min) {
4797 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, rfn->dflt_size ? "default" : "min-elements", "refine");
4798 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
4799 "The \"min-elements\" statement with non-zero value is forbidden on leaf-lists with the \"default\" statement.");
4800 goto fail;
4801 }
4802 }
4803 if ((rfn->flags & LYS_MAND_TRUE) || rfn->mod.list.min) {
4804 /* check for mandatory node in default case, first find the closest parent choice to the changed node */
4805 for (parent = node->parent;
4806 parent && !(parent->nodetype & (LYS_CHOICE | LYS_GROUPING | LYS_ACTION | LYS_USES));
4807 parent = parent->parent) {
4808 if (parent->nodetype == LYS_CONTAINER && ((struct lys_node_container *)parent)->presence) {
4809 /* stop also on presence containers */
4810 break;
4811 }
4812 }
4813 /* and if it is a choice with the default case, check it for presence of a mandatory node in it */
4814 if (parent && parent->nodetype == LYS_CHOICE && ((struct lys_node_choice *)parent)->dflt) {
4815 if (lyp_check_mandatory_choice(parent)) {
4816 goto fail;
4817 }
4818 }
4819 }
4820 }
4821 free(refine_nodes);
4822
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004823 return EXIT_SUCCESS;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004824
4825fail:
4826 LY_TREE_FOR_SAFE(uses->child, next, iter) {
4827 lys_node_free(iter, NULL, 0);
4828 }
Pavol Vican855ca622016-09-05 13:07:54 +02004829 free(refine_nodes);
Michal Vaskoa86508c2016-08-26 14:30:19 +02004830 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004831}
4832
Radek Krejci018f1f52016-08-03 16:01:20 +02004833static int
4834identity_backlink_update(struct lys_ident *der, struct lys_ident *base)
4835{
4836 int i;
4837
4838 assert(der && base);
4839
4840 base->der = ly_realloc(base->der, (base->der_size + 1) * sizeof *(base->der));
4841 if (!base->der) {
4842 LOGMEM;
4843 return EXIT_FAILURE;
4844 }
4845 base->der[base->der_size++] = der;
4846
4847 for (i = 0; i < base->base_size; i++) {
4848 if (identity_backlink_update(der, base->base[i])) {
4849 return EXIT_FAILURE;
4850 }
4851 }
4852
4853 return EXIT_SUCCESS;
4854}
4855
Michal Vasko730dfdf2015-08-11 14:48:05 +02004856/**
4857 * @brief Resolve base identity recursively. Does not log.
4858 *
4859 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004860 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004861 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004862 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004863 *
Radek Krejci219fa612016-08-15 10:36:51 +02004864 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on crucial error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004865 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004866static int
Michal Vasko1e62a092015-12-01 12:27:20 +01004867resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Radek Krejci018f1f52016-08-03 16:01:20 +02004868 struct unres_schema *unres, struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004869{
Michal Vaskof02e3742015-08-05 16:27:02 +02004870 uint32_t i, j;
Radek Krejci018f1f52016-08-03 16:01:20 +02004871 struct lys_ident *base = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004872
Radek Krejcicf509982015-12-15 09:22:44 +01004873 assert(ret);
4874
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004875 /* search module */
4876 for (i = 0; i < module->ident_size; i++) {
4877 if (!strcmp(basename, module->ident[i].name)) {
4878
4879 if (!ident) {
4880 /* just search for type, so do not modify anything, just return
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004881 * the base identity pointer */
Radek Krejcicf509982015-12-15 09:22:44 +01004882 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004883 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004884 }
4885
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004886 base = &module->ident[i];
4887 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004888 }
4889 }
4890
4891 /* search submodules */
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004892 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
4893 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
4894 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004895
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004896 if (!ident) {
4897 *ret = &module->inc[j].submodule->ident[i];
4898 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004899 }
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004900
4901 base = &module->inc[j].submodule->ident[i];
4902 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004903 }
4904 }
4905 }
4906
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004907matchfound:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004908 /* we found it somewhere */
Radek Krejcibabbff82016-02-19 13:31:37 +01004909 if (base) {
Radek Krejci018f1f52016-08-03 16:01:20 +02004910 /* is it already completely resolved? */
4911 for (i = 0; i < unres->count; i++) {
Radek Krejciba7b1cc2016-08-08 13:44:43 +02004912 if ((unres->item[i] == base) && (unres->type[i] == UNRES_IDENT)) {
Radek Krejci018f1f52016-08-03 16:01:20 +02004913 /* identity found, but not yet resolved, so do not return it in *res and try it again later */
4914
4915 /* simple check for circular reference,
4916 * the complete check is done as a side effect of using only completely
4917 * resolved identities (previous check of unres content) */
4918 if (ly_strequal((const char *)unres->str_snode[i], ident->name, 1)) {
4919 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, basename, "base");
4920 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Circular reference of \"%s\" identity.", basename);
Radek Krejci219fa612016-08-15 10:36:51 +02004921 return -1;
Radek Krejci018f1f52016-08-03 16:01:20 +02004922 }
4923
Radek Krejci06f64ed2016-08-15 11:07:44 +02004924 return EXIT_FAILURE;
Radek Krejcibabbff82016-02-19 13:31:37 +01004925 }
4926 }
Radek Krejci018f1f52016-08-03 16:01:20 +02004927
Radek Krejcibabbff82016-02-19 13:31:37 +01004928 /* checks done, store the result */
Radek Krejci018f1f52016-08-03 16:01:20 +02004929 *ret = base;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02004930 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004931 }
4932
Radek Krejci219fa612016-08-15 10:36:51 +02004933 /* base not found (maybe a forward reference) */
4934 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004935}
4936
Michal Vasko730dfdf2015-08-11 14:48:05 +02004937/**
4938 * @brief Resolve base identity. Logs directly.
4939 *
4940 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004941 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004942 * @param[in] basename Base name of the identity.
Radek Krejcibabbff82016-02-19 13:31:37 +01004943 * @param[in] parent Either "type" or "identity".
Radek Krejcicf509982015-12-15 09:22:44 +01004944 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004945 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004946 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004947 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004948static int
Michal Vaskof2d43962016-09-02 11:10:16 +02004949resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char *parent,
Radek Krejci018f1f52016-08-03 16:01:20 +02004950 struct lys_type *type, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004951{
4952 const char *name;
Radek Krejci219fa612016-08-15 10:36:51 +02004953 int mod_name_len = 0, rc;
Radek Krejcicf509982015-12-15 09:22:44 +01004954 struct lys_ident *target, **ret;
Radek Krejci4372b4e2016-04-14 17:42:16 +02004955 uint16_t flags;
Radek Krejcicf509982015-12-15 09:22:44 +01004956 struct lys_module *mod;
4957
4958 assert((ident && !type) || (!ident && type));
4959
4960 if (!type) {
4961 /* have ident to resolve */
4962 ret = &target;
4963 flags = ident->flags;
4964 mod = ident->module;
4965 } else {
4966 /* have type to fill */
Michal Vaskof2d43962016-09-02 11:10:16 +02004967 ++type->info.ident.count;
4968 type->info.ident.ref = ly_realloc(type->info.ident.ref, type->info.ident.count * sizeof *type->info.ident.ref);
4969 if (!type->info.ident.ref) {
4970 LOGMEM;
4971 return -1;
4972 }
4973
4974 ret = &type->info.ident.ref[type->info.ident.count - 1];
Radek Krejcicf509982015-12-15 09:22:44 +01004975 flags = type->parent->flags;
4976 mod = type->parent->module;
4977 }
Michal Vaskof2006002016-04-21 16:28:15 +02004978 *ret = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004979
4980 /* search for the base identity */
4981 name = strchr(basename, ':');
4982 if (name) {
4983 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02004984 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004985 name++;
4986
Michal Vasko2d851a92015-10-20 16:16:36 +02004987 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004988 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02004989 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004990 }
4991 } else {
4992 name = basename;
4993 }
4994
Radek Krejcic071c542016-01-27 14:57:51 +01004995 /* get module where to search */
4996 module = lys_get_import_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len);
4997 if (!module) {
4998 /* identity refers unknown data model */
Radek Krejci02a04992016-03-17 16:06:37 +01004999 LOGVAL(LYE_INMOD, LY_VLOG_NONE, NULL, basename);
Radek Krejcic071c542016-01-27 14:57:51 +01005000 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005001 }
5002
Radek Krejcic071c542016-01-27 14:57:51 +01005003 /* search in the identified module ... */
Radek Krejci219fa612016-08-15 10:36:51 +02005004 rc = resolve_base_ident_sub(module, ident, name, unres, ret);
5005 if (!rc) {
5006 assert(*ret);
5007
5008 /* check status */
5009 if (lyp_check_status(flags, mod, ident ? ident->name : "of type",
5010 (*ret)->flags, (*ret)->module, (*ret)->name, NULL)) {
5011 rc = -1;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02005012 } else {
5013 if (ident) {
5014 ident->base[ident->base_size++] = *ret;
5015
5016 /* maintain backlinks to the derived identities */
5017 rc = identity_backlink_update(ident, *ret) ? -1 : EXIT_SUCCESS;
5018 }
Radek Krejci219fa612016-08-15 10:36:51 +02005019 }
5020 } else if (rc == EXIT_FAILURE) {
5021 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, parent, basename);
Pavol Vican053a2882016-09-05 14:40:33 +02005022 if (type) {
5023 --type->info.ident.count;
5024 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005025 }
5026
Radek Krejci219fa612016-08-15 10:36:51 +02005027 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005028}
5029
Michal Vasko730dfdf2015-08-11 14:48:05 +02005030/**
Michal Vaskof39142b2015-10-21 11:40:05 +02005031 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005032 *
Michal Vaskof2d43962016-09-02 11:10:16 +02005033 * @param[in] type Identityref type.
Michal Vaskofb0873c2015-08-21 09:00:07 +02005034 * @param[in] ident_name Identityref name.
Radek Krejciadb57612016-02-16 13:34:34 +01005035 * @param[in] node Node where the identityref is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02005036 *
5037 * @return Pointer to the identity resolvent, NULL on error.
5038 */
Radek Krejcia52656e2015-08-05 13:41:50 +02005039struct lys_ident *
Michal Vaskof2d43962016-09-02 11:10:16 +02005040resolve_identref(struct lys_type *type, const char *ident_name, struct lyd_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005041{
Michal Vaskoc633ca02015-08-21 14:03:51 +02005042 const char *mod_name, *name;
Michal Vaskof2d43962016-09-02 11:10:16 +02005043 int mod_name_len, rc, i, j;
5044 struct lys_ident *der, *cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005045
Michal Vaskof2d43962016-09-02 11:10:16 +02005046 if (!type || (!type->info.ident.count && !type->der) || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005047 return NULL;
5048 }
5049
Michal Vaskoc633ca02015-08-21 14:03:51 +02005050 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, NULL);
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005051 if (rc < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005052 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005053 return NULL;
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005054 } else if (rc < (signed)strlen(ident_name)) {
Radek Krejci02a04992016-03-17 16:06:37 +01005055 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[rc], &ident_name[rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005056 return NULL;
5057 }
5058
Michal Vaskof2d43962016-09-02 11:10:16 +02005059 /* go through all the bases in all the derived types */
5060 while (type->der) {
5061 for (i = 0; i < type->info.ident.count; ++i) {
5062 cur = type->info.ident.ref[i];
5063 if (!strcmp(cur->name, name) && (!mod_name
5064 || (!strncmp(cur->module->name, mod_name, mod_name_len) && !cur->module->name[mod_name_len]))) {
5065 goto match;
5066 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02005067
Michal Vaskof2d43962016-09-02 11:10:16 +02005068 for (j = 0; j < cur->der_size; j++) {
5069 der = cur->der[j]; /* 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 }
5076 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005077 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005078 type = &type->der->type;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005079 }
5080
Radek Krejci48464ed2016-03-17 15:44:09 +01005081 LOGVAL(LYE_INRESOLV, LY_VLOG_LYD, node, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005082 return NULL;
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005083
5084match:
Michal Vaskof2d43962016-09-02 11:10:16 +02005085 for (i = 0; i < cur->iffeature_size; i++) {
5086 if (!resolve_iffeature(&cur->iffeature[i])) {
5087 LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, cur->name, node->schema->name);
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005088 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, "Identity \"%s\" is disabled by its if-feature condition.",
Michal Vaskof2d43962016-09-02 11:10:16 +02005089 cur->name);
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005090 return NULL;
5091 }
5092 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005093 return cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005094}
5095
Michal Vasko730dfdf2015-08-11 14:48:05 +02005096/**
Michal Vaskobb211122015-08-19 14:03:11 +02005097 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005098 *
Michal Vaskobb211122015-08-19 14:03:11 +02005099 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005100 * @param[in] unres Specific unres item.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005101 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005102 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005103 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005104static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005105resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005106{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005107 int rc;
Radek Krejci010e54b2016-03-15 09:40:34 +01005108 struct lys_node *par_grp;
Michal Vaskoe91afce2015-08-12 12:21:00 +02005109
Radek Krejci010e54b2016-03-15 09:40:34 +01005110 /* HACK: when a grouping has uses inside, all such uses have to be resolved before the grouping itself
5111 * is used in some uses. When we see such a uses, the grouping's nacm member (not used in grouping)
5112 * is used to store number of so far unresolved uses. The grouping cannot be used unless the nacm
5113 * value is decreased back to 0. To remember that the uses already increased grouping's nacm, the
5114 * LYS_USESGRP flag is used. */
Michal Vaskodcf98e62016-05-05 17:53:53 +02005115 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 +02005116
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005117 if (!uses->grp) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01005118 rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
5119 if (rc == -1) {
Michal Vasko92981a62016-10-14 10:25:16 +02005120 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005121 return -1;
5122 } else if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005123 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005124 return -1;
5125 } else if (!uses->grp) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005126 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005127 /* hack - in contrast to lys_node, lys_node_grp has bigger nacm field
5128 * (and smaller flags - it uses only a limited set of flags)
5129 */
5130 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci010e54b2016-03-15 09:40:34 +01005131 uses->flags |= LYS_USESGRP;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005132 }
Michal Vasko92981a62016-10-14 10:25:16 +02005133 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005134 return EXIT_FAILURE;
Michal Vasko12e30842015-08-04 11:54:00 +02005135 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005136 }
5137
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005138 if (uses->grp->nacm) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005139 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005140 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci010e54b2016-03-15 09:40:34 +01005141 uses->flags |= LYS_USESGRP;
Radek Krejcie00d2312016-08-12 15:27:49 +02005142 } else {
5143 /* instantiate grouping only when it is completely resolved */
5144 uses->grp = NULL;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005145 }
Michal Vasko92981a62016-10-14 10:25:16 +02005146 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005147 return EXIT_FAILURE;
5148 }
5149
Radek Krejci48464ed2016-03-17 15:44:09 +01005150 rc = resolve_uses(uses, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005151 if (!rc) {
5152 /* decrease unres count only if not first try */
Radek Krejci010e54b2016-03-15 09:40:34 +01005153 if (par_grp && (uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005154 if (!((struct lys_node_grp *)par_grp)->nacm) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005155 LOGINT;
5156 return -1;
5157 }
Radek Krejci4372b4e2016-04-14 17:42:16 +02005158 ((struct lys_node_grp *)par_grp)->nacm--;
Radek Krejci010e54b2016-03-15 09:40:34 +01005159 uses->flags &= ~LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005160 }
Radek Krejcicf509982015-12-15 09:22:44 +01005161
5162 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005163 if (lyp_check_status(uses->flags, uses->module, "of uses",
Radek Krejciadb57612016-02-16 13:34:34 +01005164 uses->grp->flags, uses->grp->module, uses->grp->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005165 (struct lys_node *)uses)) {
Radek Krejcicf509982015-12-15 09:22:44 +01005166 return -1;
5167 }
5168
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005169 return EXIT_SUCCESS;
5170 }
5171
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005172 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005173}
5174
Michal Vasko730dfdf2015-08-11 14:48:05 +02005175/**
Michal Vasko9957e592015-08-17 15:04:09 +02005176 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005177 *
Michal Vaskobb211122015-08-19 14:03:11 +02005178 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005179 * @param[in] keys_str Keys node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005180 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005181 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005182 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005183static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005184resolve_list_keys(struct lys_node_list *list, const char *keys_str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005185{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005186 int i, len, rc;
Michal Vasko4f0dad02016-02-15 14:08:23 +01005187 const char *value;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005188
5189 for (i = 0; i < list->keys_size; ++i) {
5190 /* get the key name */
5191 if ((value = strpbrk(keys_str, " \t\n"))) {
5192 len = value - keys_str;
5193 while (isspace(value[0])) {
5194 value++;
5195 }
5196 } else {
5197 len = strlen(keys_str);
5198 }
5199
Radek Krejcic4283442016-04-22 09:19:27 +02005200 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 +02005201 if (rc) {
Michal Vasko7a55bea2016-05-02 14:51:20 +02005202 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
5203 return EXIT_FAILURE;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005204 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005205
Radek Krejci48464ed2016-03-17 15:44:09 +01005206 if (check_key(list, i, keys_str, len)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005207 /* check_key logs */
5208 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005209 }
5210
Radek Krejcicf509982015-12-15 09:22:44 +01005211 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005212 if (lyp_check_status(list->flags, list->module, list->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005213 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
5214 (struct lys_node *)list->keys[i])) {
Radek Krejcicf509982015-12-15 09:22:44 +01005215 return -1;
5216 }
5217
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005218 /* prepare for next iteration */
5219 while (value && isspace(value[0])) {
5220 value++;
5221 }
5222 keys_str = value;
5223 }
5224
Michal Vaskof02e3742015-08-05 16:27:02 +02005225 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005226}
5227
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005228/**
Michal Vaskobf19d252015-10-08 15:39:17 +02005229 * @brief Resolve (check) all must conditions of \p node.
5230 * Logs directly.
5231 *
5232 * @param[in] node Data node with optional must statements.
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005233 * @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 +02005234 *
5235 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
5236 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005237static int
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005238resolve_must(struct lyd_node *node, int inout_parent)
Michal Vaskof02e3742015-08-05 16:27:02 +02005239{
Michal Vaskobf19d252015-10-08 15:39:17 +02005240 uint8_t i, must_size;
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005241 struct lys_node *schema;
Michal Vaskobf19d252015-10-08 15:39:17 +02005242 struct lys_restr *must;
5243 struct lyxp_set set;
5244
5245 assert(node);
5246 memset(&set, 0, sizeof set);
5247
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005248 if (inout_parent) {
5249 for (schema = lys_parent(node->schema);
5250 schema && (schema->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES));
5251 schema = lys_parent(schema));
5252 if (!schema || !(schema->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5253 LOGINT;
5254 return -1;
5255 }
5256 must_size = ((struct lys_node_inout *)schema)->must_size;
5257 must = ((struct lys_node_inout *)schema)->must;
5258
5259 /* context node is the RPC/action */
5260 node = node->parent;
5261 if (!(node->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
5262 LOGINT;
5263 return -1;
5264 }
5265 } else {
5266 switch (node->schema->nodetype) {
5267 case LYS_CONTAINER:
5268 must_size = ((struct lys_node_container *)node->schema)->must_size;
5269 must = ((struct lys_node_container *)node->schema)->must;
5270 break;
5271 case LYS_LEAF:
5272 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
5273 must = ((struct lys_node_leaf *)node->schema)->must;
5274 break;
5275 case LYS_LEAFLIST:
5276 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
5277 must = ((struct lys_node_leaflist *)node->schema)->must;
5278 break;
5279 case LYS_LIST:
5280 must_size = ((struct lys_node_list *)node->schema)->must_size;
5281 must = ((struct lys_node_list *)node->schema)->must;
5282 break;
5283 case LYS_ANYXML:
5284 case LYS_ANYDATA:
5285 must_size = ((struct lys_node_anydata *)node->schema)->must_size;
5286 must = ((struct lys_node_anydata *)node->schema)->must;
5287 break;
5288 case LYS_NOTIF:
5289 must_size = ((struct lys_node_notif *)node->schema)->must_size;
5290 must = ((struct lys_node_notif *)node->schema)->must;
5291 break;
5292 default:
5293 must_size = 0;
5294 break;
5295 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005296 }
5297
5298 for (i = 0; i < must_size; ++i) {
Michal Vaskoa59495d2016-08-22 09:18:58 +02005299 if (lyxp_eval(must[i].expr, node, LYXP_NODE_ELEM, &set, LYXP_MUST)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02005300 return -1;
5301 }
5302
Michal Vasko944a5642016-03-21 11:48:58 +01005303 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, LYXP_MUST);
Michal Vaskobf19d252015-10-08 15:39:17 +02005304
Michal Vasko8146d4c2016-05-09 15:50:29 +02005305 if (!set.val.bool) {
Michal Vasko6ac68282016-04-11 10:56:47 +02005306 LOGVAL(LYE_NOMUST, LY_VLOG_LYD, node, must[i].expr);
5307 if (must[i].emsg) {
5308 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, must[i].emsg);
5309 }
5310 if (must[i].eapptag) {
5311 strncpy(((struct ly_err *)&ly_errno)->apptag, must[i].eapptag, LY_APPTAG_LEN - 1);
5312 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005313 return 1;
5314 }
5315 }
5316
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005317 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02005318}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005319
Michal Vaskobf19d252015-10-08 15:39:17 +02005320/**
Michal Vasko508a50d2016-09-07 14:50:33 +02005321 * @brief Resolve (find) when condition schema context node. Does not log.
5322 *
5323 * @param[in] schema Schema node with the when condition.
5324 * @param[out] ctx_snode When schema context node.
5325 * @param[out] ctx_snode_type Schema context node type.
5326 */
5327void
5328resolve_when_ctx_snode(const struct lys_node *schema, struct lys_node **ctx_snode, enum lyxp_node_type *ctx_snode_type)
5329{
5330 const struct lys_node *sparent;
5331
5332 /* find a not schema-only node */
5333 *ctx_snode_type = LYXP_NODE_ELEM;
5334 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
5335 if (schema->nodetype == LYS_AUGMENT) {
5336 sparent = ((struct lys_node_augment *)schema)->target;
5337 } else {
5338 sparent = schema->parent;
5339 }
5340 if (!sparent) {
5341 /* context node is the document root (fake root in our case) */
5342 if (schema->flags & LYS_CONFIG_W) {
5343 *ctx_snode_type = LYXP_NODE_ROOT_CONFIG;
5344 } else {
Michal Vaskob94a5e42016-09-08 14:01:56 +02005345 *ctx_snode_type = LYXP_NODE_ROOT;
Michal Vasko508a50d2016-09-07 14:50:33 +02005346 }
Michal Vasko2d2aec12016-09-08 11:42:50 +02005347 /* we need the first top-level sibling, but no uses or groupings */
Michal Vaskob94a5e42016-09-08 14:01:56 +02005348 schema = lys_getnext(NULL, NULL, lys_node_module(schema), 0);
Michal Vasko508a50d2016-09-07 14:50:33 +02005349 break;
5350 }
5351 schema = sparent;
5352 }
5353
5354 *ctx_snode = (struct lys_node *)schema;
5355}
5356
5357/**
Michal Vaskocf024702015-10-08 15:01:42 +02005358 * @brief Resolve (find) when condition context node. Does not log.
5359 *
5360 * @param[in] node Data node, whose conditional definition is being decided.
Michal Vasko508a50d2016-09-07 14:50:33 +02005361 * @param[in] schema Schema node with the when condition.
Michal Vaskoa59495d2016-08-22 09:18:58 +02005362 * @param[out] ctx_node Context node.
5363 * @param[out] ctx_node_type Context node type.
Michal Vaskocf024702015-10-08 15:01:42 +02005364 *
Michal Vaskoa59495d2016-08-22 09:18:58 +02005365 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vaskocf024702015-10-08 15:01:42 +02005366 */
Michal Vaskoa59495d2016-08-22 09:18:58 +02005367static int
5368resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema, struct lyd_node **ctx_node,
5369 enum lyxp_node_type *ctx_node_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005370{
Michal Vaskocf024702015-10-08 15:01:42 +02005371 struct lyd_node *parent;
5372 struct lys_node *sparent;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005373 enum lyxp_node_type node_type;
Michal Vaskocf024702015-10-08 15:01:42 +02005374 uint16_t i, data_depth, schema_depth;
5375
Michal Vasko508a50d2016-09-07 14:50:33 +02005376 resolve_when_ctx_snode(schema, &schema, &node_type);
Michal Vaskocf024702015-10-08 15:01:42 +02005377
Michal Vaskofe989752016-09-08 08:47:26 +02005378 if (node_type == LYXP_NODE_ELEM) {
5379 /* standard element context node */
5380 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
5381 for (sparent = schema, schema_depth = 0;
5382 sparent;
5383 sparent = (sparent->nodetype == LYS_AUGMENT ? ((struct lys_node_augment *)sparent)->target : sparent->parent)) {
5384 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_NOTIF | LYS_RPC)) {
5385 ++schema_depth;
5386 }
Michal Vaskocf024702015-10-08 15:01:42 +02005387 }
Michal Vaskofe989752016-09-08 08:47:26 +02005388 if (data_depth < schema_depth) {
5389 return -1;
5390 }
Michal Vaskocf024702015-10-08 15:01:42 +02005391
Michal Vasko956e8542016-08-26 09:43:35 +02005392 /* find the corresponding data node */
5393 for (i = 0; i < data_depth - schema_depth; ++i) {
5394 node = node->parent;
5395 }
Michal Vaskoa59495d2016-08-22 09:18:58 +02005396 if (node->schema != schema) {
5397 return -1;
5398 }
Michal Vaskofe989752016-09-08 08:47:26 +02005399 } else {
5400 /* root context node */
5401 while (node->parent) {
5402 node = node->parent;
5403 }
5404 while (node->prev->next) {
5405 node = node->prev;
5406 }
Michal Vaskocf024702015-10-08 15:01:42 +02005407 }
5408
Michal Vaskoa59495d2016-08-22 09:18:58 +02005409 *ctx_node = node;
5410 *ctx_node_type = node_type;
5411 return EXIT_SUCCESS;
Michal Vaskocf024702015-10-08 15:01:42 +02005412}
5413
Michal Vasko76c3bd32016-08-24 16:02:52 +02005414/**
5415 * @brief Temporarily unlink nodes as per YANG 1.1 RFC section 7.21.5 for when XPath evaluation.
5416 * The context nodes is adjusted if needed.
5417 *
5418 * @param[in] snode Schema node, whose children instances need to be unlinked.
5419 * @param[in,out] node Data siblings where to look for the children of \p snode. If it is unlinked,
5420 * it is moved to point to another sibling still in the original tree.
5421 * @param[in,out] ctx_node When context node, adjusted if needed.
5422 * @param[in] ctx_node_type Context node type, just for information to detect invalid situations.
5423 * @param[out] unlinked_nodes Unlinked siblings. Can be safely appended to \p node afterwards.
5424 * Ordering may change, but there will be no semantic change.
5425 *
5426 * @return EXIT_SUCCESS on success, -1 on error.
5427 */
5428static int
5429resolve_when_unlink_nodes(struct lys_node *snode, struct lyd_node **node, struct lyd_node **ctx_node,
5430 enum lyxp_node_type ctx_node_type, struct lyd_node **unlinked_nodes)
5431{
5432 struct lyd_node *next, *elem;
5433
5434 switch (snode->nodetype) {
5435 case LYS_AUGMENT:
5436 case LYS_USES:
5437 case LYS_CHOICE:
5438 case LYS_CASE:
5439 LY_TREE_FOR(snode->child, snode) {
5440 if (resolve_when_unlink_nodes(snode, node, ctx_node, ctx_node_type, unlinked_nodes)) {
5441 return -1;
5442 }
5443 }
5444 break;
5445 case LYS_CONTAINER:
5446 case LYS_LIST:
5447 case LYS_LEAF:
5448 case LYS_LEAFLIST:
5449 case LYS_ANYXML:
5450 case LYS_ANYDATA:
5451 LY_TREE_FOR_SAFE(lyd_first_sibling(*node), next, elem) {
5452 if (elem->schema == snode) {
5453
5454 if (elem == *ctx_node) {
5455 /* We are going to unlink our context node! This normally cannot happen,
5456 * but we use normal top-level data nodes for faking a document root node,
5457 * so if this is the context node, we just use the next top-level node.
5458 * Additionally, it can even happen that there are no top-level data nodes left,
5459 * all were unlinked, so in this case we pass NULL as the context node/data tree,
5460 * lyxp_eval() can handle this special situation.
5461 */
5462 if (ctx_node_type == LYXP_NODE_ELEM) {
5463 LOGINT;
5464 return -1;
5465 }
5466
5467 if (elem->prev == elem) {
5468 /* unlinking last top-level element, use an empty data tree */
5469 *ctx_node = NULL;
5470 } else {
5471 /* in this case just use the previous/last top-level data node */
5472 *ctx_node = elem->prev;
5473 }
5474 } else if (elem == *node) {
5475 /* We are going to unlink the currently processed node. This does not matter that
5476 * much, but we would lose access to the original data tree, so just move our
5477 * pointer somewhere still inside it.
5478 */
5479 if ((*node)->prev != *node) {
5480 *node = (*node)->prev;
5481 } else {
5482 /* the processed node with sibings were all unlinked, oh well */
5483 *node = NULL;
5484 }
5485 }
5486
5487 /* temporarily unlink the node */
5488 lyd_unlink(elem);
5489 if (*unlinked_nodes) {
5490 if (lyd_insert_after(*unlinked_nodes, elem)) {
5491 LOGINT;
5492 return -1;
5493 }
5494 } else {
5495 *unlinked_nodes = elem;
5496 }
5497
5498 if (snode->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_ANYDATA)) {
5499 /* there can be only one instance */
5500 break;
5501 }
5502 }
5503 }
5504 break;
5505 default:
5506 LOGINT;
5507 return -1;
5508 }
5509
5510 return EXIT_SUCCESS;
5511}
5512
5513/**
5514 * @brief Relink the unlinked nodes back.
5515 *
5516 * @param[in] node Data node to link the nodes back to. It can actually be the adjusted context node,
5517 * we simply need a sibling from the original data tree.
5518 * @param[in] unlinked_nodes Unlinked nodes to relink to \p node.
5519 * @param[in] ctx_node_type Context node type to distinguish between \p node being the parent
5520 * or the sibling of \p unlinked_nodes.
5521 *
5522 * @return EXIT_SUCCESS on success, -1 on error.
5523 */
5524static int
5525resolve_when_relink_nodes(struct lyd_node *node, struct lyd_node *unlinked_nodes, enum lyxp_node_type ctx_node_type)
5526{
5527 struct lyd_node *elem;
5528
5529 LY_TREE_FOR_SAFE(unlinked_nodes, unlinked_nodes, elem) {
5530 if (ctx_node_type == LYXP_NODE_ELEM) {
5531 if (lyd_insert(node, elem)) {
5532 return -1;
5533 }
5534 } else {
5535 if (lyd_insert_after(node, elem)) {
5536 return -1;
5537 }
5538 }
5539 }
5540
5541 return EXIT_SUCCESS;
5542}
5543
Radek Krejci03b71f72016-03-16 11:10:09 +01005544int
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005545resolve_applies_must(const struct lyd_node *node)
Radek Krejci01696bf2016-03-18 13:19:36 +01005546{
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005547 int ret = 0;
5548 uint8_t must_size;
5549 struct lys_node *schema, *iter;
Radek Krejci46165822016-08-26 14:06:27 +02005550
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005551 assert(node);
5552
5553 schema = node->schema;
5554
5555 /* their own must */
Radek Krejci46165822016-08-26 14:06:27 +02005556 switch (schema->nodetype) {
Radek Krejci01696bf2016-03-18 13:19:36 +01005557 case LYS_CONTAINER:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005558 must_size = ((struct lys_node_container *)schema)->must_size;
5559 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005560 case LYS_LEAF:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005561 must_size = ((struct lys_node_leaf *)schema)->must_size;
5562 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005563 case LYS_LEAFLIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005564 must_size = ((struct lys_node_leaflist *)schema)->must_size;
5565 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005566 case LYS_LIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005567 must_size = ((struct lys_node_list *)schema)->must_size;
5568 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005569 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02005570 case LYS_ANYDATA:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005571 must_size = ((struct lys_node_anydata *)schema)->must_size;
5572 break;
5573 case LYS_NOTIF:
5574 must_size = ((struct lys_node_notif *)schema)->must_size;
5575 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005576 default:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005577 must_size = 0;
5578 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005579 }
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005580
5581 if (must_size) {
5582 ++ret;
5583 }
5584
5585 /* schema may be a direct data child of input/output with must (but it must be first, it needs to be evaluated only once) */
5586 if (!node->prev->next) {
5587 for (iter = lys_parent(schema); iter && (iter->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES)); iter = lys_parent(iter));
5588 if (iter && (iter->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5589 ret += 0x2;
5590 }
5591 }
5592
5593 return ret;
Radek Krejci01696bf2016-03-18 13:19:36 +01005594}
5595
5596int
Radek Krejci46165822016-08-26 14:06:27 +02005597resolve_applies_when(const struct lys_node *schema, int mode, const struct lys_node *stop)
Radek Krejci03b71f72016-03-16 11:10:09 +01005598{
Radek Krejci46165822016-08-26 14:06:27 +02005599 const struct lys_node *parent;
Radek Krejci03b71f72016-03-16 11:10:09 +01005600
Radek Krejci46165822016-08-26 14:06:27 +02005601 assert(schema);
Radek Krejci03b71f72016-03-16 11:10:09 +01005602
Radek Krejci46165822016-08-26 14:06:27 +02005603 if (!(schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)schema)->when)) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005604 return 1;
5605 }
5606
Radek Krejci46165822016-08-26 14:06:27 +02005607 parent = schema;
Radek Krejci03b71f72016-03-16 11:10:09 +01005608 goto check_augment;
5609
Radek Krejci46165822016-08-26 14:06:27 +02005610 while (parent) {
5611 /* stop conditions */
5612 if (!mode) {
5613 /* stop on node that can be instantiated in data tree */
5614 if (!(parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
5615 break;
5616 }
5617 } else {
5618 /* stop on the specified node */
5619 if (parent == stop) {
5620 break;
5621 }
5622 }
5623
5624 if (((const struct lys_node_uses *)parent)->when) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005625 return 1;
5626 }
5627check_augment:
5628
5629 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) &&
Radek Krejci46165822016-08-26 14:06:27 +02005630 (((const struct lys_node_augment *)parent->parent)->when))) {
Michal Vaskoe3655562016-08-24 15:56:17 +02005631 return 1;
Radek Krejci03b71f72016-03-16 11:10:09 +01005632 }
5633 parent = lys_parent(parent);
5634 }
5635
5636 return 0;
5637}
5638
Michal Vaskocf024702015-10-08 15:01:42 +02005639/**
5640 * @brief Resolve (check) all when conditions relevant for \p node.
5641 * Logs directly.
5642 *
5643 * @param[in] node Data node, whose conditional reference, if such, is being decided.
Michal Vaskocf024702015-10-08 15:01:42 +02005644 *
Radek Krejci03b71f72016-03-16 11:10:09 +01005645 * @return
5646 * -1 - error, ly_errno is set
5647 * 0 - true "when" statement
Radek Krejci46165822016-08-26 14:06:27 +02005648 * 0, ly_vecode = LYVE_NOWHEN - false "when" statement
Radek Krejci03b71f72016-03-16 11:10:09 +01005649 * 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 +02005650 */
Radek Krejci46165822016-08-26 14:06:27 +02005651int
5652resolve_when(struct lyd_node *node, int *result)
Michal Vaskocf024702015-10-08 15:01:42 +02005653{
Michal Vasko76c3bd32016-08-24 16:02:52 +02005654 struct lyd_node *ctx_node = NULL, *unlinked_nodes, *tmp_node;
Michal Vasko90fc2a32016-08-24 15:58:58 +02005655 struct lys_node *sparent;
Michal Vaskocf024702015-10-08 15:01:42 +02005656 struct lyxp_set set;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005657 enum lyxp_node_type ctx_node_type;
Radek Krejci51093642016-03-29 10:14:59 +02005658 int rc = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02005659
5660 assert(node);
5661 memset(&set, 0, sizeof set);
5662
5663 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)node->schema)->when)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005664 /* make the node dummy for the evaluation */
5665 node->validity |= LYD_VAL_INUSE;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005666 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 +02005667 node->validity &= ~LYD_VAL_INUSE;
Radek Krejci03b71f72016-03-16 11:10:09 +01005668 if (rc) {
5669 if (rc == 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005670 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005671 }
Radek Krejci51093642016-03-29 10:14:59 +02005672 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005673 }
5674
Radek Krejci03b71f72016-03-16 11:10:09 +01005675 /* set boolean result of the condition */
Michal Vasko944a5642016-03-21 11:48:58 +01005676 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02005677 if (!set.val.bool) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005678 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci0b7704f2016-03-18 12:16:14 +01005679 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02005680 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005681 }
Radek Krejci51093642016-03-29 10:14:59 +02005682
5683 /* free xpath set content */
5684 lyxp_set_cast(&set, LYXP_SET_EMPTY, node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005685 }
5686
Michal Vasko90fc2a32016-08-24 15:58:58 +02005687 sparent = node->schema;
Michal Vaskocf024702015-10-08 15:01:42 +02005688 goto check_augment;
5689
5690 /* check when in every schema node that affects node */
Michal Vasko90fc2a32016-08-24 15:58:58 +02005691 while (sparent && (sparent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
5692 if (((struct lys_node_uses *)sparent)->when) {
Michal Vaskocf024702015-10-08 15:01:42 +02005693 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005694 rc = resolve_when_ctx_node(node, sparent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02005695 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02005696 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02005697 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005698 }
5699 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02005700
5701 unlinked_nodes = NULL;
5702 /* we do not want our node pointer to change */
5703 tmp_node = node;
5704 rc = resolve_when_unlink_nodes(sparent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
5705 if (rc) {
5706 goto cleanup;
5707 }
5708
5709 rc = lyxp_eval(((struct lys_node_uses *)sparent)->when->cond, ctx_node, ctx_node_type, &set, LYXP_WHEN);
5710
5711 if (unlinked_nodes && ctx_node) {
5712 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
5713 rc = -1;
5714 goto cleanup;
5715 }
5716 }
5717
Radek Krejci03b71f72016-03-16 11:10:09 +01005718 if (rc) {
5719 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005720 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005721 }
Radek Krejci51093642016-03-29 10:14:59 +02005722 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005723 }
5724
Michal Vasko944a5642016-03-21 11:48:58 +01005725 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02005726 if (!set.val.bool) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005727 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Radek Krejci0b7704f2016-03-18 12:16:14 +01005728 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02005729 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005730 }
Radek Krejci51093642016-03-29 10:14:59 +02005731
5732 /* free xpath set content */
5733 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005734 }
5735
5736check_augment:
Michal Vasko90fc2a32016-08-24 15:58:58 +02005737 if ((sparent->parent && (sparent->parent->nodetype == LYS_AUGMENT) && (((struct lys_node_augment *)sparent->parent)->when))) {
Michal Vaskocf024702015-10-08 15:01:42 +02005738 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005739 rc = resolve_when_ctx_node(node, sparent->parent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02005740 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02005741 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02005742 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005743 }
5744 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02005745
5746 unlinked_nodes = NULL;
5747 tmp_node = node;
5748 rc = resolve_when_unlink_nodes(sparent->parent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
5749 if (rc) {
5750 goto cleanup;
5751 }
5752
5753 rc = lyxp_eval(((struct lys_node_augment *)sparent->parent)->when->cond, ctx_node, ctx_node_type, &set, LYXP_WHEN);
5754
5755 /* reconnect nodes, if ctx_node is NULL then all the nodes were unlinked, but linked together,
5756 * so the tree did not actually change and there is nothing for us to do
5757 */
5758 if (unlinked_nodes && ctx_node) {
5759 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
5760 rc = -1;
5761 goto cleanup;
5762 }
5763 }
5764
Radek Krejci03b71f72016-03-16 11:10:09 +01005765 if (rc) {
5766 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005767 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005768 }
Radek Krejci51093642016-03-29 10:14:59 +02005769 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005770 }
5771
Michal Vasko944a5642016-03-21 11:48:58 +01005772 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, LYXP_WHEN);
Michal Vaskocf024702015-10-08 15:01:42 +02005773
Michal Vasko8146d4c2016-05-09 15:50:29 +02005774 if (!set.val.bool) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005775 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Radek Krejci0b7704f2016-03-18 12:16:14 +01005776 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02005777 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005778 }
Radek Krejci51093642016-03-29 10:14:59 +02005779
5780 /* free xpath set content */
5781 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005782 }
5783
Michal Vasko90fc2a32016-08-24 15:58:58 +02005784 sparent = lys_parent(sparent);
Michal Vaskocf024702015-10-08 15:01:42 +02005785 }
5786
Radek Krejci0b7704f2016-03-18 12:16:14 +01005787 node->when_status |= LYD_WHEN_TRUE;
Radek Krejci03b71f72016-03-16 11:10:09 +01005788
Radek Krejci51093642016-03-29 10:14:59 +02005789cleanup:
Radek Krejci51093642016-03-29 10:14:59 +02005790 /* free xpath set content */
5791 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node ? ctx_node : node, 0);
5792
Radek Krejci46165822016-08-26 14:06:27 +02005793 if (result) {
5794 if (node->when_status & LYD_WHEN_TRUE) {
5795 *result = 1;
5796 } else {
5797 *result = 0;
5798 }
5799 }
5800
Radek Krejci51093642016-03-29 10:14:59 +02005801 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005802}
5803
Radek Krejcicbb473e2016-09-16 14:48:32 +02005804static int
5805check_leafref_features(struct lys_type *type)
5806{
5807 struct lys_node *iter;
5808 struct ly_set *src_parents, *trg_parents, *features;
5809 unsigned int i, j, size, x;
5810 int ret = EXIT_SUCCESS;
5811
5812 assert(type->parent);
5813
5814 src_parents = ly_set_new();
5815 trg_parents = ly_set_new();
5816 features = ly_set_new();
5817
5818 /* get parents chain of source (leafref) */
5819 for (iter = (struct lys_node *)type->parent; iter; iter = iter->parent) {
5820 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
5821 continue;
5822 }
5823 ly_set_add(src_parents, iter, LY_SET_OPT_USEASLIST);
5824 }
5825 /* get parents chain of target */
5826 for (iter = (struct lys_node *)type->info.lref.target; iter; iter = iter->parent) {
5827 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
5828 continue;
5829 }
5830 ly_set_add(trg_parents, iter, LY_SET_OPT_USEASLIST);
5831 }
5832
5833 /* compare the features used in if-feature statements in the rest of both
5834 * chains of parents. The set of features used for target must be a subset
5835 * of features used for the leafref. This is not a perfect, we should compare
5836 * the truth tables but it could require too much resources, so we simplify that */
5837 for (i = 0; i < src_parents->number; i++) {
5838 iter = src_parents->set.s[i]; /* shortcut */
5839 if (!iter->iffeature_size) {
5840 continue;
5841 }
5842 for (j = 0; j < iter->iffeature_size; j++) {
5843 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
5844 for (; size; size--) {
5845 if (!iter->iffeature[j].features[size - 1]) {
5846 /* not yet resolved feature, postpone this check */
5847 ret = EXIT_FAILURE;
5848 goto cleanup;
5849 }
5850 ly_set_add(features, iter->iffeature[j].features[size - 1], 0);
5851 }
5852 }
5853 }
5854 x = features->number;
5855 for (i = 0; i < trg_parents->number; i++) {
5856 iter = trg_parents->set.s[i]; /* shortcut */
5857 if (!iter->iffeature_size) {
5858 continue;
5859 }
5860 for (j = 0; j < iter->iffeature_size; j++) {
5861 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
5862 for (; size; size--) {
5863 if (!iter->iffeature[j].features[size - 1]) {
5864 /* not yet resolved feature, postpone this check */
5865 ret = EXIT_FAILURE;
5866 goto cleanup;
5867 }
5868 if ((unsigned int)ly_set_add(features, iter->iffeature[j].features[size - 1], 0) >= x) {
5869 /* the feature is not present in features set of target's parents chain */
5870 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, type->parent, "leafref", type->info.lref.path);
5871 LOGVAL(LYE_SPEC, LY_VLOG_LYS, type->parent,
5872 "Leafref is not conditional based on \"%s\" feature as its target.",
5873 iter->iffeature[j].features[size - 1]->name);
5874 ret = -1;
5875 goto cleanup;
5876 }
5877 }
5878 }
5879 }
5880
5881cleanup:
5882 ly_set_free(features);
5883 ly_set_free(src_parents);
5884 ly_set_free(trg_parents);
5885
5886 return ret;
5887}
5888
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005889/**
Michal Vaskobb211122015-08-19 14:03:11 +02005890 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005891 *
5892 * @param[in] mod Main module.
5893 * @param[in] item Item to resolve. Type determined by \p type.
5894 * @param[in] type Type of the unresolved item.
5895 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02005896 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005897 *
5898 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
5899 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005900static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02005901resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Radek Krejci48464ed2016-03-17 15:44:09 +01005902 struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005903{
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005904 /* has_str - whether the str_snode is a string in a dictionary that needs to be freed */
Radek Krejcic79c6b12016-07-26 15:11:49 +02005905 int rc = -1, has_str = 0, tpdf_flag = 0, i, k;
5906 unsigned int j;
Radek Krejcic13db382016-08-16 10:52:42 +02005907 struct lys_node *node, *par_grp;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005908 const char *expr;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005909
Radek Krejcic79c6b12016-07-26 15:11:49 +02005910 struct ly_set *refs, *procs;
5911 struct lys_feature *ref, *feat;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005912 struct lys_ident *ident;
5913 struct lys_type *stype;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005914 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01005915 struct lyxml_elem *yin;
Pavol Vicana0e4e672016-02-24 12:20:04 +01005916 struct yang_type *yang;
Radek Krejcid09d1a52016-08-11 14:05:45 +02005917 struct unres_list_uniq *unique_info;
Radek Krejcicbb473e2016-09-16 14:48:32 +02005918 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005919
5920 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005921 case UNRES_IDENT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005922 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01005923 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005924 ident = item;
5925
Radek Krejci018f1f52016-08-03 16:01:20 +02005926 rc = resolve_base_ident(mod, ident, expr, "identity", NULL, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005927 break;
5928 case UNRES_TYPE_IDENTREF:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005929 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01005930 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005931 stype = item;
5932
Radek Krejci018f1f52016-08-03 16:01:20 +02005933 rc = resolve_base_ident(mod, NULL, expr, "type", stype, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005934 break;
5935 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02005936 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005937 stype = item;
5938
Radek Krejci2f12f852016-01-08 12:59:57 +01005939 /* HACK - when there is no parent, we are in top level typedef and in that
5940 * case, the path has to contain absolute path, so we let the resolve_path_arg_schema()
5941 * know it via tpdf_flag */
5942 if (!node) {
Radek Krejci4f78b532016-02-17 13:43:00 +01005943 tpdf_flag = 1;
Radek Krejci2f12f852016-01-08 12:59:57 +01005944 node = (struct lys_node *)stype->parent;
5945 }
5946
Radek Krejci27fe55e2016-09-13 17:13:35 +02005947 if (!lys_node_module(node)->implemented) {
5948 /* not implemented module, don't bother with resolving the leafref
5949 * if the module is set to be implemented, tha path will be resolved then */
5950 rc = 0;
5951 break;
5952 }
Radek Krejci48464ed2016-03-17 15:44:09 +01005953 rc = resolve_path_arg_schema(stype->info.lref.path, node, tpdf_flag,
Michal Vasko1e62a092015-12-01 12:27:20 +01005954 (const struct lys_node **)&stype->info.lref.target);
Michal Vasko01c6fd22016-05-20 11:43:05 +02005955 if (!tpdf_flag && !rc) {
5956 assert(stype->info.lref.target);
Radek Krejcicbb473e2016-09-16 14:48:32 +02005957 /* check if leafref and its target are under a common if-features */
5958 rc = check_leafref_features(stype);
5959 if (rc) {
5960 break;
5961 }
5962
Radek Krejci46c4cd72016-01-21 15:13:52 +01005963 /* store the backlink from leafref target */
Michal Vasko01c6fd22016-05-20 11:43:05 +02005964 if (lys_leaf_add_leafref_target(stype->info.lref.target, (struct lys_node *)stype->parent)) {
5965 rc = -1;
Radek Krejci46c4cd72016-01-21 15:13:52 +01005966 }
Radek Krejci46c4cd72016-01-21 15:13:52 +01005967 }
5968
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005969 break;
Radek Krejci3a5501d2016-07-18 22:03:34 +02005970 case UNRES_TYPE_DER_TPDF:
5971 tpdf_flag = 1;
5972 /* no break */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005973 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01005974 /* parent */
5975 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005976 stype = item;
5977
Michal Vasko88c29542015-11-27 14:57:53 +01005978 /* HACK type->der is temporarily unparsed type statement */
5979 yin = (struct lyxml_elem *)stype->der;
5980 stype->der = NULL;
5981
Pavol Vicana0e4e672016-02-24 12:20:04 +01005982 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
5983 yang = (struct yang_type *)yin;
Radek Krejci3a5501d2016-07-18 22:03:34 +02005984 rc = yang_check_type(mod, node, yang, tpdf_flag, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01005985
5986 if (rc) {
Pavol Vican8bd72e42016-08-29 09:53:05 +02005987 /* may try again later */
5988 stype->der = (struct lys_tpdf *)yang;
Pavol Vicand01d8ae2016-03-01 10:45:59 +01005989 } else {
5990 /* we need to always be able to free this, it's safe only in this case */
Pavol Vican5f0316a2016-04-05 21:21:11 +02005991 lydict_remove(mod->ctx, yang->name);
Pavol Vicand01d8ae2016-03-01 10:45:59 +01005992 free(yang);
Pavol Vicana0e4e672016-02-24 12:20:04 +01005993 }
5994
Michal Vasko88c29542015-11-27 14:57:53 +01005995 } else {
Radek Krejci3a5501d2016-07-18 22:03:34 +02005996 rc = fill_yin_type(mod, node, yin, stype, tpdf_flag, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01005997 if (!rc) {
5998 /* we need to always be able to free this, it's safe only in this case */
5999 lyxml_free(mod->ctx, yin);
6000 } else {
6001 /* may try again later, put all back how it was */
6002 stype->der = (struct lys_tpdf *)yin;
6003 }
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006004 }
Radek Krejcic13db382016-08-16 10:52:42 +02006005 if (rc == EXIT_SUCCESS) {
Radek Krejci2c2fce82016-08-01 13:52:26 +02006006 /* it does not make sense to have leaf-list of empty type */
6007 if (!tpdf_flag && node->nodetype == LYS_LEAFLIST && stype->base == LY_TYPE_EMPTY) {
6008 LOGWRN("The leaf-list \"%s\" is of \"empty\" type, which does not make sense.", node->name);
6009 }
Radek Krejci9b6aad22016-09-20 15:55:51 +02006010 } else if (rc == EXIT_FAILURE && stype->base != LY_TYPE_ERR) {
Radek Krejcic13db382016-08-16 10:52:42 +02006011 /* forward reference - in case the type is in grouping, we have to make the grouping unusable
6012 * by uses statement until the type is resolved. We do that the same way as uses statements inside
6013 * grouping - the grouping's nacm member (not used un grouping) is used to increase the number of
6014 * 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 +02006015 * 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 +02006016 * of the type's base member. */
6017 for (par_grp = node; par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
6018 if (par_grp) {
6019 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci9b6aad22016-09-20 15:55:51 +02006020 stype->base = LY_TYPE_ERR;
Radek Krejcic13db382016-08-16 10:52:42 +02006021 }
Radek Krejci2c2fce82016-08-01 13:52:26 +02006022 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006023 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006024 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006025 iff_data = str_snode;
6026 rc = resolve_feature(iff_data->fname, strlen(iff_data->fname), iff_data->node, item);
Radek Krejci9ff0a922016-07-14 13:08:05 +02006027 if (!rc) {
6028 /* success */
Radek Krejcicbb473e2016-09-16 14:48:32 +02006029 lydict_remove(mod->ctx, iff_data->fname);
6030 free(iff_data);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006031 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006032 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006033 case UNRES_FEATURE:
6034 feat = (struct lys_feature *)item;
6035
6036 if (feat->iffeature_size) {
6037 refs = ly_set_new();
6038 procs = ly_set_new();
6039 ly_set_add(procs, feat, 0);
6040
6041 while (procs->number) {
6042 ref = procs->set.g[procs->number - 1];
6043 ly_set_rm_index(procs, procs->number - 1);
6044
6045 for (i = 0; i < ref->iffeature_size; i++) {
6046 resolve_iffeature_getsizes(&ref->iffeature[i], NULL, &j);
6047 for (; j > 0 ; j--) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006048 if (ref->iffeature[i].features[j - 1]) {
Radek Krejcic79c6b12016-07-26 15:11:49 +02006049 if (ref->iffeature[i].features[j - 1] == feat) {
6050 LOGVAL(LYE_CIRC_FEATURES, LY_VLOG_NONE, NULL, feat->name);
6051 goto featurecheckdone;
6052 }
6053
6054 if (ref->iffeature[i].features[j - 1]->iffeature_size) {
6055 k = refs->number;
6056 if (ly_set_add(refs, ref->iffeature[i].features[j - 1], 0) == k) {
6057 /* not yet seen feature, add it for processing */
6058 ly_set_add(procs, ref->iffeature[i].features[j - 1], 0);
6059 }
6060 }
6061 } else {
6062 /* forward reference */
6063 rc = EXIT_FAILURE;
6064 goto featurecheckdone;
6065 }
6066 }
6067
6068 }
6069 }
6070 rc = EXIT_SUCCESS;
6071
6072featurecheckdone:
6073 ly_set_free(refs);
6074 ly_set_free(procs);
6075 }
6076
6077 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006078 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006079 rc = resolve_unres_schema_uses(item, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006080 break;
6081 case UNRES_TYPE_DFLT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006082 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006083 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006084 stype = item;
6085
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006086 rc = check_default(stype, expr, mod);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006087 break;
6088 case UNRES_CHOICE_DFLT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006089 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006090 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006091 choic = item;
6092
Radek Krejcie00d2312016-08-12 15:27:49 +02006093 if (!choic->dflt) {
6094 choic->dflt = resolve_choice_dflt(choic, expr);
6095 }
Michal Vasko7955b362015-09-04 14:18:15 +02006096 if (choic->dflt) {
Radek Krejcie00d2312016-08-12 15:27:49 +02006097 rc = lyp_check_mandatory_choice((struct lys_node *)choic);
Michal Vasko7955b362015-09-04 14:18:15 +02006098 } else {
6099 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006100 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006101 break;
6102 case UNRES_LIST_KEYS:
Radek Krejci4f78b532016-02-17 13:43:00 +01006103 has_str = 1;
Radek Krejci48464ed2016-03-17 15:44:09 +01006104 rc = resolve_list_keys(item, str_snode);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006105 break;
6106 case UNRES_LIST_UNIQ:
Radek Krejcid09d1a52016-08-11 14:05:45 +02006107 unique_info = (struct unres_list_uniq *)item;
6108 rc = resolve_unique(unique_info->list, unique_info->expr, unique_info->trg_type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006109 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006110 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006111 rc = resolve_augment(item, NULL);
Michal Vasko7178e692016-02-12 15:58:05 +01006112 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006113 case UNRES_XPATH:
6114 node = (struct lys_node *)item;
Michal Vasko9e635ac2016-10-17 11:44:09 +02006115 rc = check_node_xpath(node);
Michal Vasko508a50d2016-09-07 14:50:33 +02006116 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006117 default:
6118 LOGINT;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006119 break;
6120 }
6121
Radek Krejci54081ce2016-08-12 15:21:47 +02006122 if (has_str && !rc) {
6123 /* the string is no more needed in case of success.
6124 * In case of forward reference, we will try to resolve the string later */
Radek Krejci4f78b532016-02-17 13:43:00 +01006125 lydict_remove(mod->ctx, str_snode);
6126 }
6127
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006128 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006129}
6130
Michal Vaskof02e3742015-08-05 16:27:02 +02006131/* logs directly */
6132static void
Radek Krejci48464ed2016-03-17 15:44:09 +01006133print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006134{
Michal Vaskocb34dc62016-05-20 14:38:37 +02006135 struct lyxml_elem *xml;
6136 struct lyxml_attr *attr;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006137 struct unres_iffeat_data *iff_data;
Radek Krejci76e15e12016-06-22 11:02:24 +02006138 const char *type_name = NULL;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006139
Michal Vaskof02e3742015-08-05 16:27:02 +02006140 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02006141 case UNRES_IDENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006142 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identity", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006143 break;
6144 case UNRES_TYPE_IDENTREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006145 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identityref", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006146 break;
6147 case UNRES_TYPE_LEAFREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006148 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "leafref",
6149 ((struct lys_type *)item)->info.lref.path);
Michal Vaskof02e3742015-08-05 16:27:02 +02006150 break;
Radek Krejci3a5501d2016-07-18 22:03:34 +02006151 case UNRES_TYPE_DER_TPDF:
Michal Vaskof02e3742015-08-05 16:27:02 +02006152 case UNRES_TYPE_DER:
Michal Vaskocb34dc62016-05-20 14:38:37 +02006153 xml = (struct lyxml_elem *)((struct lys_type *)item)->der;
6154 if (xml->flags & LY_YANG_STRUCTURE_FLAG) {
6155 type_name = ((struct yang_type *)xml)->name;
6156 } else {
6157 LY_TREE_FOR(xml->attr, attr) {
6158 if ((attr->type == LYXML_ATTR_STD) && !strcmp(attr->name, "name")) {
6159 type_name = attr->value;
6160 break;
6161 }
6162 }
6163 assert(attr);
6164 }
6165 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "derived type", type_name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006166 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006167 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006168 iff_data = str_node;
6169 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "if-feature", iff_data->fname);
Michal Vaskof02e3742015-08-05 16:27:02 +02006170 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006171 case UNRES_FEATURE:
6172 LOGVRB("There are unresolved if-features for \"%s\" feature circular dependency check, it will be attempted later",
6173 ((struct lys_feature *)item)->name);
6174 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006175 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006176 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "uses", ((struct lys_node_uses *)item)->name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006177 break;
6178 case UNRES_TYPE_DFLT:
Radek Krejci2e2de832016-10-13 16:12:26 +02006179 if (str_node) {
6180 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "type default", (char *)str_node);
6181 } /* else no default value in the type itself, but we are checking some restrictions against
6182 * possible default value of some base type. The failure is caused by not resolved base type,
6183 * so it was already reported */
Michal Vaskof02e3742015-08-05 16:27:02 +02006184 break;
6185 case UNRES_CHOICE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006186 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "choice default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006187 break;
6188 case UNRES_LIST_KEYS:
Radek Krejci48464ed2016-03-17 15:44:09 +01006189 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list keys", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006190 break;
6191 case UNRES_LIST_UNIQ:
Radek Krejci48464ed2016-03-17 15:44:09 +01006192 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list unique", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006193 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006194 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006195 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "augment target",
6196 ((struct lys_node_augment *)item)->target_name);
Michal Vasko7178e692016-02-12 15:58:05 +01006197 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006198 case UNRES_XPATH:
6199 LOGVRB("Resolving %s \"%s\" with the context node \"%s\" failed, it will be attempted later.", "XPath",
6200 (char *)str_node, ((struct lys_node *)item)->name);
6201 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006202 default:
6203 LOGINT;
Michal Vaskof02e3742015-08-05 16:27:02 +02006204 break;
6205 }
6206}
6207
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006208/**
Michal Vaskobb211122015-08-19 14:03:11 +02006209 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006210 *
6211 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006212 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006213 *
Michal Vasko92b8a382015-08-19 14:03:49 +02006214 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006215 */
Michal Vaskof02e3742015-08-05 16:27:02 +02006216int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006217resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02006218{
Radek Krejci010e54b2016-03-15 09:40:34 +01006219 uint32_t i, resolved = 0, unres_count, res_count;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006220 int rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006221
6222 assert(unres);
6223
Michal Vaskoe8734262016-09-29 14:12:06 +02006224 LOGVRB("Resolving \"%s\" unresolved schema nodes and their constraints...", mod->name);
Radek Krejci010e54b2016-03-15 09:40:34 +01006225 ly_vlog_hide(1);
Michal Vasko51054ca2015-08-12 12:20:00 +02006226
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006227 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02006228 do {
Michal Vasko88c29542015-11-27 14:57:53 +01006229 unres_count = 0;
6230 res_count = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02006231
6232 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006233 /* UNRES_TYPE_LEAFREF must be resolved (for storing leafref target pointers);
Radek Krejcic79c6b12016-07-26 15:11:49 +02006234 * if-features are resolved here to make sure that we will have all if-features for
6235 * later check of feature circular dependency */
Radek Krejci018f1f52016-08-03 16:01:20 +02006236 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006237 continue;
6238 }
Radek Krejci018f1f52016-08-03 16:01:20 +02006239 /* processes UNRES_USES, UNRES_IFFEAT, UNRES_TYPE_DER, UNRES_TYPE_DER_TPDF, UNRES_TYPE_LEAFREF,
Radek Krejcie00d2312016-08-12 15:27:49 +02006240 * UNRES_CHOICE_DFLT and UNRES_IDENT */
Michal Vasko51054ca2015-08-12 12:20:00 +02006241
Michal Vasko88c29542015-11-27 14:57:53 +01006242 ++unres_count;
Radek Krejci48464ed2016-03-17 15:44:09 +01006243 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006244 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006245 unres->type[i] = UNRES_RESOLVED;
6246 ++resolved;
Michal Vasko88c29542015-11-27 14:57:53 +01006247 ++res_count;
Michal Vasko89e15322015-08-17 15:46:55 +02006248 } else if (rc == -1) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006249 ly_vlog_hide(0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02006250 /* print the error */
6251 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006252 return -1;
Radek Krejcic2a180f2016-06-22 13:28:16 +02006253 } else {
6254 /* forward reference, erase ly_errno */
6255 ly_errno = LY_SUCCESS;
6256 ly_vecode = LYVE_SUCCESS;
Michal Vasko51054ca2015-08-12 12:20:00 +02006257 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006258 }
Michal Vasko88c29542015-11-27 14:57:53 +01006259 } while (res_count && (res_count < unres_count));
Michal Vasko51054ca2015-08-12 12:20:00 +02006260
Michal Vasko88c29542015-11-27 14:57:53 +01006261 if (res_count < unres_count) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006262 /* just print the errors */
6263 ly_vlog_hide(0);
6264
6265 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006266 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006267 continue;
6268 }
6269 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
6270 }
Michal Vasko92b8a382015-08-19 14:03:49 +02006271 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006272 }
6273
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006274 /* the rest */
6275 for (i = 0; i < unres->count; ++i) {
6276 if (unres->type[i] == UNRES_RESOLVED) {
6277 continue;
6278 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02006279
Radek Krejci48464ed2016-03-17 15:44:09 +01006280 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01006281 if (rc == 0) {
Pavol Vican88e16c92016-09-07 15:41:50 +02006282 if (unres->type[i] == UNRES_LIST_UNIQ) {
6283 /* free the allocated structure */
6284 free(unres->item[i]);
6285 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006286 unres->type[i] = UNRES_RESOLVED;
6287 ++resolved;
6288 } else if (rc == -1) {
6289 ly_vlog_hide(0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02006290 /* print the error */
6291 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
6292 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006293 }
6294 }
6295
Radek Krejci010e54b2016-03-15 09:40:34 +01006296 ly_vlog_hide(0);
6297
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006298 if (resolved < unres->count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006299 /* try to resolve the unresolved nodes again, it will not resolve anything, but it will print
6300 * all the validation errors
6301 */
6302 for (i = 0; i < unres->count; ++i) {
6303 if (unres->type[i] == UNRES_RESOLVED) {
6304 continue;
6305 }
Radek Krejci48464ed2016-03-17 15:44:09 +01006306 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01006307 }
Michal Vasko92b8a382015-08-19 14:03:49 +02006308 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006309 }
6310
Michal Vaskoe8734262016-09-29 14:12:06 +02006311 LOGVRB("All \"%s\" schema nodes and constraints resolved.", mod->name);
Radek Krejcic071c542016-01-27 14:57:51 +01006312 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006313 return EXIT_SUCCESS;
6314}
6315
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006316/**
Michal Vaskobb211122015-08-19 14:03:11 +02006317 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006318 *
6319 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006320 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006321 * @param[in] item Item to resolve. Type determined by \p type.
6322 * @param[in] type Type of the unresolved item.
6323 * @param[in] str String argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006324 *
Michal Vasko3767fb22016-07-21 12:10:57 +02006325 * @return EXIT_SUCCESS on success, EXIT_FAILURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006326 */
6327int
Radek Krejci48464ed2016-03-17 15:44:09 +01006328unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
6329 const char *str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006330{
Radek Krejci54081ce2016-08-12 15:21:47 +02006331 int rc;
6332 const char *dictstr;
6333
6334 dictstr = lydict_insert(mod->ctx, str, 0);
6335 rc = unres_schema_add_node(mod, unres, item, type, (struct lys_node *)dictstr);
6336
6337 if (rc == -1) {
6338 lydict_remove(mod->ctx, dictstr);
6339 }
6340 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006341}
6342
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006343/**
Michal Vaskobb211122015-08-19 14:03:11 +02006344 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006345 *
6346 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006347 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006348 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01006349 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006350 * @param[in] snode Schema node argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006351 *
Michal Vasko3767fb22016-07-21 12:10:57 +02006352 * @return EXIT_SUCCESS on success, EXIT_FIALURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006353 */
6354int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006355unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Radek Krejci48464ed2016-03-17 15:44:09 +01006356 struct lys_node *snode)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006357{
Michal Vaskoef486d72016-09-27 12:10:44 +02006358 int rc, log_hidden;
Michal Vasko88c29542015-11-27 14:57:53 +01006359 struct lyxml_elem *yin;
Radek Krejci010e54b2016-03-15 09:40:34 +01006360 char *path, *msg;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006361
Michal Vasko9bf425b2015-10-22 11:42:03 +02006362 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
6363 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006364
Michal Vaskoef486d72016-09-27 12:10:44 +02006365 if (*ly_vlog_hide_location()) {
6366 log_hidden = 1;
6367 } else {
6368 log_hidden = 0;
6369 ly_vlog_hide(1);
6370 }
Radek Krejci48464ed2016-03-17 15:44:09 +01006371 rc = resolve_unres_schema_item(mod, item, type, snode, unres);
Michal Vaskoef486d72016-09-27 12:10:44 +02006372 if (!log_hidden) {
6373 ly_vlog_hide(0);
6374 }
6375
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006376 if (rc != EXIT_FAILURE) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006377 if (rc == -1 && ly_errno == LY_EVALID) {
Radek Krejci76e15e12016-06-22 11:02:24 +02006378 if (ly_log_level >= LY_LLERR) {
6379 path = strdup(ly_errpath());
6380 msg = strdup(ly_errmsg());
6381 LOGERR(LY_EVALID, "%s%s%s%s", msg, path[0] ? " (path: " : "", path[0] ? path : "", path[0] ? ")" : "");
6382 free(path);
6383 free(msg);
6384 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006385 }
Radek Krejcid09d1a52016-08-11 14:05:45 +02006386 if (type == UNRES_LIST_UNIQ) {
6387 /* free the allocated structure */
6388 free(item);
Pavol Vican88e16c92016-09-07 15:41:50 +02006389 } else if (rc == -1 && type == UNRES_IFFEAT) {
6390 /* free the allocated resources */
6391 free(*((char **)item));
6392 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006393 return rc;
Radek Krejcif347abc2016-06-22 10:18:47 +02006394 } else {
6395 /* erase info about validation errors */
6396 ly_errno = LY_SUCCESS;
6397 ly_vecode = LYVE_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006398 }
6399
Radek Krejci48464ed2016-03-17 15:44:09 +01006400 print_unres_schema_item_fail(item, type, snode);
Michal Vaskof02e3742015-08-05 16:27:02 +02006401
Michal Vasko88c29542015-11-27 14:57:53 +01006402 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
Radek Krejci3a5501d2016-07-18 22:03:34 +02006403 if (type == UNRES_TYPE_DER || type == UNRES_TYPE_DER_TPDF) {
Michal Vasko88c29542015-11-27 14:57:53 +01006404 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
Pavol Vicana0e4e672016-02-24 12:20:04 +01006405 if (!(yin->flags & LY_YANG_STRUCTURE_FLAG)) {
6406 lyxml_unlink_elem(mod->ctx, yin, 1);
6407 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
6408 }
Michal Vasko88c29542015-11-27 14:57:53 +01006409 }
6410
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006411 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01006412 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
6413 if (!unres->item) {
6414 LOGMEM;
6415 return -1;
6416 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006417 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01006418 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
6419 if (!unres->type) {
6420 LOGMEM;
6421 return -1;
6422 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006423 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01006424 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
6425 if (!unres->str_snode) {
6426 LOGMEM;
6427 return -1;
6428 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006429 unres->str_snode[unres->count-1] = snode;
Radek Krejcic071c542016-01-27 14:57:51 +01006430 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
6431 if (!unres->module) {
6432 LOGMEM;
6433 return -1;
6434 }
6435 unres->module[unres->count-1] = mod;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006436
Michal Vasko3767fb22016-07-21 12:10:57 +02006437 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006438}
6439
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006440/**
Michal Vaskobb211122015-08-19 14:03:11 +02006441 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006442 *
6443 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006444 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006445 * @param[in] item Old item to be resolved.
6446 * @param[in] type Type of the old unresolved item.
6447 * @param[in] new_item New item to use in the duplicate.
6448 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02006449 * @return EXIT_SUCCESS on success, EXIT_FAILURE if item is not in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006450 */
Michal Vaskodad19402015-08-06 09:51:53 +02006451int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006452unres_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 +02006453{
6454 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006455 struct unres_list_uniq aux_uniq;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006456 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006457
Michal Vaskocf024702015-10-08 15:01:42 +02006458 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006459
Radek Krejcid09d1a52016-08-11 14:05:45 +02006460 /* hack for UNRES_LIST_UNIQ, which stores multiple items behind its item */
6461 if (type == UNRES_LIST_UNIQ) {
6462 aux_uniq.list = item;
6463 aux_uniq.expr = ((struct unres_list_uniq *)new_item)->expr;
6464 item = &aux_uniq;
6465 }
Michal Vasko878e38d2016-09-05 12:17:53 +02006466 i = unres_schema_find(unres, -1, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006467
6468 if (i == -1) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006469 if (type == UNRES_LIST_UNIQ) {
6470 free(new_item);
6471 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02006472 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006473 }
6474
Radek Krejcic79c6b12016-07-26 15:11:49 +02006475 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT) ||
Radek Krejcib69f3232016-09-16 17:41:07 +02006476 (type == UNRES_FEATURE) || (type == UNRES_LIST_UNIQ)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01006477 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006478 LOGINT;
6479 return -1;
6480 }
Radek Krejcicbb473e2016-09-16 14:48:32 +02006481 } else if (type == UNRES_IFFEAT) {
6482 /* duplicate unres_iffeature_data */
6483 iff_data = malloc(sizeof *iff_data);
6484 iff_data->fname = lydict_insert(mod->ctx, ((struct unres_iffeat_data *)unres->str_snode[i])->fname, 0);
6485 iff_data->node = ((struct unres_iffeat_data *)unres->str_snode[i])->node;
6486 if (unres_schema_add_node(mod, unres, new_item, type, (struct lys_node *)iff_data) == -1) {
6487 LOGINT;
6488 return -1;
6489 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006490 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01006491 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006492 LOGINT;
6493 return -1;
6494 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006495 }
Michal Vaskodad19402015-08-06 09:51:53 +02006496
6497 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006498}
6499
Michal Vaskof02e3742015-08-05 16:27:02 +02006500/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006501int
Michal Vasko878e38d2016-09-05 12:17:53 +02006502unres_schema_find(struct unres_schema *unres, int start_on_backwards, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006503{
Michal Vasko878e38d2016-09-05 12:17:53 +02006504 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006505 struct unres_list_uniq *aux_uniq1, *aux_uniq2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006506
Michal Vasko878e38d2016-09-05 12:17:53 +02006507 if (start_on_backwards > 0) {
6508 i = start_on_backwards;
6509 } else {
6510 i = unres->count - 1;
6511 }
6512 for (; i > -1; i--) {
6513 if (unres->type[i] != type) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006514 continue;
6515 }
6516 if (type != UNRES_LIST_UNIQ) {
Michal Vasko878e38d2016-09-05 12:17:53 +02006517 if (unres->item[i] == item) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006518 break;
6519 }
6520 } else {
6521 aux_uniq1 = (struct unres_list_uniq *)unres->item[i - 1];
6522 aux_uniq2 = (struct unres_list_uniq *)item;
6523 if ((aux_uniq1->list == aux_uniq2->list) && ly_strequal(aux_uniq1->expr, aux_uniq2->expr, 0)) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006524 break;
6525 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006526 }
6527 }
6528
Michal Vasko878e38d2016-09-05 12:17:53 +02006529 return i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006530}
Michal Vasko8bcdf292015-08-19 14:04:43 +02006531
Michal Vaskoede9c472016-06-07 09:38:15 +02006532static void
6533unres_schema_free_item(struct ly_ctx *ctx, struct unres_schema *unres, uint32_t i)
6534{
6535 struct lyxml_elem *yin;
6536 struct yang_type *yang;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006537 struct unres_iffeat_data *iff_data;
Michal Vaskoede9c472016-06-07 09:38:15 +02006538
6539 switch (unres->type[i]) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02006540 case UNRES_TYPE_DER_TPDF:
Michal Vaskoede9c472016-06-07 09:38:15 +02006541 case UNRES_TYPE_DER:
6542 yin = (struct lyxml_elem *)((struct lys_type *)unres->item[i])->der;
6543 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6544 yang =(struct yang_type *)yin;
6545 yang->type->base = yang->base;
6546 lydict_remove(ctx, yang->name);
6547 free(yang);
6548 } else {
6549 lyxml_free(ctx, yin);
6550 }
6551 break;
Pavol Vican88e16c92016-09-07 15:41:50 +02006552 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006553 iff_data = (struct unres_iffeat_data *)unres->str_snode[i];
6554 lydict_remove(ctx, iff_data->fname);
6555 free(unres->str_snode[i]);
Pavol Vican88e16c92016-09-07 15:41:50 +02006556 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02006557 case UNRES_IDENT:
6558 case UNRES_TYPE_IDENTREF:
Michal Vaskoede9c472016-06-07 09:38:15 +02006559 case UNRES_TYPE_DFLT:
6560 case UNRES_CHOICE_DFLT:
6561 case UNRES_LIST_KEYS:
Michal Vaskoede9c472016-06-07 09:38:15 +02006562 lydict_remove(ctx, (const char *)unres->str_snode[i]);
6563 break;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006564 case UNRES_LIST_UNIQ:
6565 free(unres->item[i]);
6566 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02006567 default:
6568 break;
6569 }
6570 unres->type[i] = UNRES_RESOLVED;
6571}
6572
Michal Vasko88c29542015-11-27 14:57:53 +01006573void
Radek Krejcic071c542016-01-27 14:57:51 +01006574unres_schema_free(struct lys_module *module, struct unres_schema **unres)
Michal Vasko88c29542015-11-27 14:57:53 +01006575{
6576 uint32_t i;
Radek Krejcic071c542016-01-27 14:57:51 +01006577 unsigned int unresolved = 0;
Michal Vasko88c29542015-11-27 14:57:53 +01006578
Radek Krejcic071c542016-01-27 14:57:51 +01006579 if (!unres || !(*unres)) {
6580 return;
Michal Vasko88c29542015-11-27 14:57:53 +01006581 }
6582
Radek Krejcic071c542016-01-27 14:57:51 +01006583 assert(module || (*unres)->count == 0);
6584
6585 for (i = 0; i < (*unres)->count; ++i) {
6586 if ((*unres)->module[i] != module) {
6587 if ((*unres)->type[i] != UNRES_RESOLVED) {
6588 unresolved++;
6589 }
6590 continue;
6591 }
Michal Vaskoede9c472016-06-07 09:38:15 +02006592
6593 /* free heap memory for the specific item */
6594 unres_schema_free_item(module->ctx, *unres, i);
Radek Krejcic071c542016-01-27 14:57:51 +01006595 }
6596
Michal Vaskoede9c472016-06-07 09:38:15 +02006597 /* free it all */
Radek Krejcic071c542016-01-27 14:57:51 +01006598 if (!module || (!unresolved && !module->type)) {
6599 free((*unres)->item);
6600 free((*unres)->type);
6601 free((*unres)->str_snode);
6602 free((*unres)->module);
Radek Krejcic071c542016-01-27 14:57:51 +01006603 free((*unres));
6604 (*unres) = NULL;
6605 }
Michal Vasko88c29542015-11-27 14:57:53 +01006606}
6607
Radek Krejci7de36cf2016-09-12 16:18:50 +02006608static int
Radek Krejci9b6aad22016-09-20 15:55:51 +02006609resolve_leafref(struct lyd_node_leaf_list *leaf, struct lys_type *type)
Radek Krejci7de36cf2016-09-12 16:18:50 +02006610{
Radek Krejci7de36cf2016-09-12 16:18:50 +02006611 struct unres_data matches;
6612 uint32_t i;
6613
Radek Krejci9b6aad22016-09-20 15:55:51 +02006614 assert(type->base == LY_TYPE_LEAFREF);
6615
6616 /* init */
Radek Krejci7de36cf2016-09-12 16:18:50 +02006617 memset(&matches, 0, sizeof matches);
Radek Krejci7de36cf2016-09-12 16:18:50 +02006618
6619 /* EXIT_FAILURE return keeps leaf->value.lefref NULL, handled later */
Radek Krejci9b6aad22016-09-20 15:55:51 +02006620 if (resolve_path_arg_data((struct lyd_node *)leaf, type->info.lref.path, &matches) == -1) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02006621 return -1;
6622 }
6623
6624 /* check that value matches */
6625 for (i = 0; i < matches.count; ++i) {
6626 if (ly_strequal(leaf->value_str, ((struct lyd_node_leaf_list *)matches.node[i])->value_str, 1)) {
6627 leaf->value.leafref = matches.node[i];
6628 break;
6629 }
6630 }
6631
6632 free(matches.node);
6633
6634 if (!leaf->value.leafref) {
6635 /* reference not found */
6636 if (type->info.lref.req > -1) {
6637 LOGVAL(LYE_NOLEAFREF, LY_VLOG_LYD, leaf, type->info.lref.path, leaf->value_str);
6638 return EXIT_FAILURE;
6639 } else {
6640 LOGVRB("There is no leafref with the value \"%s\", but it is not required.", leaf->value_str);
6641 }
6642 }
6643
6644 return EXIT_SUCCESS;
6645}
6646
Radek Krejci9b6aad22016-09-20 15:55:51 +02006647API LY_DATA_TYPE
6648lyd_leaf_type(const struct lyd_node_leaf_list *leaf)
6649{
6650 struct lyd_node *node;
6651 struct lys_type *type, *type_iter;
6652 lyd_val value;
6653 int f = 0, r;
6654
6655 if (!leaf || !(leaf->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
6656 return LY_TYPE_ERR;
6657 }
6658
6659 if (leaf->value_type > 0 && (leaf->value_type & LY_DATA_TYPE_MASK) != LY_TYPE_UNION &&
6660 (leaf->value_type & LY_DATA_TYPE_MASK) != LY_TYPE_LEAFREF) {
6661 /* we can get the type directly from the data node (it was already resolved) */
6662 return leaf->value_type & LY_DATA_TYPE_MASK;
6663 }
6664
6665 /* init */
6666 type = &((struct lys_node_leaf *)leaf->schema)->type;
6667 value = leaf->value;
6668 ly_vlog_hide(1);
6669
6670 /* resolve until we get the real data type */
6671 while (1) {
6672 /* get the correct data type from schema */
6673 switch (type->base) {
6674 case LY_TYPE_LEAFREF:
6675 type = &type->info.lref.target->type;
6676 break; /* continue in while loop */
6677 case LY_TYPE_UNION:
6678 type_iter = NULL;
6679 while ((type_iter = lyp_get_next_union_type(type, type_iter, &f))) {
6680 if (type_iter->base == LY_TYPE_LEAFREF) {
6681 if (type_iter->info.lref.req == -1) {
6682 /* target not required, so it always succeeds */
6683 break;
6684 } else {
6685 /* try to resolve leafref */
6686 memset(&((struct lyd_node_leaf_list *)leaf)->value, 0, sizeof leaf->value);
6687 r = resolve_leafref((struct lyd_node_leaf_list *)leaf, type_iter);
6688 /* revert leaf's content affected by resolve_leafref */
6689 ((struct lyd_node_leaf_list *)leaf)->value = value;
6690 if (!r) {
6691 /* success, we can continue with the leafref type */
6692 break;
6693 }
6694 }
6695 } else if (type_iter->base == LY_TYPE_INST) {
6696 if (type_iter->info.inst.req == -1) {
6697 /* target not required, so it always succeeds */
6698 return LY_TYPE_INST;
6699 } else {
6700 /* try to resolve instance-identifier */
6701 ly_errno = 0;
6702 node = resolve_instid((struct lyd_node *)leaf, leaf->value_str);
6703 if (!ly_errno && node) {
6704 /* the real type is instance-identifier */
6705 return LY_TYPE_INST;
6706 }
6707 }
6708 } else {
Radek Krejcif9837a82016-10-27 10:14:05 +02006709 r = lyp_parse_value_type((struct lyd_node_leaf_list *)leaf, type_iter, NULL, 1);
Radek Krejci9b6aad22016-09-20 15:55:51 +02006710 /* revert leaf's content affected by resolve_leafref */
6711 ((struct lyd_node_leaf_list *)leaf)->value = value;
6712 if (!r) {
6713 /* we have the real type */
6714 return type_iter->base;
6715 }
6716 }
6717 f = 0;
6718 }
6719 /* erase ly_errno and ly_vecode */
6720 ly_errno = LY_SUCCESS;
6721 ly_vecode = LYVE_SUCCESS;
6722
6723 if (!type_iter) {
6724 LOGERR(LY_EINVAL, "Unable to get type from union \"%s\" with no valid type.", type->parent->name)
6725 return LY_TYPE_ERR;
6726 }
6727 type = type_iter;
6728 break;
6729 default:
6730 /* we have the real type */
6731 ly_vlog_hide(0);
6732 return type->base;
6733 }
6734 }
6735
6736 ly_vlog_hide(0);
6737 return LY_TYPE_ERR;
6738}
6739
6740static int
6741resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type)
6742{
6743 struct lys_type *datatype = NULL;
6744 int f = 0;
6745
6746 assert(type->base == LY_TYPE_UNION);
6747
6748 memset(&leaf->value, 0, sizeof leaf->value);
6749 while ((datatype = lyp_get_next_union_type(type, datatype, &f))) {
6750 leaf->value_type = datatype->base;
6751
6752 if (datatype->base == LY_TYPE_LEAFREF) {
6753 /* try to resolve leafref */
6754 if (!resolve_leafref(leaf, datatype)) {
6755 /* success */
6756 break;
6757 }
6758 } else if (datatype->base == LY_TYPE_INST) {
6759 /* try to resolve instance-identifier */
6760 ly_errno = 0;
6761 leaf->value.instance = resolve_instid((struct lyd_node *)leaf, leaf->value_str);
6762 if (!ly_errno && (leaf->value.instance || datatype->info.inst.req == -1)) {
6763 /* success */
6764 break;
6765 }
6766 } else {
Radek Krejcif9837a82016-10-27 10:14:05 +02006767 if (!lyp_parse_value_type(leaf, datatype, NULL, 1)) {
Radek Krejci9b6aad22016-09-20 15:55:51 +02006768 /* success */
6769 break;
6770 }
6771 }
6772 f = 0;
6773 }
6774 /* erase ly_errno and ly_vecode */
6775 ly_errno = LY_SUCCESS;
6776 ly_vecode = LYVE_SUCCESS;
6777
6778 if (!datatype) {
6779 /* failure */
6780 LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, (leaf->value_str ? leaf->value_str : ""), leaf->schema->name);
6781 return EXIT_FAILURE;
6782 }
6783
6784 return EXIT_SUCCESS;
6785}
6786
Michal Vasko8bcdf292015-08-19 14:04:43 +02006787/**
6788 * @brief Resolve a single unres data item. Logs directly.
6789 *
Michal Vaskocf024702015-10-08 15:01:42 +02006790 * @param[in] node Data node to resolve.
Michal Vaskocf024702015-10-08 15:01:42 +02006791 * @param[in] type Type of the unresolved item.
Michal Vasko8bcdf292015-08-19 14:04:43 +02006792 *
6793 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
6794 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02006795int
Radek Krejci48464ed2016-03-17 15:44:09 +01006796resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02006797{
Michal Vasko0491ab32015-08-19 14:28:29 +02006798 int rc;
Michal Vasko83a6c462015-10-08 16:43:53 +02006799 struct lyd_node_leaf_list *leaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006800 struct lys_node_leaf *sleaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006801
Michal Vasko83a6c462015-10-08 16:43:53 +02006802 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02006803 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006804
Michal Vaskocf024702015-10-08 15:01:42 +02006805 switch (type) {
6806 case UNRES_LEAFREF:
6807 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Radek Krejci9b6aad22016-09-20 15:55:51 +02006808 return resolve_leafref(leaf, &sleaf->type);
Michal Vasko8bcdf292015-08-19 14:04:43 +02006809
Michal Vaskocf024702015-10-08 15:01:42 +02006810 case UNRES_INSTID:
Radek Krejci7de36cf2016-09-12 16:18:50 +02006811 assert(sleaf->type.base == LY_TYPE_INST);
Michal Vasko8bcdf292015-08-19 14:04:43 +02006812 ly_errno = 0;
Radek Krejci48464ed2016-03-17 15:44:09 +01006813 leaf->value.instance = resolve_instid(node, leaf->value_str);
Radek Krejci40f17b92016-02-03 14:30:43 +01006814 if (!leaf->value.instance) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02006815 if (ly_errno) {
6816 return -1;
6817 } else if (sleaf->type.info.inst.req > -1) {
Michal Vasko6ac68282016-04-11 10:56:47 +02006818 LOGVAL(LYE_NOREQINS, LY_VLOG_LYD, leaf, leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02006819 return EXIT_FAILURE;
6820 } else {
Michal Vasko9925e282016-09-02 12:45:14 +02006821 LOGVRB("There is no instance identifier \"%s\", but it is not required.", leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02006822 }
6823 }
Michal Vaskocf024702015-10-08 15:01:42 +02006824 break;
6825
Radek Krejci7de36cf2016-09-12 16:18:50 +02006826 case UNRES_UNION:
6827 assert(sleaf->type.base == LY_TYPE_UNION);
Radek Krejci9b6aad22016-09-20 15:55:51 +02006828 return resolve_union(leaf, &sleaf->type);
Radek Krejci7de36cf2016-09-12 16:18:50 +02006829
Michal Vaskocf024702015-10-08 15:01:42 +02006830 case UNRES_WHEN:
Radek Krejci46165822016-08-26 14:06:27 +02006831 if ((rc = resolve_when(node, NULL))) {
Michal Vaskocf024702015-10-08 15:01:42 +02006832 return rc;
6833 }
6834 break;
6835
Michal Vaskobf19d252015-10-08 15:39:17 +02006836 case UNRES_MUST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006837 if ((rc = resolve_must(node, 0))) {
6838 return rc;
6839 }
6840 break;
6841
6842 case UNRES_MUST_INOUT:
6843 if ((rc = resolve_must(node, 1))) {
Michal Vaskobf19d252015-10-08 15:39:17 +02006844 return rc;
6845 }
6846 break;
6847
Michal Vaskocf024702015-10-08 15:01:42 +02006848 default:
Michal Vasko8bcdf292015-08-19 14:04:43 +02006849 LOGINT;
6850 return -1;
6851 }
6852
6853 return EXIT_SUCCESS;
6854}
6855
6856/**
Radek Krejci0b7704f2016-03-18 12:16:14 +01006857 * @brief add data unres item
Michal Vasko8bcdf292015-08-19 14:04:43 +02006858 *
6859 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02006860 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02006861 *
Radek Krejci0b7704f2016-03-18 12:16:14 +01006862 * @return 0 on success, -1 on error.
Michal Vasko8bcdf292015-08-19 14:04:43 +02006863 */
6864int
Radek Krejci0b7704f2016-03-18 12:16:14 +01006865unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02006866{
Radek Krejci03b71f72016-03-16 11:10:09 +01006867 assert(unres && node);
Michal Vaskoc4280842016-04-19 16:10:42 +02006868 assert((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)
Radek Krejcibacc7442016-10-27 13:39:56 +02006869 || (type == UNRES_MUST_INOUT) || (type == UNRES_UNION));
Michal Vasko8bcdf292015-08-19 14:04:43 +02006870
Radek Krejci03b71f72016-03-16 11:10:09 +01006871 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01006872 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
6873 if (!unres->node) {
6874 LOGMEM;
6875 return -1;
6876 }
Michal Vaskocf024702015-10-08 15:01:42 +02006877 unres->node[unres->count - 1] = node;
Michal Vasko253035f2015-12-17 16:58:13 +01006878 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
6879 if (!unres->type) {
6880 LOGMEM;
6881 return -1;
6882 }
Michal Vaskocf024702015-10-08 15:01:42 +02006883 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006884
Radek Krejci0b7704f2016-03-18 12:16:14 +01006885 if (type == UNRES_WHEN) {
6886 /* remove previous result */
6887 node->when_status = LYD_WHEN;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006888 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006889
6890 return EXIT_SUCCESS;
6891}
6892
6893/**
6894 * @brief Resolve every unres data item in the structure. Logs directly.
6895 *
Radek Krejci082c84f2016-10-17 16:33:06 +02006896 * If options includes LYD_OPT_TRUSTED, the data are considered trusted (when, must conditions are not expected,
6897 * unresolved leafrefs/instids are accepted).
6898 *
6899 * If options includes LYD_OPT_NOAUTODEL, the false resulting when condition on non-default nodes, the error is raised.
6900 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006901 * @param[in] unres Unres data structure to use.
Radek Krejci082c84f2016-10-17 16:33:06 +02006902 * @param[in,out] root Root node of the data tree, can be changed due to autodeletion.
6903 * @param[in] options Data options as described above.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006904 *
6905 * @return EXIT_SUCCESS on success, -1 on error.
6906 */
6907int
Radek Krejci082c84f2016-10-17 16:33:06 +02006908resolve_unres_data(struct unres_data *unres, struct lyd_node **root, int options)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006909{
Radek Krejci0c0086a2016-03-24 15:20:28 +01006910 uint32_t i, j, first = 1, resolved = 0, del_items = 0, when_stmt = 0;
Radek Krejci010e54b2016-03-15 09:40:34 +01006911 int rc, progress;
Radek Krejci03b71f72016-03-16 11:10:09 +01006912 char *msg, *path;
Radek Krejci0b7704f2016-03-18 12:16:14 +01006913 struct lyd_node *parent;
Radek Krejci7de36cf2016-09-12 16:18:50 +02006914 struct lyd_node_leaf_list *leaf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006915
Radek Krejci082c84f2016-10-17 16:33:06 +02006916 assert(root);
Radek Krejci03b71f72016-03-16 11:10:09 +01006917 assert(unres);
Radek Krejci03b71f72016-03-16 11:10:09 +01006918
6919 if (!unres->count) {
6920 return EXIT_SUCCESS;
6921 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006922
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02006923 LOGVRB("Resolving unresolved data nodes and their constraints...");
Radek Krejci010e54b2016-03-15 09:40:34 +01006924 ly_vlog_hide(1);
6925
Radek Krejci0b7704f2016-03-18 12:16:14 +01006926 /* when-stmt first */
Radek Krejci03b71f72016-03-16 11:10:09 +01006927 ly_errno = LY_SUCCESS;
6928 ly_vecode = LYVE_SUCCESS;
Radek Krejci010e54b2016-03-15 09:40:34 +01006929 do {
6930 progress = 0;
Michal Vasko6df94132016-09-22 11:08:09 +02006931 for (i = 0; i < unres->count; i++) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006932 if (unres->type[i] != UNRES_WHEN) {
6933 continue;
6934 }
Radek Krejci082c84f2016-10-17 16:33:06 +02006935 assert(!(options & LYD_OPT_TRUSTED));
Radek Krejci0c0086a2016-03-24 15:20:28 +01006936 if (first) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006937 /* count when-stmt nodes in unres list */
6938 when_stmt++;
6939 }
6940
6941 /* resolve when condition only when all parent when conditions are already resolved */
6942 for (parent = unres->node[i]->parent;
6943 parent && LYD_WHEN_DONE(parent->when_status);
6944 parent = parent->parent) {
6945 if (!parent->parent && (parent->when_status & LYD_WHEN_FALSE)) {
6946 /* the parent node was already unlinked, do not resolve this node,
6947 * it will be removed anyway, so just mark it as resolved
6948 */
6949 unres->node[i]->when_status |= LYD_WHEN_FALSE;
6950 unres->type[i] = UNRES_RESOLVED;
6951 resolved++;
6952 break;
6953 }
6954 }
6955 if (parent) {
6956 continue;
6957 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006958
Radek Krejci48464ed2016-03-17 15:44:09 +01006959 rc = resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01006960 if (!rc) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006961 if (unres->node[i]->when_status & LYD_WHEN_FALSE) {
Radek Krejci082c84f2016-10-17 16:33:06 +02006962 if ((options & LYD_OPT_NOAUTODEL) && !unres->node[i]->dflt) {
Radek Krejci03b71f72016-03-16 11:10:09 +01006963 /* false when condition */
6964 ly_vlog_hide(0);
Radek Krejci76e15e12016-06-22 11:02:24 +02006965 if (ly_log_level >= LY_LLERR) {
6966 path = strdup(ly_errpath());
6967 msg = strdup(ly_errmsg());
6968 LOGERR(LY_EVALID, "%s%s%s%s", msg,
6969 path[0] ? " (path: " : "", path[0] ? path : "", path[0] ? ")" : "");
6970 free(path);
6971 free(msg);
6972 }
Radek Krejci03b71f72016-03-16 11:10:09 +01006973 return -1;
Radek Krejci0b7704f2016-03-18 12:16:14 +01006974 } /* follows else */
6975
Radek Krejci0c0086a2016-03-24 15:20:28 +01006976 /* only unlink now, the subtree can contain another nodes stored in the unres list */
6977 /* if it has parent non-presence containers that would be empty, we should actually
6978 * remove the container
6979 */
Radek Krejci2537fd32016-09-07 16:22:41 +02006980 for (parent = unres->node[i];
6981 parent->parent && parent->parent->schema->nodetype == LYS_CONTAINER;
6982 parent = parent->parent) {
6983 if (((struct lys_node_container *)parent->parent->schema)->presence) {
6984 /* presence container */
6985 break;
Radek Krejci0c0086a2016-03-24 15:20:28 +01006986 }
Radek Krejci2537fd32016-09-07 16:22:41 +02006987 if (parent->next || parent->prev != parent) {
6988 /* non empty (the child we are in and we are going to remove is not the only child) */
6989 break;
6990 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01006991 }
Radek Krejci2537fd32016-09-07 16:22:41 +02006992 unres->node[i] = parent;
Radek Krejci0c0086a2016-03-24 15:20:28 +01006993
Radek Krejci0b7704f2016-03-18 12:16:14 +01006994 /* auto-delete */
6995 LOGVRB("auto-delete node \"%s\" due to when condition (%s)", ly_errpath(),
6996 ((struct lys_node_leaf *)unres->node[i]->schema)->when->cond);
Radek Krejci0c0086a2016-03-24 15:20:28 +01006997 if (*root && *root == unres->node[i]) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006998 *root = (*root)->next;
Radek Krejci03b71f72016-03-16 11:10:09 +01006999 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007000
Radek Krejci0b7704f2016-03-18 12:16:14 +01007001 lyd_unlink(unres->node[i]);
7002 unres->type[i] = UNRES_DELETE;
7003 del_items++;
Radek Krejci51fd8162016-03-24 15:49:51 +01007004
7005 /* update the rest of unres items */
7006 for (j = 0; j < unres->count; j++) {
Radek Krejci3db819b2016-03-24 16:29:48 +01007007 if (unres->type[j] == UNRES_RESOLVED || unres->type[j] == UNRES_DELETE) {
Radek Krejci51fd8162016-03-24 15:49:51 +01007008 continue;
7009 }
7010
7011 /* test if the node is in subtree to be deleted */
7012 for (parent = unres->node[j]; parent; parent = parent->parent) {
7013 if (parent == unres->node[i]) {
7014 /* yes, it is */
7015 unres->type[j] = UNRES_RESOLVED;
7016 resolved++;
7017 break;
7018 }
7019 }
7020 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007021 } else {
7022 unres->type[i] = UNRES_RESOLVED;
Radek Krejci03b71f72016-03-16 11:10:09 +01007023 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007024 ly_errno = LY_SUCCESS;
7025 ly_vecode = LYVE_SUCCESS;
Radek Krejci010e54b2016-03-15 09:40:34 +01007026 resolved++;
7027 progress = 1;
7028 } else if (rc == -1) {
7029 ly_vlog_hide(0);
Michal Vasko76e73402016-08-24 16:00:13 +02007030 /* print only this last error */
7031 resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01007032 return -1;
Radek Krejcic2a180f2016-06-22 13:28:16 +02007033 } else {
7034 /* forward reference, erase ly_errno */
7035 ly_errno = LY_SUCCESS;
Radek Krejci010e54b2016-03-15 09:40:34 +01007036 }
7037 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007038 first = 0;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007039 } while (progress && resolved < when_stmt);
Radek Krejci010e54b2016-03-15 09:40:34 +01007040
Radek Krejci0b7704f2016-03-18 12:16:14 +01007041 /* do we have some unresolved when-stmt? */
Radek Krejcid940d732016-03-24 16:02:28 +01007042 if (when_stmt > resolved) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007043 ly_vlog_hide(0);
Radek Krejci76e15e12016-06-22 11:02:24 +02007044 if (ly_log_level >= LY_LLERR) {
7045 path = strdup(ly_errpath());
7046 msg = strdup(ly_errmsg());
7047 LOGERR(LY_EVALID, "%s%s%s%s", msg, path[0] ? " (path: " : "", path[0] ? path : "", path[0] ? ")" : "");
7048 free(path);
7049 free(msg);
7050 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007051 return -1;
7052 }
7053
7054 for (i = 0; del_items && i < unres->count; i++) {
7055 /* we had some when-stmt resulted to false, so now we have to sanitize the unres list */
7056 if (unres->type[i] != UNRES_DELETE) {
7057 continue;
7058 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007059 if (!unres->node[i]) {
7060 unres->type[i] = UNRES_RESOLVED;
7061 del_items--;
7062 continue;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007063 }
7064
7065 /* really remove the complete subtree */
7066 lyd_free(unres->node[i]);
7067 unres->type[i] = UNRES_RESOLVED;
7068 del_items--;
7069 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007070
7071 /* rest */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007072 for (i = 0; i < unres->count; ++i) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007073 if (unres->type[i] == UNRES_RESOLVED) {
7074 continue;
7075 }
Radek Krejci082c84f2016-10-17 16:33:06 +02007076 assert(!(options & LYD_OPT_TRUSTED) || ((unres->type[i] != UNRES_MUST) && (unres->type[i] != UNRES_MUST_INOUT)));
Radek Krejci010e54b2016-03-15 09:40:34 +01007077
Radek Krejci48464ed2016-03-17 15:44:09 +01007078 rc = resolve_unres_data_item(unres->node[i], unres->type[i]);
Michal Vasko6df94132016-09-22 11:08:09 +02007079 if (rc == -1) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007080 ly_vlog_hide(0);
Michal Vasko96b846c2016-05-18 13:28:58 +02007081 /* print only this last error */
7082 resolve_unres_data_item(unres->node[i], unres->type[i]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007083 return -1;
Radek Krejci082c84f2016-10-17 16:33:06 +02007084 } 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 +02007085 unres->type[i] = UNRES_RESOLVED;
7086 resolved++;
Radek Krejci082c84f2016-10-17 16:33:06 +02007087 if (options & LYD_OPT_TRUSTED) {
Michal Vasko6df94132016-09-22 11:08:09 +02007088 /* accept it in this case */
7089 if (unres->type[i] == UNRES_LEAFREF) {
7090 LOGVRB("Leafref \"%s\" with value \"%s\" failed to be resolved.",
7091 ((struct lys_node_leaf *)unres->node[i]->schema)->type.info.lref.path,
7092 ((struct lyd_node_leaf_list *)unres->node[i])->value_str);
7093 } else {
7094 LOGVRB("Instance identifier \"%s\" failed to be resolved.",
7095 ((struct lyd_node_leaf_list *)unres->node[i])->value_str);
7096 }
7097 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007098 }
7099 }
7100
Radek Krejci010e54b2016-03-15 09:40:34 +01007101 ly_vlog_hide(0);
7102 if (resolved < unres->count) {
7103 /* try to resolve the unresolved data again, it will not resolve anything, but it will print
7104 * all the validation errors
7105 */
7106 for (i = 0; i < unres->count; ++i) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02007107 if (unres->type[i] == UNRES_UNION) {
7108 /* does not make sense to print specific errors for all
7109 * the data types, just print that the value is invalid */
7110 leaf = (struct lyd_node_leaf_list *)unres->node[i];
7111 LOGVAL(LYE_INVAL, LY_VLOG_LYD, unres->node[i], (leaf->value_str ? leaf->value_str : ""),
7112 leaf->schema->name);
7113 } else if (unres->type[i] != UNRES_RESOLVED) {
7114 resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01007115 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007116 }
7117 return -1;
7118 }
7119
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02007120 LOGVRB("All data nodes and constraints resolved.");
Radek Krejci010e54b2016-03-15 09:40:34 +01007121 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007122 return EXIT_SUCCESS;
7123}