blob: 96992febf3a72bfdae98e1da9d81af057302bc56 [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"
Radek Krejcie534c132016-11-23 13:32:31 +010032#include "extensions.h"
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020033
Michal Vaskod24dd012016-09-30 12:20:22 +020034int
35parse_range_dec64(const char **str_num, uint8_t dig, int64_t *num)
Michal Vasko4d1f0482016-09-19 14:35:06 +020036{
37 const char *ptr;
38 int minus = 0;
Michal Vaskoe2ea45a2017-08-07 13:15:07 +020039 int64_t ret = 0, prev_ret;
Radek Krejcibf47a822016-11-04 10:06:08 +010040 int8_t str_exp, str_dig = -1, trailing_zeros = 0;
Michal Vasko4d1f0482016-09-19 14:35:06 +020041
42 ptr = *str_num;
43
44 if (ptr[0] == '-') {
45 minus = 1;
46 ++ptr;
Radek Krejci51673202016-11-01 17:00:32 +010047 } else if (ptr[0] == '+') {
48 ++ptr;
Michal Vasko4d1f0482016-09-19 14:35:06 +020049 }
50
Michal Vaskod24dd012016-09-30 12:20:22 +020051 if (!isdigit(ptr[0])) {
52 /* there must be at least one */
53 return 1;
54 }
55
Michal Vasko4d1f0482016-09-19 14:35:06 +020056 for (str_exp = 0; isdigit(ptr[0]) || ((ptr[0] == '.') && (str_dig < 0)); ++ptr) {
57 if (str_exp > 18) {
Michal Vaskod24dd012016-09-30 12:20:22 +020058 return 1;
Michal Vasko4d1f0482016-09-19 14:35:06 +020059 }
60
61 if (ptr[0] == '.') {
62 if (ptr[1] == '.') {
63 /* it's the next interval */
64 break;
65 }
66 ++str_dig;
67 } else {
Michal Vaskoe2ea45a2017-08-07 13:15:07 +020068 prev_ret = ret;
69 if (minus) {
70 ret = ret * 10 - (ptr[0] - '0');
71 if (ret > prev_ret) {
72 return 1;
73 }
74 } else {
75 ret = ret * 10 + (ptr[0] - '0');
76 if (ret < prev_ret) {
77 return 1;
78 }
79 }
Michal Vasko4d1f0482016-09-19 14:35:06 +020080 if (str_dig > -1) {
81 ++str_dig;
Radek Krejcibf47a822016-11-04 10:06:08 +010082 if (ptr[0] == '0') {
83 /* possibly trailing zero */
84 trailing_zeros++;
85 } else {
86 trailing_zeros = 0;
87 }
Michal Vasko4d1f0482016-09-19 14:35:06 +020088 }
89 ++str_exp;
90 }
91 }
Michal Vaskod24dd012016-09-30 12:20:22 +020092 if (str_dig == 0) {
93 /* no digits after '.' */
94 return 1;
95 } else if (str_dig == -1) {
96 /* there are 0 numbers after the floating point */
Michal Vasko4d1f0482016-09-19 14:35:06 +020097 str_dig = 0;
98 }
Radek Krejcibf47a822016-11-04 10:06:08 +010099 /* remove trailing zeros */
100 if (trailing_zeros) {
Michal Vasko6ca5ca72016-11-28 09:21:51 +0100101 str_dig -= trailing_zeros;
102 str_exp -= trailing_zeros;
Radek Krejcibf47a822016-11-04 10:06:08 +0100103 ret = ret / dec_pow(trailing_zeros);
104 }
Michal Vasko4d1f0482016-09-19 14:35:06 +0200105
106 /* it's parsed, now adjust the number based on fraction-digits, if needed */
107 if (str_dig < dig) {
108 if ((str_exp - 1) + (dig - str_dig) > 18) {
Michal Vaskod24dd012016-09-30 12:20:22 +0200109 return 1;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200110 }
Michal Vaskoe2ea45a2017-08-07 13:15:07 +0200111 prev_ret = ret;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200112 ret *= dec_pow(dig - str_dig);
Michal Vaskoe2ea45a2017-08-07 13:15:07 +0200113 if ((minus && (ret > prev_ret)) || (!minus && (ret < prev_ret))) {
114 return 1;
115 }
116
Michal Vasko4d1f0482016-09-19 14:35:06 +0200117 }
118 if (str_dig > dig) {
Michal Vaskod24dd012016-09-30 12:20:22 +0200119 return 1;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200120 }
121
Michal Vasko4d1f0482016-09-19 14:35:06 +0200122 *str_num = ptr;
Michal Vaskod24dd012016-09-30 12:20:22 +0200123 *num = ret;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200124
Michal Vaskod24dd012016-09-30 12:20:22 +0200125 return 0;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200126}
127
128/**
Radek Krejci6dc53a22015-08-17 13:27:59 +0200129 * @brief Parse an identifier.
130 *
131 * ;; An identifier MUST NOT start with (('X'|'x') ('M'|'m') ('L'|'l'))
132 * identifier = (ALPHA / "_")
133 * *(ALPHA / DIGIT / "_" / "-" / ".")
134 *
Michal Vaskobb211122015-08-19 14:03:11 +0200135 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200136 *
137 * @return Number of characters successfully parsed.
138 */
Michal Vasko249e6b52015-08-19 11:08:52 +0200139int
Radek Krejci6dc53a22015-08-17 13:27:59 +0200140parse_identifier(const char *id)
141{
142 int parsed = 0;
143
Michal Vasko1ab90bc2016-03-15 10:40:22 +0100144 assert(id);
145
Radek Krejci6dc53a22015-08-17 13:27:59 +0200146 if (!isalpha(id[0]) && (id[0] != '_')) {
147 return -parsed;
148 }
149
150 ++parsed;
151 ++id;
152
153 while (isalnum(id[0]) || (id[0] == '_') || (id[0] == '-') || (id[0] == '.')) {
154 ++parsed;
155 ++id;
156 }
157
158 return parsed;
159}
160
161/**
162 * @brief Parse a node-identifier.
163 *
Michal Vasko723e50c2015-10-20 15:20:29 +0200164 * node-identifier = [module-name ":"] identifier
Radek Krejci6dc53a22015-08-17 13:27:59 +0200165 *
Michal Vaskobb211122015-08-19 14:03:11 +0200166 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200167 * @param[out] mod_name Points to the module name, NULL if there is not any.
168 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200169 * @param[out] name Points to the node name.
170 * @param[out] nam_len Length of the node name.
171 *
172 * @return Number of characters successfully parsed,
173 * positive on success, negative on failure.
174 */
175static int
Michal Vasko723e50c2015-10-20 15:20:29 +0200176parse_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 +0200177{
178 int parsed = 0, ret;
179
180 assert(id);
Michal Vasko723e50c2015-10-20 15:20:29 +0200181 if (mod_name) {
182 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200183 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200184 if (mod_name_len) {
185 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200186 }
187 if (name) {
188 *name = NULL;
189 }
190 if (nam_len) {
191 *nam_len = 0;
192 }
193
194 if ((ret = parse_identifier(id)) < 1) {
195 return ret;
196 }
197
Michal Vasko723e50c2015-10-20 15:20:29 +0200198 if (mod_name) {
199 *mod_name = id;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200200 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200201 if (mod_name_len) {
202 *mod_name_len = ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200203 }
204
205 parsed += ret;
206 id += ret;
207
208 /* there is prefix */
209 if (id[0] == ':') {
210 ++parsed;
211 ++id;
212
213 /* there isn't */
214 } else {
Michal Vasko723e50c2015-10-20 15:20:29 +0200215 if (name && mod_name) {
216 *name = *mod_name;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200217 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200218 if (mod_name) {
219 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200220 }
221
Michal Vasko723e50c2015-10-20 15:20:29 +0200222 if (nam_len && mod_name_len) {
223 *nam_len = *mod_name_len;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200224 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200225 if (mod_name_len) {
226 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200227 }
228
229 return parsed;
230 }
231
232 /* identifier (node name) */
233 if ((ret = parse_identifier(id)) < 1) {
234 return -parsed+ret;
235 }
236
237 if (name) {
238 *name = id;
239 }
240 if (nam_len) {
241 *nam_len = ret;
242 }
243
244 return parsed+ret;
245}
246
247/**
248 * @brief Parse a path-predicate (leafref).
249 *
250 * path-predicate = "[" *WSP path-equality-expr *WSP "]"
251 * path-equality-expr = node-identifier *WSP "=" *WSP path-key-expr
252 *
Michal Vaskobb211122015-08-19 14:03:11 +0200253 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200254 * @param[out] prefix Points to the prefix, NULL if there is not any.
255 * @param[out] pref_len Length of the prefix, 0 if there is not any.
256 * @param[out] name Points to the node name.
257 * @param[out] nam_len Length of the node name.
258 * @param[out] path_key_expr Points to the path-key-expr.
259 * @param[out] pke_len Length of the path-key-expr.
260 * @param[out] has_predicate Flag to mark whether there is another predicate following.
261 *
262 * @return Number of characters successfully parsed,
263 * positive on success, negative on failure.
264 */
265static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200266parse_path_predicate(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
267 const char **path_key_expr, int *pke_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200268{
269 const char *ptr;
270 int parsed = 0, ret;
271
272 assert(id);
273 if (prefix) {
274 *prefix = NULL;
275 }
276 if (pref_len) {
277 *pref_len = 0;
278 }
279 if (name) {
280 *name = NULL;
281 }
282 if (nam_len) {
283 *nam_len = 0;
284 }
285 if (path_key_expr) {
286 *path_key_expr = NULL;
287 }
288 if (pke_len) {
289 *pke_len = 0;
290 }
291 if (has_predicate) {
292 *has_predicate = 0;
293 }
294
295 if (id[0] != '[') {
296 return -parsed;
297 }
298
299 ++parsed;
300 ++id;
301
302 while (isspace(id[0])) {
303 ++parsed;
304 ++id;
305 }
306
307 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
308 return -parsed+ret;
309 }
310
311 parsed += ret;
312 id += ret;
313
314 while (isspace(id[0])) {
315 ++parsed;
316 ++id;
317 }
318
319 if (id[0] != '=') {
320 return -parsed;
321 }
322
323 ++parsed;
324 ++id;
325
326 while (isspace(id[0])) {
327 ++parsed;
328 ++id;
329 }
330
331 if ((ptr = strchr(id, ']')) == NULL) {
332 return -parsed;
333 }
334
335 --ptr;
336 while (isspace(ptr[0])) {
337 --ptr;
338 }
339 ++ptr;
340
341 ret = ptr-id;
342 if (path_key_expr) {
343 *path_key_expr = id;
344 }
345 if (pke_len) {
346 *pke_len = ret;
347 }
348
349 parsed += ret;
350 id += ret;
351
352 while (isspace(id[0])) {
353 ++parsed;
354 ++id;
355 }
356
357 assert(id[0] == ']');
358
359 if (id[1] == '[') {
360 *has_predicate = 1;
361 }
362
363 return parsed+1;
364}
365
366/**
367 * @brief Parse a path-key-expr (leafref). First call parses "current()", all
368 * the ".." and the first node-identifier, other calls parse a single
369 * node-identifier each.
370 *
371 * path-key-expr = current-function-invocation *WSP "/" *WSP
372 * rel-path-keyexpr
373 * rel-path-keyexpr = 1*(".." *WSP "/" *WSP)
374 * *(node-identifier *WSP "/" *WSP)
375 * node-identifier
376 *
Michal Vaskobb211122015-08-19 14:03:11 +0200377 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200378 * @param[out] prefix Points to the prefix, NULL if there is not any.
379 * @param[out] pref_len Length of the prefix, 0 if there is not any.
380 * @param[out] name Points to the node name.
381 * @param[out] nam_len Length of the node name.
382 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
383 * must not be changed between consecutive calls.
384 * @return Number of characters successfully parsed,
385 * positive on success, negative on failure.
386 */
387static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200388parse_path_key_expr(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
389 int *parent_times)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200390{
391 int parsed = 0, ret, par_times = 0;
392
393 assert(id);
394 assert(parent_times);
395 if (prefix) {
396 *prefix = NULL;
397 }
398 if (pref_len) {
399 *pref_len = 0;
400 }
401 if (name) {
402 *name = NULL;
403 }
404 if (nam_len) {
405 *nam_len = 0;
406 }
407
408 if (!*parent_times) {
409 /* current-function-invocation *WSP "/" *WSP rel-path-keyexpr */
410 if (strncmp(id, "current()", 9)) {
411 return -parsed;
412 }
413
414 parsed += 9;
415 id += 9;
416
417 while (isspace(id[0])) {
418 ++parsed;
419 ++id;
420 }
421
422 if (id[0] != '/') {
423 return -parsed;
424 }
425
426 ++parsed;
427 ++id;
428
429 while (isspace(id[0])) {
430 ++parsed;
431 ++id;
432 }
433
434 /* rel-path-keyexpr */
435 if (strncmp(id, "..", 2)) {
436 return -parsed;
437 }
438 ++par_times;
439
440 parsed += 2;
441 id += 2;
442
443 while (isspace(id[0])) {
444 ++parsed;
445 ++id;
446 }
447 }
448
449 /* 1*(".." *WSP "/" *WSP) *(node-identifier *WSP "/" *WSP) node-identifier
450 *
451 * first parent reference with whitespaces already parsed
452 */
453 if (id[0] != '/') {
454 return -parsed;
455 }
456
457 ++parsed;
458 ++id;
459
460 while (isspace(id[0])) {
461 ++parsed;
462 ++id;
463 }
464
465 while (!strncmp(id, "..", 2) && !*parent_times) {
466 ++par_times;
467
468 parsed += 2;
469 id += 2;
470
471 while (isspace(id[0])) {
472 ++parsed;
473 ++id;
474 }
475
476 if (id[0] != '/') {
477 return -parsed;
478 }
479
480 ++parsed;
481 ++id;
482
483 while (isspace(id[0])) {
484 ++parsed;
485 ++id;
486 }
487 }
488
489 if (!*parent_times) {
490 *parent_times = par_times;
491 }
492
493 /* all parent references must be parsed at this point */
494 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
495 return -parsed+ret;
496 }
497
498 parsed += ret;
499 id += ret;
500
501 return parsed;
502}
503
504/**
505 * @brief Parse path-arg (leafref).
506 *
507 * path-arg = absolute-path / relative-path
508 * absolute-path = 1*("/" (node-identifier *path-predicate))
509 * relative-path = 1*(".." "/") descendant-path
510 *
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200511 * @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 +0200512 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200513 * @param[out] prefix Points to the prefix, NULL if there is not any.
514 * @param[out] pref_len Length of the prefix, 0 if there is not any.
515 * @param[out] name Points to the node name.
516 * @param[out] nam_len Length of the node name.
517 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
518 * must not be changed between consecutive calls. -1 if the
519 * path is relative.
520 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
521 *
522 * @return Number of characters successfully parsed,
523 * positive on success, negative on failure.
524 */
525static int
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200526parse_path_arg(struct lys_module *mod, const char *id, const char **prefix, int *pref_len,
527 const char **name, int *nam_len, int *parent_times, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200528{
529 int parsed = 0, ret, par_times = 0;
530
531 assert(id);
532 assert(parent_times);
533 if (prefix) {
534 *prefix = NULL;
535 }
536 if (pref_len) {
537 *pref_len = 0;
538 }
539 if (name) {
540 *name = NULL;
541 }
542 if (nam_len) {
543 *nam_len = 0;
544 }
545 if (has_predicate) {
546 *has_predicate = 0;
547 }
548
549 if (!*parent_times && !strncmp(id, "..", 2)) {
550 ++par_times;
551
552 parsed += 2;
553 id += 2;
554
555 while (!strncmp(id, "/..", 3)) {
556 ++par_times;
557
558 parsed += 3;
559 id += 3;
560 }
561 }
562
563 if (!*parent_times) {
564 if (par_times) {
565 *parent_times = par_times;
566 } else {
567 *parent_times = -1;
568 }
569 }
570
571 if (id[0] != '/') {
572 return -parsed;
573 }
574
575 /* skip '/' */
576 ++parsed;
577 ++id;
578
579 /* node-identifier ([prefix:]identifier) */
580 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
581 return -parsed-ret;
582 }
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200583 if (!(*prefix)) {
584 /* actually we always need prefix even it is not specified */
585 *prefix = lys_main_module(mod)->name;
586 *pref_len = strlen(*prefix);
587 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200588
589 parsed += ret;
590 id += ret;
591
592 /* there is no predicate */
593 if ((id[0] == '/') || !id[0]) {
594 return parsed;
595 } else if (id[0] != '[') {
596 return -parsed;
597 }
598
599 if (has_predicate) {
600 *has_predicate = 1;
601 }
602
603 return parsed;
604}
605
606/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200607 * @brief Parse instance-identifier in JSON data format. That means that prefixes
Michal Vaskob2f40be2016-09-08 16:03:48 +0200608 * (which are mandatory for every node-identifier) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200609 *
610 * instance-identifier = 1*("/" (node-identifier *predicate))
611 *
Michal Vaskobb211122015-08-19 14:03:11 +0200612 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200613 * @param[out] model Points to the model name.
614 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200615 * @param[out] name Points to the node name.
616 * @param[out] nam_len Length of the node name.
617 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
618 *
619 * @return Number of characters successfully parsed,
620 * positive on success, negative on failure.
621 */
622static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200623parse_instance_identifier(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
624 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200625{
626 int parsed = 0, ret;
627
Radek Krejci6dc53a22015-08-17 13:27:59 +0200628 if (has_predicate) {
629 *has_predicate = 0;
630 }
631
632 if (id[0] != '/') {
633 return -parsed;
634 }
635
636 ++parsed;
637 ++id;
638
Michal Vaskob2f40be2016-09-08 16:03:48 +0200639 if ((ret = parse_identifier(id)) < 1) {
640 return ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200641 }
642
Michal Vaskob2f40be2016-09-08 16:03:48 +0200643 *model = id;
644 *mod_len = ret;
645
Radek Krejci6dc53a22015-08-17 13:27:59 +0200646 parsed += ret;
647 id += ret;
648
Michal Vaskob2f40be2016-09-08 16:03:48 +0200649 if (id[0] != ':') {
650 return -parsed;
651 }
652
653 ++parsed;
654 ++id;
655
656 if ((ret = parse_identifier(id)) < 1) {
657 return ret;
658 }
659
660 *name = id;
661 *nam_len = ret;
662
663 parsed += ret;
664 id += ret;
665
Radek Krejci4967cb62016-09-14 16:40:28 +0200666 if (id[0] == '[' && has_predicate) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200667 *has_predicate = 1;
668 }
669
670 return parsed;
671}
672
673/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200674 * @brief Parse predicate (instance-identifier) in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200675 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200676 *
677 * predicate = "[" *WSP (predicate-expr / pos) *WSP "]"
678 * predicate-expr = (node-identifier / ".") *WSP "=" *WSP
679 * ((DQUOTE string DQUOTE) /
680 * (SQUOTE string SQUOTE))
681 * pos = non-negative-integer-value
682 *
Michal Vaskobb211122015-08-19 14:03:11 +0200683 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200684 * @param[out] model Points to the model name.
685 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200686 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
687 * @param[out] nam_len Length of the node name.
688 * @param[out] value Value the node-identifier must have (string from the grammar),
689 * NULL if there is not any.
690 * @param[out] val_len Length of the value, 0 if there is not any.
691 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
692 *
693 * @return Number of characters successfully parsed,
694 * positive on success, negative on failure.
695 */
696static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200697parse_predicate(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
698 const char **value, int *val_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200699{
700 const char *ptr;
701 int parsed = 0, ret;
702 char quote;
703
704 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200705 if (model) {
706 *model = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200707 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200708 if (mod_len) {
709 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200710 }
711 if (name) {
712 *name = NULL;
713 }
714 if (nam_len) {
715 *nam_len = 0;
716 }
717 if (value) {
718 *value = NULL;
719 }
720 if (val_len) {
721 *val_len = 0;
722 }
723 if (has_predicate) {
724 *has_predicate = 0;
725 }
726
727 if (id[0] != '[') {
728 return -parsed;
729 }
730
731 ++parsed;
732 ++id;
733
734 while (isspace(id[0])) {
735 ++parsed;
736 ++id;
737 }
738
739 /* pos */
740 if (isdigit(id[0])) {
741 if (name) {
742 *name = id;
743 }
744
745 if (id[0] == '0') {
Michal Vaskof2f28a12016-09-09 12:43:06 +0200746 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200747 }
748
749 while (isdigit(id[0])) {
750 ++parsed;
751 ++id;
752 }
753
754 if (nam_len) {
755 *nam_len = id-(*name);
756 }
757
Michal Vaskof2f28a12016-09-09 12:43:06 +0200758 /* "." or node-identifier */
Radek Krejci6dc53a22015-08-17 13:27:59 +0200759 } else {
Michal Vaskof2f28a12016-09-09 12:43:06 +0200760 if (id[0] == '.') {
761 if (name) {
762 *name = id;
763 }
764 if (nam_len) {
765 *nam_len = 1;
766 }
767
768 ++parsed;
769 ++id;
770
771 } else {
772 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
773 return -parsed+ret;
774 } else if (model && !*model) {
775 return -parsed;
776 }
777
778 parsed += ret;
779 id += ret;
780 }
781
782 while (isspace(id[0])) {
783 ++parsed;
784 ++id;
785 }
786
787 if (id[0] != '=') {
Michal Vasko1f2cc332015-08-19 11:18:32 +0200788 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200789 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200790
Radek Krejci6dc53a22015-08-17 13:27:59 +0200791 ++parsed;
792 ++id;
793
Michal Vaskof2f28a12016-09-09 12:43:06 +0200794 while (isspace(id[0])) {
795 ++parsed;
796 ++id;
797 }
798
799 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
800 if ((id[0] == '\"') || (id[0] == '\'')) {
801 quote = id[0];
802
803 ++parsed;
804 ++id;
805
806 if ((ptr = strchr(id, quote)) == NULL) {
807 return -parsed;
808 }
809 ret = ptr-id;
810
811 if (value) {
812 *value = id;
813 }
814 if (val_len) {
815 *val_len = ret;
816 }
817
818 parsed += ret+1;
819 id += ret+1;
820 } else {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200821 return -parsed;
822 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200823 }
824
825 while (isspace(id[0])) {
826 ++parsed;
827 ++id;
828 }
829
830 if (id[0] != ']') {
831 return -parsed;
832 }
833
834 ++parsed;
835 ++id;
836
837 if ((id[0] == '[') && has_predicate) {
838 *has_predicate = 1;
839 }
840
841 return parsed;
842}
843
844/**
845 * @brief Parse schema-nodeid.
846 *
847 * schema-nodeid = absolute-schema-nodeid /
848 * descendant-schema-nodeid
849 * absolute-schema-nodeid = 1*("/" node-identifier)
Michal Vasko48935352016-03-29 11:52:36 +0200850 * descendant-schema-nodeid = ["." "/"]
Radek Krejci6dc53a22015-08-17 13:27:59 +0200851 * node-identifier
852 * absolute-schema-nodeid
853 *
Michal Vaskobb211122015-08-19 14:03:11 +0200854 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200855 * @param[out] mod_name Points to the module name, NULL if there is not any.
856 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Michal Vasko48935352016-03-29 11:52:36 +0200857 * @param[out] name Points to the node name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200858 * @param[out] nam_len Length of the node name.
859 * @param[out] is_relative Flag to mark whether the nodeid is absolute or descendant. Must be -1
860 * on the first call, must not be changed between consecutive calls.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100861 * @param[out] has_predicate Flag to mark whether there is a predicate specified. It cannot be
862 * based on the grammar, in those cases use NULL.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200863 *
864 * @return Number of characters successfully parsed,
865 * positive on success, negative on failure.
866 */
Michal Vasko22448d32016-03-16 13:17:29 +0100867int
Michal Vasko723e50c2015-10-20 15:20:29 +0200868parse_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 +0100869 int *is_relative, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200870{
871 int parsed = 0, ret;
872
873 assert(id);
874 assert(is_relative);
Michal Vasko723e50c2015-10-20 15:20:29 +0200875 if (mod_name) {
876 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200877 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200878 if (mod_name_len) {
879 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200880 }
881 if (name) {
882 *name = NULL;
883 }
884 if (nam_len) {
885 *nam_len = 0;
886 }
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100887 if (has_predicate) {
888 *has_predicate = 0;
889 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200890
891 if (id[0] != '/') {
892 if (*is_relative != -1) {
893 return -parsed;
894 } else {
895 *is_relative = 1;
896 }
Michal Vasko48935352016-03-29 11:52:36 +0200897 if (!strncmp(id, "./", 2)) {
898 parsed += 2;
899 id += 2;
900 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200901 } else {
902 if (*is_relative == -1) {
903 *is_relative = 0;
904 }
905 ++parsed;
906 ++id;
907 }
908
Michal Vasko723e50c2015-10-20 15:20:29 +0200909 if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200910 return -parsed+ret;
911 }
912
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100913 parsed += ret;
914 id += ret;
915
916 if ((id[0] == '[') && has_predicate) {
917 *has_predicate = 1;
918 }
919
920 return parsed;
921}
922
923/**
924 * @brief Parse schema predicate (special format internally used).
925 *
926 * predicate = "[" *WSP predicate-expr *WSP "]"
Michal Vasko9fbb6e82017-07-04 13:50:04 +0200927 * predicate-expr = "." / [prefix:]identifier / positive-integer / key-with-value
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100928 * key-with-value = identifier *WSP "=" *WSP
929 * ((DQUOTE string DQUOTE) /
930 * (SQUOTE string SQUOTE))
931 *
932 * @param[in] id Identifier to use.
Michal Vasko9fbb6e82017-07-04 13:50:04 +0200933 * @param[out] mod_name Points to the list key module name.
934 * @param[out] mod_name_len Length of \p mod_name.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100935 * @param[out] name Points to the list key name.
936 * @param[out] nam_len Length of \p name.
Michal Vasko22448d32016-03-16 13:17:29 +0100937 * @param[out] value Points to the key value. If specified, key-with-value is expected.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100938 * @param[out] val_len Length of \p value.
939 * @param[out] has_predicate Flag to mark whether there is another predicate specified.
940 */
Michal Vasko22448d32016-03-16 13:17:29 +0100941int
Michal Vasko9fbb6e82017-07-04 13:50:04 +0200942parse_schema_json_predicate(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len,
943 const char **value, int *val_len, int *has_predicate)
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100944{
945 const char *ptr;
946 int parsed = 0, ret;
947 char quote;
948
949 assert(id);
Michal Vasko9fbb6e82017-07-04 13:50:04 +0200950 if (mod_name) {
951 *mod_name = NULL;
952 }
953 if (mod_name_len) {
954 *mod_name_len = 0;
955 }
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100956 if (name) {
957 *name = NULL;
958 }
959 if (nam_len) {
960 *nam_len = 0;
961 }
962 if (value) {
963 *value = NULL;
964 }
965 if (val_len) {
966 *val_len = 0;
967 }
968 if (has_predicate) {
969 *has_predicate = 0;
970 }
971
972 if (id[0] != '[') {
973 return -parsed;
974 }
975
976 ++parsed;
977 ++id;
978
979 while (isspace(id[0])) {
980 ++parsed;
981 ++id;
982 }
983
Michal Vasko22448d32016-03-16 13:17:29 +0100984 /* identifier */
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200985 if (id[0] == '.') {
986 ret = 1;
Michal Vasko9fbb6e82017-07-04 13:50:04 +0200987
988 if (name) {
989 *name = id;
990 }
991 if (nam_len) {
992 *nam_len = ret;
993 }
Michal Vasko58c2aab2017-01-05 10:02:05 +0100994 } else if (isdigit(id[0])) {
995 if (id[0] == '0') {
996 return -parsed;
997 }
998 ret = 1;
999 while (isdigit(id[ret])) {
1000 ++ret;
1001 }
Michal Vasko9fbb6e82017-07-04 13:50:04 +02001002
1003 if (name) {
1004 *name = id;
1005 }
1006 if (nam_len) {
1007 *nam_len = ret;
1008 }
1009 } else if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len)) < 1) {
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001010 return -parsed + ret;
1011 }
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001012
1013 parsed += ret;
1014 id += ret;
1015
1016 while (isspace(id[0])) {
1017 ++parsed;
1018 ++id;
1019 }
1020
1021 /* there is value as well */
1022 if (id[0] == '=') {
Michal Vasko58c2aab2017-01-05 10:02:05 +01001023 if (name && isdigit(**name)) {
1024 return -parsed;
1025 }
1026
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001027 ++parsed;
1028 ++id;
1029
1030 while (isspace(id[0])) {
1031 ++parsed;
1032 ++id;
1033 }
1034
1035 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
1036 if ((id[0] == '\"') || (id[0] == '\'')) {
1037 quote = id[0];
1038
1039 ++parsed;
1040 ++id;
1041
1042 if ((ptr = strchr(id, quote)) == NULL) {
1043 return -parsed;
1044 }
1045 ret = ptr - id;
1046
1047 if (value) {
1048 *value = id;
1049 }
1050 if (val_len) {
1051 *val_len = ret;
1052 }
1053
1054 parsed += ret + 1;
1055 id += ret + 1;
1056 } else {
1057 return -parsed;
1058 }
1059
1060 while (isspace(id[0])) {
1061 ++parsed;
1062 ++id;
1063 }
1064 }
1065
1066 if (id[0] != ']') {
1067 return -parsed;
1068 }
1069
1070 ++parsed;
1071 ++id;
1072
1073 if ((id[0] == '[') && has_predicate) {
1074 *has_predicate = 1;
1075 }
1076
1077 return parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +02001078}
1079
1080/**
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001081 * @brief Resolve (find) a feature definition. Logs directly.
1082 *
1083 * @param[in] feat_name Feature name to resolve.
1084 * @param[in] len Length of \p feat_name.
1085 * @param[in] node Node with the if-feature expression.
Radek Krejci9ff0a922016-07-14 13:08:05 +02001086 * @param[out] feature Pointer to be set to point to the feature definition, if feature not found
1087 * (return code 1), the pointer is untouched.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001088 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02001089 * @return 0 on success, 1 on forward reference, -1 on error.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001090 */
1091static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001092resolve_feature(const char *feat_name, uint16_t len, const struct lys_node *node, struct lys_feature **feature)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001093{
1094 char *str;
1095 const char *mod_name, *name;
1096 int mod_name_len, nam_len, i, j;
1097 const struct lys_module *module;
1098
Radek Krejci9ff0a922016-07-14 13:08:05 +02001099 assert(feature);
1100
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001101 /* check prefix */
1102 if ((i = parse_node_identifier(feat_name, &mod_name, &mod_name_len, &name, &nam_len)) < 1) {
1103 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, feat_name[-i], &feat_name[-i]);
1104 return -1;
1105 }
1106
1107 module = lys_get_import_module(lys_node_module(node), NULL, 0, mod_name, mod_name_len);
1108 if (!module) {
1109 /* identity refers unknown data model */
1110 LOGVAL(LYE_INMOD_LEN, LY_VLOG_NONE, NULL, mod_name_len, mod_name);
1111 return -1;
1112 }
1113
Radek Krejci9ff0a922016-07-14 13:08:05 +02001114 if (module != node->module && module == lys_node_module(node)) {
1115 /* first, try to search directly in submodule where the feature was mentioned */
1116 for (j = 0; j < node->module->features_size; j++) {
1117 if (!strncmp(name, node->module->features[j].name, nam_len) && !node->module->features[j].name[nam_len]) {
1118 /* check status */
1119 if (lyp_check_status(node->flags, lys_node_module(node), node->name, node->module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001120 node->module->features[j].module, node->module->features[j].name, NULL)) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001121 return -1;
1122 }
1123 *feature = &node->module->features[j];
1124 return 0;
1125 }
1126 }
1127 }
1128
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001129 /* search in the identified module ... */
1130 for (j = 0; j < module->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001131 if (!strncmp(name, module->features[j].name, nam_len) && !module->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001132 /* check status */
1133 if (lyp_check_status(node->flags, lys_node_module(node), node->name, module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001134 module->features[j].module, module->features[j].name, NULL)) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001135 return -1;
1136 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001137 *feature = &module->features[j];
1138 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001139 }
1140 }
1141 /* ... and all its submodules */
Radek Krejcid4c1d0f2017-01-19 16:11:38 +01001142 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001143 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001144 if (!strncmp(name, module->inc[i].submodule->features[j].name, nam_len)
1145 && !module->inc[i].submodule->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001146 /* check status */
1147 if (lyp_check_status(node->flags, lys_node_module(node), node->name,
1148 module->inc[i].submodule->features[j].flags,
1149 module->inc[i].submodule->features[j].module,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001150 module->inc[i].submodule->features[j].name, NULL)) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001151 return -1;
1152 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001153 *feature = &module->inc[i].submodule->features[j];
1154 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001155 }
1156 }
1157 }
1158
1159 /* not found */
1160 str = strndup(feat_name, len);
1161 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, "feature", str);
1162 free(str);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001163 return 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001164}
1165
Radek Krejci9ff0a922016-07-14 13:08:05 +02001166/*
1167 * @return
Radek Krejci69b8d922016-07-27 13:13:41 +02001168 * - 1 if enabled
1169 * - 0 if disabled
Radek Krejci9ff0a922016-07-14 13:08:05 +02001170 */
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001171static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001172resolve_feature_value(const struct lys_feature *feat)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001173{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001174 int i;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001175
Radek Krejci9ff0a922016-07-14 13:08:05 +02001176 for (i = 0; i < feat->iffeature_size; i++) {
Radek Krejci69b8d922016-07-27 13:13:41 +02001177 if (!resolve_iffeature(&feat->iffeature[i])) {
Radek Krejciaf566332017-02-07 15:56:59 +01001178 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001179 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001180 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001181
Radek Krejci69b8d922016-07-27 13:13:41 +02001182 return feat->flags & LYS_FENABLED ? 1 : 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001183}
1184
1185static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001186resolve_iffeature_recursive(struct lys_iffeature *expr, int *index_e, int *index_f)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001187{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001188 uint8_t op;
Radek Krejciaf566332017-02-07 15:56:59 +01001189 int a, b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001190
Radek Krejci9ff0a922016-07-14 13:08:05 +02001191 op = iff_getop(expr->expr, *index_e);
1192 (*index_e)++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001193
Radek Krejci9ff0a922016-07-14 13:08:05 +02001194 switch (op) {
1195 case LYS_IFF_F:
1196 /* resolve feature */
1197 return resolve_feature_value(expr->features[(*index_f)++]);
1198 case LYS_IFF_NOT:
Radek Krejciaf566332017-02-07 15:56:59 +01001199 /* invert result */
1200 return resolve_iffeature_recursive(expr, index_e, index_f) ? 0 : 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001201 case LYS_IFF_AND:
1202 case LYS_IFF_OR:
1203 a = resolve_iffeature_recursive(expr, index_e, index_f);
1204 b = resolve_iffeature_recursive(expr, index_e, index_f);
Radek Krejciaf566332017-02-07 15:56:59 +01001205 if (op == LYS_IFF_AND) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001206 return a && b;
1207 } else { /* LYS_IFF_OR */
1208 return a || b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001209 }
1210 }
1211
Radek Krejciaf566332017-02-07 15:56:59 +01001212 return 0;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001213}
1214
1215int
1216resolve_iffeature(struct lys_iffeature *expr)
1217{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001218 int index_e = 0, index_f = 0;
1219
1220 if (expr->expr) {
Radek Krejciaf566332017-02-07 15:56:59 +01001221 return resolve_iffeature_recursive(expr, &index_e, &index_f);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001222 }
Radek Krejciaf566332017-02-07 15:56:59 +01001223 return 0;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001224}
1225
1226struct iff_stack {
1227 int size;
1228 int index; /* first empty item */
1229 uint8_t *stack;
1230};
1231
1232static int
1233iff_stack_push(struct iff_stack *stack, uint8_t value)
1234{
1235 if (stack->index == stack->size) {
1236 stack->size += 4;
1237 stack->stack = ly_realloc(stack->stack, stack->size * sizeof *stack->stack);
Radek Krejciaa1303c2017-05-31 13:57:37 +02001238 LY_CHECK_ERR_RETURN(!stack->stack, LOGMEM; stack->size = 0, EXIT_FAILURE);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001239 }
1240
1241 stack->stack[stack->index++] = value;
1242 return EXIT_SUCCESS;
1243}
1244
1245static uint8_t
1246iff_stack_pop(struct iff_stack *stack)
1247{
1248 stack->index--;
1249 return stack->stack[stack->index];
1250}
1251
1252static void
1253iff_stack_clean(struct iff_stack *stack)
1254{
1255 stack->size = 0;
1256 free(stack->stack);
1257}
1258
1259static void
1260iff_setop(uint8_t *list, uint8_t op, int pos)
1261{
1262 uint8_t *item;
1263 uint8_t mask = 3;
1264
1265 assert(pos >= 0);
1266 assert(op <= 3); /* max 2 bits */
1267
1268 item = &list[pos / 4];
1269 mask = mask << 2 * (pos % 4);
1270 *item = (*item) & ~mask;
1271 *item = (*item) | (op << 2 * (pos % 4));
1272}
1273
1274uint8_t
1275iff_getop(uint8_t *list, int pos)
1276{
1277 uint8_t *item;
1278 uint8_t mask = 3, result;
1279
1280 assert(pos >= 0);
1281
1282 item = &list[pos / 4];
1283 result = (*item) & (mask << 2 * (pos % 4));
1284 return result >> 2 * (pos % 4);
1285}
1286
1287#define LYS_IFF_LP 0x04 /* ( */
1288#define LYS_IFF_RP 0x08 /* ) */
1289
Radek Krejcicbb473e2016-09-16 14:48:32 +02001290/* internal structure for passing data for UNRES_IFFEAT */
1291struct unres_iffeat_data {
1292 struct lys_node *node;
1293 const char *fname;
Radek Krejci9de2c042016-10-19 16:53:06 +02001294 int infeature;
Radek Krejcicbb473e2016-09-16 14:48:32 +02001295};
1296
Radek Krejci9ff0a922016-07-14 13:08:05 +02001297void
1298resolve_iffeature_getsizes(struct lys_iffeature *iffeat, unsigned int *expr_size, unsigned int *feat_size)
1299{
1300 unsigned int e = 0, f = 0, r = 0;
1301 uint8_t op;
1302
1303 assert(iffeat);
1304
1305 if (!iffeat->expr) {
1306 goto result;
1307 }
1308
1309 do {
1310 op = iff_getop(iffeat->expr, e++);
1311 switch (op) {
1312 case LYS_IFF_NOT:
1313 if (!r) {
1314 r += 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001315 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001316 break;
1317 case LYS_IFF_AND:
1318 case LYS_IFF_OR:
1319 if (!r) {
1320 r += 2;
1321 } else {
1322 r += 1;
1323 }
1324 break;
1325 case LYS_IFF_F:
1326 f++;
1327 if (r) {
1328 r--;
1329 }
1330 break;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001331 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001332 } while(r);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001333
Radek Krejci9ff0a922016-07-14 13:08:05 +02001334result:
1335 if (expr_size) {
1336 *expr_size = e;
1337 }
1338 if (feat_size) {
1339 *feat_size = f;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001340 }
1341}
1342
1343int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001344resolve_iffeature_compile(struct lys_iffeature *iffeat_expr, const char *value, struct lys_node *node,
Radek Krejci9de2c042016-10-19 16:53:06 +02001345 int infeature, struct unres_schema *unres)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001346{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001347 const char *c = value;
1348 int r, rc = EXIT_FAILURE;
Radek Krejci69b8d922016-07-27 13:13:41 +02001349 int i, j, last_not, checkversion = 0;
1350 unsigned int f_size = 0, expr_size = 0, f_exp = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001351 uint8_t op;
1352 struct iff_stack stack = {0, 0, NULL};
Radek Krejcicbb473e2016-09-16 14:48:32 +02001353 struct unres_iffeat_data *iff_data;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001354
Radek Krejci9ff0a922016-07-14 13:08:05 +02001355 assert(c);
1356
1357 if (isspace(c[0])) {
1358 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, c[0], c);
1359 return EXIT_FAILURE;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001360 }
1361
Radek Krejci9ff0a922016-07-14 13:08:05 +02001362 /* pre-parse the expression to get sizes for arrays, also do some syntax checks of the expression */
1363 for (i = j = last_not = 0; c[i]; i++) {
1364 if (c[i] == '(') {
Radek Krejci69b8d922016-07-27 13:13:41 +02001365 checkversion = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001366 j++;
1367 continue;
1368 } else if (c[i] == ')') {
1369 j--;
1370 continue;
1371 } else if (isspace(c[i])) {
1372 continue;
1373 }
1374
1375 if (!strncmp(&c[i], "not", r = 3) || !strncmp(&c[i], "and", r = 3) || !strncmp(&c[i], "or", r = 2)) {
1376 if (c[i + r] == '\0') {
Radek Krejcia98da3f2016-07-27 14:05:22 +02001377 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
Radek Krejci9ff0a922016-07-14 13:08:05 +02001378 return EXIT_FAILURE;
1379 } else if (!isspace(c[i + r])) {
1380 /* feature name starting with the not/and/or */
1381 last_not = 0;
1382 f_size++;
1383 } else if (c[i] == 'n') { /* not operation */
1384 if (last_not) {
1385 /* double not */
1386 expr_size = expr_size - 2;
1387 last_not = 0;
1388 } else {
1389 last_not = 1;
1390 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001391 } else { /* and, or */
1392 f_exp++;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001393 /* not a not operation */
1394 last_not = 0;
1395 }
1396 i += r;
1397 } else {
1398 f_size++;
1399 last_not = 0;
1400 }
1401 expr_size++;
1402
1403 while (!isspace(c[i])) {
1404 if (!c[i] || c[i] == ')') {
1405 i--;
1406 break;
1407 }
1408 i++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001409 }
1410 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001411 if (j || f_exp != f_size) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001412 /* not matching count of ( and ) */
1413 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1414 return EXIT_FAILURE;
1415 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001416
Radek Krejci69b8d922016-07-27 13:13:41 +02001417 if (checkversion || expr_size > 1) {
1418 /* check that we have 1.1 module */
1419 if (node->module->version != 2) {
1420 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1421 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "YANG 1.1 if-feature expression found in 1.0 module.");
1422 return EXIT_FAILURE;
1423 }
1424 }
1425
Radek Krejci9ff0a922016-07-14 13:08:05 +02001426 /* allocate the memory */
1427 iffeat_expr->expr = calloc((j = (expr_size / 4) + ((expr_size % 4) ? 1 : 0)), sizeof *iffeat_expr->expr);
Radek Krejcicbb473e2016-09-16 14:48:32 +02001428 iffeat_expr->features = calloc(f_size, sizeof *iffeat_expr->features);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001429 stack.stack = malloc(expr_size * sizeof *stack.stack);
Radek Krejciaa1303c2017-05-31 13:57:37 +02001430 LY_CHECK_ERR_GOTO(!stack.stack || !iffeat_expr->expr || !iffeat_expr->features, LOGMEM, error);
1431 stack.size = expr_size;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001432 f_size--; expr_size--; /* used as indexes from now */
1433
1434 for (i--; i >= 0; i--) {
1435 if (c[i] == ')') {
1436 /* push it on stack */
1437 iff_stack_push(&stack, LYS_IFF_RP);
1438 continue;
1439 } else if (c[i] == '(') {
1440 /* pop from the stack into result all operators until ) */
1441 while((op = iff_stack_pop(&stack)) != LYS_IFF_RP) {
1442 iff_setop(iffeat_expr->expr, op, expr_size--);
1443 }
1444 continue;
1445 } else if (isspace(c[i])) {
1446 continue;
1447 }
1448
1449 /* end operator or operand -> find beginning and get what is it */
1450 j = i + 1;
1451 while (i >= 0 && !isspace(c[i]) && c[i] != '(') {
1452 i--;
1453 }
1454 i++; /* get back by one step */
1455
1456 if (!strncmp(&c[i], "not ", 4)) {
1457 if (stack.index && stack.stack[stack.index - 1] == LYS_IFF_NOT) {
1458 /* double not */
1459 iff_stack_pop(&stack);
1460 } else {
1461 /* not has the highest priority, so do not pop from the stack
1462 * as in case of AND and OR */
1463 iff_stack_push(&stack, LYS_IFF_NOT);
1464 }
1465 } else if (!strncmp(&c[i], "and ", 4)) {
1466 /* as for OR - pop from the stack all operators with the same or higher
1467 * priority and store them to the result, then push the AND to the stack */
1468 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_AND) {
1469 op = iff_stack_pop(&stack);
1470 iff_setop(iffeat_expr->expr, op, expr_size--);
1471 }
1472 iff_stack_push(&stack, LYS_IFF_AND);
1473 } else if (!strncmp(&c[i], "or ", 3)) {
1474 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_OR) {
1475 op = iff_stack_pop(&stack);
1476 iff_setop(iffeat_expr->expr, op, expr_size--);
1477 }
1478 iff_stack_push(&stack, LYS_IFF_OR);
1479 } else {
1480 /* feature name, length is j - i */
1481
1482 /* add it to the result */
1483 iff_setop(iffeat_expr->expr, LYS_IFF_F, expr_size--);
1484
1485 /* now get the link to the feature definition. Since it can be
Radek Krejcicbb473e2016-09-16 14:48:32 +02001486 * forward referenced, we have to keep the feature name in auxiliary
1487 * structure passed into unres */
1488 iff_data = malloc(sizeof *iff_data);
Radek Krejciaa1303c2017-05-31 13:57:37 +02001489 LY_CHECK_ERR_GOTO(!iff_data, LOGMEM, error);
Radek Krejcicbb473e2016-09-16 14:48:32 +02001490 iff_data->node = node;
1491 iff_data->fname = lydict_insert(node->module->ctx, &c[i], j - i);
Radek Krejci9de2c042016-10-19 16:53:06 +02001492 iff_data->infeature = infeature;
Radek Krejcicbb473e2016-09-16 14:48:32 +02001493 r = unres_schema_add_node(node->module, unres, &iffeat_expr->features[f_size], UNRES_IFFEAT,
1494 (struct lys_node *)iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001495 f_size--;
1496
1497 if (r == -1) {
Pavol Vican4d084512016-09-29 16:38:12 +02001498 free(iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001499 goto error;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001500 }
1501 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001502 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001503 while (stack.index) {
1504 op = iff_stack_pop(&stack);
1505 iff_setop(iffeat_expr->expr, op, expr_size--);
1506 }
1507
1508 if (++expr_size || ++f_size) {
1509 /* not all expected operators and operands found */
1510 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1511 rc = EXIT_FAILURE;
1512 } else {
1513 rc = EXIT_SUCCESS;
1514 }
1515
1516error:
1517 /* cleanup */
1518 iff_stack_clean(&stack);
1519
1520 return rc;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001521}
1522
1523/**
Michal Vasko3edeaf72016-02-11 13:17:43 +01001524 * @brief Resolve (find) a data node based on a schema-nodeid.
1525 *
1526 * Used for resolving unique statements - so id is expected to be relative and local (without reference to a different
1527 * module).
1528 *
1529 */
1530struct lyd_node *
1531resolve_data_descendant_schema_nodeid(const char *nodeid, struct lyd_node *start)
1532{
1533 char *str, *token, *p;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001534 struct lyd_node *result = NULL, *iter;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001535 const struct lys_node *schema = NULL;
1536
1537 assert(nodeid && start);
1538
1539 if (nodeid[0] == '/') {
1540 return NULL;
1541 }
1542
1543 str = p = strdup(nodeid);
Radek Krejciaa1303c2017-05-31 13:57:37 +02001544 LY_CHECK_ERR_RETURN(!str, LOGMEM, NULL);
Radek Krejci5da4eb62016-04-08 14:45:51 +02001545
Michal Vasko3edeaf72016-02-11 13:17:43 +01001546 while (p) {
1547 token = p;
1548 p = strchr(p, '/');
1549 if (p) {
1550 *p = '\0';
1551 p++;
1552 }
1553
Radek Krejci5da4eb62016-04-08 14:45:51 +02001554 if (p) {
1555 /* inner node */
Radek Krejcicc217a62016-04-08 16:58:11 +02001556 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema,
Michal Vaskodc300b02017-04-07 14:09:20 +02001557 LYS_CONTAINER | LYS_CHOICE | LYS_CASE | LYS_LEAF, 0, &schema)
Radek Krejci5da4eb62016-04-08 14:45:51 +02001558 || !schema) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001559 result = NULL;
1560 break;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001561 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001562
Radek Krejci5da4eb62016-04-08 14:45:51 +02001563 if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
1564 continue;
1565 }
1566 } else {
1567 /* final node */
Michal Vaskodc300b02017-04-07 14:09:20 +02001568 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema, LYS_LEAF, 0, &schema)
Radek Krejcicc217a62016-04-08 16:58:11 +02001569 || !schema) {
1570 result = NULL;
1571 break;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001572 }
1573 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001574 LY_TREE_FOR(result ? result->child : start, iter) {
1575 if (iter->schema == schema) {
1576 /* move in data tree according to returned schema */
1577 result = iter;
1578 break;
1579 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001580 }
Radek Krejcicc217a62016-04-08 16:58:11 +02001581 if (!iter) {
1582 /* instance not found */
1583 result = NULL;
1584 break;
1585 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001586 }
1587 free(str);
1588
1589 return result;
1590}
1591
Radek Krejcibdf92362016-04-08 14:43:34 +02001592/*
1593 * 0 - ok (done)
1594 * 1 - continue
1595 * 2 - break
1596 * -1 - error
1597 */
Radek Krejci1a9c3612017-04-24 14:49:43 +02001598int
Michal Vaskodc300b02017-04-07 14:09:20 +02001599schema_nodeid_siblingcheck(const struct lys_node *sibling, const char *id, const struct lys_module *module,
Michal Vaskobb520442017-05-23 10:55:18 +02001600 const char *mod_name, int mod_name_len, const struct lys_node **start_parent)
Radek Krejcibdf92362016-04-08 14:43:34 +02001601{
1602 const struct lys_module *prefix_mod;
1603
1604 /* module check */
1605 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
1606 if (!prefix_mod) {
1607 return -1;
1608 }
1609 if (prefix_mod != lys_node_module(sibling)) {
1610 return 1;
1611 }
1612
Radek Krejcibdf92362016-04-08 14:43:34 +02001613 /* the result node? */
1614 if (!id[0]) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001615 return 0;
1616 }
1617
Michal Vaskodc300b02017-04-07 14:09:20 +02001618 /* move down the tree, if possible */
1619 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
1620 return -1;
Radek Krejcibdf92362016-04-08 14:43:34 +02001621 }
Michal Vaskodc300b02017-04-07 14:09:20 +02001622 *start_parent = sibling;
Radek Krejcibdf92362016-04-08 14:43:34 +02001623
1624 return 2;
1625}
1626
Radek Krejcidf46e222016-11-08 11:57:37 +01001627/* start - relative, module - absolute, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1
Radek Krejcidf46e222016-11-08 11:57:37 +01001628 */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001629int
1630resolve_augment_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_module *module,
Michal Vaskobb520442017-05-23 10:55:18 +02001631 const struct lys_node **ret)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001632{
Michal Vaskobb520442017-05-23 10:55:18 +02001633 const char *name, *mod_name, *id;
Michal Vasko24476fa2017-03-08 12:33:48 +01001634 const struct lys_node *sibling, *start_parent;
Michal Vaskobb520442017-05-23 10:55:18 +02001635 struct lys_node_augment *last_aug;
1636 int r, nam_len, mod_name_len = 0, is_relative = -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001637 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcidf46e222016-11-08 11:57:37 +01001638 const struct lys_module *start_mod, *aux_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001639
1640 assert(nodeid && (start || module) && !(start && module) && ret);
1641
1642 id = nodeid;
1643
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001644 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001645 return ((id - nodeid) - r) + 1;
1646 }
1647 id += r;
1648
1649 if ((is_relative && !start) || (!is_relative && !module)) {
1650 return -1;
1651 }
1652
1653 /* descendant-schema-nodeid */
1654 if (is_relative) {
Michal Vasko4c06fd82016-02-17 13:43:38 +01001655 module = start_mod = start->module;
Michal Vasko24476fa2017-03-08 12:33:48 +01001656 start_parent = lys_parent(start);
Michal Vasko24476fa2017-03-08 12:33:48 +01001657
Michal Vasko3edeaf72016-02-11 13:17:43 +01001658 /* absolute-schema-nodeid */
1659 } else {
1660 start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001661 if (!start_mod) {
1662 return -1;
1663 }
Michal Vasko24476fa2017-03-08 12:33:48 +01001664 start_parent = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001665 }
1666
1667 while (1) {
1668 sibling = NULL;
Michal Vaskobb520442017-05-23 10:55:18 +02001669 last_aug = NULL;
1670
1671 if (start_parent) {
Michal Vaskoe4c83442017-07-11 08:49:01 +02001672 if (mod_name && (strncmp(mod_name, module->name, mod_name_len)
1673 || (mod_name_len != (signed)strlen(module->name)))) {
Michal Vaskobb520442017-05-23 10:55:18 +02001674 /* we are getting into another module (augment) */
1675 aux_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
1676 if (!aux_mod) {
1677 return -1;
1678 }
1679 } else {
Michal Vasko201c3392017-07-10 15:15:39 +02001680 /* there is no mod_name, so why are we checking augments again?
Michal Vaskobb520442017-05-23 10:55:18 +02001681 * because this module may be not implemented and it augments something in another module and
1682 * there is another augment augmenting that previous one */
Michal Vaskoe4c83442017-07-11 08:49:01 +02001683 aux_mod = module;
Michal Vaskobb520442017-05-23 10:55:18 +02001684 }
1685
1686 /* if the module is implemented, all the augments will be connected */
1687 if (!aux_mod->implemented) {
1688get_next_augment:
1689 last_aug = lys_getnext_target_aug(last_aug, aux_mod, start_parent);
1690 }
1691 }
1692
1693 while ((sibling = lys_getnext(sibling, (last_aug ? (struct lys_node *)last_aug : start_parent), start_mod,
Michal Vasko5b997902017-04-03 14:16:22 +02001694 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_PARENTUSES))) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001695 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001696 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vaskobb520442017-05-23 10:55:18 +02001697 r = schema_nodeid_siblingcheck(sibling, id, module, mod_name, mod_name_len, &start_parent);
Radek Krejcibdf92362016-04-08 14:43:34 +02001698 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001699 *ret = sibling;
1700 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001701 } else if (r == 1) {
1702 continue;
1703 } else if (r == 2) {
1704 break;
1705 } else {
1706 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001707 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001708 }
1709 }
1710
1711 /* no match */
1712 if (!sibling) {
Michal Vaskobb520442017-05-23 10:55:18 +02001713 if (last_aug) {
1714 /* it still could be in another augment */
1715 goto get_next_augment;
1716 }
Michal Vaskoa426fef2016-03-07 10:47:31 +01001717 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001718 return EXIT_SUCCESS;
1719 }
1720
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001721 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 +01001722 return ((id - nodeid) - r) + 1;
1723 }
1724 id += r;
1725 }
1726
1727 /* cannot get here */
1728 LOGINT;
1729 return -1;
1730}
1731
Radek Krejcif3c71de2016-04-11 12:45:46 +02001732/* unique, refine,
1733 * >0 - unexpected char on position (ret - 1),
1734 * 0 - ok (but ret can still be NULL),
1735 * -1 - error,
1736 * -2 - violated no_innerlist */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001737int
1738resolve_descendant_schema_nodeid(const char *nodeid, const struct lys_node *start, int ret_nodetype,
Michal Vaskodc300b02017-04-07 14:09:20 +02001739 int no_innerlist, const struct lys_node **ret)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001740{
1741 const char *name, *mod_name, *id;
Michal Vasko24476fa2017-03-08 12:33:48 +01001742 const struct lys_node *sibling, *start_parent;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001743 int r, nam_len, mod_name_len, is_relative = -1;
1744 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcibdf92362016-04-08 14:43:34 +02001745 const struct lys_module *module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001746
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01001747 assert(nodeid && ret);
Radek Krejcie2077412017-01-26 16:03:39 +01001748 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT | LYS_GROUPING)));
Michal Vasko3edeaf72016-02-11 13:17:43 +01001749
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01001750 if (!start) {
1751 /* leaf not found */
1752 return 0;
1753 }
1754
Michal Vasko3edeaf72016-02-11 13:17:43 +01001755 id = nodeid;
1756 module = start->module;
1757
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001758 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 +01001759 return ((id - nodeid) - r) + 1;
1760 }
1761 id += r;
1762
1763 if (!is_relative) {
1764 return -1;
1765 }
1766
Michal Vasko24476fa2017-03-08 12:33:48 +01001767 start_parent = lys_parent(start);
Michal Vasko74a991b2017-03-31 09:17:22 +02001768 while ((start_parent->nodetype == LYS_USES) && lys_parent(start_parent)) {
Michal Vasko24476fa2017-03-08 12:33:48 +01001769 start_parent = lys_parent(start_parent);
1770 }
1771
Michal Vasko3edeaf72016-02-11 13:17:43 +01001772 while (1) {
1773 sibling = NULL;
Michal Vasko24476fa2017-03-08 12:33:48 +01001774 while ((sibling = lys_getnext(sibling, start_parent, module,
Michal Vasko74a991b2017-03-31 09:17:22 +02001775 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_PARENTUSES))) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001776 /* name match */
1777 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vaskobb520442017-05-23 10:55:18 +02001778 r = schema_nodeid_siblingcheck(sibling, id, module, mod_name, mod_name_len, &start_parent);
Radek Krejcibdf92362016-04-08 14:43:34 +02001779 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001780 if (!(sibling->nodetype & ret_nodetype)) {
1781 /* wrong node type, too bad */
1782 continue;
1783 }
1784 *ret = sibling;
1785 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001786 } else if (r == 1) {
1787 continue;
1788 } else if (r == 2) {
1789 break;
1790 } else {
1791 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001792 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001793 }
1794 }
1795
1796 /* no match */
1797 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001798 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001799 return EXIT_SUCCESS;
Radek Krejcif3c71de2016-04-11 12:45:46 +02001800 } else if (no_innerlist && sibling->nodetype == LYS_LIST) {
1801 *ret = NULL;
1802 return -2;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001803 }
1804
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001805 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 +01001806 return ((id - nodeid) - r) + 1;
1807 }
1808 id += r;
1809 }
1810
1811 /* cannot get here */
1812 LOGINT;
1813 return -1;
1814}
1815
1816/* choice default */
1817int
1818resolve_choice_default_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node **ret)
1819{
1820 /* cannot actually be a path */
1821 if (strchr(nodeid, '/')) {
1822 return -1;
1823 }
1824
Michal Vaskodc300b02017-04-07 14:09:20 +02001825 return resolve_descendant_schema_nodeid(nodeid, start, LYS_NO_RPC_NOTIF_NODE, 0, ret);
Michal Vasko3edeaf72016-02-11 13:17:43 +01001826}
1827
1828/* uses, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1829static int
1830resolve_uses_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node_grp **ret)
1831{
1832 const struct lys_module *module;
1833 const char *mod_prefix, *name;
1834 int i, mod_prefix_len, nam_len;
1835
1836 /* parse the identifier, it must be parsed on one call */
1837 if (((i = parse_node_identifier(nodeid, &mod_prefix, &mod_prefix_len, &name, &nam_len)) < 1) || nodeid[i]) {
1838 return -i + 1;
1839 }
1840
1841 module = lys_get_import_module(start->module, mod_prefix, mod_prefix_len, NULL, 0);
1842 if (!module) {
1843 return -1;
1844 }
Radek Krejci0a8205d2017-03-01 16:25:29 +01001845 if (module != lys_main_module(start->module)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001846 start = module->data;
1847 }
1848
1849 *ret = lys_find_grouping_up(name, (struct lys_node *)start);
1850
1851 return EXIT_SUCCESS;
1852}
1853
1854int
1855resolve_absolute_schema_nodeid(const char *nodeid, const struct lys_module *module, int ret_nodetype,
1856 const struct lys_node **ret)
1857{
1858 const char *name, *mod_name, *id;
Michal Vasko24476fa2017-03-08 12:33:48 +01001859 const struct lys_node *sibling, *start_parent;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001860 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcibdf92362016-04-08 14:43:34 +02001861 const struct lys_module *abs_start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001862
1863 assert(nodeid && module && ret);
1864 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1865
1866 id = nodeid;
Michal Vasko24476fa2017-03-08 12:33:48 +01001867 start_parent = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001868
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001869 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 +01001870 return ((id - nodeid) - r) + 1;
1871 }
1872 id += r;
1873
1874 if (is_relative) {
1875 return -1;
1876 }
1877
1878 abs_start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001879 if (!abs_start_mod) {
1880 return -1;
1881 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001882
1883 while (1) {
1884 sibling = NULL;
Michal Vasko24476fa2017-03-08 12:33:48 +01001885 while ((sibling = lys_getnext(sibling, start_parent, abs_start_mod, LYS_GETNEXT_WITHCHOICE
Michal Vasko3edeaf72016-02-11 13:17:43 +01001886 | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_WITHGROUPING))) {
1887 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001888 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vaskobb520442017-05-23 10:55:18 +02001889 r = schema_nodeid_siblingcheck(sibling, id, module, mod_name, mod_name_len, &start_parent);
Radek Krejcibdf92362016-04-08 14:43:34 +02001890 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001891 if (!(sibling->nodetype & ret_nodetype)) {
1892 /* wrong node type, too bad */
1893 continue;
1894 }
1895 *ret = sibling;
1896 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001897 } else if (r == 1) {
1898 continue;
1899 } else if (r == 2) {
1900 break;
1901 } else {
1902 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001903 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001904 }
1905 }
1906
1907 /* no match */
1908 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001909 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001910 return EXIT_SUCCESS;
1911 }
1912
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001913 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 +01001914 return ((id - nodeid) - r) + 1;
1915 }
1916 id += r;
1917 }
1918
1919 /* cannot get here */
1920 LOGINT;
1921 return -1;
1922}
1923
Michal Vaskoe733d682016-03-14 09:08:27 +01001924static int
Michal Vasko9fbb6e82017-07-04 13:50:04 +02001925resolve_json_schema_list_predicate(const char *predicate, const struct lys_node_list *list,
1926 const struct lys_module *cur_module, int *parsed)
Michal Vaskoe733d682016-03-14 09:08:27 +01001927{
Michal Vasko9fbb6e82017-07-04 13:50:04 +02001928 const char *mod_name, *name;
1929 int mod_name_len, nam_len, has_predicate, i;
1930 struct lys_node *key;
Michal Vaskoe733d682016-03-14 09:08:27 +01001931
Michal Vasko9fbb6e82017-07-04 13:50:04 +02001932 if (((i = parse_schema_json_predicate(predicate, &mod_name, &mod_name_len, &name, &nam_len, NULL, NULL, &has_predicate)) < 1)
Michal Vasko7b54f7e2016-05-03 15:07:31 +02001933 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001934 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-i], &predicate[-i]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001935 return -1;
1936 }
1937
1938 predicate += i;
1939 *parsed += i;
1940
Michal Vasko58c2aab2017-01-05 10:02:05 +01001941 if (!isdigit(name[0])) {
1942 for (i = 0; i < list->keys_size; ++i) {
Michal Vasko9fbb6e82017-07-04 13:50:04 +02001943 key = (struct lys_node *)list->keys[i];
1944 if (!strncmp(key->name, name, nam_len) && !key->name[nam_len]) {
1945 if (mod_name) {
1946 if (!strncmp(lys_node_module(key)->name, mod_name, mod_name_len) && !lys_node_module(key)->name[mod_name_len]) {
1947 break;
1948 }
1949 } else {
1950 if (!strcmp(lys_node_module(key)->name, cur_module->name)) {
1951 break;
1952 }
1953 }
Michal Vasko58c2aab2017-01-05 10:02:05 +01001954 }
Michal Vaskoe733d682016-03-14 09:08:27 +01001955 }
Michal Vaskoe733d682016-03-14 09:08:27 +01001956
Michal Vasko58c2aab2017-01-05 10:02:05 +01001957 if (i == list->keys_size) {
1958 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
1959 return -1;
1960 }
Michal Vaskoe733d682016-03-14 09:08:27 +01001961 }
1962
1963 /* more predicates? */
1964 if (has_predicate) {
Michal Vasko9fbb6e82017-07-04 13:50:04 +02001965 return resolve_json_schema_list_predicate(predicate, list, cur_module, parsed);
Michal Vaskoe733d682016-03-14 09:08:27 +01001966 }
1967
1968 return 0;
1969}
1970
Michal Vasko8d26e5c2016-09-08 10:03:49 +02001971/* cannot return LYS_GROUPING, LYS_AUGMENT, LYS_USES, logs directly */
Michal Vaskoe733d682016-03-14 09:08:27 +01001972const struct lys_node *
Michal Vasko8d26e5c2016-09-08 10:03:49 +02001973resolve_json_nodeid(const char *nodeid, struct ly_ctx *ctx, const struct lys_node *start)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001974{
Michal Vasko10728b52016-04-07 14:26:29 +02001975 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001976 const char *name, *mod_name, *id;
Michal Vasko24476fa2017-03-08 12:33:48 +01001977 const struct lys_node *sibling, *start_parent;
Michal Vaskodc300b02017-04-07 14:09:20 +02001978 int r, nam_len, mod_name_len, is_relative = -1, has_predicate;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001979 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vasko9fbb6e82017-07-04 13:50:04 +02001980 const struct lys_module *prefix_mod, *cur_module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001981
Michal Vasko3547c532016-03-14 09:40:50 +01001982 assert(nodeid && (ctx || start));
1983 if (!ctx) {
1984 ctx = start->module->ctx;
1985 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001986
1987 id = nodeid;
1988
Michal Vaskoe733d682016-03-14 09:08:27 +01001989 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 +01001990 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001991 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001992 }
1993 id += r;
1994
1995 if (is_relative) {
Michal Vasko3547c532016-03-14 09:40:50 +01001996 assert(start);
Michal Vasko24476fa2017-03-08 12:33:48 +01001997 start_parent = start;
1998 while (start_parent && (start_parent->nodetype == LYS_USES)) {
1999 start_parent = lys_parent(start_parent);
Michal Vasko3547c532016-03-14 09:40:50 +01002000 }
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002001 cur_module = start->module;
Michal Vasko3547c532016-03-14 09:40:50 +01002002 } else {
2003 if (!mod_name) {
Michal Vasko10728b52016-04-07 14:26:29 +02002004 str = strndup(nodeid, (name + nam_len) - nodeid);
2005 LOGVAL(LYE_PATH_MISSMOD, LY_VLOG_STR, nodeid);
2006 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002007 return NULL;
Michal Vasko971a3ca2016-04-01 13:09:29 +02002008 } else if (mod_name_len > LY_BUF_SIZE - 1) {
2009 LOGINT;
2010 return NULL;
Michal Vasko3547c532016-03-14 09:40:50 +01002011 }
2012
Michal Vasko971a3ca2016-04-01 13:09:29 +02002013 if (ly_buf_used && module_name[0]) {
2014 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2015 }
2016 ly_buf_used++;
2017
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002018 memmove(module_name, mod_name, mod_name_len);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002019 module_name[mod_name_len] = '\0';
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002020 cur_module = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002021
2022 if (buf_backup) {
2023 /* return previous internal buffer content */
2024 strcpy(module_name, buf_backup);
2025 free(buf_backup);
2026 buf_backup = NULL;
2027 }
2028 ly_buf_used--;
2029
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002030 if (!cur_module) {
Michal Vasko10728b52016-04-07 14:26:29 +02002031 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2032 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2033 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002034 return NULL;
2035 }
Michal Vasko24476fa2017-03-08 12:33:48 +01002036 start_parent = NULL;
Michal Vasko3547c532016-03-14 09:40:50 +01002037
2038 /* now it's as if there was no module name */
2039 mod_name = NULL;
2040 mod_name_len = 0;
Michal Vaskoe733d682016-03-14 09:08:27 +01002041 }
2042
Michal Vasko3edeaf72016-02-11 13:17:43 +01002043 while (1) {
2044 sibling = NULL;
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002045 while ((sibling = lys_getnext(sibling, start_parent, cur_module,
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002046 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002047 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02002048 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002049 /* module check */
2050 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002051 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko8757e7c2016-03-15 10:41:30 +01002052 LOGINT;
2053 return NULL;
2054 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002055
2056 if (ly_buf_used && module_name[0]) {
2057 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2058 }
2059 ly_buf_used++;
2060
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002061 memmove(module_name, mod_name, mod_name_len);
Michal Vasko8757e7c2016-03-15 10:41:30 +01002062 module_name[mod_name_len] = '\0';
2063 /* will also find an augment module */
2064 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002065
2066 if (buf_backup) {
2067 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002068 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002069 free(buf_backup);
2070 buf_backup = NULL;
2071 }
2072 ly_buf_used--;
2073
Michal Vasko3edeaf72016-02-11 13:17:43 +01002074 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002075 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2076 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2077 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002078 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002079 }
2080 } else {
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002081 prefix_mod = cur_module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002082 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01002083 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002084 continue;
2085 }
2086
Michal Vaskoe733d682016-03-14 09:08:27 +01002087 /* do we have some predicates on it? */
2088 if (has_predicate) {
2089 r = 0;
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002090 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002091 if ((r = parse_schema_json_predicate(id, NULL, NULL, NULL, NULL, NULL, NULL, &has_predicate)) < 1) {
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002092 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2093 return NULL;
2094 }
2095 } else if (sibling->nodetype == LYS_LIST) {
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002096 if (resolve_json_schema_list_predicate(id, (const struct lys_node_list *)sibling, cur_module, &r)) {
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002097 return NULL;
2098 }
2099 } else {
Michal Vasko43c300e2016-03-22 12:54:27 +01002100 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vaskoe733d682016-03-14 09:08:27 +01002101 return NULL;
Michal Vaskoe733d682016-03-14 09:08:27 +01002102 }
2103 id += r;
2104 }
2105
Michal Vasko3edeaf72016-02-11 13:17:43 +01002106 /* the result node? */
2107 if (!id[0]) {
Michal Vaskoe733d682016-03-14 09:08:27 +01002108 return sibling;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002109 }
2110
Michal Vaskodc300b02017-04-07 14:09:20 +02002111 /* move down the tree, if possible */
2112 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
2113 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2114 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002115 }
Michal Vaskodc300b02017-04-07 14:09:20 +02002116 start_parent = sibling;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002117 break;
2118 }
2119 }
2120
2121 /* no match */
2122 if (!sibling) {
Michal Vasko10728b52016-04-07 14:26:29 +02002123 str = strndup(nodeid, (name + nam_len) - nodeid);
2124 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
2125 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002126 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002127 }
2128
Michal Vaskoe733d682016-03-14 09:08:27 +01002129 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 +01002130 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002131 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002132 }
2133 id += r;
2134 }
2135
2136 /* cannot get here */
2137 LOGINT;
Michal Vaskoe733d682016-03-14 09:08:27 +01002138 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002139}
2140
Michal Vasko22448d32016-03-16 13:17:29 +01002141static int
Michal Vasko58c2aab2017-01-05 10:02:05 +01002142resolve_partial_json_data_list_predicate(const char *predicate, const char *node_name, struct lyd_node *node,
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002143 int position, const struct lys_module *cur_module, int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002144{
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002145 const char *mod_name, *name, *value, *key_val;
2146 int mod_name_len, nam_len, val_len, has_predicate = 1, r;
Michal Vasko22448d32016-03-16 13:17:29 +01002147 uint16_t i;
Michal Vaskof29903d2016-04-18 13:13:10 +02002148 struct lyd_node_leaf_list *key;
Michal Vasko22448d32016-03-16 13:17:29 +01002149
Radek Krejci61a86c62016-03-24 11:06:44 +01002150 assert(node);
Michal Vasko22448d32016-03-16 13:17:29 +01002151 assert(node->schema->nodetype == LYS_LIST);
2152
Michal Vasko53adfc72017-01-06 10:39:10 +01002153 /* is the predicate a number? */
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002154 if (((r = parse_schema_json_predicate(predicate, &mod_name, &mod_name_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1)
Michal Vasko53adfc72017-01-06 10:39:10 +01002155 || !strncmp(name, ".", nam_len)) {
2156 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
2157 return -1;
2158 }
2159
2160 if (isdigit(name[0])) {
2161 if (position == atoi(name)) {
2162 /* match */
2163 *parsed += r;
2164 return 0;
2165 } else {
2166 /* not a match */
2167 return 1;
2168 }
2169 }
2170
2171 if (!((struct lys_node_list *)node->schema)->keys_size) {
2172 /* no keys in schema - causes an error later */
2173 return 0;
2174 }
2175
Michal Vaskof29903d2016-04-18 13:13:10 +02002176 key = (struct lyd_node_leaf_list *)node->child;
Michal Vasko53adfc72017-01-06 10:39:10 +01002177 if (!key) {
2178 /* it is not a position, so we need a key for it to be a match */
2179 return 1;
2180 }
2181
2182 /* go through all the keys */
2183 i = 0;
2184 goto check_parsed_values;
2185
2186 for (; i < ((struct lys_node_list *)node->schema)->keys_size; ++i) {
Michal Vasko22448d32016-03-16 13:17:29 +01002187 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002188 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, node_name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002189 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002190 }
2191
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002192 if (((r = parse_schema_json_predicate(predicate, &mod_name, &mod_name_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1)
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002193 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002194 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
Michal Vaskof29903d2016-04-18 13:13:10 +02002195 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002196 }
2197
Michal Vasko53adfc72017-01-06 10:39:10 +01002198check_parsed_values:
Michal Vasko22448d32016-03-16 13:17:29 +01002199 predicate += r;
2200 *parsed += r;
2201
Michal Vaskof29903d2016-04-18 13:13:10 +02002202 if (strncmp(key->schema->name, name, nam_len) || key->schema->name[nam_len]) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002203 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002204 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002205 }
2206
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002207 if (mod_name) {
2208 if (strncmp(lyd_node_module((struct lyd_node *)key)->name, mod_name, mod_name_len)
2209 || lyd_node_module((struct lyd_node *)key)->name[mod_name_len]) {
2210 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
2211 return -1;
2212 }
2213 } else {
2214 if (strcmp(lyd_node_module((struct lyd_node *)key)->name, cur_module->name)) {
2215 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
2216 return -1;
2217 }
2218 }
2219
Michal Vasko9ba34de2016-12-07 12:21:19 +01002220 /* make value canonical */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01002221 if ((key->value_type & LY_TYPE_IDENT)
Michal Vasko6a938d62016-12-21 09:21:30 +01002222 && !strncmp(key->value_str, lyd_node_module(node)->name, strlen(lyd_node_module(node)->name))
2223 && (key->value_str[strlen(lyd_node_module(node)->name)] == ':')) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002224 key_val = key->value_str + strlen(lyd_node_module(node)->name) + 1;
2225 } else {
2226 key_val = key->value_str;
2227 }
2228
Michal Vasko22448d32016-03-16 13:17:29 +01002229 /* value does not match */
Michal Vasko9ba34de2016-12-07 12:21:19 +01002230 if (strncmp(key_val, value, val_len) || key_val[val_len]) {
Michal Vasko22448d32016-03-16 13:17:29 +01002231 return 1;
2232 }
Michal Vaskof29903d2016-04-18 13:13:10 +02002233
2234 key = (struct lyd_node_leaf_list *)key->next;
Michal Vasko22448d32016-03-16 13:17:29 +01002235 }
2236
2237 if (has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002238 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko22448d32016-03-16 13:17:29 +01002239 return -1;
2240 }
2241
2242 return 0;
2243}
2244
Radek Krejci45826012016-08-24 15:07:57 +02002245/**
2246 * @brief get the closest parent of the node (or the node itself) identified by the nodeid (path)
2247 *
2248 * @param[in] nodeid Node data path to find
2249 * @param[in] llist_value If the \p nodeid identifies leaf-list, this is expected value of the leaf-list instance.
2250 * @param[in] options Bitmask of options flags, see @ref pathoptions.
2251 * @param[out] parsed Number of characters processed in \p id
2252 * @return The closes parent (or the node itself) from the path
2253 */
Michal Vasko22448d32016-03-16 13:17:29 +01002254struct lyd_node *
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002255resolve_partial_json_data_nodeid(const char *nodeid, const char *llist_value, struct lyd_node *start, int options,
2256 int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002257{
Michal Vasko10728b52016-04-07 14:26:29 +02002258 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko9ba34de2016-12-07 12:21:19 +01002259 const char *id, *mod_name, *name, *pred_name, *data_val;
Michal Vasko58c2aab2017-01-05 10:02:05 +01002260 int r, ret, mod_name_len, nam_len, is_relative = -1, list_instance_position;
Michal Vasko9ba34de2016-12-07 12:21:19 +01002261 int has_predicate, last_parsed, llval_len, pred_name_len, last_has_pred;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002262 struct lyd_node *sibling, *last_match = NULL;
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002263 struct lyd_node_leaf_list *llist;
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002264 const struct lys_module *prefix_mod, *cur_module;
Michal Vasko22448d32016-03-16 13:17:29 +01002265 struct ly_ctx *ctx;
2266
2267 assert(nodeid && start && parsed);
2268
2269 ctx = start->schema->module->ctx;
2270 id = nodeid;
2271
2272 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 +01002273 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002274 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002275 return NULL;
2276 }
2277 id += r;
2278 /* add it to parsed only after the data node was actually found */
2279 last_parsed = r;
2280
2281 if (is_relative) {
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002282 cur_module = lyd_node_module(start);
Michal Vasko22448d32016-03-16 13:17:29 +01002283 start = start->child;
2284 } else {
2285 for (; start->parent; start = start->parent);
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002286 cur_module = lyd_node_module(start);
Michal Vasko22448d32016-03-16 13:17:29 +01002287 }
2288
2289 while (1) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002290 list_instance_position = 0;
2291
Michal Vasko22448d32016-03-16 13:17:29 +01002292 LY_TREE_FOR(start, sibling) {
Michal Vasko945b96b2016-10-18 11:49:12 +02002293 /* RPC/action data check, return simply invalid argument, because the data tree is invalid */
Michal Vasko2411b942016-03-23 13:50:03 +01002294 if (lys_parent(sibling->schema)) {
2295 if (options & LYD_PATH_OPT_OUTPUT) {
2296 if (lys_parent(sibling->schema)->nodetype == LYS_INPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002297 LOGERR(LY_EINVAL, "Provided data tree includes some RPC input nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002298 *parsed = -1;
2299 return NULL;
2300 }
2301 } else {
2302 if (lys_parent(sibling->schema)->nodetype == LYS_OUTPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002303 LOGERR(LY_EINVAL, "Provided data tree includes some RPC output nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002304 *parsed = -1;
2305 return NULL;
2306 }
2307 }
2308 }
2309
Michal Vasko22448d32016-03-16 13:17:29 +01002310 /* name match */
2311 if (!strncmp(name, sibling->schema->name, nam_len) && !sibling->schema->name[nam_len]) {
2312
2313 /* module check */
2314 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002315 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko22448d32016-03-16 13:17:29 +01002316 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002317 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002318 return NULL;
2319 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002320
2321 if (ly_buf_used && module_name[0]) {
2322 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2323 }
2324 ly_buf_used++;
2325
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002326 memmove(module_name, mod_name, mod_name_len);
Michal Vasko22448d32016-03-16 13:17:29 +01002327 module_name[mod_name_len] = '\0';
2328 /* will also find an augment module */
2329 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002330
2331 if (buf_backup) {
2332 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002333 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002334 free(buf_backup);
2335 buf_backup = NULL;
2336 }
2337 ly_buf_used--;
2338
Michal Vasko22448d32016-03-16 13:17:29 +01002339 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002340 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2341 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2342 free(str);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002343 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002344 return NULL;
2345 }
2346 } else {
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002347 prefix_mod = cur_module;
Michal Vasko22448d32016-03-16 13:17:29 +01002348 }
Michal Vasko1adc7242016-11-16 11:05:28 +01002349 if (prefix_mod != lyd_node_module(sibling)) {
Michal Vasko22448d32016-03-16 13:17:29 +01002350 continue;
2351 }
2352
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002353 /* leaf-list, did we find it with the correct value or not? */
Michal Vasko22448d32016-03-16 13:17:29 +01002354 if (sibling->schema->nodetype == LYS_LEAFLIST) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002355 llist = (struct lyd_node_leaf_list *)sibling;
2356
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002357 last_has_pred = 0;
Michal Vaskof0a50972016-10-19 11:33:55 +02002358 if (has_predicate) {
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002359 if ((r = parse_schema_json_predicate(id, NULL, NULL, &pred_name, &pred_name_len, &llist_value,
2360 &llval_len, &last_has_pred)) < 1) {
Michal Vaskof0a50972016-10-19 11:33:55 +02002361 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2362 *parsed = -1;
2363 return NULL;
2364 }
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002365 if ((pred_name[0] != '.') || (pred_name_len != 1)) {
2366 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[1], id + 1);
2367 *parsed = -1;
2368 return NULL;
2369 }
Michal Vaskof0a50972016-10-19 11:33:55 +02002370 } else {
2371 r = 0;
2372 if (llist_value) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002373 llval_len = strlen(llist_value);
Michal Vaskof0a50972016-10-19 11:33:55 +02002374 }
2375 }
2376
Michal Vasko9ba34de2016-12-07 12:21:19 +01002377 /* make value canonical */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01002378 if ((llist->value_type & LY_TYPE_IDENT)
Michal Vasko6a938d62016-12-21 09:21:30 +01002379 && !strncmp(llist->value_str, lyd_node_module(sibling)->name, strlen(lyd_node_module(sibling)->name))
2380 && (llist->value_str[strlen(lyd_node_module(sibling)->name)] == ':')) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002381 data_val = llist->value_str + strlen(lyd_node_module(sibling)->name) + 1;
2382 } else {
2383 data_val = llist->value_str;
2384 }
2385
2386 if ((!llist_value && data_val && data_val[0])
2387 || (llist_value && (strncmp(llist_value, data_val, llval_len) || data_val[llval_len]))) {
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002388 continue;
2389 }
Michal Vasko9ba34de2016-12-07 12:21:19 +01002390
Michal Vaskof0a50972016-10-19 11:33:55 +02002391 id += r;
2392 last_parsed += r;
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002393 has_predicate = last_has_pred;
Michal Vaskof0a50972016-10-19 11:33:55 +02002394
Radek Krejci45826012016-08-24 15:07:57 +02002395 } else if (sibling->schema->nodetype == LYS_LIST) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002396 /* 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 +01002397 if (!has_predicate) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002398 /* none match */
2399 return last_match;
Michal Vasko22448d32016-03-16 13:17:29 +01002400 }
Michal Vasko58c2aab2017-01-05 10:02:05 +01002401
2402 ++list_instance_position;
2403 r = 0;
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002404 ret = resolve_partial_json_data_list_predicate(id, name, sibling, list_instance_position, cur_module, &r);
Michal Vasko22448d32016-03-16 13:17:29 +01002405 if (ret == -1) {
Michal Vasko238bd2f2016-03-23 09:39:01 +01002406 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002407 return NULL;
2408 } else if (ret == 1) {
2409 /* this list instance does not match */
2410 continue;
2411 }
2412 id += r;
2413 last_parsed += r;
2414 }
2415
2416 *parsed += last_parsed;
2417
2418 /* the result node? */
2419 if (!id[0]) {
2420 return sibling;
2421 }
2422
2423 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002424 if (sibling->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002425 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002426 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002427 return NULL;
2428 }
Michal Vaskoc6c52cf2016-03-29 11:53:04 +02002429 last_match = sibling;
Michal Vasko22448d32016-03-16 13:17:29 +01002430 start = sibling->child;
Michal Vasko22448d32016-03-16 13:17:29 +01002431 break;
2432 }
2433 }
2434
2435 /* no match, return last match */
2436 if (!sibling) {
2437 return last_match;
2438 }
2439
2440 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 +01002441 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002442 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002443 return NULL;
2444 }
2445 id += r;
2446 last_parsed = r;
2447 }
2448
2449 /* cannot get here */
2450 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002451 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002452 return NULL;
2453}
2454
Michal Vasko3edeaf72016-02-11 13:17:43 +01002455/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02002456 * @brief Resolves length or range intervals. Does not log.
Michal Vaskoaeb51802016-04-11 10:58:47 +02002457 * Syntax is assumed to be correct, *ret MUST be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002458 *
Michal Vaskoaeb51802016-04-11 10:58:47 +02002459 * @param[in] str_restr Restriction as a string.
2460 * @param[in] type Type of the restriction.
2461 * @param[out] ret Final interval structure that starts with
2462 * the interval of the initial type, continues with intervals
2463 * of any superior types derived from the initial one, and
2464 * finishes with intervals from our \p type.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002465 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002466 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002467 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002468int
Michal Vaskoaeb51802016-04-11 10:58:47 +02002469resolve_len_ran_interval(const char *str_restr, struct lys_type *type, struct len_ran_intv **ret)
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002470{
2471 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002472 int kind;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002473 int64_t local_smin, local_smax, local_fmin, local_fmax;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002474 uint64_t local_umin, local_umax;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002475 uint8_t local_fdig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002476 const char *seg_ptr, *ptr;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002477 struct len_ran_intv *local_intv = NULL, *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002478
2479 switch (type->base) {
2480 case LY_TYPE_BINARY:
2481 kind = 0;
2482 local_umin = 0;
2483 local_umax = 18446744073709551615UL;
2484
2485 if (!str_restr && type->info.binary.length) {
2486 str_restr = type->info.binary.length->expr;
2487 }
2488 break;
2489 case LY_TYPE_DEC64:
2490 kind = 2;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002491 local_fmin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2492 local_fmax = __INT64_C(9223372036854775807);
2493 local_fdig = type->info.dec64.dig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002494
2495 if (!str_restr && type->info.dec64.range) {
2496 str_restr = type->info.dec64.range->expr;
2497 }
2498 break;
2499 case LY_TYPE_INT8:
2500 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002501 local_smin = __INT64_C(-128);
2502 local_smax = __INT64_C(127);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002503
2504 if (!str_restr && type->info.num.range) {
2505 str_restr = type->info.num.range->expr;
2506 }
2507 break;
2508 case LY_TYPE_INT16:
2509 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002510 local_smin = __INT64_C(-32768);
2511 local_smax = __INT64_C(32767);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002512
2513 if (!str_restr && type->info.num.range) {
2514 str_restr = type->info.num.range->expr;
2515 }
2516 break;
2517 case LY_TYPE_INT32:
2518 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002519 local_smin = __INT64_C(-2147483648);
2520 local_smax = __INT64_C(2147483647);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002521
2522 if (!str_restr && type->info.num.range) {
2523 str_restr = type->info.num.range->expr;
2524 }
2525 break;
2526 case LY_TYPE_INT64:
2527 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002528 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2529 local_smax = __INT64_C(9223372036854775807);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002530
2531 if (!str_restr && type->info.num.range) {
2532 str_restr = type->info.num.range->expr;
2533 }
2534 break;
2535 case LY_TYPE_UINT8:
2536 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002537 local_umin = __UINT64_C(0);
2538 local_umax = __UINT64_C(255);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002539
2540 if (!str_restr && type->info.num.range) {
2541 str_restr = type->info.num.range->expr;
2542 }
2543 break;
2544 case LY_TYPE_UINT16:
2545 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002546 local_umin = __UINT64_C(0);
2547 local_umax = __UINT64_C(65535);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002548
2549 if (!str_restr && type->info.num.range) {
2550 str_restr = type->info.num.range->expr;
2551 }
2552 break;
2553 case LY_TYPE_UINT32:
2554 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002555 local_umin = __UINT64_C(0);
2556 local_umax = __UINT64_C(4294967295);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002557
2558 if (!str_restr && type->info.num.range) {
2559 str_restr = type->info.num.range->expr;
2560 }
2561 break;
2562 case LY_TYPE_UINT64:
2563 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002564 local_umin = __UINT64_C(0);
2565 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002566
2567 if (!str_restr && type->info.num.range) {
2568 str_restr = type->info.num.range->expr;
2569 }
2570 break;
2571 case LY_TYPE_STRING:
2572 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002573 local_umin = __UINT64_C(0);
2574 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002575
2576 if (!str_restr && type->info.str.length) {
2577 str_restr = type->info.str.length->expr;
2578 }
2579 break;
2580 default:
2581 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002582 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002583 }
2584
2585 /* process superior types */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002586 if (type->der) {
2587 if (resolve_len_ran_interval(NULL, &type->der->type, &intv)) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002588 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002589 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02002590 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002591 assert(!intv || (intv->kind == kind));
2592 }
2593
2594 if (!str_restr) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002595 /* we do not have any restriction, return superior ones */
2596 *ret = intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002597 return EXIT_SUCCESS;
2598 }
2599
2600 /* adjust local min and max */
2601 if (intv) {
2602 tmp_intv = intv;
2603
2604 if (kind == 0) {
2605 local_umin = tmp_intv->value.uval.min;
2606 } else if (kind == 1) {
2607 local_smin = tmp_intv->value.sval.min;
2608 } else if (kind == 2) {
2609 local_fmin = tmp_intv->value.fval.min;
2610 }
2611
2612 while (tmp_intv->next) {
2613 tmp_intv = tmp_intv->next;
2614 }
2615
2616 if (kind == 0) {
2617 local_umax = tmp_intv->value.uval.max;
2618 } else if (kind == 1) {
2619 local_smax = tmp_intv->value.sval.max;
2620 } else if (kind == 2) {
2621 local_fmax = tmp_intv->value.fval.max;
2622 }
2623 }
2624
2625 /* finally parse our restriction */
2626 seg_ptr = str_restr;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002627 tmp_intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002628 while (1) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002629 if (!tmp_local_intv) {
2630 assert(!local_intv);
2631 local_intv = malloc(sizeof *local_intv);
2632 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002633 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002634 tmp_local_intv->next = malloc(sizeof *tmp_local_intv);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002635 tmp_local_intv = tmp_local_intv->next;
2636 }
Radek Krejciaa1303c2017-05-31 13:57:37 +02002637 LY_CHECK_ERR_GOTO(!tmp_local_intv, LOGMEM, error);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002638
2639 tmp_local_intv->kind = kind;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002640 tmp_local_intv->type = type;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002641 tmp_local_intv->next = NULL;
2642
2643 /* min */
2644 ptr = seg_ptr;
2645 while (isspace(ptr[0])) {
2646 ++ptr;
2647 }
2648 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2649 if (kind == 0) {
Radek Krejci25894412017-07-11 10:53:16 +02002650 tmp_local_intv->value.uval.min = strtoll(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002651 } else if (kind == 1) {
Radek Krejci25894412017-07-11 10:53:16 +02002652 tmp_local_intv->value.sval.min = strtoll(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002653 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002654 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.min)) {
2655 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2656 goto error;
2657 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002658 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002659 } else if (!strncmp(ptr, "min", 3)) {
2660 if (kind == 0) {
2661 tmp_local_intv->value.uval.min = local_umin;
2662 } else if (kind == 1) {
2663 tmp_local_intv->value.sval.min = local_smin;
2664 } else if (kind == 2) {
2665 tmp_local_intv->value.fval.min = local_fmin;
2666 }
2667
2668 ptr += 3;
2669 } else if (!strncmp(ptr, "max", 3)) {
2670 if (kind == 0) {
2671 tmp_local_intv->value.uval.min = local_umax;
2672 } else if (kind == 1) {
2673 tmp_local_intv->value.sval.min = local_smax;
2674 } else if (kind == 2) {
2675 tmp_local_intv->value.fval.min = local_fmax;
2676 }
2677
2678 ptr += 3;
2679 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002680 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002681 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002682 }
2683
2684 while (isspace(ptr[0])) {
2685 ptr++;
2686 }
2687
2688 /* no interval or interval */
2689 if ((ptr[0] == '|') || !ptr[0]) {
2690 if (kind == 0) {
2691 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
2692 } else if (kind == 1) {
2693 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
2694 } else if (kind == 2) {
2695 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
2696 }
2697 } else if (!strncmp(ptr, "..", 2)) {
2698 /* skip ".." */
2699 ptr += 2;
2700 while (isspace(ptr[0])) {
2701 ++ptr;
2702 }
2703
2704 /* max */
2705 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2706 if (kind == 0) {
Radek Krejci25894412017-07-11 10:53:16 +02002707 tmp_local_intv->value.uval.max = strtoll(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002708 } else if (kind == 1) {
Radek Krejci25894412017-07-11 10:53:16 +02002709 tmp_local_intv->value.sval.max = strtoll(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002710 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002711 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.max)) {
2712 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2713 goto error;
2714 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002715 }
2716 } else if (!strncmp(ptr, "max", 3)) {
2717 if (kind == 0) {
2718 tmp_local_intv->value.uval.max = local_umax;
2719 } else if (kind == 1) {
2720 tmp_local_intv->value.sval.max = local_smax;
2721 } else if (kind == 2) {
2722 tmp_local_intv->value.fval.max = local_fmax;
2723 }
2724 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002725 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002726 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002727 }
2728 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002729 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002730 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002731 }
2732
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002733 /* check min and max in correct order*/
2734 if (kind == 0) {
2735 /* current segment */
2736 if (tmp_local_intv->value.uval.min > tmp_local_intv->value.uval.max) {
2737 goto error;
2738 }
2739 if (tmp_local_intv->value.uval.min < local_umin || tmp_local_intv->value.uval.max > local_umax) {
2740 goto error;
2741 }
2742 /* segments sholud be ascending order */
Pavol Vican69f62c92016-08-30 09:06:25 +02002743 if (tmp_intv && (tmp_intv->value.uval.max >= tmp_local_intv->value.uval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002744 goto error;
2745 }
2746 } else if (kind == 1) {
2747 if (tmp_local_intv->value.sval.min > tmp_local_intv->value.sval.max) {
2748 goto error;
2749 }
2750 if (tmp_local_intv->value.sval.min < local_smin || tmp_local_intv->value.sval.max > local_smax) {
2751 goto error;
2752 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002753 if (tmp_intv && (tmp_intv->value.sval.max >= tmp_local_intv->value.sval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002754 goto error;
2755 }
2756 } else if (kind == 2) {
2757 if (tmp_local_intv->value.fval.min > tmp_local_intv->value.fval.max) {
2758 goto error;
2759 }
2760 if (tmp_local_intv->value.fval.min < local_fmin || tmp_local_intv->value.fval.max > local_fmax) {
2761 goto error;
2762 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002763 if (tmp_intv && (tmp_intv->value.fval.max >= tmp_local_intv->value.fval.min)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002764 /* fraction-digits value is always the same (it cannot be changed in derived types) */
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002765 goto error;
2766 }
2767 }
2768
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002769 /* next segment (next OR) */
2770 seg_ptr = strchr(seg_ptr, '|');
2771 if (!seg_ptr) {
2772 break;
2773 }
2774 seg_ptr++;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002775 tmp_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002776 }
2777
2778 /* check local restrictions against superior ones */
2779 if (intv) {
2780 tmp_intv = intv;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002781 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002782
2783 while (tmp_local_intv && tmp_intv) {
2784 /* reuse local variables */
2785 if (kind == 0) {
2786 local_umin = tmp_local_intv->value.uval.min;
2787 local_umax = tmp_local_intv->value.uval.max;
2788
2789 /* it must be in this interval */
2790 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
2791 /* this interval is covered, next one */
2792 if (local_umax <= tmp_intv->value.uval.max) {
2793 tmp_local_intv = tmp_local_intv->next;
2794 continue;
2795 /* ascending order of restrictions -> fail */
2796 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002797 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002798 }
2799 }
2800 } else if (kind == 1) {
2801 local_smin = tmp_local_intv->value.sval.min;
2802 local_smax = tmp_local_intv->value.sval.max;
2803
2804 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
2805 if (local_smax <= tmp_intv->value.sval.max) {
2806 tmp_local_intv = tmp_local_intv->next;
2807 continue;
2808 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002809 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002810 }
2811 }
2812 } else if (kind == 2) {
2813 local_fmin = tmp_local_intv->value.fval.min;
2814 local_fmax = tmp_local_intv->value.fval.max;
2815
Michal Vasko4d1f0482016-09-19 14:35:06 +02002816 if ((dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.min, local_fdig) > -1)
Pavol Vican3c8ee2b2016-09-29 13:18:13 +02002817 && (dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002818 if (dec64cmp(local_fmax, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002819 tmp_local_intv = tmp_local_intv->next;
2820 continue;
2821 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002822 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002823 }
2824 }
2825 }
2826
2827 tmp_intv = tmp_intv->next;
2828 }
2829
2830 /* some interval left uncovered -> fail */
2831 if (tmp_local_intv) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002832 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002833 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002834 }
2835
Michal Vaskoaeb51802016-04-11 10:58:47 +02002836 /* append the local intervals to all the intervals of the superior types, return it all */
2837 if (intv) {
2838 for (tmp_intv = intv; tmp_intv->next; tmp_intv = tmp_intv->next);
2839 tmp_intv->next = local_intv;
2840 } else {
2841 intv = local_intv;
2842 }
2843 *ret = intv;
2844
2845 return EXIT_SUCCESS;
2846
2847error:
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002848 while (intv) {
2849 tmp_intv = intv->next;
2850 free(intv);
2851 intv = tmp_intv;
2852 }
Michal Vaskoaeb51802016-04-11 10:58:47 +02002853 while (local_intv) {
2854 tmp_local_intv = local_intv->next;
2855 free(local_intv);
2856 local_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002857 }
2858
Michal Vaskoaeb51802016-04-11 10:58:47 +02002859 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002860}
2861
Michal Vasko730dfdf2015-08-11 14:48:05 +02002862/**
Michal Vasko01c6fd22016-05-20 11:43:05 +02002863 * @brief Resolve a typedef, return only resolved typedefs if derived. If leafref, it must be
2864 * resolved for this function to return it. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002865 *
2866 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02002867 * @param[in] mod_name Typedef name module name.
2868 * @param[in] module Main module.
2869 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002870 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002871 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002872 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002873 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002874int
Michal Vasko1e62a092015-12-01 12:27:20 +01002875resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
2876 const struct lys_node *parent, struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002877{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002878 int i, j;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002879 struct lys_tpdf *tpdf, *match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002880 int tpdf_size;
2881
Michal Vasko1dca6882015-10-22 14:29:42 +02002882 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002883 /* no prefix, try built-in types */
2884 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
Radek Krejcia68ddeb2017-02-24 12:49:44 +01002885 if (!strcmp(ly_types[i]->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002886 if (ret) {
Radek Krejcia68ddeb2017-02-24 12:49:44 +01002887 *ret = ly_types[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002888 }
2889 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002890 }
2891 }
2892 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02002893 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002894 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02002895 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002896 }
2897 }
2898
Michal Vasko1dca6882015-10-22 14:29:42 +02002899 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002900 /* search in local typedefs */
2901 while (parent) {
2902 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02002903 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02002904 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
2905 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002906 break;
2907
Radek Krejci76512572015-08-04 09:47:08 +02002908 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02002909 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
2910 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002911 break;
2912
Radek Krejci76512572015-08-04 09:47:08 +02002913 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02002914 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
2915 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002916 break;
2917
Radek Krejci76512572015-08-04 09:47:08 +02002918 case LYS_RPC:
Michal Vasko44fb6382016-06-29 11:12:27 +02002919 case LYS_ACTION:
2920 tpdf_size = ((struct lys_node_rpc_action *)parent)->tpdf_size;
2921 tpdf = ((struct lys_node_rpc_action *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002922 break;
2923
Radek Krejci76512572015-08-04 09:47:08 +02002924 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02002925 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
2926 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002927 break;
2928
Radek Krejci76512572015-08-04 09:47:08 +02002929 case LYS_INPUT:
2930 case LYS_OUTPUT:
Michal Vasko44fb6382016-06-29 11:12:27 +02002931 tpdf_size = ((struct lys_node_inout *)parent)->tpdf_size;
2932 tpdf = ((struct lys_node_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002933 break;
2934
2935 default:
Michal Vaskodcf98e62016-05-05 17:53:53 +02002936 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002937 continue;
2938 }
2939
2940 for (i = 0; i < tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002941 if (!strcmp(tpdf[i].name, name) && tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002942 match = &tpdf[i];
2943 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002944 }
2945 }
2946
Michal Vaskodcf98e62016-05-05 17:53:53 +02002947 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002948 }
Radek Krejcic071c542016-01-27 14:57:51 +01002949 } else {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002950 /* get module where to search */
Michal Vaskob6729c62015-10-21 12:09:47 +02002951 module = lys_get_import_module(module, NULL, 0, mod_name, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02002952 if (!module) {
2953 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002954 }
2955 }
2956
2957 /* search in top level typedefs */
2958 for (i = 0; i < module->tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002959 if (!strcmp(module->tpdf[i].name, name) && module->tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002960 match = &module->tpdf[i];
2961 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002962 }
2963 }
2964
2965 /* search in submodules */
Radek Krejcic071c542016-01-27 14:57:51 +01002966 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002967 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002968 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 +02002969 match = &module->inc[i].submodule->tpdf[j];
2970 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002971 }
2972 }
2973 }
2974
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002975 return EXIT_FAILURE;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002976
2977check_leafref:
2978 if (ret) {
2979 *ret = match;
2980 }
2981 if (match->type.base == LY_TYPE_LEAFREF) {
2982 while (!match->type.info.lref.path) {
2983 match = match->type.der;
2984 assert(match);
2985 }
Michal Vasko01c6fd22016-05-20 11:43:05 +02002986 }
2987 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002988}
2989
Michal Vasko1dca6882015-10-22 14:29:42 +02002990/**
2991 * @brief Check the default \p value of the \p type. Logs directly.
2992 *
2993 * @param[in] type Type definition to use.
2994 * @param[in] value Default value to check.
Michal Vasko56826402016-03-02 11:11:37 +01002995 * @param[in] module Type module.
Michal Vasko1dca6882015-10-22 14:29:42 +02002996 *
2997 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
2998 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002999static int
Radek Krejciab08f0f2017-03-09 16:37:15 +01003000check_default(struct lys_type *type, const char **value, struct lys_module *module, int tpdf)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003001{
Radek Krejcibad2f172016-08-02 11:04:15 +02003002 struct lys_tpdf *base_tpdf = NULL;
Michal Vasko1dca6882015-10-22 14:29:42 +02003003 struct lyd_node_leaf_list node;
Radek Krejci51673202016-11-01 17:00:32 +01003004 const char *dflt = NULL;
Radek Krejci9e6af732017-04-27 14:40:25 +02003005 char *s;
Radek Krejci37b756f2016-01-18 10:15:03 +01003006 int ret = EXIT_SUCCESS;
Michal Vasko1dca6882015-10-22 14:29:42 +02003007
Radek Krejci51673202016-11-01 17:00:32 +01003008 assert(value);
3009
Radek Krejcic13db382016-08-16 10:52:42 +02003010 if (type->base <= LY_TYPE_DER) {
Michal Vasko478c4652016-07-21 12:55:01 +02003011 /* the type was not resolved yet, nothing to do for now */
3012 return EXIT_FAILURE;
Radek Krejci9e6af732017-04-27 14:40:25 +02003013 } else if (!tpdf && !lys_main_module(module)->implemented) {
3014 /* do not check defaults in not implemented module's data */
3015 return EXIT_SUCCESS;
3016 } else if (tpdf && !lys_main_module(module)->implemented && type->base == LY_TYPE_IDENT) {
3017 /* identityrefs are checked when instantiated in data instead of typedef,
3018 * but in typedef the value has to be modified to include the prefix */
3019 if (*value) {
3020 if (strchr(*value, ':')) {
3021 dflt = transform_schema2json(module, *value);
3022 } else {
3023 /* default prefix of the module where the typedef is defined */
3024 asprintf(&s, "%s:%s", lys_main_module(module)->name, *value);
3025 dflt = lydict_insert_zc(module->ctx, s);
3026 }
3027 lydict_remove(module->ctx, *value);
3028 *value = dflt;
3029 }
3030 return EXIT_SUCCESS;
Radek Krejciab08f0f2017-03-09 16:37:15 +01003031 } else if (type->base == LY_TYPE_LEAFREF && tpdf) {
3032 /* leafref in typedef cannot be checked */
3033 return EXIT_SUCCESS;
Michal Vasko478c4652016-07-21 12:55:01 +02003034 }
3035
Radek Krejci51673202016-11-01 17:00:32 +01003036 dflt = *value;
3037 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003038 /* we do not have a new default value, so is there any to check even, in some base type? */
3039 for (base_tpdf = type->der; base_tpdf->type.der; base_tpdf = base_tpdf->type.der) {
3040 if (base_tpdf->dflt) {
Radek Krejci51673202016-11-01 17:00:32 +01003041 dflt = base_tpdf->dflt;
Michal Vasko478c4652016-07-21 12:55:01 +02003042 break;
3043 }
3044 }
3045
Radek Krejci51673202016-11-01 17:00:32 +01003046 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003047 /* no default value, nothing to check, all is well */
3048 return EXIT_SUCCESS;
3049 }
3050
3051 /* 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)? */
3052 switch (type->base) {
Michal Vasko478c4652016-07-21 12:55:01 +02003053 case LY_TYPE_IDENT:
Radek Krejci9e6af732017-04-27 14:40:25 +02003054 if (lys_main_module(base_tpdf->type.parent->module)->implemented) {
3055 return EXIT_SUCCESS;
3056 } else {
3057 /* check the default value from typedef, but use also the typedef's module
3058 * due to possible searching in imported modules which is expected in
3059 * typedef's module instead of module where the typedef is used */
3060 module = base_tpdf->module;
3061 }
3062 break;
Michal Vasko478c4652016-07-21 12:55:01 +02003063 case LY_TYPE_INST:
3064 case LY_TYPE_LEAFREF:
3065 case LY_TYPE_BOOL:
3066 case LY_TYPE_EMPTY:
3067 /* these have no restrictions, so we would do the exact same work as the unres in the base typedef */
3068 return EXIT_SUCCESS;
Radek Krejcibad2f172016-08-02 11:04:15 +02003069 case LY_TYPE_BITS:
3070 /* the default value must match the restricted list of values, if the type was restricted */
3071 if (type->info.bits.count) {
3072 break;
3073 }
3074 return EXIT_SUCCESS;
3075 case LY_TYPE_ENUM:
3076 /* the default value must match the restricted list of values, if the type was restricted */
3077 if (type->info.enums.count) {
3078 break;
3079 }
3080 return EXIT_SUCCESS;
Michal Vasko478c4652016-07-21 12:55:01 +02003081 case LY_TYPE_DEC64:
3082 if (type->info.dec64.range) {
3083 break;
3084 }
3085 return EXIT_SUCCESS;
3086 case LY_TYPE_BINARY:
3087 if (type->info.binary.length) {
3088 break;
3089 }
3090 return EXIT_SUCCESS;
3091 case LY_TYPE_INT8:
3092 case LY_TYPE_INT16:
3093 case LY_TYPE_INT32:
3094 case LY_TYPE_INT64:
3095 case LY_TYPE_UINT8:
3096 case LY_TYPE_UINT16:
3097 case LY_TYPE_UINT32:
3098 case LY_TYPE_UINT64:
3099 if (type->info.num.range) {
3100 break;
3101 }
3102 return EXIT_SUCCESS;
3103 case LY_TYPE_STRING:
3104 if (type->info.str.length || type->info.str.patterns) {
3105 break;
3106 }
3107 return EXIT_SUCCESS;
3108 case LY_TYPE_UNION:
3109 /* way too much trouble learning whether we need to check the default again, so just do it */
3110 break;
3111 default:
3112 LOGINT;
3113 return -1;
3114 }
Radek Krejci55a161c2016-09-05 17:13:25 +02003115 } else if (type->base == LY_TYPE_EMPTY) {
3116 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "default", type->parent->name);
3117 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"empty\" data type cannot have a default value.");
3118 return -1;
Michal Vasko478c4652016-07-21 12:55:01 +02003119 }
3120
Michal Vasko1dca6882015-10-22 14:29:42 +02003121 /* dummy leaf */
Radek Krejci4fe36bd2016-03-17 16:47:16 +01003122 memset(&node, 0, sizeof node);
Radek Krejci51673202016-11-01 17:00:32 +01003123 node.value_str = dflt;
Michal Vasko1dca6882015-10-22 14:29:42 +02003124 node.value_type = type->base;
Radek Krejci37b756f2016-01-18 10:15:03 +01003125 node.schema = calloc(1, sizeof (struct lys_node_leaf));
Radek Krejciaa1303c2017-05-31 13:57:37 +02003126 LY_CHECK_ERR_RETURN(!node.schema, LOGMEM, -1);
Radek Krejcibad2f172016-08-02 11:04:15 +02003127 node.schema->name = strdup("fake-default");
Radek Krejciaa1303c2017-05-31 13:57:37 +02003128 LY_CHECK_ERR_RETURN(!node.schema->name, LOGMEM; free(node.schema), -1);
Michal Vasko56826402016-03-02 11:11:37 +01003129 node.schema->module = module;
Radek Krejci37b756f2016-01-18 10:15:03 +01003130 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
Michal Vasko1dca6882015-10-22 14:29:42 +02003131
Radek Krejci37b756f2016-01-18 10:15:03 +01003132 if (type->base == LY_TYPE_LEAFREF) {
Michal Vasko1dca6882015-10-22 14:29:42 +02003133 if (!type->info.lref.target) {
3134 ret = EXIT_FAILURE;
3135 goto finish;
3136 }
Radek Krejciab08f0f2017-03-09 16:37:15 +01003137 ret = check_default(&type->info.lref.target->type, &dflt, module, 0);
Radek Krejci51673202016-11-01 17:00:32 +01003138 if (!ret) {
3139 /* adopt possibly changed default value to its canonical form */
3140 if (*value) {
3141 *value = dflt;
3142 }
3143 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003144 } else {
Radek Krejcia571d942017-02-24 09:26:49 +01003145 if (!lyp_parse_value(&((struct lys_node_leaf *)node.schema)->type, &node.value_str, NULL, &node, NULL, 1, 1)) {
Radek Krejci5dca5932016-11-04 14:30:47 +01003146 /* possible forward reference */
3147 ret = 1;
Radek Krejcibad2f172016-08-02 11:04:15 +02003148 if (base_tpdf) {
Radek Krejci9ad23f42016-10-31 15:46:52 +01003149 /* default value is defined in some base typedef */
Radek Krejcibad2f172016-08-02 11:04:15 +02003150 if ((type->base == LY_TYPE_BITS && type->der->type.der) ||
3151 (type->base == LY_TYPE_ENUM && type->der->type.der)) {
3152 /* we have refined bits/enums */
3153 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
3154 "Invalid value \"%s\" of the default statement inherited to \"%s\" from \"%s\" base type.",
Radek Krejci51673202016-11-01 17:00:32 +01003155 dflt, type->parent->name, base_tpdf->name);
Radek Krejcibad2f172016-08-02 11:04:15 +02003156 }
3157 }
Radek Krejci51673202016-11-01 17:00:32 +01003158 } else {
3159 /* success - adopt canonical form from the node into the default value */
3160 if (dflt != node.value_str) {
3161 /* this can happen only if we have non-inherited default value,
3162 * inherited default values are already in canonical form */
3163 assert(dflt == *value);
3164 *value = node.value_str;
3165 }
Michal Vasko3767fb22016-07-21 12:10:57 +02003166 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003167 }
3168
3169finish:
3170 if (node.value_type == LY_TYPE_BITS) {
3171 free(node.value.bit);
3172 }
3173 free((char *)node.schema->name);
3174 free(node.schema);
3175
3176 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003177}
3178
Michal Vasko730dfdf2015-08-11 14:48:05 +02003179/**
3180 * @brief Check a key for mandatory attributes. Logs directly.
3181 *
3182 * @param[in] key The key to check.
3183 * @param[in] flags What flags to check.
3184 * @param[in] list The list of all the keys.
3185 * @param[in] index Index of the key in the key list.
3186 * @param[in] name The name of the keys.
3187 * @param[in] len The name length.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003188 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003189 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003190 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003191static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003192check_key(struct lys_node_list *list, int index, const char *name, int len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003193{
Radek Krejciadb57612016-02-16 13:34:34 +01003194 struct lys_node_leaf *key = list->keys[index];
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003195 char *dup = NULL;
3196 int j;
3197
3198 /* existence */
3199 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02003200 if (name[len] != '\0') {
3201 dup = strdup(name);
Radek Krejciaa1303c2017-05-31 13:57:37 +02003202 LY_CHECK_ERR_RETURN(!dup, LOGMEM, -1);
Michal Vaskof02e3742015-08-05 16:27:02 +02003203 dup[len] = '\0';
3204 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003205 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003206 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, list, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003207 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003208 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003209 }
3210
3211 /* uniqueness */
3212 for (j = index - 1; j >= 0; j--) {
Radek Krejciadb57612016-02-16 13:34:34 +01003213 if (key == list->keys[j]) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003214 LOGVAL(LYE_KEY_DUP, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003215 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003216 }
3217 }
3218
3219 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02003220 if (key->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003221 LOGVAL(LYE_KEY_NLEAF, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003222 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003223 }
3224
3225 /* type of the leaf is not built-in empty */
Radek Krejcic3738db2016-09-15 15:51:21 +02003226 if (key->type.base == LY_TYPE_EMPTY && key->module->version < 2) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003227 LOGVAL(LYE_KEY_TYPE, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003228 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003229 }
3230
3231 /* config attribute is the same as of the list */
Radek Krejci5c08a992016-11-02 13:30:04 +01003232 if ((key->flags & LYS_CONFIG_MASK) && (list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003233 LOGVAL(LYE_KEY_CONFIG, 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
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003237 /* key is not placed from augment */
3238 if (key->parent->nodetype == LYS_AUGMENT) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003239 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, key, key->name);
Michal Vasko51e5c582017-01-19 14:16:39 +01003240 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Key inserted from augment.");
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003241 return -1;
3242 }
3243
Radek Krejci3f21ada2016-08-01 13:34:31 +02003244 /* key is not when/if-feature -conditional */
3245 j = 0;
3246 if (key->when || (key->iffeature_size && (j = 1))) {
3247 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, key, j ? "if-feature" : "when", "leaf");
Michal Vasko51e5c582017-01-19 14:16:39 +01003248 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Key definition cannot depend on a \"%s\" condition.",
Radek Krejci3f21ada2016-08-01 13:34:31 +02003249 j ? "if-feature" : "when");
Radek Krejci581ce772015-11-10 17:22:40 +01003250 return -1;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003251 }
3252
Michal Vasko0b85aa82016-03-07 14:37:43 +01003253 return EXIT_SUCCESS;
Michal Vasko184521f2015-09-24 13:14:26 +02003254}
Michal Vasko730dfdf2015-08-11 14:48:05 +02003255
3256/**
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003257 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003258 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003259 * @param[in] parent The parent node of the unique structure.
Michal Vasko0b85aa82016-03-07 14:37:43 +01003260 * @param[in] uniq_str_path One path from the unique string.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003261 *
3262 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
3263 */
3264int
Radek Krejcid09d1a52016-08-11 14:05:45 +02003265resolve_unique(struct lys_node *parent, const char *uniq_str_path, uint8_t *trg_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003266{
Radek Krejci581ce772015-11-10 17:22:40 +01003267 int rc;
Michal Vasko1e62a092015-12-01 12:27:20 +01003268 const struct lys_node *leaf = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003269
Michal Vaskodc300b02017-04-07 14:09:20 +02003270 rc = resolve_descendant_schema_nodeid(uniq_str_path, *lys_child(parent, LYS_LEAF), LYS_LEAF, 1, &leaf);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003271 if (rc || !leaf) {
Michal Vasko0b85aa82016-03-07 14:37:43 +01003272 if (rc) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003273 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003274 if (rc > 0) {
Michal Vasko51e5c582017-01-19 14:16:39 +01003275 LOGVAL(LYE_INCHAR, LY_VLOG_PREV, NULL, uniq_str_path[rc - 1], &uniq_str_path[rc - 1]);
Radek Krejcif3c71de2016-04-11 12:45:46 +02003276 } else if (rc == -2) {
Michal Vasko51e5c582017-01-19 14:16:39 +01003277 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Unique argument references list.");
Radek Krejci581ce772015-11-10 17:22:40 +01003278 }
Michal Vasko0b85aa82016-03-07 14:37:43 +01003279 rc = -1;
Michal Vasko0b85aa82016-03-07 14:37:43 +01003280 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01003281 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko51e5c582017-01-19 14:16:39 +01003282 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Target leaf not found.");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003283 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003284 }
Radek Krejci581ce772015-11-10 17:22:40 +01003285 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003286 }
Michal Vasko9bb061b2016-02-12 11:00:19 +01003287 if (leaf->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003288 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko51e5c582017-01-19 14:16:39 +01003289 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Target is not a leaf.");
Radek Krejcid09d1a52016-08-11 14:05:45 +02003290 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003291 }
3292
Radek Krejcicf509982015-12-15 09:22:44 +01003293 /* check status */
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01003294 if (parent->nodetype != LYS_EXT && lyp_check_status(parent->flags, parent->module, parent->name,
3295 leaf->flags, leaf->module, leaf->name, leaf)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003296 return -1;
3297 }
3298
Radek Krejcid09d1a52016-08-11 14:05:45 +02003299 /* check that all unique's targets are of the same config type */
3300 if (*trg_type) {
3301 if (((*trg_type == 1) && (leaf->flags & LYS_CONFIG_R)) || ((*trg_type == 2) && (leaf->flags & LYS_CONFIG_W))) {
3302 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko51e5c582017-01-19 14:16:39 +01003303 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Radek Krejcid09d1a52016-08-11 14:05:45 +02003304 "Leaf \"%s\" referenced in unique statement is config %s, but previous referenced leaf is config %s.",
3305 uniq_str_path, *trg_type == 1 ? "false" : "true", *trg_type == 1 ? "true" : "false");
3306 return -1;
3307 }
3308 } else {
3309 /* first unique */
3310 if (leaf->flags & LYS_CONFIG_W) {
3311 *trg_type = 1;
3312 } else {
3313 *trg_type = 2;
3314 }
3315 }
3316
Radek Krejcica7efb72016-01-18 13:06:01 +01003317 /* set leaf's unique flag */
3318 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
3319
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003320 return EXIT_SUCCESS;
3321
3322error:
3323
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003324 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003325}
3326
Radek Krejci0c0086a2016-03-24 15:20:28 +01003327void
Michal Vasko23b61ec2015-08-19 11:19:50 +02003328unres_data_del(struct unres_data *unres, uint32_t i)
3329{
3330 /* there are items after the one deleted */
3331 if (i+1 < unres->count) {
3332 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02003333 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003334
3335 /* deleting the last item */
3336 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02003337 free(unres->node);
3338 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003339 }
3340
3341 /* if there are no items after and it is not the last one, just move the counter */
3342 --unres->count;
3343}
3344
Michal Vasko0491ab32015-08-19 14:28:29 +02003345/**
3346 * @brief Resolve (find) a data node from a specific module. Does not log.
3347 *
3348 * @param[in] mod Module to search in.
3349 * @param[in] name Name of the data node.
3350 * @param[in] nam_len Length of the name.
3351 * @param[in] start Data node to start the search from.
3352 * @param[in,out] parents Resolved nodes. If there are some parents,
3353 * they are replaced (!!) with the resolvents.
3354 *
Michal Vasko2471e7f2016-04-11 11:00:15 +02003355 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko0491ab32015-08-19 14:28:29 +02003356 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003357static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003358resolve_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 +02003359{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003360 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02003361 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003362 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003363
Michal Vasko23b61ec2015-08-19 11:19:50 +02003364 if (!parents->count) {
3365 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003366 parents->node = malloc(sizeof *parents->node);
Radek Krejciaa1303c2017-05-31 13:57:37 +02003367 LY_CHECK_ERR_RETURN(!parents->node, LOGMEM, -1);
Michal Vaskocf024702015-10-08 15:01:42 +02003368 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003369 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003370 for (i = 0; i < parents->count;) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02003371 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003372 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003373 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003374 continue;
3375 }
3376 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02003377 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vasko39608352017-05-11 10:37:10 +02003378 if (lyd_node_module(node) == mod && !strncmp(node->schema->name, name, nam_len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003379 && node->schema->name[nam_len] == '\0') {
3380 /* matching target */
3381 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02003382 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02003383 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003384 flag = 1;
3385 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02003386 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003387 ++parents->count;
Michal Vasko253035f2015-12-17 16:58:13 +01003388 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
Radek Krejciaa1303c2017-05-31 13:57:37 +02003389 LY_CHECK_ERR_RETURN(!parents->node, LOGMEM, EXIT_FAILURE);
Michal Vaskocf024702015-10-08 15:01:42 +02003390 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003391 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003392 }
3393 }
3394 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003395
3396 if (!flag) {
3397 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003398 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02003399 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003400 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02003401 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003402 }
3403
Michal Vasko0491ab32015-08-19 14:28:29 +02003404 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02003405}
3406
Michal Vaskoe27516a2016-10-10 17:55:31 +00003407static int
Michal Vasko1c007172017-03-10 10:20:44 +01003408resolve_schema_leafref_valid_dep_flag(const struct lys_node *op_node, const struct lys_node *first_node, int abs_path)
Michal Vaskoe27516a2016-10-10 17:55:31 +00003409{
3410 int dep1, dep2;
3411 const struct lys_node *node;
3412
3413 if (lys_parent(op_node)) {
3414 /* inner operation (notif/action) */
3415 if (abs_path) {
3416 return 1;
3417 } else {
3418 /* compare depth of both nodes */
3419 for (dep1 = 0, node = op_node; lys_parent(node); node = lys_parent(node));
3420 for (dep2 = 0, node = first_node; lys_parent(node); node = lys_parent(node));
3421 if ((dep2 > dep1) || ((dep2 == dep1) && (op_node != first_node))) {
3422 return 1;
3423 }
3424 }
3425 } else {
3426 /* top-level operation (notif/rpc) */
3427 if (op_node != first_node) {
3428 return 1;
3429 }
3430 }
3431
3432 return 0;
3433}
3434
Michal Vasko730dfdf2015-08-11 14:48:05 +02003435/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003436 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003437 *
Michal Vaskobb211122015-08-19 14:03:11 +02003438 * @param[in] path Path to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003439 * @param[in] context_node Predicate context node (where the predicate is placed).
3440 * @param[in] parent Path context node (where the path begins/is placed).
Michal Vaskoe27516a2016-10-10 17:55:31 +00003441 * @param[in] op_node Optional node if the leafref is in an operation (action/rpc/notif).
Michal Vasko730dfdf2015-08-11 14:48:05 +02003442 *
Michal Vasko184521f2015-09-24 13:14:26 +02003443 * @return 0 on forward reference, otherwise the number
3444 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003445 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003446 */
Michal Vasko1f76a282015-08-04 16:16:53 +02003447static int
Michal Vasko1c007172017-03-10 10:20:44 +01003448resolve_schema_leafref_predicate(const char *path, const struct lys_node *context_node,
3449 struct lys_node *parent, const struct lys_node *op_node)
Michal Vasko1f76a282015-08-04 16:16:53 +02003450{
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003451 const struct lys_module *trg_mod;
Michal Vasko1e62a092015-12-01 12:27:20 +01003452 const struct lys_node *src_node, *dst_node;
Michal Vasko1f76a282015-08-04 16:16:53 +02003453 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vaskof9b35d92016-10-21 15:19:30 +02003454 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, pke_parsed, parsed = 0;
3455 int has_predicate, dest_parent_times, i, rc, first_iter;
Michal Vasko1f76a282015-08-04 16:16:53 +02003456
3457 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02003458 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02003459 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003460 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003461 return -parsed+i;
3462 }
3463 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003464 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02003465
Michal Vasko58090902015-08-13 14:04:15 +02003466 /* source (must be leaf) */
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003467 if (sour_pref) {
3468 trg_mod = lys_get_import_module(lys_node_module(parent), NULL, 0, sour_pref, sour_pref_len);
3469 } else {
3470 trg_mod = NULL;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003471 }
Michal Vaskobb520442017-05-23 10:55:18 +02003472 rc = lys_getnext_data(trg_mod, context_node, source, sour_len, LYS_LEAF | LYS_LEAFLIST, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003473 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003474 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02003475 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003476 }
3477
3478 /* destination */
Michal Vaskof9b35d92016-10-21 15:19:30 +02003479 dest_parent_times = 0;
3480 pke_parsed = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003481 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3482 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003483 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 +02003484 return -parsed;
3485 }
3486 pke_parsed += i;
3487
Radek Krejciadb57612016-02-16 13:34:34 +01003488 for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
Michal Vaskofbaead72016-10-07 10:54:48 +02003489 /* path is supposed to be evaluated in data tree, so we have to skip
3490 * all schema nodes that cannot be instantiated in data tree */
3491 for (dst_node = lys_parent(dst_node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003492 dst_node && !(dst_node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Michal Vaskofbaead72016-10-07 10:54:48 +02003493 dst_node = lys_parent(dst_node));
3494
Michal Vasko1f76a282015-08-04 16:16:53 +02003495 if (!dst_node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003496 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003497 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003498 }
3499 }
Michal Vaskoe27516a2016-10-10 17:55:31 +00003500 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003501 while (1) {
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003502 if (dest_pref) {
3503 trg_mod = lys_get_import_module(lys_node_module(parent), NULL, 0, dest_pref, dest_pref_len);
3504 } else {
3505 trg_mod = NULL;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003506 }
Michal Vaskobb520442017-05-23 10:55:18 +02003507 rc = lys_getnext_data(trg_mod, dst_node, dest, dest_len, LYS_CONTAINER | LYS_LIST | LYS_LEAF, &dst_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003508 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003509 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003510 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003511 }
3512
Michal Vaskoe27516a2016-10-10 17:55:31 +00003513 if (first_iter) {
Michal Vasko1c007172017-03-10 10:20:44 +01003514 if (resolve_schema_leafref_valid_dep_flag(op_node, dst_node, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01003515 parent->flags |= LYS_LEAFREF_DEP;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003516 }
3517 first_iter = 0;
3518 }
3519
Michal Vasko1f76a282015-08-04 16:16:53 +02003520 if (pke_len == pke_parsed) {
3521 break;
3522 }
3523
Michal Vaskobb520442017-05-23 10:55:18 +02003524 if ((i = parse_path_key_expr(path_key_expr + pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
Michal Vasko1f76a282015-08-04 16:16:53 +02003525 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003526 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent,
Michal Vaskobb520442017-05-23 10:55:18 +02003527 (path_key_expr + pke_parsed)[-i], (path_key_expr + pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003528 return -parsed;
3529 }
3530 pke_parsed += i;
3531 }
3532
3533 /* check source - dest match */
Michal Vasko59ad4582016-09-16 13:15:41 +02003534 if (dst_node->nodetype != src_node->nodetype) {
Michal Vaskobb520442017-05-23 10:55:18 +02003535 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path - parsed);
Michal Vasko51e5c582017-01-19 14:16:39 +01003536 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Destination node is not a %s, but a %s.",
Michal Vasko59ad4582016-09-16 13:15:41 +02003537 strnodetype(src_node->nodetype), strnodetype(dst_node->nodetype));
Michal Vasko184521f2015-09-24 13:14:26 +02003538 return -parsed;
3539 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003540 } while (has_predicate);
3541
3542 return parsed;
3543}
3544
Michal Vasko730dfdf2015-08-11 14:48:05 +02003545/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003546 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003547 *
Michal Vaskobb211122015-08-19 14:03:11 +02003548 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003549 * @param[in] parent_node Parent of the leafref.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003550 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003551 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003552 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003553 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003554static int
Michal Vasko1c007172017-03-10 10:20:44 +01003555resolve_schema_leafref(const char *path, struct lys_node *parent, const struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02003556{
Michal Vaskoe27516a2016-10-10 17:55:31 +00003557 const struct lys_node *node, *op_node = NULL;
Michal Vaskobb520442017-05-23 10:55:18 +02003558 struct lys_node_augment *last_aug;
3559 const struct lys_module *cur_mod;
Radek Krejci990af1f2016-11-09 13:53:36 +01003560 struct lys_module *mod_start;
Michal Vasko1f76a282015-08-04 16:16:53 +02003561 const char *id, *prefix, *name;
3562 int pref_len, nam_len, parent_times, has_predicate;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003563 int i, first_iter, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02003564
Michal Vasko184521f2015-09-24 13:14:26 +02003565 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003566 parent_times = 0;
3567 id = path;
3568
Michal Vasko1c007172017-03-10 10:20:44 +01003569 /* find operation schema we are in */
3570 for (op_node = lys_parent(parent);
3571 op_node && !(op_node->nodetype & (LYS_ACTION | LYS_NOTIF | LYS_RPC));
3572 op_node = lys_parent(op_node));
Michal Vaskoe9914d12016-10-07 14:32:37 +02003573
Radek Krejci990af1f2016-11-09 13:53:36 +01003574 mod_start = lys_node_module(parent);
Michal Vasko1f76a282015-08-04 16:16:53 +02003575 do {
Radek Krejci990af1f2016-11-09 13:53:36 +01003576 if ((i = parse_path_arg(mod_start, id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Michal Vasko1c007172017-03-10 10:20:44 +01003577 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, parent, id[-i], &id[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003578 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003579 }
3580 id += i;
3581
Michal Vaskobb520442017-05-23 10:55:18 +02003582 /* get the current module */
3583 cur_mod = prefix ? lys_get_import_module(mod_start, NULL, 0, prefix, pref_len) : mod_start;
3584 if (!cur_mod) {
3585 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
3586 return EXIT_FAILURE;
3587 }
3588 last_aug = NULL;
3589
Michal Vasko184521f2015-09-24 13:14:26 +02003590 if (first_iter) {
Michal Vasko1f76a282015-08-04 16:16:53 +02003591 if (parent_times == -1) {
Michal Vaskobb520442017-05-23 10:55:18 +02003592 /* use module data */
3593 node = NULL;
Radek Krejci990af1f2016-11-09 13:53:36 +01003594
Michal Vasko1f76a282015-08-04 16:16:53 +02003595 } else if (parent_times > 0) {
Michal Vaskobb520442017-05-23 10:55:18 +02003596 /* we are looking for the right parent */
3597 for (i = 0, node = parent; i < parent_times; i++) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02003598 /* path is supposed to be evaluated in data tree, so we have to skip
3599 * all schema nodes that cannot be instantiated in data tree */
3600 for (node = lys_parent(node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003601 node && !(node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Radek Krejci3a5501d2016-07-18 22:03:34 +02003602 node = lys_parent(node));
3603
Michal Vasko1f76a282015-08-04 16:16:53 +02003604 if (!node) {
Michal Vaskobb520442017-05-23 10:55:18 +02003605 if (i == parent_times - 1) {
3606 /* top-level */
3607 break;
3608 }
3609
3610 /* higher than top-level */
Michal Vaskoe9914d12016-10-07 14:32:37 +02003611 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003612 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003613 }
3614 }
Michal Vaskoe01eca52015-08-13 14:42:02 +02003615 } else {
3616 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003617 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003618 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003619 }
3620
Michal Vaskobb520442017-05-23 10:55:18 +02003621 /* find the next node (either in unconnected augment or as a schema sibling, node is NULL for top-level node -
3622 * - useless to search for that in augments) */
3623 if (!cur_mod->implemented && node) {
3624get_next_augment:
3625 last_aug = lys_getnext_target_aug(last_aug, cur_mod, node);
3626 }
3627
3628 rc = lys_getnext_data(cur_mod, (last_aug ? (struct lys_node *)last_aug : node), name, nam_len, LYS_LIST
3629 | LYS_CONTAINER | LYS_RPC | LYS_ACTION | LYS_NOTIF | LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA, &node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003630 if (rc) {
Michal Vaskobb520442017-05-23 10:55:18 +02003631 if (last_aug) {
3632 goto get_next_augment;
3633 }
Michal Vasko1c007172017-03-10 10:20:44 +01003634 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko7a55bea2016-05-02 14:51:20 +02003635 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003636 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003637
Michal Vaskoe27516a2016-10-10 17:55:31 +00003638 if (first_iter) {
3639 /* set external dependency flag, we can decide based on the first found node */
Michal Vasko1c007172017-03-10 10:20:44 +01003640 if (op_node && parent_times &&
3641 resolve_schema_leafref_valid_dep_flag(op_node, node, (parent_times == -1 ? 1 : 0))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01003642 parent->flags |= LYS_LEAFREF_DEP;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003643 }
3644 first_iter = 0;
3645 }
3646
Michal Vasko1f76a282015-08-04 16:16:53 +02003647 if (has_predicate) {
3648 /* we have predicate, so the current result must be list */
3649 if (node->nodetype != LYS_LIST) {
Michal Vasko1c007172017-03-10 10:20:44 +01003650 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003651 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003652 }
3653
Michal Vasko1c007172017-03-10 10:20:44 +01003654 i = resolve_schema_leafref_predicate(id, node, parent, op_node);
Michal Vaskobb520442017-05-23 10:55:18 +02003655 if (!i) {
3656 return EXIT_FAILURE;
3657 } else if (i < 0) {
3658 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003659 }
3660 id += i;
Michal Vaskof9b35d92016-10-21 15:19:30 +02003661 has_predicate = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003662 }
3663 } while (id[0]);
3664
Michal Vaskoca917682016-07-25 11:00:37 +02003665 /* the target must be leaf or leaf-list (in YANG 1.1 only) */
Radek Krejci2a5a9602016-11-04 10:21:13 +01003666 if ((node->nodetype != LYS_LEAF) && (node->nodetype != LYS_LEAFLIST)) {
Michal Vasko1c007172017-03-10 10:20:44 +01003667 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko51e5c582017-01-19 14:16:39 +01003668 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 +02003669 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02003670 }
3671
Radek Krejcicf509982015-12-15 09:22:44 +01003672 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01003673 if (lyp_check_status(parent->flags, parent->module, parent->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01003674 node->flags, node->module, node->name, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003675 return -1;
3676 }
3677
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003678 if (ret) {
3679 *ret = node;
3680 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02003681
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003682 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02003683}
3684
Michal Vasko730dfdf2015-08-11 14:48:05 +02003685/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003686 * @brief Resolve instance-identifier predicate in JSON data format.
3687 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003688 *
Michal Vaskobb211122015-08-19 14:03:11 +02003689 * @param[in] pred Predicate to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003690 * @param[in,out] node_match Nodes matching the restriction without
3691 * the predicate. Nodes not satisfying
3692 * the predicate are removed.
3693 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003694 * @return Number of characters successfully parsed,
3695 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003696 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003697static int
Michal Vasko1c007172017-03-10 10:20:44 +01003698resolve_instid_predicate(const char *pred, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003699{
Michal Vasko730dfdf2015-08-11 14:48:05 +02003700 /* ... /node[target = value] ... */
Michal Vaskob2f40be2016-09-08 16:03:48 +02003701 struct lyd_node *target;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003702 const char *model, *name, *value;
Michal Vaskob2f40be2016-09-08 16:03:48 +02003703 int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed, pred_iter, k;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003704 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003705
Michal Vasko1f2cc332015-08-19 11:18:32 +02003706 assert(pred && node_match->count);
3707
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003708 idx = -1;
3709 parsed = 0;
3710
Michal Vaskob2f40be2016-09-08 16:03:48 +02003711 pred_iter = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003712 do {
Michal Vaskof39142b2015-10-21 11:40:05 +02003713 if ((i = parse_predicate(pred, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003714 return -parsed+i;
3715 }
3716 parsed += i;
3717 pred += i;
3718
3719 if (isdigit(name[0])) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02003720 /* pos */
3721 assert(!value);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003722 idx = atoi(name);
Michal Vaskob2f40be2016-09-08 16:03:48 +02003723 } else if (name[0] != '.') {
3724 /* list keys */
3725 if (pred_iter < 0) {
3726 pred_iter = 1;
3727 } else {
3728 ++pred_iter;
3729 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003730 }
3731
Michal Vaskof2f28a12016-09-09 12:43:06 +02003732 for (cur_idx = 1, j = 0; j < node_match->count; ++cur_idx) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003733 /* target */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003734 if (name[0] == '.') {
Michal Vaskob2f40be2016-09-08 16:03:48 +02003735 /* leaf-list value */
Michal Vaskocf024702015-10-08 15:01:42 +02003736 if (node_match->node[j]->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003737 goto remove_instid;
3738 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02003739
3740 target = node_match->node[j];
3741 /* check the value */
3742 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
3743 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
3744 goto remove_instid;
3745 }
3746
3747 } else if (!value) {
3748 /* keyless list position */
3749 if ((node_match->node[j]->schema->nodetype != LYS_LIST)
3750 || ((struct lys_node_list *)node_match->node[j]->schema)->keys) {
3751 goto remove_instid;
3752 }
3753
3754 if (idx != cur_idx) {
3755 goto remove_instid;
3756 }
3757
3758 } else {
3759 /* list key value */
Michal Vaskocf024702015-10-08 15:01:42 +02003760 if (node_match->node[j]->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003761 goto remove_instid;
3762 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02003763
3764 /* key module must match the list module */
3765 if (strncmp(node_match->node[j]->schema->module->name, model, mod_len)
3766 || node_match->node[j]->schema->module->name[mod_len]) {
3767 goto remove_instid;
3768 }
3769 /* find the key leaf */
Michal Vasko045182c2016-09-09 12:44:07 +02003770 for (k = 1, target = node_match->node[j]->child; target && (k < pred_iter); k++, target = target->next);
Michal Vaskob2f40be2016-09-08 16:03:48 +02003771 if (!target) {
3772 goto remove_instid;
3773 }
3774 if ((struct lys_node_leaf *)target->schema !=
3775 ((struct lys_node_list *)node_match->node[j]->schema)->keys[pred_iter - 1]) {
3776 goto remove_instid;
3777 }
3778
3779 /* check the value */
3780 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
3781 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
3782 goto remove_instid;
3783 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003784 }
3785
Michal Vaskob2f40be2016-09-08 16:03:48 +02003786 /* instid is ok, continue check with the next one */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003787 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003788 continue;
3789
3790remove_instid:
Michal Vaskob2f40be2016-09-08 16:03:48 +02003791 /* does not fulfill conditions, remove instid record */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003792 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003793 }
3794 } while (has_predicate);
3795
Michal Vaskob2f40be2016-09-08 16:03:48 +02003796 /* check that all list keys were specified */
3797 if ((pred_iter > 0) && node_match->count) {
Michal Vasko045182c2016-09-09 12:44:07 +02003798 j = 0;
3799 while (j < node_match->count) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02003800 assert(node_match->node[j]->schema->nodetype == LYS_LIST);
3801 if (pred_iter < ((struct lys_node_list *)node_match->node[j]->schema)->keys_size) {
3802 /* not enough predicates, just remove the list instance */
3803 unres_data_del(node_match, j);
Michal Vasko045182c2016-09-09 12:44:07 +02003804 } else {
3805 ++j;
Michal Vaskob2f40be2016-09-08 16:03:48 +02003806 }
3807 }
3808
3809 if (!node_match->count) {
3810 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier is missing some list keys.");
3811 }
3812 }
3813
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003814 return parsed;
3815}
3816
Radek Krejcid2ac35f2016-10-21 23:08:28 +02003817int
Michal Vasko769f8032017-01-24 13:11:55 +01003818lys_check_xpath(struct lys_node *node, int check_place, int warn_on_fwd_ref)
Michal Vasko9e635ac2016-10-17 11:44:09 +02003819{
3820 struct lys_node *parent, *elem;
3821 struct lyxp_set set;
3822 uint32_t i;
Michal Vasko769f8032017-01-24 13:11:55 +01003823 int ret;
Michal Vasko9e635ac2016-10-17 11:44:09 +02003824
Radek Krejcid2ac35f2016-10-21 23:08:28 +02003825 if (check_place) {
3826 parent = node;
3827 while (parent) {
3828 if (parent->nodetype == LYS_GROUPING) {
3829 /* unresolved grouping, skip for now (will be checked later) */
Michal Vasko9e635ac2016-10-17 11:44:09 +02003830 return EXIT_SUCCESS;
Michal Vasko9e635ac2016-10-17 11:44:09 +02003831 }
Radek Krejcid2ac35f2016-10-21 23:08:28 +02003832 if (parent->nodetype == LYS_AUGMENT) {
3833 if (!((struct lys_node_augment *)parent)->target) {
Michal Vasko44ab1462017-05-18 13:18:36 +02003834 /* unresolved augment, skip for now (will be checked later) */
3835 return EXIT_FAILURE;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02003836 } else {
3837 parent = ((struct lys_node_augment *)parent)->target;
3838 continue;
3839 }
3840 }
3841 parent = parent->parent;
Michal Vasko9e635ac2016-10-17 11:44:09 +02003842 }
Michal Vasko9e635ac2016-10-17 11:44:09 +02003843 }
3844
Michal Vasko769f8032017-01-24 13:11:55 +01003845 ret = lyxp_node_atomize(node, &set, warn_on_fwd_ref);
3846 if (ret == -1) {
3847 return -1;
Michal Vasko9e635ac2016-10-17 11:44:09 +02003848 }
3849
3850 for (parent = node; parent && !(parent->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); parent = lys_parent(parent));
3851
3852 for (i = 0; i < set.used; ++i) {
3853 /* skip roots'n'stuff */
3854 if (set.val.snodes[i].type == LYXP_NODE_ELEM) {
3855 /* XPath expression cannot reference "lower" status than the node that has the definition */
3856 if (lyp_check_status(node->flags, lys_node_module(node), node->name, set.val.snodes[i].snode->flags,
3857 lys_node_module(set.val.snodes[i].snode), set.val.snodes[i].snode->name, node)) {
3858 return -1;
3859 }
3860
3861 if (parent) {
3862 for (elem = set.val.snodes[i].snode; elem && (elem != parent); elem = lys_parent(elem));
3863 if (!elem) {
3864 /* not in node's RPC or notification subtree, set the flag */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01003865 node->flags |= LYS_XPATH_DEP;
Michal Vasko9e635ac2016-10-17 11:44:09 +02003866 break;
3867 }
3868 }
3869 }
3870 }
3871
3872 free(set.val.snodes);
Michal Vasko769f8032017-01-24 13:11:55 +01003873 return ret;
Michal Vasko9e635ac2016-10-17 11:44:09 +02003874}
3875
Radek Krejcif71f48f2016-10-25 16:37:24 +02003876static int
3877check_leafref_config(struct lys_node_leaf *leaf, struct lys_type *type)
3878{
3879 int i;
3880
3881 if (type->base == LY_TYPE_LEAFREF) {
Radek Krejcic688ca02017-03-20 12:54:39 +01003882 if ((leaf->flags & LYS_CONFIG_W) && type->info.lref.target && type->info.lref.req != -1 &&
3883 (type->info.lref.target->flags & LYS_CONFIG_R)) {
Radek Krejcid831dd42017-03-16 12:59:30 +01003884 LOGVAL(LYE_SPEC, LY_VLOG_LYS, leaf, "The leafref %s is config but refers to a non-config %s.",
Radek Krejcif71f48f2016-10-25 16:37:24 +02003885 strnodetype(leaf->nodetype), strnodetype(type->info.lref.target->nodetype));
3886 return -1;
3887 }
3888 /* we can skip the test in case the leafref is not yet resolved. In that case the test is done in the time
3889 * of leafref resolving (lys_leaf_add_leafref_target()) */
3890 } else if (type->base == LY_TYPE_UNION) {
3891 for (i = 0; i < type->info.uni.count; i++) {
3892 if (check_leafref_config(leaf, &type->info.uni.types[i])) {
3893 return -1;
3894 }
3895 }
3896 }
3897 return 0;
3898}
3899
Michal Vasko9e635ac2016-10-17 11:44:09 +02003900/**
Michal Vaskoaec34ea2016-05-19 15:21:40 +02003901 * @brief Passes config flag down to children, skips nodes without config flags.
Michal Vasko44ab1462017-05-18 13:18:36 +02003902 * Logs.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003903 *
Michal Vaskoaec34ea2016-05-19 15:21:40 +02003904 * @param[in] node Siblings and their children to have flags changed.
Michal Vaskoe022a562016-09-27 14:24:15 +02003905 * @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 +02003906 * @param[in] flags Flags to assign to all the nodes.
Radek Krejcib3142312016-11-09 11:04:12 +01003907 * @param[in,out] unres List of unresolved items.
Michal Vaskoa86508c2016-08-26 14:30:19 +02003908 *
3909 * @return 0 on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003910 */
Michal Vasko44ab1462017-05-18 13:18:36 +02003911int
3912inherit_config_flag(struct lys_node *node, int flags, int clear)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003913{
Radek Krejcif71f48f2016-10-25 16:37:24 +02003914 struct lys_node_leaf *leaf;
3915
Michal Vaskoaec34ea2016-05-19 15:21:40 +02003916 assert(!(flags ^ (flags & LYS_CONFIG_MASK)));
Radek Krejci1d82ef62015-08-07 14:44:40 +02003917 LY_TREE_FOR(node, node) {
Michal Vaskoe022a562016-09-27 14:24:15 +02003918 if (clear) {
3919 node->flags &= ~LYS_CONFIG_MASK;
Michal Vaskoc2a8d362016-09-29 08:50:13 +02003920 node->flags &= ~LYS_CONFIG_SET;
Michal Vaskoe022a562016-09-27 14:24:15 +02003921 } else {
3922 if (node->flags & LYS_CONFIG_SET) {
3923 /* skip nodes with an explicit config value */
3924 if ((flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
3925 LOGVAL(LYE_INARG, LY_VLOG_LYS, node, "true", "config");
Michal Vasko51e5c582017-01-19 14:16:39 +01003926 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "State nodes cannot have configuration nodes as children.");
Michal Vaskoe022a562016-09-27 14:24:15 +02003927 return -1;
3928 }
3929 continue;
Michal Vaskoa86508c2016-08-26 14:30:19 +02003930 }
Michal Vaskoe022a562016-09-27 14:24:15 +02003931
3932 if (!(node->nodetype & (LYS_USES | LYS_GROUPING))) {
3933 node->flags = (node->flags & ~LYS_CONFIG_MASK) | flags;
3934 /* check that configuration lists have keys */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02003935 if ((node->nodetype == LYS_LIST) && (node->flags & LYS_CONFIG_W)
3936 && !((struct lys_node_list *)node)->keys_size) {
Michal Vaskoe022a562016-09-27 14:24:15 +02003937 LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_LYS, node, "key", "list");
3938 return -1;
3939 }
3940 }
Michal Vaskoaec34ea2016-05-19 15:21:40 +02003941 }
Radek Krejcibf2abff2016-08-23 15:51:52 +02003942 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vasko44ab1462017-05-18 13:18:36 +02003943 if (inherit_config_flag(node->child, flags, clear)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02003944 return -1;
3945 }
Radek Krejcif71f48f2016-10-25 16:37:24 +02003946 } else if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
3947 leaf = (struct lys_node_leaf *)node;
3948 if (check_leafref_config(leaf, &leaf->type)) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02003949 return -1;
3950 }
3951 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003952 }
Michal Vaskoa86508c2016-08-26 14:30:19 +02003953
3954 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003955}
3956
Michal Vasko730dfdf2015-08-11 14:48:05 +02003957/**
Michal Vasko7178e692016-02-12 15:58:05 +01003958 * @brief Resolve augment target. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003959 *
Michal Vaskobb211122015-08-19 14:03:11 +02003960 * @param[in] aug Augment to use.
Michal Vasko3edeaf72016-02-11 13:17:43 +01003961 * @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 +01003962 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003963 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003964 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003965 */
Michal Vasko7178e692016-02-12 15:58:05 +01003966static int
Radek Krejcib3142312016-11-09 11:04:12 +01003967resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003968{
Michal Vasko44ab1462017-05-18 13:18:36 +02003969 int rc;
Michal Vasko1d87a922015-08-21 12:57:16 +02003970 struct lys_node *sub;
Radek Krejci27fe55e2016-09-13 17:13:35 +02003971 struct lys_module *mod;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003972
Michal Vasko2ef7db62017-06-12 09:24:02 +02003973 assert(aug);
Radek Krejcidf46e222016-11-08 11:57:37 +01003974 mod = lys_main_module(aug->module);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003975
Michal Vaskobb520442017-05-23 10:55:18 +02003976 /* set it as not applied for now */
3977 aug->flags |= LYS_NOTAPPLIED;
3978
Michal Vasko2ef7db62017-06-12 09:24:02 +02003979 /* it can already be resolved in case we returned EXIT_FAILURE from if block below */
Michal Vasko44ab1462017-05-18 13:18:36 +02003980 if (!aug->target) {
Michal Vasko2ef7db62017-06-12 09:24:02 +02003981 /* resolve target node */
3982 rc = resolve_augment_schema_nodeid(aug->target_name, siblings, (siblings ? NULL : aug->module),
3983 (const struct lys_node **)&aug->target);
3984 if (rc == -1) {
3985 return -1;
3986 } else if (rc > 0) {
3987 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, aug, aug->target_name[rc - 1], &aug->target_name[rc - 1]);
3988 return -1;
3989 }
3990 if (!aug->target) {
3991 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
3992 return EXIT_FAILURE;
3993 }
Michal Vasko15b36692016-08-26 15:29:54 +02003994 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02003995
Michal Vaskod58d5962016-03-02 14:29:41 +01003996 /* check for mandatory nodes - if the target node is in another module
3997 * the added nodes cannot be mandatory
3998 */
Michal Vasko44ab1462017-05-18 13:18:36 +02003999 if (!aug->parent && (lys_node_module((struct lys_node *)aug) != lys_node_module(aug->target))
4000 && (rc = lyp_check_mandatory_augment(aug, aug->target))) {
Radek Krejcie00d2312016-08-12 15:27:49 +02004001 return rc;
Michal Vaskod58d5962016-03-02 14:29:41 +01004002 }
4003
Michal Vasko07e89ef2016-03-03 13:28:57 +01004004 /* check augment target type and then augment nodes type */
Michal Vasko44ab1462017-05-18 13:18:36 +02004005 if (aug->target->nodetype & (LYS_CONTAINER | LYS_LIST)) {
Michal Vaskodb017262017-01-24 13:10:04 +01004006 LY_TREE_FOR(aug->child, sub) {
4007 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES
4008 | LYS_CHOICE | LYS_ACTION | LYS_NOTIF))) {
4009 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4010 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko44ab1462017-05-18 13:18:36 +02004011 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
Michal Vaskodb017262017-01-24 13:10:04 +01004012 return -1;
4013 }
4014 }
Michal Vasko44ab1462017-05-18 13:18:36 +02004015 } else if (aug->target->nodetype & (LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF)) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004016 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004017 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES | LYS_CHOICE))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004018 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
Michal Vasko51e5c582017-01-19 14:16:39 +01004019 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko44ab1462017-05-18 13:18:36 +02004020 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004021 return -1;
4022 }
4023 }
Michal Vasko44ab1462017-05-18 13:18:36 +02004024 } else if (aug->target->nodetype == LYS_CHOICE) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004025 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004026 if (!(sub->nodetype & (LYS_CASE | LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004027 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
Michal Vasko51e5c582017-01-19 14:16:39 +01004028 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko44ab1462017-05-18 13:18:36 +02004029 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004030 return -1;
4031 }
4032 }
4033 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01004034 LOGVAL(LYE_INARG, LY_VLOG_LYS, aug, aug->target_name, "target-node");
Michal Vasko44ab1462017-05-18 13:18:36 +02004035 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Invalid augment target node type \"%s\".", strnodetype(aug->target->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004036 return -1;
4037 }
4038
Radek Krejcic071c542016-01-27 14:57:51 +01004039 /* check identifier uniqueness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02004040 LY_TREE_FOR(aug->child, sub) {
Michal Vasko44ab1462017-05-18 13:18:36 +02004041 if (lys_check_id(sub, aug->target, NULL)) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02004042 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02004043 }
4044 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004045
Michal Vasko44ab1462017-05-18 13:18:36 +02004046 if (!aug->child) {
4047 /* empty augment, nothing to connect, but it is techincally applied */
4048 LOGWRN("Augment \"%s\" without children.", aug->target_name);
4049 aug->flags &= ~LYS_NOTAPPLIED;
4050 } else if (mod->implemented && apply_aug(aug, unres)) {
4051 /* we tried to connect it, we failed */
4052 return -1;
Michal Vasko15b36692016-08-26 15:29:54 +02004053 }
4054
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004055 return EXIT_SUCCESS;
4056}
4057
Radek Krejcie534c132016-11-23 13:32:31 +01004058static int
Radek Krejcia7db9702017-01-20 12:55:14 +01004059resolve_extension(struct unres_ext *info, struct lys_ext_instance **ext, struct unres_schema *unres)
Radek Krejcie534c132016-11-23 13:32:31 +01004060{
4061 enum LY_VLOG_ELEM vlog_type;
4062 void *vlog_node;
4063 unsigned int i, j;
Radek Krejcie534c132016-11-23 13:32:31 +01004064 struct lys_ext *e;
PavolVicanc1807262017-01-31 18:00:27 +01004065 char *ext_name, *ext_prefix, *tmp;
Radek Krejcie534c132016-11-23 13:32:31 +01004066 struct lyxml_elem *next_yin, *yin;
Radek Krejcia7db9702017-01-20 12:55:14 +01004067 const struct lys_module *mod;
PavolVican22e88682017-02-14 22:38:18 +01004068 struct lys_ext_instance *tmp_ext;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004069 LYEXT_TYPE etype;
Radek Krejcie534c132016-11-23 13:32:31 +01004070
4071 switch (info->parent_type) {
Radek Krejci0aa821a2016-12-08 11:21:35 +01004072 case LYEXT_PAR_NODE:
Radek Krejcie534c132016-11-23 13:32:31 +01004073 vlog_node = info->parent;
4074 vlog_type = LY_VLOG_LYS;
4075 break;
Radek Krejci0aa821a2016-12-08 11:21:35 +01004076 case LYEXT_PAR_MODULE:
4077 case LYEXT_PAR_IMPORT:
4078 case LYEXT_PAR_INCLUDE:
Radek Krejcie534c132016-11-23 13:32:31 +01004079 vlog_node = NULL;
4080 vlog_type = LY_VLOG_LYS;
4081 break;
Radek Krejci43ce4b72017-01-04 11:02:38 +01004082 default:
Radek Krejcie534c132016-11-23 13:32:31 +01004083 vlog_node = NULL;
Radek Krejci6a7fedf2017-02-10 12:38:06 +01004084 vlog_type = LY_VLOG_NONE;
Radek Krejcie534c132016-11-23 13:32:31 +01004085 break;
4086 }
4087
4088 if (info->datatype == LYS_IN_YIN) {
Radek Krejci8d6b7422017-02-03 14:42:13 +01004089 /* YIN */
4090
Radek Krejcie534c132016-11-23 13:32:31 +01004091 /* get the module where the extension is supposed to be defined */
Radek Krejcia7db9702017-01-20 12:55:14 +01004092 mod = lys_get_import_module_ns(info->mod, info->data.yin->ns->value);
Radek Krejcie534c132016-11-23 13:32:31 +01004093 if (!mod) {
4094 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, info->data.yin->name);
Radek Krejci2b999ac2017-01-18 16:22:12 +01004095 return EXIT_FAILURE;
Radek Krejcie534c132016-11-23 13:32:31 +01004096 }
4097
4098 /* find the extension definition */
4099 e = NULL;
4100 for (i = 0; i < mod->extensions_size; i++) {
4101 if (ly_strequal(mod->extensions[i].name, info->data.yin->name, 1)) {
4102 e = &mod->extensions[i];
4103 break;
4104 }
4105 }
4106 /* try submodules */
4107 for (j = 0; !e && j < mod->inc_size; j++) {
4108 for (i = 0; i < mod->inc[j].submodule->extensions_size; i++) {
4109 if (ly_strequal(mod->inc[j].submodule->extensions[i].name, info->data.yin->name, 1)) {
4110 e = &mod->inc[j].submodule->extensions[i];
4111 break;
4112 }
4113 }
4114 }
4115 if (!e) {
4116 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, info->data.yin->name);
4117 return EXIT_FAILURE;
4118 }
4119
4120 /* we have the extension definition, so now it cannot be forward referenced and error is always fatal */
Radek Krejcie534c132016-11-23 13:32:31 +01004121
Radek Krejci72b35992017-01-04 16:27:44 +01004122 if (e->plugin && e->plugin->check_position) {
4123 /* common part - we have plugin with position checking function, use it first */
4124 if ((*e->plugin->check_position)(info->parent, info->parent_type, info->substmt)) {
4125 /* extension is not allowed here */
4126 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, e->name);
4127 return -1;
4128 }
4129 }
4130
Radek Krejci8d6b7422017-02-03 14:42:13 +01004131 /* extension type-specific part - allocation */
4132 if (e->plugin) {
4133 etype = e->plugin->type;
4134 } else {
4135 /* default type */
4136 etype = LYEXT_FLAG;
4137 }
4138 switch (etype) {
4139 case LYEXT_FLAG:
4140 (*ext) = calloc(1, sizeof(struct lys_ext_instance));
4141 break;
4142 case LYEXT_COMPLEX:
4143 (*ext) = calloc(1, ((struct lyext_plugin_complex*)e->plugin)->instance_size);
4144 break;
4145 case LYEXT_ERR:
4146 /* we never should be here */
4147 LOGINT;
4148 return -1;
4149 }
Radek Krejciaa1303c2017-05-31 13:57:37 +02004150 LY_CHECK_ERR_RETURN(!*ext, LOGMEM, -1);
Radek Krejci8d6b7422017-02-03 14:42:13 +01004151
4152 /* common part for all extension types */
4153 (*ext)->def = e;
4154 (*ext)->parent = info->parent;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004155 (*ext)->parent_type = info->parent_type;
Radek Krejcifebdad72017-02-06 11:35:51 +01004156 (*ext)->insubstmt = info->substmt;
4157 (*ext)->insubstmt_index = info->substmt_index;
Radek Krejci8de8f612017-02-16 15:03:32 +01004158 (*ext)->ext_type = e->plugin ? e->plugin->type : LYEXT_FLAG;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004159
4160 if (!(e->flags & LYS_YINELEM) && e->argument) {
4161 (*ext)->arg_value = lyxml_get_attr(info->data.yin, e->argument, NULL);
4162 if (!(*ext)->arg_value) {
4163 LOGVAL(LYE_MISSARG, LY_VLOG_NONE, NULL, e->argument, info->data.yin->name);
4164 return -1;
4165 }
4166 (*ext)->arg_value = lydict_insert(mod->ctx, (*ext)->arg_value, 0);
4167 }
4168
Radek Krejci7f1d47e2017-04-12 15:29:02 +02004169 (*ext)->nodetype = LYS_EXT;
4170 (*ext)->module = info->mod;
Radek Krejci5138e9f2017-04-12 13:10:46 +02004171
Radek Krejci8d6b7422017-02-03 14:42:13 +01004172 /* extension type-specific part - parsing content */
4173 switch (etype) {
4174 case LYEXT_FLAG:
Radek Krejci72b35992017-01-04 16:27:44 +01004175 LY_TREE_FOR_SAFE(info->data.yin->child, next_yin, yin) {
4176 if (!yin->ns) {
4177 /* garbage */
4178 lyxml_free(mod->ctx, yin);
4179 continue;
4180 } else if (!strcmp(yin->ns->value, LY_NSYIN)) {
4181 /* standard YANG statements are not expected here */
4182 LOGVAL(LYE_INCHILDSTMT, vlog_type, vlog_node, yin->name, info->data.yin->name);
4183 return -1;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004184 } else if (yin->ns == info->data.yin->ns &&
4185 (e->flags & LYS_YINELEM) && ly_strequal(yin->name, e->argument, 1)) {
Radek Krejci72b35992017-01-04 16:27:44 +01004186 /* we have the extension's argument */
Radek Krejci8d6b7422017-02-03 14:42:13 +01004187 if ((*ext)->arg_value) {
Radek Krejci72b35992017-01-04 16:27:44 +01004188 LOGVAL(LYE_TOOMANY, vlog_type, vlog_node, yin->name, info->data.yin->name);
Radek Krejcie534c132016-11-23 13:32:31 +01004189 return -1;
4190 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004191 (*ext)->arg_value = yin->content;
Radek Krejci72b35992017-01-04 16:27:44 +01004192 yin->content = NULL;
4193 lyxml_free(mod->ctx, yin);
4194 } else {
Radek Krejci8d6b7422017-02-03 14:42:13 +01004195 /* extension instance */
4196 if (lyp_yin_parse_subnode_ext(info->mod, *ext, LYEXT_PAR_EXTINST, yin,
4197 LYEXT_SUBSTMT_SELF, 0, unres)) {
4198 return -1;
4199 }
Radek Krejci72b35992017-01-04 16:27:44 +01004200
Radek Krejci72b35992017-01-04 16:27:44 +01004201 continue;
Radek Krejcie534c132016-11-23 13:32:31 +01004202 }
Radek Krejci72b35992017-01-04 16:27:44 +01004203 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004204 break;
4205 case LYEXT_COMPLEX:
Radek Krejcifebdad72017-02-06 11:35:51 +01004206 ((struct lys_ext_instance_complex*)(*ext))->substmt = ((struct lyext_plugin_complex*)e->plugin)->substmt;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004207 if (lyp_yin_parse_complex_ext(info->mod, (struct lys_ext_instance_complex*)(*ext), info->data.yin, unres)) {
4208 /* TODO memory cleanup */
Radek Krejci72b35992017-01-04 16:27:44 +01004209 return -1;
4210 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004211 break;
4212 default:
4213 break;
Radek Krejcie534c132016-11-23 13:32:31 +01004214 }
Radek Krejci72b35992017-01-04 16:27:44 +01004215
4216 /* TODO - lyext_check_result_clb, other than LYEXT_FLAG plugins */
4217
Radek Krejcie534c132016-11-23 13:32:31 +01004218 } else {
Radek Krejci8d6b7422017-02-03 14:42:13 +01004219 /* YANG */
4220
PavolVicanc1807262017-01-31 18:00:27 +01004221 ext_prefix = (char *)(*ext)->def;
4222 tmp = strchr(ext_prefix, ':');
4223 if (!tmp) {
4224 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
PavolVican22e88682017-02-14 22:38:18 +01004225 goto error;
PavolVicanc1807262017-01-31 18:00:27 +01004226 }
4227 ext_name = tmp + 1;
Radek Krejcie534c132016-11-23 13:32:31 +01004228
PavolVicanc1807262017-01-31 18:00:27 +01004229 /* get the module where the extension is supposed to be defined */
4230 mod = lys_get_import_module(info->mod, ext_prefix, tmp - ext_prefix, NULL, 0);
4231 if (!mod) {
4232 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
4233 return EXIT_FAILURE;
4234 }
4235
4236 /* find the extension definition */
4237 e = NULL;
4238 for (i = 0; i < mod->extensions_size; i++) {
4239 if (ly_strequal(mod->extensions[i].name, ext_name, 0)) {
4240 e = &mod->extensions[i];
4241 break;
4242 }
4243 }
4244 /* try submodules */
4245 for (j = 0; !e && j < mod->inc_size; j++) {
4246 for (i = 0; i < mod->inc[j].submodule->extensions_size; i++) {
4247 if (ly_strequal(mod->inc[j].submodule->extensions[i].name, ext_name, 0)) {
4248 e = &mod->inc[j].submodule->extensions[i];
4249 break;
4250 }
4251 }
4252 }
4253 if (!e) {
4254 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
4255 return EXIT_FAILURE;
4256 }
4257
4258 /* we have the extension definition, so now it cannot be forward referenced and error is always fatal */
4259
4260 if (e->plugin && e->plugin->check_position) {
4261 /* common part - we have plugin with position checking function, use it first */
4262 if ((*e->plugin->check_position)(info->parent, info->parent_type, info->substmt)) {
4263 /* extension is not allowed here */
4264 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, e->name);
PavolVican22e88682017-02-14 22:38:18 +01004265 goto error;
PavolVicanc1807262017-01-31 18:00:27 +01004266 }
4267 }
4268
PavolVican22e88682017-02-14 22:38:18 +01004269 /* extension common part */
PavolVicanc1807262017-01-31 18:00:27 +01004270 (*ext)->flags &= ~LYEXT_OPT_YANG;
PavolVicanc1807262017-01-31 18:00:27 +01004271 (*ext)->def = e;
4272 (*ext)->parent = info->parent;
Radek Krejci8de8f612017-02-16 15:03:32 +01004273 (*ext)->ext_type = e->plugin ? e->plugin->type : LYEXT_FLAG;
PavolVican22e88682017-02-14 22:38:18 +01004274
PavolVicanb0d84102017-02-15 16:32:42 +01004275 if (e->argument && !(*ext)->arg_value) {
4276 LOGVAL(LYE_MISSARG, LY_VLOG_NONE, NULL, e->argument, ext_name);
4277 goto error;
4278 }
4279
Radek Krejci7f1d47e2017-04-12 15:29:02 +02004280 (*ext)->module = info->mod;
4281 (*ext)->nodetype = LYS_EXT;
Radek Krejci5138e9f2017-04-12 13:10:46 +02004282
PavolVican22e88682017-02-14 22:38:18 +01004283 /* extension type-specific part */
4284 if (e->plugin) {
4285 etype = e->plugin->type;
4286 } else {
4287 /* default type */
4288 etype = LYEXT_FLAG;
PavolVicanc1807262017-01-31 18:00:27 +01004289 }
PavolVican22e88682017-02-14 22:38:18 +01004290 switch (etype) {
4291 case LYEXT_FLAG:
4292 /* nothing change */
4293 break;
4294 case LYEXT_COMPLEX:
4295 tmp_ext = realloc(*ext, ((struct lyext_plugin_complex*)e->plugin)->instance_size);
Radek Krejciaa1303c2017-05-31 13:57:37 +02004296 LY_CHECK_ERR_GOTO(!tmp_ext, LOGMEM, error);
PavolVican22e88682017-02-14 22:38:18 +01004297 memset((char *)tmp_ext + sizeof **ext, 0, ((struct lyext_plugin_complex*)e->plugin)->instance_size - sizeof **ext);
4298 (*ext) = tmp_ext;
PavolVican22e88682017-02-14 22:38:18 +01004299 ((struct lys_ext_instance_complex*)(*ext))->substmt = ((struct lyext_plugin_complex*)e->plugin)->substmt;
PavolVicana1e291f2017-02-19 16:07:12 +01004300 if (info->data.yang) {
4301 *tmp = ':';
PavolVicandb0e8172017-02-20 00:46:09 +01004302 if (yang_parse_ext_substatement(info->mod, unres, info->data.yang->ext_substmt, ext_prefix,
4303 (struct lys_ext_instance_complex*)(*ext))) {
4304 goto error;
4305 }
4306 if (yang_fill_extcomplex_module(info->mod->ctx, (struct lys_ext_instance_complex*)(*ext), ext_prefix,
4307 info->data.yang->ext_modules, info->mod->implemented)) {
PavolVicana1e291f2017-02-19 16:07:12 +01004308 goto error;
4309 }
PavolVicana3876672017-02-21 15:49:51 +01004310 }
4311 if (lyp_mand_check_ext((struct lys_ext_instance_complex*)(*ext), ext_prefix)) {
4312 goto error;
PavolVicana1e291f2017-02-19 16:07:12 +01004313 }
PavolVican22e88682017-02-14 22:38:18 +01004314 break;
4315 case LYEXT_ERR:
4316 /* we never should be here */
4317 LOGINT;
4318 goto error;
4319 }
4320
PavolVican22e88682017-02-14 22:38:18 +01004321 if (yang_check_ext_instance(info->mod, &(*ext)->ext, (*ext)->ext_size, *ext, unres)) {
4322 goto error;
4323 }
4324 free(ext_prefix);
Radek Krejcie534c132016-11-23 13:32:31 +01004325 }
4326
4327 return EXIT_SUCCESS;
PavolVican22e88682017-02-14 22:38:18 +01004328error:
4329 free(ext_prefix);
4330 return -1;
Radek Krejcie534c132016-11-23 13:32:31 +01004331}
4332
Michal Vasko730dfdf2015-08-11 14:48:05 +02004333/**
Pavol Vican855ca622016-09-05 13:07:54 +02004334 * @brief Resolve (find) choice default case. Does not log.
4335 *
4336 * @param[in] choic Choice to use.
4337 * @param[in] dflt Name of the default case.
4338 *
4339 * @return Pointer to the default node or NULL.
4340 */
4341static struct lys_node *
4342resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
4343{
4344 struct lys_node *child, *ret;
4345
4346 LY_TREE_FOR(choic->child, child) {
4347 if (child->nodetype == LYS_USES) {
4348 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
4349 if (ret) {
4350 return ret;
4351 }
4352 }
4353
4354 if (ly_strequal(child->name, dflt, 1) && (child->nodetype & (LYS_ANYDATA | LYS_CASE
Radek Krejci2f792db2016-09-12 10:52:33 +02004355 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE))) {
Pavol Vican855ca622016-09-05 13:07:54 +02004356 return child;
4357 }
4358 }
4359
4360 return NULL;
4361}
4362
4363/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02004364 * @brief Resolve uses, apply augments, refines. Logs directly.
4365 *
Michal Vaskobb211122015-08-19 14:03:11 +02004366 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004367 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004368 *
Michal Vaskodef0db12015-10-07 13:22:48 +02004369 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004370 */
Michal Vasko184521f2015-09-24 13:14:26 +02004371static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004372resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004373{
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004374 struct ly_ctx *ctx = uses->module->ctx; /* shortcut */
Pavol Vican855ca622016-09-05 13:07:54 +02004375 struct lys_node *node = NULL, *next, *iter, **refine_nodes = NULL;
Pavol Vican55abd332016-07-12 15:54:49 +02004376 struct lys_node *node_aux, *parent, *tmp;
Radek Krejci200bf712016-08-16 17:11:04 +02004377 struct lys_node_leaflist *llist;
4378 struct lys_node_leaf *leaf;
Radek Krejci76512572015-08-04 09:47:08 +02004379 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004380 struct lys_restr *must, **old_must;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004381 struct lys_iffeature *iff, **old_iff;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004382 int i, j, k, rc;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004383 uint8_t size, *old_size;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004384 unsigned int usize, usize1, usize2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004385
Michal Vasko71e1aa82015-08-12 12:17:51 +02004386 assert(uses->grp);
Radek Krejci6ff885d2017-01-03 14:06:22 +01004387
4388 /* HACK just check that the grouping is resolved
4389 * - the higher byte in flags is always empty in grouping (no flags there apply to the groupings)
4390 * so we use it to count unresolved uses inside the grouping */
4391#if __BYTE_ORDER == __LITTLE_ENDIAN
4392 assert(!((uint8_t*)&uses->grp->flags)[1]);
4393#else
4394 assert(!((uint8_t*)&uses->grp->flags)[0]);
4395#endif
Michal Vasko71e1aa82015-08-12 12:17:51 +02004396
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004397 if (!uses->grp->child) {
4398 /* grouping without children, warning was already displayed */
4399 return EXIT_SUCCESS;
4400 }
4401
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004402 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01004403 LY_TREE_FOR(uses->grp->child, node_aux) {
Radek Krejcif0bb3602017-01-25 17:05:08 +01004404 if (node_aux->nodetype & LYS_GROUPING) {
4405 /* do not instantiate groupings from groupings */
4406 continue;
4407 }
Radek Krejci6ff885d2017-01-03 14:06:22 +01004408 node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, unres, 0);
Michal Vasko1e62a092015-12-01 12:27:20 +01004409 if (!node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004410 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, uses->grp->name, "uses");
Michal Vasko51e5c582017-01-19 14:16:39 +01004411 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Copying data from grouping failed.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004412 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004413 }
Pavol Vican55abd332016-07-12 15:54:49 +02004414 /* test the name of siblings */
Radek Krejcif95b6292017-02-13 15:57:37 +01004415 LY_TREE_FOR((uses->parent) ? *lys_child(uses->parent, LYS_USES) : lys_main_module(uses->module)->data, tmp) {
Pavol Vican2510ddc2016-07-18 16:23:44 +02004416 if (!(tmp->nodetype & (LYS_USES | LYS_GROUPING | LYS_CASE)) && ly_strequal(tmp->name, node_aux->name, 1)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004417 goto fail;
Pavol Vican55abd332016-07-12 15:54:49 +02004418 }
4419 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004420 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004421
Michal Vaskodef0db12015-10-07 13:22:48 +02004422 /* we managed to copy the grouping, the rest must be possible to resolve */
4423
Pavol Vican855ca622016-09-05 13:07:54 +02004424 if (uses->refine_size) {
4425 refine_nodes = malloc(uses->refine_size * sizeof *refine_nodes);
Radek Krejciaa1303c2017-05-31 13:57:37 +02004426 LY_CHECK_ERR_GOTO(!refine_nodes, LOGMEM, fail);
Pavol Vican855ca622016-09-05 13:07:54 +02004427 }
4428
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004429 /* apply refines */
4430 for (i = 0; i < uses->refine_size; i++) {
4431 rfn = &uses->refine[i];
Radek Krejcie2077412017-01-26 16:03:39 +01004432 rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child,
4433 LYS_NO_RPC_NOTIF_NODE | LYS_ACTION | LYS_NOTIF,
Michal Vaskodc300b02017-04-07 14:09:20 +02004434 0, (const struct lys_node **)&node);
Michal Vasko9bb061b2016-02-12 11:00:19 +01004435 if (rc || !node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004436 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004437 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004438 }
4439
Radek Krejci1d82ef62015-08-07 14:44:40 +02004440 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004441 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vasko51e5c582017-01-19 14:16:39 +01004442 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Refine substatements not applicable to the target-node.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004443 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004444 }
Pavol Vican855ca622016-09-05 13:07:54 +02004445 refine_nodes[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004446
4447 /* description on any nodetype */
4448 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004449 lydict_remove(ctx, node->dsc);
4450 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004451 }
4452
4453 /* reference on any nodetype */
4454 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004455 lydict_remove(ctx, node->ref);
4456 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004457 }
4458
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004459 /* config on any nodetype,
4460 * in case of notification or rpc/action, the config is not applicable (there is no config status) */
4461 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004462 node->flags &= ~LYS_CONFIG_MASK;
4463 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004464 }
4465
4466 /* default value ... */
Radek Krejci200bf712016-08-16 17:11:04 +02004467 if (rfn->dflt_size) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004468 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004469 /* leaf */
Radek Krejci200bf712016-08-16 17:11:04 +02004470 leaf = (struct lys_node_leaf *)node;
4471
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004472 /* replace default value */
Radek Krejci200bf712016-08-16 17:11:04 +02004473 lydict_remove(ctx, leaf->dflt);
4474 leaf->dflt = lydict_insert(ctx, rfn->dflt[0], 0);
4475
4476 /* check the default value */
Radek Krejci51673202016-11-01 17:00:32 +01004477 if (unres_schema_add_node(leaf->module, unres, &leaf->type, UNRES_TYPE_DFLT,
4478 (struct lys_node *)(&leaf->dflt)) == -1) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004479 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004480 }
Radek Krejci200bf712016-08-16 17:11:04 +02004481 } else if (node->nodetype == LYS_LEAFLIST) {
4482 /* leaf-list */
4483 llist = (struct lys_node_leaflist *)node;
4484
4485 /* remove complete set of defaults in target */
Radek Krejci542ab142017-01-23 15:57:08 +01004486 for (j = 0; j < llist->dflt_size; j++) {
4487 lydict_remove(ctx, llist->dflt[j]);
Radek Krejci200bf712016-08-16 17:11:04 +02004488 }
4489 free(llist->dflt);
4490
4491 /* copy the default set from refine */
Radek Krejciaa1303c2017-05-31 13:57:37 +02004492 llist->dflt = malloc(rfn->dflt_size * sizeof *llist->dflt);
4493 LY_CHECK_ERR_GOTO(!llist->dflt, LOGMEM, fail);
Radek Krejci200bf712016-08-16 17:11:04 +02004494 llist->dflt_size = rfn->dflt_size;
Radek Krejci542ab142017-01-23 15:57:08 +01004495 for (j = 0; j < llist->dflt_size; j++) {
4496 llist->dflt[j] = lydict_insert(ctx, rfn->dflt[j], 0);
Radek Krejci200bf712016-08-16 17:11:04 +02004497 }
4498
4499 /* check default value */
Radek Krejci542ab142017-01-23 15:57:08 +01004500 for (j = 0; j < llist->dflt_size; j++) {
Radek Krejci51673202016-11-01 17:00:32 +01004501 if (unres_schema_add_node(llist->module, unres, &llist->type, UNRES_TYPE_DFLT,
Radek Krejci542ab142017-01-23 15:57:08 +01004502 (struct lys_node *)(&llist->dflt[j])) == -1) {
Pavol Vican855ca622016-09-05 13:07:54 +02004503 goto fail;
Radek Krejci200bf712016-08-16 17:11:04 +02004504 }
4505 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004506 }
4507 }
4508
4509 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02004510 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejcibf285832017-01-26 16:05:41 +01004511 /* remove current value */
4512 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004513
Radek Krejcibf285832017-01-26 16:05:41 +01004514 /* set new value */
4515 node->flags |= (rfn->flags & LYS_MAND_MASK);
4516
Pavol Vican855ca622016-09-05 13:07:54 +02004517 if (rfn->flags & LYS_MAND_TRUE) {
4518 /* check if node has default value */
4519 if ((node->nodetype & LYS_LEAF) && ((struct lys_node_leaf *)node)->dflt) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02004520 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4521 "The \"mandatory\" statement is forbidden on leaf with \"default\".");
Pavol Vican855ca622016-09-05 13:07:54 +02004522 goto fail;
4523 }
4524 if ((node->nodetype & LYS_CHOICE) && ((struct lys_node_choice *)node)->dflt) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02004525 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4526 "The \"mandatory\" statement is forbidden on choices with \"default\".");
Pavol Vican855ca622016-09-05 13:07:54 +02004527 goto fail;
4528 }
4529 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004530 }
4531
4532 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004533 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
4534 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
4535 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004536 }
4537
4538 /* min/max-elements on list or leaf-list */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004539 if (node->nodetype == LYS_LIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004540 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004541 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004542 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004543 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004544 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004545 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02004546 } else if (node->nodetype == LYS_LEAFLIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004547 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004548 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004549 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004550 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004551 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004552 }
4553 }
4554
4555 /* must in leaf, leaf-list, list, container or anyxml */
4556 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004557 switch (node->nodetype) {
4558 case LYS_LEAF:
4559 old_size = &((struct lys_node_leaf *)node)->must_size;
4560 old_must = &((struct lys_node_leaf *)node)->must;
4561 break;
4562 case LYS_LEAFLIST:
4563 old_size = &((struct lys_node_leaflist *)node)->must_size;
4564 old_must = &((struct lys_node_leaflist *)node)->must;
4565 break;
4566 case LYS_LIST:
4567 old_size = &((struct lys_node_list *)node)->must_size;
4568 old_must = &((struct lys_node_list *)node)->must;
4569 break;
4570 case LYS_CONTAINER:
4571 old_size = &((struct lys_node_container *)node)->must_size;
4572 old_must = &((struct lys_node_container *)node)->must;
4573 break;
4574 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02004575 case LYS_ANYDATA:
4576 old_size = &((struct lys_node_anydata *)node)->must_size;
4577 old_must = &((struct lys_node_anydata *)node)->must;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004578 break;
4579 default:
4580 LOGINT;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004581 goto fail;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004582 }
4583
4584 size = *old_size + rfn->must_size;
4585 must = realloc(*old_must, size * sizeof *rfn->must);
Radek Krejciaa1303c2017-05-31 13:57:37 +02004586 LY_CHECK_ERR_GOTO(!must, LOGMEM, fail);
Pavol Vican855ca622016-09-05 13:07:54 +02004587 for (k = 0, j = *old_size; k < rfn->must_size; k++, j++) {
Radek Krejci7f0164a2017-01-25 17:04:06 +01004588 must[j].ext_size = rfn->must[k].ext_size;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004589 lys_ext_dup(rfn->module, rfn->must[k].ext, rfn->must[k].ext_size, &rfn->must[k], LYEXT_PAR_RESTR,
Radek Krejci5138e9f2017-04-12 13:10:46 +02004590 &must[j].ext, 0, unres);
Pavol Vican855ca622016-09-05 13:07:54 +02004591 must[j].expr = lydict_insert(ctx, rfn->must[k].expr, 0);
4592 must[j].dsc = lydict_insert(ctx, rfn->must[k].dsc, 0);
4593 must[j].ref = lydict_insert(ctx, rfn->must[k].ref, 0);
4594 must[j].eapptag = lydict_insert(ctx, rfn->must[k].eapptag, 0);
4595 must[j].emsg = lydict_insert(ctx, rfn->must[k].emsg, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004596 }
4597
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004598 *old_must = must;
4599 *old_size = size;
Michal Vasko508a50d2016-09-07 14:50:33 +02004600
4601 /* check XPath dependencies again */
4602 if (unres_schema_add_node(node->module, unres, node, UNRES_XPATH, NULL) == -1) {
4603 goto fail;
4604 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004605 }
Radek Krejci363bd4a2016-07-29 14:30:20 +02004606
4607 /* if-feature in leaf, leaf-list, list, container or anyxml */
4608 if (rfn->iffeature_size) {
4609 old_size = &node->iffeature_size;
4610 old_iff = &node->iffeature;
4611
4612 size = *old_size + rfn->iffeature_size;
4613 iff = realloc(*old_iff, size * sizeof *rfn->iffeature);
Radek Krejciaa1303c2017-05-31 13:57:37 +02004614 LY_CHECK_ERR_GOTO(!iff, LOGMEM, fail);
Pavol Vican855ca622016-09-05 13:07:54 +02004615 for (k = 0, j = *old_size; k < rfn->iffeature_size; k++, j++) {
4616 resolve_iffeature_getsizes(&rfn->iffeature[k], &usize1, &usize2);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004617 if (usize1) {
4618 /* there is something to duplicate */
4619 /* duplicate compiled expression */
4620 usize = (usize1 / 4) + (usize1 % 4) ? 1 : 0;
4621 iff[j].expr = malloc(usize * sizeof *iff[j].expr);
Radek Krejciaa1303c2017-05-31 13:57:37 +02004622 LY_CHECK_ERR_GOTO(!iff[j].expr, LOGMEM, fail);
Pavol Vican855ca622016-09-05 13:07:54 +02004623 memcpy(iff[j].expr, rfn->iffeature[k].expr, usize * sizeof *iff[j].expr);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004624
4625 /* duplicate list of feature pointers */
Pavol Vican855ca622016-09-05 13:07:54 +02004626 iff[j].features = malloc(usize2 * sizeof *iff[k].features);
Radek Krejciaa1303c2017-05-31 13:57:37 +02004627 LY_CHECK_ERR_GOTO(!iff[j].expr, LOGMEM, fail);
Pavol Vican855ca622016-09-05 13:07:54 +02004628 memcpy(iff[j].features, rfn->iffeature[k].features, usize2 * sizeof *iff[j].features);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004629 }
4630 }
4631
4632 *old_iff = iff;
4633 *old_size = size;
4634 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004635 }
4636
4637 /* apply augments */
4638 for (i = 0; i < uses->augment_size; i++) {
Radek Krejcib3142312016-11-09 11:04:12 +01004639 rc = resolve_augment(&uses->augment[i], uses->child, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004640 if (rc) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004641 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004642 }
4643 }
4644
Pavol Vican855ca622016-09-05 13:07:54 +02004645 /* check refines */
4646 for (i = 0; i < uses->refine_size; i++) {
4647 node = refine_nodes[i];
4648 rfn = &uses->refine[i];
4649
4650 /* config on any nodetype */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004651 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Pavol Vican855ca622016-09-05 13:07:54 +02004652 for (parent = lys_parent(node); parent && parent->nodetype == LYS_USES; parent = lys_parent(parent));
Radek Krejci5c08a992016-11-02 13:30:04 +01004653 if (parent && parent->nodetype != LYS_GROUPING && (parent->flags & LYS_CONFIG_MASK) &&
Pavol Vican855ca622016-09-05 13:07:54 +02004654 ((parent->flags & LYS_CONFIG_MASK) != (rfn->flags & LYS_CONFIG_MASK)) &&
4655 (rfn->flags & LYS_CONFIG_W)) {
4656 /* setting config true under config false is prohibited */
4657 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
Michal Vasko51e5c582017-01-19 14:16:39 +01004658 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02004659 "changing config from 'false' to 'true' is prohibited while "
4660 "the target's parent is still config 'false'.");
4661 goto fail;
4662 }
4663
4664 /* inherit config change to the target children */
4665 LY_TREE_DFS_BEGIN(node->child, next, iter) {
4666 if (rfn->flags & LYS_CONFIG_W) {
4667 if (iter->flags & LYS_CONFIG_SET) {
4668 /* config is set explicitely, go to next sibling */
4669 next = NULL;
4670 goto nextsibling;
4671 }
4672 } else { /* LYS_CONFIG_R */
4673 if ((iter->flags & LYS_CONFIG_SET) && (iter->flags & LYS_CONFIG_W)) {
4674 /* error - we would have config data under status data */
4675 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
Michal Vasko51e5c582017-01-19 14:16:39 +01004676 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02004677 "changing config from 'true' to 'false' is prohibited while the target "
4678 "has still a children with explicit config 'true'.");
4679 goto fail;
4680 }
4681 }
4682 /* change config */
4683 iter->flags &= ~LYS_CONFIG_MASK;
4684 iter->flags |= (rfn->flags & LYS_CONFIG_MASK);
4685
4686 /* select next iter - modified LY_TREE_DFS_END */
4687 if (iter->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
4688 next = NULL;
4689 } else {
4690 next = iter->child;
4691 }
4692nextsibling:
4693 if (!next) {
4694 /* try siblings */
4695 next = iter->next;
4696 }
4697 while (!next) {
4698 /* parent is already processed, go to its sibling */
4699 iter = lys_parent(iter);
4700
4701 /* no siblings, go back through parents */
4702 if (iter == node) {
4703 /* we are done, no next element to process */
4704 break;
4705 }
4706 next = iter->next;
4707 }
4708 }
4709 }
4710
4711 /* default value */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004712 if (rfn->dflt_size) {
4713 if (node->nodetype == LYS_CHOICE) {
4714 /* choice */
4715 ((struct lys_node_choice *)node)->dflt = resolve_choice_dflt((struct lys_node_choice *)node,
4716 rfn->dflt[0]);
4717 if (!((struct lys_node_choice *)node)->dflt) {
4718 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->dflt[0], "default");
4719 goto fail;
4720 }
4721 if (lyp_check_mandatory_choice(node)) {
4722 goto fail;
4723 }
Pavol Vican855ca622016-09-05 13:07:54 +02004724 }
4725 }
4726
4727 /* min/max-elements on list or leaf-list */
Radek Krejci2d3c8112017-04-19 10:20:50 +02004728 if (node->nodetype == LYS_LIST && ((struct lys_node_list *)node)->max) {
Pavol Vican855ca622016-09-05 13:07:54 +02004729 if (((struct lys_node_list *)node)->min > ((struct lys_node_list *)node)->max) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02004730 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
4731 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "\"min-elements\" is bigger than \"max-elements\".");
Pavol Vican855ca622016-09-05 13:07:54 +02004732 goto fail;
4733 }
Radek Krejci2d3c8112017-04-19 10:20:50 +02004734 } else if (node->nodetype == LYS_LEAFLIST && ((struct lys_node_leaflist *)node)->max) {
Pavol Vican855ca622016-09-05 13:07:54 +02004735 if (((struct lys_node_leaflist *)node)->min > ((struct lys_node_leaflist *)node)->max) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02004736 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
4737 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "\"min-elements\" is bigger than \"max-elements\".");
Pavol Vican855ca622016-09-05 13:07:54 +02004738 goto fail;
4739 }
4740 }
4741
4742 /* additional checks */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004743 /* default value with mandatory/min-elements */
Pavol Vican855ca622016-09-05 13:07:54 +02004744 if (node->nodetype == LYS_LEAFLIST) {
4745 llist = (struct lys_node_leaflist *)node;
4746 if (llist->dflt_size && llist->min) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02004747 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, uses, rfn->dflt_size ? "default" : "min-elements", "refine");
4748 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02004749 "The \"min-elements\" statement with non-zero value is forbidden on leaf-lists with the \"default\" statement.");
4750 goto fail;
4751 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004752 } else if (node->nodetype == LYS_LEAF) {
4753 leaf = (struct lys_node_leaf *)node;
4754 if (leaf->dflt && (leaf->flags & LYS_MAND_TRUE)) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02004755 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, uses, rfn->dflt_size ? "default" : "mandatory", "refine");
4756 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004757 "The \"mandatory\" statement is forbidden on leafs with the \"default\" statement.");
4758 goto fail;
4759 }
Pavol Vican855ca622016-09-05 13:07:54 +02004760 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004761
Pavol Vican855ca622016-09-05 13:07:54 +02004762 /* check for mandatory node in default case, first find the closest parent choice to the changed node */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004763 if ((rfn->flags & LYS_MAND_TRUE) || rfn->mod.list.min) {
Pavol Vican855ca622016-09-05 13:07:54 +02004764 for (parent = node->parent;
4765 parent && !(parent->nodetype & (LYS_CHOICE | LYS_GROUPING | LYS_ACTION | LYS_USES));
4766 parent = parent->parent) {
4767 if (parent->nodetype == LYS_CONTAINER && ((struct lys_node_container *)parent)->presence) {
4768 /* stop also on presence containers */
4769 break;
4770 }
4771 }
4772 /* and if it is a choice with the default case, check it for presence of a mandatory node in it */
4773 if (parent && parent->nodetype == LYS_CHOICE && ((struct lys_node_choice *)parent)->dflt) {
4774 if (lyp_check_mandatory_choice(parent)) {
4775 goto fail;
4776 }
4777 }
4778 }
4779 }
4780 free(refine_nodes);
4781
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004782 return EXIT_SUCCESS;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004783
4784fail:
4785 LY_TREE_FOR_SAFE(uses->child, next, iter) {
4786 lys_node_free(iter, NULL, 0);
4787 }
Pavol Vican855ca622016-09-05 13:07:54 +02004788 free(refine_nodes);
Michal Vaskoa86508c2016-08-26 14:30:19 +02004789 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004790}
4791
Radek Krejci83a4bac2017-02-07 15:53:04 +01004792void
4793resolve_identity_backlink_update(struct lys_ident *der, struct lys_ident *base)
Radek Krejci018f1f52016-08-03 16:01:20 +02004794{
4795 int i;
4796
4797 assert(der && base);
4798
Radek Krejci018f1f52016-08-03 16:01:20 +02004799 if (!base->der) {
Radek Krejci85a54be2016-10-20 12:39:56 +02004800 /* create a set for backlinks if it does not exist */
4801 base->der = ly_set_new();
Radek Krejci018f1f52016-08-03 16:01:20 +02004802 }
Radek Krejci85a54be2016-10-20 12:39:56 +02004803 /* store backlink */
4804 ly_set_add(base->der, der, LY_SET_OPT_USEASLIST);
Radek Krejci018f1f52016-08-03 16:01:20 +02004805
Radek Krejci85a54be2016-10-20 12:39:56 +02004806 /* do it recursively */
Radek Krejci018f1f52016-08-03 16:01:20 +02004807 for (i = 0; i < base->base_size; i++) {
Radek Krejci83a4bac2017-02-07 15:53:04 +01004808 resolve_identity_backlink_update(der, base->base[i]);
Radek Krejci018f1f52016-08-03 16:01:20 +02004809 }
Radek Krejci018f1f52016-08-03 16:01:20 +02004810}
4811
Michal Vasko730dfdf2015-08-11 14:48:05 +02004812/**
4813 * @brief Resolve base identity recursively. Does not log.
4814 *
4815 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004816 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004817 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004818 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004819 *
Radek Krejci219fa612016-08-15 10:36:51 +02004820 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on crucial error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004821 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004822static int
Michal Vasko1e62a092015-12-01 12:27:20 +01004823resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Radek Krejci018f1f52016-08-03 16:01:20 +02004824 struct unres_schema *unres, struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004825{
Michal Vaskof02e3742015-08-05 16:27:02 +02004826 uint32_t i, j;
Radek Krejci018f1f52016-08-03 16:01:20 +02004827 struct lys_ident *base = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004828
Radek Krejcicf509982015-12-15 09:22:44 +01004829 assert(ret);
4830
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004831 /* search module */
4832 for (i = 0; i < module->ident_size; i++) {
4833 if (!strcmp(basename, module->ident[i].name)) {
4834
4835 if (!ident) {
4836 /* just search for type, so do not modify anything, just return
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004837 * the base identity pointer */
Radek Krejcicf509982015-12-15 09:22:44 +01004838 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004839 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004840 }
4841
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004842 base = &module->ident[i];
4843 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004844 }
4845 }
4846
4847 /* search submodules */
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004848 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
4849 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
4850 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004851
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004852 if (!ident) {
4853 *ret = &module->inc[j].submodule->ident[i];
4854 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004855 }
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004856
4857 base = &module->inc[j].submodule->ident[i];
4858 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004859 }
4860 }
4861 }
4862
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004863matchfound:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004864 /* we found it somewhere */
Radek Krejcibabbff82016-02-19 13:31:37 +01004865 if (base) {
Radek Krejci018f1f52016-08-03 16:01:20 +02004866 /* is it already completely resolved? */
4867 for (i = 0; i < unres->count; i++) {
Radek Krejciba7b1cc2016-08-08 13:44:43 +02004868 if ((unres->item[i] == base) && (unres->type[i] == UNRES_IDENT)) {
Radek Krejci018f1f52016-08-03 16:01:20 +02004869 /* identity found, but not yet resolved, so do not return it in *res and try it again later */
4870
4871 /* simple check for circular reference,
4872 * the complete check is done as a side effect of using only completely
4873 * resolved identities (previous check of unres content) */
4874 if (ly_strequal((const char *)unres->str_snode[i], ident->name, 1)) {
4875 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, basename, "base");
4876 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Circular reference of \"%s\" identity.", basename);
Radek Krejci219fa612016-08-15 10:36:51 +02004877 return -1;
Radek Krejci018f1f52016-08-03 16:01:20 +02004878 }
4879
Radek Krejci06f64ed2016-08-15 11:07:44 +02004880 return EXIT_FAILURE;
Radek Krejcibabbff82016-02-19 13:31:37 +01004881 }
4882 }
Radek Krejci018f1f52016-08-03 16:01:20 +02004883
Radek Krejcibabbff82016-02-19 13:31:37 +01004884 /* checks done, store the result */
Radek Krejci018f1f52016-08-03 16:01:20 +02004885 *ret = base;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02004886 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004887 }
4888
Radek Krejci219fa612016-08-15 10:36:51 +02004889 /* base not found (maybe a forward reference) */
4890 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004891}
4892
Michal Vasko730dfdf2015-08-11 14:48:05 +02004893/**
4894 * @brief Resolve base identity. Logs directly.
4895 *
4896 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004897 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004898 * @param[in] basename Base name of the identity.
Radek Krejcibabbff82016-02-19 13:31:37 +01004899 * @param[in] parent Either "type" or "identity".
Radek Krejcicf509982015-12-15 09:22:44 +01004900 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004901 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004902 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004903 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004904static int
Michal Vaskof2d43962016-09-02 11:10:16 +02004905resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char *parent,
Radek Krejci018f1f52016-08-03 16:01:20 +02004906 struct lys_type *type, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004907{
4908 const char *name;
Radek Krejci219fa612016-08-15 10:36:51 +02004909 int mod_name_len = 0, rc;
Radek Krejcicf509982015-12-15 09:22:44 +01004910 struct lys_ident *target, **ret;
Radek Krejci4372b4e2016-04-14 17:42:16 +02004911 uint16_t flags;
Radek Krejcicf509982015-12-15 09:22:44 +01004912 struct lys_module *mod;
4913
4914 assert((ident && !type) || (!ident && type));
4915
4916 if (!type) {
4917 /* have ident to resolve */
4918 ret = &target;
4919 flags = ident->flags;
4920 mod = ident->module;
4921 } else {
4922 /* have type to fill */
Michal Vaskof2d43962016-09-02 11:10:16 +02004923 ++type->info.ident.count;
4924 type->info.ident.ref = ly_realloc(type->info.ident.ref, type->info.ident.count * sizeof *type->info.ident.ref);
Radek Krejciaa1303c2017-05-31 13:57:37 +02004925 LY_CHECK_ERR_RETURN(!type->info.ident.ref, LOGMEM, -1);
Michal Vaskof2d43962016-09-02 11:10:16 +02004926
4927 ret = &type->info.ident.ref[type->info.ident.count - 1];
Radek Krejcicf509982015-12-15 09:22:44 +01004928 flags = type->parent->flags;
4929 mod = type->parent->module;
4930 }
Michal Vaskof2006002016-04-21 16:28:15 +02004931 *ret = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004932
4933 /* search for the base identity */
4934 name = strchr(basename, ':');
4935 if (name) {
4936 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02004937 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004938 name++;
4939
Michal Vasko2d851a92015-10-20 16:16:36 +02004940 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004941 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02004942 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004943 }
4944 } else {
4945 name = basename;
4946 }
4947
Radek Krejcic071c542016-01-27 14:57:51 +01004948 /* get module where to search */
4949 module = lys_get_import_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len);
4950 if (!module) {
4951 /* identity refers unknown data model */
Radek Krejci02a04992016-03-17 16:06:37 +01004952 LOGVAL(LYE_INMOD, LY_VLOG_NONE, NULL, basename);
Radek Krejcic071c542016-01-27 14:57:51 +01004953 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004954 }
4955
Radek Krejcic071c542016-01-27 14:57:51 +01004956 /* search in the identified module ... */
Radek Krejci219fa612016-08-15 10:36:51 +02004957 rc = resolve_base_ident_sub(module, ident, name, unres, ret);
4958 if (!rc) {
4959 assert(*ret);
4960
4961 /* check status */
4962 if (lyp_check_status(flags, mod, ident ? ident->name : "of type",
4963 (*ret)->flags, (*ret)->module, (*ret)->name, NULL)) {
4964 rc = -1;
Radek Krejci83a4bac2017-02-07 15:53:04 +01004965 } else if (ident) {
4966 ident->base[ident->base_size++] = *ret;
Radek Krejci9e6af732017-04-27 14:40:25 +02004967 if (lys_main_module(mod)->implemented) {
4968 /* in case of the implemented identity, maintain backlinks to it
4969 * from the base identities to make it available when resolving
4970 * data with the identity values (not implemented identity is not
4971 * allowed as an identityref value). */
4972 resolve_identity_backlink_update(ident, *ret);
4973 }
Radek Krejci219fa612016-08-15 10:36:51 +02004974 }
4975 } else if (rc == EXIT_FAILURE) {
4976 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, parent, basename);
Pavol Vican053a2882016-09-05 14:40:33 +02004977 if (type) {
4978 --type->info.ident.count;
4979 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004980 }
4981
Radek Krejci219fa612016-08-15 10:36:51 +02004982 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004983}
4984
Radek Krejci9e6af732017-04-27 14:40:25 +02004985/*
4986 * 1 - true (der is derived from base)
4987 * 0 - false (der is not derived from base)
4988 */
4989static int
4990search_base_identity(struct lys_ident *der, struct lys_ident *base)
4991{
4992 int i;
4993
4994 if (der == base) {
4995 return 1;
4996 } else {
4997 for(i = 0; i < der->base_size; i++) {
4998 if (search_base_identity(der->base[i], base) == 1) {
4999 return 1;
5000 }
5001 }
5002 }
5003
5004 return 0;
5005}
5006
Michal Vasko730dfdf2015-08-11 14:48:05 +02005007/**
Michal Vaskof39142b2015-10-21 11:40:05 +02005008 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005009 *
Michal Vaskof2d43962016-09-02 11:10:16 +02005010 * @param[in] type Identityref type.
Michal Vaskofb0873c2015-08-21 09:00:07 +02005011 * @param[in] ident_name Identityref name.
Radek Krejciadb57612016-02-16 13:34:34 +01005012 * @param[in] node Node where the identityref is being resolved
Radek Krejci9e6af732017-04-27 14:40:25 +02005013 * @param[in] dflt flag if we are resolving default value in the schema
Michal Vasko730dfdf2015-08-11 14:48:05 +02005014 *
5015 * @return Pointer to the identity resolvent, NULL on error.
5016 */
Radek Krejcia52656e2015-08-05 13:41:50 +02005017struct lys_ident *
Radek Krejci9e6af732017-04-27 14:40:25 +02005018resolve_identref(struct lys_type *type, const char *ident_name, struct lyd_node *node, struct lys_module *mod, int dflt)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005019{
Radek Krejci9e6af732017-04-27 14:40:25 +02005020 const char *mod_name, *name;
5021 int mod_name_len, rc, i, j;
5022 int make_implemented = 0;
Radek Krejci85a54be2016-10-20 12:39:56 +02005023 unsigned int u;
Michal Vaskof2d43962016-09-02 11:10:16 +02005024 struct lys_ident *der, *cur;
Radek Krejci9e6af732017-04-27 14:40:25 +02005025 struct lys_module *imod = NULL, *m;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005026
Radek Krejci9e6af732017-04-27 14:40:25 +02005027 assert(type && ident_name && node && mod);
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005028
Michal Vaskof2d43962016-09-02 11:10:16 +02005029 if (!type || (!type->info.ident.count && !type->der) || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005030 return NULL;
5031 }
5032
Michal Vaskoc633ca02015-08-21 14:03:51 +02005033 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, NULL);
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005034 if (rc < 1) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005035 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005036 return NULL;
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005037 } else if (rc < (signed)strlen(ident_name)) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005038 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[rc], &ident_name[rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005039 return NULL;
5040 }
Radek Krejci9e6af732017-04-27 14:40:25 +02005041
5042 m = lys_main_module(mod); /* shortcut */
5043 if (!mod_name || (!strncmp(mod_name, m->name, mod_name_len) && !m->name[mod_name_len])) {
5044 /* identity is defined in the same module as node */
5045 imod = m;
5046 } else if (dflt) {
5047 /* solving identityref in default definition in schema -
5048 * find the identity's module in the imported modules list to have a correct revision */
5049 for (i = 0; i < mod->imp_size; i++) {
5050 if (!strncmp(mod_name, mod->imp[i].module->name, mod_name_len) && !mod->imp[i].module->name[mod_name_len]) {
5051 imod = mod->imp[i].module;
5052 break;
5053 }
5054 }
5055 } else {
5056 /* solving identityref in data - get the (implemented) module from the context */
5057 u = 0;
5058 while ((imod = (struct lys_module*)ly_ctx_get_module_iter(mod->ctx, &u))) {
5059 if (imod->implemented && !strncmp(mod_name, imod->name, mod_name_len) && !imod->name[mod_name_len]) {
5060 break;
5061 }
5062 }
5063 }
5064 if (!imod) {
5065 goto fail;
5066 }
5067
5068 if (dflt && (m != imod || lys_main_module(type->parent->module) != mod)) {
5069 /* we are solving default statement in schema AND the type is not referencing the same schema,
5070 * THEN, we may need to make the module with the identity implemented, but only if it really
5071 * contains the identity */
5072 if (!imod->implemented) {
5073 cur = NULL;
5074 /* get the identity in the module */
5075 for (i = 0; i < imod->ident_size; i++) {
5076 if (!strcmp(name, imod->ident[i].name)) {
5077 cur = &imod->ident[i];
5078 break;
5079 }
5080 }
5081 if (!cur) {
5082 /* go through includes */
5083 for (j = 0; j < imod->inc_size; j++) {
5084 for (i = 0; i < imod->inc[j].submodule->ident_size; i++) {
5085 if (!strcmp(name, imod->inc[j].submodule->ident[i].name)) {
5086 cur = &imod->inc[j].submodule->ident[i];
5087 break;
5088 }
5089 }
5090 }
5091 if (!cur) {
5092 goto fail;
5093 }
5094 }
5095
5096 /* check that identity is derived from one of the type's base */
5097 while (type->der) {
5098 for (i = 0; i < type->info.ident.count; i++) {
5099 if (search_base_identity(cur, type->info.ident.ref[i])) {
5100 /* cur's base matches the type's base */
5101 make_implemented = 1;
5102 goto match;
5103 }
5104 }
5105 type = &type->der->type;
5106 }
5107 /* matching base not found */
5108 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, "Identity used as identityref value is not implemented.");
5109 goto fail;
5110 }
Radek Krejcif32c5f62016-12-05 09:27:38 +01005111 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02005112
Radek Krejci98a1e2d2017-04-26 14:34:52 +02005113 /* go through all the derived types of all the bases */
Michal Vaskof2d43962016-09-02 11:10:16 +02005114 while (type->der) {
5115 for (i = 0; i < type->info.ident.count; ++i) {
5116 cur = type->info.ident.ref[i];
Michal Vaskofb0873c2015-08-21 09:00:07 +02005117
Radek Krejci85a54be2016-10-20 12:39:56 +02005118 if (cur->der) {
Radek Krejci98a1e2d2017-04-26 14:34:52 +02005119 /* there are some derived identities */
Radek Krejci85a54be2016-10-20 12:39:56 +02005120 for (u = 0; u < cur->der->number; u++) {
5121 der = (struct lys_ident *)cur->der->set.g[u]; /* shortcut */
Radek Krejci9e6af732017-04-27 14:40:25 +02005122 if (!strcmp(der->name, name) && lys_main_module(der->module) == imod) {
Radek Krejci85a54be2016-10-20 12:39:56 +02005123 /* we have match */
5124 cur = der;
5125 goto match;
5126 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005127 }
5128 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005129 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005130 type = &type->der->type;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005131 }
5132
Radek Krejci9e6af732017-04-27 14:40:25 +02005133fail:
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005134 LOGVAL(LYE_INRESOLV, LY_VLOG_LYD, node, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005135 return NULL;
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005136
5137match:
Michal Vaskof2d43962016-09-02 11:10:16 +02005138 for (i = 0; i < cur->iffeature_size; i++) {
5139 if (!resolve_iffeature(&cur->iffeature[i])) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005140 LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, cur->name, node->schema->name);
Michal Vasko51e5c582017-01-19 14:16:39 +01005141 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 +02005142 return NULL;
5143 }
5144 }
Radek Krejci9e6af732017-04-27 14:40:25 +02005145 if (make_implemented) {
5146 LOGVRB("Making \"%s\" module implemented because of identityref default value \"%s\" used in the implemented \"%s\" module",
5147 imod->name, cur->name, mod->name);
5148 if (lys_set_implemented(imod)) {
5149 LOGERR(ly_errno, "Setting the module \"%s\" implemented because of used default identity \"%s\" failed.",
5150 imod->name, cur->name);
5151 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, "Identity used as identityref value is not implemented.");
5152 goto fail;
5153 }
5154 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005155 return cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005156}
5157
Michal Vasko730dfdf2015-08-11 14:48:05 +02005158/**
Michal Vaskobb211122015-08-19 14:03:11 +02005159 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005160 *
Michal Vaskobb211122015-08-19 14:03:11 +02005161 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005162 * @param[in] unres Specific unres item.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005163 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005164 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005165 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005166static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005167resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005168{
Michal Vasko51917552017-03-08 10:21:34 +01005169 int rc, endian_idx;
Radek Krejci010e54b2016-03-15 09:40:34 +01005170 struct lys_node *par_grp;
Michal Vaskoe91afce2015-08-12 12:21:00 +02005171
Michal Vasko51917552017-03-08 10:21:34 +01005172#if __BYTE_ORDER == __LITTLE_ENDIAN
5173 endian_idx = 1;
5174#else
5175 endian_idx = 0;
5176#endif
5177
Radek Krejci6ff885d2017-01-03 14:06:22 +01005178 /* HACK: when a grouping has uses inside, all such uses have to be resolved before the grouping itself is used
5179 * in some uses. When we see such a uses, the grouping's higher byte of the flags member (not used in
5180 * grouping) is used to store number of so far unresolved uses. The grouping cannot be used unless this
5181 * counter is decreased back to 0. To remember that the uses already increased grouping's counter, the
Radek Krejci010e54b2016-03-15 09:40:34 +01005182 * LYS_USESGRP flag is used. */
Michal Vaskodcf98e62016-05-05 17:53:53 +02005183 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 +02005184
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005185 if (!uses->grp) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01005186 rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
5187 if (rc == -1) {
Michal Vasko92981a62016-10-14 10:25:16 +02005188 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005189 return -1;
5190 } else if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005191 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005192 return -1;
5193 } else if (!uses->grp) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005194 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005195 /* hack - in contrast to lys_node, lys_node_grp has bigger nacm field
5196 * (and smaller flags - it uses only a limited set of flags)
5197 */
Michal Vasko51917552017-03-08 10:21:34 +01005198 ((uint8_t*)&((struct lys_node_grp *)par_grp)->flags)[endian_idx]++;
Radek Krejci010e54b2016-03-15 09:40:34 +01005199 uses->flags |= LYS_USESGRP;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005200 }
Michal Vasko92981a62016-10-14 10:25:16 +02005201 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005202 return EXIT_FAILURE;
Michal Vasko12e30842015-08-04 11:54:00 +02005203 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005204 }
5205
Michal Vasko51917552017-03-08 10:21:34 +01005206 if (((uint8_t*)&uses->grp->flags)[endian_idx]) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005207 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Michal Vasko51917552017-03-08 10:21:34 +01005208 ((uint8_t*)&((struct lys_node_grp *)par_grp)->flags)[endian_idx]++;
Radek Krejci010e54b2016-03-15 09:40:34 +01005209 uses->flags |= LYS_USESGRP;
Radek Krejcie00d2312016-08-12 15:27:49 +02005210 } else {
5211 /* instantiate grouping only when it is completely resolved */
5212 uses->grp = NULL;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005213 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005214 return EXIT_FAILURE;
5215 }
5216
Radek Krejci48464ed2016-03-17 15:44:09 +01005217 rc = resolve_uses(uses, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005218 if (!rc) {
5219 /* decrease unres count only if not first try */
Radek Krejci010e54b2016-03-15 09:40:34 +01005220 if (par_grp && (uses->flags & LYS_USESGRP)) {
Michal Vasko51917552017-03-08 10:21:34 +01005221 if (!((uint8_t*)&((struct lys_node_grp *)par_grp)->flags)[endian_idx]) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005222 LOGINT;
5223 return -1;
5224 }
Michal Vasko51917552017-03-08 10:21:34 +01005225 ((uint8_t*)&((struct lys_node_grp *)par_grp)->flags)[endian_idx]--;
Radek Krejci010e54b2016-03-15 09:40:34 +01005226 uses->flags &= ~LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005227 }
Radek Krejcicf509982015-12-15 09:22:44 +01005228
5229 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005230 if (lyp_check_status(uses->flags, uses->module, "of uses",
Radek Krejciadb57612016-02-16 13:34:34 +01005231 uses->grp->flags, uses->grp->module, uses->grp->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005232 (struct lys_node *)uses)) {
Radek Krejcicf509982015-12-15 09:22:44 +01005233 return -1;
5234 }
5235
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005236 return EXIT_SUCCESS;
5237 }
5238
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005239 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005240}
5241
Michal Vasko730dfdf2015-08-11 14:48:05 +02005242/**
Michal Vasko9957e592015-08-17 15:04:09 +02005243 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005244 *
Michal Vaskobb211122015-08-19 14:03:11 +02005245 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005246 * @param[in] keys_str Keys node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005247 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005248 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005249 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005250static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005251resolve_list_keys(struct lys_node_list *list, const char *keys_str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005252{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005253 int i, len, rc;
Michal Vasko4f0dad02016-02-15 14:08:23 +01005254 const char *value;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005255
5256 for (i = 0; i < list->keys_size; ++i) {
Radek Krejci5c08a992016-11-02 13:30:04 +01005257 if (!list->child) {
5258 /* no child, possible forward reference */
5259 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
5260 return EXIT_FAILURE;
5261 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005262 /* get the key name */
5263 if ((value = strpbrk(keys_str, " \t\n"))) {
5264 len = value - keys_str;
5265 while (isspace(value[0])) {
5266 value++;
5267 }
5268 } else {
5269 len = strlen(keys_str);
5270 }
5271
Michal Vaskobb520442017-05-23 10:55:18 +02005272 rc = lys_getnext_data(lys_node_module((struct lys_node *)list), (struct lys_node *)list, keys_str, len, LYS_LEAF,
5273 (const struct lys_node **)&list->keys[i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005274 if (rc) {
Michal Vasko7a55bea2016-05-02 14:51:20 +02005275 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
5276 return EXIT_FAILURE;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005277 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005278
Radek Krejci48464ed2016-03-17 15:44:09 +01005279 if (check_key(list, i, keys_str, len)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005280 /* check_key logs */
5281 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005282 }
5283
Radek Krejcicf509982015-12-15 09:22:44 +01005284 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005285 if (lyp_check_status(list->flags, list->module, list->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005286 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
5287 (struct lys_node *)list->keys[i])) {
Radek Krejcicf509982015-12-15 09:22:44 +01005288 return -1;
5289 }
5290
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005291 /* prepare for next iteration */
5292 while (value && isspace(value[0])) {
5293 value++;
5294 }
5295 keys_str = value;
5296 }
5297
Michal Vaskof02e3742015-08-05 16:27:02 +02005298 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005299}
5300
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005301/**
Michal Vaskobf19d252015-10-08 15:39:17 +02005302 * @brief Resolve (check) all must conditions of \p node.
5303 * Logs directly.
5304 *
5305 * @param[in] node Data node with optional must statements.
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005306 * @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 +02005307 *
5308 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
5309 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005310static int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005311resolve_must(struct lyd_node *node, int inout_parent, int ignore_fail)
Michal Vaskof02e3742015-08-05 16:27:02 +02005312{
Michal Vasko3cfa3182017-01-17 10:00:58 +01005313 int node_flags;
Michal Vaskobf19d252015-10-08 15:39:17 +02005314 uint8_t i, must_size;
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005315 struct lys_node *schema;
Michal Vaskobf19d252015-10-08 15:39:17 +02005316 struct lys_restr *must;
5317 struct lyxp_set set;
5318
5319 assert(node);
5320 memset(&set, 0, sizeof set);
5321
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005322 if (inout_parent) {
5323 for (schema = lys_parent(node->schema);
5324 schema && (schema->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES));
5325 schema = lys_parent(schema));
5326 if (!schema || !(schema->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5327 LOGINT;
5328 return -1;
5329 }
5330 must_size = ((struct lys_node_inout *)schema)->must_size;
5331 must = ((struct lys_node_inout *)schema)->must;
5332
Michal Vasko3cfa3182017-01-17 10:00:58 +01005333 node_flags = schema->flags;
5334
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005335 /* context node is the RPC/action */
5336 node = node->parent;
5337 if (!(node->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
5338 LOGINT;
5339 return -1;
5340 }
5341 } else {
5342 switch (node->schema->nodetype) {
5343 case LYS_CONTAINER:
5344 must_size = ((struct lys_node_container *)node->schema)->must_size;
5345 must = ((struct lys_node_container *)node->schema)->must;
5346 break;
5347 case LYS_LEAF:
5348 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
5349 must = ((struct lys_node_leaf *)node->schema)->must;
5350 break;
5351 case LYS_LEAFLIST:
5352 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
5353 must = ((struct lys_node_leaflist *)node->schema)->must;
5354 break;
5355 case LYS_LIST:
5356 must_size = ((struct lys_node_list *)node->schema)->must_size;
5357 must = ((struct lys_node_list *)node->schema)->must;
5358 break;
5359 case LYS_ANYXML:
5360 case LYS_ANYDATA:
5361 must_size = ((struct lys_node_anydata *)node->schema)->must_size;
5362 must = ((struct lys_node_anydata *)node->schema)->must;
5363 break;
5364 case LYS_NOTIF:
5365 must_size = ((struct lys_node_notif *)node->schema)->must_size;
5366 must = ((struct lys_node_notif *)node->schema)->must;
5367 break;
5368 default:
5369 must_size = 0;
5370 break;
5371 }
Michal Vasko3cfa3182017-01-17 10:00:58 +01005372
5373 node_flags = node->schema->flags;
Michal Vaskobf19d252015-10-08 15:39:17 +02005374 }
5375
5376 for (i = 0; i < must_size; ++i) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005377 if (lyxp_eval(must[i].expr, node, LYXP_NODE_ELEM, lyd_node_module(node), &set, LYXP_MUST)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02005378 return -1;
5379 }
5380
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005381 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_MUST);
Michal Vaskobf19d252015-10-08 15:39:17 +02005382
Michal Vasko8146d4c2016-05-09 15:50:29 +02005383 if (!set.val.bool) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01005384 if ((ignore_fail == 1) || ((node_flags & LYS_XPATH_DEP) && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005385 LOGVRB("Must condition \"%s\" not satisfied, but it is not required.", must[i].expr);
5386 } else {
5387 LOGVAL(LYE_NOMUST, LY_VLOG_LYD, node, must[i].expr);
5388 if (must[i].emsg) {
Michal Vasko51e5c582017-01-19 14:16:39 +01005389 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, must[i].emsg);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005390 }
5391 if (must[i].eapptag) {
5392 strncpy(((struct ly_err *)&ly_errno)->apptag, must[i].eapptag, LY_APPTAG_LEN - 1);
5393 }
5394 return 1;
Michal Vasko6ac68282016-04-11 10:56:47 +02005395 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005396 }
5397 }
5398
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005399 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02005400}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005401
Michal Vaskobf19d252015-10-08 15:39:17 +02005402/**
Michal Vasko508a50d2016-09-07 14:50:33 +02005403 * @brief Resolve (find) when condition schema context node. Does not log.
5404 *
5405 * @param[in] schema Schema node with the when condition.
5406 * @param[out] ctx_snode When schema context node.
5407 * @param[out] ctx_snode_type Schema context node type.
5408 */
5409void
5410resolve_when_ctx_snode(const struct lys_node *schema, struct lys_node **ctx_snode, enum lyxp_node_type *ctx_snode_type)
5411{
5412 const struct lys_node *sparent;
5413
5414 /* find a not schema-only node */
5415 *ctx_snode_type = LYXP_NODE_ELEM;
5416 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
5417 if (schema->nodetype == LYS_AUGMENT) {
5418 sparent = ((struct lys_node_augment *)schema)->target;
5419 } else {
5420 sparent = schema->parent;
5421 }
5422 if (!sparent) {
5423 /* context node is the document root (fake root in our case) */
5424 if (schema->flags & LYS_CONFIG_W) {
5425 *ctx_snode_type = LYXP_NODE_ROOT_CONFIG;
5426 } else {
Michal Vaskob94a5e42016-09-08 14:01:56 +02005427 *ctx_snode_type = LYXP_NODE_ROOT;
Michal Vasko508a50d2016-09-07 14:50:33 +02005428 }
Michal Vasko2d2aec12016-09-08 11:42:50 +02005429 /* we need the first top-level sibling, but no uses or groupings */
Michal Vaskob94a5e42016-09-08 14:01:56 +02005430 schema = lys_getnext(NULL, NULL, lys_node_module(schema), 0);
Michal Vasko508a50d2016-09-07 14:50:33 +02005431 break;
5432 }
5433 schema = sparent;
5434 }
5435
5436 *ctx_snode = (struct lys_node *)schema;
5437}
5438
5439/**
Michal Vaskocf024702015-10-08 15:01:42 +02005440 * @brief Resolve (find) when condition context node. Does not log.
5441 *
5442 * @param[in] node Data node, whose conditional definition is being decided.
Michal Vasko508a50d2016-09-07 14:50:33 +02005443 * @param[in] schema Schema node with the when condition.
Michal Vaskoa59495d2016-08-22 09:18:58 +02005444 * @param[out] ctx_node Context node.
5445 * @param[out] ctx_node_type Context node type.
Michal Vaskocf024702015-10-08 15:01:42 +02005446 *
Michal Vaskoa59495d2016-08-22 09:18:58 +02005447 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vaskocf024702015-10-08 15:01:42 +02005448 */
Michal Vaskoa59495d2016-08-22 09:18:58 +02005449static int
5450resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema, struct lyd_node **ctx_node,
5451 enum lyxp_node_type *ctx_node_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005452{
Michal Vaskocf024702015-10-08 15:01:42 +02005453 struct lyd_node *parent;
5454 struct lys_node *sparent;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005455 enum lyxp_node_type node_type;
Michal Vaskocf024702015-10-08 15:01:42 +02005456 uint16_t i, data_depth, schema_depth;
5457
Michal Vasko508a50d2016-09-07 14:50:33 +02005458 resolve_when_ctx_snode(schema, &schema, &node_type);
Michal Vaskocf024702015-10-08 15:01:42 +02005459
Michal Vaskofe989752016-09-08 08:47:26 +02005460 if (node_type == LYXP_NODE_ELEM) {
5461 /* standard element context node */
5462 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
5463 for (sparent = schema, schema_depth = 0;
5464 sparent;
5465 sparent = (sparent->nodetype == LYS_AUGMENT ? ((struct lys_node_augment *)sparent)->target : sparent->parent)) {
5466 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_NOTIF | LYS_RPC)) {
5467 ++schema_depth;
5468 }
Michal Vaskocf024702015-10-08 15:01:42 +02005469 }
Michal Vaskofe989752016-09-08 08:47:26 +02005470 if (data_depth < schema_depth) {
5471 return -1;
5472 }
Michal Vaskocf024702015-10-08 15:01:42 +02005473
Michal Vasko956e8542016-08-26 09:43:35 +02005474 /* find the corresponding data node */
5475 for (i = 0; i < data_depth - schema_depth; ++i) {
5476 node = node->parent;
5477 }
Michal Vaskoa59495d2016-08-22 09:18:58 +02005478 if (node->schema != schema) {
5479 return -1;
5480 }
Michal Vaskofe989752016-09-08 08:47:26 +02005481 } else {
5482 /* root context node */
5483 while (node->parent) {
5484 node = node->parent;
5485 }
5486 while (node->prev->next) {
5487 node = node->prev;
5488 }
Michal Vaskocf024702015-10-08 15:01:42 +02005489 }
5490
Michal Vaskoa59495d2016-08-22 09:18:58 +02005491 *ctx_node = node;
5492 *ctx_node_type = node_type;
5493 return EXIT_SUCCESS;
Michal Vaskocf024702015-10-08 15:01:42 +02005494}
5495
Michal Vasko76c3bd32016-08-24 16:02:52 +02005496/**
5497 * @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 +01005498 * The context node is adjusted if needed.
Michal Vasko76c3bd32016-08-24 16:02:52 +02005499 *
5500 * @param[in] snode Schema node, whose children instances need to be unlinked.
5501 * @param[in,out] node Data siblings where to look for the children of \p snode. If it is unlinked,
5502 * it is moved to point to another sibling still in the original tree.
5503 * @param[in,out] ctx_node When context node, adjusted if needed.
5504 * @param[in] ctx_node_type Context node type, just for information to detect invalid situations.
5505 * @param[out] unlinked_nodes Unlinked siblings. Can be safely appended to \p node afterwards.
5506 * Ordering may change, but there will be no semantic change.
5507 *
5508 * @return EXIT_SUCCESS on success, -1 on error.
5509 */
5510static int
5511resolve_when_unlink_nodes(struct lys_node *snode, struct lyd_node **node, struct lyd_node **ctx_node,
5512 enum lyxp_node_type ctx_node_type, struct lyd_node **unlinked_nodes)
5513{
5514 struct lyd_node *next, *elem;
Michal Vaskoeb81fb72017-02-06 12:11:08 +01005515 const struct lys_node *slast;
Michal Vasko76c3bd32016-08-24 16:02:52 +02005516
5517 switch (snode->nodetype) {
5518 case LYS_AUGMENT:
5519 case LYS_USES:
5520 case LYS_CHOICE:
5521 case LYS_CASE:
Michal Vaskoeb81fb72017-02-06 12:11:08 +01005522 slast = NULL;
Michal Vasko24476fa2017-03-08 12:33:48 +01005523 while ((slast = lys_getnext(slast, snode, NULL, LYS_GETNEXT_PARENTUSES))) {
Michal Vaskoeb81fb72017-02-06 12:11:08 +01005524 if (slast->nodetype & (LYS_ACTION | LYS_NOTIF)) {
5525 continue;
5526 }
5527
5528 if (resolve_when_unlink_nodes((struct lys_node *)slast, node, ctx_node, ctx_node_type, unlinked_nodes)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005529 return -1;
5530 }
5531 }
5532 break;
5533 case LYS_CONTAINER:
5534 case LYS_LIST:
5535 case LYS_LEAF:
5536 case LYS_LEAFLIST:
5537 case LYS_ANYXML:
5538 case LYS_ANYDATA:
5539 LY_TREE_FOR_SAFE(lyd_first_sibling(*node), next, elem) {
5540 if (elem->schema == snode) {
5541
5542 if (elem == *ctx_node) {
5543 /* We are going to unlink our context node! This normally cannot happen,
5544 * but we use normal top-level data nodes for faking a document root node,
5545 * so if this is the context node, we just use the next top-level node.
5546 * Additionally, it can even happen that there are no top-level data nodes left,
5547 * all were unlinked, so in this case we pass NULL as the context node/data tree,
5548 * lyxp_eval() can handle this special situation.
5549 */
5550 if (ctx_node_type == LYXP_NODE_ELEM) {
5551 LOGINT;
5552 return -1;
5553 }
5554
5555 if (elem->prev == elem) {
5556 /* unlinking last top-level element, use an empty data tree */
5557 *ctx_node = NULL;
5558 } else {
5559 /* in this case just use the previous/last top-level data node */
5560 *ctx_node = elem->prev;
5561 }
5562 } else if (elem == *node) {
5563 /* We are going to unlink the currently processed node. This does not matter that
5564 * much, but we would lose access to the original data tree, so just move our
5565 * pointer somewhere still inside it.
5566 */
5567 if ((*node)->prev != *node) {
5568 *node = (*node)->prev;
5569 } else {
5570 /* the processed node with sibings were all unlinked, oh well */
5571 *node = NULL;
5572 }
5573 }
5574
5575 /* temporarily unlink the node */
Michal Vasko2bce30c2017-02-06 12:16:39 +01005576 lyd_unlink_internal(elem, 0);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005577 if (*unlinked_nodes) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005578 if (lyd_insert_after((*unlinked_nodes)->prev, elem)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005579 LOGINT;
5580 return -1;
5581 }
5582 } else {
5583 *unlinked_nodes = elem;
5584 }
5585
5586 if (snode->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_ANYDATA)) {
5587 /* there can be only one instance */
5588 break;
5589 }
5590 }
5591 }
5592 break;
5593 default:
5594 LOGINT;
5595 return -1;
5596 }
5597
5598 return EXIT_SUCCESS;
5599}
5600
5601/**
5602 * @brief Relink the unlinked nodes back.
5603 *
5604 * @param[in] node Data node to link the nodes back to. It can actually be the adjusted context node,
5605 * we simply need a sibling from the original data tree.
5606 * @param[in] unlinked_nodes Unlinked nodes to relink to \p node.
5607 * @param[in] ctx_node_type Context node type to distinguish between \p node being the parent
5608 * or the sibling of \p unlinked_nodes.
5609 *
5610 * @return EXIT_SUCCESS on success, -1 on error.
5611 */
5612static int
5613resolve_when_relink_nodes(struct lyd_node *node, struct lyd_node *unlinked_nodes, enum lyxp_node_type ctx_node_type)
5614{
5615 struct lyd_node *elem;
5616
5617 LY_TREE_FOR_SAFE(unlinked_nodes, unlinked_nodes, elem) {
Michal Vasko2bce30c2017-02-06 12:16:39 +01005618 lyd_unlink_internal(elem, 0);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005619 if (ctx_node_type == LYXP_NODE_ELEM) {
Michal Vasko2bce30c2017-02-06 12:16:39 +01005620 if (lyd_insert_common(node, NULL, elem, 0)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005621 return -1;
5622 }
5623 } else {
Michal Vasko2bce30c2017-02-06 12:16:39 +01005624 if (lyd_insert_nextto(node, elem, 0, 0)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005625 return -1;
5626 }
5627 }
5628 }
5629
5630 return EXIT_SUCCESS;
5631}
5632
Radek Krejci03b71f72016-03-16 11:10:09 +01005633int
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005634resolve_applies_must(const struct lyd_node *node)
Radek Krejci01696bf2016-03-18 13:19:36 +01005635{
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005636 int ret = 0;
5637 uint8_t must_size;
5638 struct lys_node *schema, *iter;
Radek Krejci46165822016-08-26 14:06:27 +02005639
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005640 assert(node);
5641
5642 schema = node->schema;
5643
5644 /* their own must */
Radek Krejci46165822016-08-26 14:06:27 +02005645 switch (schema->nodetype) {
Radek Krejci01696bf2016-03-18 13:19:36 +01005646 case LYS_CONTAINER:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005647 must_size = ((struct lys_node_container *)schema)->must_size;
5648 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005649 case LYS_LEAF:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005650 must_size = ((struct lys_node_leaf *)schema)->must_size;
5651 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005652 case LYS_LEAFLIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005653 must_size = ((struct lys_node_leaflist *)schema)->must_size;
5654 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005655 case LYS_LIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005656 must_size = ((struct lys_node_list *)schema)->must_size;
5657 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005658 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02005659 case LYS_ANYDATA:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005660 must_size = ((struct lys_node_anydata *)schema)->must_size;
5661 break;
5662 case LYS_NOTIF:
5663 must_size = ((struct lys_node_notif *)schema)->must_size;
5664 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005665 default:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005666 must_size = 0;
5667 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005668 }
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005669
5670 if (must_size) {
5671 ++ret;
5672 }
5673
5674 /* schema may be a direct data child of input/output with must (but it must be first, it needs to be evaluated only once) */
5675 if (!node->prev->next) {
5676 for (iter = lys_parent(schema); iter && (iter->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES)); iter = lys_parent(iter));
5677 if (iter && (iter->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5678 ret += 0x2;
5679 }
5680 }
5681
5682 return ret;
Radek Krejci01696bf2016-03-18 13:19:36 +01005683}
5684
5685int
Radek Krejci46165822016-08-26 14:06:27 +02005686resolve_applies_when(const struct lys_node *schema, int mode, const struct lys_node *stop)
Radek Krejci03b71f72016-03-16 11:10:09 +01005687{
Radek Krejci46165822016-08-26 14:06:27 +02005688 const struct lys_node *parent;
Radek Krejci03b71f72016-03-16 11:10:09 +01005689
Radek Krejci46165822016-08-26 14:06:27 +02005690 assert(schema);
Radek Krejci03b71f72016-03-16 11:10:09 +01005691
Radek Krejci46165822016-08-26 14:06:27 +02005692 if (!(schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)schema)->when)) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005693 return 1;
5694 }
5695
Radek Krejci46165822016-08-26 14:06:27 +02005696 parent = schema;
Radek Krejci03b71f72016-03-16 11:10:09 +01005697 goto check_augment;
5698
Radek Krejci46165822016-08-26 14:06:27 +02005699 while (parent) {
5700 /* stop conditions */
5701 if (!mode) {
5702 /* stop on node that can be instantiated in data tree */
5703 if (!(parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
5704 break;
5705 }
5706 } else {
5707 /* stop on the specified node */
5708 if (parent == stop) {
5709 break;
5710 }
5711 }
5712
5713 if (((const struct lys_node_uses *)parent)->when) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005714 return 1;
5715 }
5716check_augment:
5717
5718 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) &&
Radek Krejci46165822016-08-26 14:06:27 +02005719 (((const struct lys_node_augment *)parent->parent)->when))) {
Michal Vaskoe3655562016-08-24 15:56:17 +02005720 return 1;
Radek Krejci03b71f72016-03-16 11:10:09 +01005721 }
5722 parent = lys_parent(parent);
5723 }
5724
5725 return 0;
5726}
5727
Michal Vaskocf024702015-10-08 15:01:42 +02005728/**
5729 * @brief Resolve (check) all when conditions relevant for \p node.
5730 * Logs directly.
5731 *
5732 * @param[in] node Data node, whose conditional reference, if such, is being decided.
Michal Vaskocf024702015-10-08 15:01:42 +02005733 *
Radek Krejci03b71f72016-03-16 11:10:09 +01005734 * @return
5735 * -1 - error, ly_errno is set
5736 * 0 - true "when" statement
Radek Krejci46165822016-08-26 14:06:27 +02005737 * 0, ly_vecode = LYVE_NOWHEN - false "when" statement
Radek Krejci03b71f72016-03-16 11:10:09 +01005738 * 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 +02005739 */
Radek Krejci46165822016-08-26 14:06:27 +02005740int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005741resolve_when(struct lyd_node *node, int *result, int ignore_fail)
Michal Vaskocf024702015-10-08 15:01:42 +02005742{
Michal Vasko76c3bd32016-08-24 16:02:52 +02005743 struct lyd_node *ctx_node = NULL, *unlinked_nodes, *tmp_node;
Michal Vasko90fc2a32016-08-24 15:58:58 +02005744 struct lys_node *sparent;
Michal Vaskocf024702015-10-08 15:01:42 +02005745 struct lyxp_set set;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005746 enum lyxp_node_type ctx_node_type;
Radek Krejci51093642016-03-29 10:14:59 +02005747 int rc = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02005748
5749 assert(node);
5750 memset(&set, 0, sizeof set);
5751
Michal Vasko78d97e22017-02-21 09:54:38 +01005752 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC | LYS_ACTION)) && (((struct lys_node_container *)node->schema)->when)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005753 /* make the node dummy for the evaluation */
5754 node->validity |= LYD_VAL_INUSE;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005755 rc = lyxp_eval(((struct lys_node_container *)node->schema)->when->cond, node, LYXP_NODE_ELEM, lyd_node_module(node),
5756 &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005757 node->validity &= ~LYD_VAL_INUSE;
Radek Krejci03b71f72016-03-16 11:10:09 +01005758 if (rc) {
5759 if (rc == 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005760 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005761 }
Radek Krejci51093642016-03-29 10:14:59 +02005762 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005763 }
5764
Radek Krejci03b71f72016-03-16 11:10:09 +01005765 /* set boolean result of the condition */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005766 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02005767 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01005768 node->when_status |= LYD_WHEN_FALSE;
Michal Vasko3cfa3182017-01-17 10:00:58 +01005769 if ((ignore_fail == 1) || ((node->schema->flags & LYS_XPATH_DEP) && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005770 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
5771 ((struct lys_node_container *)node->schema)->when->cond);
5772 } else {
5773 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
5774 goto cleanup;
5775 }
Michal Vaskocf024702015-10-08 15:01:42 +02005776 }
Radek Krejci51093642016-03-29 10:14:59 +02005777
5778 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005779 lyxp_set_cast(&set, LYXP_SET_EMPTY, node, lyd_node_module(node), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005780 }
5781
Michal Vasko90fc2a32016-08-24 15:58:58 +02005782 sparent = node->schema;
Michal Vaskocf024702015-10-08 15:01:42 +02005783 goto check_augment;
5784
5785 /* check when in every schema node that affects node */
Michal Vasko90fc2a32016-08-24 15:58:58 +02005786 while (sparent && (sparent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
5787 if (((struct lys_node_uses *)sparent)->when) {
Michal Vaskocf024702015-10-08 15:01:42 +02005788 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005789 rc = resolve_when_ctx_node(node, sparent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02005790 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02005791 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02005792 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005793 }
5794 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02005795
5796 unlinked_nodes = NULL;
5797 /* we do not want our node pointer to change */
5798 tmp_node = node;
5799 rc = resolve_when_unlink_nodes(sparent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
5800 if (rc) {
5801 goto cleanup;
5802 }
5803
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005804 rc = lyxp_eval(((struct lys_node_uses *)sparent)->when->cond, ctx_node, ctx_node_type, lys_node_module(sparent),
5805 &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005806
5807 if (unlinked_nodes && ctx_node) {
5808 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
5809 rc = -1;
5810 goto cleanup;
5811 }
5812 }
5813
Radek Krejci03b71f72016-03-16 11:10:09 +01005814 if (rc) {
5815 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005816 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005817 }
Radek Krejci51093642016-03-29 10:14:59 +02005818 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005819 }
5820
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005821 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02005822 if (!set.val.bool) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01005823 if ((ignore_fail == 1) || ((sparent->flags & LYS_XPATH_DEP) || (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005824 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
5825 ((struct lys_node_uses *)sparent)->when->cond);
5826 } else {
Michal Vasko2cb18e72017-03-28 14:46:33 +02005827 node->when_status |= LYD_WHEN_FALSE;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005828 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
5829 goto cleanup;
5830 }
Michal Vaskocf024702015-10-08 15:01:42 +02005831 }
Radek Krejci51093642016-03-29 10:14:59 +02005832
5833 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005834 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005835 }
5836
5837check_augment:
Michal Vasko90fc2a32016-08-24 15:58:58 +02005838 if ((sparent->parent && (sparent->parent->nodetype == LYS_AUGMENT) && (((struct lys_node_augment *)sparent->parent)->when))) {
Michal Vaskocf024702015-10-08 15:01:42 +02005839 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005840 rc = resolve_when_ctx_node(node, sparent->parent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02005841 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02005842 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02005843 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005844 }
5845 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02005846
5847 unlinked_nodes = NULL;
5848 tmp_node = node;
5849 rc = resolve_when_unlink_nodes(sparent->parent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
5850 if (rc) {
5851 goto cleanup;
5852 }
5853
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005854 rc = lyxp_eval(((struct lys_node_augment *)sparent->parent)->when->cond, ctx_node, ctx_node_type,
5855 lys_node_module(sparent->parent), &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005856
5857 /* reconnect nodes, if ctx_node is NULL then all the nodes were unlinked, but linked together,
5858 * so the tree did not actually change and there is nothing for us to do
5859 */
5860 if (unlinked_nodes && ctx_node) {
5861 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
5862 rc = -1;
5863 goto cleanup;
5864 }
5865 }
5866
Radek Krejci03b71f72016-03-16 11:10:09 +01005867 if (rc) {
5868 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005869 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005870 }
Radek Krejci51093642016-03-29 10:14:59 +02005871 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005872 }
5873
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005874 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent->parent), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02005875 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01005876 node->when_status |= LYD_WHEN_FALSE;
Michal Vasko3cfa3182017-01-17 10:00:58 +01005877 if ((ignore_fail == 1) || ((sparent->parent->flags & LYS_XPATH_DEP) && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005878 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
Michal Vasko3cfa3182017-01-17 10:00:58 +01005879 ((struct lys_node_augment *)sparent->parent)->when->cond);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005880 } else {
5881 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
5882 goto cleanup;
5883 }
Michal Vaskocf024702015-10-08 15:01:42 +02005884 }
Radek Krejci51093642016-03-29 10:14:59 +02005885
5886 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005887 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent->parent), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005888 }
5889
Michal Vasko90fc2a32016-08-24 15:58:58 +02005890 sparent = lys_parent(sparent);
Michal Vaskocf024702015-10-08 15:01:42 +02005891 }
5892
Radek Krejci0b7704f2016-03-18 12:16:14 +01005893 node->when_status |= LYD_WHEN_TRUE;
Radek Krejci03b71f72016-03-16 11:10:09 +01005894
Radek Krejci51093642016-03-29 10:14:59 +02005895cleanup:
Radek Krejci51093642016-03-29 10:14:59 +02005896 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005897 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node ? ctx_node : node, NULL, 0);
Radek Krejci51093642016-03-29 10:14:59 +02005898
Radek Krejci46165822016-08-26 14:06:27 +02005899 if (result) {
5900 if (node->when_status & LYD_WHEN_TRUE) {
5901 *result = 1;
5902 } else {
5903 *result = 0;
5904 }
5905 }
5906
Radek Krejci51093642016-03-29 10:14:59 +02005907 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005908}
5909
Radek Krejcicbb473e2016-09-16 14:48:32 +02005910static int
5911check_leafref_features(struct lys_type *type)
5912{
5913 struct lys_node *iter;
5914 struct ly_set *src_parents, *trg_parents, *features;
5915 unsigned int i, j, size, x;
5916 int ret = EXIT_SUCCESS;
5917
5918 assert(type->parent);
5919
5920 src_parents = ly_set_new();
5921 trg_parents = ly_set_new();
5922 features = ly_set_new();
5923
5924 /* get parents chain of source (leafref) */
Radek Krejciecda01a2017-04-05 15:44:27 +02005925 for (iter = (struct lys_node *)type->parent; iter; iter = lys_parent(iter)) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02005926 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
5927 continue;
5928 }
5929 ly_set_add(src_parents, iter, LY_SET_OPT_USEASLIST);
5930 }
5931 /* get parents chain of target */
Radek Krejciecda01a2017-04-05 15:44:27 +02005932 for (iter = (struct lys_node *)type->info.lref.target; iter; iter = lys_parent(iter)) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02005933 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
5934 continue;
5935 }
5936 ly_set_add(trg_parents, iter, LY_SET_OPT_USEASLIST);
5937 }
5938
5939 /* compare the features used in if-feature statements in the rest of both
5940 * chains of parents. The set of features used for target must be a subset
5941 * of features used for the leafref. This is not a perfect, we should compare
5942 * the truth tables but it could require too much resources, so we simplify that */
5943 for (i = 0; i < src_parents->number; i++) {
5944 iter = src_parents->set.s[i]; /* shortcut */
5945 if (!iter->iffeature_size) {
5946 continue;
5947 }
5948 for (j = 0; j < iter->iffeature_size; j++) {
5949 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
5950 for (; size; size--) {
5951 if (!iter->iffeature[j].features[size - 1]) {
5952 /* not yet resolved feature, postpone this check */
5953 ret = EXIT_FAILURE;
5954 goto cleanup;
5955 }
5956 ly_set_add(features, iter->iffeature[j].features[size - 1], 0);
5957 }
5958 }
5959 }
5960 x = features->number;
5961 for (i = 0; i < trg_parents->number; i++) {
5962 iter = trg_parents->set.s[i]; /* shortcut */
5963 if (!iter->iffeature_size) {
5964 continue;
5965 }
5966 for (j = 0; j < iter->iffeature_size; j++) {
5967 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
5968 for (; size; size--) {
5969 if (!iter->iffeature[j].features[size - 1]) {
5970 /* not yet resolved feature, postpone this check */
5971 ret = EXIT_FAILURE;
5972 goto cleanup;
5973 }
5974 if ((unsigned int)ly_set_add(features, iter->iffeature[j].features[size - 1], 0) >= x) {
5975 /* the feature is not present in features set of target's parents chain */
5976 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, type->parent, "leafref", type->info.lref.path);
Michal Vasko51e5c582017-01-19 14:16:39 +01005977 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Radek Krejcicbb473e2016-09-16 14:48:32 +02005978 "Leafref is not conditional based on \"%s\" feature as its target.",
5979 iter->iffeature[j].features[size - 1]->name);
5980 ret = -1;
5981 goto cleanup;
5982 }
5983 }
5984 }
5985 }
5986
5987cleanup:
5988 ly_set_free(features);
5989 ly_set_free(src_parents);
5990 ly_set_free(trg_parents);
5991
5992 return ret;
5993}
5994
Michal Vaskoe1c7a822017-06-30 13:15:18 +02005995static int
5996check_type_union_leafref(struct lys_type *type)
5997{
5998 uint8_t i;
5999
6000 if ((type->base == LY_TYPE_UNION) && type->info.uni.count) {
6001 /* go through unions and look for leafref */
6002 for (i = 0; i < type->info.uni.count; ++i) {
6003 switch (type->info.uni.types[i].base) {
6004 case LY_TYPE_LEAFREF:
6005 return 1;
6006 case LY_TYPE_UNION:
6007 if (check_type_union_leafref(&type->info.uni.types[i])) {
6008 return 1;
6009 }
6010 break;
6011 default:
6012 break;
6013 }
6014 }
6015
6016 return 0;
6017 }
6018
6019 /* just inherit the flag value */
6020 return type->der->has_union_leafref;
6021}
6022
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006023/**
Michal Vaskobb211122015-08-19 14:03:11 +02006024 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006025 *
6026 * @param[in] mod Main module.
6027 * @param[in] item Item to resolve. Type determined by \p type.
6028 * @param[in] type Type of the unresolved item.
6029 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02006030 * @param[in] unres Unres schema structure to use.
Michal Vasko769f8032017-01-24 13:11:55 +01006031 * @param[in] final_fail Whether we are just printing errors of the failed unres items.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006032 *
6033 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
6034 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006035static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006036resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Michal Vasko769f8032017-01-24 13:11:55 +01006037 struct unres_schema *unres, int final_fail)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006038{
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006039 /* has_str - whether the str_snode is a string in a dictionary that needs to be freed */
Radek Krejci8d6b7422017-02-03 14:42:13 +01006040 int rc = -1, has_str = 0, parent_type = 0, i, k;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006041 unsigned int j;
Radek Krejci80056d52017-01-05 13:13:33 +01006042 struct lys_node *root, *next, *node, *par_grp;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006043 const char *expr;
Radek Krejci2b999ac2017-01-18 16:22:12 +01006044 uint8_t *u;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006045
Radek Krejcic79c6b12016-07-26 15:11:49 +02006046 struct ly_set *refs, *procs;
6047 struct lys_feature *ref, *feat;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006048 struct lys_ident *ident;
6049 struct lys_type *stype;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006050 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01006051 struct lyxml_elem *yin;
Pavol Vicana0e4e672016-02-24 12:20:04 +01006052 struct yang_type *yang;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006053 struct unres_list_uniq *unique_info;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006054 struct unres_iffeat_data *iff_data;
Radek Krejcie534c132016-11-23 13:32:31 +01006055 struct unres_ext *ext_data;
Radek Krejci80056d52017-01-05 13:13:33 +01006056 struct lys_ext_instance *ext, **extlist;
6057 struct lyext_plugin *eplugin;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006058
6059 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006060 case UNRES_IDENT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006061 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006062 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006063 ident = item;
6064
Radek Krejci018f1f52016-08-03 16:01:20 +02006065 rc = resolve_base_ident(mod, ident, expr, "identity", NULL, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006066 break;
6067 case UNRES_TYPE_IDENTREF:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006068 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006069 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006070 stype = item;
6071
Radek Krejci018f1f52016-08-03 16:01:20 +02006072 rc = resolve_base_ident(mod, NULL, expr, "type", stype, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006073 break;
6074 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02006075 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006076 stype = item;
6077
Michal Vasko1c007172017-03-10 10:20:44 +01006078 rc = resolve_schema_leafref(stype->info.lref.path, node, (const struct lys_node **)&stype->info.lref.target);
6079 if (!rc) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02006080 assert(stype->info.lref.target);
Radek Krejcicbb473e2016-09-16 14:48:32 +02006081 /* check if leafref and its target are under a common if-features */
6082 rc = check_leafref_features(stype);
6083 if (rc) {
6084 break;
6085 }
6086
Michal Vaskobb520442017-05-23 10:55:18 +02006087 if (lys_node_module(node)->implemented) {
6088 /* make all the modules on the path implemented */
6089 for (next = (struct lys_node *)stype->info.lref.target; next; next = lys_parent(next)) {
6090 if (!lys_node_module(next)->implemented) {
6091 if (lys_set_implemented(lys_node_module(next))) {
6092 rc = -1;
6093 break;
6094 }
6095 }
6096 }
6097 if (next) {
6098 break;
6099 }
6100
6101 /* store the backlink from leafref target */
6102 if (lys_leaf_add_leafref_target(stype->info.lref.target, (struct lys_node *)stype->parent)) {
6103 rc = -1;
6104 }
Radek Krejci46c4cd72016-01-21 15:13:52 +01006105 }
Radek Krejci46c4cd72016-01-21 15:13:52 +01006106 }
6107
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006108 break;
Radek Krejci8d6b7422017-02-03 14:42:13 +01006109 case UNRES_TYPE_DER_EXT:
6110 parent_type++;
6111 /* no break */
Radek Krejci3a5501d2016-07-18 22:03:34 +02006112 case UNRES_TYPE_DER_TPDF:
Radek Krejci8d6b7422017-02-03 14:42:13 +01006113 parent_type++;
Radek Krejci3a5501d2016-07-18 22:03:34 +02006114 /* no break */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006115 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01006116 /* parent */
6117 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006118 stype = item;
6119
Michal Vasko88c29542015-11-27 14:57:53 +01006120 /* HACK type->der is temporarily unparsed type statement */
6121 yin = (struct lyxml_elem *)stype->der;
6122 stype->der = NULL;
6123
Pavol Vicana0e4e672016-02-24 12:20:04 +01006124 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6125 yang = (struct yang_type *)yin;
Radek Krejci8d6b7422017-02-03 14:42:13 +01006126 rc = yang_check_type(mod, node, yang, stype, parent_type, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006127
6128 if (rc) {
Pavol Vican8bd72e42016-08-29 09:53:05 +02006129 /* may try again later */
6130 stype->der = (struct lys_tpdf *)yang;
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006131 } else {
6132 /* we need to always be able to free this, it's safe only in this case */
Pavol Vican5f0316a2016-04-05 21:21:11 +02006133 lydict_remove(mod->ctx, yang->name);
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006134 free(yang);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006135 }
6136
Michal Vasko88c29542015-11-27 14:57:53 +01006137 } else {
Radek Krejci8d6b7422017-02-03 14:42:13 +01006138 rc = fill_yin_type(mod, node, yin, stype, parent_type, unres);
Radek Krejci63fc0962017-02-15 13:20:18 +01006139 if (!rc || rc == -1) {
Pavol Vicana0e4e672016-02-24 12:20:04 +01006140 /* we need to always be able to free this, it's safe only in this case */
6141 lyxml_free(mod->ctx, yin);
6142 } else {
6143 /* may try again later, put all back how it was */
6144 stype->der = (struct lys_tpdf *)yin;
6145 }
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006146 }
Radek Krejcic13db382016-08-16 10:52:42 +02006147 if (rc == EXIT_SUCCESS) {
Radek Krejci2c2fce82016-08-01 13:52:26 +02006148 /* it does not make sense to have leaf-list of empty type */
Radek Krejci8d6b7422017-02-03 14:42:13 +01006149 if (!parent_type && node->nodetype == LYS_LEAFLIST && stype->base == LY_TYPE_EMPTY) {
Radek Krejci2c2fce82016-08-01 13:52:26 +02006150 LOGWRN("The leaf-list \"%s\" is of \"empty\" type, which does not make sense.", node->name);
6151 }
Michal Vaskoe1c7a822017-06-30 13:15:18 +02006152
6153 if ((type == UNRES_TYPE_DER_TPDF) && (stype->base == LY_TYPE_UNION)) {
6154 /* fill typedef union leafref flag */
6155 ((struct lys_tpdf *)stype->parent)->has_union_leafref = check_type_union_leafref(stype);
6156 } else if ((type == UNRES_TYPE_DER) && stype->der->has_union_leafref) {
6157 /* copy the type in case it has union leafref flag */
6158 if (lys_copy_union_leafrefs(mod, node, stype, NULL, unres)) {
6159 LOGERR(LY_EINT, "Failed to duplicate type.");
6160 return -1;
6161 }
6162 }
Radek Krejci9b6aad22016-09-20 15:55:51 +02006163 } else if (rc == EXIT_FAILURE && stype->base != LY_TYPE_ERR) {
Radek Krejcic13db382016-08-16 10:52:42 +02006164 /* forward reference - in case the type is in grouping, we have to make the grouping unusable
6165 * by uses statement until the type is resolved. We do that the same way as uses statements inside
6166 * grouping - the grouping's nacm member (not used un grouping) is used to increase the number of
6167 * 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 +02006168 * 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 +02006169 * of the type's base member. */
6170 for (par_grp = node; par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
6171 if (par_grp) {
Radek Krejci6ff885d2017-01-03 14:06:22 +01006172#if __BYTE_ORDER == __LITTLE_ENDIAN
6173 ((uint8_t*)&((struct lys_node_grp *)par_grp)->flags)[1]++;
6174#else
6175 ((uint8_t*)&((struct lys_node_grp *)par_grp)->flags)[0]++;
6176#endif
Radek Krejci9b6aad22016-09-20 15:55:51 +02006177 stype->base = LY_TYPE_ERR;
Radek Krejcic13db382016-08-16 10:52:42 +02006178 }
Radek Krejci2c2fce82016-08-01 13:52:26 +02006179 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006180 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006181 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006182 iff_data = str_snode;
6183 rc = resolve_feature(iff_data->fname, strlen(iff_data->fname), iff_data->node, item);
Radek Krejci9ff0a922016-07-14 13:08:05 +02006184 if (!rc) {
6185 /* success */
Radek Krejci9de2c042016-10-19 16:53:06 +02006186 if (iff_data->infeature) {
6187 /* store backlink into the target feature to allow reverse changes in case of changing feature status */
6188 feat = *((struct lys_feature **)item);
6189 if (!feat->depfeatures) {
6190 feat->depfeatures = ly_set_new();
6191 }
Radek Krejci85a54be2016-10-20 12:39:56 +02006192 ly_set_add(feat->depfeatures, iff_data->node, LY_SET_OPT_USEASLIST);
Radek Krejci9de2c042016-10-19 16:53:06 +02006193 }
6194 /* cleanup temporary data */
Radek Krejcicbb473e2016-09-16 14:48:32 +02006195 lydict_remove(mod->ctx, iff_data->fname);
6196 free(iff_data);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006197 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006198 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006199 case UNRES_FEATURE:
6200 feat = (struct lys_feature *)item;
6201
6202 if (feat->iffeature_size) {
6203 refs = ly_set_new();
6204 procs = ly_set_new();
6205 ly_set_add(procs, feat, 0);
6206
6207 while (procs->number) {
6208 ref = procs->set.g[procs->number - 1];
6209 ly_set_rm_index(procs, procs->number - 1);
6210
6211 for (i = 0; i < ref->iffeature_size; i++) {
6212 resolve_iffeature_getsizes(&ref->iffeature[i], NULL, &j);
6213 for (; j > 0 ; j--) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006214 if (ref->iffeature[i].features[j - 1]) {
Radek Krejcic79c6b12016-07-26 15:11:49 +02006215 if (ref->iffeature[i].features[j - 1] == feat) {
6216 LOGVAL(LYE_CIRC_FEATURES, LY_VLOG_NONE, NULL, feat->name);
6217 goto featurecheckdone;
6218 }
6219
6220 if (ref->iffeature[i].features[j - 1]->iffeature_size) {
6221 k = refs->number;
6222 if (ly_set_add(refs, ref->iffeature[i].features[j - 1], 0) == k) {
6223 /* not yet seen feature, add it for processing */
6224 ly_set_add(procs, ref->iffeature[i].features[j - 1], 0);
6225 }
6226 }
6227 } else {
6228 /* forward reference */
6229 rc = EXIT_FAILURE;
6230 goto featurecheckdone;
6231 }
6232 }
6233
6234 }
6235 }
6236 rc = EXIT_SUCCESS;
6237
6238featurecheckdone:
6239 ly_set_free(refs);
6240 ly_set_free(procs);
6241 }
6242
6243 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006244 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006245 rc = resolve_unres_schema_uses(item, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006246 break;
Radek Krejciab08f0f2017-03-09 16:37:15 +01006247 case UNRES_TYPEDEF_DFLT:
6248 parent_type++;
6249 /* no break */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006250 case UNRES_TYPE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006251 stype = item;
Radek Krejciab08f0f2017-03-09 16:37:15 +01006252 rc = check_default(stype, (const char **)str_snode, mod, parent_type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006253 break;
6254 case UNRES_CHOICE_DFLT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006255 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006256 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006257 choic = item;
6258
Radek Krejcie00d2312016-08-12 15:27:49 +02006259 if (!choic->dflt) {
6260 choic->dflt = resolve_choice_dflt(choic, expr);
6261 }
Michal Vasko7955b362015-09-04 14:18:15 +02006262 if (choic->dflt) {
Radek Krejcie00d2312016-08-12 15:27:49 +02006263 rc = lyp_check_mandatory_choice((struct lys_node *)choic);
Michal Vasko7955b362015-09-04 14:18:15 +02006264 } else {
6265 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006266 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006267 break;
6268 case UNRES_LIST_KEYS:
Radek Krejci5c08a992016-11-02 13:30:04 +01006269 rc = resolve_list_keys(item, ((struct lys_node_list *)item)->keys_str);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006270 break;
6271 case UNRES_LIST_UNIQ:
Radek Krejcid09d1a52016-08-11 14:05:45 +02006272 unique_info = (struct unres_list_uniq *)item;
6273 rc = resolve_unique(unique_info->list, unique_info->expr, unique_info->trg_type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006274 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006275 case UNRES_AUGMENT:
Radek Krejcib3142312016-11-09 11:04:12 +01006276 rc = resolve_augment(item, NULL, unres);
Michal Vasko7178e692016-02-12 15:58:05 +01006277 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006278 case UNRES_XPATH:
6279 node = (struct lys_node *)item;
Michal Vasko769f8032017-01-24 13:11:55 +01006280 rc = lys_check_xpath(node, 1, final_fail);
Michal Vasko508a50d2016-09-07 14:50:33 +02006281 break;
Radek Krejcie534c132016-11-23 13:32:31 +01006282 case UNRES_EXT:
6283 ext_data = (struct unres_ext *)str_snode;
Radek Krejci2b999ac2017-01-18 16:22:12 +01006284 extlist = &(*(struct lys_ext_instance ***)item)[ext_data->ext_index];
Radek Krejcia7db9702017-01-20 12:55:14 +01006285 rc = resolve_extension(ext_data, extlist, unres);
Radek Krejcie534c132016-11-23 13:32:31 +01006286 if (!rc) {
Radek Krejci79685c92017-02-17 10:49:43 +01006287 /* success */
Radek Krejci80056d52017-01-05 13:13:33 +01006288 /* is there a callback to be done to finalize the extension? */
Radek Krejci2b999ac2017-01-18 16:22:12 +01006289 eplugin = extlist[0]->def->plugin;
Radek Krejci80056d52017-01-05 13:13:33 +01006290 if (eplugin) {
6291 if (eplugin->check_result || (eplugin->flags & LYEXT_OPT_INHERIT)) {
Radek Krejci2b999ac2017-01-18 16:22:12 +01006292 u = malloc(sizeof *u);
Radek Krejciaa1303c2017-05-31 13:57:37 +02006293 LY_CHECK_ERR_RETURN(!u, LOGMEM, -1);
Radek Krejci2b999ac2017-01-18 16:22:12 +01006294 (*u) = ext_data->ext_index;
Radek Krejcib08bc172017-02-27 13:17:14 +01006295 if (unres_schema_add_node(mod, unres, item, UNRES_EXT_FINALIZE, (struct lys_node *)u) == -1) {
6296 /* something really bad happend since the extension finalization is not actually
6297 * being resolved while adding into unres, so something more serious with the unres
6298 * list itself must happened */
6299 return -1;
6300 }
Radek Krejci80056d52017-01-05 13:13:33 +01006301 }
6302 }
Radek Krejci79685c92017-02-17 10:49:43 +01006303 }
6304 if (!rc || rc == -1) {
6305 /* cleanup on success or fatal error */
6306 if (ext_data->datatype == LYS_IN_YIN) {
6307 /* YIN */
6308 lyxml_free(mod->ctx, ext_data->data.yin);
6309 } else {
PavolVicandb0e8172017-02-20 00:46:09 +01006310 /* YANG */
6311 yang_free_ext_data(ext_data->data.yang);
Radek Krejci79685c92017-02-17 10:49:43 +01006312 }
Radek Krejci2b999ac2017-01-18 16:22:12 +01006313 free(ext_data);
Radek Krejcie534c132016-11-23 13:32:31 +01006314 }
6315 break;
Radek Krejci80056d52017-01-05 13:13:33 +01006316 case UNRES_EXT_FINALIZE:
Radek Krejci2b999ac2017-01-18 16:22:12 +01006317 u = (uint8_t *)str_snode;
6318 ext = (*(struct lys_ext_instance ***)item)[*u];
6319 free(u);
6320
Radek Krejci80056d52017-01-05 13:13:33 +01006321 eplugin = ext->def->plugin;
6322
6323 /* inherit */
6324 if ((eplugin->flags & LYEXT_OPT_INHERIT) && (ext->parent_type == LYEXT_PAR_NODE)) {
6325 root = (struct lys_node *)ext->parent;
6326 if (!(root->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
6327 LY_TREE_DFS_BEGIN(root->child, next, node) {
6328 /* first, check if the node already contain instance of the same extension,
6329 * in such a case we won't inherit. In case the node was actually defined as
6330 * augment data, we are supposed to check the same way also the augment node itself */
6331 if (lys_ext_instance_presence(ext->def, node->ext, node->ext_size) != -1) {
6332 goto inherit_dfs_sibling;
6333 } else if (node->parent != root && node->parent->nodetype == LYS_AUGMENT &&
6334 lys_ext_instance_presence(ext->def, node->parent->ext, node->parent->ext_size) != -1) {
6335 goto inherit_dfs_sibling;
6336 }
6337
6338 if (eplugin->check_inherit) {
6339 /* we have a callback to check the inheritance, use it */
6340 switch ((rc = (*eplugin->check_inherit)(ext, node))) {
6341 case 0:
6342 /* yes - continue with the inheriting code */
6343 break;
6344 case 1:
6345 /* no - continue with the node's sibling */
6346 goto inherit_dfs_sibling;
6347 case 2:
6348 /* no, but continue with the children, just skip the inheriting code for this node */
6349 goto inherit_dfs_child;
6350 default:
6351 LOGERR(LY_EINT, "Plugin's (%s:%s) check_inherit callback returns invalid value (%d),",
6352 ext->def->module->name, ext->def->name, rc);
6353 }
6354 }
6355
6356 /* inherit the extension */
6357 extlist = realloc(node->ext, (node->ext_size + 1) * sizeof *node->ext);
Radek Krejciaa1303c2017-05-31 13:57:37 +02006358 LY_CHECK_ERR_RETURN(!extlist, LOGMEM, -1);
Radek Krejci80056d52017-01-05 13:13:33 +01006359 extlist[node->ext_size] = malloc(sizeof **extlist);
Radek Krejciaa1303c2017-05-31 13:57:37 +02006360 LY_CHECK_ERR_RETURN(!extlist[node->ext_size], LOGMEM; node->ext = extlist, -1);
Radek Krejci80056d52017-01-05 13:13:33 +01006361 memcpy(extlist[node->ext_size], ext, sizeof *ext);
6362 extlist[node->ext_size]->flags |= LYEXT_OPT_INHERIT;
6363
6364 node->ext = extlist;
6365 node->ext_size++;
6366
6367inherit_dfs_child:
6368 /* modification of - select element for the next run - children first */
6369 if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
6370 next = NULL;
6371 } else {
6372 next = node->child;
6373 }
6374 if (!next) {
6375inherit_dfs_sibling:
6376 /* no children, try siblings */
6377 next = node->next;
6378 }
6379 while (!next) {
6380 /* go to the parent */
6381 node = lys_parent(node);
6382
6383 /* we are done if we are back in the root (the starter's parent */
6384 if (node == root) {
6385 break;
6386 }
6387
6388 /* parent is already processed, go to its sibling */
6389 next = node->next;
6390 }
6391 }
6392 }
6393 }
6394
6395 /* final check */
6396 if (eplugin->check_result) {
6397 if ((*eplugin->check_result)(ext)) {
Radek Krejci2c121b32017-02-24 10:03:16 +01006398 ly_errno = LY_EEXT;
Radek Krejci80056d52017-01-05 13:13:33 +01006399 return -1;
6400 }
6401 }
6402
6403 rc = 0;
6404 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006405 default:
6406 LOGINT;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006407 break;
6408 }
6409
Radek Krejci54081ce2016-08-12 15:21:47 +02006410 if (has_str && !rc) {
6411 /* the string is no more needed in case of success.
6412 * In case of forward reference, we will try to resolve the string later */
Radek Krejci4f78b532016-02-17 13:43:00 +01006413 lydict_remove(mod->ctx, str_snode);
6414 }
6415
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006416 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006417}
6418
Michal Vaskof02e3742015-08-05 16:27:02 +02006419/* logs directly */
6420static void
Radek Krejci48464ed2016-03-17 15:44:09 +01006421print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006422{
Michal Vaskocb34dc62016-05-20 14:38:37 +02006423 struct lyxml_elem *xml;
6424 struct lyxml_attr *attr;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006425 struct unres_iffeat_data *iff_data;
Radek Krejcie534c132016-11-23 13:32:31 +01006426 const char *name = NULL;
6427 struct unres_ext *extinfo;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006428
Michal Vaskof02e3742015-08-05 16:27:02 +02006429 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02006430 case UNRES_IDENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006431 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identity", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006432 break;
6433 case UNRES_TYPE_IDENTREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006434 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identityref", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006435 break;
6436 case UNRES_TYPE_LEAFREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006437 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "leafref",
6438 ((struct lys_type *)item)->info.lref.path);
Michal Vaskof02e3742015-08-05 16:27:02 +02006439 break;
Radek Krejci8d6b7422017-02-03 14:42:13 +01006440 case UNRES_TYPE_DER_EXT:
Radek Krejci3a5501d2016-07-18 22:03:34 +02006441 case UNRES_TYPE_DER_TPDF:
Michal Vaskof02e3742015-08-05 16:27:02 +02006442 case UNRES_TYPE_DER:
Michal Vaskocb34dc62016-05-20 14:38:37 +02006443 xml = (struct lyxml_elem *)((struct lys_type *)item)->der;
6444 if (xml->flags & LY_YANG_STRUCTURE_FLAG) {
Radek Krejcie534c132016-11-23 13:32:31 +01006445 name = ((struct yang_type *)xml)->name;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006446 } else {
6447 LY_TREE_FOR(xml->attr, attr) {
6448 if ((attr->type == LYXML_ATTR_STD) && !strcmp(attr->name, "name")) {
Radek Krejcie534c132016-11-23 13:32:31 +01006449 name = attr->value;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006450 break;
6451 }
6452 }
6453 assert(attr);
6454 }
Radek Krejcie534c132016-11-23 13:32:31 +01006455 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "derived type", name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006456 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006457 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006458 iff_data = str_node;
6459 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "if-feature", iff_data->fname);
Michal Vaskof02e3742015-08-05 16:27:02 +02006460 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006461 case UNRES_FEATURE:
6462 LOGVRB("There are unresolved if-features for \"%s\" feature circular dependency check, it will be attempted later",
6463 ((struct lys_feature *)item)->name);
6464 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006465 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006466 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "uses", ((struct lys_node_uses *)item)->name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006467 break;
Radek Krejciab08f0f2017-03-09 16:37:15 +01006468 case UNRES_TYPEDEF_DFLT:
Michal Vaskof02e3742015-08-05 16:27:02 +02006469 case UNRES_TYPE_DFLT:
Radek Krejci2e2de832016-10-13 16:12:26 +02006470 if (str_node) {
6471 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "type default", (char *)str_node);
6472 } /* else no default value in the type itself, but we are checking some restrictions against
6473 * possible default value of some base type. The failure is caused by not resolved base type,
6474 * so it was already reported */
Michal Vaskof02e3742015-08-05 16:27:02 +02006475 break;
6476 case UNRES_CHOICE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006477 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "choice default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006478 break;
6479 case UNRES_LIST_KEYS:
Radek Krejci48464ed2016-03-17 15:44:09 +01006480 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list keys", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006481 break;
6482 case UNRES_LIST_UNIQ:
Radek Krejci48464ed2016-03-17 15:44:09 +01006483 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list unique", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006484 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006485 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006486 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "augment target",
6487 ((struct lys_node_augment *)item)->target_name);
Michal Vasko7178e692016-02-12 15:58:05 +01006488 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006489 case UNRES_XPATH:
Michal Vasko0d198372016-11-16 11:40:03 +01006490 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "XPath expressions of",
6491 ((struct lys_node *)item)->name);
Michal Vasko508a50d2016-09-07 14:50:33 +02006492 break;
Radek Krejcie534c132016-11-23 13:32:31 +01006493 case UNRES_EXT:
6494 extinfo = (struct unres_ext *)str_node;
6495 name = extinfo->datatype == LYS_IN_YIN ? extinfo->data.yin->name : NULL; /* TODO YANG extension */
6496 LOGVRB("Resolving extension \"%s\" failed, it will be attempted later.", name);
6497 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006498 default:
6499 LOGINT;
Michal Vaskof02e3742015-08-05 16:27:02 +02006500 break;
6501 }
6502}
6503
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006504/**
Michal Vaskobb211122015-08-19 14:03:11 +02006505 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006506 *
6507 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006508 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006509 *
Michal Vasko92b8a382015-08-19 14:03:49 +02006510 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006511 */
Michal Vaskof02e3742015-08-05 16:27:02 +02006512int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006513resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02006514{
Radek Krejci010e54b2016-03-15 09:40:34 +01006515 uint32_t i, resolved = 0, unres_count, res_count;
PavolVicana0fdbf32017-02-15 17:59:02 +01006516 struct lyxml_elem *yin;
6517 struct yang_type *yang;
Michal Vasko74a60c02017-03-08 10:19:48 +01006518 int rc, log_hidden;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006519
6520 assert(unres);
6521
Michal Vaskoe8734262016-09-29 14:12:06 +02006522 LOGVRB("Resolving \"%s\" unresolved schema nodes and their constraints...", mod->name);
Michal Vasko74a60c02017-03-08 10:19:48 +01006523 if (*ly_vlog_hide_location()) {
6524 log_hidden = 1;
6525 } else {
6526 log_hidden = 0;
6527 ly_vlog_hide(1);
6528 }
Michal Vasko51054ca2015-08-12 12:20:00 +02006529
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006530 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02006531 do {
Michal Vasko88c29542015-11-27 14:57:53 +01006532 unres_count = 0;
6533 res_count = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02006534
6535 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006536 /* UNRES_TYPE_LEAFREF must be resolved (for storing leafref target pointers);
Radek Krejcic79c6b12016-07-26 15:11:49 +02006537 * if-features are resolved here to make sure that we will have all if-features for
6538 * later check of feature circular dependency */
Radek Krejci018f1f52016-08-03 16:01:20 +02006539 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006540 continue;
6541 }
Radek Krejci018f1f52016-08-03 16:01:20 +02006542 /* processes UNRES_USES, UNRES_IFFEAT, UNRES_TYPE_DER, UNRES_TYPE_DER_TPDF, UNRES_TYPE_LEAFREF,
Radek Krejci818b0c52016-11-09 15:10:51 +01006543 * UNRES_AUGMENT, UNRES_CHOICE_DFLT and UNRES_IDENT */
Michal Vasko51054ca2015-08-12 12:20:00 +02006544
Michal Vasko88c29542015-11-27 14:57:53 +01006545 ++unres_count;
Radek Krejcicd9a95a2017-03-25 12:02:35 -05006546 rc = resolve_unres_schema_item(unres->module[i], unres->item[i], unres->type[i], unres->str_snode[i], unres, 0);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006547 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006548 unres->type[i] = UNRES_RESOLVED;
6549 ++resolved;
Michal Vasko88c29542015-11-27 14:57:53 +01006550 ++res_count;
Michal Vasko89e15322015-08-17 15:46:55 +02006551 } else if (rc == -1) {
Michal Vasko74a60c02017-03-08 10:19:48 +01006552 if (!log_hidden) {
6553 ly_vlog_hide(0);
6554 }
Michal Vasko22af5ca2016-05-20 11:44:02 +02006555 /* print the error */
Radek Krejci791f6c72017-02-22 15:23:39 +01006556 ly_err_repeat();
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006557 return -1;
Radek Krejcic2a180f2016-06-22 13:28:16 +02006558 } else {
6559 /* forward reference, erase ly_errno */
Radek Krejci00a0e712016-10-26 10:24:46 +02006560 ly_err_clean(1);
Michal Vasko51054ca2015-08-12 12:20:00 +02006561 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006562 }
Michal Vasko88c29542015-11-27 14:57:53 +01006563 } while (res_count && (res_count < unres_count));
Michal Vasko51054ca2015-08-12 12:20:00 +02006564
Michal Vasko88c29542015-11-27 14:57:53 +01006565 if (res_count < unres_count) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006566 /* just print the errors */
Michal Vasko74a60c02017-03-08 10:19:48 +01006567 if (!log_hidden) {
6568 ly_vlog_hide(0);
6569 }
Michal Vasko22af5ca2016-05-20 11:44:02 +02006570
6571 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006572 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006573 continue;
6574 }
Radek Krejcicd9a95a2017-03-25 12:02:35 -05006575 resolve_unres_schema_item(unres->module[i], unres->item[i], unres->type[i], unres->str_snode[i], unres, 1);
Radek Krejci63fc0962017-02-15 13:20:18 +01006576 if (unres->type[i] == UNRES_TYPE_DER_EXT) {
PavolVicana0fdbf32017-02-15 17:59:02 +01006577 yin = (struct lyxml_elem*)((struct lys_type *)unres->item[i])->der;
6578 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6579 yang =(struct yang_type *)yin;
6580 ((struct lys_type *)unres->item[i])->base = yang->base;
6581 if (yang->base == LY_TYPE_UNION) {
6582 yang_free_type_union(mod->ctx, (struct lys_type *)unres->item[i]);
6583 }
6584 lydict_remove(mod->ctx, yang->name);
6585 free(yang);
6586 } else {
6587 lyxml_free(mod->ctx, yin);
6588 }
Radek Krejci63fc0962017-02-15 13:20:18 +01006589 }
Michal Vasko22af5ca2016-05-20 11:44:02 +02006590 }
Michal Vasko92b8a382015-08-19 14:03:49 +02006591 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006592 }
6593
Radek Krejci07d0fb92017-01-13 14:11:05 +01006594 /* the rest except finalizing extensions */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006595 for (i = 0; i < unres->count; ++i) {
Radek Krejci80056d52017-01-05 13:13:33 +01006596 if (unres->type[i] == UNRES_RESOLVED || unres->type[i] == UNRES_EXT_FINALIZE) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006597 continue;
6598 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02006599
Radek Krejcicd9a95a2017-03-25 12:02:35 -05006600 rc = resolve_unres_schema_item(unres->module[i], unres->item[i], unres->type[i], unres->str_snode[i], unres, 0);
Radek Krejci010e54b2016-03-15 09:40:34 +01006601 if (rc == 0) {
Pavol Vican88e16c92016-09-07 15:41:50 +02006602 if (unres->type[i] == UNRES_LIST_UNIQ) {
6603 /* free the allocated structure */
6604 free(unres->item[i]);
6605 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006606 unres->type[i] = UNRES_RESOLVED;
6607 ++resolved;
6608 } else if (rc == -1) {
Michal Vasko74a60c02017-03-08 10:19:48 +01006609 if (!log_hidden) {
6610 ly_vlog_hide(0);
6611 }
Michal Vasko22af5ca2016-05-20 11:44:02 +02006612 /* print the error */
Radek Krejci791f6c72017-02-22 15:23:39 +01006613 ly_err_repeat();
Michal Vasko22af5ca2016-05-20 11:44:02 +02006614 return -1;
Radek Krejci791f6c72017-02-22 15:23:39 +01006615 } else {
6616 /* forward reference, erase ly_errno */
6617 ly_err_clean(1);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006618 }
6619 }
6620
Michal Vasko74a60c02017-03-08 10:19:48 +01006621 if (!log_hidden) {
6622 ly_vlog_hide(0);
6623 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006624
Radek Krejci80056d52017-01-05 13:13:33 +01006625 /* finalize extensions, keep it last to provide the complete schema tree information to the plugin's checkers */
6626 for (i = 0; i < unres->count; ++i) {
6627 if (unres->type[i] != UNRES_EXT_FINALIZE) {
6628 continue;
6629 }
6630
Radek Krejcicd9a95a2017-03-25 12:02:35 -05006631 rc = resolve_unres_schema_item(unres->module[i], unres->item[i], unres->type[i], unres->str_snode[i], unres, 0);
Radek Krejci791f6c72017-02-22 15:23:39 +01006632 unres->type[i] = UNRES_RESOLVED;
Radek Krejci80056d52017-01-05 13:13:33 +01006633 if (rc == 0) {
Radek Krejci80056d52017-01-05 13:13:33 +01006634 ++resolved;
6635 }
Radek Krejci791f6c72017-02-22 15:23:39 +01006636 /* else error - it was already printed, but resolved was not increased,
6637 so this unres item will not be resolved again in the following code,
6638 but it will cause returning -1 at the end, this way we are able to
6639 print all the issues with unres */
Radek Krejci80056d52017-01-05 13:13:33 +01006640 }
6641
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006642 if (resolved < unres->count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006643 /* try to resolve the unresolved nodes again, it will not resolve anything, but it will print
6644 * all the validation errors
6645 */
6646 for (i = 0; i < unres->count; ++i) {
6647 if (unres->type[i] == UNRES_RESOLVED) {
6648 continue;
6649 }
Radek Krejcicd9a95a2017-03-25 12:02:35 -05006650 resolve_unres_schema_item(unres->module[i], unres->item[i], unres->type[i], unres->str_snode[i], unres, 1);
Radek Krejcib3142312016-11-09 11:04:12 +01006651 if (unres->type[i] == UNRES_XPATH) {
Michal Vasko769f8032017-01-24 13:11:55 +01006652 /* XPath referencing an unknown node is actually supposed to be just a warning */
Radek Krejcib3142312016-11-09 11:04:12 +01006653 unres->type[i] = UNRES_RESOLVED;
6654 resolved++;
Radek Krejcib3142312016-11-09 11:04:12 +01006655 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006656 }
Radek Krejcib3142312016-11-09 11:04:12 +01006657 if (resolved < unres->count) {
6658 return -1;
6659 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006660 }
6661
Michal Vaskoe8734262016-09-29 14:12:06 +02006662 LOGVRB("All \"%s\" schema nodes and constraints resolved.", mod->name);
Radek Krejcic071c542016-01-27 14:57:51 +01006663 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006664 return EXIT_SUCCESS;
6665}
6666
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006667/**
Michal Vaskobb211122015-08-19 14:03:11 +02006668 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006669 *
6670 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006671 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006672 * @param[in] item Item to resolve. Type determined by \p type.
6673 * @param[in] type Type of the unresolved item.
6674 * @param[in] str String argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006675 *
Michal Vasko3767fb22016-07-21 12:10:57 +02006676 * @return EXIT_SUCCESS on success, EXIT_FAILURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006677 */
6678int
Radek Krejci48464ed2016-03-17 15:44:09 +01006679unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
6680 const char *str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006681{
Radek Krejci54081ce2016-08-12 15:21:47 +02006682 int rc;
6683 const char *dictstr;
6684
6685 dictstr = lydict_insert(mod->ctx, str, 0);
6686 rc = unres_schema_add_node(mod, unres, item, type, (struct lys_node *)dictstr);
6687
Radek Krejcid9c0ce22017-01-20 15:20:16 +01006688 if (rc < 0) {
Radek Krejci54081ce2016-08-12 15:21:47 +02006689 lydict_remove(mod->ctx, dictstr);
6690 }
6691 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006692}
6693
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006694/**
Michal Vaskobb211122015-08-19 14:03:11 +02006695 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006696 *
6697 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006698 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006699 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01006700 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006701 * @param[in] snode Schema node argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006702 *
Radek Krejcid9c0ce22017-01-20 15:20:16 +01006703 * @return EXIT_SUCCESS on success, EXIT_FIALURE on storing the item in unres, -1 on error, -2 if the unres item
6704 * is already in the unres list.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006705 */
6706int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006707unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Radek Krejci48464ed2016-03-17 15:44:09 +01006708 struct lys_node *snode)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006709{
Michal Vaskoef486d72016-09-27 12:10:44 +02006710 int rc, log_hidden;
Michal Vasko88c29542015-11-27 14:57:53 +01006711 struct lyxml_elem *yin;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006712
Michal Vasko9bf425b2015-10-22 11:42:03 +02006713 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
6714 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006715
Michal Vasko9e862e82017-03-08 10:20:49 +01006716#ifndef NDEBUG
Radek Krejcidf056df2017-03-09 13:24:45 +01006717 uint32_t u;
6718
Radek Krejci850a5de2016-11-08 14:06:40 +01006719 /* check for duplicities in unres */
6720 for (u = 0; u < unres->count; u++) {
6721 if (unres->type[u] == type && unres->item[u] == item &&
6722 unres->str_snode[u] == snode && unres->module[u] == mod) {
Michal Vasko9e862e82017-03-08 10:20:49 +01006723 /* duplication, should not happen */
6724 assert(0);
Radek Krejci850a5de2016-11-08 14:06:40 +01006725 }
6726 }
Michal Vasko9e862e82017-03-08 10:20:49 +01006727#endif
Radek Krejci850a5de2016-11-08 14:06:40 +01006728
Radek Krejcic293bac2017-02-27 11:25:28 +01006729 if (type == UNRES_EXT_FINALIZE) {
Radek Krejci80056d52017-01-05 13:13:33 +01006730 /* extension finalization is not even tried when adding the item into the inres list */
Radek Krejcic293bac2017-02-27 11:25:28 +01006731 rc = EXIT_FAILURE;
6732 } else {
Radek Krejci80056d52017-01-05 13:13:33 +01006733 if (*ly_vlog_hide_location()) {
6734 log_hidden = 1;
6735 } else {
6736 log_hidden = 0;
6737 ly_vlog_hide(1);
Radek Krejci010e54b2016-03-15 09:40:34 +01006738 }
Radek Krejcicbba57c2017-01-24 13:43:20 +01006739 rc = resolve_unres_schema_item(mod, item, type, snode, unres, 0);
Radek Krejci80056d52017-01-05 13:13:33 +01006740 if (!log_hidden) {
6741 ly_vlog_hide(0);
6742 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006743
Radek Krejci80056d52017-01-05 13:13:33 +01006744 if (rc != EXIT_FAILURE) {
Michal Vaskobb520442017-05-23 10:55:18 +02006745 if (rc == -1) {
Radek Krejci80056d52017-01-05 13:13:33 +01006746 ly_err_repeat();
6747 }
6748 if (type == UNRES_LIST_UNIQ) {
6749 /* free the allocated structure */
6750 free(item);
6751 } else if (rc == -1 && type == UNRES_IFFEAT) {
6752 /* free the allocated resources */
6753 free(*((char **)item));
Michal Vaskobb520442017-05-23 10:55:18 +02006754 }
Radek Krejci80056d52017-01-05 13:13:33 +01006755 return rc;
6756 } else {
6757 /* erase info about validation errors */
6758 ly_err_clean(1);
6759 }
Michal Vaskof02e3742015-08-05 16:27:02 +02006760
Radek Krejci80056d52017-01-05 13:13:33 +01006761 print_unres_schema_item_fail(item, type, snode);
6762
6763 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
6764 if (type == UNRES_TYPE_DER || type == UNRES_TYPE_DER_TPDF) {
6765 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
6766 if (!(yin->flags & LY_YANG_STRUCTURE_FLAG)) {
6767 lyxml_unlink_elem(mod->ctx, yin, 1);
6768 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
6769 }
Pavol Vicana0e4e672016-02-24 12:20:04 +01006770 }
Michal Vasko88c29542015-11-27 14:57:53 +01006771 }
6772
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006773 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01006774 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
Radek Krejciaa1303c2017-05-31 13:57:37 +02006775 LY_CHECK_ERR_RETURN(!unres->item, LOGMEM, -1);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006776 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01006777 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
Radek Krejciaa1303c2017-05-31 13:57:37 +02006778 LY_CHECK_ERR_RETURN(!unres->type, LOGMEM, -1);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006779 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01006780 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
Radek Krejciaa1303c2017-05-31 13:57:37 +02006781 LY_CHECK_ERR_RETURN(!unres->str_snode, LOGMEM, -1);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006782 unres->str_snode[unres->count-1] = snode;
Radek Krejcic071c542016-01-27 14:57:51 +01006783 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
Radek Krejciaa1303c2017-05-31 13:57:37 +02006784 LY_CHECK_ERR_RETURN(!unres->module, LOGMEM, -1);
Radek Krejcic071c542016-01-27 14:57:51 +01006785 unres->module[unres->count-1] = mod;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006786
Michal Vasko3767fb22016-07-21 12:10:57 +02006787 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006788}
6789
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006790/**
Michal Vaskobb211122015-08-19 14:03:11 +02006791 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006792 *
6793 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006794 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006795 * @param[in] item Old item to be resolved.
6796 * @param[in] type Type of the old unresolved item.
6797 * @param[in] new_item New item to use in the duplicate.
6798 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02006799 * @return EXIT_SUCCESS on success, EXIT_FAILURE if item is not in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006800 */
Michal Vaskodad19402015-08-06 09:51:53 +02006801int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006802unres_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 +02006803{
6804 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006805 struct unres_list_uniq aux_uniq;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006806 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006807
Michal Vaskocf024702015-10-08 15:01:42 +02006808 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006809
Radek Krejcid09d1a52016-08-11 14:05:45 +02006810 /* hack for UNRES_LIST_UNIQ, which stores multiple items behind its item */
6811 if (type == UNRES_LIST_UNIQ) {
6812 aux_uniq.list = item;
6813 aux_uniq.expr = ((struct unres_list_uniq *)new_item)->expr;
6814 item = &aux_uniq;
6815 }
Michal Vasko878e38d2016-09-05 12:17:53 +02006816 i = unres_schema_find(unres, -1, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006817
6818 if (i == -1) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006819 if (type == UNRES_LIST_UNIQ) {
6820 free(new_item);
6821 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02006822 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006823 }
6824
Radek Krejcic79c6b12016-07-26 15:11:49 +02006825 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT) ||
Radek Krejcib69f3232016-09-16 17:41:07 +02006826 (type == UNRES_FEATURE) || (type == UNRES_LIST_UNIQ)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01006827 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006828 LOGINT;
6829 return -1;
6830 }
Radek Krejcicbb473e2016-09-16 14:48:32 +02006831 } else if (type == UNRES_IFFEAT) {
6832 /* duplicate unres_iffeature_data */
6833 iff_data = malloc(sizeof *iff_data);
Radek Krejciaa1303c2017-05-31 13:57:37 +02006834 LY_CHECK_ERR_RETURN(!iff_data, LOGMEM, -1);
Radek Krejcicbb473e2016-09-16 14:48:32 +02006835 iff_data->fname = lydict_insert(mod->ctx, ((struct unres_iffeat_data *)unres->str_snode[i])->fname, 0);
6836 iff_data->node = ((struct unres_iffeat_data *)unres->str_snode[i])->node;
6837 if (unres_schema_add_node(mod, unres, new_item, type, (struct lys_node *)iff_data) == -1) {
6838 LOGINT;
6839 return -1;
6840 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006841 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01006842 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006843 LOGINT;
6844 return -1;
6845 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006846 }
Michal Vaskodad19402015-08-06 09:51:53 +02006847
6848 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006849}
6850
Michal Vaskof02e3742015-08-05 16:27:02 +02006851/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006852int
Michal Vasko878e38d2016-09-05 12:17:53 +02006853unres_schema_find(struct unres_schema *unres, int start_on_backwards, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006854{
Michal Vasko878e38d2016-09-05 12:17:53 +02006855 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006856 struct unres_list_uniq *aux_uniq1, *aux_uniq2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006857
Radek Krejciddddd0d2017-01-20 15:20:46 +01006858 if (start_on_backwards >= 0) {
Michal Vasko878e38d2016-09-05 12:17:53 +02006859 i = start_on_backwards;
6860 } else {
6861 i = unres->count - 1;
6862 }
6863 for (; i > -1; i--) {
6864 if (unres->type[i] != type) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006865 continue;
6866 }
6867 if (type != UNRES_LIST_UNIQ) {
Michal Vasko878e38d2016-09-05 12:17:53 +02006868 if (unres->item[i] == item) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006869 break;
6870 }
6871 } else {
6872 aux_uniq1 = (struct unres_list_uniq *)unres->item[i - 1];
6873 aux_uniq2 = (struct unres_list_uniq *)item;
6874 if ((aux_uniq1->list == aux_uniq2->list) && ly_strequal(aux_uniq1->expr, aux_uniq2->expr, 0)) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006875 break;
6876 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006877 }
6878 }
6879
Michal Vasko878e38d2016-09-05 12:17:53 +02006880 return i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006881}
Michal Vasko8bcdf292015-08-19 14:04:43 +02006882
Michal Vaskoede9c472016-06-07 09:38:15 +02006883static void
6884unres_schema_free_item(struct ly_ctx *ctx, struct unres_schema *unres, uint32_t i)
6885{
6886 struct lyxml_elem *yin;
6887 struct yang_type *yang;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006888 struct unres_iffeat_data *iff_data;
Michal Vaskoede9c472016-06-07 09:38:15 +02006889
6890 switch (unres->type[i]) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02006891 case UNRES_TYPE_DER_TPDF:
Michal Vaskoede9c472016-06-07 09:38:15 +02006892 case UNRES_TYPE_DER:
6893 yin = (struct lyxml_elem *)((struct lys_type *)unres->item[i])->der;
6894 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6895 yang =(struct yang_type *)yin;
Pavol Vicancf2af4d2016-12-21 14:13:06 +01006896 ((struct lys_type *)unres->item[i])->base = yang->base;
Michal Vaskoede9c472016-06-07 09:38:15 +02006897 lydict_remove(ctx, yang->name);
6898 free(yang);
Pavol Vicancf2af4d2016-12-21 14:13:06 +01006899 if (((struct lys_type *)unres->item[i])->base == LY_TYPE_UNION) {
6900 yang_free_type_union(ctx, (struct lys_type *)unres->item[i]);
6901 }
Michal Vaskoede9c472016-06-07 09:38:15 +02006902 } else {
6903 lyxml_free(ctx, yin);
6904 }
6905 break;
Pavol Vican88e16c92016-09-07 15:41:50 +02006906 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006907 iff_data = (struct unres_iffeat_data *)unres->str_snode[i];
6908 lydict_remove(ctx, iff_data->fname);
6909 free(unres->str_snode[i]);
Pavol Vican88e16c92016-09-07 15:41:50 +02006910 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02006911 case UNRES_IDENT:
6912 case UNRES_TYPE_IDENTREF:
Michal Vaskoede9c472016-06-07 09:38:15 +02006913 case UNRES_CHOICE_DFLT:
6914 case UNRES_LIST_KEYS:
Michal Vaskoede9c472016-06-07 09:38:15 +02006915 lydict_remove(ctx, (const char *)unres->str_snode[i]);
6916 break;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006917 case UNRES_LIST_UNIQ:
6918 free(unres->item[i]);
6919 break;
PavolVicanc1807262017-01-31 18:00:27 +01006920 case UNRES_EXT:
6921 free(unres->str_snode[i]);
6922 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02006923 default:
6924 break;
6925 }
6926 unres->type[i] = UNRES_RESOLVED;
6927}
6928
Michal Vasko88c29542015-11-27 14:57:53 +01006929void
Michal Vasko44ab1462017-05-18 13:18:36 +02006930unres_schema_free(struct lys_module *module, struct unres_schema **unres, int all)
Michal Vasko88c29542015-11-27 14:57:53 +01006931{
6932 uint32_t i;
Radek Krejcic071c542016-01-27 14:57:51 +01006933 unsigned int unresolved = 0;
Michal Vasko88c29542015-11-27 14:57:53 +01006934
Radek Krejcic071c542016-01-27 14:57:51 +01006935 if (!unres || !(*unres)) {
6936 return;
Michal Vasko88c29542015-11-27 14:57:53 +01006937 }
6938
Michal Vasko44ab1462017-05-18 13:18:36 +02006939 assert(module || ((*unres)->count == 0));
Radek Krejcic071c542016-01-27 14:57:51 +01006940
6941 for (i = 0; i < (*unres)->count; ++i) {
Michal Vasko44ab1462017-05-18 13:18:36 +02006942 if (!all && ((*unres)->module[i] != module)) {
Radek Krejcic071c542016-01-27 14:57:51 +01006943 if ((*unres)->type[i] != UNRES_RESOLVED) {
6944 unresolved++;
6945 }
6946 continue;
6947 }
Michal Vaskoede9c472016-06-07 09:38:15 +02006948
6949 /* free heap memory for the specific item */
6950 unres_schema_free_item(module->ctx, *unres, i);
Radek Krejcic071c542016-01-27 14:57:51 +01006951 }
6952
Michal Vaskoede9c472016-06-07 09:38:15 +02006953 /* free it all */
Michal Vasko44ab1462017-05-18 13:18:36 +02006954 if (!module || all || (!unresolved && !module->type)) {
Radek Krejcic071c542016-01-27 14:57:51 +01006955 free((*unres)->item);
6956 free((*unres)->type);
6957 free((*unres)->str_snode);
6958 free((*unres)->module);
Radek Krejcic071c542016-01-27 14:57:51 +01006959 free((*unres));
6960 (*unres) = NULL;
6961 }
Michal Vasko88c29542015-11-27 14:57:53 +01006962}
6963
Michal Vasko3cfa3182017-01-17 10:00:58 +01006964static int
6965check_instid_ext_dep(const struct lys_node *sleaf, const char *json_instid)
6966{
6967 struct ly_set *set;
Michal Vasko3c777092017-01-17 14:10:09 +01006968 struct lys_node *op_node, *first_node;
Michal Vasko3cfa3182017-01-17 10:00:58 +01006969 char *buf;
6970
6971 for (op_node = lys_parent(sleaf);
6972 op_node && !(op_node->nodetype & (LYS_NOTIF | LYS_RPC | LYS_ACTION));
6973 op_node = lys_parent(op_node));
6974
6975 if (op_node && lys_parent(op_node)) {
6976 /* nested operation - any absolute path is external */
6977 return 1;
6978 }
6979
6980 /* get the first node from the instid */
6981 buf = strndup(json_instid, strchr(json_instid + 1, '/') - json_instid);
6982 if (!buf) {
6983 LOGMEM;
6984 return -1;
6985 }
6986
6987 /* there is a predicate, remove it */
6988 if (buf[strlen(buf) - 1] == ']') {
6989 assert(strchr(buf, '['));
6990 *strchr(buf, '[') = '\0';
6991 }
6992
6993 /* find the first schema node */
Michal Vasko2611e192017-01-23 10:33:21 +01006994 set = lys_find_xpath(NULL, sleaf, buf, 0);
Michal Vasko3cfa3182017-01-17 10:00:58 +01006995 if (!set || !set->number) {
6996 free(buf);
Michal Vasko29fd9742017-01-23 09:55:44 +01006997 ly_set_free(set);
Michal Vasko3cfa3182017-01-17 10:00:58 +01006998 return 1;
6999 }
7000 free(buf);
7001
Michal Vasko3c777092017-01-17 14:10:09 +01007002 first_node = set->set.s[0];
7003 ly_set_free(set);
7004
Michal Vasko3cfa3182017-01-17 10:00:58 +01007005 /* based on the first schema node in the path we can decide whether it points to an external tree or not */
7006
7007 if (op_node) {
7008 /* it is an operation, so we're good if it points somewhere inside it */
Michal Vasko3c777092017-01-17 14:10:09 +01007009 if (op_node == first_node) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007010 assert(set->number == 1);
7011 return 0;
7012 } else {
7013 return 1;
7014 }
7015 }
7016
7017 /* we cannot know whether it points to a tree that is going to be unlinked (application must handle
7018 * this itself), so we say it's not external */
7019 return 0;
7020}
7021
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007022/**
7023 * @brief Resolve instance-identifier in JSON data format. Logs directly.
7024 *
7025 * @param[in] data Data node where the path is used
7026 * @param[in] path Instance-identifier node value.
7027 * @param[in,out] ret Resolved instance or NULL.
7028 *
7029 * @return 0 on success (even if unresolved and \p ret is NULL), -1 on error.
7030 */
7031static int
7032resolve_instid(struct lyd_node *data, const char *path, int req_inst, struct lyd_node **ret)
7033{
7034 int i = 0, j;
7035 const struct lys_module *mod;
7036 struct ly_ctx *ctx = data->schema->module->ctx;
7037 const char *model, *name;
7038 char *str;
7039 int mod_len, name_len, has_predicate;
7040 struct unres_data node_match;
7041
7042 memset(&node_match, 0, sizeof node_match);
7043 *ret = NULL;
7044
7045 /* we need root to resolve absolute path */
7046 for (; data->parent; data = data->parent);
7047 /* we're still parsing it and the pointer is not correct yet */
7048 if (data->prev) {
7049 for (; data->prev->next; data = data->prev);
7050 }
7051
7052 /* search for the instance node */
7053 while (path[i]) {
7054 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
7055 if (j <= 0) {
7056 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
7057 goto error;
7058 }
7059 i += j;
7060
7061 str = strndup(model, mod_len);
7062 if (!str) {
7063 LOGMEM;
7064 goto error;
7065 }
7066 mod = ly_ctx_get_module(ctx, str, NULL);
Michal Vaskof53187d2017-01-13 13:23:14 +01007067 if (ctx->data_clb) {
7068 if (!mod) {
7069 mod = ctx->data_clb(ctx, str, NULL, 0, ctx->data_clb_data);
7070 } else if (!mod->implemented) {
7071 mod = ctx->data_clb(ctx, mod->name, mod->ns, LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
7072 }
7073 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007074 free(str);
7075
Michal Vaskof53187d2017-01-13 13:23:14 +01007076 if (!mod || !mod->implemented || mod->disabled) {
7077 break;
7078 }
7079
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007080 if (resolve_data(mod, name, name_len, data, &node_match)) {
7081 /* no instance exists */
7082 break;
7083 }
7084
7085 if (has_predicate) {
7086 /* we have predicate, so the current results must be list or leaf-list */
Michal Vasko1c007172017-03-10 10:20:44 +01007087 j = resolve_instid_predicate(&path[i], &node_match);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007088 if (j < 1) {
7089 LOGVAL(LYE_INPRED, LY_VLOG_LYD, data, &path[i-j]);
7090 goto error;
7091 }
7092 i += j;
7093
7094 if (!node_match.count) {
7095 /* no instance exists */
7096 break;
7097 }
Michal Vasko6f28e0f2017-04-18 15:14:13 +02007098 } else if (node_match.count) {
7099 /* check that we are not addressing lists */
7100 for (j = 0; (unsigned)j < node_match.count; ++j) {
7101 if (node_match.node[j]->schema->nodetype == LYS_LIST) {
7102 unres_data_del(&node_match, j--);
7103 }
7104 }
7105 if (!node_match.count) {
7106 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier is missing list keys.");
7107 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007108 }
7109 }
7110
7111 if (!node_match.count) {
7112 /* no instance exists */
7113 if (req_inst > -1) {
7114 LOGVAL(LYE_NOREQINS, LY_VLOG_NONE, NULL, path);
7115 return EXIT_FAILURE;
7116 }
7117 LOGVRB("There is no instance of \"%s\", but it is not required.", path);
7118 return EXIT_SUCCESS;
7119 } else if (node_match.count > 1) {
7120 /* instance identifier must resolve to a single node */
7121 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
7122 goto error;
7123 } else {
7124 /* we have required result, remember it and cleanup */
7125 *ret = node_match.node[0];
7126 free(node_match.node);
7127 return EXIT_SUCCESS;
7128 }
7129
7130error:
7131 /* cleanup */
7132 free(node_match.node);
7133 return -1;
7134}
7135
7136static int
7137resolve_leafref(struct lyd_node_leaf_list *leaf, const char *path, int req_inst, struct lyd_node **ret)
Radek Krejci7de36cf2016-09-12 16:18:50 +02007138{
Michal Vaskoca16cb32017-07-10 11:50:33 +02007139 struct ly_set *set;
Radek Krejci7de36cf2016-09-12 16:18:50 +02007140 uint32_t i;
7141
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007142 *ret = NULL;
Radek Krejci7de36cf2016-09-12 16:18:50 +02007143
Michal Vaskoca16cb32017-07-10 11:50:33 +02007144 /* syntax was already checked, so just evaluate the path using standard XPath */
7145 set = lyd_find_xpath((struct lyd_node *)leaf, path);
7146 if (!set) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02007147 return -1;
7148 }
7149
Michal Vaskoca16cb32017-07-10 11:50:33 +02007150 for (i = 0; i < set->number; ++i) {
7151 if (!(set->set.d[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
7152 continue;
7153 }
7154
Radek Krejci1899d6a2016-11-03 13:48:07 +01007155 /* not that the value is already in canonical form since the parsers does the conversion,
7156 * so we can simply compare just the values */
Michal Vaskoca16cb32017-07-10 11:50:33 +02007157 if (ly_strequal(leaf->value_str, ((struct lyd_node_leaf_list *)set->set.d[i])->value_str, 1)) {
Radek Krejci1899d6a2016-11-03 13:48:07 +01007158 /* we have the match */
Michal Vaskoca16cb32017-07-10 11:50:33 +02007159 *ret = set->set.d[i];
Radek Krejci7de36cf2016-09-12 16:18:50 +02007160 break;
7161 }
7162 }
7163
Michal Vaskoca16cb32017-07-10 11:50:33 +02007164 ly_set_free(set);
Radek Krejci7de36cf2016-09-12 16:18:50 +02007165
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007166 if (!*ret) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02007167 /* reference not found */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007168 if (req_inst > -1) {
7169 LOGVAL(LYE_NOLEAFREF, LY_VLOG_LYD, leaf, path, leaf->value_str);
Radek Krejci7de36cf2016-09-12 16:18:50 +02007170 return EXIT_FAILURE;
7171 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007172 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 +02007173 }
7174 }
7175
7176 return EXIT_SUCCESS;
7177}
7178
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007179/* 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 +01007180int
7181resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type, int store, int ignore_fail,
7182 struct lys_type **resolved_type)
Radek Krejci9b6aad22016-09-20 15:55:51 +02007183{
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007184 struct lys_type *t;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007185 struct lyd_node *ret;
7186 int found, hidden, success = 0, ext_dep, req_inst;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007187 const char *json_val = NULL;
Radek Krejci9b6aad22016-09-20 15:55:51 +02007188
7189 assert(type->base == LY_TYPE_UNION);
7190
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007191 if ((leaf->value_type == LY_TYPE_UNION) || (leaf->value_type == (LY_TYPE_INST | LY_TYPE_INST_UNRES))) {
7192 /* either NULL or instid previously converted to JSON */
7193 json_val = leaf->value.string;
7194 }
Michal Vasko1c8567a2017-01-05 13:42:27 +01007195
Michal Vaskofd6c6502017-01-06 12:15:41 +01007196 if (store) {
7197 if ((leaf->value_type & LY_DATA_TYPE_MASK) == LY_TYPE_BITS) {
7198 free(leaf->value.bit);
7199 }
7200 memset(&leaf->value, 0, sizeof leaf->value);
Michal Vasko1c8567a2017-01-05 13:42:27 +01007201 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007202
7203 /* turn logging off, we are going to try to validate the value with all the types in order */
7204 hidden = *ly_vlog_hide_location();
7205 ly_vlog_hide(1);
7206
7207 t = NULL;
7208 found = 0;
7209 while ((t = lyp_get_next_union_type(type, t, &found))) {
7210 found = 0;
7211
7212 switch (t->base) {
7213 case LY_TYPE_LEAFREF:
Michal Vasko3cfa3182017-01-17 10:00:58 +01007214 if ((ignore_fail == 1) || ((leaf->schema->flags & LYS_LEAFREF_DEP) && (ignore_fail == 2))) {
7215 req_inst = -1;
7216 } else {
7217 req_inst = t->info.lref.req;
7218 }
7219
7220 if (!resolve_leafref(leaf, t->info.lref.path, req_inst, &ret)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007221 if (store) {
7222 if (ret && !(leaf->schema->flags & LYS_LEAFREF_DEP)) {
7223 /* valid resolved */
7224 leaf->value.leafref = ret;
7225 leaf->value_type = LY_TYPE_LEAFREF;
7226 } else {
7227 /* valid unresolved */
Radek Krejcia571d942017-02-24 09:26:49 +01007228 if (!lyp_parse_value(t, &leaf->value_str, NULL, leaf, NULL, 1, 0)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007229 return -1;
7230 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007231 }
7232 }
7233
7234 success = 1;
7235 }
7236 break;
7237 case LY_TYPE_INST:
Michal Vasko3cfa3182017-01-17 10:00:58 +01007238 ext_dep = check_instid_ext_dep(leaf->schema, (json_val ? json_val : leaf->value_str));
7239 if ((ignore_fail == 1) || (ext_dep && (ignore_fail == 2))) {
7240 req_inst = -1;
7241 } else {
7242 req_inst = t->info.inst.req;
7243 }
7244
Michal Vaskod3a03112017-01-23 09:56:02 +01007245 if (!resolve_instid((struct lyd_node *)leaf, (json_val ? json_val : leaf->value_str), req_inst, &ret)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007246 if (store) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007247 if (ret && !ext_dep) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007248 /* valid resolved */
7249 leaf->value.instance = ret;
7250 leaf->value_type = LY_TYPE_INST;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007251
Michal Vaskofd6c6502017-01-06 12:15:41 +01007252 if (json_val) {
7253 lydict_remove(leaf->schema->module->ctx, leaf->value_str);
7254 leaf->value_str = json_val;
7255 json_val = NULL;
7256 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007257 } else {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007258 /* valid unresolved */
7259 if (json_val) {
7260 /* put the JSON val back */
7261 leaf->value.string = json_val;
7262 json_val = NULL;
7263 } else {
7264 leaf->value.instance = NULL;
7265 }
7266 leaf->value_type = LY_TYPE_INST | LY_TYPE_INST_UNRES;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007267 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007268 }
7269
7270 success = 1;
7271 }
7272 break;
7273 default:
Radek Krejcia571d942017-02-24 09:26:49 +01007274 if (lyp_parse_value(t, &leaf->value_str, NULL, leaf, NULL, store, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007275 success = 1;
7276 }
7277 break;
7278 }
7279
7280 if (success) {
7281 break;
7282 }
7283
7284 /* erase information about errors - they are false or irrelevant
7285 * and will be replaced by a single error messages */
7286 ly_err_clean(1);
7287
7288 /* erase possible present and invalid value data */
Michal Vaskofd6c6502017-01-06 12:15:41 +01007289 if (store) {
7290 if (t->base == LY_TYPE_BITS) {
7291 free(leaf->value.bit);
7292 }
7293 memset(&leaf->value, 0, sizeof leaf->value);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007294 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007295 }
7296
7297 /* turn logging back on */
7298 if (!hidden) {
7299 ly_vlog_hide(0);
7300 }
7301
7302 if (json_val) {
7303 if (!success) {
7304 /* put the value back for now */
7305 assert(leaf->value_type == LY_TYPE_UNION);
7306 leaf->value.string = json_val;
7307 } else {
7308 /* value was ultimately useless, but we could not have known */
7309 lydict_remove(leaf->schema->module->ctx, json_val);
7310 }
7311 }
7312
Michal Vaskofd6c6502017-01-06 12:15:41 +01007313 if (success) {
7314 if (resolved_type) {
7315 *resolved_type = t;
7316 }
7317 } else if (!ignore_fail || !type->info.uni.has_ptr_type) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007318 /* not found and it is required */
7319 LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, leaf->value_str ? leaf->value_str : "", leaf->schema->name);
Radek Krejci9b6aad22016-09-20 15:55:51 +02007320 return EXIT_FAILURE;
7321 }
7322
7323 return EXIT_SUCCESS;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007324
Radek Krejci9b6aad22016-09-20 15:55:51 +02007325}
7326
Michal Vasko8bcdf292015-08-19 14:04:43 +02007327/**
7328 * @brief Resolve a single unres data item. Logs directly.
7329 *
Michal Vaskocf024702015-10-08 15:01:42 +02007330 * @param[in] node Data node to resolve.
Michal Vaskocf024702015-10-08 15:01:42 +02007331 * @param[in] type Type of the unresolved item.
Michal Vasko3cfa3182017-01-17 10:00:58 +01007332 * @param[in] ignore_fail 0 - no, 1 - yes, 2 - yes, but only for external dependencies.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007333 *
7334 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
7335 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02007336int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007337resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type, int ignore_fail)
Michal Vasko8bcdf292015-08-19 14:04:43 +02007338{
Michal Vasko3cfa3182017-01-17 10:00:58 +01007339 int rc, req_inst, ext_dep;
Michal Vasko83a6c462015-10-08 16:43:53 +02007340 struct lyd_node_leaf_list *leaf;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007341 struct lyd_node *ret;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007342 struct lys_node_leaf *sleaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007343
Michal Vasko83a6c462015-10-08 16:43:53 +02007344 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02007345 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007346
Michal Vaskocf024702015-10-08 15:01:42 +02007347 switch (type) {
7348 case UNRES_LEAFREF:
7349 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007350 assert(leaf->validity & LYD_VAL_LEAFREF);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007351 if ((ignore_fail == 1) || ((leaf->schema->flags & LYS_LEAFREF_DEP) && (ignore_fail == 2))) {
7352 req_inst = -1;
7353 } else {
7354 req_inst = sleaf->type.info.lref.req;
7355 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007356 rc = resolve_leafref(leaf, sleaf->type.info.lref.path, req_inst, &ret);
7357 if (!rc) {
Michal Vaskob1ac8722017-01-02 13:04:25 +01007358 if (ret && !(leaf->schema->flags & LYS_LEAFREF_DEP)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007359 /* valid resolved */
Michal Vasko1c8567a2017-01-05 13:42:27 +01007360 if ((leaf->value_type & LY_DATA_TYPE_MASK) == LY_TYPE_BITS) {
7361 free(leaf->value.bit);
7362 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007363 leaf->value.leafref = ret;
7364 leaf->value_type = LY_TYPE_LEAFREF;
7365 } else {
7366 /* valid unresolved */
7367 if (!(leaf->value_type & LY_TYPE_LEAFREF_UNRES)) {
Radek Krejcia571d942017-02-24 09:26:49 +01007368 if (!lyp_parse_value(&sleaf->type, &leaf->value_str, NULL, leaf, NULL, 1, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007369 return -1;
7370 }
7371 }
7372 }
7373 leaf->validity &= ~LYD_VAL_LEAFREF;
7374 } else {
7375 return rc;
7376 }
7377 break;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007378
Michal Vaskocf024702015-10-08 15:01:42 +02007379 case UNRES_INSTID:
Radek Krejci7de36cf2016-09-12 16:18:50 +02007380 assert(sleaf->type.base == LY_TYPE_INST);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007381 ext_dep = check_instid_ext_dep(leaf->schema, leaf->value_str);
7382 if (ext_dep == -1) {
7383 return -1;
7384 }
7385
7386 if ((ignore_fail == 1) || (ext_dep && (ignore_fail == 2))) {
7387 req_inst = -1;
7388 } else {
7389 req_inst = sleaf->type.info.inst.req;
7390 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007391 rc = resolve_instid(node, leaf->value_str, req_inst, &ret);
7392 if (!rc) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007393 if (ret && !ext_dep) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007394 /* valid resolved */
7395 leaf->value.instance = ret;
7396 leaf->value_type = LY_TYPE_INST;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007397 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007398 /* valid unresolved */
7399 leaf->value.instance = NULL;
7400 leaf->value_type = LY_TYPE_INST | LY_TYPE_INST_UNRES;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007401 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007402 } else {
7403 return rc;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007404 }
Michal Vaskocf024702015-10-08 15:01:42 +02007405 break;
7406
Radek Krejci7de36cf2016-09-12 16:18:50 +02007407 case UNRES_UNION:
7408 assert(sleaf->type.base == LY_TYPE_UNION);
Michal Vaskofd6c6502017-01-06 12:15:41 +01007409 return resolve_union(leaf, &sleaf->type, 1, ignore_fail, NULL);
Radek Krejci7de36cf2016-09-12 16:18:50 +02007410
Michal Vaskocf024702015-10-08 15:01:42 +02007411 case UNRES_WHEN:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007412 if ((rc = resolve_when(node, NULL, ignore_fail))) {
Michal Vaskocf024702015-10-08 15:01:42 +02007413 return rc;
7414 }
7415 break;
7416
Michal Vaskobf19d252015-10-08 15:39:17 +02007417 case UNRES_MUST:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007418 if ((rc = resolve_must(node, 0, ignore_fail))) {
Michal Vaskoc8c810c2016-09-15 14:02:00 +02007419 return rc;
7420 }
7421 break;
7422
7423 case UNRES_MUST_INOUT:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007424 if ((rc = resolve_must(node, 1, ignore_fail))) {
Michal Vaskobf19d252015-10-08 15:39:17 +02007425 return rc;
7426 }
7427 break;
7428
Michal Vaskocf024702015-10-08 15:01:42 +02007429 default:
Michal Vasko8bcdf292015-08-19 14:04:43 +02007430 LOGINT;
7431 return -1;
7432 }
7433
7434 return EXIT_SUCCESS;
7435}
7436
7437/**
Radek Krejci0b7704f2016-03-18 12:16:14 +01007438 * @brief add data unres item
Michal Vasko8bcdf292015-08-19 14:04:43 +02007439 *
7440 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02007441 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007442 *
Radek Krejci0b7704f2016-03-18 12:16:14 +01007443 * @return 0 on success, -1 on error.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007444 */
7445int
Radek Krejci0b7704f2016-03-18 12:16:14 +01007446unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02007447{
Radek Krejci03b71f72016-03-16 11:10:09 +01007448 assert(unres && node);
Michal Vaskoc4280842016-04-19 16:10:42 +02007449 assert((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)
Radek Krejcibacc7442016-10-27 13:39:56 +02007450 || (type == UNRES_MUST_INOUT) || (type == UNRES_UNION));
Michal Vasko8bcdf292015-08-19 14:04:43 +02007451
Radek Krejci03b71f72016-03-16 11:10:09 +01007452 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01007453 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
Radek Krejciaa1303c2017-05-31 13:57:37 +02007454 LY_CHECK_ERR_RETURN(!unres->node, LOGMEM, -1);
Michal Vaskocf024702015-10-08 15:01:42 +02007455 unres->node[unres->count - 1] = node;
Michal Vasko253035f2015-12-17 16:58:13 +01007456 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
Radek Krejciaa1303c2017-05-31 13:57:37 +02007457 LY_CHECK_ERR_RETURN(!unres->type, LOGMEM, -1);
Michal Vaskocf024702015-10-08 15:01:42 +02007458 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007459
Radek Krejci0b7704f2016-03-18 12:16:14 +01007460 if (type == UNRES_WHEN) {
7461 /* remove previous result */
7462 node->when_status = LYD_WHEN;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007463 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007464
7465 return EXIT_SUCCESS;
7466}
7467
7468/**
7469 * @brief Resolve every unres data item in the structure. Logs directly.
7470 *
Radek Krejci082c84f2016-10-17 16:33:06 +02007471 * If options includes LYD_OPT_TRUSTED, the data are considered trusted (when, must conditions are not expected,
7472 * unresolved leafrefs/instids are accepted).
7473 *
7474 * If options includes LYD_OPT_NOAUTODEL, the false resulting when condition on non-default nodes, the error is raised.
7475 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007476 * @param[in] unres Unres data structure to use.
Radek Krejci082c84f2016-10-17 16:33:06 +02007477 * @param[in,out] root Root node of the data tree, can be changed due to autodeletion.
7478 * @param[in] options Data options as described above.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007479 *
7480 * @return EXIT_SUCCESS on success, -1 on error.
7481 */
7482int
Radek Krejci082c84f2016-10-17 16:33:06 +02007483resolve_unres_data(struct unres_data *unres, struct lyd_node **root, int options)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007484{
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007485 uint32_t i, j, first, resolved, del_items, stmt_count;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007486 int rc, progress, ignore_fail;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007487 struct lyd_node *parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007488
Radek Krejci082c84f2016-10-17 16:33:06 +02007489 assert(root);
Radek Krejci03b71f72016-03-16 11:10:09 +01007490 assert(unres);
Radek Krejci03b71f72016-03-16 11:10:09 +01007491
7492 if (!unres->count) {
7493 return EXIT_SUCCESS;
7494 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007495
Michal Vaskoad2e44a2017-01-03 10:31:35 +01007496 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 +01007497 ignore_fail = 1;
7498 } else if (options & LYD_OPT_NOEXTDEPS) {
7499 ignore_fail = 2;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007500 } else {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007501 ignore_fail = 0;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007502 }
7503
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02007504 LOGVRB("Resolving unresolved data nodes and their constraints...");
Radek Krejci010e54b2016-03-15 09:40:34 +01007505 ly_vlog_hide(1);
7506
Radek Krejci0b7704f2016-03-18 12:16:14 +01007507 /* when-stmt first */
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007508 first = 1;
7509 stmt_count = 0;
7510 resolved = 0;
7511 del_items = 0;
Radek Krejci010e54b2016-03-15 09:40:34 +01007512 do {
Radek Krejci00a0e712016-10-26 10:24:46 +02007513 ly_err_clean(1);
Radek Krejci010e54b2016-03-15 09:40:34 +01007514 progress = 0;
Michal Vasko6df94132016-09-22 11:08:09 +02007515 for (i = 0; i < unres->count; i++) {
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007516 if (unres->type[i] != UNRES_WHEN) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007517 continue;
7518 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007519 if (first) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007520 /* count when-stmt nodes in unres list */
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007521 stmt_count++;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007522 }
7523
7524 /* resolve when condition only when all parent when conditions are already resolved */
7525 for (parent = unres->node[i]->parent;
7526 parent && LYD_WHEN_DONE(parent->when_status);
7527 parent = parent->parent) {
7528 if (!parent->parent && (parent->when_status & LYD_WHEN_FALSE)) {
7529 /* the parent node was already unlinked, do not resolve this node,
7530 * it will be removed anyway, so just mark it as resolved
7531 */
7532 unres->node[i]->when_status |= LYD_WHEN_FALSE;
7533 unres->type[i] = UNRES_RESOLVED;
7534 resolved++;
7535 break;
7536 }
7537 }
7538 if (parent) {
7539 continue;
7540 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007541
Michal Vasko3cfa3182017-01-17 10:00:58 +01007542 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail);
Radek Krejci010e54b2016-03-15 09:40:34 +01007543 if (!rc) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007544 if (unres->node[i]->when_status & LYD_WHEN_FALSE) {
Radek Krejci082c84f2016-10-17 16:33:06 +02007545 if ((options & LYD_OPT_NOAUTODEL) && !unres->node[i]->dflt) {
Radek Krejci03b71f72016-03-16 11:10:09 +01007546 /* false when condition */
7547 ly_vlog_hide(0);
Radek Krejci2467a492016-10-24 15:16:59 +02007548 ly_err_repeat();
Radek Krejci03b71f72016-03-16 11:10:09 +01007549 return -1;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007550 } /* follows else */
7551
Michal Vaskoe31d34a2017-03-28 14:50:38 +02007552 /* auto-delete */
7553 LOGVRB("auto-delete node \"%s\" due to when condition (%s)", ly_errpath(),
7554 ((struct lys_node_leaf *)unres->node[i]->schema)->when->cond);
7555
Radek Krejci0c0086a2016-03-24 15:20:28 +01007556 /* only unlink now, the subtree can contain another nodes stored in the unres list */
7557 /* if it has parent non-presence containers that would be empty, we should actually
7558 * remove the container
7559 */
Radek Krejci2537fd32016-09-07 16:22:41 +02007560 for (parent = unres->node[i];
7561 parent->parent && parent->parent->schema->nodetype == LYS_CONTAINER;
7562 parent = parent->parent) {
7563 if (((struct lys_node_container *)parent->parent->schema)->presence) {
7564 /* presence container */
7565 break;
Radek Krejci0c0086a2016-03-24 15:20:28 +01007566 }
Radek Krejci2537fd32016-09-07 16:22:41 +02007567 if (parent->next || parent->prev != parent) {
7568 /* non empty (the child we are in and we are going to remove is not the only child) */
7569 break;
7570 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007571 }
Radek Krejci2537fd32016-09-07 16:22:41 +02007572 unres->node[i] = parent;
Radek Krejci0c0086a2016-03-24 15:20:28 +01007573
Radek Krejci0c0086a2016-03-24 15:20:28 +01007574 if (*root && *root == unres->node[i]) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007575 *root = (*root)->next;
Radek Krejci03b71f72016-03-16 11:10:09 +01007576 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007577
Radek Krejci0b7704f2016-03-18 12:16:14 +01007578 lyd_unlink(unres->node[i]);
7579 unres->type[i] = UNRES_DELETE;
7580 del_items++;
Radek Krejci51fd8162016-03-24 15:49:51 +01007581
7582 /* update the rest of unres items */
7583 for (j = 0; j < unres->count; j++) {
Radek Krejci3db819b2016-03-24 16:29:48 +01007584 if (unres->type[j] == UNRES_RESOLVED || unres->type[j] == UNRES_DELETE) {
Radek Krejci51fd8162016-03-24 15:49:51 +01007585 continue;
7586 }
7587
7588 /* test if the node is in subtree to be deleted */
7589 for (parent = unres->node[j]; parent; parent = parent->parent) {
7590 if (parent == unres->node[i]) {
7591 /* yes, it is */
7592 unres->type[j] = UNRES_RESOLVED;
7593 resolved++;
7594 break;
7595 }
7596 }
7597 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007598 } else {
7599 unres->type[i] = UNRES_RESOLVED;
Radek Krejci03b71f72016-03-16 11:10:09 +01007600 }
Radek Krejci00a0e712016-10-26 10:24:46 +02007601 ly_err_clean(1);
Radek Krejci010e54b2016-03-15 09:40:34 +01007602 resolved++;
7603 progress = 1;
7604 } else if (rc == -1) {
7605 ly_vlog_hide(0);
Michal Vasko76e73402016-08-24 16:00:13 +02007606 /* print only this last error */
Michal Vasko3cfa3182017-01-17 10:00:58 +01007607 resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail);
Radek Krejci010e54b2016-03-15 09:40:34 +01007608 return -1;
Radek Krejci2467a492016-10-24 15:16:59 +02007609 } /* else forward reference */
Radek Krejci010e54b2016-03-15 09:40:34 +01007610 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007611 first = 0;
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007612 } while (progress && resolved < stmt_count);
Radek Krejci010e54b2016-03-15 09:40:34 +01007613
Radek Krejci0b7704f2016-03-18 12:16:14 +01007614 /* do we have some unresolved when-stmt? */
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007615 if (stmt_count > resolved) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007616 ly_vlog_hide(0);
Radek Krejci2467a492016-10-24 15:16:59 +02007617 ly_err_repeat();
Radek Krejci0b7704f2016-03-18 12:16:14 +01007618 return -1;
7619 }
7620
7621 for (i = 0; del_items && i < unres->count; i++) {
7622 /* we had some when-stmt resulted to false, so now we have to sanitize the unres list */
7623 if (unres->type[i] != UNRES_DELETE) {
7624 continue;
7625 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007626 if (!unres->node[i]) {
7627 unres->type[i] = UNRES_RESOLVED;
7628 del_items--;
7629 continue;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007630 }
7631
7632 /* really remove the complete subtree */
7633 lyd_free(unres->node[i]);
7634 unres->type[i] = UNRES_RESOLVED;
7635 del_items--;
7636 }
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007637
7638 /* now leafrefs */
7639 first = 1;
7640 stmt_count = 0;
7641 resolved = 0;
7642 do {
7643 progress = 0;
7644 for (i = 0; i < unres->count; i++) {
7645 if (unres->type[i] != UNRES_LEAFREF) {
7646 continue;
7647 }
7648 if (first) {
7649 /* count leafref nodes in unres list */
7650 stmt_count++;
7651 }
7652
7653 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail);
7654 if (!rc) {
7655 unres->type[i] = UNRES_RESOLVED;
7656 ly_err_clean(1);
7657 resolved++;
7658 progress = 1;
7659 } else if (rc == -1) {
7660 ly_vlog_hide(0);
7661 /* print only this last error */
7662 resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail);
7663 return -1;
7664 } /* else forward reference */
7665 }
7666 first = 0;
7667 } while (progress && resolved < stmt_count);
7668
7669 /* do we have some unresolved leafrefs? */
7670 if (stmt_count > resolved) {
7671 ly_vlog_hide(0);
7672 ly_err_repeat();
7673 return -1;
7674 }
7675
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007676 ly_vlog_hide(0);
Radek Krejci010e54b2016-03-15 09:40:34 +01007677
7678 /* rest */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007679 for (i = 0; i < unres->count; ++i) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007680 if (unres->type[i] == UNRES_RESOLVED) {
7681 continue;
7682 }
Radek Krejci082c84f2016-10-17 16:33:06 +02007683 assert(!(options & LYD_OPT_TRUSTED) || ((unres->type[i] != UNRES_MUST) && (unres->type[i] != UNRES_MUST_INOUT)));
Radek Krejci010e54b2016-03-15 09:40:34 +01007684
Michal Vasko3cfa3182017-01-17 10:00:58 +01007685 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007686 if (rc) {
7687 /* since when was already resolved, a forward reference is an error */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007688 return -1;
7689 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007690
7691 unres->type[i] = UNRES_RESOLVED;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007692 }
7693
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02007694 LOGVRB("All data nodes and constraints resolved.");
Radek Krejci010e54b2016-03-15 09:40:34 +01007695 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007696 return EXIT_SUCCESS;
7697}