blob: c462f31c88704abcd2a7c2aff753dc463d976a11 [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 Vaskod24dd012016-09-30 12:20:22 +020033int
34parse_range_dec64(const char **str_num, uint8_t dig, int64_t *num)
Michal Vasko4d1f0482016-09-19 14:35:06 +020035{
36 const char *ptr;
37 int minus = 0;
38 int64_t ret = 0;
Radek Krejcibf47a822016-11-04 10:06:08 +010039 int8_t str_exp, str_dig = -1, trailing_zeros = 0;
Michal Vasko4d1f0482016-09-19 14:35:06 +020040
41 ptr = *str_num;
42
43 if (ptr[0] == '-') {
44 minus = 1;
45 ++ptr;
Radek Krejci51673202016-11-01 17:00:32 +010046 } else if (ptr[0] == '+') {
47 ++ptr;
Michal Vasko4d1f0482016-09-19 14:35:06 +020048 }
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 {
Radek Krejcibf47a822016-11-04 10:06:08 +010067 ret = ret * 10 + (ptr[0] - '0');
Michal Vasko4d1f0482016-09-19 14:35:06 +020068 if (str_dig > -1) {
69 ++str_dig;
Radek Krejcibf47a822016-11-04 10:06:08 +010070 if (ptr[0] == '0') {
71 /* possibly trailing zero */
72 trailing_zeros++;
73 } else {
74 trailing_zeros = 0;
75 }
Michal Vasko4d1f0482016-09-19 14:35:06 +020076 }
77 ++str_exp;
78 }
79 }
Michal Vaskod24dd012016-09-30 12:20:22 +020080 if (str_dig == 0) {
81 /* no digits after '.' */
82 return 1;
83 } else if (str_dig == -1) {
84 /* there are 0 numbers after the floating point */
Michal Vasko4d1f0482016-09-19 14:35:06 +020085 str_dig = 0;
86 }
Radek Krejcibf47a822016-11-04 10:06:08 +010087 /* remove trailing zeros */
88 if (trailing_zeros) {
Michal Vasko6ca5ca72016-11-28 09:21:51 +010089 str_dig -= trailing_zeros;
90 str_exp -= trailing_zeros;
Radek Krejcibf47a822016-11-04 10:06:08 +010091 ret = ret / dec_pow(trailing_zeros);
92 }
Michal Vasko4d1f0482016-09-19 14:35:06 +020093
94 /* it's parsed, now adjust the number based on fraction-digits, if needed */
95 if (str_dig < dig) {
96 if ((str_exp - 1) + (dig - str_dig) > 18) {
Michal Vaskod24dd012016-09-30 12:20:22 +020097 return 1;
Michal Vasko4d1f0482016-09-19 14:35:06 +020098 }
99 ret *= dec_pow(dig - str_dig);
100 }
101 if (str_dig > dig) {
Michal Vaskod24dd012016-09-30 12:20:22 +0200102 return 1;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200103 }
104
105 if (minus) {
106 ret *= -1;
107 }
108 *str_num = ptr;
Michal Vaskod24dd012016-09-30 12:20:22 +0200109 *num = ret;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200110
Michal Vaskod24dd012016-09-30 12:20:22 +0200111 return 0;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200112}
113
114/**
Radek Krejci6dc53a22015-08-17 13:27:59 +0200115 * @brief Parse an identifier.
116 *
117 * ;; An identifier MUST NOT start with (('X'|'x') ('M'|'m') ('L'|'l'))
118 * identifier = (ALPHA / "_")
119 * *(ALPHA / DIGIT / "_" / "-" / ".")
120 *
Michal Vaskobb211122015-08-19 14:03:11 +0200121 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200122 *
123 * @return Number of characters successfully parsed.
124 */
Michal Vasko249e6b52015-08-19 11:08:52 +0200125int
Radek Krejci6dc53a22015-08-17 13:27:59 +0200126parse_identifier(const char *id)
127{
128 int parsed = 0;
129
Michal Vasko1ab90bc2016-03-15 10:40:22 +0100130 assert(id);
131
Radek Krejci6dc53a22015-08-17 13:27:59 +0200132 if (!isalpha(id[0]) && (id[0] != '_')) {
133 return -parsed;
134 }
135
136 ++parsed;
137 ++id;
138
139 while (isalnum(id[0]) || (id[0] == '_') || (id[0] == '-') || (id[0] == '.')) {
140 ++parsed;
141 ++id;
142 }
143
144 return parsed;
145}
146
147/**
148 * @brief Parse a node-identifier.
149 *
Michal Vasko723e50c2015-10-20 15:20:29 +0200150 * node-identifier = [module-name ":"] identifier
Radek Krejci6dc53a22015-08-17 13:27:59 +0200151 *
Michal Vaskobb211122015-08-19 14:03:11 +0200152 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200153 * @param[out] mod_name Points to the module name, NULL if there is not any.
154 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200155 * @param[out] name Points to the node name.
156 * @param[out] nam_len Length of the node name.
157 *
158 * @return Number of characters successfully parsed,
159 * positive on success, negative on failure.
160 */
161static int
Michal Vasko723e50c2015-10-20 15:20:29 +0200162parse_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 +0200163{
164 int parsed = 0, ret;
165
166 assert(id);
Michal Vasko723e50c2015-10-20 15:20:29 +0200167 if (mod_name) {
168 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200169 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200170 if (mod_name_len) {
171 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200172 }
173 if (name) {
174 *name = NULL;
175 }
176 if (nam_len) {
177 *nam_len = 0;
178 }
179
180 if ((ret = parse_identifier(id)) < 1) {
181 return ret;
182 }
183
Michal Vasko723e50c2015-10-20 15:20:29 +0200184 if (mod_name) {
185 *mod_name = id;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200186 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200187 if (mod_name_len) {
188 *mod_name_len = ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200189 }
190
191 parsed += ret;
192 id += ret;
193
194 /* there is prefix */
195 if (id[0] == ':') {
196 ++parsed;
197 ++id;
198
199 /* there isn't */
200 } else {
Michal Vasko723e50c2015-10-20 15:20:29 +0200201 if (name && mod_name) {
202 *name = *mod_name;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200203 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200204 if (mod_name) {
205 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200206 }
207
Michal Vasko723e50c2015-10-20 15:20:29 +0200208 if (nam_len && mod_name_len) {
209 *nam_len = *mod_name_len;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200210 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200211 if (mod_name_len) {
212 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200213 }
214
215 return parsed;
216 }
217
218 /* identifier (node name) */
219 if ((ret = parse_identifier(id)) < 1) {
220 return -parsed+ret;
221 }
222
223 if (name) {
224 *name = id;
225 }
226 if (nam_len) {
227 *nam_len = ret;
228 }
229
230 return parsed+ret;
231}
232
233/**
234 * @brief Parse a path-predicate (leafref).
235 *
236 * path-predicate = "[" *WSP path-equality-expr *WSP "]"
237 * path-equality-expr = node-identifier *WSP "=" *WSP path-key-expr
238 *
Michal Vaskobb211122015-08-19 14:03:11 +0200239 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200240 * @param[out] prefix Points to the prefix, NULL if there is not any.
241 * @param[out] pref_len Length of the prefix, 0 if there is not any.
242 * @param[out] name Points to the node name.
243 * @param[out] nam_len Length of the node name.
244 * @param[out] path_key_expr Points to the path-key-expr.
245 * @param[out] pke_len Length of the path-key-expr.
246 * @param[out] has_predicate Flag to mark whether there is another predicate following.
247 *
248 * @return Number of characters successfully parsed,
249 * positive on success, negative on failure.
250 */
251static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200252parse_path_predicate(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
253 const char **path_key_expr, int *pke_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200254{
255 const char *ptr;
256 int parsed = 0, ret;
257
258 assert(id);
259 if (prefix) {
260 *prefix = NULL;
261 }
262 if (pref_len) {
263 *pref_len = 0;
264 }
265 if (name) {
266 *name = NULL;
267 }
268 if (nam_len) {
269 *nam_len = 0;
270 }
271 if (path_key_expr) {
272 *path_key_expr = NULL;
273 }
274 if (pke_len) {
275 *pke_len = 0;
276 }
277 if (has_predicate) {
278 *has_predicate = 0;
279 }
280
281 if (id[0] != '[') {
282 return -parsed;
283 }
284
285 ++parsed;
286 ++id;
287
288 while (isspace(id[0])) {
289 ++parsed;
290 ++id;
291 }
292
293 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
294 return -parsed+ret;
295 }
296
297 parsed += ret;
298 id += ret;
299
300 while (isspace(id[0])) {
301 ++parsed;
302 ++id;
303 }
304
305 if (id[0] != '=') {
306 return -parsed;
307 }
308
309 ++parsed;
310 ++id;
311
312 while (isspace(id[0])) {
313 ++parsed;
314 ++id;
315 }
316
317 if ((ptr = strchr(id, ']')) == NULL) {
318 return -parsed;
319 }
320
321 --ptr;
322 while (isspace(ptr[0])) {
323 --ptr;
324 }
325 ++ptr;
326
327 ret = ptr-id;
328 if (path_key_expr) {
329 *path_key_expr = id;
330 }
331 if (pke_len) {
332 *pke_len = ret;
333 }
334
335 parsed += ret;
336 id += ret;
337
338 while (isspace(id[0])) {
339 ++parsed;
340 ++id;
341 }
342
343 assert(id[0] == ']');
344
345 if (id[1] == '[') {
346 *has_predicate = 1;
347 }
348
349 return parsed+1;
350}
351
352/**
353 * @brief Parse a path-key-expr (leafref). First call parses "current()", all
354 * the ".." and the first node-identifier, other calls parse a single
355 * node-identifier each.
356 *
357 * path-key-expr = current-function-invocation *WSP "/" *WSP
358 * rel-path-keyexpr
359 * rel-path-keyexpr = 1*(".." *WSP "/" *WSP)
360 * *(node-identifier *WSP "/" *WSP)
361 * node-identifier
362 *
Michal Vaskobb211122015-08-19 14:03:11 +0200363 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200364 * @param[out] prefix Points to the prefix, NULL if there is not any.
365 * @param[out] pref_len Length of the prefix, 0 if there is not any.
366 * @param[out] name Points to the node name.
367 * @param[out] nam_len Length of the node name.
368 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
369 * must not be changed between consecutive calls.
370 * @return Number of characters successfully parsed,
371 * positive on success, negative on failure.
372 */
373static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200374parse_path_key_expr(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
375 int *parent_times)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200376{
377 int parsed = 0, ret, par_times = 0;
378
379 assert(id);
380 assert(parent_times);
381 if (prefix) {
382 *prefix = NULL;
383 }
384 if (pref_len) {
385 *pref_len = 0;
386 }
387 if (name) {
388 *name = NULL;
389 }
390 if (nam_len) {
391 *nam_len = 0;
392 }
393
394 if (!*parent_times) {
395 /* current-function-invocation *WSP "/" *WSP rel-path-keyexpr */
396 if (strncmp(id, "current()", 9)) {
397 return -parsed;
398 }
399
400 parsed += 9;
401 id += 9;
402
403 while (isspace(id[0])) {
404 ++parsed;
405 ++id;
406 }
407
408 if (id[0] != '/') {
409 return -parsed;
410 }
411
412 ++parsed;
413 ++id;
414
415 while (isspace(id[0])) {
416 ++parsed;
417 ++id;
418 }
419
420 /* rel-path-keyexpr */
421 if (strncmp(id, "..", 2)) {
422 return -parsed;
423 }
424 ++par_times;
425
426 parsed += 2;
427 id += 2;
428
429 while (isspace(id[0])) {
430 ++parsed;
431 ++id;
432 }
433 }
434
435 /* 1*(".." *WSP "/" *WSP) *(node-identifier *WSP "/" *WSP) node-identifier
436 *
437 * first parent reference with whitespaces already parsed
438 */
439 if (id[0] != '/') {
440 return -parsed;
441 }
442
443 ++parsed;
444 ++id;
445
446 while (isspace(id[0])) {
447 ++parsed;
448 ++id;
449 }
450
451 while (!strncmp(id, "..", 2) && !*parent_times) {
452 ++par_times;
453
454 parsed += 2;
455 id += 2;
456
457 while (isspace(id[0])) {
458 ++parsed;
459 ++id;
460 }
461
462 if (id[0] != '/') {
463 return -parsed;
464 }
465
466 ++parsed;
467 ++id;
468
469 while (isspace(id[0])) {
470 ++parsed;
471 ++id;
472 }
473 }
474
475 if (!*parent_times) {
476 *parent_times = par_times;
477 }
478
479 /* all parent references must be parsed at this point */
480 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
481 return -parsed+ret;
482 }
483
484 parsed += ret;
485 id += ret;
486
487 return parsed;
488}
489
490/**
491 * @brief Parse path-arg (leafref).
492 *
493 * path-arg = absolute-path / relative-path
494 * absolute-path = 1*("/" (node-identifier *path-predicate))
495 * relative-path = 1*(".." "/") descendant-path
496 *
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200497 * @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 +0200498 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200499 * @param[out] prefix Points to the prefix, NULL if there is not any.
500 * @param[out] pref_len Length of the prefix, 0 if there is not any.
501 * @param[out] name Points to the node name.
502 * @param[out] nam_len Length of the node name.
503 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
504 * must not be changed between consecutive calls. -1 if the
505 * path is relative.
506 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
507 *
508 * @return Number of characters successfully parsed,
509 * positive on success, negative on failure.
510 */
511static int
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200512parse_path_arg(struct lys_module *mod, const char *id, const char **prefix, int *pref_len,
513 const char **name, int *nam_len, int *parent_times, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200514{
515 int parsed = 0, ret, par_times = 0;
516
517 assert(id);
518 assert(parent_times);
519 if (prefix) {
520 *prefix = NULL;
521 }
522 if (pref_len) {
523 *pref_len = 0;
524 }
525 if (name) {
526 *name = NULL;
527 }
528 if (nam_len) {
529 *nam_len = 0;
530 }
531 if (has_predicate) {
532 *has_predicate = 0;
533 }
534
535 if (!*parent_times && !strncmp(id, "..", 2)) {
536 ++par_times;
537
538 parsed += 2;
539 id += 2;
540
541 while (!strncmp(id, "/..", 3)) {
542 ++par_times;
543
544 parsed += 3;
545 id += 3;
546 }
547 }
548
549 if (!*parent_times) {
550 if (par_times) {
551 *parent_times = par_times;
552 } else {
553 *parent_times = -1;
554 }
555 }
556
557 if (id[0] != '/') {
558 return -parsed;
559 }
560
561 /* skip '/' */
562 ++parsed;
563 ++id;
564
565 /* node-identifier ([prefix:]identifier) */
566 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
567 return -parsed-ret;
568 }
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200569 if (!(*prefix)) {
570 /* actually we always need prefix even it is not specified */
571 *prefix = lys_main_module(mod)->name;
572 *pref_len = strlen(*prefix);
573 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200574
575 parsed += ret;
576 id += ret;
577
578 /* there is no predicate */
579 if ((id[0] == '/') || !id[0]) {
580 return parsed;
581 } else if (id[0] != '[') {
582 return -parsed;
583 }
584
585 if (has_predicate) {
586 *has_predicate = 1;
587 }
588
589 return parsed;
590}
591
592/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200593 * @brief Parse instance-identifier in JSON data format. That means that prefixes
Michal Vaskob2f40be2016-09-08 16:03:48 +0200594 * (which are mandatory for every node-identifier) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200595 *
596 * instance-identifier = 1*("/" (node-identifier *predicate))
597 *
Michal Vaskobb211122015-08-19 14:03:11 +0200598 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200599 * @param[out] model Points to the model name.
600 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200601 * @param[out] name Points to the node name.
602 * @param[out] nam_len Length of the node name.
603 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
604 *
605 * @return Number of characters successfully parsed,
606 * positive on success, negative on failure.
607 */
608static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200609parse_instance_identifier(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
610 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200611{
612 int parsed = 0, ret;
613
Radek Krejci6dc53a22015-08-17 13:27:59 +0200614 if (has_predicate) {
615 *has_predicate = 0;
616 }
617
618 if (id[0] != '/') {
619 return -parsed;
620 }
621
622 ++parsed;
623 ++id;
624
Michal Vaskob2f40be2016-09-08 16:03:48 +0200625 if ((ret = parse_identifier(id)) < 1) {
626 return ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200627 }
628
Michal Vaskob2f40be2016-09-08 16:03:48 +0200629 *model = id;
630 *mod_len = ret;
631
Radek Krejci6dc53a22015-08-17 13:27:59 +0200632 parsed += ret;
633 id += ret;
634
Michal Vaskob2f40be2016-09-08 16:03:48 +0200635 if (id[0] != ':') {
636 return -parsed;
637 }
638
639 ++parsed;
640 ++id;
641
642 if ((ret = parse_identifier(id)) < 1) {
643 return ret;
644 }
645
646 *name = id;
647 *nam_len = ret;
648
649 parsed += ret;
650 id += ret;
651
Radek Krejci4967cb62016-09-14 16:40:28 +0200652 if (id[0] == '[' && has_predicate) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200653 *has_predicate = 1;
654 }
655
656 return parsed;
657}
658
659/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200660 * @brief Parse predicate (instance-identifier) in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200661 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200662 *
663 * predicate = "[" *WSP (predicate-expr / pos) *WSP "]"
664 * predicate-expr = (node-identifier / ".") *WSP "=" *WSP
665 * ((DQUOTE string DQUOTE) /
666 * (SQUOTE string SQUOTE))
667 * pos = non-negative-integer-value
668 *
Michal Vaskobb211122015-08-19 14:03:11 +0200669 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200670 * @param[out] model Points to the model name.
671 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200672 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
673 * @param[out] nam_len Length of the node name.
674 * @param[out] value Value the node-identifier must have (string from the grammar),
675 * NULL if there is not any.
676 * @param[out] val_len Length of the value, 0 if there is not any.
677 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
678 *
679 * @return Number of characters successfully parsed,
680 * positive on success, negative on failure.
681 */
682static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200683parse_predicate(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
684 const char **value, int *val_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200685{
686 const char *ptr;
687 int parsed = 0, ret;
688 char quote;
689
690 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200691 if (model) {
692 *model = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200693 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200694 if (mod_len) {
695 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200696 }
697 if (name) {
698 *name = NULL;
699 }
700 if (nam_len) {
701 *nam_len = 0;
702 }
703 if (value) {
704 *value = NULL;
705 }
706 if (val_len) {
707 *val_len = 0;
708 }
709 if (has_predicate) {
710 *has_predicate = 0;
711 }
712
713 if (id[0] != '[') {
714 return -parsed;
715 }
716
717 ++parsed;
718 ++id;
719
720 while (isspace(id[0])) {
721 ++parsed;
722 ++id;
723 }
724
725 /* pos */
726 if (isdigit(id[0])) {
727 if (name) {
728 *name = id;
729 }
730
731 if (id[0] == '0') {
Michal Vaskof2f28a12016-09-09 12:43:06 +0200732 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200733 }
734
735 while (isdigit(id[0])) {
736 ++parsed;
737 ++id;
738 }
739
740 if (nam_len) {
741 *nam_len = id-(*name);
742 }
743
Michal Vaskof2f28a12016-09-09 12:43:06 +0200744 /* "." or node-identifier */
Radek Krejci6dc53a22015-08-17 13:27:59 +0200745 } else {
Michal Vaskof2f28a12016-09-09 12:43:06 +0200746 if (id[0] == '.') {
747 if (name) {
748 *name = id;
749 }
750 if (nam_len) {
751 *nam_len = 1;
752 }
753
754 ++parsed;
755 ++id;
756
757 } else {
758 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
759 return -parsed+ret;
760 } else if (model && !*model) {
761 return -parsed;
762 }
763
764 parsed += ret;
765 id += ret;
766 }
767
768 while (isspace(id[0])) {
769 ++parsed;
770 ++id;
771 }
772
773 if (id[0] != '=') {
Michal Vasko1f2cc332015-08-19 11:18:32 +0200774 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200775 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200776
Radek Krejci6dc53a22015-08-17 13:27:59 +0200777 ++parsed;
778 ++id;
779
Michal Vaskof2f28a12016-09-09 12:43:06 +0200780 while (isspace(id[0])) {
781 ++parsed;
782 ++id;
783 }
784
785 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
786 if ((id[0] == '\"') || (id[0] == '\'')) {
787 quote = id[0];
788
789 ++parsed;
790 ++id;
791
792 if ((ptr = strchr(id, quote)) == NULL) {
793 return -parsed;
794 }
795 ret = ptr-id;
796
797 if (value) {
798 *value = id;
799 }
800 if (val_len) {
801 *val_len = ret;
802 }
803
804 parsed += ret+1;
805 id += ret+1;
806 } else {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200807 return -parsed;
808 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200809 }
810
811 while (isspace(id[0])) {
812 ++parsed;
813 ++id;
814 }
815
816 if (id[0] != ']') {
817 return -parsed;
818 }
819
820 ++parsed;
821 ++id;
822
823 if ((id[0] == '[') && has_predicate) {
824 *has_predicate = 1;
825 }
826
827 return parsed;
828}
829
830/**
831 * @brief Parse schema-nodeid.
832 *
833 * schema-nodeid = absolute-schema-nodeid /
834 * descendant-schema-nodeid
835 * absolute-schema-nodeid = 1*("/" node-identifier)
Michal Vasko48935352016-03-29 11:52:36 +0200836 * descendant-schema-nodeid = ["." "/"]
Radek Krejci6dc53a22015-08-17 13:27:59 +0200837 * node-identifier
838 * absolute-schema-nodeid
839 *
Michal Vaskobb211122015-08-19 14:03:11 +0200840 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200841 * @param[out] mod_name Points to the module name, NULL if there is not any.
842 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Michal Vasko48935352016-03-29 11:52:36 +0200843 * @param[out] name Points to the node name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200844 * @param[out] nam_len Length of the node name.
845 * @param[out] is_relative Flag to mark whether the nodeid is absolute or descendant. Must be -1
846 * on the first call, must not be changed between consecutive calls.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100847 * @param[out] has_predicate Flag to mark whether there is a predicate specified. It cannot be
848 * based on the grammar, in those cases use NULL.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200849 *
850 * @return Number of characters successfully parsed,
851 * positive on success, negative on failure.
852 */
Michal Vasko22448d32016-03-16 13:17:29 +0100853int
Michal Vasko723e50c2015-10-20 15:20:29 +0200854parse_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 +0100855 int *is_relative, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200856{
857 int parsed = 0, ret;
858
859 assert(id);
860 assert(is_relative);
Michal Vasko723e50c2015-10-20 15:20:29 +0200861 if (mod_name) {
862 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200863 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200864 if (mod_name_len) {
865 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200866 }
867 if (name) {
868 *name = NULL;
869 }
870 if (nam_len) {
871 *nam_len = 0;
872 }
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100873 if (has_predicate) {
874 *has_predicate = 0;
875 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200876
877 if (id[0] != '/') {
878 if (*is_relative != -1) {
879 return -parsed;
880 } else {
881 *is_relative = 1;
882 }
Michal Vasko48935352016-03-29 11:52:36 +0200883 if (!strncmp(id, "./", 2)) {
884 parsed += 2;
885 id += 2;
886 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200887 } else {
888 if (*is_relative == -1) {
889 *is_relative = 0;
890 }
891 ++parsed;
892 ++id;
893 }
894
Michal Vasko723e50c2015-10-20 15:20:29 +0200895 if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200896 return -parsed+ret;
897 }
898
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100899 parsed += ret;
900 id += ret;
901
902 if ((id[0] == '[') && has_predicate) {
903 *has_predicate = 1;
904 }
905
906 return parsed;
907}
908
909/**
910 * @brief Parse schema predicate (special format internally used).
911 *
912 * predicate = "[" *WSP predicate-expr *WSP "]"
Michal Vasko58c2aab2017-01-05 10:02:05 +0100913 * predicate-expr = "." / identifier / positive-integer / key-with-value
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100914 * key-with-value = identifier *WSP "=" *WSP
915 * ((DQUOTE string DQUOTE) /
916 * (SQUOTE string SQUOTE))
917 *
918 * @param[in] id Identifier to use.
919 * @param[out] name Points to the list key name.
920 * @param[out] nam_len Length of \p name.
Michal Vasko22448d32016-03-16 13:17:29 +0100921 * @param[out] value Points to the key value. If specified, key-with-value is expected.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100922 * @param[out] val_len Length of \p value.
923 * @param[out] has_predicate Flag to mark whether there is another predicate specified.
924 */
Michal Vasko22448d32016-03-16 13:17:29 +0100925int
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200926parse_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 +0100927 int *has_predicate)
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100928{
929 const char *ptr;
930 int parsed = 0, ret;
931 char quote;
932
933 assert(id);
934 if (name) {
935 *name = NULL;
936 }
937 if (nam_len) {
938 *nam_len = 0;
939 }
940 if (value) {
941 *value = NULL;
942 }
943 if (val_len) {
944 *val_len = 0;
945 }
946 if (has_predicate) {
947 *has_predicate = 0;
948 }
949
950 if (id[0] != '[') {
951 return -parsed;
952 }
953
954 ++parsed;
955 ++id;
956
957 while (isspace(id[0])) {
958 ++parsed;
959 ++id;
960 }
961
Michal Vasko22448d32016-03-16 13:17:29 +0100962 /* identifier */
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200963 if (id[0] == '.') {
964 ret = 1;
Michal Vasko58c2aab2017-01-05 10:02:05 +0100965 } else if (isdigit(id[0])) {
966 if (id[0] == '0') {
967 return -parsed;
968 }
969 ret = 1;
970 while (isdigit(id[ret])) {
971 ++ret;
972 }
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200973 } else if ((ret = parse_identifier(id)) < 1) {
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100974 return -parsed + ret;
975 }
976 if (name) {
977 *name = id;
978 }
979 if (nam_len) {
980 *nam_len = ret;
981 }
982
983 parsed += ret;
984 id += ret;
985
986 while (isspace(id[0])) {
987 ++parsed;
988 ++id;
989 }
990
991 /* there is value as well */
992 if (id[0] == '=') {
Michal Vasko58c2aab2017-01-05 10:02:05 +0100993 if (name && isdigit(**name)) {
994 return -parsed;
995 }
996
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100997 ++parsed;
998 ++id;
999
1000 while (isspace(id[0])) {
1001 ++parsed;
1002 ++id;
1003 }
1004
1005 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
1006 if ((id[0] == '\"') || (id[0] == '\'')) {
1007 quote = id[0];
1008
1009 ++parsed;
1010 ++id;
1011
1012 if ((ptr = strchr(id, quote)) == NULL) {
1013 return -parsed;
1014 }
1015 ret = ptr - id;
1016
1017 if (value) {
1018 *value = id;
1019 }
1020 if (val_len) {
1021 *val_len = ret;
1022 }
1023
1024 parsed += ret + 1;
1025 id += ret + 1;
1026 } else {
1027 return -parsed;
1028 }
1029
1030 while (isspace(id[0])) {
1031 ++parsed;
1032 ++id;
1033 }
1034 }
1035
1036 if (id[0] != ']') {
1037 return -parsed;
1038 }
1039
1040 ++parsed;
1041 ++id;
1042
1043 if ((id[0] == '[') && has_predicate) {
1044 *has_predicate = 1;
1045 }
1046
1047 return parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +02001048}
1049
1050/**
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001051 * @brief Resolve (find) a feature definition. Logs directly.
1052 *
1053 * @param[in] feat_name Feature name to resolve.
1054 * @param[in] len Length of \p feat_name.
1055 * @param[in] node Node with the if-feature expression.
Radek Krejci9ff0a922016-07-14 13:08:05 +02001056 * @param[out] feature Pointer to be set to point to the feature definition, if feature not found
1057 * (return code 1), the pointer is untouched.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001058 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02001059 * @return 0 on success, 1 on forward reference, -1 on error.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001060 */
1061static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001062resolve_feature(const char *feat_name, uint16_t len, const struct lys_node *node, struct lys_feature **feature)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001063{
1064 char *str;
1065 const char *mod_name, *name;
1066 int mod_name_len, nam_len, i, j;
1067 const struct lys_module *module;
1068
Radek Krejci9ff0a922016-07-14 13:08:05 +02001069 assert(feature);
1070
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001071 /* check prefix */
1072 if ((i = parse_node_identifier(feat_name, &mod_name, &mod_name_len, &name, &nam_len)) < 1) {
1073 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, feat_name[-i], &feat_name[-i]);
1074 return -1;
1075 }
1076
1077 module = lys_get_import_module(lys_node_module(node), NULL, 0, mod_name, mod_name_len);
1078 if (!module) {
1079 /* identity refers unknown data model */
1080 LOGVAL(LYE_INMOD_LEN, LY_VLOG_NONE, NULL, mod_name_len, mod_name);
1081 return -1;
1082 }
1083
Radek Krejci9ff0a922016-07-14 13:08:05 +02001084 if (module != node->module && module == lys_node_module(node)) {
1085 /* first, try to search directly in submodule where the feature was mentioned */
1086 for (j = 0; j < node->module->features_size; j++) {
1087 if (!strncmp(name, node->module->features[j].name, nam_len) && !node->module->features[j].name[nam_len]) {
1088 /* check status */
1089 if (lyp_check_status(node->flags, lys_node_module(node), node->name, node->module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001090 node->module->features[j].module, node->module->features[j].name, NULL)) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001091 return -1;
1092 }
1093 *feature = &node->module->features[j];
1094 return 0;
1095 }
1096 }
1097 }
1098
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001099 /* search in the identified module ... */
1100 for (j = 0; j < module->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001101 if (!strncmp(name, module->features[j].name, nam_len) && !module->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001102 /* check status */
1103 if (lyp_check_status(node->flags, lys_node_module(node), node->name, module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001104 module->features[j].module, module->features[j].name, NULL)) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001105 return -1;
1106 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001107 *feature = &module->features[j];
1108 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001109 }
1110 }
1111 /* ... and all its submodules */
Radek Krejcid4c1d0f2017-01-19 16:11:38 +01001112 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001113 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001114 if (!strncmp(name, module->inc[i].submodule->features[j].name, nam_len)
1115 && !module->inc[i].submodule->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001116 /* check status */
1117 if (lyp_check_status(node->flags, lys_node_module(node), node->name,
1118 module->inc[i].submodule->features[j].flags,
1119 module->inc[i].submodule->features[j].module,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001120 module->inc[i].submodule->features[j].name, NULL)) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001121 return -1;
1122 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001123 *feature = &module->inc[i].submodule->features[j];
1124 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001125 }
1126 }
1127 }
1128
1129 /* not found */
1130 str = strndup(feat_name, len);
1131 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, "feature", str);
1132 free(str);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001133 return 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001134}
1135
Radek Krejci9ff0a922016-07-14 13:08:05 +02001136/*
1137 * @return
Radek Krejci69b8d922016-07-27 13:13:41 +02001138 * - 1 if enabled
1139 * - 0 if disabled
Radek Krejci9ff0a922016-07-14 13:08:05 +02001140 * - -1 if not usable by its if-feature expression
1141 */
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001142static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001143resolve_feature_value(const struct lys_feature *feat)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001144{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001145 int i;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001146
Radek Krejci9ff0a922016-07-14 13:08:05 +02001147 for (i = 0; i < feat->iffeature_size; i++) {
Radek Krejci69b8d922016-07-27 13:13:41 +02001148 if (!resolve_iffeature(&feat->iffeature[i])) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001149 return -1;
1150 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001151 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001152
Radek Krejci69b8d922016-07-27 13:13:41 +02001153 return feat->flags & LYS_FENABLED ? 1 : 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001154}
1155
1156static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001157resolve_iffeature_recursive(struct lys_iffeature *expr, int *index_e, int *index_f)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001158{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001159 uint8_t op;
1160 int rc, a, b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001161
Radek Krejci9ff0a922016-07-14 13:08:05 +02001162 op = iff_getop(expr->expr, *index_e);
1163 (*index_e)++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001164
Radek Krejci9ff0a922016-07-14 13:08:05 +02001165 switch (op) {
1166 case LYS_IFF_F:
1167 /* resolve feature */
1168 return resolve_feature_value(expr->features[(*index_f)++]);
1169 case LYS_IFF_NOT:
1170 rc = resolve_iffeature_recursive(expr, index_e, index_f);
1171 if (rc == -1) {
1172 /* one of the referenced feature is hidden by its if-feature,
1173 * so this if-feature expression is always false */
1174 return -1;
1175 } else {
1176 /* invert result */
1177 return rc ? 0 : 1;
1178 }
1179 case LYS_IFF_AND:
1180 case LYS_IFF_OR:
1181 a = resolve_iffeature_recursive(expr, index_e, index_f);
1182 b = resolve_iffeature_recursive(expr, index_e, index_f);
1183 if (a == -1 || b == -1) {
1184 /* one of the referenced feature is hidden by its if-feature,
1185 * so this if-feature expression is always false */
1186 return -1;
1187 } else if (op == LYS_IFF_AND) {
1188 return a && b;
1189 } else { /* LYS_IFF_OR */
1190 return a || b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001191 }
1192 }
1193
Radek Krejci9ff0a922016-07-14 13:08:05 +02001194 return -1;
1195}
1196
1197int
1198resolve_iffeature(struct lys_iffeature *expr)
1199{
1200 int rc = -1;
1201 int index_e = 0, index_f = 0;
1202
1203 if (expr->expr) {
1204 rc = resolve_iffeature_recursive(expr, &index_e, &index_f);
1205 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001206 return (rc == 1) ? 1 : 0;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001207}
1208
1209struct iff_stack {
1210 int size;
1211 int index; /* first empty item */
1212 uint8_t *stack;
1213};
1214
1215static int
1216iff_stack_push(struct iff_stack *stack, uint8_t value)
1217{
1218 if (stack->index == stack->size) {
1219 stack->size += 4;
1220 stack->stack = ly_realloc(stack->stack, stack->size * sizeof *stack->stack);
1221 if (!stack->stack) {
1222 LOGMEM;
1223 stack->size = 0;
1224 return EXIT_FAILURE;
1225 }
1226 }
1227
1228 stack->stack[stack->index++] = value;
1229 return EXIT_SUCCESS;
1230}
1231
1232static uint8_t
1233iff_stack_pop(struct iff_stack *stack)
1234{
1235 stack->index--;
1236 return stack->stack[stack->index];
1237}
1238
1239static void
1240iff_stack_clean(struct iff_stack *stack)
1241{
1242 stack->size = 0;
1243 free(stack->stack);
1244}
1245
1246static void
1247iff_setop(uint8_t *list, uint8_t op, int pos)
1248{
1249 uint8_t *item;
1250 uint8_t mask = 3;
1251
1252 assert(pos >= 0);
1253 assert(op <= 3); /* max 2 bits */
1254
1255 item = &list[pos / 4];
1256 mask = mask << 2 * (pos % 4);
1257 *item = (*item) & ~mask;
1258 *item = (*item) | (op << 2 * (pos % 4));
1259}
1260
1261uint8_t
1262iff_getop(uint8_t *list, int pos)
1263{
1264 uint8_t *item;
1265 uint8_t mask = 3, result;
1266
1267 assert(pos >= 0);
1268
1269 item = &list[pos / 4];
1270 result = (*item) & (mask << 2 * (pos % 4));
1271 return result >> 2 * (pos % 4);
1272}
1273
1274#define LYS_IFF_LP 0x04 /* ( */
1275#define LYS_IFF_RP 0x08 /* ) */
1276
Radek Krejcicbb473e2016-09-16 14:48:32 +02001277/* internal structure for passing data for UNRES_IFFEAT */
1278struct unres_iffeat_data {
1279 struct lys_node *node;
1280 const char *fname;
Radek Krejci9de2c042016-10-19 16:53:06 +02001281 int infeature;
Radek Krejcicbb473e2016-09-16 14:48:32 +02001282};
1283
Radek Krejci9ff0a922016-07-14 13:08:05 +02001284void
1285resolve_iffeature_getsizes(struct lys_iffeature *iffeat, unsigned int *expr_size, unsigned int *feat_size)
1286{
1287 unsigned int e = 0, f = 0, r = 0;
1288 uint8_t op;
1289
1290 assert(iffeat);
1291
1292 if (!iffeat->expr) {
1293 goto result;
1294 }
1295
1296 do {
1297 op = iff_getop(iffeat->expr, e++);
1298 switch (op) {
1299 case LYS_IFF_NOT:
1300 if (!r) {
1301 r += 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001302 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001303 break;
1304 case LYS_IFF_AND:
1305 case LYS_IFF_OR:
1306 if (!r) {
1307 r += 2;
1308 } else {
1309 r += 1;
1310 }
1311 break;
1312 case LYS_IFF_F:
1313 f++;
1314 if (r) {
1315 r--;
1316 }
1317 break;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001318 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001319 } while(r);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001320
Radek Krejci9ff0a922016-07-14 13:08:05 +02001321result:
1322 if (expr_size) {
1323 *expr_size = e;
1324 }
1325 if (feat_size) {
1326 *feat_size = f;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001327 }
1328}
1329
1330int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001331resolve_iffeature_compile(struct lys_iffeature *iffeat_expr, const char *value, struct lys_node *node,
Radek Krejci9de2c042016-10-19 16:53:06 +02001332 int infeature, struct unres_schema *unres)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001333{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001334 const char *c = value;
1335 int r, rc = EXIT_FAILURE;
Radek Krejci69b8d922016-07-27 13:13:41 +02001336 int i, j, last_not, checkversion = 0;
1337 unsigned int f_size = 0, expr_size = 0, f_exp = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001338 uint8_t op;
1339 struct iff_stack stack = {0, 0, NULL};
Radek Krejcicbb473e2016-09-16 14:48:32 +02001340 struct unres_iffeat_data *iff_data;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001341
Radek Krejci9ff0a922016-07-14 13:08:05 +02001342 assert(c);
1343
1344 if (isspace(c[0])) {
1345 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, c[0], c);
1346 return EXIT_FAILURE;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001347 }
1348
Radek Krejci9ff0a922016-07-14 13:08:05 +02001349 /* pre-parse the expression to get sizes for arrays, also do some syntax checks of the expression */
1350 for (i = j = last_not = 0; c[i]; i++) {
1351 if (c[i] == '(') {
Radek Krejci69b8d922016-07-27 13:13:41 +02001352 checkversion = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001353 j++;
1354 continue;
1355 } else if (c[i] == ')') {
1356 j--;
1357 continue;
1358 } else if (isspace(c[i])) {
1359 continue;
1360 }
1361
1362 if (!strncmp(&c[i], "not", r = 3) || !strncmp(&c[i], "and", r = 3) || !strncmp(&c[i], "or", r = 2)) {
1363 if (c[i + r] == '\0') {
Radek Krejcia98da3f2016-07-27 14:05:22 +02001364 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
Radek Krejci9ff0a922016-07-14 13:08:05 +02001365 return EXIT_FAILURE;
1366 } else if (!isspace(c[i + r])) {
1367 /* feature name starting with the not/and/or */
1368 last_not = 0;
1369 f_size++;
1370 } else if (c[i] == 'n') { /* not operation */
1371 if (last_not) {
1372 /* double not */
1373 expr_size = expr_size - 2;
1374 last_not = 0;
1375 } else {
1376 last_not = 1;
1377 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001378 } else { /* and, or */
1379 f_exp++;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001380 /* not a not operation */
1381 last_not = 0;
1382 }
1383 i += r;
1384 } else {
1385 f_size++;
1386 last_not = 0;
1387 }
1388 expr_size++;
1389
1390 while (!isspace(c[i])) {
1391 if (!c[i] || c[i] == ')') {
1392 i--;
1393 break;
1394 }
1395 i++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001396 }
1397 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001398 if (j || f_exp != f_size) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001399 /* not matching count of ( and ) */
1400 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1401 return EXIT_FAILURE;
1402 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001403
Radek Krejci69b8d922016-07-27 13:13:41 +02001404 if (checkversion || expr_size > 1) {
1405 /* check that we have 1.1 module */
1406 if (node->module->version != 2) {
1407 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1408 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "YANG 1.1 if-feature expression found in 1.0 module.");
1409 return EXIT_FAILURE;
1410 }
1411 }
1412
Radek Krejci9ff0a922016-07-14 13:08:05 +02001413 /* allocate the memory */
1414 iffeat_expr->expr = calloc((j = (expr_size / 4) + ((expr_size % 4) ? 1 : 0)), sizeof *iffeat_expr->expr);
Radek Krejcicbb473e2016-09-16 14:48:32 +02001415 iffeat_expr->features = calloc(f_size, sizeof *iffeat_expr->features);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001416 stack.size = expr_size;
1417 stack.stack = malloc(expr_size * sizeof *stack.stack);
1418 if (!stack.stack || !iffeat_expr->expr || !iffeat_expr->features) {
1419 LOGMEM;
1420 goto error;
1421 }
1422 f_size--; expr_size--; /* used as indexes from now */
1423
1424 for (i--; i >= 0; i--) {
1425 if (c[i] == ')') {
1426 /* push it on stack */
1427 iff_stack_push(&stack, LYS_IFF_RP);
1428 continue;
1429 } else if (c[i] == '(') {
1430 /* pop from the stack into result all operators until ) */
1431 while((op = iff_stack_pop(&stack)) != LYS_IFF_RP) {
1432 iff_setop(iffeat_expr->expr, op, expr_size--);
1433 }
1434 continue;
1435 } else if (isspace(c[i])) {
1436 continue;
1437 }
1438
1439 /* end operator or operand -> find beginning and get what is it */
1440 j = i + 1;
1441 while (i >= 0 && !isspace(c[i]) && c[i] != '(') {
1442 i--;
1443 }
1444 i++; /* get back by one step */
1445
1446 if (!strncmp(&c[i], "not ", 4)) {
1447 if (stack.index && stack.stack[stack.index - 1] == LYS_IFF_NOT) {
1448 /* double not */
1449 iff_stack_pop(&stack);
1450 } else {
1451 /* not has the highest priority, so do not pop from the stack
1452 * as in case of AND and OR */
1453 iff_stack_push(&stack, LYS_IFF_NOT);
1454 }
1455 } else if (!strncmp(&c[i], "and ", 4)) {
1456 /* as for OR - pop from the stack all operators with the same or higher
1457 * priority and store them to the result, then push the AND to the stack */
1458 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_AND) {
1459 op = iff_stack_pop(&stack);
1460 iff_setop(iffeat_expr->expr, op, expr_size--);
1461 }
1462 iff_stack_push(&stack, LYS_IFF_AND);
1463 } else if (!strncmp(&c[i], "or ", 3)) {
1464 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_OR) {
1465 op = iff_stack_pop(&stack);
1466 iff_setop(iffeat_expr->expr, op, expr_size--);
1467 }
1468 iff_stack_push(&stack, LYS_IFF_OR);
1469 } else {
1470 /* feature name, length is j - i */
1471
1472 /* add it to the result */
1473 iff_setop(iffeat_expr->expr, LYS_IFF_F, expr_size--);
1474
1475 /* now get the link to the feature definition. Since it can be
Radek Krejcicbb473e2016-09-16 14:48:32 +02001476 * forward referenced, we have to keep the feature name in auxiliary
1477 * structure passed into unres */
1478 iff_data = malloc(sizeof *iff_data);
1479 iff_data->node = node;
1480 iff_data->fname = lydict_insert(node->module->ctx, &c[i], j - i);
Radek Krejci9de2c042016-10-19 16:53:06 +02001481 iff_data->infeature = infeature;
Radek Krejcicbb473e2016-09-16 14:48:32 +02001482 r = unres_schema_add_node(node->module, unres, &iffeat_expr->features[f_size], UNRES_IFFEAT,
1483 (struct lys_node *)iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001484 f_size--;
1485
1486 if (r == -1) {
Pavol Vican4d084512016-09-29 16:38:12 +02001487 free(iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001488 goto error;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001489 }
1490 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001491 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001492 while (stack.index) {
1493 op = iff_stack_pop(&stack);
1494 iff_setop(iffeat_expr->expr, op, expr_size--);
1495 }
1496
1497 if (++expr_size || ++f_size) {
1498 /* not all expected operators and operands found */
1499 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1500 rc = EXIT_FAILURE;
1501 } else {
1502 rc = EXIT_SUCCESS;
1503 }
1504
1505error:
1506 /* cleanup */
1507 iff_stack_clean(&stack);
1508
1509 return rc;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001510}
1511
1512/**
Michal Vasko3edeaf72016-02-11 13:17:43 +01001513 * @brief Resolve (find) a data node based on a schema-nodeid.
1514 *
1515 * Used for resolving unique statements - so id is expected to be relative and local (without reference to a different
1516 * module).
1517 *
1518 */
1519struct lyd_node *
1520resolve_data_descendant_schema_nodeid(const char *nodeid, struct lyd_node *start)
1521{
1522 char *str, *token, *p;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001523 struct lyd_node *result = NULL, *iter;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001524 const struct lys_node *schema = NULL;
Radek Krejcicc217a62016-04-08 16:58:11 +02001525 int shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001526
1527 assert(nodeid && start);
1528
1529 if (nodeid[0] == '/') {
1530 return NULL;
1531 }
1532
1533 str = p = strdup(nodeid);
1534 if (!str) {
1535 LOGMEM;
1536 return NULL;
1537 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001538
Michal Vasko3edeaf72016-02-11 13:17:43 +01001539 while (p) {
1540 token = p;
1541 p = strchr(p, '/');
1542 if (p) {
1543 *p = '\0';
1544 p++;
1545 }
1546
Radek Krejci5da4eb62016-04-08 14:45:51 +02001547 if (p) {
1548 /* inner node */
Radek Krejcicc217a62016-04-08 16:58:11 +02001549 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema,
Radek Krejcif3c71de2016-04-11 12:45:46 +02001550 LYS_CONTAINER | LYS_CHOICE | LYS_CASE | LYS_LEAF, 0, 0, &schema)
Radek Krejci5da4eb62016-04-08 14:45:51 +02001551 || !schema) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001552 result = NULL;
1553 break;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001554 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001555
Radek Krejci5da4eb62016-04-08 14:45:51 +02001556 if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
1557 continue;
Michal Vaskodcf98e62016-05-05 17:53:53 +02001558 } else if (lys_parent(schema)->nodetype == LYS_CHOICE) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001559 /* shorthand case */
1560 if (!shorthand) {
1561 shorthand = 1;
Michal Vaskodcf98e62016-05-05 17:53:53 +02001562 schema = lys_parent(schema);
Radek Krejcicc217a62016-04-08 16:58:11 +02001563 continue;
1564 } else {
1565 shorthand = 0;
1566 if (schema->nodetype == LYS_LEAF) {
1567 /* should not be here, since we have leaf, which is not a shorthand nor final node */
1568 result = NULL;
1569 break;
1570 }
1571 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001572 }
1573 } else {
1574 /* final node */
Radek Krejcif3c71de2016-04-11 12:45:46 +02001575 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema, LYS_LEAF,
1576 shorthand ? 0 : 1, 0, &schema)
Radek Krejcicc217a62016-04-08 16:58:11 +02001577 || !schema) {
1578 result = NULL;
1579 break;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001580 }
1581 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001582 LY_TREE_FOR(result ? result->child : start, iter) {
1583 if (iter->schema == schema) {
1584 /* move in data tree according to returned schema */
1585 result = iter;
1586 break;
1587 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001588 }
Radek Krejcicc217a62016-04-08 16:58:11 +02001589 if (!iter) {
1590 /* instance not found */
1591 result = NULL;
1592 break;
1593 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001594 }
1595 free(str);
1596
1597 return result;
1598}
1599
Radek Krejcibdf92362016-04-08 14:43:34 +02001600/*
1601 * 0 - ok (done)
1602 * 1 - continue
1603 * 2 - break
1604 * -1 - error
1605 */
1606static int
Radek Krejcicc217a62016-04-08 16:58:11 +02001607schema_nodeid_siblingcheck(const struct lys_node *sibling, int8_t *shorthand, const char *id,
Radek Krejcibdf92362016-04-08 14:43:34 +02001608 const struct lys_module *module, const char *mod_name, int mod_name_len,
Radek Krejci0fa54e92016-09-14 14:01:05 +02001609 int implemented_mod, const struct lys_node **start)
Radek Krejcibdf92362016-04-08 14:43:34 +02001610{
1611 const struct lys_module *prefix_mod;
1612
1613 /* module check */
1614 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Radek Krejcidf46e222016-11-08 11:57:37 +01001615 if (prefix_mod && implemented_mod) {
Radek Krejci2eee5c02016-12-06 19:18:05 +01001616 prefix_mod = lys_implemented_module(prefix_mod);
Radek Krejci0fa54e92016-09-14 14:01:05 +02001617 }
Radek Krejcibdf92362016-04-08 14:43:34 +02001618 if (!prefix_mod) {
1619 return -1;
1620 }
1621 if (prefix_mod != lys_node_module(sibling)) {
1622 return 1;
1623 }
1624
1625 /* check for shorthand cases - then 'start' does not change */
Michal Vaskodcf98e62016-05-05 17:53:53 +02001626 if (lys_parent(sibling) && (lys_parent(sibling)->nodetype == LYS_CHOICE) && (sibling->nodetype != LYS_CASE)) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001627 if (*shorthand != -1) {
1628 *shorthand = *shorthand ? 0 : 1;
1629 }
Radek Krejcibdf92362016-04-08 14:43:34 +02001630 }
1631
1632 /* the result node? */
1633 if (!id[0]) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001634 if (*shorthand == 1) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001635 return 1;
1636 }
1637 return 0;
1638 }
1639
Radek Krejci3a130162016-11-07 16:21:20 +01001640 if (!(*shorthand)) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001641 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02001642 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001643 return -1;
1644 }
1645 *start = sibling->child;
1646 }
1647
1648 return 2;
1649}
1650
Radek Krejcidf46e222016-11-08 11:57:37 +01001651/* start - relative, module - absolute, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1
1652 * implement: 0 - do not change the implemented status of the affected modules, 1 - change implemented status of the affected modules
1653 */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001654int
1655resolve_augment_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_module *module,
Radek Krejcidf46e222016-11-08 11:57:37 +01001656 int implement, const struct lys_node **ret)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001657{
Radek Krejcidf46e222016-11-08 11:57:37 +01001658 const char *name, *mod_name, *mod_name_prev, *id;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001659 const struct lys_node *sibling;
1660 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001661 int8_t shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001662 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcidf46e222016-11-08 11:57:37 +01001663 const struct lys_module *start_mod, *aux_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001664
1665 assert(nodeid && (start || module) && !(start && module) && ret);
1666
1667 id = nodeid;
1668
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001669 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 +01001670 return ((id - nodeid) - r) + 1;
1671 }
1672 id += r;
1673
1674 if ((is_relative && !start) || (!is_relative && !module)) {
1675 return -1;
1676 }
1677
1678 /* descendant-schema-nodeid */
1679 if (is_relative) {
Michal Vasko4c06fd82016-02-17 13:43:38 +01001680 module = start_mod = start->module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001681
1682 /* absolute-schema-nodeid */
1683 } else {
1684 start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Radek Krejcidf46e222016-11-08 11:57:37 +01001685 if (start_mod != lys_main_module(module) && start_mod && !start_mod->implemented) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001686 /* if the submodule augments the mainmodule (or in general a module augments
1687 * itself, we don't want to search for the implemented module but augments
1688 * the module anyway. But when augmenting another module, we need the implemented
1689 * revision of the module if any */
Radek Krejci2eee5c02016-12-06 19:18:05 +01001690 aux_mod = lys_implemented_module(start_mod);
Radek Krejcidf46e222016-11-08 11:57:37 +01001691 if (!aux_mod->implemented && implement) {
1692 /* make the found module implemented */
1693 if (lys_set_implemented(aux_mod)) {
1694 return -1;
1695 }
1696 }
1697 start_mod = aux_mod;
1698 implement++;
Radek Krejci0fa54e92016-09-14 14:01:05 +02001699 }
Michal Vaskoe2905632016-02-11 15:42:24 +01001700 if (!start_mod) {
1701 return -1;
1702 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001703 start = start_mod->data;
1704 }
1705
1706 while (1) {
1707 sibling = NULL;
Radek Krejcidf46e222016-11-08 11:57:37 +01001708 mod_name_prev = mod_name;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001709 while ((sibling = lys_getnext(sibling, lys_parent(start), start_mod,
1710 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
1711 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001712 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001713 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len,
Radek Krejcidf46e222016-11-08 11:57:37 +01001714 implement, &start);
Radek Krejcibdf92362016-04-08 14:43:34 +02001715 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001716 *ret = sibling;
1717 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001718 } else if (r == 1) {
1719 continue;
1720 } else if (r == 2) {
1721 break;
1722 } else {
1723 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001724 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001725 }
1726 }
1727
1728 /* no match */
1729 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001730 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001731 return EXIT_SUCCESS;
1732 }
1733
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001734 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001735 return ((id - nodeid) - r) + 1;
1736 }
1737 id += r;
Radek Krejcidf46e222016-11-08 11:57:37 +01001738
1739 if ((mod_name && mod_name_prev && strncmp(mod_name, mod_name_prev, mod_name_len + 1)) ||
1740 (mod_name != mod_name_prev && (!mod_name || !mod_name_prev))) {
1741 /* we are getting into another module (augment) */
1742 if (implement) {
1743 /* we have to check that also target modules are implemented, if not, we have to change it */
1744 aux_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
1745 if (!aux_mod) {
1746 return -1;
1747 }
1748 if (!aux_mod->implemented) {
Radek Krejci2eee5c02016-12-06 19:18:05 +01001749 aux_mod = lys_implemented_module(aux_mod);
Radek Krejcidf46e222016-11-08 11:57:37 +01001750 if (!aux_mod->implemented) {
1751 /* make the found module implemented */
1752 if (lys_set_implemented(aux_mod)) {
1753 return -1;
1754 }
1755 }
1756 }
1757 } else {
1758 /* we are not implementing the module itself, so the augments outside the module are ignored */
1759 *ret = NULL;
1760 return EXIT_SUCCESS;
1761 }
1762 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001763 }
1764
1765 /* cannot get here */
1766 LOGINT;
1767 return -1;
1768}
1769
Radek Krejcif3c71de2016-04-11 12:45:46 +02001770/* unique, refine,
1771 * >0 - unexpected char on position (ret - 1),
1772 * 0 - ok (but ret can still be NULL),
1773 * -1 - error,
1774 * -2 - violated no_innerlist */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001775int
1776resolve_descendant_schema_nodeid(const char *nodeid, const struct lys_node *start, int ret_nodetype,
Radek Krejcif3c71de2016-04-11 12:45:46 +02001777 int check_shorthand, int no_innerlist, const struct lys_node **ret)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001778{
1779 const char *name, *mod_name, *id;
1780 const struct lys_node *sibling;
1781 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001782 int8_t shorthand = check_shorthand ? 0 : -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001783 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcibdf92362016-04-08 14:43:34 +02001784 const struct lys_module *module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001785
1786 assert(nodeid && start && ret);
1787 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1788
1789 id = nodeid;
1790 module = start->module;
1791
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001792 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 +01001793 return ((id - nodeid) - r) + 1;
1794 }
1795 id += r;
1796
1797 if (!is_relative) {
1798 return -1;
1799 }
1800
1801 while (1) {
1802 sibling = NULL;
1803 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
1804 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE))) {
1805 /* name match */
1806 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001807 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len, 0, &start);
Radek Krejcibdf92362016-04-08 14:43:34 +02001808 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001809 if (!(sibling->nodetype & ret_nodetype)) {
1810 /* wrong node type, too bad */
1811 continue;
1812 }
1813 *ret = sibling;
1814 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001815 } else if (r == 1) {
1816 continue;
1817 } else if (r == 2) {
1818 break;
1819 } else {
1820 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001821 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001822 }
1823 }
1824
1825 /* no match */
1826 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001827 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001828 return EXIT_SUCCESS;
Radek Krejcif3c71de2016-04-11 12:45:46 +02001829 } else if (no_innerlist && sibling->nodetype == LYS_LIST) {
1830 *ret = NULL;
1831 return -2;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001832 }
1833
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001834 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 +01001835 return ((id - nodeid) - r) + 1;
1836 }
1837 id += r;
1838 }
1839
1840 /* cannot get here */
1841 LOGINT;
1842 return -1;
1843}
1844
1845/* choice default */
1846int
1847resolve_choice_default_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node **ret)
1848{
1849 /* cannot actually be a path */
1850 if (strchr(nodeid, '/')) {
1851 return -1;
1852 }
1853
Radek Krejcif3c71de2016-04-11 12:45:46 +02001854 return resolve_descendant_schema_nodeid(nodeid, start, LYS_NO_RPC_NOTIF_NODE, 1, 0, ret);
Michal Vasko3edeaf72016-02-11 13:17:43 +01001855}
1856
1857/* uses, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1858static int
1859resolve_uses_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node_grp **ret)
1860{
1861 const struct lys_module *module;
1862 const char *mod_prefix, *name;
1863 int i, mod_prefix_len, nam_len;
1864
1865 /* parse the identifier, it must be parsed on one call */
1866 if (((i = parse_node_identifier(nodeid, &mod_prefix, &mod_prefix_len, &name, &nam_len)) < 1) || nodeid[i]) {
1867 return -i + 1;
1868 }
1869
1870 module = lys_get_import_module(start->module, mod_prefix, mod_prefix_len, NULL, 0);
1871 if (!module) {
1872 return -1;
1873 }
1874 if (module != start->module) {
1875 start = module->data;
1876 }
1877
1878 *ret = lys_find_grouping_up(name, (struct lys_node *)start);
1879
1880 return EXIT_SUCCESS;
1881}
1882
1883int
1884resolve_absolute_schema_nodeid(const char *nodeid, const struct lys_module *module, int ret_nodetype,
1885 const struct lys_node **ret)
1886{
1887 const char *name, *mod_name, *id;
1888 const struct lys_node *sibling, *start;
1889 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001890 int8_t shorthand = 0;
Radek Krejcibdf92362016-04-08 14:43:34 +02001891 const struct lys_module *abs_start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001892
1893 assert(nodeid && module && ret);
1894 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1895
1896 id = nodeid;
1897 start = module->data;
1898
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001899 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 +01001900 return ((id - nodeid) - r) + 1;
1901 }
1902 id += r;
1903
1904 if (is_relative) {
1905 return -1;
1906 }
1907
1908 abs_start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001909 if (!abs_start_mod) {
1910 return -1;
1911 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001912
1913 while (1) {
1914 sibling = NULL;
1915 while ((sibling = lys_getnext(sibling, lys_parent(start), abs_start_mod, LYS_GETNEXT_WITHCHOICE
1916 | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_WITHGROUPING))) {
1917 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001918 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001919 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len, 0, &start);
Radek Krejcibdf92362016-04-08 14:43:34 +02001920 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001921 if (!(sibling->nodetype & ret_nodetype)) {
1922 /* wrong node type, too bad */
1923 continue;
1924 }
1925 *ret = sibling;
1926 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001927 } else if (r == 1) {
1928 continue;
1929 } else if (r == 2) {
1930 break;
1931 } else {
1932 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001933 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001934 }
1935 }
1936
1937 /* no match */
1938 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001939 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001940 return EXIT_SUCCESS;
1941 }
1942
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001943 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 +01001944 return ((id - nodeid) - r) + 1;
1945 }
1946 id += r;
1947 }
1948
1949 /* cannot get here */
1950 LOGINT;
1951 return -1;
1952}
1953
Michal Vaskoe733d682016-03-14 09:08:27 +01001954static int
Michal Vasko3547c532016-03-14 09:40:50 +01001955resolve_json_schema_list_predicate(const char *predicate, const struct lys_node_list *list, int *parsed)
Michal Vaskoe733d682016-03-14 09:08:27 +01001956{
1957 const char *name;
1958 int nam_len, has_predicate, i;
1959
Michal Vasko7b54f7e2016-05-03 15:07:31 +02001960 if (((i = parse_schema_json_predicate(predicate, &name, &nam_len, NULL, NULL, &has_predicate)) < 1)
1961 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001962 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-i], &predicate[-i]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001963 return -1;
1964 }
1965
1966 predicate += i;
1967 *parsed += i;
1968
Michal Vasko58c2aab2017-01-05 10:02:05 +01001969 if (!isdigit(name[0])) {
1970 for (i = 0; i < list->keys_size; ++i) {
1971 if (!strncmp(list->keys[i]->name, name, nam_len) && !list->keys[i]->name[nam_len]) {
1972 break;
1973 }
Michal Vaskoe733d682016-03-14 09:08:27 +01001974 }
Michal Vaskoe733d682016-03-14 09:08:27 +01001975
Michal Vasko58c2aab2017-01-05 10:02:05 +01001976 if (i == list->keys_size) {
1977 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
1978 return -1;
1979 }
Michal Vaskoe733d682016-03-14 09:08:27 +01001980 }
1981
1982 /* more predicates? */
1983 if (has_predicate) {
Michal Vasko3547c532016-03-14 09:40:50 +01001984 return resolve_json_schema_list_predicate(predicate, list, parsed);
Michal Vaskoe733d682016-03-14 09:08:27 +01001985 }
1986
1987 return 0;
1988}
1989
Michal Vasko8d26e5c2016-09-08 10:03:49 +02001990/* cannot return LYS_GROUPING, LYS_AUGMENT, LYS_USES, logs directly */
Michal Vaskoe733d682016-03-14 09:08:27 +01001991const struct lys_node *
Michal Vasko8d26e5c2016-09-08 10:03:49 +02001992resolve_json_nodeid(const char *nodeid, struct ly_ctx *ctx, const struct lys_node *start)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001993{
Michal Vasko10728b52016-04-07 14:26:29 +02001994 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001995 const char *name, *mod_name, *id;
Michal Vasko3547c532016-03-14 09:40:50 +01001996 const struct lys_node *sibling;
Radek Krejcibdf92362016-04-08 14:43:34 +02001997 int r, nam_len, mod_name_len, is_relative = -1, has_predicate, shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001998 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vaskoe733d682016-03-14 09:08:27 +01001999 const struct lys_module *prefix_mod, *module, *prev_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002000
Michal Vasko3547c532016-03-14 09:40:50 +01002001 assert(nodeid && (ctx || start));
2002 if (!ctx) {
2003 ctx = start->module->ctx;
2004 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01002005
2006 id = nodeid;
2007
Michal Vaskoe733d682016-03-14 09:08:27 +01002008 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 +01002009 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002010 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002011 }
2012 id += r;
2013
2014 if (is_relative) {
Michal Vasko3547c532016-03-14 09:40:50 +01002015 assert(start);
2016 start = start->child;
2017 if (!start) {
2018 /* no descendants, fail for sure */
Michal Vasko10728b52016-04-07 14:26:29 +02002019 str = strndup(nodeid, (name + nam_len) - nodeid);
2020 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
2021 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002022 return NULL;
2023 }
2024 module = start->module;
2025 } else {
2026 if (!mod_name) {
Michal Vasko10728b52016-04-07 14:26:29 +02002027 str = strndup(nodeid, (name + nam_len) - nodeid);
2028 LOGVAL(LYE_PATH_MISSMOD, LY_VLOG_STR, nodeid);
2029 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002030 return NULL;
Michal Vasko971a3ca2016-04-01 13:09:29 +02002031 } else if (mod_name_len > LY_BUF_SIZE - 1) {
2032 LOGINT;
2033 return NULL;
Michal Vasko3547c532016-03-14 09:40:50 +01002034 }
2035
Michal Vasko971a3ca2016-04-01 13:09:29 +02002036 if (ly_buf_used && module_name[0]) {
2037 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2038 }
2039 ly_buf_used++;
2040
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002041 memmove(module_name, mod_name, mod_name_len);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002042 module_name[mod_name_len] = '\0';
2043 module = ly_ctx_get_module(ctx, module_name, NULL);
2044
2045 if (buf_backup) {
2046 /* return previous internal buffer content */
2047 strcpy(module_name, buf_backup);
2048 free(buf_backup);
2049 buf_backup = NULL;
2050 }
2051 ly_buf_used--;
2052
Michal Vasko3547c532016-03-14 09:40:50 +01002053 if (!module) {
Michal Vasko10728b52016-04-07 14:26:29 +02002054 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2055 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2056 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002057 return NULL;
2058 }
2059 start = module->data;
2060
2061 /* now it's as if there was no module name */
2062 mod_name = NULL;
2063 mod_name_len = 0;
Michal Vaskoe733d682016-03-14 09:08:27 +01002064 }
2065
Michal Vaskoe733d682016-03-14 09:08:27 +01002066 prev_mod = module;
2067
Michal Vasko3edeaf72016-02-11 13:17:43 +01002068 while (1) {
2069 sibling = NULL;
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002070 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
2071 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002072 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02002073 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002074 /* module check */
2075 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002076 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko8757e7c2016-03-15 10:41:30 +01002077 LOGINT;
2078 return NULL;
2079 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002080
2081 if (ly_buf_used && module_name[0]) {
2082 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2083 }
2084 ly_buf_used++;
2085
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002086 memmove(module_name, mod_name, mod_name_len);
Michal Vasko8757e7c2016-03-15 10:41:30 +01002087 module_name[mod_name_len] = '\0';
2088 /* will also find an augment module */
2089 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002090
2091 if (buf_backup) {
2092 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002093 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002094 free(buf_backup);
2095 buf_backup = NULL;
2096 }
2097 ly_buf_used--;
2098
Michal Vasko3edeaf72016-02-11 13:17:43 +01002099 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002100 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2101 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2102 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002103 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002104 }
2105 } else {
2106 prefix_mod = prev_mod;
2107 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01002108 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002109 continue;
2110 }
2111
Michal Vaskoe733d682016-03-14 09:08:27 +01002112 /* do we have some predicates on it? */
2113 if (has_predicate) {
2114 r = 0;
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002115 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
2116 if ((r = parse_schema_json_predicate(id, NULL, NULL, NULL, NULL, &has_predicate)) < 1) {
2117 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2118 return NULL;
2119 }
2120 } else if (sibling->nodetype == LYS_LIST) {
2121 if (resolve_json_schema_list_predicate(id, (const struct lys_node_list *)sibling, &r)) {
2122 return NULL;
2123 }
2124 } else {
Michal Vasko43c300e2016-03-22 12:54:27 +01002125 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vaskoe733d682016-03-14 09:08:27 +01002126 return NULL;
Michal Vaskoe733d682016-03-14 09:08:27 +01002127 }
2128 id += r;
2129 }
2130
Radek Krejcibdf92362016-04-08 14:43:34 +02002131 /* check for shorthand cases - then 'start' does not change */
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002132 if (lys_parent(sibling) && (lys_parent(sibling)->nodetype == LYS_CHOICE) && (sibling->nodetype != LYS_CASE)) {
Radek Krejcibdf92362016-04-08 14:43:34 +02002133 shorthand = ~shorthand;
2134 }
2135
Michal Vasko3edeaf72016-02-11 13:17:43 +01002136 /* the result node? */
2137 if (!id[0]) {
Radek Krejcibdf92362016-04-08 14:43:34 +02002138 if (shorthand) {
2139 /* wrong path for shorthand */
Michal Vasko025e0452016-05-17 16:14:20 +02002140 str = strndup(nodeid, (name + nam_len) - nodeid);
2141 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
Michal Vasko51e5c582017-01-19 14:16:39 +01002142 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Schema shorthand case path must include the virtual case statement.");
Radek Krejci9a5fccc2016-05-18 15:44:58 +02002143 free(str);
Michal Vasko025e0452016-05-17 16:14:20 +02002144 return NULL;
Radek Krejcibdf92362016-04-08 14:43:34 +02002145 }
Michal Vaskoe733d682016-03-14 09:08:27 +01002146 return sibling;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002147 }
2148
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002149 if (!shorthand) {
Michal Vasko7dc71d02016-03-15 10:42:28 +01002150 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002151 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002152 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko7dc71d02016-03-15 10:42:28 +01002153 return NULL;
2154 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01002155 start = sibling->child;
2156 }
2157
2158 /* update prev mod */
2159 prev_mod = start->module;
2160 break;
2161 }
2162 }
2163
2164 /* no match */
2165 if (!sibling) {
Michal Vasko10728b52016-04-07 14:26:29 +02002166 str = strndup(nodeid, (name + nam_len) - nodeid);
2167 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
2168 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002169 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002170 }
2171
Michal Vaskoe733d682016-03-14 09:08:27 +01002172 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 +01002173 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002174 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002175 }
2176 id += r;
2177 }
2178
2179 /* cannot get here */
2180 LOGINT;
Michal Vaskoe733d682016-03-14 09:08:27 +01002181 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002182}
2183
Michal Vasko22448d32016-03-16 13:17:29 +01002184static int
Michal Vasko58c2aab2017-01-05 10:02:05 +01002185resolve_partial_json_data_list_predicate(const char *predicate, const char *node_name, struct lyd_node *node,
2186 int position, int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002187{
Michal Vasko9ba34de2016-12-07 12:21:19 +01002188 const char *name, *value, *key_val;
Michal Vasko22448d32016-03-16 13:17:29 +01002189 int nam_len, val_len, has_predicate = 1, r;
2190 uint16_t i;
Michal Vaskof29903d2016-04-18 13:13:10 +02002191 struct lyd_node_leaf_list *key;
Michal Vasko22448d32016-03-16 13:17:29 +01002192
Radek Krejci61a86c62016-03-24 11:06:44 +01002193 assert(node);
Michal Vasko22448d32016-03-16 13:17:29 +01002194 assert(node->schema->nodetype == LYS_LIST);
2195
Michal Vasko53adfc72017-01-06 10:39:10 +01002196 /* is the predicate a number? */
2197 if (((r = parse_schema_json_predicate(predicate, &name, &nam_len, &value, &val_len, &has_predicate)) < 1)
2198 || !strncmp(name, ".", nam_len)) {
2199 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
2200 return -1;
2201 }
2202
2203 if (isdigit(name[0])) {
2204 if (position == atoi(name)) {
2205 /* match */
2206 *parsed += r;
2207 return 0;
2208 } else {
2209 /* not a match */
2210 return 1;
2211 }
2212 }
2213
2214 if (!((struct lys_node_list *)node->schema)->keys_size) {
2215 /* no keys in schema - causes an error later */
2216 return 0;
2217 }
2218
Michal Vaskof29903d2016-04-18 13:13:10 +02002219 key = (struct lyd_node_leaf_list *)node->child;
Michal Vasko53adfc72017-01-06 10:39:10 +01002220 if (!key) {
2221 /* it is not a position, so we need a key for it to be a match */
2222 return 1;
2223 }
2224
2225 /* go through all the keys */
2226 i = 0;
2227 goto check_parsed_values;
2228
2229 for (; i < ((struct lys_node_list *)node->schema)->keys_size; ++i) {
Michal Vasko22448d32016-03-16 13:17:29 +01002230 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002231 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, node_name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002232 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002233 }
2234
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002235 if (((r = parse_schema_json_predicate(predicate, &name, &nam_len, &value, &val_len, &has_predicate)) < 1)
2236 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002237 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
Michal Vaskof29903d2016-04-18 13:13:10 +02002238 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002239 }
2240
Michal Vasko53adfc72017-01-06 10:39:10 +01002241check_parsed_values:
Michal Vasko22448d32016-03-16 13:17:29 +01002242 predicate += r;
2243 *parsed += r;
2244
Michal Vaskof29903d2016-04-18 13:13:10 +02002245 if (strncmp(key->schema->name, name, nam_len) || key->schema->name[nam_len]) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002246 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002247 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002248 }
2249
Michal Vasko9ba34de2016-12-07 12:21:19 +01002250 /* make value canonical */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01002251 if ((key->value_type & LY_TYPE_IDENT)
Michal Vasko6a938d62016-12-21 09:21:30 +01002252 && !strncmp(key->value_str, lyd_node_module(node)->name, strlen(lyd_node_module(node)->name))
2253 && (key->value_str[strlen(lyd_node_module(node)->name)] == ':')) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002254 key_val = key->value_str + strlen(lyd_node_module(node)->name) + 1;
2255 } else {
2256 key_val = key->value_str;
2257 }
2258
Michal Vasko22448d32016-03-16 13:17:29 +01002259 /* value does not match */
Michal Vasko9ba34de2016-12-07 12:21:19 +01002260 if (strncmp(key_val, value, val_len) || key_val[val_len]) {
Michal Vasko22448d32016-03-16 13:17:29 +01002261 return 1;
2262 }
Michal Vaskof29903d2016-04-18 13:13:10 +02002263
2264 key = (struct lyd_node_leaf_list *)key->next;
Michal Vasko22448d32016-03-16 13:17:29 +01002265 }
2266
2267 if (has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002268 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko22448d32016-03-16 13:17:29 +01002269 return -1;
2270 }
2271
2272 return 0;
2273}
2274
Radek Krejci45826012016-08-24 15:07:57 +02002275/**
2276 * @brief get the closest parent of the node (or the node itself) identified by the nodeid (path)
2277 *
2278 * @param[in] nodeid Node data path to find
2279 * @param[in] llist_value If the \p nodeid identifies leaf-list, this is expected value of the leaf-list instance.
2280 * @param[in] options Bitmask of options flags, see @ref pathoptions.
2281 * @param[out] parsed Number of characters processed in \p id
2282 * @return The closes parent (or the node itself) from the path
2283 */
Michal Vasko22448d32016-03-16 13:17:29 +01002284struct lyd_node *
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002285resolve_partial_json_data_nodeid(const char *nodeid, const char *llist_value, struct lyd_node *start, int options,
2286 int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002287{
Michal Vasko10728b52016-04-07 14:26:29 +02002288 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko9ba34de2016-12-07 12:21:19 +01002289 const char *id, *mod_name, *name, *pred_name, *data_val;
Michal Vasko58c2aab2017-01-05 10:02:05 +01002290 int r, ret, mod_name_len, nam_len, is_relative = -1, list_instance_position;
Michal Vasko9ba34de2016-12-07 12:21:19 +01002291 int has_predicate, last_parsed, llval_len, pred_name_len, last_has_pred;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002292 struct lyd_node *sibling, *last_match = NULL;
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002293 struct lyd_node_leaf_list *llist;
Michal Vasko22448d32016-03-16 13:17:29 +01002294 const struct lys_module *prefix_mod, *prev_mod;
2295 struct ly_ctx *ctx;
2296
2297 assert(nodeid && start && parsed);
2298
2299 ctx = start->schema->module->ctx;
2300 id = nodeid;
2301
2302 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 +01002303 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002304 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002305 return NULL;
2306 }
2307 id += r;
2308 /* add it to parsed only after the data node was actually found */
2309 last_parsed = r;
2310
2311 if (is_relative) {
Michal Vasko1adc7242016-11-16 11:05:28 +01002312 prev_mod = lyd_node_module(start);
Michal Vasko22448d32016-03-16 13:17:29 +01002313 start = start->child;
2314 } else {
2315 for (; start->parent; start = start->parent);
Michal Vasko1adc7242016-11-16 11:05:28 +01002316 prev_mod = lyd_node_module(start);
Michal Vasko22448d32016-03-16 13:17:29 +01002317 }
2318
2319 while (1) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002320 list_instance_position = 0;
2321
Michal Vasko22448d32016-03-16 13:17:29 +01002322 LY_TREE_FOR(start, sibling) {
Michal Vasko945b96b2016-10-18 11:49:12 +02002323 /* RPC/action data check, return simply invalid argument, because the data tree is invalid */
Michal Vasko2411b942016-03-23 13:50:03 +01002324 if (lys_parent(sibling->schema)) {
2325 if (options & LYD_PATH_OPT_OUTPUT) {
2326 if (lys_parent(sibling->schema)->nodetype == LYS_INPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002327 LOGERR(LY_EINVAL, "Provided data tree includes some RPC input nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002328 *parsed = -1;
2329 return NULL;
2330 }
2331 } else {
2332 if (lys_parent(sibling->schema)->nodetype == LYS_OUTPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002333 LOGERR(LY_EINVAL, "Provided data tree includes some RPC output nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002334 *parsed = -1;
2335 return NULL;
2336 }
2337 }
2338 }
2339
Michal Vasko22448d32016-03-16 13:17:29 +01002340 /* name match */
2341 if (!strncmp(name, sibling->schema->name, nam_len) && !sibling->schema->name[nam_len]) {
2342
2343 /* module check */
2344 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002345 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko22448d32016-03-16 13:17:29 +01002346 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002347 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002348 return NULL;
2349 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002350
2351 if (ly_buf_used && module_name[0]) {
2352 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2353 }
2354 ly_buf_used++;
2355
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002356 memmove(module_name, mod_name, mod_name_len);
Michal Vasko22448d32016-03-16 13:17:29 +01002357 module_name[mod_name_len] = '\0';
2358 /* will also find an augment module */
2359 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002360
2361 if (buf_backup) {
2362 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002363 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002364 free(buf_backup);
2365 buf_backup = NULL;
2366 }
2367 ly_buf_used--;
2368
Michal Vasko22448d32016-03-16 13:17:29 +01002369 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002370 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2371 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2372 free(str);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002373 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002374 return NULL;
2375 }
2376 } else {
2377 prefix_mod = prev_mod;
2378 }
Michal Vasko1adc7242016-11-16 11:05:28 +01002379 if (prefix_mod != lyd_node_module(sibling)) {
Michal Vasko22448d32016-03-16 13:17:29 +01002380 continue;
2381 }
2382
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002383 /* leaf-list, did we find it with the correct value or not? */
Michal Vasko22448d32016-03-16 13:17:29 +01002384 if (sibling->schema->nodetype == LYS_LEAFLIST) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002385 llist = (struct lyd_node_leaf_list *)sibling;
2386
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002387 last_has_pred = 0;
Michal Vaskof0a50972016-10-19 11:33:55 +02002388 if (has_predicate) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002389 if ((r = parse_schema_json_predicate(id, &pred_name, &pred_name_len, &llist_value, &llval_len, &last_has_pred)) < 1) {
Michal Vaskof0a50972016-10-19 11:33:55 +02002390 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2391 *parsed = -1;
2392 return NULL;
2393 }
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002394 if ((pred_name[0] != '.') || (pred_name_len != 1)) {
2395 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[1], id + 1);
2396 *parsed = -1;
2397 return NULL;
2398 }
Michal Vaskof0a50972016-10-19 11:33:55 +02002399 } else {
2400 r = 0;
2401 if (llist_value) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002402 llval_len = strlen(llist_value);
Michal Vaskof0a50972016-10-19 11:33:55 +02002403 }
2404 }
2405
Michal Vasko9ba34de2016-12-07 12:21:19 +01002406 /* make value canonical */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01002407 if ((llist->value_type & LY_TYPE_IDENT)
Michal Vasko6a938d62016-12-21 09:21:30 +01002408 && !strncmp(llist->value_str, lyd_node_module(sibling)->name, strlen(lyd_node_module(sibling)->name))
2409 && (llist->value_str[strlen(lyd_node_module(sibling)->name)] == ':')) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002410 data_val = llist->value_str + strlen(lyd_node_module(sibling)->name) + 1;
2411 } else {
2412 data_val = llist->value_str;
2413 }
2414
2415 if ((!llist_value && data_val && data_val[0])
2416 || (llist_value && (strncmp(llist_value, data_val, llval_len) || data_val[llval_len]))) {
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002417 continue;
2418 }
Michal Vasko9ba34de2016-12-07 12:21:19 +01002419
Michal Vaskof0a50972016-10-19 11:33:55 +02002420 id += r;
2421 last_parsed += r;
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002422 has_predicate = last_has_pred;
Michal Vaskof0a50972016-10-19 11:33:55 +02002423
Radek Krejci45826012016-08-24 15:07:57 +02002424 } else if (sibling->schema->nodetype == LYS_LIST) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002425 /* list, we likely need predicates'n'stuff then, but if without a predicate, we are always creating it */
Michal Vasko22448d32016-03-16 13:17:29 +01002426 if (!has_predicate) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002427 /* none match */
2428 return last_match;
Michal Vasko22448d32016-03-16 13:17:29 +01002429 }
Michal Vasko58c2aab2017-01-05 10:02:05 +01002430
2431 ++list_instance_position;
2432 r = 0;
2433 ret = resolve_partial_json_data_list_predicate(id, name, sibling, list_instance_position, &r);
Michal Vasko22448d32016-03-16 13:17:29 +01002434 if (ret == -1) {
Michal Vasko238bd2f2016-03-23 09:39:01 +01002435 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002436 return NULL;
2437 } else if (ret == 1) {
2438 /* this list instance does not match */
2439 continue;
2440 }
2441 id += r;
2442 last_parsed += r;
2443 }
2444
2445 *parsed += last_parsed;
2446
2447 /* the result node? */
2448 if (!id[0]) {
2449 return sibling;
2450 }
2451
2452 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002453 if (sibling->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002454 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002455 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002456 return NULL;
2457 }
Michal Vaskoc6c52cf2016-03-29 11:53:04 +02002458 last_match = sibling;
Michal Vaskofc11b682016-11-18 09:52:41 +01002459 prev_mod = lyd_node_module(sibling);
Michal Vasko22448d32016-03-16 13:17:29 +01002460 start = sibling->child;
Michal Vasko22448d32016-03-16 13:17:29 +01002461 break;
2462 }
2463 }
2464
2465 /* no match, return last match */
2466 if (!sibling) {
2467 return last_match;
2468 }
2469
2470 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 +01002471 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002472 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002473 return NULL;
2474 }
2475 id += r;
2476 last_parsed = r;
2477 }
2478
2479 /* cannot get here */
2480 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002481 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002482 return NULL;
2483}
2484
Michal Vasko3edeaf72016-02-11 13:17:43 +01002485/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02002486 * @brief Resolves length or range intervals. Does not log.
Michal Vaskoaeb51802016-04-11 10:58:47 +02002487 * Syntax is assumed to be correct, *ret MUST be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002488 *
Michal Vaskoaeb51802016-04-11 10:58:47 +02002489 * @param[in] str_restr Restriction as a string.
2490 * @param[in] type Type of the restriction.
2491 * @param[out] ret Final interval structure that starts with
2492 * the interval of the initial type, continues with intervals
2493 * of any superior types derived from the initial one, and
2494 * finishes with intervals from our \p type.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002495 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002496 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002497 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002498int
Michal Vaskoaeb51802016-04-11 10:58:47 +02002499resolve_len_ran_interval(const char *str_restr, struct lys_type *type, struct len_ran_intv **ret)
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002500{
2501 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002502 int kind;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002503 int64_t local_smin, local_smax, local_fmin, local_fmax;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002504 uint64_t local_umin, local_umax;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002505 uint8_t local_fdig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002506 const char *seg_ptr, *ptr;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002507 struct len_ran_intv *local_intv = NULL, *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002508
2509 switch (type->base) {
2510 case LY_TYPE_BINARY:
2511 kind = 0;
2512 local_umin = 0;
2513 local_umax = 18446744073709551615UL;
2514
2515 if (!str_restr && type->info.binary.length) {
2516 str_restr = type->info.binary.length->expr;
2517 }
2518 break;
2519 case LY_TYPE_DEC64:
2520 kind = 2;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002521 local_fmin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2522 local_fmax = __INT64_C(9223372036854775807);
2523 local_fdig = type->info.dec64.dig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002524
2525 if (!str_restr && type->info.dec64.range) {
2526 str_restr = type->info.dec64.range->expr;
2527 }
2528 break;
2529 case LY_TYPE_INT8:
2530 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002531 local_smin = __INT64_C(-128);
2532 local_smax = __INT64_C(127);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002533
2534 if (!str_restr && type->info.num.range) {
2535 str_restr = type->info.num.range->expr;
2536 }
2537 break;
2538 case LY_TYPE_INT16:
2539 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002540 local_smin = __INT64_C(-32768);
2541 local_smax = __INT64_C(32767);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002542
2543 if (!str_restr && type->info.num.range) {
2544 str_restr = type->info.num.range->expr;
2545 }
2546 break;
2547 case LY_TYPE_INT32:
2548 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002549 local_smin = __INT64_C(-2147483648);
2550 local_smax = __INT64_C(2147483647);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002551
2552 if (!str_restr && type->info.num.range) {
2553 str_restr = type->info.num.range->expr;
2554 }
2555 break;
2556 case LY_TYPE_INT64:
2557 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002558 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2559 local_smax = __INT64_C(9223372036854775807);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002560
2561 if (!str_restr && type->info.num.range) {
2562 str_restr = type->info.num.range->expr;
2563 }
2564 break;
2565 case LY_TYPE_UINT8:
2566 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002567 local_umin = __UINT64_C(0);
2568 local_umax = __UINT64_C(255);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002569
2570 if (!str_restr && type->info.num.range) {
2571 str_restr = type->info.num.range->expr;
2572 }
2573 break;
2574 case LY_TYPE_UINT16:
2575 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002576 local_umin = __UINT64_C(0);
2577 local_umax = __UINT64_C(65535);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002578
2579 if (!str_restr && type->info.num.range) {
2580 str_restr = type->info.num.range->expr;
2581 }
2582 break;
2583 case LY_TYPE_UINT32:
2584 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002585 local_umin = __UINT64_C(0);
2586 local_umax = __UINT64_C(4294967295);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002587
2588 if (!str_restr && type->info.num.range) {
2589 str_restr = type->info.num.range->expr;
2590 }
2591 break;
2592 case LY_TYPE_UINT64:
2593 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002594 local_umin = __UINT64_C(0);
2595 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002596
2597 if (!str_restr && type->info.num.range) {
2598 str_restr = type->info.num.range->expr;
2599 }
2600 break;
2601 case LY_TYPE_STRING:
2602 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002603 local_umin = __UINT64_C(0);
2604 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002605
2606 if (!str_restr && type->info.str.length) {
2607 str_restr = type->info.str.length->expr;
2608 }
2609 break;
2610 default:
2611 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002612 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002613 }
2614
2615 /* process superior types */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002616 if (type->der) {
2617 if (resolve_len_ran_interval(NULL, &type->der->type, &intv)) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002618 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002619 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02002620 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002621 assert(!intv || (intv->kind == kind));
2622 }
2623
2624 if (!str_restr) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002625 /* we do not have any restriction, return superior ones */
2626 *ret = intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002627 return EXIT_SUCCESS;
2628 }
2629
2630 /* adjust local min and max */
2631 if (intv) {
2632 tmp_intv = intv;
2633
2634 if (kind == 0) {
2635 local_umin = tmp_intv->value.uval.min;
2636 } else if (kind == 1) {
2637 local_smin = tmp_intv->value.sval.min;
2638 } else if (kind == 2) {
2639 local_fmin = tmp_intv->value.fval.min;
2640 }
2641
2642 while (tmp_intv->next) {
2643 tmp_intv = tmp_intv->next;
2644 }
2645
2646 if (kind == 0) {
2647 local_umax = tmp_intv->value.uval.max;
2648 } else if (kind == 1) {
2649 local_smax = tmp_intv->value.sval.max;
2650 } else if (kind == 2) {
2651 local_fmax = tmp_intv->value.fval.max;
2652 }
2653 }
2654
2655 /* finally parse our restriction */
2656 seg_ptr = str_restr;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002657 tmp_intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002658 while (1) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002659 if (!tmp_local_intv) {
2660 assert(!local_intv);
2661 local_intv = malloc(sizeof *local_intv);
2662 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002663 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002664 tmp_local_intv->next = malloc(sizeof *tmp_local_intv);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002665 tmp_local_intv = tmp_local_intv->next;
2666 }
Michal Vasko253035f2015-12-17 16:58:13 +01002667 if (!tmp_local_intv) {
2668 LOGMEM;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002669 goto error;
Michal Vasko253035f2015-12-17 16:58:13 +01002670 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002671
2672 tmp_local_intv->kind = kind;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002673 tmp_local_intv->type = type;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002674 tmp_local_intv->next = NULL;
2675
2676 /* min */
2677 ptr = seg_ptr;
2678 while (isspace(ptr[0])) {
2679 ++ptr;
2680 }
2681 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2682 if (kind == 0) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002683 tmp_local_intv->value.uval.min = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002684 } else if (kind == 1) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002685 tmp_local_intv->value.sval.min = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002686 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002687 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.min)) {
2688 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2689 goto error;
2690 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002691 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002692 } else if (!strncmp(ptr, "min", 3)) {
2693 if (kind == 0) {
2694 tmp_local_intv->value.uval.min = local_umin;
2695 } else if (kind == 1) {
2696 tmp_local_intv->value.sval.min = local_smin;
2697 } else if (kind == 2) {
2698 tmp_local_intv->value.fval.min = local_fmin;
2699 }
2700
2701 ptr += 3;
2702 } else if (!strncmp(ptr, "max", 3)) {
2703 if (kind == 0) {
2704 tmp_local_intv->value.uval.min = local_umax;
2705 } else if (kind == 1) {
2706 tmp_local_intv->value.sval.min = local_smax;
2707 } else if (kind == 2) {
2708 tmp_local_intv->value.fval.min = local_fmax;
2709 }
2710
2711 ptr += 3;
2712 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002713 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002714 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002715 }
2716
2717 while (isspace(ptr[0])) {
2718 ptr++;
2719 }
2720
2721 /* no interval or interval */
2722 if ((ptr[0] == '|') || !ptr[0]) {
2723 if (kind == 0) {
2724 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
2725 } else if (kind == 1) {
2726 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
2727 } else if (kind == 2) {
2728 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
2729 }
2730 } else if (!strncmp(ptr, "..", 2)) {
2731 /* skip ".." */
2732 ptr += 2;
2733 while (isspace(ptr[0])) {
2734 ++ptr;
2735 }
2736
2737 /* max */
2738 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2739 if (kind == 0) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002740 tmp_local_intv->value.uval.max = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002741 } else if (kind == 1) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002742 tmp_local_intv->value.sval.max = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002743 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002744 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.max)) {
2745 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2746 goto error;
2747 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002748 }
2749 } else if (!strncmp(ptr, "max", 3)) {
2750 if (kind == 0) {
2751 tmp_local_intv->value.uval.max = local_umax;
2752 } else if (kind == 1) {
2753 tmp_local_intv->value.sval.max = local_smax;
2754 } else if (kind == 2) {
2755 tmp_local_intv->value.fval.max = local_fmax;
2756 }
2757 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002758 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002759 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002760 }
2761 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002762 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002763 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002764 }
2765
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002766 /* check min and max in correct order*/
2767 if (kind == 0) {
2768 /* current segment */
2769 if (tmp_local_intv->value.uval.min > tmp_local_intv->value.uval.max) {
2770 goto error;
2771 }
2772 if (tmp_local_intv->value.uval.min < local_umin || tmp_local_intv->value.uval.max > local_umax) {
2773 goto error;
2774 }
2775 /* segments sholud be ascending order */
Pavol Vican69f62c92016-08-30 09:06:25 +02002776 if (tmp_intv && (tmp_intv->value.uval.max >= tmp_local_intv->value.uval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002777 goto error;
2778 }
2779 } else if (kind == 1) {
2780 if (tmp_local_intv->value.sval.min > tmp_local_intv->value.sval.max) {
2781 goto error;
2782 }
2783 if (tmp_local_intv->value.sval.min < local_smin || tmp_local_intv->value.sval.max > local_smax) {
2784 goto error;
2785 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002786 if (tmp_intv && (tmp_intv->value.sval.max >= tmp_local_intv->value.sval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002787 goto error;
2788 }
2789 } else if (kind == 2) {
2790 if (tmp_local_intv->value.fval.min > tmp_local_intv->value.fval.max) {
2791 goto error;
2792 }
2793 if (tmp_local_intv->value.fval.min < local_fmin || tmp_local_intv->value.fval.max > local_fmax) {
2794 goto error;
2795 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002796 if (tmp_intv && (tmp_intv->value.fval.max >= tmp_local_intv->value.fval.min)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002797 /* fraction-digits value is always the same (it cannot be changed in derived types) */
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002798 goto error;
2799 }
2800 }
2801
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002802 /* next segment (next OR) */
2803 seg_ptr = strchr(seg_ptr, '|');
2804 if (!seg_ptr) {
2805 break;
2806 }
2807 seg_ptr++;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002808 tmp_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002809 }
2810
2811 /* check local restrictions against superior ones */
2812 if (intv) {
2813 tmp_intv = intv;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002814 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002815
2816 while (tmp_local_intv && tmp_intv) {
2817 /* reuse local variables */
2818 if (kind == 0) {
2819 local_umin = tmp_local_intv->value.uval.min;
2820 local_umax = tmp_local_intv->value.uval.max;
2821
2822 /* it must be in this interval */
2823 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
2824 /* this interval is covered, next one */
2825 if (local_umax <= tmp_intv->value.uval.max) {
2826 tmp_local_intv = tmp_local_intv->next;
2827 continue;
2828 /* ascending order of restrictions -> fail */
2829 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002830 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002831 }
2832 }
2833 } else if (kind == 1) {
2834 local_smin = tmp_local_intv->value.sval.min;
2835 local_smax = tmp_local_intv->value.sval.max;
2836
2837 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
2838 if (local_smax <= tmp_intv->value.sval.max) {
2839 tmp_local_intv = tmp_local_intv->next;
2840 continue;
2841 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002842 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002843 }
2844 }
2845 } else if (kind == 2) {
2846 local_fmin = tmp_local_intv->value.fval.min;
2847 local_fmax = tmp_local_intv->value.fval.max;
2848
Michal Vasko4d1f0482016-09-19 14:35:06 +02002849 if ((dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.min, local_fdig) > -1)
Pavol Vican3c8ee2b2016-09-29 13:18:13 +02002850 && (dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002851 if (dec64cmp(local_fmax, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002852 tmp_local_intv = tmp_local_intv->next;
2853 continue;
2854 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002855 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002856 }
2857 }
2858 }
2859
2860 tmp_intv = tmp_intv->next;
2861 }
2862
2863 /* some interval left uncovered -> fail */
2864 if (tmp_local_intv) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002865 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002866 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002867 }
2868
Michal Vaskoaeb51802016-04-11 10:58:47 +02002869 /* append the local intervals to all the intervals of the superior types, return it all */
2870 if (intv) {
2871 for (tmp_intv = intv; tmp_intv->next; tmp_intv = tmp_intv->next);
2872 tmp_intv->next = local_intv;
2873 } else {
2874 intv = local_intv;
2875 }
2876 *ret = intv;
2877
2878 return EXIT_SUCCESS;
2879
2880error:
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002881 while (intv) {
2882 tmp_intv = intv->next;
2883 free(intv);
2884 intv = tmp_intv;
2885 }
Michal Vaskoaeb51802016-04-11 10:58:47 +02002886 while (local_intv) {
2887 tmp_local_intv = local_intv->next;
2888 free(local_intv);
2889 local_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002890 }
2891
Michal Vaskoaeb51802016-04-11 10:58:47 +02002892 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002893}
2894
Michal Vasko730dfdf2015-08-11 14:48:05 +02002895/**
Michal Vasko01c6fd22016-05-20 11:43:05 +02002896 * @brief Resolve a typedef, return only resolved typedefs if derived. If leafref, it must be
2897 * resolved for this function to return it. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002898 *
2899 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02002900 * @param[in] mod_name Typedef name module name.
2901 * @param[in] module Main module.
2902 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002903 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002904 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002905 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002906 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002907int
Michal Vasko1e62a092015-12-01 12:27:20 +01002908resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
2909 const struct lys_node *parent, struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002910{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002911 int i, j;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002912 struct lys_tpdf *tpdf, *match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002913 int tpdf_size;
2914
Michal Vasko1dca6882015-10-22 14:29:42 +02002915 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002916 /* no prefix, try built-in types */
2917 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
2918 if (!strcmp(ly_types[i].def->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002919 if (ret) {
2920 *ret = ly_types[i].def;
2921 }
2922 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002923 }
2924 }
2925 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02002926 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002927 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02002928 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002929 }
2930 }
2931
Michal Vasko1dca6882015-10-22 14:29:42 +02002932 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002933 /* search in local typedefs */
2934 while (parent) {
2935 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02002936 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02002937 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
2938 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002939 break;
2940
Radek Krejci76512572015-08-04 09:47:08 +02002941 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02002942 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
2943 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002944 break;
2945
Radek Krejci76512572015-08-04 09:47:08 +02002946 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02002947 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
2948 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002949 break;
2950
Radek Krejci76512572015-08-04 09:47:08 +02002951 case LYS_RPC:
Michal Vasko44fb6382016-06-29 11:12:27 +02002952 case LYS_ACTION:
2953 tpdf_size = ((struct lys_node_rpc_action *)parent)->tpdf_size;
2954 tpdf = ((struct lys_node_rpc_action *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002955 break;
2956
Radek Krejci76512572015-08-04 09:47:08 +02002957 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02002958 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
2959 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002960 break;
2961
Radek Krejci76512572015-08-04 09:47:08 +02002962 case LYS_INPUT:
2963 case LYS_OUTPUT:
Michal Vasko44fb6382016-06-29 11:12:27 +02002964 tpdf_size = ((struct lys_node_inout *)parent)->tpdf_size;
2965 tpdf = ((struct lys_node_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002966 break;
2967
2968 default:
Michal Vaskodcf98e62016-05-05 17:53:53 +02002969 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002970 continue;
2971 }
2972
2973 for (i = 0; i < tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002974 if (!strcmp(tpdf[i].name, name) && tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002975 match = &tpdf[i];
2976 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002977 }
2978 }
2979
Michal Vaskodcf98e62016-05-05 17:53:53 +02002980 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002981 }
Radek Krejcic071c542016-01-27 14:57:51 +01002982 } else {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002983 /* get module where to search */
Michal Vaskob6729c62015-10-21 12:09:47 +02002984 module = lys_get_import_module(module, NULL, 0, mod_name, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02002985 if (!module) {
2986 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002987 }
2988 }
2989
2990 /* search in top level typedefs */
2991 for (i = 0; i < module->tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002992 if (!strcmp(module->tpdf[i].name, name) && module->tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002993 match = &module->tpdf[i];
2994 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002995 }
2996 }
2997
2998 /* search in submodules */
Radek Krejcic071c542016-01-27 14:57:51 +01002999 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003000 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
Radek Krejcic13db382016-08-16 10:52:42 +02003001 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 +02003002 match = &module->inc[i].submodule->tpdf[j];
3003 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003004 }
3005 }
3006 }
3007
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003008 return EXIT_FAILURE;
Michal Vasko01c6fd22016-05-20 11:43:05 +02003009
3010check_leafref:
3011 if (ret) {
3012 *ret = match;
3013 }
3014 if (match->type.base == LY_TYPE_LEAFREF) {
3015 while (!match->type.info.lref.path) {
3016 match = match->type.der;
3017 assert(match);
3018 }
Michal Vasko01c6fd22016-05-20 11:43:05 +02003019 }
3020 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003021}
3022
Michal Vasko1dca6882015-10-22 14:29:42 +02003023/**
3024 * @brief Check the default \p value of the \p type. Logs directly.
3025 *
3026 * @param[in] type Type definition to use.
3027 * @param[in] value Default value to check.
Michal Vasko56826402016-03-02 11:11:37 +01003028 * @param[in] module Type module.
Michal Vasko1dca6882015-10-22 14:29:42 +02003029 *
3030 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3031 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003032static int
Radek Krejci51673202016-11-01 17:00:32 +01003033check_default(struct lys_type *type, const char **value, struct lys_module *module)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003034{
Radek Krejcibad2f172016-08-02 11:04:15 +02003035 struct lys_tpdf *base_tpdf = NULL;
Michal Vasko1dca6882015-10-22 14:29:42 +02003036 struct lyd_node_leaf_list node;
Radek Krejci51673202016-11-01 17:00:32 +01003037 const char *dflt = NULL;
Radek Krejci37b756f2016-01-18 10:15:03 +01003038 int ret = EXIT_SUCCESS;
Michal Vasko1dca6882015-10-22 14:29:42 +02003039
Radek Krejci51673202016-11-01 17:00:32 +01003040 assert(value);
3041
Radek Krejcic13db382016-08-16 10:52:42 +02003042 if (type->base <= LY_TYPE_DER) {
Michal Vasko478c4652016-07-21 12:55:01 +02003043 /* the type was not resolved yet, nothing to do for now */
3044 return EXIT_FAILURE;
3045 }
3046
Radek Krejci51673202016-11-01 17:00:32 +01003047 dflt = *value;
3048 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003049 /* we do not have a new default value, so is there any to check even, in some base type? */
3050 for (base_tpdf = type->der; base_tpdf->type.der; base_tpdf = base_tpdf->type.der) {
3051 if (base_tpdf->dflt) {
Radek Krejci51673202016-11-01 17:00:32 +01003052 dflt = base_tpdf->dflt;
Michal Vasko478c4652016-07-21 12:55:01 +02003053 break;
3054 }
3055 }
3056
Radek Krejci51673202016-11-01 17:00:32 +01003057 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003058 /* no default value, nothing to check, all is well */
3059 return EXIT_SUCCESS;
3060 }
3061
3062 /* 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)? */
3063 switch (type->base) {
Michal Vasko478c4652016-07-21 12:55:01 +02003064 case LY_TYPE_IDENT:
3065 case LY_TYPE_INST:
3066 case LY_TYPE_LEAFREF:
3067 case LY_TYPE_BOOL:
3068 case LY_TYPE_EMPTY:
3069 /* these have no restrictions, so we would do the exact same work as the unres in the base typedef */
3070 return EXIT_SUCCESS;
Radek Krejcibad2f172016-08-02 11:04:15 +02003071 case LY_TYPE_BITS:
3072 /* the default value must match the restricted list of values, if the type was restricted */
3073 if (type->info.bits.count) {
3074 break;
3075 }
3076 return EXIT_SUCCESS;
3077 case LY_TYPE_ENUM:
3078 /* the default value must match the restricted list of values, if the type was restricted */
3079 if (type->info.enums.count) {
3080 break;
3081 }
3082 return EXIT_SUCCESS;
Michal Vasko478c4652016-07-21 12:55:01 +02003083 case LY_TYPE_DEC64:
3084 if (type->info.dec64.range) {
3085 break;
3086 }
3087 return EXIT_SUCCESS;
3088 case LY_TYPE_BINARY:
3089 if (type->info.binary.length) {
3090 break;
3091 }
3092 return EXIT_SUCCESS;
3093 case LY_TYPE_INT8:
3094 case LY_TYPE_INT16:
3095 case LY_TYPE_INT32:
3096 case LY_TYPE_INT64:
3097 case LY_TYPE_UINT8:
3098 case LY_TYPE_UINT16:
3099 case LY_TYPE_UINT32:
3100 case LY_TYPE_UINT64:
3101 if (type->info.num.range) {
3102 break;
3103 }
3104 return EXIT_SUCCESS;
3105 case LY_TYPE_STRING:
3106 if (type->info.str.length || type->info.str.patterns) {
3107 break;
3108 }
3109 return EXIT_SUCCESS;
3110 case LY_TYPE_UNION:
3111 /* way too much trouble learning whether we need to check the default again, so just do it */
3112 break;
3113 default:
3114 LOGINT;
3115 return -1;
3116 }
Radek Krejci55a161c2016-09-05 17:13:25 +02003117 } else if (type->base == LY_TYPE_EMPTY) {
3118 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "default", type->parent->name);
3119 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"empty\" data type cannot have a default value.");
3120 return -1;
Michal Vasko478c4652016-07-21 12:55:01 +02003121 }
3122
Michal Vasko1dca6882015-10-22 14:29:42 +02003123 /* dummy leaf */
Radek Krejci4fe36bd2016-03-17 16:47:16 +01003124 memset(&node, 0, sizeof node);
Radek Krejci51673202016-11-01 17:00:32 +01003125 node.value_str = dflt;
Michal Vasko1dca6882015-10-22 14:29:42 +02003126 node.value_type = type->base;
Radek Krejci37b756f2016-01-18 10:15:03 +01003127 node.schema = calloc(1, sizeof (struct lys_node_leaf));
Michal Vasko253035f2015-12-17 16:58:13 +01003128 if (!node.schema) {
3129 LOGMEM;
3130 return -1;
3131 }
Radek Krejcibad2f172016-08-02 11:04:15 +02003132 node.schema->name = strdup("fake-default");
Michal Vasko253035f2015-12-17 16:58:13 +01003133 if (!node.schema->name) {
3134 LOGMEM;
Michal Vaskof49eda02016-07-21 12:17:01 +02003135 free(node.schema);
Michal Vasko253035f2015-12-17 16:58:13 +01003136 return -1;
3137 }
Michal Vasko56826402016-03-02 11:11:37 +01003138 node.schema->module = module;
Radek Krejci37b756f2016-01-18 10:15:03 +01003139 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
Michal Vasko1dca6882015-10-22 14:29:42 +02003140
Radek Krejci37b756f2016-01-18 10:15:03 +01003141 if (type->base == LY_TYPE_LEAFREF) {
Michal Vasko1dca6882015-10-22 14:29:42 +02003142 if (!type->info.lref.target) {
3143 ret = EXIT_FAILURE;
3144 goto finish;
3145 }
Radek Krejci51673202016-11-01 17:00:32 +01003146 ret = check_default(&type->info.lref.target->type, &dflt, module);
3147 if (!ret) {
3148 /* adopt possibly changed default value to its canonical form */
3149 if (*value) {
3150 *value = dflt;
3151 }
3152 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003153 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01003154 if (!lyp_parse_value(&((struct lys_node_leaf *)node.schema)->type, &node.value_str, NULL, &node, 1, 1)) {
Radek Krejci5dca5932016-11-04 14:30:47 +01003155 /* possible forward reference */
3156 ret = 1;
Radek Krejcibad2f172016-08-02 11:04:15 +02003157 if (base_tpdf) {
Radek Krejci9ad23f42016-10-31 15:46:52 +01003158 /* default value is defined in some base typedef */
Radek Krejcibad2f172016-08-02 11:04:15 +02003159 if ((type->base == LY_TYPE_BITS && type->der->type.der) ||
3160 (type->base == LY_TYPE_ENUM && type->der->type.der)) {
3161 /* we have refined bits/enums */
3162 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
3163 "Invalid value \"%s\" of the default statement inherited to \"%s\" from \"%s\" base type.",
Radek Krejci51673202016-11-01 17:00:32 +01003164 dflt, type->parent->name, base_tpdf->name);
Radek Krejcibad2f172016-08-02 11:04:15 +02003165 }
3166 }
Radek Krejci51673202016-11-01 17:00:32 +01003167 } else {
3168 /* success - adopt canonical form from the node into the default value */
3169 if (dflt != node.value_str) {
3170 /* this can happen only if we have non-inherited default value,
3171 * inherited default values are already in canonical form */
3172 assert(dflt == *value);
3173 *value = node.value_str;
3174 }
Michal Vasko3767fb22016-07-21 12:10:57 +02003175 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003176 }
3177
3178finish:
3179 if (node.value_type == LY_TYPE_BITS) {
3180 free(node.value.bit);
3181 }
3182 free((char *)node.schema->name);
3183 free(node.schema);
3184
3185 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003186}
3187
Michal Vasko730dfdf2015-08-11 14:48:05 +02003188/**
3189 * @brief Check a key for mandatory attributes. Logs directly.
3190 *
3191 * @param[in] key The key to check.
3192 * @param[in] flags What flags to check.
3193 * @param[in] list The list of all the keys.
3194 * @param[in] index Index of the key in the key list.
3195 * @param[in] name The name of the keys.
3196 * @param[in] len The name length.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003197 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003198 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003199 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003200static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003201check_key(struct lys_node_list *list, int index, const char *name, int len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003202{
Radek Krejciadb57612016-02-16 13:34:34 +01003203 struct lys_node_leaf *key = list->keys[index];
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003204 char *dup = NULL;
3205 int j;
3206
3207 /* existence */
3208 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02003209 if (name[len] != '\0') {
3210 dup = strdup(name);
Michal Vasko253035f2015-12-17 16:58:13 +01003211 if (!dup) {
3212 LOGMEM;
3213 return -1;
3214 }
Michal Vaskof02e3742015-08-05 16:27:02 +02003215 dup[len] = '\0';
3216 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003217 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003218 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, list, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003219 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003220 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003221 }
3222
3223 /* uniqueness */
3224 for (j = index - 1; j >= 0; j--) {
Radek Krejciadb57612016-02-16 13:34:34 +01003225 if (key == list->keys[j]) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003226 LOGVAL(LYE_KEY_DUP, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003227 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003228 }
3229 }
3230
3231 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02003232 if (key->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003233 LOGVAL(LYE_KEY_NLEAF, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003234 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003235 }
3236
3237 /* type of the leaf is not built-in empty */
Radek Krejcic3738db2016-09-15 15:51:21 +02003238 if (key->type.base == LY_TYPE_EMPTY && key->module->version < 2) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003239 LOGVAL(LYE_KEY_TYPE, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003240 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003241 }
3242
3243 /* config attribute is the same as of the list */
Radek Krejci5c08a992016-11-02 13:30:04 +01003244 if ((key->flags & LYS_CONFIG_MASK) && (list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003245 LOGVAL(LYE_KEY_CONFIG, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003246 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003247 }
3248
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003249 /* key is not placed from augment */
3250 if (key->parent->nodetype == LYS_AUGMENT) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003251 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, key, key->name);
Michal Vasko51e5c582017-01-19 14:16:39 +01003252 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Key inserted from augment.");
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003253 return -1;
3254 }
3255
Radek Krejci3f21ada2016-08-01 13:34:31 +02003256 /* key is not when/if-feature -conditional */
3257 j = 0;
3258 if (key->when || (key->iffeature_size && (j = 1))) {
3259 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, key, j ? "if-feature" : "when", "leaf");
Michal Vasko51e5c582017-01-19 14:16:39 +01003260 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Key definition cannot depend on a \"%s\" condition.",
Radek Krejci3f21ada2016-08-01 13:34:31 +02003261 j ? "if-feature" : "when");
Radek Krejci581ce772015-11-10 17:22:40 +01003262 return -1;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003263 }
3264
Michal Vasko0b85aa82016-03-07 14:37:43 +01003265 return EXIT_SUCCESS;
Michal Vasko184521f2015-09-24 13:14:26 +02003266}
Michal Vasko730dfdf2015-08-11 14:48:05 +02003267
3268/**
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003269 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003270 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003271 * @param[in] parent The parent node of the unique structure.
Michal Vasko0b85aa82016-03-07 14:37:43 +01003272 * @param[in] uniq_str_path One path from the unique string.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003273 *
3274 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
3275 */
3276int
Radek Krejcid09d1a52016-08-11 14:05:45 +02003277resolve_unique(struct lys_node *parent, const char *uniq_str_path, uint8_t *trg_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003278{
Radek Krejci581ce772015-11-10 17:22:40 +01003279 int rc;
Michal Vasko1e62a092015-12-01 12:27:20 +01003280 const struct lys_node *leaf = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003281
Radek Krejcif3c71de2016-04-11 12:45:46 +02003282 rc = resolve_descendant_schema_nodeid(uniq_str_path, parent->child, LYS_LEAF, 1, 1, &leaf);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003283 if (rc || !leaf) {
Michal Vasko0b85aa82016-03-07 14:37:43 +01003284 if (rc) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003285 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003286 if (rc > 0) {
Michal Vasko51e5c582017-01-19 14:16:39 +01003287 LOGVAL(LYE_INCHAR, LY_VLOG_PREV, NULL, uniq_str_path[rc - 1], &uniq_str_path[rc - 1]);
Radek Krejcif3c71de2016-04-11 12:45:46 +02003288 } else if (rc == -2) {
Michal Vasko51e5c582017-01-19 14:16:39 +01003289 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Unique argument references list.");
Radek Krejci581ce772015-11-10 17:22:40 +01003290 }
Michal Vasko0b85aa82016-03-07 14:37:43 +01003291 rc = -1;
Michal Vasko0b85aa82016-03-07 14:37:43 +01003292 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01003293 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko51e5c582017-01-19 14:16:39 +01003294 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Target leaf not found.");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003295 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003296 }
Radek Krejci581ce772015-11-10 17:22:40 +01003297 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003298 }
Michal Vasko9bb061b2016-02-12 11:00:19 +01003299 if (leaf->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003300 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko51e5c582017-01-19 14:16:39 +01003301 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Target is not a leaf.");
Radek Krejcid09d1a52016-08-11 14:05:45 +02003302 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003303 }
3304
Radek Krejcicf509982015-12-15 09:22:44 +01003305 /* check status */
Radek Krejci48464ed2016-03-17 15:44:09 +01003306 if (lyp_check_status(parent->flags, parent->module, parent->name, leaf->flags, leaf->module, leaf->name, leaf)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003307 return -1;
3308 }
3309
Radek Krejcid09d1a52016-08-11 14:05:45 +02003310 /* check that all unique's targets are of the same config type */
3311 if (*trg_type) {
3312 if (((*trg_type == 1) && (leaf->flags & LYS_CONFIG_R)) || ((*trg_type == 2) && (leaf->flags & LYS_CONFIG_W))) {
3313 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko51e5c582017-01-19 14:16:39 +01003314 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Radek Krejcid09d1a52016-08-11 14:05:45 +02003315 "Leaf \"%s\" referenced in unique statement is config %s, but previous referenced leaf is config %s.",
3316 uniq_str_path, *trg_type == 1 ? "false" : "true", *trg_type == 1 ? "true" : "false");
3317 return -1;
3318 }
3319 } else {
3320 /* first unique */
3321 if (leaf->flags & LYS_CONFIG_W) {
3322 *trg_type = 1;
3323 } else {
3324 *trg_type = 2;
3325 }
3326 }
3327
Radek Krejcica7efb72016-01-18 13:06:01 +01003328 /* set leaf's unique flag */
3329 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
3330
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003331 return EXIT_SUCCESS;
3332
3333error:
3334
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003335 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003336}
3337
Radek Krejci0c0086a2016-03-24 15:20:28 +01003338void
Michal Vasko23b61ec2015-08-19 11:19:50 +02003339unres_data_del(struct unres_data *unres, uint32_t i)
3340{
3341 /* there are items after the one deleted */
3342 if (i+1 < unres->count) {
3343 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02003344 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003345
3346 /* deleting the last item */
3347 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02003348 free(unres->node);
3349 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003350 }
3351
3352 /* if there are no items after and it is not the last one, just move the counter */
3353 --unres->count;
3354}
3355
Michal Vasko0491ab32015-08-19 14:28:29 +02003356/**
3357 * @brief Resolve (find) a data node from a specific module. Does not log.
3358 *
3359 * @param[in] mod Module to search in.
3360 * @param[in] name Name of the data node.
3361 * @param[in] nam_len Length of the name.
3362 * @param[in] start Data node to start the search from.
3363 * @param[in,out] parents Resolved nodes. If there are some parents,
3364 * they are replaced (!!) with the resolvents.
3365 *
Michal Vasko2471e7f2016-04-11 11:00:15 +02003366 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko0491ab32015-08-19 14:28:29 +02003367 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003368static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003369resolve_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 +02003370{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003371 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02003372 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003373 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003374
Michal Vasko23b61ec2015-08-19 11:19:50 +02003375 if (!parents->count) {
3376 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003377 parents->node = malloc(sizeof *parents->node);
Michal Vasko253035f2015-12-17 16:58:13 +01003378 if (!parents->node) {
3379 LOGMEM;
Michal Vasko2471e7f2016-04-11 11:00:15 +02003380 return -1;
Michal Vasko253035f2015-12-17 16:58:13 +01003381 }
Michal Vaskocf024702015-10-08 15:01:42 +02003382 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003383 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003384 for (i = 0; i < parents->count;) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02003385 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003386 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003387 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003388 continue;
3389 }
3390 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02003391 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003392 if (node->schema->module == mod && !strncmp(node->schema->name, name, nam_len)
3393 && node->schema->name[nam_len] == '\0') {
3394 /* matching target */
3395 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02003396 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02003397 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003398 flag = 1;
3399 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02003400 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003401 ++parents->count;
Michal Vasko253035f2015-12-17 16:58:13 +01003402 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
3403 if (!parents->node) {
3404 return EXIT_FAILURE;
3405 }
Michal Vaskocf024702015-10-08 15:01:42 +02003406 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003407 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003408 }
3409 }
3410 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003411
3412 if (!flag) {
3413 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003414 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02003415 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003416 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02003417 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003418 }
3419
Michal Vasko0491ab32015-08-19 14:28:29 +02003420 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02003421}
3422
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003423/**
3424 * @brief Resolve (find) a data node. Does not log.
3425 *
Radek Krejci581ce772015-11-10 17:22:40 +01003426 * @param[in] mod_name Module name of the data node.
3427 * @param[in] mod_name_len Length of the module name.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003428 * @param[in] name Name of the data node.
3429 * @param[in] nam_len Length of the name.
3430 * @param[in] start Data node to start the search from.
3431 * @param[in,out] parents Resolved nodes. If there are some parents,
3432 * they are replaced (!!) with the resolvents.
3433 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003434 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003435 */
Radek Krejcic5090c32015-08-12 09:46:19 +02003436static int
Radek Krejci581ce772015-11-10 17:22:40 +01003437resolve_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 +02003438 struct unres_data *parents)
Radek Krejcic5090c32015-08-12 09:46:19 +02003439{
Michal Vasko1e62a092015-12-01 12:27:20 +01003440 const struct lys_module *mod;
Michal Vasko31fc3672015-10-21 12:08:13 +02003441 char *str;
Radek Krejcic5090c32015-08-12 09:46:19 +02003442
Michal Vasko23b61ec2015-08-19 11:19:50 +02003443 assert(start);
3444
Michal Vasko31fc3672015-10-21 12:08:13 +02003445 if (mod_name) {
3446 /* we have mod_name, find appropriate module */
3447 str = strndup(mod_name, mod_name_len);
Michal Vasko253035f2015-12-17 16:58:13 +01003448 if (!str) {
3449 LOGMEM;
3450 return -1;
3451 }
Michal Vasko31fc3672015-10-21 12:08:13 +02003452 mod = ly_ctx_get_module(start->schema->module->ctx, str, NULL);
3453 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02003454 if (!mod) {
3455 /* invalid prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003456 return -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02003457 }
3458 } else {
3459 /* no prefix, module is the same as of current node */
3460 mod = start->schema->module;
3461 }
3462
3463 return resolve_data(mod, name, name_len, start, parents);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003464}
3465
Michal Vasko730dfdf2015-08-11 14:48:05 +02003466/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003467 * @brief Resolve a path predicate (leafref) in JSON data context. Logs directly
Radek Krejci48464ed2016-03-17 15:44:09 +01003468 * only specific errors, general no-resolvent error is left to the caller.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003469 *
Michal Vaskobb211122015-08-19 14:03:11 +02003470 * @param[in] pred Predicate to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003471 * @param[in] node Node from which the predicate is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02003472 * @param[in,out] node_match Nodes satisfying the restriction
3473 * without the predicate. Nodes not
3474 * satisfying the predicate are removed.
Michal Vasko0491ab32015-08-19 14:28:29 +02003475 * @param[out] parsed Number of characters parsed, negative on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003476 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003477 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003478 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003479static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003480resolve_path_predicate_data(const char *pred, struct lyd_node *node, struct unres_data *node_match,
Radek Krejci010e54b2016-03-15 09:40:34 +01003481 int *parsed)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003482{
Michal Vasko730dfdf2015-08-11 14:48:05 +02003483 /* ... /node[source = destination] ... */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003484 struct unres_data source_match, dest_match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003485 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vasko0491ab32015-08-19 14:28:29 +02003486 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed_loc = 0, pke_parsed = 0;
3487 int has_predicate, dest_parent_times, i, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003488 uint32_t j;
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003489 struct lyd_node_leaf_list *leaf_dst, *leaf_src;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003490
3491 source_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003492 source_match.node = malloc(sizeof *source_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003493 if (!source_match.node) {
3494 LOGMEM;
3495 return -1;
3496 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003497 dest_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003498 dest_match.node = malloc(sizeof *dest_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003499 if (!dest_match.node) {
3500 LOGMEM;
3501 return -1;
3502 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003503
3504 do {
3505 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
3506 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003507 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, pred[-i], &pred[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003508 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003509 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003510 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003511 parsed_loc += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003512 pred += i;
3513
Michal Vasko23b61ec2015-08-19 11:19:50 +02003514 for (j = 0; j < node_match->count;) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003515 /* source */
Michal Vaskocf024702015-10-08 15:01:42 +02003516 source_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02003517
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003518 /* must be leaf (key of a list) */
Radek Krejci581ce772015-11-10 17:22:40 +01003519 if ((rc = resolve_data_node(sour_pref, sour_pref_len, source, sour_len, node_match->node[j],
Michal Vaskocf024702015-10-08 15:01:42 +02003520 &source_match)) || (source_match.count != 1) || (source_match.node[0]->schema->nodetype != LYS_LEAF)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003521 i = 0;
3522 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003523 }
3524
3525 /* destination */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003526 dest_match.node[0] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003527 dest_parent_times = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003528 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3529 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003530 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003531 rc = -1;
3532 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003533 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003534 pke_parsed = i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003535 for (i = 0; i < dest_parent_times; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02003536 dest_match.node[0] = dest_match.node[0]->parent;
3537 if (!dest_match.node[0]) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003538 i = 0;
Michal Vasko0491ab32015-08-19 14:28:29 +02003539 rc = EXIT_FAILURE;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003540 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003541 }
3542 }
3543 while (1) {
Radek Krejci581ce772015-11-10 17:22:40 +01003544 if ((rc = resolve_data_node(dest_pref, dest_pref_len, dest, dest_len, dest_match.node[0],
Michal Vasko0491ab32015-08-19 14:28:29 +02003545 &dest_match)) || (dest_match.count != 1)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003546 i = 0;
3547 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003548 }
3549
3550 if (pke_len == pke_parsed) {
3551 break;
3552 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003553 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 +02003554 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003555 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003556 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003557 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003558 }
3559 pke_parsed += i;
3560 }
3561
3562 /* check match between source and destination nodes */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003563 leaf_dst = (struct lyd_node_leaf_list *)dest_match.node[0];
3564 while (leaf_dst->value_type == LY_TYPE_LEAFREF) {
3565 leaf_dst = (struct lyd_node_leaf_list *)leaf_dst->value.leafref;
3566 }
3567 leaf_src = (struct lyd_node_leaf_list *)source_match.node[0];
3568 while (leaf_src->value_type == LY_TYPE_LEAFREF) {
3569 leaf_src = (struct lyd_node_leaf_list *)leaf_src->value.leafref;
3570 }
3571 if (leaf_src->value_type != leaf_dst->value_type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003572 goto remove_leafref;
3573 }
3574
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003575 if (!ly_strequal(leaf_src->value_str, leaf_dst->value_str, 1)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003576 goto remove_leafref;
3577 }
3578
3579 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003580 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003581 continue;
3582
3583remove_leafref:
3584 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003585 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003586 }
3587 } while (has_predicate);
3588
Michal Vaskocf024702015-10-08 15:01:42 +02003589 free(source_match.node);
3590 free(dest_match.node);
Michal Vasko0491ab32015-08-19 14:28:29 +02003591 if (parsed) {
3592 *parsed = parsed_loc;
3593 }
3594 return EXIT_SUCCESS;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003595
3596error:
3597
3598 if (source_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003599 free(source_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003600 }
3601 if (dest_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003602 free(dest_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003603 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003604 if (parsed) {
3605 *parsed = -parsed_loc+i;
3606 }
3607 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003608}
3609
Michal Vasko730dfdf2015-08-11 14:48:05 +02003610/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003611 * @brief Resolve a path (leafref) in JSON data context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003612 *
Michal Vaskocf024702015-10-08 15:01:42 +02003613 * @param[in] node Leafref data node.
Michal Vasko23b61ec2015-08-19 11:19:50 +02003614 * @param[in] path Path of the leafref.
Radek Krejci48464ed2016-03-17 15:44:09 +01003615 * @param[out] ret Matching nodes. Expects an empty, but allocated structure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003616 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003617 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003618 */
Michal Vasko184521f2015-09-24 13:14:26 +02003619static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003620resolve_path_arg_data(struct lyd_node *node, const char *path, struct unres_data *ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003621{
Radek Krejci71b795b2015-08-10 16:20:39 +02003622 struct lyd_node *data = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003623 const char *prefix, *name;
Michal Vasko0491ab32015-08-19 14:28:29 +02003624 int pref_len, nam_len, has_predicate, parent_times, i, parsed, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003625 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003626
Michal Vaskocf024702015-10-08 15:01:42 +02003627 assert(node && path && ret && !ret->count);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003628
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003629 parent_times = 0;
Michal Vaskod9173342015-08-17 14:35:36 +02003630 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003631
3632 /* searching for nodeset */
3633 do {
Radek Krejcif7ed4c32016-10-27 16:20:03 +02003634 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 +01003635 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path[-i], &path[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003636 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003637 goto error;
3638 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003639 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003640 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003641
Michal Vasko23b61ec2015-08-19 11:19:50 +02003642 if (!ret->count) {
Michal Vaskobfd98e62016-09-02 09:50:05 +02003643 if (parent_times > 0) {
3644 data = node;
3645 for (i = 1; i < parent_times; ++i) {
3646 data = data->parent;
Michal Vasko253035f2015-12-17 16:58:13 +01003647 }
Michal Vaskobfd98e62016-09-02 09:50:05 +02003648 } else if (!parent_times) {
3649 data = node->child;
3650 } else {
3651 /* absolute path */
3652 for (data = node; data->parent; data = data->parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003653 }
3654
Michal Vaskobfd98e62016-09-02 09:50:05 +02003655 /* we may still be parsing it and the pointer is not correct yet */
3656 if (data->prev) {
3657 while (data->prev->next) {
3658 data = data->prev;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003659 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003660 }
3661 }
3662
3663 /* node identifier */
Radek Krejci581ce772015-11-10 17:22:40 +01003664 if ((rc = resolve_data_node(prefix, pref_len, name, nam_len, data, ret))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003665 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003666 LOGVAL(LYE_INELEM_LEN, LY_VLOG_LYD, node, nam_len, name);
Michal Vasko184521f2015-09-24 13:14:26 +02003667 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003668 goto error;
3669 }
3670
3671 if (has_predicate) {
3672 /* we have predicate, so the current results must be lists */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003673 for (j = 0; j < ret->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02003674 if (ret->node[j]->schema->nodetype == LYS_LIST &&
3675 ((struct lys_node_list *)ret->node[0]->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003676 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003677 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003678 continue;
3679 }
3680
3681 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003682 unres_data_del(ret, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003683 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003684 if ((rc = resolve_path_predicate_data(path, node, ret, &i))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003685 if (rc == -1) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003686 LOGVAL(LYE_NORESOLV, LY_VLOG_LYD, node, "leafref", path);
Michal Vasko184521f2015-09-24 13:14:26 +02003687 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003688 goto error;
3689 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003690 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003691 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003692
Michal Vasko23b61ec2015-08-19 11:19:50 +02003693 if (!ret->count) {
Michal Vasko0491ab32015-08-19 14:28:29 +02003694 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003695 goto error;
3696 }
3697 }
3698 } while (path[0] != '\0');
3699
Michal Vaskof02e3742015-08-05 16:27:02 +02003700 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003701
3702error:
3703
Michal Vaskocf024702015-10-08 15:01:42 +02003704 free(ret->node);
3705 ret->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003706 ret->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003707
Michal Vasko0491ab32015-08-19 14:28:29 +02003708 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003709}
3710
Michal Vaskoe27516a2016-10-10 17:55:31 +00003711static int
3712resolve_path_arg_schema_valid_dep_flag(const struct lys_node *op_node, const struct lys_node *first_node, int abs_path)
3713{
3714 int dep1, dep2;
3715 const struct lys_node *node;
3716
3717 if (lys_parent(op_node)) {
3718 /* inner operation (notif/action) */
3719 if (abs_path) {
3720 return 1;
3721 } else {
3722 /* compare depth of both nodes */
3723 for (dep1 = 0, node = op_node; lys_parent(node); node = lys_parent(node));
3724 for (dep2 = 0, node = first_node; lys_parent(node); node = lys_parent(node));
3725 if ((dep2 > dep1) || ((dep2 == dep1) && (op_node != first_node))) {
3726 return 1;
3727 }
3728 }
3729 } else {
3730 /* top-level operation (notif/rpc) */
3731 if (op_node != first_node) {
3732 return 1;
3733 }
3734 }
3735
3736 return 0;
3737}
3738
Michal Vasko730dfdf2015-08-11 14:48:05 +02003739/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003740 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003741 *
Michal Vaskobb211122015-08-19 14:03:11 +02003742 * @param[in] path Path to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003743 * @param[in] context_node Predicate context node (where the predicate is placed).
3744 * @param[in] parent Path context node (where the path begins/is placed).
Michal Vaskoe27516a2016-10-10 17:55:31 +00003745 * @param[in] op_node Optional node if the leafref is in an operation (action/rpc/notif).
Michal Vasko730dfdf2015-08-11 14:48:05 +02003746 *
Michal Vasko184521f2015-09-24 13:14:26 +02003747 * @return 0 on forward reference, otherwise the number
3748 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003749 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003750 */
Michal Vasko1f76a282015-08-04 16:16:53 +02003751static int
Radek Krejciadb57612016-02-16 13:34:34 +01003752resolve_path_predicate_schema(const char *path, const struct lys_node *context_node,
Michal Vaskoe27516a2016-10-10 17:55:31 +00003753 struct lys_node *parent, const struct lys_node *op_node)
Michal Vasko1f76a282015-08-04 16:16:53 +02003754{
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003755 const struct lys_module *trg_mod;
Michal Vasko1e62a092015-12-01 12:27:20 +01003756 const struct lys_node *src_node, *dst_node;
Michal Vasko1f76a282015-08-04 16:16:53 +02003757 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vaskof9b35d92016-10-21 15:19:30 +02003758 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, pke_parsed, parsed = 0;
3759 int has_predicate, dest_parent_times, i, rc, first_iter;
Michal Vasko1f76a282015-08-04 16:16:53 +02003760
3761 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02003762 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02003763 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003764 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003765 return -parsed+i;
3766 }
3767 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003768 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02003769
Michal Vasko58090902015-08-13 14:04:15 +02003770 /* source (must be leaf) */
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003771 if (sour_pref) {
3772 trg_mod = lys_get_import_module(lys_node_module(parent), NULL, 0, sour_pref, sour_pref_len);
3773 } else {
3774 trg_mod = NULL;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003775 }
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003776 rc = lys_get_data_sibling(trg_mod, context_node->child, source, sour_len, LYS_LEAF | LYS_LEAFLIST, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003777 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003778 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02003779 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003780 }
3781
3782 /* destination */
Michal Vaskof9b35d92016-10-21 15:19:30 +02003783 dest_parent_times = 0;
3784 pke_parsed = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003785 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3786 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003787 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 +02003788 return -parsed;
3789 }
3790 pke_parsed += i;
3791
Radek Krejciadb57612016-02-16 13:34:34 +01003792 for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
Michal Vaskofbaead72016-10-07 10:54:48 +02003793 /* path is supposed to be evaluated in data tree, so we have to skip
3794 * all schema nodes that cannot be instantiated in data tree */
3795 for (dst_node = lys_parent(dst_node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003796 dst_node && !(dst_node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Michal Vaskofbaead72016-10-07 10:54:48 +02003797 dst_node = lys_parent(dst_node));
3798
Michal Vasko1f76a282015-08-04 16:16:53 +02003799 if (!dst_node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003800 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003801 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003802 }
3803 }
Michal Vaskoe27516a2016-10-10 17:55:31 +00003804 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003805 while (1) {
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003806 if (dest_pref) {
3807 trg_mod = lys_get_import_module(lys_node_module(parent), NULL, 0, dest_pref, dest_pref_len);
3808 } else {
3809 trg_mod = NULL;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003810 }
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003811 rc = lys_get_data_sibling(trg_mod, dst_node->child, dest, dest_len, LYS_CONTAINER | LYS_LIST | LYS_LEAF, &dst_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003812 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003813 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003814 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003815 }
3816
Michal Vaskoe27516a2016-10-10 17:55:31 +00003817 if (first_iter) {
3818 if (resolve_path_arg_schema_valid_dep_flag(op_node, dst_node, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01003819 parent->flags |= LYS_LEAFREF_DEP;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003820 }
3821 first_iter = 0;
3822 }
3823
Michal Vasko1f76a282015-08-04 16:16:53 +02003824 if (pke_len == pke_parsed) {
3825 break;
3826 }
3827
3828 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
3829 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003830 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent,
Radek Krejciadb57612016-02-16 13:34:34 +01003831 (path_key_expr+pke_parsed)[-i], (path_key_expr+pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003832 return -parsed;
3833 }
3834 pke_parsed += i;
3835 }
3836
3837 /* check source - dest match */
Michal Vasko59ad4582016-09-16 13:15:41 +02003838 if (dst_node->nodetype != src_node->nodetype) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003839 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko51e5c582017-01-19 14:16:39 +01003840 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Destination node is not a %s, but a %s.",
Michal Vasko59ad4582016-09-16 13:15:41 +02003841 strnodetype(src_node->nodetype), strnodetype(dst_node->nodetype));
Michal Vasko184521f2015-09-24 13:14:26 +02003842 return -parsed;
3843 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003844 } while (has_predicate);
3845
3846 return parsed;
3847}
3848
Michal Vasko730dfdf2015-08-11 14:48:05 +02003849/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003850 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003851 *
Michal Vaskobb211122015-08-19 14:03:11 +02003852 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003853 * @param[in] parent_node Parent of the leafref.
Radek Krejci2f12f852016-01-08 12:59:57 +01003854 * @param[in] parent_tpdf Flag if the parent node is actually typedef, in that case the path
3855 * has to contain absolute path
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003856 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003857 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003858 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003859 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003860static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003861resolve_path_arg_schema(const char *path, struct lys_node *parent, int parent_tpdf,
Michal Vasko36cbaa42015-12-14 13:15:48 +01003862 const struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02003863{
Michal Vaskoe27516a2016-10-10 17:55:31 +00003864 const struct lys_node *node, *op_node = NULL;
Radek Krejci990af1f2016-11-09 13:53:36 +01003865 const struct lys_module *mod;
3866 struct lys_module *mod_start;
Michal Vasko1f76a282015-08-04 16:16:53 +02003867 const char *id, *prefix, *name;
3868 int pref_len, nam_len, parent_times, has_predicate;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003869 int i, first_iter, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02003870
Michal Vasko184521f2015-09-24 13:14:26 +02003871 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003872 parent_times = 0;
3873 id = path;
3874
Michal Vaskoe27516a2016-10-10 17:55:31 +00003875 /* find operation schema we are in, if applicable */
Michal Vaskoe9914d12016-10-07 14:32:37 +02003876 if (!parent_tpdf) {
Michal Vaskoe27516a2016-10-10 17:55:31 +00003877 for (op_node = lys_parent(parent);
3878 op_node && !(op_node->nodetype & (LYS_ACTION | LYS_NOTIF | LYS_RPC));
3879 op_node = lys_parent(op_node));
Michal Vaskoe9914d12016-10-07 14:32:37 +02003880 }
3881
Radek Krejci990af1f2016-11-09 13:53:36 +01003882 mod_start = lys_node_module(parent);
Michal Vasko1f76a282015-08-04 16:16:53 +02003883 do {
Radek Krejci990af1f2016-11-09 13:53:36 +01003884 if ((i = parse_path_arg(mod_start, id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003885 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 +02003886 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003887 }
3888 id += i;
3889
Michal Vasko184521f2015-09-24 13:14:26 +02003890 if (first_iter) {
Michal Vasko1f76a282015-08-04 16:16:53 +02003891 if (parent_times == -1) {
Radek Krejcic071c542016-01-27 14:57:51 +01003892 /* resolve prefix of the module */
Radek Krejci990af1f2016-11-09 13:53:36 +01003893 mod = prefix ? lys_get_import_module(mod_start, NULL, 0, prefix, pref_len) : mod_start;
3894 if (!mod) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003895 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3896 "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003897 return EXIT_FAILURE;
Michal Vasko58090902015-08-13 14:04:15 +02003898 }
Radek Krejci990af1f2016-11-09 13:53:36 +01003899 if (!mod->implemented) {
Radek Krejci2eee5c02016-12-06 19:18:05 +01003900 mod = lys_implemented_module(mod);
Radek Krejci990af1f2016-11-09 13:53:36 +01003901 if (!mod->implemented) {
3902 /* make the found module implemented */
3903 if (lys_set_implemented(mod)) {
3904 return EXIT_FAILURE;
3905 }
3906 }
3907 }
3908 /* get start node */
3909 if (!mod->data) {
3910 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3911 "leafref", path);
3912 return EXIT_FAILURE;
3913 }
3914 node = mod->data;
3915
Michal Vasko1f76a282015-08-04 16:16:53 +02003916 } else if (parent_times > 0) {
Radek Krejci2f12f852016-01-08 12:59:57 +01003917 if (parent_tpdf) {
3918 /* the path is not allowed to contain relative path since we are in top level typedef */
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003919 LOGVAL(LYE_NORESOLV, 0, NULL, "leafref", path);
Radek Krejci2f12f852016-01-08 12:59:57 +01003920 return -1;
3921 }
3922
Michal Vasko94458082016-10-07 14:34:36 +02003923 /* we are looking for a sibling of a node, node it's parent (that is why parent_times - 1) */
3924 for (i = 0, node = parent; i < parent_times - 1; i++) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02003925 /* path is supposed to be evaluated in data tree, so we have to skip
3926 * all schema nodes that cannot be instantiated in data tree */
3927 for (node = lys_parent(node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003928 node && !(node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Radek Krejci3a5501d2016-07-18 22:03:34 +02003929 node = lys_parent(node));
3930
Michal Vasko1f76a282015-08-04 16:16:53 +02003931 if (!node) {
Michal Vaskoe9914d12016-10-07 14:32:37 +02003932 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003933 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003934 }
3935 }
Radek Krejci990af1f2016-11-09 13:53:36 +01003936
3937 /* now we have to check that if we are going into a node from a different module,
3938 * the module is implemented (so its augments are applied) */
3939 mod = prefix ? lys_get_import_module(mod_start, NULL, 0, prefix, pref_len) : mod_start;
3940 if (!mod) {
3941 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
3942 return EXIT_FAILURE;
3943 }
3944 if (!mod->implemented) {
Radek Krejci2eee5c02016-12-06 19:18:05 +01003945 mod = lys_implemented_module(mod);
Radek Krejci990af1f2016-11-09 13:53:36 +01003946 if (!mod->implemented) {
3947 /* make the found module implemented */
3948 if (lys_set_implemented(mod)) {
3949 return EXIT_FAILURE;
3950 }
3951 }
3952 }
Michal Vaskoe01eca52015-08-13 14:42:02 +02003953 } else {
3954 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003955 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003956 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003957 } else {
Radek Krejci990af1f2016-11-09 13:53:36 +01003958 /* we have to first check that the module we are going into is implemented */
3959 mod = prefix ? lys_get_import_module(mod_start, NULL, 0, prefix, pref_len) : mod_start;
3960 if (!mod) {
3961 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
3962 return EXIT_FAILURE;
3963 }
3964 if (!mod->implemented) {
Radek Krejci2eee5c02016-12-06 19:18:05 +01003965 mod = lys_implemented_module(mod);
Radek Krejci990af1f2016-11-09 13:53:36 +01003966 if (!mod->implemented) {
3967 /* make the found module implemented */
3968 if (lys_set_implemented(mod)) {
3969 return EXIT_FAILURE;
3970 }
3971 }
3972 }
3973
Michal Vasko7dc71d02016-03-15 10:42:28 +01003974 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02003975 if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko2f5aceb2016-03-22 10:24:14 +01003976 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 +01003977 return -1;
3978 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003979 node = node->child;
Radek Krejci43ccc4c2016-10-18 20:40:06 +02003980 if (!node) {
3981 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3982 "leafref", path);
3983 return EXIT_FAILURE;
3984 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003985 }
3986
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003987 rc = lys_get_data_sibling(mod, node, name, nam_len, LYS_LIST | LYS_CONTAINER | LYS_RPC | LYS_ACTION | LYS_NOTIF
3988 | LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA, &node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003989 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003990 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko7a55bea2016-05-02 14:51:20 +02003991 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003992 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003993
Michal Vaskoe27516a2016-10-10 17:55:31 +00003994 if (first_iter) {
3995 /* set external dependency flag, we can decide based on the first found node */
3996 if (!parent_tpdf && op_node && parent_times &&
3997 resolve_path_arg_schema_valid_dep_flag(op_node, node, (parent_times == -1 ? 1 : 0))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01003998 parent->flags |= LYS_LEAFREF_DEP;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003999 }
4000 first_iter = 0;
4001 }
4002
Michal Vasko1f76a282015-08-04 16:16:53 +02004003 if (has_predicate) {
4004 /* we have predicate, so the current result must be list */
4005 if (node->nodetype != LYS_LIST) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02004006 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004007 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02004008 }
4009
Michal Vaskoe27516a2016-10-10 17:55:31 +00004010 i = resolve_path_predicate_schema(id, node, parent, op_node);
Radek Krejci27fe55e2016-09-13 17:13:35 +02004011 if (i <= 0) {
4012 if (i == 0) {
4013 return EXIT_FAILURE;
4014 } else { /* i < 0 */
4015 return -1;
4016 }
Michal Vasko1f76a282015-08-04 16:16:53 +02004017 }
4018 id += i;
Michal Vaskof9b35d92016-10-21 15:19:30 +02004019 has_predicate = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02004020 }
4021 } while (id[0]);
4022
Michal Vaskoca917682016-07-25 11:00:37 +02004023 /* the target must be leaf or leaf-list (in YANG 1.1 only) */
Radek Krejci2a5a9602016-11-04 10:21:13 +01004024 if ((node->nodetype != LYS_LEAF) && (node->nodetype != LYS_LEAFLIST)) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02004025 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko51e5c582017-01-19 14:16:39 +01004026 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Leafref target \"%s\" is not a leaf nor a leaf-list.", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004027 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02004028 }
4029
Radek Krejcicf509982015-12-15 09:22:44 +01004030 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01004031 if (lyp_check_status(parent->flags, parent->module, parent->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01004032 node->flags, node->module, node->name, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01004033 return -1;
4034 }
4035
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004036 if (ret) {
4037 *ret = node;
4038 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02004039
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004040 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02004041}
4042
Michal Vasko730dfdf2015-08-11 14:48:05 +02004043/**
Michal Vaskof39142b2015-10-21 11:40:05 +02004044 * @brief Resolve instance-identifier predicate in JSON data format.
4045 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004046 *
Michal Vaskobb211122015-08-19 14:03:11 +02004047 * @param[in] pred Predicate to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004048 * @param[in,out] node_match Nodes matching the restriction without
4049 * the predicate. Nodes not satisfying
4050 * the predicate are removed.
4051 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004052 * @return Number of characters successfully parsed,
4053 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004054 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004055static int
Michal Vaskof39142b2015-10-21 11:40:05 +02004056resolve_predicate(const char *pred, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004057{
Michal Vasko730dfdf2015-08-11 14:48:05 +02004058 /* ... /node[target = value] ... */
Michal Vaskob2f40be2016-09-08 16:03:48 +02004059 struct lyd_node *target;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004060 const char *model, *name, *value;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004061 int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed, pred_iter, k;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004062 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004063
Michal Vasko1f2cc332015-08-19 11:18:32 +02004064 assert(pred && node_match->count);
4065
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004066 idx = -1;
4067 parsed = 0;
4068
Michal Vaskob2f40be2016-09-08 16:03:48 +02004069 pred_iter = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004070 do {
Michal Vaskof39142b2015-10-21 11:40:05 +02004071 if ((i = parse_predicate(pred, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004072 return -parsed+i;
4073 }
4074 parsed += i;
4075 pred += i;
4076
4077 if (isdigit(name[0])) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004078 /* pos */
4079 assert(!value);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004080 idx = atoi(name);
Michal Vaskob2f40be2016-09-08 16:03:48 +02004081 } else if (name[0] != '.') {
4082 /* list keys */
4083 if (pred_iter < 0) {
4084 pred_iter = 1;
4085 } else {
4086 ++pred_iter;
4087 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004088 }
4089
Michal Vaskof2f28a12016-09-09 12:43:06 +02004090 for (cur_idx = 1, j = 0; j < node_match->count; ++cur_idx) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004091 /* target */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004092 if (name[0] == '.') {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004093 /* leaf-list value */
Michal Vaskocf024702015-10-08 15:01:42 +02004094 if (node_match->node[j]->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004095 goto remove_instid;
4096 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004097
4098 target = node_match->node[j];
4099 /* check the value */
4100 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
4101 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
4102 goto remove_instid;
4103 }
4104
4105 } else if (!value) {
4106 /* keyless list position */
4107 if ((node_match->node[j]->schema->nodetype != LYS_LIST)
4108 || ((struct lys_node_list *)node_match->node[j]->schema)->keys) {
4109 goto remove_instid;
4110 }
4111
4112 if (idx != cur_idx) {
4113 goto remove_instid;
4114 }
4115
4116 } else {
4117 /* list key value */
Michal Vaskocf024702015-10-08 15:01:42 +02004118 if (node_match->node[j]->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004119 goto remove_instid;
4120 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004121
4122 /* key module must match the list module */
4123 if (strncmp(node_match->node[j]->schema->module->name, model, mod_len)
4124 || node_match->node[j]->schema->module->name[mod_len]) {
4125 goto remove_instid;
4126 }
4127 /* find the key leaf */
Michal Vasko045182c2016-09-09 12:44:07 +02004128 for (k = 1, target = node_match->node[j]->child; target && (k < pred_iter); k++, target = target->next);
Michal Vaskob2f40be2016-09-08 16:03:48 +02004129 if (!target) {
4130 goto remove_instid;
4131 }
4132 if ((struct lys_node_leaf *)target->schema !=
4133 ((struct lys_node_list *)node_match->node[j]->schema)->keys[pred_iter - 1]) {
4134 goto remove_instid;
4135 }
4136
4137 /* check the value */
4138 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
4139 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
4140 goto remove_instid;
4141 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004142 }
4143
Michal Vaskob2f40be2016-09-08 16:03:48 +02004144 /* instid is ok, continue check with the next one */
Michal Vasko1f2cc332015-08-19 11:18:32 +02004145 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004146 continue;
4147
4148remove_instid:
Michal Vaskob2f40be2016-09-08 16:03:48 +02004149 /* does not fulfill conditions, remove instid record */
Michal Vasko1f2cc332015-08-19 11:18:32 +02004150 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004151 }
4152 } while (has_predicate);
4153
Michal Vaskob2f40be2016-09-08 16:03:48 +02004154 /* check that all list keys were specified */
4155 if ((pred_iter > 0) && node_match->count) {
Michal Vasko045182c2016-09-09 12:44:07 +02004156 j = 0;
4157 while (j < node_match->count) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004158 assert(node_match->node[j]->schema->nodetype == LYS_LIST);
4159 if (pred_iter < ((struct lys_node_list *)node_match->node[j]->schema)->keys_size) {
4160 /* not enough predicates, just remove the list instance */
4161 unres_data_del(node_match, j);
Michal Vasko045182c2016-09-09 12:44:07 +02004162 } else {
4163 ++j;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004164 }
4165 }
4166
4167 if (!node_match->count) {
4168 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier is missing some list keys.");
4169 }
4170 }
4171
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004172 return parsed;
4173}
4174
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004175int
4176lys_check_xpath(struct lys_node *node, int check_place)
Michal Vasko9e635ac2016-10-17 11:44:09 +02004177{
4178 struct lys_node *parent, *elem;
4179 struct lyxp_set set;
4180 uint32_t i;
4181 int rc;
4182
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004183 if (check_place) {
4184 parent = node;
4185 while (parent) {
4186 if (parent->nodetype == LYS_GROUPING) {
4187 /* unresolved grouping, skip for now (will be checked later) */
Michal Vasko9e635ac2016-10-17 11:44:09 +02004188 return EXIT_SUCCESS;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004189 }
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004190 if (parent->nodetype == LYS_AUGMENT) {
4191 if (!((struct lys_node_augment *)parent)->target) {
Radek Krejcidf46e222016-11-08 11:57:37 +01004192 /* unresolved augment */
4193 if (parent->module->implemented) {
4194 /* skip for now (will be checked later) */
4195 return EXIT_FAILURE;
4196 } else {
4197 /* not implemented augment, skip resolving */
4198 return EXIT_SUCCESS;
4199 }
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004200 } else {
4201 parent = ((struct lys_node_augment *)parent)->target;
4202 continue;
4203 }
4204 }
4205 parent = parent->parent;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004206 }
Michal Vasko9e635ac2016-10-17 11:44:09 +02004207 }
4208
4209 rc = lyxp_node_atomize(node, &set);
4210 if (rc) {
4211 return rc;
4212 }
4213
4214 for (parent = node; parent && !(parent->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); parent = lys_parent(parent));
4215
4216 for (i = 0; i < set.used; ++i) {
4217 /* skip roots'n'stuff */
4218 if (set.val.snodes[i].type == LYXP_NODE_ELEM) {
4219 /* XPath expression cannot reference "lower" status than the node that has the definition */
4220 if (lyp_check_status(node->flags, lys_node_module(node), node->name, set.val.snodes[i].snode->flags,
4221 lys_node_module(set.val.snodes[i].snode), set.val.snodes[i].snode->name, node)) {
4222 return -1;
4223 }
4224
4225 if (parent) {
4226 for (elem = set.val.snodes[i].snode; elem && (elem != parent); elem = lys_parent(elem));
4227 if (!elem) {
4228 /* not in node's RPC or notification subtree, set the flag */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01004229 node->flags |= LYS_XPATH_DEP;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004230 break;
4231 }
4232 }
4233 }
4234 }
4235
4236 free(set.val.snodes);
4237 return EXIT_SUCCESS;
4238}
4239
Radek Krejcif71f48f2016-10-25 16:37:24 +02004240static int
4241check_leafref_config(struct lys_node_leaf *leaf, struct lys_type *type)
4242{
4243 int i;
4244
4245 if (type->base == LY_TYPE_LEAFREF) {
4246 if ((leaf->flags & LYS_CONFIG_W) && type->info.lref.target && (type->info.lref.target->flags & LYS_CONFIG_R)) {
4247 LOGVAL(LYE_SPEC, LY_VLOG_LYS, leaf, "The %s is config but refers to a non-config %s.",
4248 strnodetype(leaf->nodetype), strnodetype(type->info.lref.target->nodetype));
4249 return -1;
4250 }
4251 /* we can skip the test in case the leafref is not yet resolved. In that case the test is done in the time
4252 * of leafref resolving (lys_leaf_add_leafref_target()) */
4253 } else if (type->base == LY_TYPE_UNION) {
4254 for (i = 0; i < type->info.uni.count; i++) {
4255 if (check_leafref_config(leaf, &type->info.uni.types[i])) {
4256 return -1;
4257 }
4258 }
4259 }
4260 return 0;
4261}
4262
Michal Vasko9e635ac2016-10-17 11:44:09 +02004263/**
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004264 * @brief Passes config flag down to children, skips nodes without config flags.
4265 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004266 *
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004267 * @param[in] node Siblings and their children to have flags changed.
Michal Vaskoe022a562016-09-27 14:24:15 +02004268 * @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 +02004269 * @param[in] flags Flags to assign to all the nodes.
Radek Krejcib3142312016-11-09 11:04:12 +01004270 * @param[in,out] unres List of unresolved items.
Michal Vaskoa86508c2016-08-26 14:30:19 +02004271 *
4272 * @return 0 on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004273 */
Michal Vaskoa86508c2016-08-26 14:30:19 +02004274static int
Radek Krejcib3142312016-11-09 11:04:12 +01004275inherit_config_flag(struct lys_node *node, int flags, int clear, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004276{
Radek Krejcif71f48f2016-10-25 16:37:24 +02004277 struct lys_node_leaf *leaf;
4278
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004279 assert(!(flags ^ (flags & LYS_CONFIG_MASK)));
Radek Krejci1d82ef62015-08-07 14:44:40 +02004280 LY_TREE_FOR(node, node) {
Radek Krejcib3142312016-11-09 11:04:12 +01004281 if (lys_has_xpath(node) && unres_schema_add_node(node->module, unres, node, UNRES_XPATH, NULL) == -1) {
Michal Vasko9e635ac2016-10-17 11:44:09 +02004282 return -1;
4283 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004284 if (clear) {
4285 node->flags &= ~LYS_CONFIG_MASK;
Michal Vaskoc2a8d362016-09-29 08:50:13 +02004286 node->flags &= ~LYS_CONFIG_SET;
Michal Vaskoe022a562016-09-27 14:24:15 +02004287 } else {
4288 if (node->flags & LYS_CONFIG_SET) {
4289 /* skip nodes with an explicit config value */
4290 if ((flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
4291 LOGVAL(LYE_INARG, LY_VLOG_LYS, node, "true", "config");
Michal Vasko51e5c582017-01-19 14:16:39 +01004292 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "State nodes cannot have configuration nodes as children.");
Michal Vaskoe022a562016-09-27 14:24:15 +02004293 return -1;
4294 }
4295 continue;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004296 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004297
4298 if (!(node->nodetype & (LYS_USES | LYS_GROUPING))) {
4299 node->flags = (node->flags & ~LYS_CONFIG_MASK) | flags;
4300 /* check that configuration lists have keys */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004301 if ((node->nodetype == LYS_LIST) && (node->flags & LYS_CONFIG_W)
4302 && !((struct lys_node_list *)node)->keys_size) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004303 LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_LYS, node, "key", "list");
4304 return -1;
4305 }
4306 }
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004307 }
Radek Krejcibf2abff2016-08-23 15:51:52 +02004308 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Radek Krejcib3142312016-11-09 11:04:12 +01004309 if (inherit_config_flag(node->child, flags, clear, unres)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004310 return -1;
4311 }
Radek Krejcif71f48f2016-10-25 16:37:24 +02004312 } else if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
4313 leaf = (struct lys_node_leaf *)node;
4314 if (check_leafref_config(leaf, &leaf->type)) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02004315 return -1;
4316 }
4317 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004318 }
Michal Vaskoa86508c2016-08-26 14:30:19 +02004319
4320 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004321}
4322
Michal Vasko730dfdf2015-08-11 14:48:05 +02004323/**
Michal Vasko7178e692016-02-12 15:58:05 +01004324 * @brief Resolve augment target. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004325 *
Michal Vaskobb211122015-08-19 14:03:11 +02004326 * @param[in] aug Augment to use.
Michal Vasko3edeaf72016-02-11 13:17:43 +01004327 * @param[in] siblings Nodes where to start the search in. If set, uses augment, if not, standalone augment.
Radek Krejcib3142312016-11-09 11:04:12 +01004328 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004329 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004330 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004331 */
Michal Vasko7178e692016-02-12 15:58:05 +01004332static int
Radek Krejcib3142312016-11-09 11:04:12 +01004333resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004334{
Michal Vaskoe022a562016-09-27 14:24:15 +02004335 int rc, clear_config;
Michal Vasko1d87a922015-08-21 12:57:16 +02004336 struct lys_node *sub;
Pavol Vican47319932016-08-29 09:14:47 +02004337 const struct lys_node *aug_target, *parent;
Radek Krejci27fe55e2016-09-13 17:13:35 +02004338 struct lys_module *mod;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004339
Michal Vasko15b36692016-08-26 15:29:54 +02004340 assert(aug && !aug->target);
Radek Krejcidf46e222016-11-08 11:57:37 +01004341 mod = lys_main_module(aug->module);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004342
Michal Vasko15b36692016-08-26 15:29:54 +02004343 /* resolve target node */
Radek Krejcidf46e222016-11-08 11:57:37 +01004344 rc = resolve_augment_schema_nodeid(aug->target_name, siblings, (siblings ? NULL : aug->module), mod->implemented, &aug_target);
Michal Vasko15b36692016-08-26 15:29:54 +02004345 if (rc == -1) {
4346 return -1;
Radek Krejci5fb4c382016-11-28 09:21:42 +01004347 } else if (rc > 0) {
Michal Vasko15b36692016-08-26 15:29:54 +02004348 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, aug, aug->target_name[rc - 1], &aug->target_name[rc - 1]);
4349 return -1;
Radek Krejci5fb4c382016-11-28 09:21:42 +01004350 } else if (rc == 0 && aug->target) {
4351 /* augment was resolved as a side effect of setting module implemented when
4352 * resolving augment schema nodeid, so we are done here */
4353 return 0;
Michal Vasko15b36692016-08-26 15:29:54 +02004354 }
Radek Krejcidf46e222016-11-08 11:57:37 +01004355 if (!aug_target && mod->implemented) {
Michal Vasko15b36692016-08-26 15:29:54 +02004356 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
4357 return EXIT_FAILURE;
4358 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02004359 /* check that we want to connect augment into its target */
Radek Krejci27fe55e2016-09-13 17:13:35 +02004360 if (!mod->implemented) {
4361 /* it must be augment only to the same module,
4362 * otherwise we do not apply augment in not-implemented
4363 * module. If the module is set to be implemented in future,
4364 * the augment is being resolved and checked again */
Radek Krejcidf46e222016-11-08 11:57:37 +01004365 if (!aug_target) {
4366 /* target was not even resolved */
4367 return EXIT_SUCCESS;
4368 }
4369 /* target was resolved, but it may refer another module */
4370 for (sub = (struct lys_node *)aug_target; sub; sub = lys_parent(sub)) {
Radek Krejci27fe55e2016-09-13 17:13:35 +02004371 if (lys_node_module(sub) != mod) {
4372 /* this is not an implemented module and the augment
4373 * target some other module, so avoid its connecting
4374 * to the target */
4375 return EXIT_SUCCESS;
4376 }
4377 }
4378 }
4379
Michal Vasko15b36692016-08-26 15:29:54 +02004380 if (!aug->child) {
4381 /* nothing to do */
4382 LOGWRN("Augment \"%s\" without children.", aug->target_name);
Radek Krejci27fe55e2016-09-13 17:13:35 +02004383 goto success;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004384 }
4385
Michal Vaskod58d5962016-03-02 14:29:41 +01004386 /* check for mandatory nodes - if the target node is in another module
4387 * the added nodes cannot be mandatory
4388 */
Michal Vasko15b36692016-08-26 15:29:54 +02004389 if (!aug->parent && (lys_node_module((struct lys_node *)aug) != lys_node_module(aug_target))
Radek Krejcidf24cbe2016-11-08 11:55:51 +01004390 && (rc = lyp_check_mandatory_augment(aug, aug_target))) {
Radek Krejcie00d2312016-08-12 15:27:49 +02004391 return rc;
Michal Vaskod58d5962016-03-02 14:29:41 +01004392 }
4393
Michal Vasko07e89ef2016-03-03 13:28:57 +01004394 /* check augment target type and then augment nodes type */
Michal Vasko15b36692016-08-26 15:29:54 +02004395 if (aug_target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF)) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004396 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004397 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES | LYS_CHOICE))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004398 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
Michal Vasko51e5c582017-01-19 14:16:39 +01004399 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko15b36692016-08-26 15:29:54 +02004400 strnodetype(aug_target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004401 return -1;
4402 }
4403 }
Michal Vasko15b36692016-08-26 15:29:54 +02004404 } else if (aug_target->nodetype == LYS_CHOICE) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004405 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004406 if (!(sub->nodetype & (LYS_CASE | LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004407 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
Michal Vasko51e5c582017-01-19 14:16:39 +01004408 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko15b36692016-08-26 15:29:54 +02004409 strnodetype(aug_target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004410 return -1;
4411 }
4412 }
4413 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01004414 LOGVAL(LYE_INARG, LY_VLOG_LYS, aug, aug->target_name, "target-node");
Michal Vasko51e5c582017-01-19 14:16:39 +01004415 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Invalid augment target node type \"%s\".", strnodetype(aug_target->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004416 return -1;
4417 }
4418
Radek Krejcic071c542016-01-27 14:57:51 +01004419 /* check identifier uniqueness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02004420 LY_TREE_FOR(aug->child, sub) {
Michal Vasko15b36692016-08-26 15:29:54 +02004421 if (lys_check_id(sub, (struct lys_node *)aug_target, NULL)) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02004422 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02004423 }
4424 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004425
Michal Vasko15b36692016-08-26 15:29:54 +02004426 /* finally reconnect augmenting data into the target - add them to the target child list,
4427 * by setting aug->target we know the augment is fully resolved now */
4428 aug->target = (struct lys_node *)aug_target;
4429 if (aug->target->child) {
4430 sub = aug->target->child->prev; /* remember current target's last node */
4431 sub->next = aug->child; /* connect augmenting data after target's last node */
4432 aug->target->child->prev = aug->child->prev; /* new target's last node is last augmenting node */
4433 aug->child->prev = sub; /* finish connecting of both child lists */
4434 } else {
4435 aug->target->child = aug->child;
4436 }
4437
Michal Vasko9e635ac2016-10-17 11:44:09 +02004438 /* inherit config information from actual parent */
4439 for(parent = aug_target; parent && !(parent->nodetype & (LYS_NOTIF | LYS_INPUT | LYS_OUTPUT | LYS_RPC)); parent = lys_parent(parent));
4440 clear_config = (parent) ? 1 : 0;
4441 LY_TREE_FOR(aug->child, sub) {
Radek Krejcib3142312016-11-09 11:04:12 +01004442 if (inherit_config_flag(sub, aug_target->flags & LYS_CONFIG_MASK, clear_config, unres)) {
Michal Vasko9e635ac2016-10-17 11:44:09 +02004443 return -1;
4444 }
4445 }
4446
Radek Krejci27fe55e2016-09-13 17:13:35 +02004447success:
4448 if (mod->implemented) {
4449 /* make target modules also implemented */
4450 for (sub = aug->target; sub; sub = lys_parent(sub)) {
4451 if (lys_set_implemented(sub->module)) {
4452 return -1;
4453 }
4454 }
4455 }
4456
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004457 return EXIT_SUCCESS;
4458}
4459
Michal Vasko730dfdf2015-08-11 14:48:05 +02004460/**
Pavol Vican855ca622016-09-05 13:07:54 +02004461 * @brief Resolve (find) choice default case. Does not log.
4462 *
4463 * @param[in] choic Choice to use.
4464 * @param[in] dflt Name of the default case.
4465 *
4466 * @return Pointer to the default node or NULL.
4467 */
4468static struct lys_node *
4469resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
4470{
4471 struct lys_node *child, *ret;
4472
4473 LY_TREE_FOR(choic->child, child) {
4474 if (child->nodetype == LYS_USES) {
4475 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
4476 if (ret) {
4477 return ret;
4478 }
4479 }
4480
4481 if (ly_strequal(child->name, dflt, 1) && (child->nodetype & (LYS_ANYDATA | LYS_CASE
Radek Krejci2f792db2016-09-12 10:52:33 +02004482 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE))) {
Pavol Vican855ca622016-09-05 13:07:54 +02004483 return child;
4484 }
4485 }
4486
4487 return NULL;
4488}
4489
4490/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02004491 * @brief Resolve uses, apply augments, refines. Logs directly.
4492 *
Michal Vaskobb211122015-08-19 14:03:11 +02004493 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004494 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004495 *
Michal Vaskodef0db12015-10-07 13:22:48 +02004496 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004497 */
Michal Vasko184521f2015-09-24 13:14:26 +02004498static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004499resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004500{
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004501 struct ly_ctx *ctx = uses->module->ctx; /* shortcut */
Pavol Vican855ca622016-09-05 13:07:54 +02004502 struct lys_node *node = NULL, *next, *iter, **refine_nodes = NULL;
Pavol Vican55abd332016-07-12 15:54:49 +02004503 struct lys_node *node_aux, *parent, *tmp;
Radek Krejci200bf712016-08-16 17:11:04 +02004504 struct lys_node_leaflist *llist;
4505 struct lys_node_leaf *leaf;
Radek Krejci76512572015-08-04 09:47:08 +02004506 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004507 struct lys_restr *must, **old_must;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004508 struct lys_iffeature *iff, **old_iff;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004509 int i, j, k, rc;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004510 uint8_t size, *old_size;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004511 unsigned int usize, usize1, usize2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004512
Michal Vasko71e1aa82015-08-12 12:17:51 +02004513 assert(uses->grp);
Michal Vaskoe7708512016-03-11 10:26:55 +01004514 /* HACK just check that the grouping is resolved */
Michal Vaskodef0db12015-10-07 13:22:48 +02004515 assert(!uses->grp->nacm);
Michal Vasko71e1aa82015-08-12 12:17:51 +02004516
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004517 if (!uses->grp->child) {
4518 /* grouping without children, warning was already displayed */
4519 return EXIT_SUCCESS;
4520 }
4521
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004522 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01004523 LY_TREE_FOR(uses->grp->child, node_aux) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004524 node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, uses->nacm, unres, 0);
Michal Vasko1e62a092015-12-01 12:27:20 +01004525 if (!node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004526 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, uses->grp->name, "uses");
Michal Vasko51e5c582017-01-19 14:16:39 +01004527 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Copying data from grouping failed.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004528 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004529 }
Pavol Vican55abd332016-07-12 15:54:49 +02004530 /* test the name of siblings */
4531 LY_TREE_FOR((uses->parent) ? uses->parent->child : lys_main_module(uses->module)->data, tmp) {
Pavol Vican2510ddc2016-07-18 16:23:44 +02004532 if (!(tmp->nodetype & (LYS_USES | LYS_GROUPING | LYS_CASE)) && ly_strequal(tmp->name, node_aux->name, 1)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004533 goto fail;
Pavol Vican55abd332016-07-12 15:54:49 +02004534 }
4535 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004536 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004537
Michal Vaskodef0db12015-10-07 13:22:48 +02004538 /* we managed to copy the grouping, the rest must be possible to resolve */
4539
Pavol Vican855ca622016-09-05 13:07:54 +02004540 if (uses->refine_size) {
4541 refine_nodes = malloc(uses->refine_size * sizeof *refine_nodes);
4542 if (!refine_nodes) {
4543 LOGMEM;
4544 goto fail;
4545 }
4546 }
4547
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004548 /* apply refines */
4549 for (i = 0; i < uses->refine_size; i++) {
4550 rfn = &uses->refine[i];
Michal Vasko3edeaf72016-02-11 13:17:43 +01004551 rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child, LYS_NO_RPC_NOTIF_NODE,
Radek Krejcif3c71de2016-04-11 12:45:46 +02004552 1, 0, (const struct lys_node **)&node);
Michal Vasko9bb061b2016-02-12 11:00:19 +01004553 if (rc || !node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004554 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004555 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004556 }
4557
Radek Krejci1d82ef62015-08-07 14:44:40 +02004558 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004559 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vasko51e5c582017-01-19 14:16:39 +01004560 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Refine substatements not applicable to the target-node.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004561 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004562 }
Pavol Vican855ca622016-09-05 13:07:54 +02004563 refine_nodes[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004564
4565 /* description on any nodetype */
4566 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004567 lydict_remove(ctx, node->dsc);
4568 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004569 }
4570
4571 /* reference on any nodetype */
4572 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004573 lydict_remove(ctx, node->ref);
4574 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004575 }
4576
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004577 /* config on any nodetype,
4578 * in case of notification or rpc/action, the config is not applicable (there is no config status) */
4579 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004580 node->flags &= ~LYS_CONFIG_MASK;
4581 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004582 }
4583
4584 /* default value ... */
Radek Krejci200bf712016-08-16 17:11:04 +02004585 if (rfn->dflt_size) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004586 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004587 /* leaf */
Radek Krejci200bf712016-08-16 17:11:04 +02004588 leaf = (struct lys_node_leaf *)node;
4589
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004590 /* replace default value */
Radek Krejci200bf712016-08-16 17:11:04 +02004591 lydict_remove(ctx, leaf->dflt);
4592 leaf->dflt = lydict_insert(ctx, rfn->dflt[0], 0);
4593
4594 /* check the default value */
Radek Krejci51673202016-11-01 17:00:32 +01004595 if (unres_schema_add_node(leaf->module, unres, &leaf->type, UNRES_TYPE_DFLT,
4596 (struct lys_node *)(&leaf->dflt)) == -1) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004597 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004598 }
Radek Krejci200bf712016-08-16 17:11:04 +02004599 } else if (node->nodetype == LYS_LEAFLIST) {
4600 /* leaf-list */
4601 llist = (struct lys_node_leaflist *)node;
4602
4603 /* remove complete set of defaults in target */
4604 for (i = 0; i < llist->dflt_size; i++) {
4605 lydict_remove(ctx, llist->dflt[i]);
4606 }
4607 free(llist->dflt);
4608
4609 /* copy the default set from refine */
4610 llist->dflt_size = rfn->dflt_size;
4611 llist->dflt = malloc(llist->dflt_size * sizeof *llist->dflt);
4612 for (i = 0; i < llist->dflt_size; i++) {
4613 llist->dflt[i] = lydict_insert(ctx, rfn->dflt[i], 0);
4614 }
4615
4616 /* check default value */
4617 for (i = 0; i < llist->dflt_size; i++) {
Radek Krejci51673202016-11-01 17:00:32 +01004618 if (unres_schema_add_node(llist->module, unres, &llist->type, UNRES_TYPE_DFLT,
4619 (struct lys_node *)(&llist->dflt[i])) == -1) {
Pavol Vican855ca622016-09-05 13:07:54 +02004620 goto fail;
Radek Krejci200bf712016-08-16 17:11:04 +02004621 }
4622 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004623 }
4624 }
4625
4626 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02004627 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004628 if (node->nodetype & (LYS_LEAF | LYS_ANYDATA | LYS_CHOICE)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004629 /* remove current value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004630 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004631
4632 /* set new value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004633 node->flags |= (rfn->flags & LYS_MAND_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004634 }
Pavol Vican855ca622016-09-05 13:07:54 +02004635 if (rfn->flags & LYS_MAND_TRUE) {
4636 /* check if node has default value */
4637 if ((node->nodetype & LYS_LEAF) && ((struct lys_node_leaf *)node)->dflt) {
4638 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"mandatory\" statement is forbidden on leaf with \"default\".");
4639 goto fail;
4640 }
4641 if ((node->nodetype & LYS_CHOICE) && ((struct lys_node_choice *)node)->dflt) {
4642 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"mandatory\" statement is forbidden on choices with \"default\".");
4643 goto fail;
4644 }
4645 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004646 }
4647
4648 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004649 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
4650 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
4651 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004652 }
4653
4654 /* min/max-elements on list or leaf-list */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004655 if (node->nodetype == LYS_LIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004656 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004657 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004658 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004659 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004660 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004661 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02004662 } else if (node->nodetype == LYS_LEAFLIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004663 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004664 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004665 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004666 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004667 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004668 }
4669 }
4670
4671 /* must in leaf, leaf-list, list, container or anyxml */
4672 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004673 switch (node->nodetype) {
4674 case LYS_LEAF:
4675 old_size = &((struct lys_node_leaf *)node)->must_size;
4676 old_must = &((struct lys_node_leaf *)node)->must;
4677 break;
4678 case LYS_LEAFLIST:
4679 old_size = &((struct lys_node_leaflist *)node)->must_size;
4680 old_must = &((struct lys_node_leaflist *)node)->must;
4681 break;
4682 case LYS_LIST:
4683 old_size = &((struct lys_node_list *)node)->must_size;
4684 old_must = &((struct lys_node_list *)node)->must;
4685 break;
4686 case LYS_CONTAINER:
4687 old_size = &((struct lys_node_container *)node)->must_size;
4688 old_must = &((struct lys_node_container *)node)->must;
4689 break;
4690 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02004691 case LYS_ANYDATA:
4692 old_size = &((struct lys_node_anydata *)node)->must_size;
4693 old_must = &((struct lys_node_anydata *)node)->must;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004694 break;
4695 default:
4696 LOGINT;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004697 goto fail;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004698 }
4699
4700 size = *old_size + rfn->must_size;
4701 must = realloc(*old_must, size * sizeof *rfn->must);
4702 if (!must) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004703 LOGMEM;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004704 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004705 }
Pavol Vican855ca622016-09-05 13:07:54 +02004706 for (k = 0, j = *old_size; k < rfn->must_size; k++, j++) {
4707 must[j].expr = lydict_insert(ctx, rfn->must[k].expr, 0);
4708 must[j].dsc = lydict_insert(ctx, rfn->must[k].dsc, 0);
4709 must[j].ref = lydict_insert(ctx, rfn->must[k].ref, 0);
4710 must[j].eapptag = lydict_insert(ctx, rfn->must[k].eapptag, 0);
4711 must[j].emsg = lydict_insert(ctx, rfn->must[k].emsg, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004712 }
4713
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004714 *old_must = must;
4715 *old_size = size;
Michal Vasko508a50d2016-09-07 14:50:33 +02004716
4717 /* check XPath dependencies again */
4718 if (unres_schema_add_node(node->module, unres, node, UNRES_XPATH, NULL) == -1) {
4719 goto fail;
4720 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004721 }
Radek Krejci363bd4a2016-07-29 14:30:20 +02004722
4723 /* if-feature in leaf, leaf-list, list, container or anyxml */
4724 if (rfn->iffeature_size) {
4725 old_size = &node->iffeature_size;
4726 old_iff = &node->iffeature;
4727
4728 size = *old_size + rfn->iffeature_size;
4729 iff = realloc(*old_iff, size * sizeof *rfn->iffeature);
4730 if (!iff) {
4731 LOGMEM;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004732 goto fail;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004733 }
Pavol Vican855ca622016-09-05 13:07:54 +02004734 for (k = 0, j = *old_size; k < rfn->iffeature_size; k++, j++) {
4735 resolve_iffeature_getsizes(&rfn->iffeature[k], &usize1, &usize2);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004736 if (usize1) {
4737 /* there is something to duplicate */
4738 /* duplicate compiled expression */
4739 usize = (usize1 / 4) + (usize1 % 4) ? 1 : 0;
4740 iff[j].expr = malloc(usize * sizeof *iff[j].expr);
Pavol Vican855ca622016-09-05 13:07:54 +02004741 memcpy(iff[j].expr, rfn->iffeature[k].expr, usize * sizeof *iff[j].expr);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004742
4743 /* duplicate list of feature pointers */
Pavol Vican855ca622016-09-05 13:07:54 +02004744 iff[j].features = malloc(usize2 * sizeof *iff[k].features);
4745 memcpy(iff[j].features, rfn->iffeature[k].features, usize2 * sizeof *iff[j].features);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004746 }
4747 }
4748
4749 *old_iff = iff;
4750 *old_size = size;
4751 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004752 }
4753
4754 /* apply augments */
4755 for (i = 0; i < uses->augment_size; i++) {
Radek Krejcib3142312016-11-09 11:04:12 +01004756 rc = resolve_augment(&uses->augment[i], uses->child, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004757 if (rc) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004758 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004759 }
4760 }
4761
Pavol Vican855ca622016-09-05 13:07:54 +02004762 /* check refines */
4763 for (i = 0; i < uses->refine_size; i++) {
4764 node = refine_nodes[i];
4765 rfn = &uses->refine[i];
4766
4767 /* config on any nodetype */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004768 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Pavol Vican855ca622016-09-05 13:07:54 +02004769 for (parent = lys_parent(node); parent && parent->nodetype == LYS_USES; parent = lys_parent(parent));
Radek Krejci5c08a992016-11-02 13:30:04 +01004770 if (parent && parent->nodetype != LYS_GROUPING && (parent->flags & LYS_CONFIG_MASK) &&
Pavol Vican855ca622016-09-05 13:07:54 +02004771 ((parent->flags & LYS_CONFIG_MASK) != (rfn->flags & LYS_CONFIG_MASK)) &&
4772 (rfn->flags & LYS_CONFIG_W)) {
4773 /* setting config true under config false is prohibited */
4774 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
Michal Vasko51e5c582017-01-19 14:16:39 +01004775 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02004776 "changing config from 'false' to 'true' is prohibited while "
4777 "the target's parent is still config 'false'.");
4778 goto fail;
4779 }
4780
4781 /* inherit config change to the target children */
4782 LY_TREE_DFS_BEGIN(node->child, next, iter) {
4783 if (rfn->flags & LYS_CONFIG_W) {
4784 if (iter->flags & LYS_CONFIG_SET) {
4785 /* config is set explicitely, go to next sibling */
4786 next = NULL;
4787 goto nextsibling;
4788 }
4789 } else { /* LYS_CONFIG_R */
4790 if ((iter->flags & LYS_CONFIG_SET) && (iter->flags & LYS_CONFIG_W)) {
4791 /* error - we would have config data under status data */
4792 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
Michal Vasko51e5c582017-01-19 14:16:39 +01004793 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02004794 "changing config from 'true' to 'false' is prohibited while the target "
4795 "has still a children with explicit config 'true'.");
4796 goto fail;
4797 }
4798 }
4799 /* change config */
4800 iter->flags &= ~LYS_CONFIG_MASK;
4801 iter->flags |= (rfn->flags & LYS_CONFIG_MASK);
4802
4803 /* select next iter - modified LY_TREE_DFS_END */
4804 if (iter->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
4805 next = NULL;
4806 } else {
4807 next = iter->child;
4808 }
4809nextsibling:
4810 if (!next) {
4811 /* try siblings */
4812 next = iter->next;
4813 }
4814 while (!next) {
4815 /* parent is already processed, go to its sibling */
4816 iter = lys_parent(iter);
4817
4818 /* no siblings, go back through parents */
4819 if (iter == node) {
4820 /* we are done, no next element to process */
4821 break;
4822 }
4823 next = iter->next;
4824 }
4825 }
4826 }
4827
4828 /* default value */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004829 if (rfn->dflt_size) {
4830 if (node->nodetype == LYS_CHOICE) {
4831 /* choice */
4832 ((struct lys_node_choice *)node)->dflt = resolve_choice_dflt((struct lys_node_choice *)node,
4833 rfn->dflt[0]);
4834 if (!((struct lys_node_choice *)node)->dflt) {
4835 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->dflt[0], "default");
4836 goto fail;
4837 }
4838 if (lyp_check_mandatory_choice(node)) {
4839 goto fail;
4840 }
Pavol Vican855ca622016-09-05 13:07:54 +02004841 }
4842 }
4843
4844 /* min/max-elements on list or leaf-list */
4845 if (node->nodetype == LYS_LIST) {
4846 if (((struct lys_node_list *)node)->min > ((struct lys_node_list *)node)->max) {
4847 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
4848 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "\"min-elements\" is bigger than \"max-elements\".");
4849 goto fail;
4850 }
4851 } else if (node->nodetype == LYS_LEAFLIST) {
4852 if (((struct lys_node_leaflist *)node)->min > ((struct lys_node_leaflist *)node)->max) {
4853 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
4854 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "\"min-elements\" is bigger than \"max-elements\".");
4855 goto fail;
4856 }
4857 }
4858
4859 /* additional checks */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004860 /* default value with mandatory/min-elements */
Pavol Vican855ca622016-09-05 13:07:54 +02004861 if (node->nodetype == LYS_LEAFLIST) {
4862 llist = (struct lys_node_leaflist *)node;
4863 if (llist->dflt_size && llist->min) {
4864 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, rfn->dflt_size ? "default" : "min-elements", "refine");
4865 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
4866 "The \"min-elements\" statement with non-zero value is forbidden on leaf-lists with the \"default\" statement.");
4867 goto fail;
4868 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004869 } else if (node->nodetype == LYS_LEAF) {
4870 leaf = (struct lys_node_leaf *)node;
4871 if (leaf->dflt && (leaf->flags & LYS_MAND_TRUE)) {
4872 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, rfn->dflt_size ? "default" : "mandatory", "refine");
4873 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
4874 "The \"mandatory\" statement is forbidden on leafs with the \"default\" statement.");
4875 goto fail;
4876 }
Pavol Vican855ca622016-09-05 13:07:54 +02004877 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004878
Pavol Vican855ca622016-09-05 13:07:54 +02004879 /* check for mandatory node in default case, first find the closest parent choice to the changed node */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004880 if ((rfn->flags & LYS_MAND_TRUE) || rfn->mod.list.min) {
Pavol Vican855ca622016-09-05 13:07:54 +02004881 for (parent = node->parent;
4882 parent && !(parent->nodetype & (LYS_CHOICE | LYS_GROUPING | LYS_ACTION | LYS_USES));
4883 parent = parent->parent) {
4884 if (parent->nodetype == LYS_CONTAINER && ((struct lys_node_container *)parent)->presence) {
4885 /* stop also on presence containers */
4886 break;
4887 }
4888 }
4889 /* and if it is a choice with the default case, check it for presence of a mandatory node in it */
4890 if (parent && parent->nodetype == LYS_CHOICE && ((struct lys_node_choice *)parent)->dflt) {
4891 if (lyp_check_mandatory_choice(parent)) {
4892 goto fail;
4893 }
4894 }
4895 }
4896 }
4897 free(refine_nodes);
4898
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004899 return EXIT_SUCCESS;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004900
4901fail:
4902 LY_TREE_FOR_SAFE(uses->child, next, iter) {
4903 lys_node_free(iter, NULL, 0);
4904 }
Pavol Vican855ca622016-09-05 13:07:54 +02004905 free(refine_nodes);
Michal Vaskoa86508c2016-08-26 14:30:19 +02004906 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004907}
4908
Radek Krejci018f1f52016-08-03 16:01:20 +02004909static int
4910identity_backlink_update(struct lys_ident *der, struct lys_ident *base)
4911{
4912 int i;
4913
4914 assert(der && base);
4915
Radek Krejci018f1f52016-08-03 16:01:20 +02004916 if (!base->der) {
Radek Krejci85a54be2016-10-20 12:39:56 +02004917 /* create a set for backlinks if it does not exist */
4918 base->der = ly_set_new();
Radek Krejci018f1f52016-08-03 16:01:20 +02004919 }
Radek Krejci85a54be2016-10-20 12:39:56 +02004920 /* store backlink */
4921 ly_set_add(base->der, der, LY_SET_OPT_USEASLIST);
Radek Krejci018f1f52016-08-03 16:01:20 +02004922
Radek Krejci85a54be2016-10-20 12:39:56 +02004923 /* do it recursively */
Radek Krejci018f1f52016-08-03 16:01:20 +02004924 for (i = 0; i < base->base_size; i++) {
4925 if (identity_backlink_update(der, base->base[i])) {
4926 return EXIT_FAILURE;
4927 }
4928 }
4929
4930 return EXIT_SUCCESS;
4931}
4932
Michal Vasko730dfdf2015-08-11 14:48:05 +02004933/**
4934 * @brief Resolve base identity recursively. Does not log.
4935 *
4936 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004937 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004938 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004939 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004940 *
Radek Krejci219fa612016-08-15 10:36:51 +02004941 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on crucial error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004942 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004943static int
Michal Vasko1e62a092015-12-01 12:27:20 +01004944resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Radek Krejci018f1f52016-08-03 16:01:20 +02004945 struct unres_schema *unres, struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004946{
Michal Vaskof02e3742015-08-05 16:27:02 +02004947 uint32_t i, j;
Radek Krejci018f1f52016-08-03 16:01:20 +02004948 struct lys_ident *base = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004949
Radek Krejcicf509982015-12-15 09:22:44 +01004950 assert(ret);
4951
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004952 /* search module */
4953 for (i = 0; i < module->ident_size; i++) {
4954 if (!strcmp(basename, module->ident[i].name)) {
4955
4956 if (!ident) {
4957 /* just search for type, so do not modify anything, just return
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004958 * the base identity pointer */
Radek Krejcicf509982015-12-15 09:22:44 +01004959 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004960 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004961 }
4962
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004963 base = &module->ident[i];
4964 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004965 }
4966 }
4967
4968 /* search submodules */
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004969 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
4970 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
4971 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004972
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004973 if (!ident) {
4974 *ret = &module->inc[j].submodule->ident[i];
4975 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004976 }
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004977
4978 base = &module->inc[j].submodule->ident[i];
4979 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004980 }
4981 }
4982 }
4983
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004984matchfound:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004985 /* we found it somewhere */
Radek Krejcibabbff82016-02-19 13:31:37 +01004986 if (base) {
Radek Krejci018f1f52016-08-03 16:01:20 +02004987 /* is it already completely resolved? */
4988 for (i = 0; i < unres->count; i++) {
Radek Krejciba7b1cc2016-08-08 13:44:43 +02004989 if ((unres->item[i] == base) && (unres->type[i] == UNRES_IDENT)) {
Radek Krejci018f1f52016-08-03 16:01:20 +02004990 /* identity found, but not yet resolved, so do not return it in *res and try it again later */
4991
4992 /* simple check for circular reference,
4993 * the complete check is done as a side effect of using only completely
4994 * resolved identities (previous check of unres content) */
4995 if (ly_strequal((const char *)unres->str_snode[i], ident->name, 1)) {
4996 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, basename, "base");
4997 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Circular reference of \"%s\" identity.", basename);
Radek Krejci219fa612016-08-15 10:36:51 +02004998 return -1;
Radek Krejci018f1f52016-08-03 16:01:20 +02004999 }
5000
Radek Krejci06f64ed2016-08-15 11:07:44 +02005001 return EXIT_FAILURE;
Radek Krejcibabbff82016-02-19 13:31:37 +01005002 }
5003 }
Radek Krejci018f1f52016-08-03 16:01:20 +02005004
Radek Krejcibabbff82016-02-19 13:31:37 +01005005 /* checks done, store the result */
Radek Krejci018f1f52016-08-03 16:01:20 +02005006 *ret = base;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02005007 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005008 }
5009
Radek Krejci219fa612016-08-15 10:36:51 +02005010 /* base not found (maybe a forward reference) */
5011 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005012}
5013
Michal Vasko730dfdf2015-08-11 14:48:05 +02005014/**
5015 * @brief Resolve base identity. Logs directly.
5016 *
5017 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02005018 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005019 * @param[in] basename Base name of the identity.
Radek Krejcibabbff82016-02-19 13:31:37 +01005020 * @param[in] parent Either "type" or "identity".
Radek Krejcicf509982015-12-15 09:22:44 +01005021 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005022 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005023 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005024 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005025static int
Michal Vaskof2d43962016-09-02 11:10:16 +02005026resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char *parent,
Radek Krejci018f1f52016-08-03 16:01:20 +02005027 struct lys_type *type, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005028{
5029 const char *name;
Radek Krejci219fa612016-08-15 10:36:51 +02005030 int mod_name_len = 0, rc;
Radek Krejcicf509982015-12-15 09:22:44 +01005031 struct lys_ident *target, **ret;
Radek Krejci4372b4e2016-04-14 17:42:16 +02005032 uint16_t flags;
Radek Krejcicf509982015-12-15 09:22:44 +01005033 struct lys_module *mod;
5034
5035 assert((ident && !type) || (!ident && type));
5036
5037 if (!type) {
5038 /* have ident to resolve */
5039 ret = &target;
5040 flags = ident->flags;
5041 mod = ident->module;
5042 } else {
5043 /* have type to fill */
Michal Vaskof2d43962016-09-02 11:10:16 +02005044 ++type->info.ident.count;
5045 type->info.ident.ref = ly_realloc(type->info.ident.ref, type->info.ident.count * sizeof *type->info.ident.ref);
5046 if (!type->info.ident.ref) {
5047 LOGMEM;
5048 return -1;
5049 }
5050
5051 ret = &type->info.ident.ref[type->info.ident.count - 1];
Radek Krejcicf509982015-12-15 09:22:44 +01005052 flags = type->parent->flags;
5053 mod = type->parent->module;
5054 }
Michal Vaskof2006002016-04-21 16:28:15 +02005055 *ret = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005056
5057 /* search for the base identity */
5058 name = strchr(basename, ':');
5059 if (name) {
5060 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02005061 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005062 name++;
5063
Michal Vasko2d851a92015-10-20 16:16:36 +02005064 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005065 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02005066 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005067 }
5068 } else {
5069 name = basename;
5070 }
5071
Radek Krejcic071c542016-01-27 14:57:51 +01005072 /* get module where to search */
5073 module = lys_get_import_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len);
5074 if (!module) {
5075 /* identity refers unknown data model */
Radek Krejci02a04992016-03-17 16:06:37 +01005076 LOGVAL(LYE_INMOD, LY_VLOG_NONE, NULL, basename);
Radek Krejcic071c542016-01-27 14:57:51 +01005077 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005078 }
5079
Radek Krejcic071c542016-01-27 14:57:51 +01005080 /* search in the identified module ... */
Radek Krejci219fa612016-08-15 10:36:51 +02005081 rc = resolve_base_ident_sub(module, ident, name, unres, ret);
5082 if (!rc) {
5083 assert(*ret);
5084
5085 /* check status */
5086 if (lyp_check_status(flags, mod, ident ? ident->name : "of type",
5087 (*ret)->flags, (*ret)->module, (*ret)->name, NULL)) {
5088 rc = -1;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02005089 } else {
5090 if (ident) {
5091 ident->base[ident->base_size++] = *ret;
5092
5093 /* maintain backlinks to the derived identities */
5094 rc = identity_backlink_update(ident, *ret) ? -1 : EXIT_SUCCESS;
5095 }
Radek Krejci219fa612016-08-15 10:36:51 +02005096 }
5097 } else if (rc == EXIT_FAILURE) {
5098 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, parent, basename);
Pavol Vican053a2882016-09-05 14:40:33 +02005099 if (type) {
5100 --type->info.ident.count;
5101 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005102 }
5103
Radek Krejci219fa612016-08-15 10:36:51 +02005104 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005105}
5106
Michal Vasko730dfdf2015-08-11 14:48:05 +02005107/**
Michal Vaskof39142b2015-10-21 11:40:05 +02005108 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005109 *
Michal Vaskof2d43962016-09-02 11:10:16 +02005110 * @param[in] type Identityref type.
Michal Vaskofb0873c2015-08-21 09:00:07 +02005111 * @param[in] ident_name Identityref name.
Radek Krejciadb57612016-02-16 13:34:34 +01005112 * @param[in] node Node where the identityref is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02005113 *
5114 * @return Pointer to the identity resolvent, NULL on error.
5115 */
Radek Krejcia52656e2015-08-05 13:41:50 +02005116struct lys_ident *
Michal Vaskof2d43962016-09-02 11:10:16 +02005117resolve_identref(struct lys_type *type, const char *ident_name, struct lyd_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005118{
Radek Krejci639491e2016-12-05 13:30:42 +01005119 const char *mod_name, *name, *mod_name_iter;
Radek Krejci85a54be2016-10-20 12:39:56 +02005120 int mod_name_len, rc, i;
5121 unsigned int u;
Michal Vaskof2d43962016-09-02 11:10:16 +02005122 struct lys_ident *der, *cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005123
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005124 assert(type && ident_name && node);
5125
Michal Vaskof2d43962016-09-02 11:10:16 +02005126 if (!type || (!type->info.ident.count && !type->der) || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005127 return NULL;
5128 }
5129
Michal Vaskoc633ca02015-08-21 14:03:51 +02005130 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, NULL);
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005131 if (rc < 1) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005132 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005133 return NULL;
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005134 } else if (rc < (signed)strlen(ident_name)) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005135 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[rc], &ident_name[rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005136 return NULL;
5137 }
Radek Krejcif32c5f62016-12-05 09:27:38 +01005138 if (!mod_name) {
5139 /* no prefix, identity must be defined in the same module as node */
Radek Krejci639491e2016-12-05 13:30:42 +01005140 mod_name = lys_main_module(node->schema->module)->name;
Radek Krejcif32c5f62016-12-05 09:27:38 +01005141 mod_name_len = strlen(mod_name);
5142 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02005143
Michal Vaskof2d43962016-09-02 11:10:16 +02005144 /* go through all the bases in all the derived types */
5145 while (type->der) {
5146 for (i = 0; i < type->info.ident.count; ++i) {
5147 cur = type->info.ident.ref[i];
Radek Krejci639491e2016-12-05 13:30:42 +01005148 mod_name_iter = lys_main_module(cur->module)->name;
Radek Krejcif32c5f62016-12-05 09:27:38 +01005149 if (!strcmp(cur->name, name) &&
Radek Krejci639491e2016-12-05 13:30:42 +01005150 !strncmp(mod_name_iter, mod_name, mod_name_len) && !mod_name_iter[mod_name_len]) {
Michal Vaskof2d43962016-09-02 11:10:16 +02005151 goto match;
5152 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02005153
Radek Krejci85a54be2016-10-20 12:39:56 +02005154 if (cur->der) {
5155 /* there are also some derived identities */
5156 for (u = 0; u < cur->der->number; u++) {
5157 der = (struct lys_ident *)cur->der->set.g[u]; /* shortcut */
Radek Krejci639491e2016-12-05 13:30:42 +01005158 mod_name_iter = lys_main_module(der->module)->name;
Radek Krejci85a54be2016-10-20 12:39:56 +02005159 if (!strcmp(der->name, name) &&
Radek Krejci639491e2016-12-05 13:30:42 +01005160 !strncmp(mod_name_iter, mod_name, mod_name_len) && !mod_name_iter[mod_name_len]) {
Radek Krejci85a54be2016-10-20 12:39:56 +02005161 /* we have match */
5162 cur = der;
5163 goto match;
5164 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005165 }
5166 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005167 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005168 type = &type->der->type;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005169 }
5170
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005171 LOGVAL(LYE_INRESOLV, LY_VLOG_LYD, node, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005172 return NULL;
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005173
5174match:
Michal Vaskof2d43962016-09-02 11:10:16 +02005175 for (i = 0; i < cur->iffeature_size; i++) {
5176 if (!resolve_iffeature(&cur->iffeature[i])) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005177 LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, cur->name, node->schema->name);
Michal Vasko51e5c582017-01-19 14:16:39 +01005178 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Identity \"%s\" is disabled by its if-feature condition.", cur->name);
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005179 return NULL;
5180 }
5181 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005182 return cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005183}
5184
Michal Vasko730dfdf2015-08-11 14:48:05 +02005185/**
Michal Vaskobb211122015-08-19 14:03:11 +02005186 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005187 *
Michal Vaskobb211122015-08-19 14:03:11 +02005188 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005189 * @param[in] unres Specific unres item.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005190 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005191 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005192 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005193static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005194resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005195{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005196 int rc;
Radek Krejci010e54b2016-03-15 09:40:34 +01005197 struct lys_node *par_grp;
Michal Vaskoe91afce2015-08-12 12:21:00 +02005198
Radek Krejci010e54b2016-03-15 09:40:34 +01005199 /* HACK: when a grouping has uses inside, all such uses have to be resolved before the grouping itself
5200 * is used in some uses. When we see such a uses, the grouping's nacm member (not used in grouping)
5201 * is used to store number of so far unresolved uses. The grouping cannot be used unless the nacm
5202 * value is decreased back to 0. To remember that the uses already increased grouping's nacm, the
5203 * LYS_USESGRP flag is used. */
Michal Vaskodcf98e62016-05-05 17:53:53 +02005204 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 +02005205
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005206 if (!uses->grp) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01005207 rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
5208 if (rc == -1) {
Michal Vasko92981a62016-10-14 10:25:16 +02005209 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005210 return -1;
5211 } else if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005212 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005213 return -1;
5214 } else if (!uses->grp) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005215 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005216 /* hack - in contrast to lys_node, lys_node_grp has bigger nacm field
5217 * (and smaller flags - it uses only a limited set of flags)
5218 */
5219 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci010e54b2016-03-15 09:40:34 +01005220 uses->flags |= LYS_USESGRP;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005221 }
Michal Vasko92981a62016-10-14 10:25:16 +02005222 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005223 return EXIT_FAILURE;
Michal Vasko12e30842015-08-04 11:54:00 +02005224 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005225 }
5226
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005227 if (uses->grp->nacm) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005228 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005229 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci010e54b2016-03-15 09:40:34 +01005230 uses->flags |= LYS_USESGRP;
Radek Krejcie00d2312016-08-12 15:27:49 +02005231 } else {
5232 /* instantiate grouping only when it is completely resolved */
5233 uses->grp = NULL;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005234 }
Michal Vasko92981a62016-10-14 10:25:16 +02005235 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005236 return EXIT_FAILURE;
5237 }
5238
Radek Krejci48464ed2016-03-17 15:44:09 +01005239 rc = resolve_uses(uses, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005240 if (!rc) {
5241 /* decrease unres count only if not first try */
Radek Krejci010e54b2016-03-15 09:40:34 +01005242 if (par_grp && (uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005243 if (!((struct lys_node_grp *)par_grp)->nacm) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005244 LOGINT;
5245 return -1;
5246 }
Radek Krejci4372b4e2016-04-14 17:42:16 +02005247 ((struct lys_node_grp *)par_grp)->nacm--;
Radek Krejci010e54b2016-03-15 09:40:34 +01005248 uses->flags &= ~LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005249 }
Radek Krejcicf509982015-12-15 09:22:44 +01005250
5251 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005252 if (lyp_check_status(uses->flags, uses->module, "of uses",
Radek Krejciadb57612016-02-16 13:34:34 +01005253 uses->grp->flags, uses->grp->module, uses->grp->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005254 (struct lys_node *)uses)) {
Radek Krejcicf509982015-12-15 09:22:44 +01005255 return -1;
5256 }
5257
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005258 return EXIT_SUCCESS;
5259 }
5260
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005261 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005262}
5263
Michal Vasko730dfdf2015-08-11 14:48:05 +02005264/**
Michal Vasko9957e592015-08-17 15:04:09 +02005265 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005266 *
Michal Vaskobb211122015-08-19 14:03:11 +02005267 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005268 * @param[in] keys_str Keys node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005269 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005270 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005271 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005272static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005273resolve_list_keys(struct lys_node_list *list, const char *keys_str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005274{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005275 int i, len, rc;
Michal Vasko4f0dad02016-02-15 14:08:23 +01005276 const char *value;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005277
5278 for (i = 0; i < list->keys_size; ++i) {
Radek Krejci5c08a992016-11-02 13:30:04 +01005279 if (!list->child) {
5280 /* no child, possible forward reference */
5281 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
5282 return EXIT_FAILURE;
5283 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005284 /* get the key name */
5285 if ((value = strpbrk(keys_str, " \t\n"))) {
5286 len = value - keys_str;
5287 while (isspace(value[0])) {
5288 value++;
5289 }
5290 } else {
5291 len = strlen(keys_str);
5292 }
5293
Michal Vasko0f99d3e2017-01-10 10:50:40 +01005294 rc = lys_get_data_sibling(lys_node_module((struct lys_node *)list), list->child, keys_str, len, LYS_LEAF,
5295 (const struct lys_node **)&list->keys[i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005296 if (rc) {
Michal Vasko7a55bea2016-05-02 14:51:20 +02005297 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
5298 return EXIT_FAILURE;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005299 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005300
Radek Krejci48464ed2016-03-17 15:44:09 +01005301 if (check_key(list, i, keys_str, len)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005302 /* check_key logs */
5303 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005304 }
5305
Radek Krejcicf509982015-12-15 09:22:44 +01005306 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005307 if (lyp_check_status(list->flags, list->module, list->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005308 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
5309 (struct lys_node *)list->keys[i])) {
Radek Krejcicf509982015-12-15 09:22:44 +01005310 return -1;
5311 }
5312
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005313 /* prepare for next iteration */
5314 while (value && isspace(value[0])) {
5315 value++;
5316 }
5317 keys_str = value;
5318 }
5319
Michal Vaskof02e3742015-08-05 16:27:02 +02005320 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005321}
5322
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005323/**
Michal Vaskobf19d252015-10-08 15:39:17 +02005324 * @brief Resolve (check) all must conditions of \p node.
5325 * Logs directly.
5326 *
5327 * @param[in] node Data node with optional must statements.
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005328 * @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 +02005329 *
5330 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
5331 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005332static int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005333resolve_must(struct lyd_node *node, int inout_parent, int ignore_fail)
Michal Vaskof02e3742015-08-05 16:27:02 +02005334{
Michal Vasko3cfa3182017-01-17 10:00:58 +01005335 int node_flags;
Michal Vaskobf19d252015-10-08 15:39:17 +02005336 uint8_t i, must_size;
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005337 struct lys_node *schema;
Michal Vaskobf19d252015-10-08 15:39:17 +02005338 struct lys_restr *must;
5339 struct lyxp_set set;
5340
5341 assert(node);
5342 memset(&set, 0, sizeof set);
5343
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005344 if (inout_parent) {
5345 for (schema = lys_parent(node->schema);
5346 schema && (schema->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES));
5347 schema = lys_parent(schema));
5348 if (!schema || !(schema->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5349 LOGINT;
5350 return -1;
5351 }
5352 must_size = ((struct lys_node_inout *)schema)->must_size;
5353 must = ((struct lys_node_inout *)schema)->must;
5354
Michal Vasko3cfa3182017-01-17 10:00:58 +01005355 node_flags = schema->flags;
5356
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005357 /* context node is the RPC/action */
5358 node = node->parent;
5359 if (!(node->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
5360 LOGINT;
5361 return -1;
5362 }
5363 } else {
5364 switch (node->schema->nodetype) {
5365 case LYS_CONTAINER:
5366 must_size = ((struct lys_node_container *)node->schema)->must_size;
5367 must = ((struct lys_node_container *)node->schema)->must;
5368 break;
5369 case LYS_LEAF:
5370 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
5371 must = ((struct lys_node_leaf *)node->schema)->must;
5372 break;
5373 case LYS_LEAFLIST:
5374 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
5375 must = ((struct lys_node_leaflist *)node->schema)->must;
5376 break;
5377 case LYS_LIST:
5378 must_size = ((struct lys_node_list *)node->schema)->must_size;
5379 must = ((struct lys_node_list *)node->schema)->must;
5380 break;
5381 case LYS_ANYXML:
5382 case LYS_ANYDATA:
5383 must_size = ((struct lys_node_anydata *)node->schema)->must_size;
5384 must = ((struct lys_node_anydata *)node->schema)->must;
5385 break;
5386 case LYS_NOTIF:
5387 must_size = ((struct lys_node_notif *)node->schema)->must_size;
5388 must = ((struct lys_node_notif *)node->schema)->must;
5389 break;
5390 default:
5391 must_size = 0;
5392 break;
5393 }
Michal Vasko3cfa3182017-01-17 10:00:58 +01005394
5395 node_flags = node->schema->flags;
Michal Vaskobf19d252015-10-08 15:39:17 +02005396 }
5397
5398 for (i = 0; i < must_size; ++i) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005399 if (lyxp_eval(must[i].expr, node, LYXP_NODE_ELEM, lyd_node_module(node), &set, LYXP_MUST)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02005400 return -1;
5401 }
5402
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005403 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_MUST);
Michal Vaskobf19d252015-10-08 15:39:17 +02005404
Michal Vasko8146d4c2016-05-09 15:50:29 +02005405 if (!set.val.bool) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01005406 if ((ignore_fail == 1) || ((node_flags & LYS_XPATH_DEP) && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005407 LOGVRB("Must condition \"%s\" not satisfied, but it is not required.", must[i].expr);
5408 } else {
5409 LOGVAL(LYE_NOMUST, LY_VLOG_LYD, node, must[i].expr);
5410 if (must[i].emsg) {
Michal Vasko51e5c582017-01-19 14:16:39 +01005411 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, must[i].emsg);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005412 }
5413 if (must[i].eapptag) {
5414 strncpy(((struct ly_err *)&ly_errno)->apptag, must[i].eapptag, LY_APPTAG_LEN - 1);
5415 }
5416 return 1;
Michal Vasko6ac68282016-04-11 10:56:47 +02005417 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005418 }
5419 }
5420
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005421 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02005422}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005423
Michal Vaskobf19d252015-10-08 15:39:17 +02005424/**
Michal Vasko508a50d2016-09-07 14:50:33 +02005425 * @brief Resolve (find) when condition schema context node. Does not log.
5426 *
5427 * @param[in] schema Schema node with the when condition.
5428 * @param[out] ctx_snode When schema context node.
5429 * @param[out] ctx_snode_type Schema context node type.
5430 */
5431void
5432resolve_when_ctx_snode(const struct lys_node *schema, struct lys_node **ctx_snode, enum lyxp_node_type *ctx_snode_type)
5433{
5434 const struct lys_node *sparent;
5435
5436 /* find a not schema-only node */
5437 *ctx_snode_type = LYXP_NODE_ELEM;
5438 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
5439 if (schema->nodetype == LYS_AUGMENT) {
5440 sparent = ((struct lys_node_augment *)schema)->target;
5441 } else {
5442 sparent = schema->parent;
5443 }
5444 if (!sparent) {
5445 /* context node is the document root (fake root in our case) */
5446 if (schema->flags & LYS_CONFIG_W) {
5447 *ctx_snode_type = LYXP_NODE_ROOT_CONFIG;
5448 } else {
Michal Vaskob94a5e42016-09-08 14:01:56 +02005449 *ctx_snode_type = LYXP_NODE_ROOT;
Michal Vasko508a50d2016-09-07 14:50:33 +02005450 }
Michal Vasko2d2aec12016-09-08 11:42:50 +02005451 /* we need the first top-level sibling, but no uses or groupings */
Michal Vaskob94a5e42016-09-08 14:01:56 +02005452 schema = lys_getnext(NULL, NULL, lys_node_module(schema), 0);
Michal Vasko508a50d2016-09-07 14:50:33 +02005453 break;
5454 }
5455 schema = sparent;
5456 }
5457
5458 *ctx_snode = (struct lys_node *)schema;
5459}
5460
5461/**
Michal Vaskocf024702015-10-08 15:01:42 +02005462 * @brief Resolve (find) when condition context node. Does not log.
5463 *
5464 * @param[in] node Data node, whose conditional definition is being decided.
Michal Vasko508a50d2016-09-07 14:50:33 +02005465 * @param[in] schema Schema node with the when condition.
Michal Vaskoa59495d2016-08-22 09:18:58 +02005466 * @param[out] ctx_node Context node.
5467 * @param[out] ctx_node_type Context node type.
Michal Vaskocf024702015-10-08 15:01:42 +02005468 *
Michal Vaskoa59495d2016-08-22 09:18:58 +02005469 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vaskocf024702015-10-08 15:01:42 +02005470 */
Michal Vaskoa59495d2016-08-22 09:18:58 +02005471static int
5472resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema, struct lyd_node **ctx_node,
5473 enum lyxp_node_type *ctx_node_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005474{
Michal Vaskocf024702015-10-08 15:01:42 +02005475 struct lyd_node *parent;
5476 struct lys_node *sparent;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005477 enum lyxp_node_type node_type;
Michal Vaskocf024702015-10-08 15:01:42 +02005478 uint16_t i, data_depth, schema_depth;
5479
Michal Vasko508a50d2016-09-07 14:50:33 +02005480 resolve_when_ctx_snode(schema, &schema, &node_type);
Michal Vaskocf024702015-10-08 15:01:42 +02005481
Michal Vaskofe989752016-09-08 08:47:26 +02005482 if (node_type == LYXP_NODE_ELEM) {
5483 /* standard element context node */
5484 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
5485 for (sparent = schema, schema_depth = 0;
5486 sparent;
5487 sparent = (sparent->nodetype == LYS_AUGMENT ? ((struct lys_node_augment *)sparent)->target : sparent->parent)) {
5488 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_NOTIF | LYS_RPC)) {
5489 ++schema_depth;
5490 }
Michal Vaskocf024702015-10-08 15:01:42 +02005491 }
Michal Vaskofe989752016-09-08 08:47:26 +02005492 if (data_depth < schema_depth) {
5493 return -1;
5494 }
Michal Vaskocf024702015-10-08 15:01:42 +02005495
Michal Vasko956e8542016-08-26 09:43:35 +02005496 /* find the corresponding data node */
5497 for (i = 0; i < data_depth - schema_depth; ++i) {
5498 node = node->parent;
5499 }
Michal Vaskoa59495d2016-08-22 09:18:58 +02005500 if (node->schema != schema) {
5501 return -1;
5502 }
Michal Vaskofe989752016-09-08 08:47:26 +02005503 } else {
5504 /* root context node */
5505 while (node->parent) {
5506 node = node->parent;
5507 }
5508 while (node->prev->next) {
5509 node = node->prev;
5510 }
Michal Vaskocf024702015-10-08 15:01:42 +02005511 }
5512
Michal Vaskoa59495d2016-08-22 09:18:58 +02005513 *ctx_node = node;
5514 *ctx_node_type = node_type;
5515 return EXIT_SUCCESS;
Michal Vaskocf024702015-10-08 15:01:42 +02005516}
5517
Michal Vasko76c3bd32016-08-24 16:02:52 +02005518/**
5519 * @brief Temporarily unlink nodes as per YANG 1.1 RFC section 7.21.5 for when XPath evaluation.
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005520 * The context node is adjusted if needed.
Michal Vasko76c3bd32016-08-24 16:02:52 +02005521 *
5522 * @param[in] snode Schema node, whose children instances need to be unlinked.
5523 * @param[in,out] node Data siblings where to look for the children of \p snode. If it is unlinked,
5524 * it is moved to point to another sibling still in the original tree.
5525 * @param[in,out] ctx_node When context node, adjusted if needed.
5526 * @param[in] ctx_node_type Context node type, just for information to detect invalid situations.
5527 * @param[out] unlinked_nodes Unlinked siblings. Can be safely appended to \p node afterwards.
5528 * Ordering may change, but there will be no semantic change.
5529 *
5530 * @return EXIT_SUCCESS on success, -1 on error.
5531 */
5532static int
5533resolve_when_unlink_nodes(struct lys_node *snode, struct lyd_node **node, struct lyd_node **ctx_node,
5534 enum lyxp_node_type ctx_node_type, struct lyd_node **unlinked_nodes)
5535{
5536 struct lyd_node *next, *elem;
5537
5538 switch (snode->nodetype) {
5539 case LYS_AUGMENT:
5540 case LYS_USES:
5541 case LYS_CHOICE:
5542 case LYS_CASE:
5543 LY_TREE_FOR(snode->child, snode) {
5544 if (resolve_when_unlink_nodes(snode, node, ctx_node, ctx_node_type, unlinked_nodes)) {
5545 return -1;
5546 }
5547 }
5548 break;
5549 case LYS_CONTAINER:
5550 case LYS_LIST:
5551 case LYS_LEAF:
5552 case LYS_LEAFLIST:
5553 case LYS_ANYXML:
5554 case LYS_ANYDATA:
5555 LY_TREE_FOR_SAFE(lyd_first_sibling(*node), next, elem) {
5556 if (elem->schema == snode) {
5557
5558 if (elem == *ctx_node) {
5559 /* We are going to unlink our context node! This normally cannot happen,
5560 * but we use normal top-level data nodes for faking a document root node,
5561 * so if this is the context node, we just use the next top-level node.
5562 * Additionally, it can even happen that there are no top-level data nodes left,
5563 * all were unlinked, so in this case we pass NULL as the context node/data tree,
5564 * lyxp_eval() can handle this special situation.
5565 */
5566 if (ctx_node_type == LYXP_NODE_ELEM) {
5567 LOGINT;
5568 return -1;
5569 }
5570
5571 if (elem->prev == elem) {
5572 /* unlinking last top-level element, use an empty data tree */
5573 *ctx_node = NULL;
5574 } else {
5575 /* in this case just use the previous/last top-level data node */
5576 *ctx_node = elem->prev;
5577 }
5578 } else if (elem == *node) {
5579 /* We are going to unlink the currently processed node. This does not matter that
5580 * much, but we would lose access to the original data tree, so just move our
5581 * pointer somewhere still inside it.
5582 */
5583 if ((*node)->prev != *node) {
5584 *node = (*node)->prev;
5585 } else {
5586 /* the processed node with sibings were all unlinked, oh well */
5587 *node = NULL;
5588 }
5589 }
5590
5591 /* temporarily unlink the node */
5592 lyd_unlink(elem);
5593 if (*unlinked_nodes) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005594 if (lyd_insert_after((*unlinked_nodes)->prev, elem)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005595 LOGINT;
5596 return -1;
5597 }
5598 } else {
5599 *unlinked_nodes = elem;
5600 }
5601
5602 if (snode->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_ANYDATA)) {
5603 /* there can be only one instance */
5604 break;
5605 }
5606 }
5607 }
5608 break;
5609 default:
5610 LOGINT;
5611 return -1;
5612 }
5613
5614 return EXIT_SUCCESS;
5615}
5616
5617/**
5618 * @brief Relink the unlinked nodes back.
5619 *
5620 * @param[in] node Data node to link the nodes back to. It can actually be the adjusted context node,
5621 * we simply need a sibling from the original data tree.
5622 * @param[in] unlinked_nodes Unlinked nodes to relink to \p node.
5623 * @param[in] ctx_node_type Context node type to distinguish between \p node being the parent
5624 * or the sibling of \p unlinked_nodes.
5625 *
5626 * @return EXIT_SUCCESS on success, -1 on error.
5627 */
5628static int
5629resolve_when_relink_nodes(struct lyd_node *node, struct lyd_node *unlinked_nodes, enum lyxp_node_type ctx_node_type)
5630{
5631 struct lyd_node *elem;
5632
5633 LY_TREE_FOR_SAFE(unlinked_nodes, unlinked_nodes, elem) {
Michal Vaskode1feeb2016-12-20 14:48:42 +01005634 lyd_unlink(elem);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005635 if (ctx_node_type == LYXP_NODE_ELEM) {
5636 if (lyd_insert(node, elem)) {
5637 return -1;
5638 }
5639 } else {
5640 if (lyd_insert_after(node, elem)) {
5641 return -1;
5642 }
5643 }
5644 }
5645
5646 return EXIT_SUCCESS;
5647}
5648
Radek Krejci03b71f72016-03-16 11:10:09 +01005649int
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005650resolve_applies_must(const struct lyd_node *node)
Radek Krejci01696bf2016-03-18 13:19:36 +01005651{
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005652 int ret = 0;
5653 uint8_t must_size;
5654 struct lys_node *schema, *iter;
Radek Krejci46165822016-08-26 14:06:27 +02005655
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005656 assert(node);
5657
5658 schema = node->schema;
5659
5660 /* their own must */
Radek Krejci46165822016-08-26 14:06:27 +02005661 switch (schema->nodetype) {
Radek Krejci01696bf2016-03-18 13:19:36 +01005662 case LYS_CONTAINER:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005663 must_size = ((struct lys_node_container *)schema)->must_size;
5664 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005665 case LYS_LEAF:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005666 must_size = ((struct lys_node_leaf *)schema)->must_size;
5667 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005668 case LYS_LEAFLIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005669 must_size = ((struct lys_node_leaflist *)schema)->must_size;
5670 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005671 case LYS_LIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005672 must_size = ((struct lys_node_list *)schema)->must_size;
5673 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005674 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02005675 case LYS_ANYDATA:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005676 must_size = ((struct lys_node_anydata *)schema)->must_size;
5677 break;
5678 case LYS_NOTIF:
5679 must_size = ((struct lys_node_notif *)schema)->must_size;
5680 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005681 default:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005682 must_size = 0;
5683 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005684 }
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005685
5686 if (must_size) {
5687 ++ret;
5688 }
5689
5690 /* schema may be a direct data child of input/output with must (but it must be first, it needs to be evaluated only once) */
5691 if (!node->prev->next) {
5692 for (iter = lys_parent(schema); iter && (iter->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES)); iter = lys_parent(iter));
5693 if (iter && (iter->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5694 ret += 0x2;
5695 }
5696 }
5697
5698 return ret;
Radek Krejci01696bf2016-03-18 13:19:36 +01005699}
5700
5701int
Radek Krejci46165822016-08-26 14:06:27 +02005702resolve_applies_when(const struct lys_node *schema, int mode, const struct lys_node *stop)
Radek Krejci03b71f72016-03-16 11:10:09 +01005703{
Radek Krejci46165822016-08-26 14:06:27 +02005704 const struct lys_node *parent;
Radek Krejci03b71f72016-03-16 11:10:09 +01005705
Radek Krejci46165822016-08-26 14:06:27 +02005706 assert(schema);
Radek Krejci03b71f72016-03-16 11:10:09 +01005707
Radek Krejci46165822016-08-26 14:06:27 +02005708 if (!(schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)schema)->when)) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005709 return 1;
5710 }
5711
Radek Krejci46165822016-08-26 14:06:27 +02005712 parent = schema;
Radek Krejci03b71f72016-03-16 11:10:09 +01005713 goto check_augment;
5714
Radek Krejci46165822016-08-26 14:06:27 +02005715 while (parent) {
5716 /* stop conditions */
5717 if (!mode) {
5718 /* stop on node that can be instantiated in data tree */
5719 if (!(parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
5720 break;
5721 }
5722 } else {
5723 /* stop on the specified node */
5724 if (parent == stop) {
5725 break;
5726 }
5727 }
5728
5729 if (((const struct lys_node_uses *)parent)->when) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005730 return 1;
5731 }
5732check_augment:
5733
5734 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) &&
Radek Krejci46165822016-08-26 14:06:27 +02005735 (((const struct lys_node_augment *)parent->parent)->when))) {
Michal Vaskoe3655562016-08-24 15:56:17 +02005736 return 1;
Radek Krejci03b71f72016-03-16 11:10:09 +01005737 }
5738 parent = lys_parent(parent);
5739 }
5740
5741 return 0;
5742}
5743
Michal Vaskocf024702015-10-08 15:01:42 +02005744/**
5745 * @brief Resolve (check) all when conditions relevant for \p node.
5746 * Logs directly.
5747 *
5748 * @param[in] node Data node, whose conditional reference, if such, is being decided.
Michal Vaskocf024702015-10-08 15:01:42 +02005749 *
Radek Krejci03b71f72016-03-16 11:10:09 +01005750 * @return
5751 * -1 - error, ly_errno is set
5752 * 0 - true "when" statement
Radek Krejci46165822016-08-26 14:06:27 +02005753 * 0, ly_vecode = LYVE_NOWHEN - false "when" statement
Radek Krejci03b71f72016-03-16 11:10:09 +01005754 * 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 +02005755 */
Radek Krejci46165822016-08-26 14:06:27 +02005756int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005757resolve_when(struct lyd_node *node, int *result, int ignore_fail)
Michal Vaskocf024702015-10-08 15:01:42 +02005758{
Michal Vasko76c3bd32016-08-24 16:02:52 +02005759 struct lyd_node *ctx_node = NULL, *unlinked_nodes, *tmp_node;
Michal Vasko90fc2a32016-08-24 15:58:58 +02005760 struct lys_node *sparent;
Michal Vaskocf024702015-10-08 15:01:42 +02005761 struct lyxp_set set;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005762 enum lyxp_node_type ctx_node_type;
Radek Krejci51093642016-03-29 10:14:59 +02005763 int rc = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02005764
5765 assert(node);
5766 memset(&set, 0, sizeof set);
5767
5768 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)node->schema)->when)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005769 /* make the node dummy for the evaluation */
5770 node->validity |= LYD_VAL_INUSE;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005771 rc = lyxp_eval(((struct lys_node_container *)node->schema)->when->cond, node, LYXP_NODE_ELEM, lyd_node_module(node),
5772 &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005773 node->validity &= ~LYD_VAL_INUSE;
Radek Krejci03b71f72016-03-16 11:10:09 +01005774 if (rc) {
5775 if (rc == 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005776 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005777 }
Radek Krejci51093642016-03-29 10:14:59 +02005778 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005779 }
5780
Radek Krejci03b71f72016-03-16 11:10:09 +01005781 /* set boolean result of the condition */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005782 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02005783 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01005784 node->when_status |= LYD_WHEN_FALSE;
Michal Vasko3cfa3182017-01-17 10:00:58 +01005785 if ((ignore_fail == 1) || ((node->schema->flags & LYS_XPATH_DEP) && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005786 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
5787 ((struct lys_node_container *)node->schema)->when->cond);
5788 } else {
5789 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
5790 goto cleanup;
5791 }
Michal Vaskocf024702015-10-08 15:01:42 +02005792 }
Radek Krejci51093642016-03-29 10:14:59 +02005793
5794 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005795 lyxp_set_cast(&set, LYXP_SET_EMPTY, node, lyd_node_module(node), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005796 }
5797
Michal Vasko90fc2a32016-08-24 15:58:58 +02005798 sparent = node->schema;
Michal Vaskocf024702015-10-08 15:01:42 +02005799 goto check_augment;
5800
5801 /* check when in every schema node that affects node */
Michal Vasko90fc2a32016-08-24 15:58:58 +02005802 while (sparent && (sparent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
5803 if (((struct lys_node_uses *)sparent)->when) {
Michal Vaskocf024702015-10-08 15:01:42 +02005804 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005805 rc = resolve_when_ctx_node(node, sparent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02005806 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02005807 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02005808 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005809 }
5810 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02005811
5812 unlinked_nodes = NULL;
5813 /* we do not want our node pointer to change */
5814 tmp_node = node;
5815 rc = resolve_when_unlink_nodes(sparent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
5816 if (rc) {
5817 goto cleanup;
5818 }
5819
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005820 rc = lyxp_eval(((struct lys_node_uses *)sparent)->when->cond, ctx_node, ctx_node_type, lys_node_module(sparent),
5821 &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005822
5823 if (unlinked_nodes && ctx_node) {
5824 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
5825 rc = -1;
5826 goto cleanup;
5827 }
5828 }
5829
Radek Krejci03b71f72016-03-16 11:10:09 +01005830 if (rc) {
5831 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005832 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005833 }
Radek Krejci51093642016-03-29 10:14:59 +02005834 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005835 }
5836
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005837 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02005838 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01005839 node->when_status |= LYD_WHEN_FALSE;
Michal Vasko3cfa3182017-01-17 10:00:58 +01005840 if ((ignore_fail == 1) || ((sparent->flags & LYS_XPATH_DEP) || (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005841 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
5842 ((struct lys_node_uses *)sparent)->when->cond);
5843 } else {
5844 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
5845 goto cleanup;
5846 }
Michal Vaskocf024702015-10-08 15:01:42 +02005847 }
Radek Krejci51093642016-03-29 10:14:59 +02005848
5849 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005850 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005851 }
5852
5853check_augment:
Michal Vasko90fc2a32016-08-24 15:58:58 +02005854 if ((sparent->parent && (sparent->parent->nodetype == LYS_AUGMENT) && (((struct lys_node_augment *)sparent->parent)->when))) {
Michal Vaskocf024702015-10-08 15:01:42 +02005855 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005856 rc = resolve_when_ctx_node(node, sparent->parent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02005857 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02005858 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02005859 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005860 }
5861 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02005862
5863 unlinked_nodes = NULL;
5864 tmp_node = node;
5865 rc = resolve_when_unlink_nodes(sparent->parent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
5866 if (rc) {
5867 goto cleanup;
5868 }
5869
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005870 rc = lyxp_eval(((struct lys_node_augment *)sparent->parent)->when->cond, ctx_node, ctx_node_type,
5871 lys_node_module(sparent->parent), &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005872
5873 /* reconnect nodes, if ctx_node is NULL then all the nodes were unlinked, but linked together,
5874 * so the tree did not actually change and there is nothing for us to do
5875 */
5876 if (unlinked_nodes && ctx_node) {
5877 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
5878 rc = -1;
5879 goto cleanup;
5880 }
5881 }
5882
Radek Krejci03b71f72016-03-16 11:10:09 +01005883 if (rc) {
5884 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005885 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005886 }
Radek Krejci51093642016-03-29 10:14:59 +02005887 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005888 }
5889
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005890 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent->parent), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02005891 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01005892 node->when_status |= LYD_WHEN_FALSE;
Michal Vasko3cfa3182017-01-17 10:00:58 +01005893 if ((ignore_fail == 1) || ((sparent->parent->flags & LYS_XPATH_DEP) && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005894 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
Michal Vasko3cfa3182017-01-17 10:00:58 +01005895 ((struct lys_node_augment *)sparent->parent)->when->cond);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005896 } else {
5897 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
5898 goto cleanup;
5899 }
Michal Vaskocf024702015-10-08 15:01:42 +02005900 }
Radek Krejci51093642016-03-29 10:14:59 +02005901
5902 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005903 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent->parent), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005904 }
5905
Michal Vasko90fc2a32016-08-24 15:58:58 +02005906 sparent = lys_parent(sparent);
Michal Vaskocf024702015-10-08 15:01:42 +02005907 }
5908
Radek Krejci0b7704f2016-03-18 12:16:14 +01005909 node->when_status |= LYD_WHEN_TRUE;
Radek Krejci03b71f72016-03-16 11:10:09 +01005910
Radek Krejci51093642016-03-29 10:14:59 +02005911cleanup:
Radek Krejci51093642016-03-29 10:14:59 +02005912 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005913 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node ? ctx_node : node, NULL, 0);
Radek Krejci51093642016-03-29 10:14:59 +02005914
Radek Krejci46165822016-08-26 14:06:27 +02005915 if (result) {
5916 if (node->when_status & LYD_WHEN_TRUE) {
5917 *result = 1;
5918 } else {
5919 *result = 0;
5920 }
5921 }
5922
Radek Krejci51093642016-03-29 10:14:59 +02005923 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005924}
5925
Radek Krejcicbb473e2016-09-16 14:48:32 +02005926static int
5927check_leafref_features(struct lys_type *type)
5928{
5929 struct lys_node *iter;
5930 struct ly_set *src_parents, *trg_parents, *features;
5931 unsigned int i, j, size, x;
5932 int ret = EXIT_SUCCESS;
5933
5934 assert(type->parent);
5935
5936 src_parents = ly_set_new();
5937 trg_parents = ly_set_new();
5938 features = ly_set_new();
5939
5940 /* get parents chain of source (leafref) */
5941 for (iter = (struct lys_node *)type->parent; iter; iter = iter->parent) {
5942 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
5943 continue;
5944 }
5945 ly_set_add(src_parents, iter, LY_SET_OPT_USEASLIST);
5946 }
5947 /* get parents chain of target */
5948 for (iter = (struct lys_node *)type->info.lref.target; iter; iter = iter->parent) {
5949 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
5950 continue;
5951 }
5952 ly_set_add(trg_parents, iter, LY_SET_OPT_USEASLIST);
5953 }
5954
5955 /* compare the features used in if-feature statements in the rest of both
5956 * chains of parents. The set of features used for target must be a subset
5957 * of features used for the leafref. This is not a perfect, we should compare
5958 * the truth tables but it could require too much resources, so we simplify that */
5959 for (i = 0; i < src_parents->number; i++) {
5960 iter = src_parents->set.s[i]; /* shortcut */
5961 if (!iter->iffeature_size) {
5962 continue;
5963 }
5964 for (j = 0; j < iter->iffeature_size; j++) {
5965 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
5966 for (; size; size--) {
5967 if (!iter->iffeature[j].features[size - 1]) {
5968 /* not yet resolved feature, postpone this check */
5969 ret = EXIT_FAILURE;
5970 goto cleanup;
5971 }
5972 ly_set_add(features, iter->iffeature[j].features[size - 1], 0);
5973 }
5974 }
5975 }
5976 x = features->number;
5977 for (i = 0; i < trg_parents->number; i++) {
5978 iter = trg_parents->set.s[i]; /* shortcut */
5979 if (!iter->iffeature_size) {
5980 continue;
5981 }
5982 for (j = 0; j < iter->iffeature_size; j++) {
5983 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
5984 for (; size; size--) {
5985 if (!iter->iffeature[j].features[size - 1]) {
5986 /* not yet resolved feature, postpone this check */
5987 ret = EXIT_FAILURE;
5988 goto cleanup;
5989 }
5990 if ((unsigned int)ly_set_add(features, iter->iffeature[j].features[size - 1], 0) >= x) {
5991 /* the feature is not present in features set of target's parents chain */
5992 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, type->parent, "leafref", type->info.lref.path);
Michal Vasko51e5c582017-01-19 14:16:39 +01005993 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Radek Krejcicbb473e2016-09-16 14:48:32 +02005994 "Leafref is not conditional based on \"%s\" feature as its target.",
5995 iter->iffeature[j].features[size - 1]->name);
5996 ret = -1;
5997 goto cleanup;
5998 }
5999 }
6000 }
6001 }
6002
6003cleanup:
6004 ly_set_free(features);
6005 ly_set_free(src_parents);
6006 ly_set_free(trg_parents);
6007
6008 return ret;
6009}
6010
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006011/**
Michal Vaskobb211122015-08-19 14:03:11 +02006012 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006013 *
6014 * @param[in] mod Main module.
6015 * @param[in] item Item to resolve. Type determined by \p type.
6016 * @param[in] type Type of the unresolved item.
6017 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02006018 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006019 *
6020 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
6021 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006022static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006023resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Radek Krejci48464ed2016-03-17 15:44:09 +01006024 struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006025{
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006026 /* has_str - whether the str_snode is a string in a dictionary that needs to be freed */
Radek Krejcic79c6b12016-07-26 15:11:49 +02006027 int rc = -1, has_str = 0, tpdf_flag = 0, i, k;
6028 unsigned int j;
Radek Krejcic13db382016-08-16 10:52:42 +02006029 struct lys_node *node, *par_grp;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006030 const char *expr;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006031
Radek Krejcic79c6b12016-07-26 15:11:49 +02006032 struct ly_set *refs, *procs;
6033 struct lys_feature *ref, *feat;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006034 struct lys_ident *ident;
6035 struct lys_type *stype;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006036 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01006037 struct lyxml_elem *yin;
Pavol Vicana0e4e672016-02-24 12:20:04 +01006038 struct yang_type *yang;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006039 struct unres_list_uniq *unique_info;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006040 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006041
6042 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006043 case UNRES_IDENT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006044 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006045 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006046 ident = item;
6047
Radek Krejci018f1f52016-08-03 16:01:20 +02006048 rc = resolve_base_ident(mod, ident, expr, "identity", NULL, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006049 break;
6050 case UNRES_TYPE_IDENTREF:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006051 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006052 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006053 stype = item;
6054
Radek Krejci018f1f52016-08-03 16:01:20 +02006055 rc = resolve_base_ident(mod, NULL, expr, "type", stype, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006056 break;
6057 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02006058 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006059 stype = item;
6060
Radek Krejci2f12f852016-01-08 12:59:57 +01006061 /* HACK - when there is no parent, we are in top level typedef and in that
6062 * case, the path has to contain absolute path, so we let the resolve_path_arg_schema()
6063 * know it via tpdf_flag */
6064 if (!node) {
Radek Krejci4f78b532016-02-17 13:43:00 +01006065 tpdf_flag = 1;
Radek Krejci2f12f852016-01-08 12:59:57 +01006066 node = (struct lys_node *)stype->parent;
6067 }
6068
Radek Krejci27fe55e2016-09-13 17:13:35 +02006069 if (!lys_node_module(node)->implemented) {
6070 /* not implemented module, don't bother with resolving the leafref
Radek Krejci990af1f2016-11-09 13:53:36 +01006071 * if the module is set to be implemented, the path will be resolved then */
Radek Krejci27fe55e2016-09-13 17:13:35 +02006072 rc = 0;
6073 break;
6074 }
Radek Krejci48464ed2016-03-17 15:44:09 +01006075 rc = resolve_path_arg_schema(stype->info.lref.path, node, tpdf_flag,
Michal Vasko1e62a092015-12-01 12:27:20 +01006076 (const struct lys_node **)&stype->info.lref.target);
Michal Vasko01c6fd22016-05-20 11:43:05 +02006077 if (!tpdf_flag && !rc) {
6078 assert(stype->info.lref.target);
Radek Krejcicbb473e2016-09-16 14:48:32 +02006079 /* check if leafref and its target are under a common if-features */
6080 rc = check_leafref_features(stype);
6081 if (rc) {
6082 break;
6083 }
6084
Radek Krejci46c4cd72016-01-21 15:13:52 +01006085 /* store the backlink from leafref target */
Michal Vasko01c6fd22016-05-20 11:43:05 +02006086 if (lys_leaf_add_leafref_target(stype->info.lref.target, (struct lys_node *)stype->parent)) {
6087 rc = -1;
Radek Krejci46c4cd72016-01-21 15:13:52 +01006088 }
Radek Krejci46c4cd72016-01-21 15:13:52 +01006089 }
6090
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006091 break;
Radek Krejci3a5501d2016-07-18 22:03:34 +02006092 case UNRES_TYPE_DER_TPDF:
6093 tpdf_flag = 1;
6094 /* no break */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006095 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01006096 /* parent */
6097 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006098 stype = item;
6099
Michal Vasko88c29542015-11-27 14:57:53 +01006100 /* HACK type->der is temporarily unparsed type statement */
6101 yin = (struct lyxml_elem *)stype->der;
6102 stype->der = NULL;
6103
Pavol Vicana0e4e672016-02-24 12:20:04 +01006104 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6105 yang = (struct yang_type *)yin;
Radek Krejci3a5501d2016-07-18 22:03:34 +02006106 rc = yang_check_type(mod, node, yang, tpdf_flag, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006107
6108 if (rc) {
Pavol Vican8bd72e42016-08-29 09:53:05 +02006109 /* may try again later */
6110 stype->der = (struct lys_tpdf *)yang;
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006111 } else {
6112 /* we need to always be able to free this, it's safe only in this case */
Pavol Vican5f0316a2016-04-05 21:21:11 +02006113 lydict_remove(mod->ctx, yang->name);
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006114 free(yang);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006115 }
6116
Michal Vasko88c29542015-11-27 14:57:53 +01006117 } else {
Radek Krejci3a5501d2016-07-18 22:03:34 +02006118 rc = fill_yin_type(mod, node, yin, stype, tpdf_flag, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006119 if (!rc) {
6120 /* we need to always be able to free this, it's safe only in this case */
6121 lyxml_free(mod->ctx, yin);
6122 } else {
6123 /* may try again later, put all back how it was */
6124 stype->der = (struct lys_tpdf *)yin;
6125 }
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006126 }
Radek Krejcic13db382016-08-16 10:52:42 +02006127 if (rc == EXIT_SUCCESS) {
Radek Krejci2c2fce82016-08-01 13:52:26 +02006128 /* it does not make sense to have leaf-list of empty type */
6129 if (!tpdf_flag && node->nodetype == LYS_LEAFLIST && stype->base == LY_TYPE_EMPTY) {
6130 LOGWRN("The leaf-list \"%s\" is of \"empty\" type, which does not make sense.", node->name);
6131 }
Radek Krejci9b6aad22016-09-20 15:55:51 +02006132 } else if (rc == EXIT_FAILURE && stype->base != LY_TYPE_ERR) {
Radek Krejcic13db382016-08-16 10:52:42 +02006133 /* forward reference - in case the type is in grouping, we have to make the grouping unusable
6134 * by uses statement until the type is resolved. We do that the same way as uses statements inside
6135 * grouping - the grouping's nacm member (not used un grouping) is used to increase the number of
6136 * 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 +02006137 * 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 +02006138 * of the type's base member. */
6139 for (par_grp = node; par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
6140 if (par_grp) {
6141 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci9b6aad22016-09-20 15:55:51 +02006142 stype->base = LY_TYPE_ERR;
Radek Krejcic13db382016-08-16 10:52:42 +02006143 }
Radek Krejci2c2fce82016-08-01 13:52:26 +02006144 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006145 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006146 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006147 iff_data = str_snode;
6148 rc = resolve_feature(iff_data->fname, strlen(iff_data->fname), iff_data->node, item);
Radek Krejci9ff0a922016-07-14 13:08:05 +02006149 if (!rc) {
6150 /* success */
Radek Krejci9de2c042016-10-19 16:53:06 +02006151 if (iff_data->infeature) {
6152 /* store backlink into the target feature to allow reverse changes in case of changing feature status */
6153 feat = *((struct lys_feature **)item);
6154 if (!feat->depfeatures) {
6155 feat->depfeatures = ly_set_new();
6156 }
Radek Krejci85a54be2016-10-20 12:39:56 +02006157 ly_set_add(feat->depfeatures, iff_data->node, LY_SET_OPT_USEASLIST);
Radek Krejci9de2c042016-10-19 16:53:06 +02006158 }
6159 /* cleanup temporary data */
Radek Krejcicbb473e2016-09-16 14:48:32 +02006160 lydict_remove(mod->ctx, iff_data->fname);
6161 free(iff_data);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006162 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006163 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006164 case UNRES_FEATURE:
6165 feat = (struct lys_feature *)item;
6166
6167 if (feat->iffeature_size) {
6168 refs = ly_set_new();
6169 procs = ly_set_new();
6170 ly_set_add(procs, feat, 0);
6171
6172 while (procs->number) {
6173 ref = procs->set.g[procs->number - 1];
6174 ly_set_rm_index(procs, procs->number - 1);
6175
6176 for (i = 0; i < ref->iffeature_size; i++) {
6177 resolve_iffeature_getsizes(&ref->iffeature[i], NULL, &j);
6178 for (; j > 0 ; j--) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006179 if (ref->iffeature[i].features[j - 1]) {
Radek Krejcic79c6b12016-07-26 15:11:49 +02006180 if (ref->iffeature[i].features[j - 1] == feat) {
6181 LOGVAL(LYE_CIRC_FEATURES, LY_VLOG_NONE, NULL, feat->name);
6182 goto featurecheckdone;
6183 }
6184
6185 if (ref->iffeature[i].features[j - 1]->iffeature_size) {
6186 k = refs->number;
6187 if (ly_set_add(refs, ref->iffeature[i].features[j - 1], 0) == k) {
6188 /* not yet seen feature, add it for processing */
6189 ly_set_add(procs, ref->iffeature[i].features[j - 1], 0);
6190 }
6191 }
6192 } else {
6193 /* forward reference */
6194 rc = EXIT_FAILURE;
6195 goto featurecheckdone;
6196 }
6197 }
6198
6199 }
6200 }
6201 rc = EXIT_SUCCESS;
6202
6203featurecheckdone:
6204 ly_set_free(refs);
6205 ly_set_free(procs);
6206 }
6207
6208 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006209 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006210 rc = resolve_unres_schema_uses(item, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006211 break;
6212 case UNRES_TYPE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006213 stype = item;
6214
Radek Krejci51673202016-11-01 17:00:32 +01006215 rc = check_default(stype, (const char **)str_snode, mod);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006216 break;
6217 case UNRES_CHOICE_DFLT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006218 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006219 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006220 choic = item;
6221
Radek Krejcie00d2312016-08-12 15:27:49 +02006222 if (!choic->dflt) {
6223 choic->dflt = resolve_choice_dflt(choic, expr);
6224 }
Michal Vasko7955b362015-09-04 14:18:15 +02006225 if (choic->dflt) {
Radek Krejcie00d2312016-08-12 15:27:49 +02006226 rc = lyp_check_mandatory_choice((struct lys_node *)choic);
Michal Vasko7955b362015-09-04 14:18:15 +02006227 } else {
6228 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006229 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006230 break;
6231 case UNRES_LIST_KEYS:
Radek Krejci5c08a992016-11-02 13:30:04 +01006232 rc = resolve_list_keys(item, ((struct lys_node_list *)item)->keys_str);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006233 break;
6234 case UNRES_LIST_UNIQ:
Radek Krejcid09d1a52016-08-11 14:05:45 +02006235 unique_info = (struct unres_list_uniq *)item;
6236 rc = resolve_unique(unique_info->list, unique_info->expr, unique_info->trg_type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006237 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006238 case UNRES_AUGMENT:
Radek Krejcib3142312016-11-09 11:04:12 +01006239 rc = resolve_augment(item, NULL, unres);
Michal Vasko7178e692016-02-12 15:58:05 +01006240 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006241 case UNRES_XPATH:
6242 node = (struct lys_node *)item;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02006243 rc = lys_check_xpath(node, 1);
Michal Vasko508a50d2016-09-07 14:50:33 +02006244 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006245 default:
6246 LOGINT;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006247 break;
6248 }
6249
Radek Krejci54081ce2016-08-12 15:21:47 +02006250 if (has_str && !rc) {
6251 /* the string is no more needed in case of success.
6252 * In case of forward reference, we will try to resolve the string later */
Radek Krejci4f78b532016-02-17 13:43:00 +01006253 lydict_remove(mod->ctx, str_snode);
6254 }
6255
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006256 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006257}
6258
Michal Vaskof02e3742015-08-05 16:27:02 +02006259/* logs directly */
6260static void
Radek Krejci48464ed2016-03-17 15:44:09 +01006261print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006262{
Michal Vaskocb34dc62016-05-20 14:38:37 +02006263 struct lyxml_elem *xml;
6264 struct lyxml_attr *attr;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006265 struct unres_iffeat_data *iff_data;
Radek Krejci76e15e12016-06-22 11:02:24 +02006266 const char *type_name = NULL;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006267
Michal Vaskof02e3742015-08-05 16:27:02 +02006268 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02006269 case UNRES_IDENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006270 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identity", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006271 break;
6272 case UNRES_TYPE_IDENTREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006273 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identityref", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006274 break;
6275 case UNRES_TYPE_LEAFREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006276 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "leafref",
6277 ((struct lys_type *)item)->info.lref.path);
Michal Vaskof02e3742015-08-05 16:27:02 +02006278 break;
Radek Krejci3a5501d2016-07-18 22:03:34 +02006279 case UNRES_TYPE_DER_TPDF:
Michal Vaskof02e3742015-08-05 16:27:02 +02006280 case UNRES_TYPE_DER:
Michal Vaskocb34dc62016-05-20 14:38:37 +02006281 xml = (struct lyxml_elem *)((struct lys_type *)item)->der;
6282 if (xml->flags & LY_YANG_STRUCTURE_FLAG) {
6283 type_name = ((struct yang_type *)xml)->name;
6284 } else {
6285 LY_TREE_FOR(xml->attr, attr) {
6286 if ((attr->type == LYXML_ATTR_STD) && !strcmp(attr->name, "name")) {
6287 type_name = attr->value;
6288 break;
6289 }
6290 }
6291 assert(attr);
6292 }
6293 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "derived type", type_name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006294 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006295 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006296 iff_data = str_node;
6297 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "if-feature", iff_data->fname);
Michal Vaskof02e3742015-08-05 16:27:02 +02006298 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006299 case UNRES_FEATURE:
6300 LOGVRB("There are unresolved if-features for \"%s\" feature circular dependency check, it will be attempted later",
6301 ((struct lys_feature *)item)->name);
6302 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006303 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006304 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "uses", ((struct lys_node_uses *)item)->name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006305 break;
6306 case UNRES_TYPE_DFLT:
Radek Krejci2e2de832016-10-13 16:12:26 +02006307 if (str_node) {
6308 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "type default", (char *)str_node);
6309 } /* else no default value in the type itself, but we are checking some restrictions against
6310 * possible default value of some base type. The failure is caused by not resolved base type,
6311 * so it was already reported */
Michal Vaskof02e3742015-08-05 16:27:02 +02006312 break;
6313 case UNRES_CHOICE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006314 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "choice default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006315 break;
6316 case UNRES_LIST_KEYS:
Radek Krejci48464ed2016-03-17 15:44:09 +01006317 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list keys", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006318 break;
6319 case UNRES_LIST_UNIQ:
Radek Krejci48464ed2016-03-17 15:44:09 +01006320 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list unique", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006321 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006322 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006323 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "augment target",
6324 ((struct lys_node_augment *)item)->target_name);
Michal Vasko7178e692016-02-12 15:58:05 +01006325 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006326 case UNRES_XPATH:
Michal Vasko0d198372016-11-16 11:40:03 +01006327 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "XPath expressions of",
6328 ((struct lys_node *)item)->name);
Michal Vasko508a50d2016-09-07 14:50:33 +02006329 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006330 default:
6331 LOGINT;
Michal Vaskof02e3742015-08-05 16:27:02 +02006332 break;
6333 }
6334}
6335
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006336/**
Michal Vaskobb211122015-08-19 14:03:11 +02006337 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006338 *
6339 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006340 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006341 *
Michal Vasko92b8a382015-08-19 14:03:49 +02006342 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006343 */
Michal Vaskof02e3742015-08-05 16:27:02 +02006344int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006345resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02006346{
Radek Krejci010e54b2016-03-15 09:40:34 +01006347 uint32_t i, resolved = 0, unres_count, res_count;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006348 int rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006349
6350 assert(unres);
6351
Michal Vaskoe8734262016-09-29 14:12:06 +02006352 LOGVRB("Resolving \"%s\" unresolved schema nodes and their constraints...", mod->name);
Radek Krejci010e54b2016-03-15 09:40:34 +01006353 ly_vlog_hide(1);
Michal Vasko51054ca2015-08-12 12:20:00 +02006354
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006355 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02006356 do {
Michal Vasko88c29542015-11-27 14:57:53 +01006357 unres_count = 0;
6358 res_count = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02006359
6360 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006361 /* UNRES_TYPE_LEAFREF must be resolved (for storing leafref target pointers);
Radek Krejcic79c6b12016-07-26 15:11:49 +02006362 * if-features are resolved here to make sure that we will have all if-features for
6363 * later check of feature circular dependency */
Radek Krejci018f1f52016-08-03 16:01:20 +02006364 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006365 continue;
6366 }
Radek Krejci018f1f52016-08-03 16:01:20 +02006367 /* processes UNRES_USES, UNRES_IFFEAT, UNRES_TYPE_DER, UNRES_TYPE_DER_TPDF, UNRES_TYPE_LEAFREF,
Radek Krejci818b0c52016-11-09 15:10:51 +01006368 * UNRES_AUGMENT, UNRES_CHOICE_DFLT and UNRES_IDENT */
Michal Vasko51054ca2015-08-12 12:20:00 +02006369
Michal Vasko88c29542015-11-27 14:57:53 +01006370 ++unres_count;
Radek Krejci48464ed2016-03-17 15:44:09 +01006371 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006372 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006373 unres->type[i] = UNRES_RESOLVED;
6374 ++resolved;
Michal Vasko88c29542015-11-27 14:57:53 +01006375 ++res_count;
Michal Vasko89e15322015-08-17 15:46:55 +02006376 } else if (rc == -1) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006377 ly_vlog_hide(0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02006378 /* print the error */
6379 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006380 return -1;
Radek Krejcic2a180f2016-06-22 13:28:16 +02006381 } else {
6382 /* forward reference, erase ly_errno */
Radek Krejci00a0e712016-10-26 10:24:46 +02006383 ly_err_clean(1);
Michal Vasko51054ca2015-08-12 12:20:00 +02006384 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006385 }
Michal Vasko88c29542015-11-27 14:57:53 +01006386 } while (res_count && (res_count < unres_count));
Michal Vasko51054ca2015-08-12 12:20:00 +02006387
Michal Vasko88c29542015-11-27 14:57:53 +01006388 if (res_count < unres_count) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006389 /* just print the errors */
6390 ly_vlog_hide(0);
6391
6392 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006393 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006394 continue;
6395 }
6396 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
6397 }
Michal Vasko92b8a382015-08-19 14:03:49 +02006398 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006399 }
6400
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006401 /* the rest */
6402 for (i = 0; i < unres->count; ++i) {
6403 if (unres->type[i] == UNRES_RESOLVED) {
6404 continue;
6405 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02006406
Radek Krejci48464ed2016-03-17 15:44:09 +01006407 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01006408 if (rc == 0) {
Pavol Vican88e16c92016-09-07 15:41:50 +02006409 if (unres->type[i] == UNRES_LIST_UNIQ) {
6410 /* free the allocated structure */
6411 free(unres->item[i]);
6412 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006413 unres->type[i] = UNRES_RESOLVED;
6414 ++resolved;
6415 } else if (rc == -1) {
6416 ly_vlog_hide(0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02006417 /* print the error */
6418 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
6419 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006420 }
6421 }
6422
Radek Krejci010e54b2016-03-15 09:40:34 +01006423 ly_vlog_hide(0);
6424
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006425 if (resolved < unres->count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006426 /* try to resolve the unresolved nodes again, it will not resolve anything, but it will print
6427 * all the validation errors
6428 */
6429 for (i = 0; i < unres->count; ++i) {
6430 if (unres->type[i] == UNRES_RESOLVED) {
6431 continue;
6432 }
Radek Krejcib3142312016-11-09 11:04:12 +01006433 if (unres->type[i] == UNRES_XPATH) {
6434 /* unresolvable XPaths are actually supposed to be warnings - they may be
6435 * unresolved due to the not implemented target module so it shouldn't avoid
6436 * parsing the module, but we still want to announce some issue here */
6437 ly_vlog_hide(0xff);
6438 }
Radek Krejci48464ed2016-03-17 15:44:09 +01006439 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejcib3142312016-11-09 11:04:12 +01006440 if (unres->type[i] == UNRES_XPATH && *ly_vlog_hide_location() == 0xff) {
6441 unres->type[i] = UNRES_RESOLVED;
6442 resolved++;
6443 ly_vlog_hide(0);
6444 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006445 }
Radek Krejcib3142312016-11-09 11:04:12 +01006446 if (resolved < unres->count) {
6447 return -1;
6448 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006449 }
6450
Michal Vaskoe8734262016-09-29 14:12:06 +02006451 LOGVRB("All \"%s\" schema nodes and constraints resolved.", mod->name);
Radek Krejcic071c542016-01-27 14:57:51 +01006452 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006453 return EXIT_SUCCESS;
6454}
6455
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006456/**
Michal Vaskobb211122015-08-19 14:03:11 +02006457 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006458 *
6459 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006460 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006461 * @param[in] item Item to resolve. Type determined by \p type.
6462 * @param[in] type Type of the unresolved item.
6463 * @param[in] str String argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006464 *
Michal Vasko3767fb22016-07-21 12:10:57 +02006465 * @return EXIT_SUCCESS on success, EXIT_FAILURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006466 */
6467int
Radek Krejci48464ed2016-03-17 15:44:09 +01006468unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
6469 const char *str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006470{
Radek Krejci54081ce2016-08-12 15:21:47 +02006471 int rc;
6472 const char *dictstr;
6473
6474 dictstr = lydict_insert(mod->ctx, str, 0);
6475 rc = unres_schema_add_node(mod, unres, item, type, (struct lys_node *)dictstr);
6476
Radek Krejcid9c0ce22017-01-20 15:20:16 +01006477 if (rc < 0) {
Radek Krejci54081ce2016-08-12 15:21:47 +02006478 lydict_remove(mod->ctx, dictstr);
6479 }
6480 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006481}
6482
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006483/**
Michal Vaskobb211122015-08-19 14:03:11 +02006484 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006485 *
6486 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006487 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006488 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01006489 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006490 * @param[in] snode Schema node argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006491 *
Radek Krejcid9c0ce22017-01-20 15:20:16 +01006492 * @return EXIT_SUCCESS on success, EXIT_FIALURE on storing the item in unres, -1 on error, -2 if the unres item
6493 * is already in the unres list.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006494 */
6495int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006496unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Radek Krejci48464ed2016-03-17 15:44:09 +01006497 struct lys_node *snode)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006498{
Michal Vaskoef486d72016-09-27 12:10:44 +02006499 int rc, log_hidden;
Radek Krejci850a5de2016-11-08 14:06:40 +01006500 uint32_t u;
Michal Vasko88c29542015-11-27 14:57:53 +01006501 struct lyxml_elem *yin;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006502
Michal Vasko9bf425b2015-10-22 11:42:03 +02006503 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
6504 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006505
Radek Krejci850a5de2016-11-08 14:06:40 +01006506 /* check for duplicities in unres */
6507 for (u = 0; u < unres->count; u++) {
6508 if (unres->type[u] == type && unres->item[u] == item &&
6509 unres->str_snode[u] == snode && unres->module[u] == mod) {
6510 /* duplication, will be resolved later */
Radek Krejcid9c0ce22017-01-20 15:20:16 +01006511 return -2;
Radek Krejci850a5de2016-11-08 14:06:40 +01006512 }
6513 }
6514
Michal Vaskoef486d72016-09-27 12:10:44 +02006515 if (*ly_vlog_hide_location()) {
6516 log_hidden = 1;
6517 } else {
6518 log_hidden = 0;
6519 ly_vlog_hide(1);
6520 }
Radek Krejci48464ed2016-03-17 15:44:09 +01006521 rc = resolve_unres_schema_item(mod, item, type, snode, unres);
Michal Vaskoef486d72016-09-27 12:10:44 +02006522 if (!log_hidden) {
6523 ly_vlog_hide(0);
6524 }
6525
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006526 if (rc != EXIT_FAILURE) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006527 if (rc == -1 && ly_errno == LY_EVALID) {
Radek Krejci2467a492016-10-24 15:16:59 +02006528 ly_err_repeat();
Radek Krejci010e54b2016-03-15 09:40:34 +01006529 }
Radek Krejcid09d1a52016-08-11 14:05:45 +02006530 if (type == UNRES_LIST_UNIQ) {
6531 /* free the allocated structure */
6532 free(item);
Pavol Vican88e16c92016-09-07 15:41:50 +02006533 } else if (rc == -1 && type == UNRES_IFFEAT) {
6534 /* free the allocated resources */
6535 free(*((char **)item));
6536 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006537 return rc;
Radek Krejcif347abc2016-06-22 10:18:47 +02006538 } else {
6539 /* erase info about validation errors */
Radek Krejci00a0e712016-10-26 10:24:46 +02006540 ly_err_clean(1);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006541 }
6542
Radek Krejci48464ed2016-03-17 15:44:09 +01006543 print_unres_schema_item_fail(item, type, snode);
Michal Vaskof02e3742015-08-05 16:27:02 +02006544
Michal Vasko88c29542015-11-27 14:57:53 +01006545 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
Radek Krejci3a5501d2016-07-18 22:03:34 +02006546 if (type == UNRES_TYPE_DER || type == UNRES_TYPE_DER_TPDF) {
Michal Vasko88c29542015-11-27 14:57:53 +01006547 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
Pavol Vicana0e4e672016-02-24 12:20:04 +01006548 if (!(yin->flags & LY_YANG_STRUCTURE_FLAG)) {
6549 lyxml_unlink_elem(mod->ctx, yin, 1);
6550 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
6551 }
Michal Vasko88c29542015-11-27 14:57:53 +01006552 }
6553
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006554 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01006555 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
6556 if (!unres->item) {
6557 LOGMEM;
6558 return -1;
6559 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006560 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01006561 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
6562 if (!unres->type) {
6563 LOGMEM;
6564 return -1;
6565 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006566 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01006567 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
6568 if (!unres->str_snode) {
6569 LOGMEM;
6570 return -1;
6571 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006572 unres->str_snode[unres->count-1] = snode;
Radek Krejcic071c542016-01-27 14:57:51 +01006573 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
6574 if (!unres->module) {
6575 LOGMEM;
6576 return -1;
6577 }
6578 unres->module[unres->count-1] = mod;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006579
Michal Vasko3767fb22016-07-21 12:10:57 +02006580 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006581}
6582
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006583/**
Michal Vaskobb211122015-08-19 14:03:11 +02006584 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006585 *
6586 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006587 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006588 * @param[in] item Old item to be resolved.
6589 * @param[in] type Type of the old unresolved item.
6590 * @param[in] new_item New item to use in the duplicate.
6591 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02006592 * @return EXIT_SUCCESS on success, EXIT_FAILURE if item is not in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006593 */
Michal Vaskodad19402015-08-06 09:51:53 +02006594int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006595unres_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 +02006596{
6597 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006598 struct unres_list_uniq aux_uniq;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006599 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006600
Michal Vaskocf024702015-10-08 15:01:42 +02006601 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006602
Radek Krejcid09d1a52016-08-11 14:05:45 +02006603 /* hack for UNRES_LIST_UNIQ, which stores multiple items behind its item */
6604 if (type == UNRES_LIST_UNIQ) {
6605 aux_uniq.list = item;
6606 aux_uniq.expr = ((struct unres_list_uniq *)new_item)->expr;
6607 item = &aux_uniq;
6608 }
Michal Vasko878e38d2016-09-05 12:17:53 +02006609 i = unres_schema_find(unres, -1, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006610
6611 if (i == -1) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006612 if (type == UNRES_LIST_UNIQ) {
6613 free(new_item);
6614 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02006615 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006616 }
6617
Radek Krejcic79c6b12016-07-26 15:11:49 +02006618 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT) ||
Radek Krejcib69f3232016-09-16 17:41:07 +02006619 (type == UNRES_FEATURE) || (type == UNRES_LIST_UNIQ)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01006620 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006621 LOGINT;
6622 return -1;
6623 }
Radek Krejcicbb473e2016-09-16 14:48:32 +02006624 } else if (type == UNRES_IFFEAT) {
6625 /* duplicate unres_iffeature_data */
6626 iff_data = malloc(sizeof *iff_data);
6627 iff_data->fname = lydict_insert(mod->ctx, ((struct unres_iffeat_data *)unres->str_snode[i])->fname, 0);
6628 iff_data->node = ((struct unres_iffeat_data *)unres->str_snode[i])->node;
6629 if (unres_schema_add_node(mod, unres, new_item, type, (struct lys_node *)iff_data) == -1) {
6630 LOGINT;
6631 return -1;
6632 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006633 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01006634 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006635 LOGINT;
6636 return -1;
6637 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006638 }
Michal Vaskodad19402015-08-06 09:51:53 +02006639
6640 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006641}
6642
Michal Vaskof02e3742015-08-05 16:27:02 +02006643/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006644int
Michal Vasko878e38d2016-09-05 12:17:53 +02006645unres_schema_find(struct unres_schema *unres, int start_on_backwards, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006646{
Michal Vasko878e38d2016-09-05 12:17:53 +02006647 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006648 struct unres_list_uniq *aux_uniq1, *aux_uniq2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006649
Radek Krejciddddd0d2017-01-20 15:20:46 +01006650 if (start_on_backwards >= 0) {
Michal Vasko878e38d2016-09-05 12:17:53 +02006651 i = start_on_backwards;
6652 } else {
6653 i = unres->count - 1;
6654 }
6655 for (; i > -1; i--) {
6656 if (unres->type[i] != type) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006657 continue;
6658 }
6659 if (type != UNRES_LIST_UNIQ) {
Michal Vasko878e38d2016-09-05 12:17:53 +02006660 if (unres->item[i] == item) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006661 break;
6662 }
6663 } else {
6664 aux_uniq1 = (struct unres_list_uniq *)unres->item[i - 1];
6665 aux_uniq2 = (struct unres_list_uniq *)item;
6666 if ((aux_uniq1->list == aux_uniq2->list) && ly_strequal(aux_uniq1->expr, aux_uniq2->expr, 0)) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006667 break;
6668 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006669 }
6670 }
6671
Michal Vasko878e38d2016-09-05 12:17:53 +02006672 return i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006673}
Michal Vasko8bcdf292015-08-19 14:04:43 +02006674
Michal Vaskoede9c472016-06-07 09:38:15 +02006675static void
6676unres_schema_free_item(struct ly_ctx *ctx, struct unres_schema *unres, uint32_t i)
6677{
6678 struct lyxml_elem *yin;
6679 struct yang_type *yang;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006680 struct unres_iffeat_data *iff_data;
Michal Vaskoede9c472016-06-07 09:38:15 +02006681
6682 switch (unres->type[i]) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02006683 case UNRES_TYPE_DER_TPDF:
Michal Vaskoede9c472016-06-07 09:38:15 +02006684 case UNRES_TYPE_DER:
6685 yin = (struct lyxml_elem *)((struct lys_type *)unres->item[i])->der;
6686 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6687 yang =(struct yang_type *)yin;
Pavol Vicancf2af4d2016-12-21 14:13:06 +01006688 ((struct lys_type *)unres->item[i])->base = yang->base;
Michal Vaskoede9c472016-06-07 09:38:15 +02006689 lydict_remove(ctx, yang->name);
6690 free(yang);
Pavol Vicancf2af4d2016-12-21 14:13:06 +01006691 if (((struct lys_type *)unres->item[i])->base == LY_TYPE_UNION) {
6692 yang_free_type_union(ctx, (struct lys_type *)unres->item[i]);
6693 }
Michal Vaskoede9c472016-06-07 09:38:15 +02006694 } else {
6695 lyxml_free(ctx, yin);
6696 }
6697 break;
Pavol Vican88e16c92016-09-07 15:41:50 +02006698 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006699 iff_data = (struct unres_iffeat_data *)unres->str_snode[i];
6700 lydict_remove(ctx, iff_data->fname);
6701 free(unres->str_snode[i]);
Pavol Vican88e16c92016-09-07 15:41:50 +02006702 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02006703 case UNRES_IDENT:
6704 case UNRES_TYPE_IDENTREF:
Michal Vaskoede9c472016-06-07 09:38:15 +02006705 case UNRES_CHOICE_DFLT:
6706 case UNRES_LIST_KEYS:
Michal Vaskoede9c472016-06-07 09:38:15 +02006707 lydict_remove(ctx, (const char *)unres->str_snode[i]);
6708 break;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006709 case UNRES_LIST_UNIQ:
6710 free(unres->item[i]);
6711 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02006712 default:
6713 break;
6714 }
6715 unres->type[i] = UNRES_RESOLVED;
6716}
6717
Michal Vasko88c29542015-11-27 14:57:53 +01006718void
Radek Krejcic071c542016-01-27 14:57:51 +01006719unres_schema_free(struct lys_module *module, struct unres_schema **unres)
Michal Vasko88c29542015-11-27 14:57:53 +01006720{
6721 uint32_t i;
Radek Krejcic071c542016-01-27 14:57:51 +01006722 unsigned int unresolved = 0;
Michal Vasko88c29542015-11-27 14:57:53 +01006723
Radek Krejcic071c542016-01-27 14:57:51 +01006724 if (!unres || !(*unres)) {
6725 return;
Michal Vasko88c29542015-11-27 14:57:53 +01006726 }
6727
Radek Krejcic071c542016-01-27 14:57:51 +01006728 assert(module || (*unres)->count == 0);
6729
6730 for (i = 0; i < (*unres)->count; ++i) {
6731 if ((*unres)->module[i] != module) {
6732 if ((*unres)->type[i] != UNRES_RESOLVED) {
6733 unresolved++;
6734 }
6735 continue;
6736 }
Michal Vaskoede9c472016-06-07 09:38:15 +02006737
6738 /* free heap memory for the specific item */
6739 unres_schema_free_item(module->ctx, *unres, i);
Radek Krejcic071c542016-01-27 14:57:51 +01006740 }
6741
Michal Vaskoede9c472016-06-07 09:38:15 +02006742 /* free it all */
Radek Krejcic071c542016-01-27 14:57:51 +01006743 if (!module || (!unresolved && !module->type)) {
6744 free((*unres)->item);
6745 free((*unres)->type);
6746 free((*unres)->str_snode);
6747 free((*unres)->module);
Radek Krejcic071c542016-01-27 14:57:51 +01006748 free((*unres));
6749 (*unres) = NULL;
6750 }
Michal Vasko88c29542015-11-27 14:57:53 +01006751}
6752
Michal Vasko3cfa3182017-01-17 10:00:58 +01006753static int
6754check_instid_ext_dep(const struct lys_node *sleaf, const char *json_instid)
6755{
6756 struct ly_set *set;
Michal Vasko3c777092017-01-17 14:10:09 +01006757 struct lys_node *op_node, *first_node;
Michal Vasko3cfa3182017-01-17 10:00:58 +01006758 char *buf;
6759
6760 for (op_node = lys_parent(sleaf);
6761 op_node && !(op_node->nodetype & (LYS_NOTIF | LYS_RPC | LYS_ACTION));
6762 op_node = lys_parent(op_node));
6763
6764 if (op_node && lys_parent(op_node)) {
6765 /* nested operation - any absolute path is external */
6766 return 1;
6767 }
6768
6769 /* get the first node from the instid */
6770 buf = strndup(json_instid, strchr(json_instid + 1, '/') - json_instid);
6771 if (!buf) {
6772 LOGMEM;
6773 return -1;
6774 }
6775
6776 /* there is a predicate, remove it */
6777 if (buf[strlen(buf) - 1] == ']') {
6778 assert(strchr(buf, '['));
6779 *strchr(buf, '[') = '\0';
6780 }
6781
6782 /* find the first schema node */
6783 set = lys_find_xpath(sleaf, buf, 0);
6784 if (!set || !set->number) {
6785 free(buf);
Michal Vasko29fd9742017-01-23 09:55:44 +01006786 ly_set_free(set);
Michal Vasko3cfa3182017-01-17 10:00:58 +01006787 return 1;
6788 }
6789 free(buf);
6790
Michal Vasko3c777092017-01-17 14:10:09 +01006791 first_node = set->set.s[0];
6792 ly_set_free(set);
6793
Michal Vasko3cfa3182017-01-17 10:00:58 +01006794 /* based on the first schema node in the path we can decide whether it points to an external tree or not */
6795
6796 if (op_node) {
6797 /* it is an operation, so we're good if it points somewhere inside it */
Michal Vasko3c777092017-01-17 14:10:09 +01006798 if (op_node == first_node) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01006799 assert(set->number == 1);
6800 return 0;
6801 } else {
6802 return 1;
6803 }
6804 }
6805
6806 /* we cannot know whether it points to a tree that is going to be unlinked (application must handle
6807 * this itself), so we say it's not external */
6808 return 0;
6809}
6810
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006811/**
6812 * @brief Resolve instance-identifier in JSON data format. Logs directly.
6813 *
6814 * @param[in] data Data node where the path is used
6815 * @param[in] path Instance-identifier node value.
6816 * @param[in,out] ret Resolved instance or NULL.
6817 *
6818 * @return 0 on success (even if unresolved and \p ret is NULL), -1 on error.
6819 */
6820static int
6821resolve_instid(struct lyd_node *data, const char *path, int req_inst, struct lyd_node **ret)
6822{
6823 int i = 0, j;
6824 const struct lys_module *mod;
6825 struct ly_ctx *ctx = data->schema->module->ctx;
6826 const char *model, *name;
6827 char *str;
6828 int mod_len, name_len, has_predicate;
6829 struct unres_data node_match;
6830
6831 memset(&node_match, 0, sizeof node_match);
6832 *ret = NULL;
6833
6834 /* we need root to resolve absolute path */
6835 for (; data->parent; data = data->parent);
6836 /* we're still parsing it and the pointer is not correct yet */
6837 if (data->prev) {
6838 for (; data->prev->next; data = data->prev);
6839 }
6840
6841 /* search for the instance node */
6842 while (path[i]) {
6843 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
6844 if (j <= 0) {
6845 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
6846 goto error;
6847 }
6848 i += j;
6849
6850 str = strndup(model, mod_len);
6851 if (!str) {
6852 LOGMEM;
6853 goto error;
6854 }
6855 mod = ly_ctx_get_module(ctx, str, NULL);
Michal Vaskof53187d2017-01-13 13:23:14 +01006856 if (ctx->data_clb) {
6857 if (!mod) {
6858 mod = ctx->data_clb(ctx, str, NULL, 0, ctx->data_clb_data);
6859 } else if (!mod->implemented) {
6860 mod = ctx->data_clb(ctx, mod->name, mod->ns, LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
6861 }
6862 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006863 free(str);
6864
Michal Vaskof53187d2017-01-13 13:23:14 +01006865 if (!mod || !mod->implemented || mod->disabled) {
6866 break;
6867 }
6868
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006869 if (resolve_data(mod, name, name_len, data, &node_match)) {
6870 /* no instance exists */
6871 break;
6872 }
6873
6874 if (has_predicate) {
6875 /* we have predicate, so the current results must be list or leaf-list */
6876 j = resolve_predicate(&path[i], &node_match);
6877 if (j < 1) {
6878 LOGVAL(LYE_INPRED, LY_VLOG_LYD, data, &path[i-j]);
6879 goto error;
6880 }
6881 i += j;
6882
6883 if (!node_match.count) {
6884 /* no instance exists */
6885 break;
6886 }
6887 }
6888 }
6889
6890 if (!node_match.count) {
6891 /* no instance exists */
6892 if (req_inst > -1) {
6893 LOGVAL(LYE_NOREQINS, LY_VLOG_NONE, NULL, path);
6894 return EXIT_FAILURE;
6895 }
6896 LOGVRB("There is no instance of \"%s\", but it is not required.", path);
6897 return EXIT_SUCCESS;
6898 } else if (node_match.count > 1) {
6899 /* instance identifier must resolve to a single node */
6900 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
6901 goto error;
6902 } else {
6903 /* we have required result, remember it and cleanup */
6904 *ret = node_match.node[0];
6905 free(node_match.node);
6906 return EXIT_SUCCESS;
6907 }
6908
6909error:
6910 /* cleanup */
6911 free(node_match.node);
6912 return -1;
6913}
6914
6915static int
6916resolve_leafref(struct lyd_node_leaf_list *leaf, const char *path, int req_inst, struct lyd_node **ret)
Radek Krejci7de36cf2016-09-12 16:18:50 +02006917{
Radek Krejci7de36cf2016-09-12 16:18:50 +02006918 struct unres_data matches;
6919 uint32_t i;
6920
Radek Krejci9b6aad22016-09-20 15:55:51 +02006921 /* init */
Radek Krejci7de36cf2016-09-12 16:18:50 +02006922 memset(&matches, 0, sizeof matches);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006923 *ret = NULL;
Radek Krejci7de36cf2016-09-12 16:18:50 +02006924
6925 /* EXIT_FAILURE return keeps leaf->value.lefref NULL, handled later */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006926 if (resolve_path_arg_data((struct lyd_node *)leaf, path, &matches) == -1) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02006927 return -1;
6928 }
6929
6930 /* check that value matches */
6931 for (i = 0; i < matches.count; ++i) {
Radek Krejci1899d6a2016-11-03 13:48:07 +01006932 /* not that the value is already in canonical form since the parsers does the conversion,
6933 * so we can simply compare just the values */
Radek Krejci7de36cf2016-09-12 16:18:50 +02006934 if (ly_strequal(leaf->value_str, ((struct lyd_node_leaf_list *)matches.node[i])->value_str, 1)) {
Radek Krejci1899d6a2016-11-03 13:48:07 +01006935 /* we have the match */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006936 *ret = matches.node[i];
Radek Krejci7de36cf2016-09-12 16:18:50 +02006937 break;
6938 }
6939 }
6940
6941 free(matches.node);
6942
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006943 if (!*ret) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02006944 /* reference not found */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006945 if (req_inst > -1) {
6946 LOGVAL(LYE_NOLEAFREF, LY_VLOG_LYD, leaf, path, leaf->value_str);
Radek Krejci7de36cf2016-09-12 16:18:50 +02006947 return EXIT_FAILURE;
6948 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006949 LOGVRB("There is no leafref \"%s\" with the value \"%s\", but it is not required.", path, leaf->value_str);
Radek Krejci7de36cf2016-09-12 16:18:50 +02006950 }
6951 }
6952
6953 return EXIT_SUCCESS;
6954}
6955
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006956/* ignore fail because we are parsing edit-config, get, or get-config - but only if the union includes leafref or instid */
Michal Vaskofd6c6502017-01-06 12:15:41 +01006957int
6958resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type, int store, int ignore_fail,
6959 struct lys_type **resolved_type)
Radek Krejci9b6aad22016-09-20 15:55:51 +02006960{
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006961 struct lys_type *t;
Michal Vasko3cfa3182017-01-17 10:00:58 +01006962 struct lyd_node *ret;
6963 int found, hidden, success = 0, ext_dep, req_inst;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006964 const char *json_val = NULL;
Radek Krejci9b6aad22016-09-20 15:55:51 +02006965
6966 assert(type->base == LY_TYPE_UNION);
6967
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006968 if ((leaf->value_type == LY_TYPE_UNION) || (leaf->value_type == (LY_TYPE_INST | LY_TYPE_INST_UNRES))) {
6969 /* either NULL or instid previously converted to JSON */
6970 json_val = leaf->value.string;
6971 }
Michal Vasko1c8567a2017-01-05 13:42:27 +01006972
Michal Vaskofd6c6502017-01-06 12:15:41 +01006973 if (store) {
6974 if ((leaf->value_type & LY_DATA_TYPE_MASK) == LY_TYPE_BITS) {
6975 free(leaf->value.bit);
6976 }
6977 memset(&leaf->value, 0, sizeof leaf->value);
Michal Vasko1c8567a2017-01-05 13:42:27 +01006978 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006979
6980 /* turn logging off, we are going to try to validate the value with all the types in order */
6981 hidden = *ly_vlog_hide_location();
6982 ly_vlog_hide(1);
6983
6984 t = NULL;
6985 found = 0;
6986 while ((t = lyp_get_next_union_type(type, t, &found))) {
6987 found = 0;
6988
6989 switch (t->base) {
6990 case LY_TYPE_LEAFREF:
Michal Vasko3cfa3182017-01-17 10:00:58 +01006991 if ((ignore_fail == 1) || ((leaf->schema->flags & LYS_LEAFREF_DEP) && (ignore_fail == 2))) {
6992 req_inst = -1;
6993 } else {
6994 req_inst = t->info.lref.req;
6995 }
6996
6997 if (!resolve_leafref(leaf, t->info.lref.path, req_inst, &ret)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01006998 if (store) {
6999 if (ret && !(leaf->schema->flags & LYS_LEAFREF_DEP)) {
7000 /* valid resolved */
7001 leaf->value.leafref = ret;
7002 leaf->value_type = LY_TYPE_LEAFREF;
7003 } else {
7004 /* valid unresolved */
7005 if (!lyp_parse_value(t, &leaf->value_str, NULL, leaf, 1, 0)) {
7006 return -1;
7007 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007008 }
7009 }
7010
7011 success = 1;
7012 }
7013 break;
7014 case LY_TYPE_INST:
Michal Vasko3cfa3182017-01-17 10:00:58 +01007015 ext_dep = check_instid_ext_dep(leaf->schema, (json_val ? json_val : leaf->value_str));
7016 if ((ignore_fail == 1) || (ext_dep && (ignore_fail == 2))) {
7017 req_inst = -1;
7018 } else {
7019 req_inst = t->info.inst.req;
7020 }
7021
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007022 if (!resolve_instid((struct lyd_node *)leaf, (json_val ? json_val : leaf->value_str),
7023 (ignore_fail ? -1 : t->info.inst.req), &ret)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007024 if (store) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007025 if (ret && !ext_dep) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007026 /* valid resolved */
7027 leaf->value.instance = ret;
7028 leaf->value_type = LY_TYPE_INST;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007029
Michal Vaskofd6c6502017-01-06 12:15:41 +01007030 if (json_val) {
7031 lydict_remove(leaf->schema->module->ctx, leaf->value_str);
7032 leaf->value_str = json_val;
7033 json_val = NULL;
7034 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007035 } else {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007036 /* valid unresolved */
7037 if (json_val) {
7038 /* put the JSON val back */
7039 leaf->value.string = json_val;
7040 json_val = NULL;
7041 } else {
7042 leaf->value.instance = NULL;
7043 }
7044 leaf->value_type = LY_TYPE_INST | LY_TYPE_INST_UNRES;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007045 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007046 }
7047
7048 success = 1;
7049 }
7050 break;
7051 default:
Michal Vaskofd6c6502017-01-06 12:15:41 +01007052 if (lyp_parse_value(t, &leaf->value_str, NULL, leaf, store, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007053 success = 1;
7054 }
7055 break;
7056 }
7057
7058 if (success) {
7059 break;
7060 }
7061
7062 /* erase information about errors - they are false or irrelevant
7063 * and will be replaced by a single error messages */
7064 ly_err_clean(1);
7065
7066 /* erase possible present and invalid value data */
Michal Vaskofd6c6502017-01-06 12:15:41 +01007067 if (store) {
7068 if (t->base == LY_TYPE_BITS) {
7069 free(leaf->value.bit);
7070 }
7071 memset(&leaf->value, 0, sizeof leaf->value);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007072 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007073 }
7074
7075 /* turn logging back on */
7076 if (!hidden) {
7077 ly_vlog_hide(0);
7078 }
7079
7080 if (json_val) {
7081 if (!success) {
7082 /* put the value back for now */
7083 assert(leaf->value_type == LY_TYPE_UNION);
7084 leaf->value.string = json_val;
7085 } else {
7086 /* value was ultimately useless, but we could not have known */
7087 lydict_remove(leaf->schema->module->ctx, json_val);
7088 }
7089 }
7090
Michal Vaskofd6c6502017-01-06 12:15:41 +01007091 if (success) {
7092 if (resolved_type) {
7093 *resolved_type = t;
7094 }
7095 } else if (!ignore_fail || !type->info.uni.has_ptr_type) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007096 /* not found and it is required */
7097 LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, leaf->value_str ? leaf->value_str : "", leaf->schema->name);
Radek Krejci9b6aad22016-09-20 15:55:51 +02007098 return EXIT_FAILURE;
7099 }
7100
7101 return EXIT_SUCCESS;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007102
Radek Krejci9b6aad22016-09-20 15:55:51 +02007103}
7104
Michal Vasko8bcdf292015-08-19 14:04:43 +02007105/**
7106 * @brief Resolve a single unres data item. Logs directly.
7107 *
Michal Vaskocf024702015-10-08 15:01:42 +02007108 * @param[in] node Data node to resolve.
Michal Vaskocf024702015-10-08 15:01:42 +02007109 * @param[in] type Type of the unresolved item.
Michal Vasko3cfa3182017-01-17 10:00:58 +01007110 * @param[in] ignore_fail 0 - no, 1 - yes, 2 - yes, but only for external dependencies.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007111 *
7112 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
7113 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02007114int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007115resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type, int ignore_fail)
Michal Vasko8bcdf292015-08-19 14:04:43 +02007116{
Michal Vasko3cfa3182017-01-17 10:00:58 +01007117 int rc, req_inst, ext_dep;
Michal Vasko83a6c462015-10-08 16:43:53 +02007118 struct lyd_node_leaf_list *leaf;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007119 struct lyd_node *ret;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007120 struct lys_node_leaf *sleaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007121
Michal Vasko83a6c462015-10-08 16:43:53 +02007122 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02007123 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007124
Michal Vaskocf024702015-10-08 15:01:42 +02007125 switch (type) {
7126 case UNRES_LEAFREF:
7127 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007128 assert(leaf->validity & LYD_VAL_LEAFREF);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007129 if ((ignore_fail == 1) || ((leaf->schema->flags & LYS_LEAFREF_DEP) && (ignore_fail == 2))) {
7130 req_inst = -1;
7131 } else {
7132 req_inst = sleaf->type.info.lref.req;
7133 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007134 rc = resolve_leafref(leaf, sleaf->type.info.lref.path, req_inst, &ret);
7135 if (!rc) {
Michal Vaskob1ac8722017-01-02 13:04:25 +01007136 if (ret && !(leaf->schema->flags & LYS_LEAFREF_DEP)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007137 /* valid resolved */
Michal Vasko1c8567a2017-01-05 13:42:27 +01007138 if ((leaf->value_type & LY_DATA_TYPE_MASK) == LY_TYPE_BITS) {
7139 free(leaf->value.bit);
7140 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007141 leaf->value.leafref = ret;
7142 leaf->value_type = LY_TYPE_LEAFREF;
7143 } else {
7144 /* valid unresolved */
7145 if (!(leaf->value_type & LY_TYPE_LEAFREF_UNRES)) {
7146 if (!lyp_parse_value(&sleaf->type, &leaf->value_str, NULL, leaf, 1, 0)) {
7147 return -1;
7148 }
7149 }
7150 }
7151 leaf->validity &= ~LYD_VAL_LEAFREF;
7152 } else {
7153 return rc;
7154 }
7155 break;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007156
Michal Vaskocf024702015-10-08 15:01:42 +02007157 case UNRES_INSTID:
Radek Krejci7de36cf2016-09-12 16:18:50 +02007158 assert(sleaf->type.base == LY_TYPE_INST);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007159 ext_dep = check_instid_ext_dep(leaf->schema, leaf->value_str);
7160 if (ext_dep == -1) {
7161 return -1;
7162 }
7163
7164 if ((ignore_fail == 1) || (ext_dep && (ignore_fail == 2))) {
7165 req_inst = -1;
7166 } else {
7167 req_inst = sleaf->type.info.inst.req;
7168 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007169 rc = resolve_instid(node, leaf->value_str, req_inst, &ret);
7170 if (!rc) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007171 if (ret && !ext_dep) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007172 /* valid resolved */
7173 leaf->value.instance = ret;
7174 leaf->value_type = LY_TYPE_INST;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007175 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007176 /* valid unresolved */
7177 leaf->value.instance = NULL;
7178 leaf->value_type = LY_TYPE_INST | LY_TYPE_INST_UNRES;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007179 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007180 } else {
7181 return rc;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007182 }
Michal Vaskocf024702015-10-08 15:01:42 +02007183 break;
7184
Radek Krejci7de36cf2016-09-12 16:18:50 +02007185 case UNRES_UNION:
7186 assert(sleaf->type.base == LY_TYPE_UNION);
Michal Vaskofd6c6502017-01-06 12:15:41 +01007187 return resolve_union(leaf, &sleaf->type, 1, ignore_fail, NULL);
Radek Krejci7de36cf2016-09-12 16:18:50 +02007188
Michal Vaskocf024702015-10-08 15:01:42 +02007189 case UNRES_WHEN:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007190 if ((rc = resolve_when(node, NULL, ignore_fail))) {
Michal Vaskocf024702015-10-08 15:01:42 +02007191 return rc;
7192 }
7193 break;
7194
Michal Vaskobf19d252015-10-08 15:39:17 +02007195 case UNRES_MUST:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007196 if ((rc = resolve_must(node, 0, ignore_fail))) {
Michal Vaskoc8c810c2016-09-15 14:02:00 +02007197 return rc;
7198 }
7199 break;
7200
7201 case UNRES_MUST_INOUT:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007202 if ((rc = resolve_must(node, 1, ignore_fail))) {
Michal Vaskobf19d252015-10-08 15:39:17 +02007203 return rc;
7204 }
7205 break;
7206
Michal Vaskocf024702015-10-08 15:01:42 +02007207 default:
Michal Vasko8bcdf292015-08-19 14:04:43 +02007208 LOGINT;
7209 return -1;
7210 }
7211
7212 return EXIT_SUCCESS;
7213}
7214
7215/**
Radek Krejci0b7704f2016-03-18 12:16:14 +01007216 * @brief add data unres item
Michal Vasko8bcdf292015-08-19 14:04:43 +02007217 *
7218 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02007219 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007220 *
Radek Krejci0b7704f2016-03-18 12:16:14 +01007221 * @return 0 on success, -1 on error.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007222 */
7223int
Radek Krejci0b7704f2016-03-18 12:16:14 +01007224unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02007225{
Radek Krejci03b71f72016-03-16 11:10:09 +01007226 assert(unres && node);
Michal Vaskoc4280842016-04-19 16:10:42 +02007227 assert((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)
Radek Krejcibacc7442016-10-27 13:39:56 +02007228 || (type == UNRES_MUST_INOUT) || (type == UNRES_UNION));
Michal Vasko8bcdf292015-08-19 14:04:43 +02007229
Radek Krejci03b71f72016-03-16 11:10:09 +01007230 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01007231 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
7232 if (!unres->node) {
7233 LOGMEM;
7234 return -1;
7235 }
Michal Vaskocf024702015-10-08 15:01:42 +02007236 unres->node[unres->count - 1] = node;
Michal Vasko253035f2015-12-17 16:58:13 +01007237 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
7238 if (!unres->type) {
7239 LOGMEM;
7240 return -1;
7241 }
Michal Vaskocf024702015-10-08 15:01:42 +02007242 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007243
Radek Krejci0b7704f2016-03-18 12:16:14 +01007244 if (type == UNRES_WHEN) {
7245 /* remove previous result */
7246 node->when_status = LYD_WHEN;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007247 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007248
7249 return EXIT_SUCCESS;
7250}
7251
7252/**
7253 * @brief Resolve every unres data item in the structure. Logs directly.
7254 *
Radek Krejci082c84f2016-10-17 16:33:06 +02007255 * If options includes LYD_OPT_TRUSTED, the data are considered trusted (when, must conditions are not expected,
7256 * unresolved leafrefs/instids are accepted).
7257 *
7258 * If options includes LYD_OPT_NOAUTODEL, the false resulting when condition on non-default nodes, the error is raised.
7259 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007260 * @param[in] unres Unres data structure to use.
Radek Krejci082c84f2016-10-17 16:33:06 +02007261 * @param[in,out] root Root node of the data tree, can be changed due to autodeletion.
7262 * @param[in] options Data options as described above.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007263 *
7264 * @return EXIT_SUCCESS on success, -1 on error.
7265 */
7266int
Radek Krejci082c84f2016-10-17 16:33:06 +02007267resolve_unres_data(struct unres_data *unres, struct lyd_node **root, int options)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007268{
Radek Krejci0c0086a2016-03-24 15:20:28 +01007269 uint32_t i, j, first = 1, resolved = 0, del_items = 0, when_stmt = 0;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007270 int rc, progress, ignore_fail;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007271 struct lyd_node *parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007272
Radek Krejci082c84f2016-10-17 16:33:06 +02007273 assert(root);
Radek Krejci03b71f72016-03-16 11:10:09 +01007274 assert(unres);
Radek Krejci03b71f72016-03-16 11:10:09 +01007275
7276 if (!unres->count) {
7277 return EXIT_SUCCESS;
7278 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007279
Michal Vaskoad2e44a2017-01-03 10:31:35 +01007280 if (options & (LYD_OPT_TRUSTED | LYD_OPT_NOTIF_FILTER | LYD_OPT_GET | LYD_OPT_GETCONFIG | LYD_OPT_EDIT)) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007281 ignore_fail = 1;
7282 } else if (options & LYD_OPT_NOEXTDEPS) {
7283 ignore_fail = 2;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007284 } else {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007285 ignore_fail = 0;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007286 }
7287
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02007288 LOGVRB("Resolving unresolved data nodes and their constraints...");
Radek Krejci010e54b2016-03-15 09:40:34 +01007289 ly_vlog_hide(1);
7290
Radek Krejci0b7704f2016-03-18 12:16:14 +01007291 /* when-stmt first */
Radek Krejci010e54b2016-03-15 09:40:34 +01007292 do {
Radek Krejci00a0e712016-10-26 10:24:46 +02007293 ly_err_clean(1);
Radek Krejci010e54b2016-03-15 09:40:34 +01007294 progress = 0;
Michal Vasko6df94132016-09-22 11:08:09 +02007295 for (i = 0; i < unres->count; i++) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007296 if (unres->type[i] != UNRES_WHEN) {
7297 continue;
7298 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007299 if (first) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007300 /* count when-stmt nodes in unres list */
7301 when_stmt++;
7302 }
7303
7304 /* resolve when condition only when all parent when conditions are already resolved */
7305 for (parent = unres->node[i]->parent;
7306 parent && LYD_WHEN_DONE(parent->when_status);
7307 parent = parent->parent) {
7308 if (!parent->parent && (parent->when_status & LYD_WHEN_FALSE)) {
7309 /* the parent node was already unlinked, do not resolve this node,
7310 * it will be removed anyway, so just mark it as resolved
7311 */
7312 unres->node[i]->when_status |= LYD_WHEN_FALSE;
7313 unres->type[i] = UNRES_RESOLVED;
7314 resolved++;
7315 break;
7316 }
7317 }
7318 if (parent) {
7319 continue;
7320 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007321
Michal Vasko3cfa3182017-01-17 10:00:58 +01007322 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail);
Radek Krejci010e54b2016-03-15 09:40:34 +01007323 if (!rc) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007324 if (unres->node[i]->when_status & LYD_WHEN_FALSE) {
Radek Krejci082c84f2016-10-17 16:33:06 +02007325 if ((options & LYD_OPT_NOAUTODEL) && !unres->node[i]->dflt) {
Radek Krejci03b71f72016-03-16 11:10:09 +01007326 /* false when condition */
7327 ly_vlog_hide(0);
Radek Krejci2467a492016-10-24 15:16:59 +02007328 ly_err_repeat();
Radek Krejci03b71f72016-03-16 11:10:09 +01007329 return -1;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007330 } /* follows else */
7331
Radek Krejci0c0086a2016-03-24 15:20:28 +01007332 /* only unlink now, the subtree can contain another nodes stored in the unres list */
7333 /* if it has parent non-presence containers that would be empty, we should actually
7334 * remove the container
7335 */
Radek Krejci2537fd32016-09-07 16:22:41 +02007336 for (parent = unres->node[i];
7337 parent->parent && parent->parent->schema->nodetype == LYS_CONTAINER;
7338 parent = parent->parent) {
7339 if (((struct lys_node_container *)parent->parent->schema)->presence) {
7340 /* presence container */
7341 break;
Radek Krejci0c0086a2016-03-24 15:20:28 +01007342 }
Radek Krejci2537fd32016-09-07 16:22:41 +02007343 if (parent->next || parent->prev != parent) {
7344 /* non empty (the child we are in and we are going to remove is not the only child) */
7345 break;
7346 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007347 }
Radek Krejci2537fd32016-09-07 16:22:41 +02007348 unres->node[i] = parent;
Radek Krejci0c0086a2016-03-24 15:20:28 +01007349
Radek Krejci0b7704f2016-03-18 12:16:14 +01007350 /* auto-delete */
7351 LOGVRB("auto-delete node \"%s\" due to when condition (%s)", ly_errpath(),
7352 ((struct lys_node_leaf *)unres->node[i]->schema)->when->cond);
Radek Krejci0c0086a2016-03-24 15:20:28 +01007353 if (*root && *root == unres->node[i]) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007354 *root = (*root)->next;
Radek Krejci03b71f72016-03-16 11:10:09 +01007355 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007356
Radek Krejci0b7704f2016-03-18 12:16:14 +01007357 lyd_unlink(unres->node[i]);
7358 unres->type[i] = UNRES_DELETE;
7359 del_items++;
Radek Krejci51fd8162016-03-24 15:49:51 +01007360
7361 /* update the rest of unres items */
7362 for (j = 0; j < unres->count; j++) {
Radek Krejci3db819b2016-03-24 16:29:48 +01007363 if (unres->type[j] == UNRES_RESOLVED || unres->type[j] == UNRES_DELETE) {
Radek Krejci51fd8162016-03-24 15:49:51 +01007364 continue;
7365 }
7366
7367 /* test if the node is in subtree to be deleted */
7368 for (parent = unres->node[j]; parent; parent = parent->parent) {
7369 if (parent == unres->node[i]) {
7370 /* yes, it is */
7371 unres->type[j] = UNRES_RESOLVED;
7372 resolved++;
7373 break;
7374 }
7375 }
7376 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007377 } else {
7378 unres->type[i] = UNRES_RESOLVED;
Radek Krejci03b71f72016-03-16 11:10:09 +01007379 }
Radek Krejci00a0e712016-10-26 10:24:46 +02007380 ly_err_clean(1);
Radek Krejci010e54b2016-03-15 09:40:34 +01007381 resolved++;
7382 progress = 1;
7383 } else if (rc == -1) {
7384 ly_vlog_hide(0);
Michal Vasko76e73402016-08-24 16:00:13 +02007385 /* print only this last error */
Michal Vasko3cfa3182017-01-17 10:00:58 +01007386 resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail);
Radek Krejci010e54b2016-03-15 09:40:34 +01007387 return -1;
Radek Krejci2467a492016-10-24 15:16:59 +02007388 } /* else forward reference */
Radek Krejci010e54b2016-03-15 09:40:34 +01007389 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007390 first = 0;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007391 } while (progress && resolved < when_stmt);
Radek Krejci010e54b2016-03-15 09:40:34 +01007392
Radek Krejci0b7704f2016-03-18 12:16:14 +01007393 /* do we have some unresolved when-stmt? */
Radek Krejcid940d732016-03-24 16:02:28 +01007394 if (when_stmt > resolved) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007395 ly_vlog_hide(0);
Radek Krejci2467a492016-10-24 15:16:59 +02007396 ly_err_repeat();
Radek Krejci0b7704f2016-03-18 12:16:14 +01007397 return -1;
7398 }
7399
7400 for (i = 0; del_items && i < unres->count; i++) {
7401 /* we had some when-stmt resulted to false, so now we have to sanitize the unres list */
7402 if (unres->type[i] != UNRES_DELETE) {
7403 continue;
7404 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007405 if (!unres->node[i]) {
7406 unres->type[i] = UNRES_RESOLVED;
7407 del_items--;
7408 continue;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007409 }
7410
7411 /* really remove the complete subtree */
7412 lyd_free(unres->node[i]);
7413 unres->type[i] = UNRES_RESOLVED;
7414 del_items--;
7415 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007416 ly_vlog_hide(0);
Radek Krejci010e54b2016-03-15 09:40:34 +01007417
7418 /* rest */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007419 for (i = 0; i < unres->count; ++i) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007420 if (unres->type[i] == UNRES_RESOLVED) {
7421 continue;
7422 }
Radek Krejci082c84f2016-10-17 16:33:06 +02007423 assert(!(options & LYD_OPT_TRUSTED) || ((unres->type[i] != UNRES_MUST) && (unres->type[i] != UNRES_MUST_INOUT)));
Radek Krejci010e54b2016-03-15 09:40:34 +01007424
Michal Vasko3cfa3182017-01-17 10:00:58 +01007425 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007426 if (rc) {
7427 /* since when was already resolved, a forward reference is an error */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007428 return -1;
7429 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007430
7431 unres->type[i] = UNRES_RESOLVED;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007432 }
7433
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02007434 LOGVRB("All data nodes and constraints resolved.");
Radek Krejci010e54b2016-03-15 09:40:34 +01007435 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007436 return EXIT_SUCCESS;
7437}