blob: ebe9d5315a87fbc409e9498f349a76ef560c7308 [file] [log] [blame]
Michal Vasko730dfdf2015-08-11 14:48:05 +02001/**
2 * @file resolve.c
3 * @author Michal Vasko <mvasko@cesnet.cz>
4 * @brief libyang resolve functions
5 *
6 * Copyright (c) 2015 CESNET, z.s.p.o.
7 *
Radek Krejci54f6fb32016-02-24 12:56:39 +01008 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
Michal Vasko8de098c2016-02-26 10:00:25 +010011 *
Radek Krejci54f6fb32016-02-24 12:56:39 +010012 * https://opensource.org/licenses/BSD-3-Clause
Michal Vasko730dfdf2015-08-11 14:48:05 +020013 */
14
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020015#define _GNU_SOURCE
16
17#include <stdlib.h>
18#include <assert.h>
19#include <string.h>
20#include <ctype.h>
Michal Vaskoe7fc19c2015-08-05 16:24:39 +020021#include <limits.h>
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020022
23#include "libyang.h"
24#include "resolve.h"
25#include "common.h"
Michal Vaskocf024702015-10-08 15:01:42 +020026#include "xpath.h"
Michal Vasko1dca6882015-10-22 14:29:42 +020027#include "parser.h"
Pavol Vicana0e4e672016-02-24 12:20:04 +010028#include "parser_yang.h"
Michal Vasko88c29542015-11-27 14:57:53 +010029#include "xml_internal.h"
Radek Krejci41912fe2015-10-22 10:22:12 +020030#include "dict_private.h"
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020031#include "tree_internal.h"
32
Michal Vaskod24dd012016-09-30 12:20:22 +020033int
34parse_range_dec64(const char **str_num, uint8_t dig, int64_t *num)
Michal Vasko4d1f0482016-09-19 14:35:06 +020035{
36 const char *ptr;
37 int minus = 0;
38 int64_t ret = 0;
Radek Krejcibf47a822016-11-04 10:06:08 +010039 int8_t str_exp, str_dig = -1, trailing_zeros = 0;
Michal Vasko4d1f0482016-09-19 14:35:06 +020040
41 ptr = *str_num;
42
43 if (ptr[0] == '-') {
44 minus = 1;
45 ++ptr;
Radek Krejci51673202016-11-01 17:00:32 +010046 } else if (ptr[0] == '+') {
47 ++ptr;
Michal Vasko4d1f0482016-09-19 14:35:06 +020048 }
49
Michal Vaskod24dd012016-09-30 12:20:22 +020050 if (!isdigit(ptr[0])) {
51 /* there must be at least one */
52 return 1;
53 }
54
Michal Vasko4d1f0482016-09-19 14:35:06 +020055 for (str_exp = 0; isdigit(ptr[0]) || ((ptr[0] == '.') && (str_dig < 0)); ++ptr) {
56 if (str_exp > 18) {
Michal Vaskod24dd012016-09-30 12:20:22 +020057 return 1;
Michal Vasko4d1f0482016-09-19 14:35:06 +020058 }
59
60 if (ptr[0] == '.') {
61 if (ptr[1] == '.') {
62 /* it's the next interval */
63 break;
64 }
65 ++str_dig;
66 } else {
Radek Krejcibf47a822016-11-04 10:06:08 +010067 ret = ret * 10 + (ptr[0] - '0');
Michal Vasko4d1f0482016-09-19 14:35:06 +020068 if (str_dig > -1) {
69 ++str_dig;
Radek Krejcibf47a822016-11-04 10:06:08 +010070 if (ptr[0] == '0') {
71 /* possibly trailing zero */
72 trailing_zeros++;
73 } else {
74 trailing_zeros = 0;
75 }
Michal Vasko4d1f0482016-09-19 14:35:06 +020076 }
77 ++str_exp;
78 }
79 }
Michal Vaskod24dd012016-09-30 12:20:22 +020080 if (str_dig == 0) {
81 /* no digits after '.' */
82 return 1;
83 } else if (str_dig == -1) {
84 /* there are 0 numbers after the floating point */
Michal Vasko4d1f0482016-09-19 14:35:06 +020085 str_dig = 0;
86 }
Radek Krejcibf47a822016-11-04 10:06:08 +010087 /* remove trailing zeros */
88 if (trailing_zeros) {
Michal Vasko6ca5ca72016-11-28 09:21:51 +010089 str_dig -= trailing_zeros;
90 str_exp -= trailing_zeros;
Radek Krejcibf47a822016-11-04 10:06:08 +010091 ret = ret / dec_pow(trailing_zeros);
92 }
Michal Vasko4d1f0482016-09-19 14:35:06 +020093
94 /* it's parsed, now adjust the number based on fraction-digits, if needed */
95 if (str_dig < dig) {
96 if ((str_exp - 1) + (dig - str_dig) > 18) {
Michal Vaskod24dd012016-09-30 12:20:22 +020097 return 1;
Michal Vasko4d1f0482016-09-19 14:35:06 +020098 }
99 ret *= dec_pow(dig - str_dig);
100 }
101 if (str_dig > dig) {
Michal Vaskod24dd012016-09-30 12:20:22 +0200102 return 1;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200103 }
104
105 if (minus) {
106 ret *= -1;
107 }
108 *str_num = ptr;
Michal Vaskod24dd012016-09-30 12:20:22 +0200109 *num = ret;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200110
Michal Vaskod24dd012016-09-30 12:20:22 +0200111 return 0;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200112}
113
114/**
Radek Krejci6dc53a22015-08-17 13:27:59 +0200115 * @brief Parse an identifier.
116 *
117 * ;; An identifier MUST NOT start with (('X'|'x') ('M'|'m') ('L'|'l'))
118 * identifier = (ALPHA / "_")
119 * *(ALPHA / DIGIT / "_" / "-" / ".")
120 *
Michal Vaskobb211122015-08-19 14:03:11 +0200121 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200122 *
123 * @return Number of characters successfully parsed.
124 */
Michal Vasko249e6b52015-08-19 11:08:52 +0200125int
Radek Krejci6dc53a22015-08-17 13:27:59 +0200126parse_identifier(const char *id)
127{
128 int parsed = 0;
129
Michal Vasko1ab90bc2016-03-15 10:40:22 +0100130 assert(id);
131
Radek Krejci6dc53a22015-08-17 13:27:59 +0200132 if (!isalpha(id[0]) && (id[0] != '_')) {
133 return -parsed;
134 }
135
136 ++parsed;
137 ++id;
138
139 while (isalnum(id[0]) || (id[0] == '_') || (id[0] == '-') || (id[0] == '.')) {
140 ++parsed;
141 ++id;
142 }
143
144 return parsed;
145}
146
147/**
148 * @brief Parse a node-identifier.
149 *
Michal Vasko723e50c2015-10-20 15:20:29 +0200150 * node-identifier = [module-name ":"] identifier
Radek Krejci6dc53a22015-08-17 13:27:59 +0200151 *
Michal Vaskobb211122015-08-19 14:03:11 +0200152 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200153 * @param[out] mod_name Points to the module name, NULL if there is not any.
154 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200155 * @param[out] name Points to the node name.
156 * @param[out] nam_len Length of the node name.
157 *
158 * @return Number of characters successfully parsed,
159 * positive on success, negative on failure.
160 */
161static int
Michal Vasko723e50c2015-10-20 15:20:29 +0200162parse_node_identifier(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200163{
164 int parsed = 0, ret;
165
166 assert(id);
Michal Vasko723e50c2015-10-20 15:20:29 +0200167 if (mod_name) {
168 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200169 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200170 if (mod_name_len) {
171 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200172 }
173 if (name) {
174 *name = NULL;
175 }
176 if (nam_len) {
177 *nam_len = 0;
178 }
179
180 if ((ret = parse_identifier(id)) < 1) {
181 return ret;
182 }
183
Michal Vasko723e50c2015-10-20 15:20:29 +0200184 if (mod_name) {
185 *mod_name = id;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200186 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200187 if (mod_name_len) {
188 *mod_name_len = ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200189 }
190
191 parsed += ret;
192 id += ret;
193
194 /* there is prefix */
195 if (id[0] == ':') {
196 ++parsed;
197 ++id;
198
199 /* there isn't */
200 } else {
Michal Vasko723e50c2015-10-20 15:20:29 +0200201 if (name && mod_name) {
202 *name = *mod_name;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200203 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200204 if (mod_name) {
205 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200206 }
207
Michal Vasko723e50c2015-10-20 15:20:29 +0200208 if (nam_len && mod_name_len) {
209 *nam_len = *mod_name_len;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200210 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200211 if (mod_name_len) {
212 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200213 }
214
215 return parsed;
216 }
217
218 /* identifier (node name) */
219 if ((ret = parse_identifier(id)) < 1) {
220 return -parsed+ret;
221 }
222
223 if (name) {
224 *name = id;
225 }
226 if (nam_len) {
227 *nam_len = ret;
228 }
229
230 return parsed+ret;
231}
232
233/**
234 * @brief Parse a path-predicate (leafref).
235 *
236 * path-predicate = "[" *WSP path-equality-expr *WSP "]"
237 * path-equality-expr = node-identifier *WSP "=" *WSP path-key-expr
238 *
Michal Vaskobb211122015-08-19 14:03:11 +0200239 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200240 * @param[out] prefix Points to the prefix, NULL if there is not any.
241 * @param[out] pref_len Length of the prefix, 0 if there is not any.
242 * @param[out] name Points to the node name.
243 * @param[out] nam_len Length of the node name.
244 * @param[out] path_key_expr Points to the path-key-expr.
245 * @param[out] pke_len Length of the path-key-expr.
246 * @param[out] has_predicate Flag to mark whether there is another predicate following.
247 *
248 * @return Number of characters successfully parsed,
249 * positive on success, negative on failure.
250 */
251static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200252parse_path_predicate(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
253 const char **path_key_expr, int *pke_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200254{
255 const char *ptr;
256 int parsed = 0, ret;
257
258 assert(id);
259 if (prefix) {
260 *prefix = NULL;
261 }
262 if (pref_len) {
263 *pref_len = 0;
264 }
265 if (name) {
266 *name = NULL;
267 }
268 if (nam_len) {
269 *nam_len = 0;
270 }
271 if (path_key_expr) {
272 *path_key_expr = NULL;
273 }
274 if (pke_len) {
275 *pke_len = 0;
276 }
277 if (has_predicate) {
278 *has_predicate = 0;
279 }
280
281 if (id[0] != '[') {
282 return -parsed;
283 }
284
285 ++parsed;
286 ++id;
287
288 while (isspace(id[0])) {
289 ++parsed;
290 ++id;
291 }
292
293 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
294 return -parsed+ret;
295 }
296
297 parsed += ret;
298 id += ret;
299
300 while (isspace(id[0])) {
301 ++parsed;
302 ++id;
303 }
304
305 if (id[0] != '=') {
306 return -parsed;
307 }
308
309 ++parsed;
310 ++id;
311
312 while (isspace(id[0])) {
313 ++parsed;
314 ++id;
315 }
316
317 if ((ptr = strchr(id, ']')) == NULL) {
318 return -parsed;
319 }
320
321 --ptr;
322 while (isspace(ptr[0])) {
323 --ptr;
324 }
325 ++ptr;
326
327 ret = ptr-id;
328 if (path_key_expr) {
329 *path_key_expr = id;
330 }
331 if (pke_len) {
332 *pke_len = ret;
333 }
334
335 parsed += ret;
336 id += ret;
337
338 while (isspace(id[0])) {
339 ++parsed;
340 ++id;
341 }
342
343 assert(id[0] == ']');
344
345 if (id[1] == '[') {
346 *has_predicate = 1;
347 }
348
349 return parsed+1;
350}
351
352/**
353 * @brief Parse a path-key-expr (leafref). First call parses "current()", all
354 * the ".." and the first node-identifier, other calls parse a single
355 * node-identifier each.
356 *
357 * path-key-expr = current-function-invocation *WSP "/" *WSP
358 * rel-path-keyexpr
359 * rel-path-keyexpr = 1*(".." *WSP "/" *WSP)
360 * *(node-identifier *WSP "/" *WSP)
361 * node-identifier
362 *
Michal Vaskobb211122015-08-19 14:03:11 +0200363 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200364 * @param[out] prefix Points to the prefix, NULL if there is not any.
365 * @param[out] pref_len Length of the prefix, 0 if there is not any.
366 * @param[out] name Points to the node name.
367 * @param[out] nam_len Length of the node name.
368 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
369 * must not be changed between consecutive calls.
370 * @return Number of characters successfully parsed,
371 * positive on success, negative on failure.
372 */
373static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200374parse_path_key_expr(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
375 int *parent_times)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200376{
377 int parsed = 0, ret, par_times = 0;
378
379 assert(id);
380 assert(parent_times);
381 if (prefix) {
382 *prefix = NULL;
383 }
384 if (pref_len) {
385 *pref_len = 0;
386 }
387 if (name) {
388 *name = NULL;
389 }
390 if (nam_len) {
391 *nam_len = 0;
392 }
393
394 if (!*parent_times) {
395 /* current-function-invocation *WSP "/" *WSP rel-path-keyexpr */
396 if (strncmp(id, "current()", 9)) {
397 return -parsed;
398 }
399
400 parsed += 9;
401 id += 9;
402
403 while (isspace(id[0])) {
404 ++parsed;
405 ++id;
406 }
407
408 if (id[0] != '/') {
409 return -parsed;
410 }
411
412 ++parsed;
413 ++id;
414
415 while (isspace(id[0])) {
416 ++parsed;
417 ++id;
418 }
419
420 /* rel-path-keyexpr */
421 if (strncmp(id, "..", 2)) {
422 return -parsed;
423 }
424 ++par_times;
425
426 parsed += 2;
427 id += 2;
428
429 while (isspace(id[0])) {
430 ++parsed;
431 ++id;
432 }
433 }
434
435 /* 1*(".." *WSP "/" *WSP) *(node-identifier *WSP "/" *WSP) node-identifier
436 *
437 * first parent reference with whitespaces already parsed
438 */
439 if (id[0] != '/') {
440 return -parsed;
441 }
442
443 ++parsed;
444 ++id;
445
446 while (isspace(id[0])) {
447 ++parsed;
448 ++id;
449 }
450
451 while (!strncmp(id, "..", 2) && !*parent_times) {
452 ++par_times;
453
454 parsed += 2;
455 id += 2;
456
457 while (isspace(id[0])) {
458 ++parsed;
459 ++id;
460 }
461
462 if (id[0] != '/') {
463 return -parsed;
464 }
465
466 ++parsed;
467 ++id;
468
469 while (isspace(id[0])) {
470 ++parsed;
471 ++id;
472 }
473 }
474
475 if (!*parent_times) {
476 *parent_times = par_times;
477 }
478
479 /* all parent references must be parsed at this point */
480 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
481 return -parsed+ret;
482 }
483
484 parsed += ret;
485 id += ret;
486
487 return parsed;
488}
489
490/**
491 * @brief Parse path-arg (leafref).
492 *
493 * path-arg = absolute-path / relative-path
494 * absolute-path = 1*("/" (node-identifier *path-predicate))
495 * relative-path = 1*(".." "/") descendant-path
496 *
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200497 * @param[in] mod Module of the context node to get correct prefix in case it is not explicitly specified
Michal Vaskobb211122015-08-19 14:03:11 +0200498 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200499 * @param[out] prefix Points to the prefix, NULL if there is not any.
500 * @param[out] pref_len Length of the prefix, 0 if there is not any.
501 * @param[out] name Points to the node name.
502 * @param[out] nam_len Length of the node name.
503 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
504 * must not be changed between consecutive calls. -1 if the
505 * path is relative.
506 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
507 *
508 * @return Number of characters successfully parsed,
509 * positive on success, negative on failure.
510 */
511static int
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200512parse_path_arg(struct lys_module *mod, const char *id, const char **prefix, int *pref_len,
513 const char **name, int *nam_len, int *parent_times, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200514{
515 int parsed = 0, ret, par_times = 0;
516
517 assert(id);
518 assert(parent_times);
519 if (prefix) {
520 *prefix = NULL;
521 }
522 if (pref_len) {
523 *pref_len = 0;
524 }
525 if (name) {
526 *name = NULL;
527 }
528 if (nam_len) {
529 *nam_len = 0;
530 }
531 if (has_predicate) {
532 *has_predicate = 0;
533 }
534
535 if (!*parent_times && !strncmp(id, "..", 2)) {
536 ++par_times;
537
538 parsed += 2;
539 id += 2;
540
541 while (!strncmp(id, "/..", 3)) {
542 ++par_times;
543
544 parsed += 3;
545 id += 3;
546 }
547 }
548
549 if (!*parent_times) {
550 if (par_times) {
551 *parent_times = par_times;
552 } else {
553 *parent_times = -1;
554 }
555 }
556
557 if (id[0] != '/') {
558 return -parsed;
559 }
560
561 /* skip '/' */
562 ++parsed;
563 ++id;
564
565 /* node-identifier ([prefix:]identifier) */
566 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
567 return -parsed-ret;
568 }
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200569 if (!(*prefix)) {
570 /* actually we always need prefix even it is not specified */
571 *prefix = lys_main_module(mod)->name;
572 *pref_len = strlen(*prefix);
573 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200574
575 parsed += ret;
576 id += ret;
577
578 /* there is no predicate */
579 if ((id[0] == '/') || !id[0]) {
580 return parsed;
581 } else if (id[0] != '[') {
582 return -parsed;
583 }
584
585 if (has_predicate) {
586 *has_predicate = 1;
587 }
588
589 return parsed;
590}
591
592/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200593 * @brief Parse instance-identifier in JSON data format. That means that prefixes
Michal Vaskob2f40be2016-09-08 16:03:48 +0200594 * (which are mandatory for every node-identifier) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200595 *
596 * instance-identifier = 1*("/" (node-identifier *predicate))
597 *
Michal Vaskobb211122015-08-19 14:03:11 +0200598 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200599 * @param[out] model Points to the model name.
600 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200601 * @param[out] name Points to the node name.
602 * @param[out] nam_len Length of the node name.
603 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
604 *
605 * @return Number of characters successfully parsed,
606 * positive on success, negative on failure.
607 */
608static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200609parse_instance_identifier(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
610 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200611{
612 int parsed = 0, ret;
613
Radek Krejci6dc53a22015-08-17 13:27:59 +0200614 if (has_predicate) {
615 *has_predicate = 0;
616 }
617
618 if (id[0] != '/') {
619 return -parsed;
620 }
621
622 ++parsed;
623 ++id;
624
Michal Vaskob2f40be2016-09-08 16:03:48 +0200625 if ((ret = parse_identifier(id)) < 1) {
626 return ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200627 }
628
Michal Vaskob2f40be2016-09-08 16:03:48 +0200629 *model = id;
630 *mod_len = ret;
631
Radek Krejci6dc53a22015-08-17 13:27:59 +0200632 parsed += ret;
633 id += ret;
634
Michal Vaskob2f40be2016-09-08 16:03:48 +0200635 if (id[0] != ':') {
636 return -parsed;
637 }
638
639 ++parsed;
640 ++id;
641
642 if ((ret = parse_identifier(id)) < 1) {
643 return ret;
644 }
645
646 *name = id;
647 *nam_len = ret;
648
649 parsed += ret;
650 id += ret;
651
Radek Krejci4967cb62016-09-14 16:40:28 +0200652 if (id[0] == '[' && has_predicate) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200653 *has_predicate = 1;
654 }
655
656 return parsed;
657}
658
659/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200660 * @brief Parse predicate (instance-identifier) in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200661 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200662 *
663 * predicate = "[" *WSP (predicate-expr / pos) *WSP "]"
664 * predicate-expr = (node-identifier / ".") *WSP "=" *WSP
665 * ((DQUOTE string DQUOTE) /
666 * (SQUOTE string SQUOTE))
667 * pos = non-negative-integer-value
668 *
Michal Vaskobb211122015-08-19 14:03:11 +0200669 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200670 * @param[out] model Points to the model name.
671 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200672 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
673 * @param[out] nam_len Length of the node name.
674 * @param[out] value Value the node-identifier must have (string from the grammar),
675 * NULL if there is not any.
676 * @param[out] val_len Length of the value, 0 if there is not any.
677 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
678 *
679 * @return Number of characters successfully parsed,
680 * positive on success, negative on failure.
681 */
682static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200683parse_predicate(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
684 const char **value, int *val_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200685{
686 const char *ptr;
687 int parsed = 0, ret;
688 char quote;
689
690 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200691 if (model) {
692 *model = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200693 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200694 if (mod_len) {
695 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200696 }
697 if (name) {
698 *name = NULL;
699 }
700 if (nam_len) {
701 *nam_len = 0;
702 }
703 if (value) {
704 *value = NULL;
705 }
706 if (val_len) {
707 *val_len = 0;
708 }
709 if (has_predicate) {
710 *has_predicate = 0;
711 }
712
713 if (id[0] != '[') {
714 return -parsed;
715 }
716
717 ++parsed;
718 ++id;
719
720 while (isspace(id[0])) {
721 ++parsed;
722 ++id;
723 }
724
725 /* pos */
726 if (isdigit(id[0])) {
727 if (name) {
728 *name = id;
729 }
730
731 if (id[0] == '0') {
Michal Vaskof2f28a12016-09-09 12:43:06 +0200732 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200733 }
734
735 while (isdigit(id[0])) {
736 ++parsed;
737 ++id;
738 }
739
740 if (nam_len) {
741 *nam_len = id-(*name);
742 }
743
Michal Vaskof2f28a12016-09-09 12:43:06 +0200744 /* "." or node-identifier */
Radek Krejci6dc53a22015-08-17 13:27:59 +0200745 } else {
Michal Vaskof2f28a12016-09-09 12:43:06 +0200746 if (id[0] == '.') {
747 if (name) {
748 *name = id;
749 }
750 if (nam_len) {
751 *nam_len = 1;
752 }
753
754 ++parsed;
755 ++id;
756
757 } else {
758 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
759 return -parsed+ret;
760 } else if (model && !*model) {
761 return -parsed;
762 }
763
764 parsed += ret;
765 id += ret;
766 }
767
768 while (isspace(id[0])) {
769 ++parsed;
770 ++id;
771 }
772
773 if (id[0] != '=') {
Michal Vasko1f2cc332015-08-19 11:18:32 +0200774 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200775 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200776
Radek Krejci6dc53a22015-08-17 13:27:59 +0200777 ++parsed;
778 ++id;
779
Michal Vaskof2f28a12016-09-09 12:43:06 +0200780 while (isspace(id[0])) {
781 ++parsed;
782 ++id;
783 }
784
785 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
786 if ((id[0] == '\"') || (id[0] == '\'')) {
787 quote = id[0];
788
789 ++parsed;
790 ++id;
791
792 if ((ptr = strchr(id, quote)) == NULL) {
793 return -parsed;
794 }
795 ret = ptr-id;
796
797 if (value) {
798 *value = id;
799 }
800 if (val_len) {
801 *val_len = ret;
802 }
803
804 parsed += ret+1;
805 id += ret+1;
806 } else {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200807 return -parsed;
808 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200809 }
810
811 while (isspace(id[0])) {
812 ++parsed;
813 ++id;
814 }
815
816 if (id[0] != ']') {
817 return -parsed;
818 }
819
820 ++parsed;
821 ++id;
822
823 if ((id[0] == '[') && has_predicate) {
824 *has_predicate = 1;
825 }
826
827 return parsed;
828}
829
830/**
831 * @brief Parse schema-nodeid.
832 *
833 * schema-nodeid = absolute-schema-nodeid /
834 * descendant-schema-nodeid
835 * absolute-schema-nodeid = 1*("/" node-identifier)
Michal Vasko48935352016-03-29 11:52:36 +0200836 * descendant-schema-nodeid = ["." "/"]
Radek Krejci6dc53a22015-08-17 13:27:59 +0200837 * node-identifier
838 * absolute-schema-nodeid
839 *
Michal Vaskobb211122015-08-19 14:03:11 +0200840 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200841 * @param[out] mod_name Points to the module name, NULL if there is not any.
842 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Michal Vasko48935352016-03-29 11:52:36 +0200843 * @param[out] name Points to the node name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200844 * @param[out] nam_len Length of the node name.
845 * @param[out] is_relative Flag to mark whether the nodeid is absolute or descendant. Must be -1
846 * on the first call, must not be changed between consecutive calls.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100847 * @param[out] has_predicate Flag to mark whether there is a predicate specified. It cannot be
848 * based on the grammar, in those cases use NULL.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200849 *
850 * @return Number of characters successfully parsed,
851 * positive on success, negative on failure.
852 */
Michal Vasko22448d32016-03-16 13:17:29 +0100853int
Michal Vasko723e50c2015-10-20 15:20:29 +0200854parse_schema_nodeid(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len,
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100855 int *is_relative, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200856{
857 int parsed = 0, ret;
858
859 assert(id);
860 assert(is_relative);
Michal Vasko723e50c2015-10-20 15:20:29 +0200861 if (mod_name) {
862 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200863 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200864 if (mod_name_len) {
865 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200866 }
867 if (name) {
868 *name = NULL;
869 }
870 if (nam_len) {
871 *nam_len = 0;
872 }
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100873 if (has_predicate) {
874 *has_predicate = 0;
875 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200876
877 if (id[0] != '/') {
878 if (*is_relative != -1) {
879 return -parsed;
880 } else {
881 *is_relative = 1;
882 }
Michal Vasko48935352016-03-29 11:52:36 +0200883 if (!strncmp(id, "./", 2)) {
884 parsed += 2;
885 id += 2;
886 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200887 } else {
888 if (*is_relative == -1) {
889 *is_relative = 0;
890 }
891 ++parsed;
892 ++id;
893 }
894
Michal Vasko723e50c2015-10-20 15:20:29 +0200895 if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200896 return -parsed+ret;
897 }
898
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100899 parsed += ret;
900 id += ret;
901
902 if ((id[0] == '[') && has_predicate) {
903 *has_predicate = 1;
904 }
905
906 return parsed;
907}
908
909/**
910 * @brief Parse schema predicate (special format internally used).
911 *
912 * predicate = "[" *WSP predicate-expr *WSP "]"
Michal Vasko58c2aab2017-01-05 10:02:05 +0100913 * predicate-expr = "." / identifier / positive-integer / key-with-value
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100914 * key-with-value = identifier *WSP "=" *WSP
915 * ((DQUOTE string DQUOTE) /
916 * (SQUOTE string SQUOTE))
917 *
918 * @param[in] id Identifier to use.
919 * @param[out] name Points to the list key name.
920 * @param[out] nam_len Length of \p name.
Michal Vasko22448d32016-03-16 13:17:29 +0100921 * @param[out] value Points to the key value. If specified, key-with-value is expected.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100922 * @param[out] val_len Length of \p value.
923 * @param[out] has_predicate Flag to mark whether there is another predicate specified.
924 */
Michal Vasko22448d32016-03-16 13:17:29 +0100925int
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200926parse_schema_json_predicate(const char *id, const char **name, int *nam_len, const char **value, int *val_len,
Michal Vasko3547c532016-03-14 09:40:50 +0100927 int *has_predicate)
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100928{
929 const char *ptr;
930 int parsed = 0, ret;
931 char quote;
932
933 assert(id);
934 if (name) {
935 *name = NULL;
936 }
937 if (nam_len) {
938 *nam_len = 0;
939 }
940 if (value) {
941 *value = NULL;
942 }
943 if (val_len) {
944 *val_len = 0;
945 }
946 if (has_predicate) {
947 *has_predicate = 0;
948 }
949
950 if (id[0] != '[') {
951 return -parsed;
952 }
953
954 ++parsed;
955 ++id;
956
957 while (isspace(id[0])) {
958 ++parsed;
959 ++id;
960 }
961
Michal Vasko22448d32016-03-16 13:17:29 +0100962 /* identifier */
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200963 if (id[0] == '.') {
964 ret = 1;
Michal Vasko58c2aab2017-01-05 10:02:05 +0100965 } else if (isdigit(id[0])) {
966 if (id[0] == '0') {
967 return -parsed;
968 }
969 ret = 1;
970 while (isdigit(id[ret])) {
971 ++ret;
972 }
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200973 } else if ((ret = parse_identifier(id)) < 1) {
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100974 return -parsed + ret;
975 }
976 if (name) {
977 *name = id;
978 }
979 if (nam_len) {
980 *nam_len = ret;
981 }
982
983 parsed += ret;
984 id += ret;
985
986 while (isspace(id[0])) {
987 ++parsed;
988 ++id;
989 }
990
991 /* there is value as well */
992 if (id[0] == '=') {
Michal Vasko58c2aab2017-01-05 10:02:05 +0100993 if (name && isdigit(**name)) {
994 return -parsed;
995 }
996
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100997 ++parsed;
998 ++id;
999
1000 while (isspace(id[0])) {
1001 ++parsed;
1002 ++id;
1003 }
1004
1005 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
1006 if ((id[0] == '\"') || (id[0] == '\'')) {
1007 quote = id[0];
1008
1009 ++parsed;
1010 ++id;
1011
1012 if ((ptr = strchr(id, quote)) == NULL) {
1013 return -parsed;
1014 }
1015 ret = ptr - id;
1016
1017 if (value) {
1018 *value = id;
1019 }
1020 if (val_len) {
1021 *val_len = ret;
1022 }
1023
1024 parsed += ret + 1;
1025 id += ret + 1;
1026 } else {
1027 return -parsed;
1028 }
1029
1030 while (isspace(id[0])) {
1031 ++parsed;
1032 ++id;
1033 }
1034 }
1035
1036 if (id[0] != ']') {
1037 return -parsed;
1038 }
1039
1040 ++parsed;
1041 ++id;
1042
1043 if ((id[0] == '[') && has_predicate) {
1044 *has_predicate = 1;
1045 }
1046
1047 return parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +02001048}
1049
1050/**
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001051 * @brief Resolve (find) a feature definition. Logs directly.
1052 *
1053 * @param[in] feat_name Feature name to resolve.
1054 * @param[in] len Length of \p feat_name.
1055 * @param[in] node Node with the if-feature expression.
Radek Krejci9ff0a922016-07-14 13:08:05 +02001056 * @param[out] feature Pointer to be set to point to the feature definition, if feature not found
1057 * (return code 1), the pointer is untouched.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001058 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02001059 * @return 0 on success, 1 on forward reference, -1 on error.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001060 */
1061static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001062resolve_feature(const char *feat_name, uint16_t len, const struct lys_node *node, struct lys_feature **feature)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001063{
1064 char *str;
1065 const char *mod_name, *name;
1066 int mod_name_len, nam_len, i, j;
1067 const struct lys_module *module;
1068
Radek Krejci9ff0a922016-07-14 13:08:05 +02001069 assert(feature);
1070
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001071 /* check prefix */
1072 if ((i = parse_node_identifier(feat_name, &mod_name, &mod_name_len, &name, &nam_len)) < 1) {
1073 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, feat_name[-i], &feat_name[-i]);
1074 return -1;
1075 }
1076
1077 module = lys_get_import_module(lys_node_module(node), NULL, 0, mod_name, mod_name_len);
1078 if (!module) {
1079 /* identity refers unknown data model */
1080 LOGVAL(LYE_INMOD_LEN, LY_VLOG_NONE, NULL, mod_name_len, mod_name);
1081 return -1;
1082 }
1083
Radek Krejci9ff0a922016-07-14 13:08:05 +02001084 if (module != node->module && module == lys_node_module(node)) {
1085 /* first, try to search directly in submodule where the feature was mentioned */
1086 for (j = 0; j < node->module->features_size; j++) {
1087 if (!strncmp(name, node->module->features[j].name, nam_len) && !node->module->features[j].name[nam_len]) {
1088 /* check status */
1089 if (lyp_check_status(node->flags, lys_node_module(node), node->name, node->module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001090 node->module->features[j].module, node->module->features[j].name, NULL)) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001091 return -1;
1092 }
1093 *feature = &node->module->features[j];
1094 return 0;
1095 }
1096 }
1097 }
1098
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001099 /* search in the identified module ... */
1100 for (j = 0; j < module->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001101 if (!strncmp(name, module->features[j].name, nam_len) && !module->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001102 /* check status */
1103 if (lyp_check_status(node->flags, lys_node_module(node), node->name, module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001104 module->features[j].module, module->features[j].name, NULL)) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001105 return -1;
1106 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001107 *feature = &module->features[j];
1108 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001109 }
1110 }
1111 /* ... and all its submodules */
1112 for (i = 0; i < module->inc_size; i++) {
1113 if (!module->inc[i].submodule) {
1114 /* not yet resolved */
1115 continue;
1116 }
1117 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001118 if (!strncmp(name, module->inc[i].submodule->features[j].name, nam_len)
1119 && !module->inc[i].submodule->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001120 /* check status */
1121 if (lyp_check_status(node->flags, lys_node_module(node), node->name,
1122 module->inc[i].submodule->features[j].flags,
1123 module->inc[i].submodule->features[j].module,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001124 module->inc[i].submodule->features[j].name, NULL)) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001125 return -1;
1126 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001127 *feature = &module->inc[i].submodule->features[j];
1128 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001129 }
1130 }
1131 }
1132
1133 /* not found */
1134 str = strndup(feat_name, len);
1135 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, "feature", str);
1136 free(str);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001137 return 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001138}
1139
Radek Krejci9ff0a922016-07-14 13:08:05 +02001140/*
1141 * @return
Radek Krejci69b8d922016-07-27 13:13:41 +02001142 * - 1 if enabled
1143 * - 0 if disabled
Radek Krejci9ff0a922016-07-14 13:08:05 +02001144 * - -1 if not usable by its if-feature expression
1145 */
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001146static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001147resolve_feature_value(const struct lys_feature *feat)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001148{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001149 int i;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001150
Radek Krejci9ff0a922016-07-14 13:08:05 +02001151 for (i = 0; i < feat->iffeature_size; i++) {
Radek Krejci69b8d922016-07-27 13:13:41 +02001152 if (!resolve_iffeature(&feat->iffeature[i])) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001153 return -1;
1154 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001155 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001156
Radek Krejci69b8d922016-07-27 13:13:41 +02001157 return feat->flags & LYS_FENABLED ? 1 : 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001158}
1159
1160static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001161resolve_iffeature_recursive(struct lys_iffeature *expr, int *index_e, int *index_f)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001162{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001163 uint8_t op;
1164 int rc, a, b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001165
Radek Krejci9ff0a922016-07-14 13:08:05 +02001166 op = iff_getop(expr->expr, *index_e);
1167 (*index_e)++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001168
Radek Krejci9ff0a922016-07-14 13:08:05 +02001169 switch (op) {
1170 case LYS_IFF_F:
1171 /* resolve feature */
1172 return resolve_feature_value(expr->features[(*index_f)++]);
1173 case LYS_IFF_NOT:
1174 rc = resolve_iffeature_recursive(expr, index_e, index_f);
1175 if (rc == -1) {
1176 /* one of the referenced feature is hidden by its if-feature,
1177 * so this if-feature expression is always false */
1178 return -1;
1179 } else {
1180 /* invert result */
1181 return rc ? 0 : 1;
1182 }
1183 case LYS_IFF_AND:
1184 case LYS_IFF_OR:
1185 a = resolve_iffeature_recursive(expr, index_e, index_f);
1186 b = resolve_iffeature_recursive(expr, index_e, index_f);
1187 if (a == -1 || b == -1) {
1188 /* one of the referenced feature is hidden by its if-feature,
1189 * so this if-feature expression is always false */
1190 return -1;
1191 } else if (op == LYS_IFF_AND) {
1192 return a && b;
1193 } else { /* LYS_IFF_OR */
1194 return a || b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001195 }
1196 }
1197
Radek Krejci9ff0a922016-07-14 13:08:05 +02001198 return -1;
1199}
1200
1201int
1202resolve_iffeature(struct lys_iffeature *expr)
1203{
1204 int rc = -1;
1205 int index_e = 0, index_f = 0;
1206
1207 if (expr->expr) {
1208 rc = resolve_iffeature_recursive(expr, &index_e, &index_f);
1209 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001210 return (rc == 1) ? 1 : 0;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001211}
1212
1213struct iff_stack {
1214 int size;
1215 int index; /* first empty item */
1216 uint8_t *stack;
1217};
1218
1219static int
1220iff_stack_push(struct iff_stack *stack, uint8_t value)
1221{
1222 if (stack->index == stack->size) {
1223 stack->size += 4;
1224 stack->stack = ly_realloc(stack->stack, stack->size * sizeof *stack->stack);
1225 if (!stack->stack) {
1226 LOGMEM;
1227 stack->size = 0;
1228 return EXIT_FAILURE;
1229 }
1230 }
1231
1232 stack->stack[stack->index++] = value;
1233 return EXIT_SUCCESS;
1234}
1235
1236static uint8_t
1237iff_stack_pop(struct iff_stack *stack)
1238{
1239 stack->index--;
1240 return stack->stack[stack->index];
1241}
1242
1243static void
1244iff_stack_clean(struct iff_stack *stack)
1245{
1246 stack->size = 0;
1247 free(stack->stack);
1248}
1249
1250static void
1251iff_setop(uint8_t *list, uint8_t op, int pos)
1252{
1253 uint8_t *item;
1254 uint8_t mask = 3;
1255
1256 assert(pos >= 0);
1257 assert(op <= 3); /* max 2 bits */
1258
1259 item = &list[pos / 4];
1260 mask = mask << 2 * (pos % 4);
1261 *item = (*item) & ~mask;
1262 *item = (*item) | (op << 2 * (pos % 4));
1263}
1264
1265uint8_t
1266iff_getop(uint8_t *list, int pos)
1267{
1268 uint8_t *item;
1269 uint8_t mask = 3, result;
1270
1271 assert(pos >= 0);
1272
1273 item = &list[pos / 4];
1274 result = (*item) & (mask << 2 * (pos % 4));
1275 return result >> 2 * (pos % 4);
1276}
1277
1278#define LYS_IFF_LP 0x04 /* ( */
1279#define LYS_IFF_RP 0x08 /* ) */
1280
Radek Krejcicbb473e2016-09-16 14:48:32 +02001281/* internal structure for passing data for UNRES_IFFEAT */
1282struct unres_iffeat_data {
1283 struct lys_node *node;
1284 const char *fname;
Radek Krejci9de2c042016-10-19 16:53:06 +02001285 int infeature;
Radek Krejcicbb473e2016-09-16 14:48:32 +02001286};
1287
Radek Krejci9ff0a922016-07-14 13:08:05 +02001288void
1289resolve_iffeature_getsizes(struct lys_iffeature *iffeat, unsigned int *expr_size, unsigned int *feat_size)
1290{
1291 unsigned int e = 0, f = 0, r = 0;
1292 uint8_t op;
1293
1294 assert(iffeat);
1295
1296 if (!iffeat->expr) {
1297 goto result;
1298 }
1299
1300 do {
1301 op = iff_getop(iffeat->expr, e++);
1302 switch (op) {
1303 case LYS_IFF_NOT:
1304 if (!r) {
1305 r += 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001306 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001307 break;
1308 case LYS_IFF_AND:
1309 case LYS_IFF_OR:
1310 if (!r) {
1311 r += 2;
1312 } else {
1313 r += 1;
1314 }
1315 break;
1316 case LYS_IFF_F:
1317 f++;
1318 if (r) {
1319 r--;
1320 }
1321 break;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001322 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001323 } while(r);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001324
Radek Krejci9ff0a922016-07-14 13:08:05 +02001325result:
1326 if (expr_size) {
1327 *expr_size = e;
1328 }
1329 if (feat_size) {
1330 *feat_size = f;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001331 }
1332}
1333
1334int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001335resolve_iffeature_compile(struct lys_iffeature *iffeat_expr, const char *value, struct lys_node *node,
Radek Krejci9de2c042016-10-19 16:53:06 +02001336 int infeature, struct unres_schema *unres)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001337{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001338 const char *c = value;
1339 int r, rc = EXIT_FAILURE;
Radek Krejci69b8d922016-07-27 13:13:41 +02001340 int i, j, last_not, checkversion = 0;
1341 unsigned int f_size = 0, expr_size = 0, f_exp = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001342 uint8_t op;
1343 struct iff_stack stack = {0, 0, NULL};
Radek Krejcicbb473e2016-09-16 14:48:32 +02001344 struct unres_iffeat_data *iff_data;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001345
Radek Krejci9ff0a922016-07-14 13:08:05 +02001346 assert(c);
1347
1348 if (isspace(c[0])) {
1349 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, c[0], c);
1350 return EXIT_FAILURE;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001351 }
1352
Radek Krejci9ff0a922016-07-14 13:08:05 +02001353 /* pre-parse the expression to get sizes for arrays, also do some syntax checks of the expression */
1354 for (i = j = last_not = 0; c[i]; i++) {
1355 if (c[i] == '(') {
Radek Krejci69b8d922016-07-27 13:13:41 +02001356 checkversion = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001357 j++;
1358 continue;
1359 } else if (c[i] == ')') {
1360 j--;
1361 continue;
1362 } else if (isspace(c[i])) {
1363 continue;
1364 }
1365
1366 if (!strncmp(&c[i], "not", r = 3) || !strncmp(&c[i], "and", r = 3) || !strncmp(&c[i], "or", r = 2)) {
1367 if (c[i + r] == '\0') {
Radek Krejcia98da3f2016-07-27 14:05:22 +02001368 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
Radek Krejci9ff0a922016-07-14 13:08:05 +02001369 return EXIT_FAILURE;
1370 } else if (!isspace(c[i + r])) {
1371 /* feature name starting with the not/and/or */
1372 last_not = 0;
1373 f_size++;
1374 } else if (c[i] == 'n') { /* not operation */
1375 if (last_not) {
1376 /* double not */
1377 expr_size = expr_size - 2;
1378 last_not = 0;
1379 } else {
1380 last_not = 1;
1381 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001382 } else { /* and, or */
1383 f_exp++;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001384 /* not a not operation */
1385 last_not = 0;
1386 }
1387 i += r;
1388 } else {
1389 f_size++;
1390 last_not = 0;
1391 }
1392 expr_size++;
1393
1394 while (!isspace(c[i])) {
1395 if (!c[i] || c[i] == ')') {
1396 i--;
1397 break;
1398 }
1399 i++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001400 }
1401 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001402 if (j || f_exp != f_size) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001403 /* not matching count of ( and ) */
1404 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1405 return EXIT_FAILURE;
1406 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001407
Radek Krejci69b8d922016-07-27 13:13:41 +02001408 if (checkversion || expr_size > 1) {
1409 /* check that we have 1.1 module */
1410 if (node->module->version != 2) {
1411 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1412 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "YANG 1.1 if-feature expression found in 1.0 module.");
1413 return EXIT_FAILURE;
1414 }
1415 }
1416
Radek Krejci9ff0a922016-07-14 13:08:05 +02001417 /* allocate the memory */
1418 iffeat_expr->expr = calloc((j = (expr_size / 4) + ((expr_size % 4) ? 1 : 0)), sizeof *iffeat_expr->expr);
Radek Krejcicbb473e2016-09-16 14:48:32 +02001419 iffeat_expr->features = calloc(f_size, sizeof *iffeat_expr->features);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001420 stack.size = expr_size;
1421 stack.stack = malloc(expr_size * sizeof *stack.stack);
1422 if (!stack.stack || !iffeat_expr->expr || !iffeat_expr->features) {
1423 LOGMEM;
1424 goto error;
1425 }
1426 f_size--; expr_size--; /* used as indexes from now */
1427
1428 for (i--; i >= 0; i--) {
1429 if (c[i] == ')') {
1430 /* push it on stack */
1431 iff_stack_push(&stack, LYS_IFF_RP);
1432 continue;
1433 } else if (c[i] == '(') {
1434 /* pop from the stack into result all operators until ) */
1435 while((op = iff_stack_pop(&stack)) != LYS_IFF_RP) {
1436 iff_setop(iffeat_expr->expr, op, expr_size--);
1437 }
1438 continue;
1439 } else if (isspace(c[i])) {
1440 continue;
1441 }
1442
1443 /* end operator or operand -> find beginning and get what is it */
1444 j = i + 1;
1445 while (i >= 0 && !isspace(c[i]) && c[i] != '(') {
1446 i--;
1447 }
1448 i++; /* get back by one step */
1449
1450 if (!strncmp(&c[i], "not ", 4)) {
1451 if (stack.index && stack.stack[stack.index - 1] == LYS_IFF_NOT) {
1452 /* double not */
1453 iff_stack_pop(&stack);
1454 } else {
1455 /* not has the highest priority, so do not pop from the stack
1456 * as in case of AND and OR */
1457 iff_stack_push(&stack, LYS_IFF_NOT);
1458 }
1459 } else if (!strncmp(&c[i], "and ", 4)) {
1460 /* as for OR - pop from the stack all operators with the same or higher
1461 * priority and store them to the result, then push the AND to the stack */
1462 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_AND) {
1463 op = iff_stack_pop(&stack);
1464 iff_setop(iffeat_expr->expr, op, expr_size--);
1465 }
1466 iff_stack_push(&stack, LYS_IFF_AND);
1467 } else if (!strncmp(&c[i], "or ", 3)) {
1468 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_OR) {
1469 op = iff_stack_pop(&stack);
1470 iff_setop(iffeat_expr->expr, op, expr_size--);
1471 }
1472 iff_stack_push(&stack, LYS_IFF_OR);
1473 } else {
1474 /* feature name, length is j - i */
1475
1476 /* add it to the result */
1477 iff_setop(iffeat_expr->expr, LYS_IFF_F, expr_size--);
1478
1479 /* now get the link to the feature definition. Since it can be
Radek Krejcicbb473e2016-09-16 14:48:32 +02001480 * forward referenced, we have to keep the feature name in auxiliary
1481 * structure passed into unres */
1482 iff_data = malloc(sizeof *iff_data);
1483 iff_data->node = node;
1484 iff_data->fname = lydict_insert(node->module->ctx, &c[i], j - i);
Radek Krejci9de2c042016-10-19 16:53:06 +02001485 iff_data->infeature = infeature;
Radek Krejcicbb473e2016-09-16 14:48:32 +02001486 r = unres_schema_add_node(node->module, unres, &iffeat_expr->features[f_size], UNRES_IFFEAT,
1487 (struct lys_node *)iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001488 f_size--;
1489
1490 if (r == -1) {
Pavol Vican4d084512016-09-29 16:38:12 +02001491 free(iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001492 goto error;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001493 }
1494 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001495 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001496 while (stack.index) {
1497 op = iff_stack_pop(&stack);
1498 iff_setop(iffeat_expr->expr, op, expr_size--);
1499 }
1500
1501 if (++expr_size || ++f_size) {
1502 /* not all expected operators and operands found */
1503 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1504 rc = EXIT_FAILURE;
1505 } else {
1506 rc = EXIT_SUCCESS;
1507 }
1508
1509error:
1510 /* cleanup */
1511 iff_stack_clean(&stack);
1512
1513 return rc;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001514}
1515
1516/**
Michal Vasko3edeaf72016-02-11 13:17:43 +01001517 * @brief Resolve (find) a data node based on a schema-nodeid.
1518 *
1519 * Used for resolving unique statements - so id is expected to be relative and local (without reference to a different
1520 * module).
1521 *
1522 */
1523struct lyd_node *
1524resolve_data_descendant_schema_nodeid(const char *nodeid, struct lyd_node *start)
1525{
1526 char *str, *token, *p;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001527 struct lyd_node *result = NULL, *iter;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001528 const struct lys_node *schema = NULL;
Radek Krejcicc217a62016-04-08 16:58:11 +02001529 int shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001530
1531 assert(nodeid && start);
1532
1533 if (nodeid[0] == '/') {
1534 return NULL;
1535 }
1536
1537 str = p = strdup(nodeid);
1538 if (!str) {
1539 LOGMEM;
1540 return NULL;
1541 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001542
Michal Vasko3edeaf72016-02-11 13:17:43 +01001543 while (p) {
1544 token = p;
1545 p = strchr(p, '/');
1546 if (p) {
1547 *p = '\0';
1548 p++;
1549 }
1550
Radek Krejci5da4eb62016-04-08 14:45:51 +02001551 if (p) {
1552 /* inner node */
Radek Krejcicc217a62016-04-08 16:58:11 +02001553 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema,
Radek Krejcif3c71de2016-04-11 12:45:46 +02001554 LYS_CONTAINER | LYS_CHOICE | LYS_CASE | LYS_LEAF, 0, 0, &schema)
Radek Krejci5da4eb62016-04-08 14:45:51 +02001555 || !schema) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001556 result = NULL;
1557 break;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001558 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001559
Radek Krejci5da4eb62016-04-08 14:45:51 +02001560 if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
1561 continue;
Michal Vaskodcf98e62016-05-05 17:53:53 +02001562 } else if (lys_parent(schema)->nodetype == LYS_CHOICE) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001563 /* shorthand case */
1564 if (!shorthand) {
1565 shorthand = 1;
Michal Vaskodcf98e62016-05-05 17:53:53 +02001566 schema = lys_parent(schema);
Radek Krejcicc217a62016-04-08 16:58:11 +02001567 continue;
1568 } else {
1569 shorthand = 0;
1570 if (schema->nodetype == LYS_LEAF) {
1571 /* should not be here, since we have leaf, which is not a shorthand nor final node */
1572 result = NULL;
1573 break;
1574 }
1575 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001576 }
1577 } else {
1578 /* final node */
Radek Krejcif3c71de2016-04-11 12:45:46 +02001579 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema, LYS_LEAF,
1580 shorthand ? 0 : 1, 0, &schema)
Radek Krejcicc217a62016-04-08 16:58:11 +02001581 || !schema) {
1582 result = NULL;
1583 break;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001584 }
1585 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001586 LY_TREE_FOR(result ? result->child : start, iter) {
1587 if (iter->schema == schema) {
1588 /* move in data tree according to returned schema */
1589 result = iter;
1590 break;
1591 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001592 }
Radek Krejcicc217a62016-04-08 16:58:11 +02001593 if (!iter) {
1594 /* instance not found */
1595 result = NULL;
1596 break;
1597 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001598 }
1599 free(str);
1600
1601 return result;
1602}
1603
Radek Krejcibdf92362016-04-08 14:43:34 +02001604/*
1605 * 0 - ok (done)
1606 * 1 - continue
1607 * 2 - break
1608 * -1 - error
1609 */
1610static int
Radek Krejcicc217a62016-04-08 16:58:11 +02001611schema_nodeid_siblingcheck(const struct lys_node *sibling, int8_t *shorthand, const char *id,
Radek Krejcibdf92362016-04-08 14:43:34 +02001612 const struct lys_module *module, const char *mod_name, int mod_name_len,
Radek Krejci0fa54e92016-09-14 14:01:05 +02001613 int implemented_mod, const struct lys_node **start)
Radek Krejcibdf92362016-04-08 14:43:34 +02001614{
1615 const struct lys_module *prefix_mod;
1616
1617 /* module check */
1618 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Radek Krejcidf46e222016-11-08 11:57:37 +01001619 if (prefix_mod && implemented_mod) {
Radek Krejci2eee5c02016-12-06 19:18:05 +01001620 prefix_mod = lys_implemented_module(prefix_mod);
Radek Krejci0fa54e92016-09-14 14:01:05 +02001621 }
Radek Krejcibdf92362016-04-08 14:43:34 +02001622 if (!prefix_mod) {
1623 return -1;
1624 }
1625 if (prefix_mod != lys_node_module(sibling)) {
1626 return 1;
1627 }
1628
1629 /* check for shorthand cases - then 'start' does not change */
Michal Vaskodcf98e62016-05-05 17:53:53 +02001630 if (lys_parent(sibling) && (lys_parent(sibling)->nodetype == LYS_CHOICE) && (sibling->nodetype != LYS_CASE)) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001631 if (*shorthand != -1) {
1632 *shorthand = *shorthand ? 0 : 1;
1633 }
Radek Krejcibdf92362016-04-08 14:43:34 +02001634 }
1635
1636 /* the result node? */
1637 if (!id[0]) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001638 if (*shorthand == 1) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001639 return 1;
1640 }
1641 return 0;
1642 }
1643
Radek Krejci3a130162016-11-07 16:21:20 +01001644 if (!(*shorthand)) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001645 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02001646 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001647 return -1;
1648 }
1649 *start = sibling->child;
1650 }
1651
1652 return 2;
1653}
1654
Radek Krejcidf46e222016-11-08 11:57:37 +01001655/* start - relative, module - absolute, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1
1656 * implement: 0 - do not change the implemented status of the affected modules, 1 - change implemented status of the affected modules
1657 */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001658int
1659resolve_augment_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_module *module,
Radek Krejcidf46e222016-11-08 11:57:37 +01001660 int implement, const struct lys_node **ret)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001661{
Radek Krejcidf46e222016-11-08 11:57:37 +01001662 const char *name, *mod_name, *mod_name_prev, *id;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001663 const struct lys_node *sibling;
1664 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001665 int8_t shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001666 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcidf46e222016-11-08 11:57:37 +01001667 const struct lys_module *start_mod, *aux_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001668
1669 assert(nodeid && (start || module) && !(start && module) && ret);
1670
1671 id = nodeid;
1672
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001673 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 +01001674 return ((id - nodeid) - r) + 1;
1675 }
1676 id += r;
1677
1678 if ((is_relative && !start) || (!is_relative && !module)) {
1679 return -1;
1680 }
1681
1682 /* descendant-schema-nodeid */
1683 if (is_relative) {
Michal Vasko4c06fd82016-02-17 13:43:38 +01001684 module = start_mod = start->module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001685
1686 /* absolute-schema-nodeid */
1687 } else {
1688 start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Radek Krejcidf46e222016-11-08 11:57:37 +01001689 if (start_mod != lys_main_module(module) && start_mod && !start_mod->implemented) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001690 /* if the submodule augments the mainmodule (or in general a module augments
1691 * itself, we don't want to search for the implemented module but augments
1692 * the module anyway. But when augmenting another module, we need the implemented
1693 * revision of the module if any */
Radek Krejci2eee5c02016-12-06 19:18:05 +01001694 aux_mod = lys_implemented_module(start_mod);
Radek Krejcidf46e222016-11-08 11:57:37 +01001695 if (!aux_mod->implemented && implement) {
1696 /* make the found module implemented */
1697 if (lys_set_implemented(aux_mod)) {
1698 return -1;
1699 }
1700 }
1701 start_mod = aux_mod;
1702 implement++;
Radek Krejci0fa54e92016-09-14 14:01:05 +02001703 }
Michal Vaskoe2905632016-02-11 15:42:24 +01001704 if (!start_mod) {
1705 return -1;
1706 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001707 start = start_mod->data;
1708 }
1709
1710 while (1) {
1711 sibling = NULL;
Radek Krejcidf46e222016-11-08 11:57:37 +01001712 mod_name_prev = mod_name;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001713 while ((sibling = lys_getnext(sibling, lys_parent(start), start_mod,
1714 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
1715 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001716 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001717 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len,
Radek Krejcidf46e222016-11-08 11:57:37 +01001718 implement, &start);
Radek Krejcibdf92362016-04-08 14:43:34 +02001719 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001720 *ret = sibling;
1721 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001722 } else if (r == 1) {
1723 continue;
1724 } else if (r == 2) {
1725 break;
1726 } else {
1727 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001728 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001729 }
1730 }
1731
1732 /* no match */
1733 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001734 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001735 return EXIT_SUCCESS;
1736 }
1737
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001738 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 +01001739 return ((id - nodeid) - r) + 1;
1740 }
1741 id += r;
Radek Krejcidf46e222016-11-08 11:57:37 +01001742
1743 if ((mod_name && mod_name_prev && strncmp(mod_name, mod_name_prev, mod_name_len + 1)) ||
1744 (mod_name != mod_name_prev && (!mod_name || !mod_name_prev))) {
1745 /* we are getting into another module (augment) */
1746 if (implement) {
1747 /* we have to check that also target modules are implemented, if not, we have to change it */
1748 aux_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
1749 if (!aux_mod) {
1750 return -1;
1751 }
1752 if (!aux_mod->implemented) {
Radek Krejci2eee5c02016-12-06 19:18:05 +01001753 aux_mod = lys_implemented_module(aux_mod);
Radek Krejcidf46e222016-11-08 11:57:37 +01001754 if (!aux_mod->implemented) {
1755 /* make the found module implemented */
1756 if (lys_set_implemented(aux_mod)) {
1757 return -1;
1758 }
1759 }
1760 }
1761 } else {
1762 /* we are not implementing the module itself, so the augments outside the module are ignored */
1763 *ret = NULL;
1764 return EXIT_SUCCESS;
1765 }
1766 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001767 }
1768
1769 /* cannot get here */
1770 LOGINT;
1771 return -1;
1772}
1773
Radek Krejcif3c71de2016-04-11 12:45:46 +02001774/* unique, refine,
1775 * >0 - unexpected char on position (ret - 1),
1776 * 0 - ok (but ret can still be NULL),
1777 * -1 - error,
1778 * -2 - violated no_innerlist */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001779int
1780resolve_descendant_schema_nodeid(const char *nodeid, const struct lys_node *start, int ret_nodetype,
Radek Krejcif3c71de2016-04-11 12:45:46 +02001781 int check_shorthand, int no_innerlist, const struct lys_node **ret)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001782{
1783 const char *name, *mod_name, *id;
1784 const struct lys_node *sibling;
1785 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001786 int8_t shorthand = check_shorthand ? 0 : -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001787 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcibdf92362016-04-08 14:43:34 +02001788 const struct lys_module *module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001789
1790 assert(nodeid && start && ret);
1791 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1792
1793 id = nodeid;
1794 module = start->module;
1795
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001796 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 +01001797 return ((id - nodeid) - r) + 1;
1798 }
1799 id += r;
1800
1801 if (!is_relative) {
1802 return -1;
1803 }
1804
1805 while (1) {
1806 sibling = NULL;
1807 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
1808 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE))) {
1809 /* name match */
1810 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001811 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len, 0, &start);
Radek Krejcibdf92362016-04-08 14:43:34 +02001812 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001813 if (!(sibling->nodetype & ret_nodetype)) {
1814 /* wrong node type, too bad */
1815 continue;
1816 }
1817 *ret = sibling;
1818 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001819 } else if (r == 1) {
1820 continue;
1821 } else if (r == 2) {
1822 break;
1823 } else {
1824 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001825 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001826 }
1827 }
1828
1829 /* no match */
1830 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001831 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001832 return EXIT_SUCCESS;
Radek Krejcif3c71de2016-04-11 12:45:46 +02001833 } else if (no_innerlist && sibling->nodetype == LYS_LIST) {
1834 *ret = NULL;
1835 return -2;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001836 }
1837
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001838 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 +01001839 return ((id - nodeid) - r) + 1;
1840 }
1841 id += r;
1842 }
1843
1844 /* cannot get here */
1845 LOGINT;
1846 return -1;
1847}
1848
1849/* choice default */
1850int
1851resolve_choice_default_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node **ret)
1852{
1853 /* cannot actually be a path */
1854 if (strchr(nodeid, '/')) {
1855 return -1;
1856 }
1857
Radek Krejcif3c71de2016-04-11 12:45:46 +02001858 return resolve_descendant_schema_nodeid(nodeid, start, LYS_NO_RPC_NOTIF_NODE, 1, 0, ret);
Michal Vasko3edeaf72016-02-11 13:17:43 +01001859}
1860
1861/* uses, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1862static int
1863resolve_uses_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node_grp **ret)
1864{
1865 const struct lys_module *module;
1866 const char *mod_prefix, *name;
1867 int i, mod_prefix_len, nam_len;
1868
1869 /* parse the identifier, it must be parsed on one call */
1870 if (((i = parse_node_identifier(nodeid, &mod_prefix, &mod_prefix_len, &name, &nam_len)) < 1) || nodeid[i]) {
1871 return -i + 1;
1872 }
1873
1874 module = lys_get_import_module(start->module, mod_prefix, mod_prefix_len, NULL, 0);
1875 if (!module) {
1876 return -1;
1877 }
1878 if (module != start->module) {
1879 start = module->data;
1880 }
1881
1882 *ret = lys_find_grouping_up(name, (struct lys_node *)start);
1883
1884 return EXIT_SUCCESS;
1885}
1886
1887int
1888resolve_absolute_schema_nodeid(const char *nodeid, const struct lys_module *module, int ret_nodetype,
1889 const struct lys_node **ret)
1890{
1891 const char *name, *mod_name, *id;
1892 const struct lys_node *sibling, *start;
1893 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001894 int8_t shorthand = 0;
Radek Krejcibdf92362016-04-08 14:43:34 +02001895 const struct lys_module *abs_start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001896
1897 assert(nodeid && module && ret);
1898 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1899
1900 id = nodeid;
1901 start = module->data;
1902
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001903 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 +01001904 return ((id - nodeid) - r) + 1;
1905 }
1906 id += r;
1907
1908 if (is_relative) {
1909 return -1;
1910 }
1911
1912 abs_start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001913 if (!abs_start_mod) {
1914 return -1;
1915 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001916
1917 while (1) {
1918 sibling = NULL;
1919 while ((sibling = lys_getnext(sibling, lys_parent(start), abs_start_mod, LYS_GETNEXT_WITHCHOICE
1920 | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_WITHGROUPING))) {
1921 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001922 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001923 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len, 0, &start);
Radek Krejcibdf92362016-04-08 14:43:34 +02001924 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001925 if (!(sibling->nodetype & ret_nodetype)) {
1926 /* wrong node type, too bad */
1927 continue;
1928 }
1929 *ret = sibling;
1930 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001931 } else if (r == 1) {
1932 continue;
1933 } else if (r == 2) {
1934 break;
1935 } else {
1936 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001937 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001938 }
1939 }
1940
1941 /* no match */
1942 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001943 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001944 return EXIT_SUCCESS;
1945 }
1946
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001947 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 +01001948 return ((id - nodeid) - r) + 1;
1949 }
1950 id += r;
1951 }
1952
1953 /* cannot get here */
1954 LOGINT;
1955 return -1;
1956}
1957
Michal Vaskoe733d682016-03-14 09:08:27 +01001958static int
Michal Vasko3547c532016-03-14 09:40:50 +01001959resolve_json_schema_list_predicate(const char *predicate, const struct lys_node_list *list, int *parsed)
Michal Vaskoe733d682016-03-14 09:08:27 +01001960{
1961 const char *name;
1962 int nam_len, has_predicate, i;
1963
Michal Vasko7b54f7e2016-05-03 15:07:31 +02001964 if (((i = parse_schema_json_predicate(predicate, &name, &nam_len, NULL, NULL, &has_predicate)) < 1)
1965 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001966 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-i], &predicate[-i]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001967 return -1;
1968 }
1969
1970 predicate += i;
1971 *parsed += i;
1972
Michal Vasko58c2aab2017-01-05 10:02:05 +01001973 if (!isdigit(name[0])) {
1974 for (i = 0; i < list->keys_size; ++i) {
1975 if (!strncmp(list->keys[i]->name, name, nam_len) && !list->keys[i]->name[nam_len]) {
1976 break;
1977 }
Michal Vaskoe733d682016-03-14 09:08:27 +01001978 }
Michal Vaskoe733d682016-03-14 09:08:27 +01001979
Michal Vasko58c2aab2017-01-05 10:02:05 +01001980 if (i == list->keys_size) {
1981 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
1982 return -1;
1983 }
Michal Vaskoe733d682016-03-14 09:08:27 +01001984 }
1985
1986 /* more predicates? */
1987 if (has_predicate) {
Michal Vasko3547c532016-03-14 09:40:50 +01001988 return resolve_json_schema_list_predicate(predicate, list, parsed);
Michal Vaskoe733d682016-03-14 09:08:27 +01001989 }
1990
1991 return 0;
1992}
1993
Michal Vasko8d26e5c2016-09-08 10:03:49 +02001994/* cannot return LYS_GROUPING, LYS_AUGMENT, LYS_USES, logs directly */
Michal Vaskoe733d682016-03-14 09:08:27 +01001995const struct lys_node *
Michal Vasko8d26e5c2016-09-08 10:03:49 +02001996resolve_json_nodeid(const char *nodeid, struct ly_ctx *ctx, const struct lys_node *start)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001997{
Michal Vasko10728b52016-04-07 14:26:29 +02001998 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001999 const char *name, *mod_name, *id;
Michal Vasko3547c532016-03-14 09:40:50 +01002000 const struct lys_node *sibling;
Radek Krejcibdf92362016-04-08 14:43:34 +02002001 int r, nam_len, mod_name_len, is_relative = -1, has_predicate, shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002002 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vaskoe733d682016-03-14 09:08:27 +01002003 const struct lys_module *prefix_mod, *module, *prev_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002004
Michal Vasko3547c532016-03-14 09:40:50 +01002005 assert(nodeid && (ctx || start));
2006 if (!ctx) {
2007 ctx = start->module->ctx;
2008 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01002009
2010 id = nodeid;
2011
Michal Vaskoe733d682016-03-14 09:08:27 +01002012 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 +01002013 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002014 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002015 }
2016 id += r;
2017
2018 if (is_relative) {
Michal Vasko3547c532016-03-14 09:40:50 +01002019 assert(start);
2020 start = start->child;
2021 if (!start) {
2022 /* no descendants, fail for sure */
Michal Vasko10728b52016-04-07 14:26:29 +02002023 str = strndup(nodeid, (name + nam_len) - nodeid);
2024 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
2025 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002026 return NULL;
2027 }
2028 module = start->module;
2029 } else {
2030 if (!mod_name) {
Michal Vasko10728b52016-04-07 14:26:29 +02002031 str = strndup(nodeid, (name + nam_len) - nodeid);
2032 LOGVAL(LYE_PATH_MISSMOD, LY_VLOG_STR, nodeid);
2033 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002034 return NULL;
Michal Vasko971a3ca2016-04-01 13:09:29 +02002035 } else if (mod_name_len > LY_BUF_SIZE - 1) {
2036 LOGINT;
2037 return NULL;
Michal Vasko3547c532016-03-14 09:40:50 +01002038 }
2039
Michal Vasko971a3ca2016-04-01 13:09:29 +02002040 if (ly_buf_used && module_name[0]) {
2041 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2042 }
2043 ly_buf_used++;
2044
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002045 memmove(module_name, mod_name, mod_name_len);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002046 module_name[mod_name_len] = '\0';
2047 module = ly_ctx_get_module(ctx, module_name, NULL);
2048
2049 if (buf_backup) {
2050 /* return previous internal buffer content */
2051 strcpy(module_name, buf_backup);
2052 free(buf_backup);
2053 buf_backup = NULL;
2054 }
2055 ly_buf_used--;
2056
Michal Vasko3547c532016-03-14 09:40:50 +01002057 if (!module) {
Michal Vasko10728b52016-04-07 14:26:29 +02002058 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2059 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2060 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002061 return NULL;
2062 }
2063 start = module->data;
2064
2065 /* now it's as if there was no module name */
2066 mod_name = NULL;
2067 mod_name_len = 0;
Michal Vaskoe733d682016-03-14 09:08:27 +01002068 }
2069
Michal Vaskoe733d682016-03-14 09:08:27 +01002070 prev_mod = module;
2071
Michal Vasko3edeaf72016-02-11 13:17:43 +01002072 while (1) {
2073 sibling = NULL;
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002074 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
2075 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002076 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02002077 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002078 /* module check */
2079 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002080 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko8757e7c2016-03-15 10:41:30 +01002081 LOGINT;
2082 return NULL;
2083 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002084
2085 if (ly_buf_used && module_name[0]) {
2086 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2087 }
2088 ly_buf_used++;
2089
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002090 memmove(module_name, mod_name, mod_name_len);
Michal Vasko8757e7c2016-03-15 10:41:30 +01002091 module_name[mod_name_len] = '\0';
2092 /* will also find an augment module */
2093 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002094
2095 if (buf_backup) {
2096 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002097 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002098 free(buf_backup);
2099 buf_backup = NULL;
2100 }
2101 ly_buf_used--;
2102
Michal Vasko3edeaf72016-02-11 13:17:43 +01002103 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002104 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2105 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2106 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002107 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002108 }
2109 } else {
2110 prefix_mod = prev_mod;
2111 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01002112 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002113 continue;
2114 }
2115
Michal Vaskoe733d682016-03-14 09:08:27 +01002116 /* do we have some predicates on it? */
2117 if (has_predicate) {
2118 r = 0;
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002119 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
2120 if ((r = parse_schema_json_predicate(id, NULL, NULL, NULL, NULL, &has_predicate)) < 1) {
2121 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2122 return NULL;
2123 }
2124 } else if (sibling->nodetype == LYS_LIST) {
2125 if (resolve_json_schema_list_predicate(id, (const struct lys_node_list *)sibling, &r)) {
2126 return NULL;
2127 }
2128 } else {
Michal Vasko43c300e2016-03-22 12:54:27 +01002129 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vaskoe733d682016-03-14 09:08:27 +01002130 return NULL;
Michal Vaskoe733d682016-03-14 09:08:27 +01002131 }
2132 id += r;
2133 }
2134
Radek Krejcibdf92362016-04-08 14:43:34 +02002135 /* check for shorthand cases - then 'start' does not change */
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002136 if (lys_parent(sibling) && (lys_parent(sibling)->nodetype == LYS_CHOICE) && (sibling->nodetype != LYS_CASE)) {
Radek Krejcibdf92362016-04-08 14:43:34 +02002137 shorthand = ~shorthand;
2138 }
2139
Michal Vasko3edeaf72016-02-11 13:17:43 +01002140 /* the result node? */
2141 if (!id[0]) {
Radek Krejcibdf92362016-04-08 14:43:34 +02002142 if (shorthand) {
2143 /* wrong path for shorthand */
Michal Vasko025e0452016-05-17 16:14:20 +02002144 str = strndup(nodeid, (name + nam_len) - nodeid);
2145 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
Michal Vasko3c0f9f52016-05-17 16:38:10 +02002146 LOGVAL(LYE_SPEC, LY_VLOG_STR, str, "Schema shorthand case path must include the virtual case statement.");
Radek Krejci9a5fccc2016-05-18 15:44:58 +02002147 free(str);
Michal Vasko025e0452016-05-17 16:14:20 +02002148 return NULL;
Radek Krejcibdf92362016-04-08 14:43:34 +02002149 }
Michal Vaskoe733d682016-03-14 09:08:27 +01002150 return sibling;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002151 }
2152
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002153 if (!shorthand) {
Michal Vasko7dc71d02016-03-15 10:42:28 +01002154 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002155 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002156 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko7dc71d02016-03-15 10:42:28 +01002157 return NULL;
2158 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01002159 start = sibling->child;
2160 }
2161
2162 /* update prev mod */
2163 prev_mod = start->module;
2164 break;
2165 }
2166 }
2167
2168 /* no match */
2169 if (!sibling) {
Michal Vasko10728b52016-04-07 14:26:29 +02002170 str = strndup(nodeid, (name + nam_len) - nodeid);
2171 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
2172 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002173 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002174 }
2175
Michal Vaskoe733d682016-03-14 09:08:27 +01002176 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 +01002177 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002178 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002179 }
2180 id += r;
2181 }
2182
2183 /* cannot get here */
2184 LOGINT;
Michal Vaskoe733d682016-03-14 09:08:27 +01002185 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002186}
2187
Michal Vasko22448d32016-03-16 13:17:29 +01002188static int
Michal Vasko58c2aab2017-01-05 10:02:05 +01002189resolve_partial_json_data_list_predicate(const char *predicate, const char *node_name, struct lyd_node *node,
2190 int position, int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002191{
Michal Vasko9ba34de2016-12-07 12:21:19 +01002192 const char *name, *value, *key_val;
Michal Vasko22448d32016-03-16 13:17:29 +01002193 int nam_len, val_len, has_predicate = 1, r;
2194 uint16_t i;
Michal Vaskof29903d2016-04-18 13:13:10 +02002195 struct lyd_node_leaf_list *key;
Michal Vasko22448d32016-03-16 13:17:29 +01002196
Radek Krejci61a86c62016-03-24 11:06:44 +01002197 assert(node);
Michal Vasko22448d32016-03-16 13:17:29 +01002198 assert(node->schema->nodetype == LYS_LIST);
2199
Michal Vaskof29903d2016-04-18 13:13:10 +02002200 key = (struct lyd_node_leaf_list *)node->child;
2201 for (i = 0; i < ((struct lys_node_list *)node->schema)->keys_size; ++i) {
Michal Vasko22448d32016-03-16 13:17:29 +01002202 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002203 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, node_name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002204 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002205 }
2206
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002207 if (((r = parse_schema_json_predicate(predicate, &name, &nam_len, &value, &val_len, &has_predicate)) < 1)
2208 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002209 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
Michal Vaskof29903d2016-04-18 13:13:10 +02002210 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002211 }
2212
2213 predicate += r;
2214 *parsed += r;
2215
Michal Vasko58c2aab2017-01-05 10:02:05 +01002216 if (isdigit(name[0])) {
2217 if (position == atoi(name)) {
2218 /* match */
2219 break;
2220 } else {
2221 /* not a match */
2222 return 1;
2223 }
2224 }
2225
2226 if (!key) {
2227 /* it is not a position, so we need to key for it to be a match */
2228 return 1;
2229 }
2230
Michal Vaskof29903d2016-04-18 13:13:10 +02002231 if (strncmp(key->schema->name, name, nam_len) || key->schema->name[nam_len]) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002232 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002233 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002234 }
2235
Michal Vasko9ba34de2016-12-07 12:21:19 +01002236 /* make value canonical */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01002237 if ((key->value_type & LY_TYPE_IDENT)
Michal Vasko6a938d62016-12-21 09:21:30 +01002238 && !strncmp(key->value_str, lyd_node_module(node)->name, strlen(lyd_node_module(node)->name))
2239 && (key->value_str[strlen(lyd_node_module(node)->name)] == ':')) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002240 key_val = key->value_str + strlen(lyd_node_module(node)->name) + 1;
2241 } else {
2242 key_val = key->value_str;
2243 }
2244
Michal Vasko22448d32016-03-16 13:17:29 +01002245 /* value does not match */
Michal Vasko9ba34de2016-12-07 12:21:19 +01002246 if (strncmp(key_val, value, val_len) || key_val[val_len]) {
Michal Vasko22448d32016-03-16 13:17:29 +01002247 return 1;
2248 }
Michal Vaskof29903d2016-04-18 13:13:10 +02002249
2250 key = (struct lyd_node_leaf_list *)key->next;
Michal Vasko22448d32016-03-16 13:17:29 +01002251 }
2252
2253 if (has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002254 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko22448d32016-03-16 13:17:29 +01002255 return -1;
2256 }
2257
2258 return 0;
2259}
2260
Radek Krejci45826012016-08-24 15:07:57 +02002261/**
2262 * @brief get the closest parent of the node (or the node itself) identified by the nodeid (path)
2263 *
2264 * @param[in] nodeid Node data path to find
2265 * @param[in] llist_value If the \p nodeid identifies leaf-list, this is expected value of the leaf-list instance.
2266 * @param[in] options Bitmask of options flags, see @ref pathoptions.
2267 * @param[out] parsed Number of characters processed in \p id
2268 * @return The closes parent (or the node itself) from the path
2269 */
Michal Vasko22448d32016-03-16 13:17:29 +01002270struct lyd_node *
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002271resolve_partial_json_data_nodeid(const char *nodeid, const char *llist_value, struct lyd_node *start, int options,
2272 int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002273{
Michal Vasko10728b52016-04-07 14:26:29 +02002274 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko9ba34de2016-12-07 12:21:19 +01002275 const char *id, *mod_name, *name, *pred_name, *data_val;
Michal Vasko58c2aab2017-01-05 10:02:05 +01002276 int r, ret, mod_name_len, nam_len, is_relative = -1, list_instance_position;
Michal Vasko9ba34de2016-12-07 12:21:19 +01002277 int has_predicate, last_parsed, llval_len, pred_name_len, last_has_pred;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002278 struct lyd_node *sibling, *last_match = NULL;
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002279 struct lyd_node_leaf_list *llist;
Michal Vasko22448d32016-03-16 13:17:29 +01002280 const struct lys_module *prefix_mod, *prev_mod;
2281 struct ly_ctx *ctx;
2282
2283 assert(nodeid && start && parsed);
2284
2285 ctx = start->schema->module->ctx;
2286 id = nodeid;
2287
2288 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 +01002289 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002290 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002291 return NULL;
2292 }
2293 id += r;
2294 /* add it to parsed only after the data node was actually found */
2295 last_parsed = r;
2296
2297 if (is_relative) {
Michal Vasko1adc7242016-11-16 11:05:28 +01002298 prev_mod = lyd_node_module(start);
Michal Vasko22448d32016-03-16 13:17:29 +01002299 start = start->child;
2300 } else {
2301 for (; start->parent; start = start->parent);
Michal Vasko1adc7242016-11-16 11:05:28 +01002302 prev_mod = lyd_node_module(start);
Michal Vasko22448d32016-03-16 13:17:29 +01002303 }
2304
2305 while (1) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002306 list_instance_position = 0;
2307
Michal Vasko22448d32016-03-16 13:17:29 +01002308 LY_TREE_FOR(start, sibling) {
Michal Vasko945b96b2016-10-18 11:49:12 +02002309 /* RPC/action data check, return simply invalid argument, because the data tree is invalid */
Michal Vasko2411b942016-03-23 13:50:03 +01002310 if (lys_parent(sibling->schema)) {
2311 if (options & LYD_PATH_OPT_OUTPUT) {
2312 if (lys_parent(sibling->schema)->nodetype == LYS_INPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002313 LOGERR(LY_EINVAL, "Provided data tree includes some RPC input nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002314 *parsed = -1;
2315 return NULL;
2316 }
2317 } else {
2318 if (lys_parent(sibling->schema)->nodetype == LYS_OUTPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002319 LOGERR(LY_EINVAL, "Provided data tree includes some RPC output nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002320 *parsed = -1;
2321 return NULL;
2322 }
2323 }
2324 }
2325
Michal Vasko22448d32016-03-16 13:17:29 +01002326 /* name match */
2327 if (!strncmp(name, sibling->schema->name, nam_len) && !sibling->schema->name[nam_len]) {
2328
2329 /* module check */
2330 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002331 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko22448d32016-03-16 13:17:29 +01002332 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002333 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002334 return NULL;
2335 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002336
2337 if (ly_buf_used && module_name[0]) {
2338 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2339 }
2340 ly_buf_used++;
2341
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002342 memmove(module_name, mod_name, mod_name_len);
Michal Vasko22448d32016-03-16 13:17:29 +01002343 module_name[mod_name_len] = '\0';
2344 /* will also find an augment module */
2345 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002346
2347 if (buf_backup) {
2348 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002349 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002350 free(buf_backup);
2351 buf_backup = NULL;
2352 }
2353 ly_buf_used--;
2354
Michal Vasko22448d32016-03-16 13:17:29 +01002355 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002356 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2357 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2358 free(str);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002359 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002360 return NULL;
2361 }
2362 } else {
2363 prefix_mod = prev_mod;
2364 }
Michal Vasko1adc7242016-11-16 11:05:28 +01002365 if (prefix_mod != lyd_node_module(sibling)) {
Michal Vasko22448d32016-03-16 13:17:29 +01002366 continue;
2367 }
2368
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002369 /* leaf-list, did we find it with the correct value or not? */
Michal Vasko22448d32016-03-16 13:17:29 +01002370 if (sibling->schema->nodetype == LYS_LEAFLIST) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002371 llist = (struct lyd_node_leaf_list *)sibling;
2372
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002373 last_has_pred = 0;
Michal Vaskof0a50972016-10-19 11:33:55 +02002374 if (has_predicate) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002375 if ((r = parse_schema_json_predicate(id, &pred_name, &pred_name_len, &llist_value, &llval_len, &last_has_pred)) < 1) {
Michal Vaskof0a50972016-10-19 11:33:55 +02002376 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2377 *parsed = -1;
2378 return NULL;
2379 }
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002380 if ((pred_name[0] != '.') || (pred_name_len != 1)) {
2381 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[1], id + 1);
2382 *parsed = -1;
2383 return NULL;
2384 }
Michal Vaskof0a50972016-10-19 11:33:55 +02002385 } else {
2386 r = 0;
2387 if (llist_value) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002388 llval_len = strlen(llist_value);
Michal Vaskof0a50972016-10-19 11:33:55 +02002389 }
2390 }
2391
Michal Vasko9ba34de2016-12-07 12:21:19 +01002392 /* make value canonical */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01002393 if ((llist->value_type & LY_TYPE_IDENT)
Michal Vasko6a938d62016-12-21 09:21:30 +01002394 && !strncmp(llist->value_str, lyd_node_module(sibling)->name, strlen(lyd_node_module(sibling)->name))
2395 && (llist->value_str[strlen(lyd_node_module(sibling)->name)] == ':')) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002396 data_val = llist->value_str + strlen(lyd_node_module(sibling)->name) + 1;
2397 } else {
2398 data_val = llist->value_str;
2399 }
2400
2401 if ((!llist_value && data_val && data_val[0])
2402 || (llist_value && (strncmp(llist_value, data_val, llval_len) || data_val[llval_len]))) {
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002403 continue;
2404 }
Michal Vasko9ba34de2016-12-07 12:21:19 +01002405
Michal Vaskof0a50972016-10-19 11:33:55 +02002406 id += r;
2407 last_parsed += r;
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002408 has_predicate = last_has_pred;
Michal Vaskof0a50972016-10-19 11:33:55 +02002409
Radek Krejci45826012016-08-24 15:07:57 +02002410 } else if (sibling->schema->nodetype == LYS_LIST) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002411 /* 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 +01002412 if (!has_predicate) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002413 /* none match */
2414 return last_match;
Michal Vasko22448d32016-03-16 13:17:29 +01002415 }
Michal Vasko58c2aab2017-01-05 10:02:05 +01002416
2417 ++list_instance_position;
2418 r = 0;
2419 ret = resolve_partial_json_data_list_predicate(id, name, sibling, list_instance_position, &r);
Michal Vasko22448d32016-03-16 13:17:29 +01002420 if (ret == -1) {
Michal Vasko238bd2f2016-03-23 09:39:01 +01002421 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002422 return NULL;
2423 } else if (ret == 1) {
2424 /* this list instance does not match */
2425 continue;
2426 }
2427 id += r;
2428 last_parsed += r;
2429 }
2430
2431 *parsed += last_parsed;
2432
2433 /* the result node? */
2434 if (!id[0]) {
2435 return sibling;
2436 }
2437
2438 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002439 if (sibling->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002440 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002441 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002442 return NULL;
2443 }
Michal Vaskoc6c52cf2016-03-29 11:53:04 +02002444 last_match = sibling;
Michal Vaskofc11b682016-11-18 09:52:41 +01002445 prev_mod = lyd_node_module(sibling);
Michal Vasko22448d32016-03-16 13:17:29 +01002446 start = sibling->child;
Michal Vasko22448d32016-03-16 13:17:29 +01002447 break;
2448 }
2449 }
2450
2451 /* no match, return last match */
2452 if (!sibling) {
2453 return last_match;
2454 }
2455
2456 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 +01002457 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002458 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002459 return NULL;
2460 }
2461 id += r;
2462 last_parsed = r;
2463 }
2464
2465 /* cannot get here */
2466 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002467 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002468 return NULL;
2469}
2470
Michal Vasko3edeaf72016-02-11 13:17:43 +01002471/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02002472 * @brief Resolves length or range intervals. Does not log.
Michal Vaskoaeb51802016-04-11 10:58:47 +02002473 * Syntax is assumed to be correct, *ret MUST be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002474 *
Michal Vaskoaeb51802016-04-11 10:58:47 +02002475 * @param[in] str_restr Restriction as a string.
2476 * @param[in] type Type of the restriction.
2477 * @param[out] ret Final interval structure that starts with
2478 * the interval of the initial type, continues with intervals
2479 * of any superior types derived from the initial one, and
2480 * finishes with intervals from our \p type.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002481 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002482 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002483 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002484int
Michal Vaskoaeb51802016-04-11 10:58:47 +02002485resolve_len_ran_interval(const char *str_restr, struct lys_type *type, struct len_ran_intv **ret)
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002486{
2487 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002488 int kind;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002489 int64_t local_smin, local_smax, local_fmin, local_fmax;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002490 uint64_t local_umin, local_umax;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002491 uint8_t local_fdig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002492 const char *seg_ptr, *ptr;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002493 struct len_ran_intv *local_intv = NULL, *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002494
2495 switch (type->base) {
2496 case LY_TYPE_BINARY:
2497 kind = 0;
2498 local_umin = 0;
2499 local_umax = 18446744073709551615UL;
2500
2501 if (!str_restr && type->info.binary.length) {
2502 str_restr = type->info.binary.length->expr;
2503 }
2504 break;
2505 case LY_TYPE_DEC64:
2506 kind = 2;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002507 local_fmin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2508 local_fmax = __INT64_C(9223372036854775807);
2509 local_fdig = type->info.dec64.dig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002510
2511 if (!str_restr && type->info.dec64.range) {
2512 str_restr = type->info.dec64.range->expr;
2513 }
2514 break;
2515 case LY_TYPE_INT8:
2516 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002517 local_smin = __INT64_C(-128);
2518 local_smax = __INT64_C(127);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002519
2520 if (!str_restr && type->info.num.range) {
2521 str_restr = type->info.num.range->expr;
2522 }
2523 break;
2524 case LY_TYPE_INT16:
2525 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002526 local_smin = __INT64_C(-32768);
2527 local_smax = __INT64_C(32767);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002528
2529 if (!str_restr && type->info.num.range) {
2530 str_restr = type->info.num.range->expr;
2531 }
2532 break;
2533 case LY_TYPE_INT32:
2534 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002535 local_smin = __INT64_C(-2147483648);
2536 local_smax = __INT64_C(2147483647);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002537
2538 if (!str_restr && type->info.num.range) {
2539 str_restr = type->info.num.range->expr;
2540 }
2541 break;
2542 case LY_TYPE_INT64:
2543 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002544 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2545 local_smax = __INT64_C(9223372036854775807);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002546
2547 if (!str_restr && type->info.num.range) {
2548 str_restr = type->info.num.range->expr;
2549 }
2550 break;
2551 case LY_TYPE_UINT8:
2552 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002553 local_umin = __UINT64_C(0);
2554 local_umax = __UINT64_C(255);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002555
2556 if (!str_restr && type->info.num.range) {
2557 str_restr = type->info.num.range->expr;
2558 }
2559 break;
2560 case LY_TYPE_UINT16:
2561 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002562 local_umin = __UINT64_C(0);
2563 local_umax = __UINT64_C(65535);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002564
2565 if (!str_restr && type->info.num.range) {
2566 str_restr = type->info.num.range->expr;
2567 }
2568 break;
2569 case LY_TYPE_UINT32:
2570 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002571 local_umin = __UINT64_C(0);
2572 local_umax = __UINT64_C(4294967295);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002573
2574 if (!str_restr && type->info.num.range) {
2575 str_restr = type->info.num.range->expr;
2576 }
2577 break;
2578 case LY_TYPE_UINT64:
2579 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002580 local_umin = __UINT64_C(0);
2581 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002582
2583 if (!str_restr && type->info.num.range) {
2584 str_restr = type->info.num.range->expr;
2585 }
2586 break;
2587 case LY_TYPE_STRING:
2588 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002589 local_umin = __UINT64_C(0);
2590 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002591
2592 if (!str_restr && type->info.str.length) {
2593 str_restr = type->info.str.length->expr;
2594 }
2595 break;
2596 default:
2597 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002598 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002599 }
2600
2601 /* process superior types */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002602 if (type->der) {
2603 if (resolve_len_ran_interval(NULL, &type->der->type, &intv)) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002604 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002605 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02002606 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002607 assert(!intv || (intv->kind == kind));
2608 }
2609
2610 if (!str_restr) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002611 /* we do not have any restriction, return superior ones */
2612 *ret = intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002613 return EXIT_SUCCESS;
2614 }
2615
2616 /* adjust local min and max */
2617 if (intv) {
2618 tmp_intv = intv;
2619
2620 if (kind == 0) {
2621 local_umin = tmp_intv->value.uval.min;
2622 } else if (kind == 1) {
2623 local_smin = tmp_intv->value.sval.min;
2624 } else if (kind == 2) {
2625 local_fmin = tmp_intv->value.fval.min;
2626 }
2627
2628 while (tmp_intv->next) {
2629 tmp_intv = tmp_intv->next;
2630 }
2631
2632 if (kind == 0) {
2633 local_umax = tmp_intv->value.uval.max;
2634 } else if (kind == 1) {
2635 local_smax = tmp_intv->value.sval.max;
2636 } else if (kind == 2) {
2637 local_fmax = tmp_intv->value.fval.max;
2638 }
2639 }
2640
2641 /* finally parse our restriction */
2642 seg_ptr = str_restr;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002643 tmp_intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002644 while (1) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002645 if (!tmp_local_intv) {
2646 assert(!local_intv);
2647 local_intv = malloc(sizeof *local_intv);
2648 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002649 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002650 tmp_local_intv->next = malloc(sizeof *tmp_local_intv);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002651 tmp_local_intv = tmp_local_intv->next;
2652 }
Michal Vasko253035f2015-12-17 16:58:13 +01002653 if (!tmp_local_intv) {
2654 LOGMEM;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002655 goto error;
Michal Vasko253035f2015-12-17 16:58:13 +01002656 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002657
2658 tmp_local_intv->kind = kind;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002659 tmp_local_intv->type = type;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002660 tmp_local_intv->next = NULL;
2661
2662 /* min */
2663 ptr = seg_ptr;
2664 while (isspace(ptr[0])) {
2665 ++ptr;
2666 }
2667 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2668 if (kind == 0) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002669 tmp_local_intv->value.uval.min = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002670 } else if (kind == 1) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002671 tmp_local_intv->value.sval.min = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002672 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002673 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.min)) {
2674 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2675 goto error;
2676 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002677 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002678 } else if (!strncmp(ptr, "min", 3)) {
2679 if (kind == 0) {
2680 tmp_local_intv->value.uval.min = local_umin;
2681 } else if (kind == 1) {
2682 tmp_local_intv->value.sval.min = local_smin;
2683 } else if (kind == 2) {
2684 tmp_local_intv->value.fval.min = local_fmin;
2685 }
2686
2687 ptr += 3;
2688 } else if (!strncmp(ptr, "max", 3)) {
2689 if (kind == 0) {
2690 tmp_local_intv->value.uval.min = local_umax;
2691 } else if (kind == 1) {
2692 tmp_local_intv->value.sval.min = local_smax;
2693 } else if (kind == 2) {
2694 tmp_local_intv->value.fval.min = local_fmax;
2695 }
2696
2697 ptr += 3;
2698 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002699 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002700 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002701 }
2702
2703 while (isspace(ptr[0])) {
2704 ptr++;
2705 }
2706
2707 /* no interval or interval */
2708 if ((ptr[0] == '|') || !ptr[0]) {
2709 if (kind == 0) {
2710 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
2711 } else if (kind == 1) {
2712 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
2713 } else if (kind == 2) {
2714 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
2715 }
2716 } else if (!strncmp(ptr, "..", 2)) {
2717 /* skip ".." */
2718 ptr += 2;
2719 while (isspace(ptr[0])) {
2720 ++ptr;
2721 }
2722
2723 /* max */
2724 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2725 if (kind == 0) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002726 tmp_local_intv->value.uval.max = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002727 } else if (kind == 1) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002728 tmp_local_intv->value.sval.max = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002729 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002730 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.max)) {
2731 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2732 goto error;
2733 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002734 }
2735 } else if (!strncmp(ptr, "max", 3)) {
2736 if (kind == 0) {
2737 tmp_local_intv->value.uval.max = local_umax;
2738 } else if (kind == 1) {
2739 tmp_local_intv->value.sval.max = local_smax;
2740 } else if (kind == 2) {
2741 tmp_local_intv->value.fval.max = local_fmax;
2742 }
2743 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002744 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002745 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002746 }
2747 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002748 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002749 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002750 }
2751
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002752 /* check min and max in correct order*/
2753 if (kind == 0) {
2754 /* current segment */
2755 if (tmp_local_intv->value.uval.min > tmp_local_intv->value.uval.max) {
2756 goto error;
2757 }
2758 if (tmp_local_intv->value.uval.min < local_umin || tmp_local_intv->value.uval.max > local_umax) {
2759 goto error;
2760 }
2761 /* segments sholud be ascending order */
Pavol Vican69f62c92016-08-30 09:06:25 +02002762 if (tmp_intv && (tmp_intv->value.uval.max >= tmp_local_intv->value.uval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002763 goto error;
2764 }
2765 } else if (kind == 1) {
2766 if (tmp_local_intv->value.sval.min > tmp_local_intv->value.sval.max) {
2767 goto error;
2768 }
2769 if (tmp_local_intv->value.sval.min < local_smin || tmp_local_intv->value.sval.max > local_smax) {
2770 goto error;
2771 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002772 if (tmp_intv && (tmp_intv->value.sval.max >= tmp_local_intv->value.sval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002773 goto error;
2774 }
2775 } else if (kind == 2) {
2776 if (tmp_local_intv->value.fval.min > tmp_local_intv->value.fval.max) {
2777 goto error;
2778 }
2779 if (tmp_local_intv->value.fval.min < local_fmin || tmp_local_intv->value.fval.max > local_fmax) {
2780 goto error;
2781 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002782 if (tmp_intv && (tmp_intv->value.fval.max >= tmp_local_intv->value.fval.min)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002783 /* fraction-digits value is always the same (it cannot be changed in derived types) */
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002784 goto error;
2785 }
2786 }
2787
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002788 /* next segment (next OR) */
2789 seg_ptr = strchr(seg_ptr, '|');
2790 if (!seg_ptr) {
2791 break;
2792 }
2793 seg_ptr++;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002794 tmp_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002795 }
2796
2797 /* check local restrictions against superior ones */
2798 if (intv) {
2799 tmp_intv = intv;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002800 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002801
2802 while (tmp_local_intv && tmp_intv) {
2803 /* reuse local variables */
2804 if (kind == 0) {
2805 local_umin = tmp_local_intv->value.uval.min;
2806 local_umax = tmp_local_intv->value.uval.max;
2807
2808 /* it must be in this interval */
2809 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
2810 /* this interval is covered, next one */
2811 if (local_umax <= tmp_intv->value.uval.max) {
2812 tmp_local_intv = tmp_local_intv->next;
2813 continue;
2814 /* ascending order of restrictions -> fail */
2815 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002816 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002817 }
2818 }
2819 } else if (kind == 1) {
2820 local_smin = tmp_local_intv->value.sval.min;
2821 local_smax = tmp_local_intv->value.sval.max;
2822
2823 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
2824 if (local_smax <= tmp_intv->value.sval.max) {
2825 tmp_local_intv = tmp_local_intv->next;
2826 continue;
2827 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002828 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002829 }
2830 }
2831 } else if (kind == 2) {
2832 local_fmin = tmp_local_intv->value.fval.min;
2833 local_fmax = tmp_local_intv->value.fval.max;
2834
Michal Vasko4d1f0482016-09-19 14:35:06 +02002835 if ((dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.min, local_fdig) > -1)
Pavol Vican3c8ee2b2016-09-29 13:18:13 +02002836 && (dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002837 if (dec64cmp(local_fmax, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002838 tmp_local_intv = tmp_local_intv->next;
2839 continue;
2840 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002841 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002842 }
2843 }
2844 }
2845
2846 tmp_intv = tmp_intv->next;
2847 }
2848
2849 /* some interval left uncovered -> fail */
2850 if (tmp_local_intv) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002851 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002852 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002853 }
2854
Michal Vaskoaeb51802016-04-11 10:58:47 +02002855 /* append the local intervals to all the intervals of the superior types, return it all */
2856 if (intv) {
2857 for (tmp_intv = intv; tmp_intv->next; tmp_intv = tmp_intv->next);
2858 tmp_intv->next = local_intv;
2859 } else {
2860 intv = local_intv;
2861 }
2862 *ret = intv;
2863
2864 return EXIT_SUCCESS;
2865
2866error:
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002867 while (intv) {
2868 tmp_intv = intv->next;
2869 free(intv);
2870 intv = tmp_intv;
2871 }
Michal Vaskoaeb51802016-04-11 10:58:47 +02002872 while (local_intv) {
2873 tmp_local_intv = local_intv->next;
2874 free(local_intv);
2875 local_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002876 }
2877
Michal Vaskoaeb51802016-04-11 10:58:47 +02002878 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002879}
2880
Michal Vasko730dfdf2015-08-11 14:48:05 +02002881/**
Michal Vasko01c6fd22016-05-20 11:43:05 +02002882 * @brief Resolve a typedef, return only resolved typedefs if derived. If leafref, it must be
2883 * resolved for this function to return it. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002884 *
2885 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02002886 * @param[in] mod_name Typedef name module name.
2887 * @param[in] module Main module.
2888 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002889 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002890 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002891 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002892 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002893int
Michal Vasko1e62a092015-12-01 12:27:20 +01002894resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
2895 const struct lys_node *parent, struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002896{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002897 int i, j;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002898 struct lys_tpdf *tpdf, *match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002899 int tpdf_size;
2900
Michal Vasko1dca6882015-10-22 14:29:42 +02002901 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002902 /* no prefix, try built-in types */
2903 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
2904 if (!strcmp(ly_types[i].def->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002905 if (ret) {
2906 *ret = ly_types[i].def;
2907 }
2908 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002909 }
2910 }
2911 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02002912 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002913 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02002914 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002915 }
2916 }
2917
Michal Vasko1dca6882015-10-22 14:29:42 +02002918 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002919 /* search in local typedefs */
2920 while (parent) {
2921 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02002922 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02002923 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
2924 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002925 break;
2926
Radek Krejci76512572015-08-04 09:47:08 +02002927 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02002928 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
2929 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002930 break;
2931
Radek Krejci76512572015-08-04 09:47:08 +02002932 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02002933 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
2934 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002935 break;
2936
Radek Krejci76512572015-08-04 09:47:08 +02002937 case LYS_RPC:
Michal Vasko44fb6382016-06-29 11:12:27 +02002938 case LYS_ACTION:
2939 tpdf_size = ((struct lys_node_rpc_action *)parent)->tpdf_size;
2940 tpdf = ((struct lys_node_rpc_action *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002941 break;
2942
Radek Krejci76512572015-08-04 09:47:08 +02002943 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02002944 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
2945 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002946 break;
2947
Radek Krejci76512572015-08-04 09:47:08 +02002948 case LYS_INPUT:
2949 case LYS_OUTPUT:
Michal Vasko44fb6382016-06-29 11:12:27 +02002950 tpdf_size = ((struct lys_node_inout *)parent)->tpdf_size;
2951 tpdf = ((struct lys_node_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002952 break;
2953
2954 default:
Michal Vaskodcf98e62016-05-05 17:53:53 +02002955 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002956 continue;
2957 }
2958
2959 for (i = 0; i < tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002960 if (!strcmp(tpdf[i].name, name) && tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002961 match = &tpdf[i];
2962 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002963 }
2964 }
2965
Michal Vaskodcf98e62016-05-05 17:53:53 +02002966 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002967 }
Radek Krejcic071c542016-01-27 14:57:51 +01002968 } else {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002969 /* get module where to search */
Michal Vaskob6729c62015-10-21 12:09:47 +02002970 module = lys_get_import_module(module, NULL, 0, mod_name, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02002971 if (!module) {
2972 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002973 }
2974 }
2975
2976 /* search in top level typedefs */
2977 for (i = 0; i < module->tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002978 if (!strcmp(module->tpdf[i].name, name) && module->tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002979 match = &module->tpdf[i];
2980 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002981 }
2982 }
2983
2984 /* search in submodules */
Radek Krejcic071c542016-01-27 14:57:51 +01002985 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002986 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002987 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 +02002988 match = &module->inc[i].submodule->tpdf[j];
2989 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002990 }
2991 }
2992 }
2993
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002994 return EXIT_FAILURE;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002995
2996check_leafref:
2997 if (ret) {
2998 *ret = match;
2999 }
3000 if (match->type.base == LY_TYPE_LEAFREF) {
3001 while (!match->type.info.lref.path) {
3002 match = match->type.der;
3003 assert(match);
3004 }
Michal Vasko01c6fd22016-05-20 11:43:05 +02003005 }
3006 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003007}
3008
Michal Vasko1dca6882015-10-22 14:29:42 +02003009/**
3010 * @brief Check the default \p value of the \p type. Logs directly.
3011 *
3012 * @param[in] type Type definition to use.
3013 * @param[in] value Default value to check.
Michal Vasko56826402016-03-02 11:11:37 +01003014 * @param[in] module Type module.
Michal Vasko1dca6882015-10-22 14:29:42 +02003015 *
3016 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3017 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003018static int
Radek Krejci51673202016-11-01 17:00:32 +01003019check_default(struct lys_type *type, const char **value, struct lys_module *module)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003020{
Radek Krejcibad2f172016-08-02 11:04:15 +02003021 struct lys_tpdf *base_tpdf = NULL;
Michal Vasko1dca6882015-10-22 14:29:42 +02003022 struct lyd_node_leaf_list node;
Radek Krejci51673202016-11-01 17:00:32 +01003023 const char *dflt = NULL;
Radek Krejci37b756f2016-01-18 10:15:03 +01003024 int ret = EXIT_SUCCESS;
Michal Vasko1dca6882015-10-22 14:29:42 +02003025
Radek Krejci51673202016-11-01 17:00:32 +01003026 assert(value);
3027
Radek Krejcic13db382016-08-16 10:52:42 +02003028 if (type->base <= LY_TYPE_DER) {
Michal Vasko478c4652016-07-21 12:55:01 +02003029 /* the type was not resolved yet, nothing to do for now */
3030 return EXIT_FAILURE;
3031 }
3032
Radek Krejci51673202016-11-01 17:00:32 +01003033 dflt = *value;
3034 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003035 /* we do not have a new default value, so is there any to check even, in some base type? */
3036 for (base_tpdf = type->der; base_tpdf->type.der; base_tpdf = base_tpdf->type.der) {
3037 if (base_tpdf->dflt) {
Radek Krejci51673202016-11-01 17:00:32 +01003038 dflt = base_tpdf->dflt;
Michal Vasko478c4652016-07-21 12:55:01 +02003039 break;
3040 }
3041 }
3042
Radek Krejci51673202016-11-01 17:00:32 +01003043 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003044 /* no default value, nothing to check, all is well */
3045 return EXIT_SUCCESS;
3046 }
3047
3048 /* 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)? */
3049 switch (type->base) {
Michal Vasko478c4652016-07-21 12:55:01 +02003050 case LY_TYPE_IDENT:
3051 case LY_TYPE_INST:
3052 case LY_TYPE_LEAFREF:
3053 case LY_TYPE_BOOL:
3054 case LY_TYPE_EMPTY:
3055 /* these have no restrictions, so we would do the exact same work as the unres in the base typedef */
3056 return EXIT_SUCCESS;
Radek Krejcibad2f172016-08-02 11:04:15 +02003057 case LY_TYPE_BITS:
3058 /* the default value must match the restricted list of values, if the type was restricted */
3059 if (type->info.bits.count) {
3060 break;
3061 }
3062 return EXIT_SUCCESS;
3063 case LY_TYPE_ENUM:
3064 /* the default value must match the restricted list of values, if the type was restricted */
3065 if (type->info.enums.count) {
3066 break;
3067 }
3068 return EXIT_SUCCESS;
Michal Vasko478c4652016-07-21 12:55:01 +02003069 case LY_TYPE_DEC64:
3070 if (type->info.dec64.range) {
3071 break;
3072 }
3073 return EXIT_SUCCESS;
3074 case LY_TYPE_BINARY:
3075 if (type->info.binary.length) {
3076 break;
3077 }
3078 return EXIT_SUCCESS;
3079 case LY_TYPE_INT8:
3080 case LY_TYPE_INT16:
3081 case LY_TYPE_INT32:
3082 case LY_TYPE_INT64:
3083 case LY_TYPE_UINT8:
3084 case LY_TYPE_UINT16:
3085 case LY_TYPE_UINT32:
3086 case LY_TYPE_UINT64:
3087 if (type->info.num.range) {
3088 break;
3089 }
3090 return EXIT_SUCCESS;
3091 case LY_TYPE_STRING:
3092 if (type->info.str.length || type->info.str.patterns) {
3093 break;
3094 }
3095 return EXIT_SUCCESS;
3096 case LY_TYPE_UNION:
3097 /* way too much trouble learning whether we need to check the default again, so just do it */
3098 break;
3099 default:
3100 LOGINT;
3101 return -1;
3102 }
Radek Krejci55a161c2016-09-05 17:13:25 +02003103 } else if (type->base == LY_TYPE_EMPTY) {
3104 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "default", type->parent->name);
3105 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"empty\" data type cannot have a default value.");
3106 return -1;
Michal Vasko478c4652016-07-21 12:55:01 +02003107 }
3108
Michal Vasko1dca6882015-10-22 14:29:42 +02003109 /* dummy leaf */
Radek Krejci4fe36bd2016-03-17 16:47:16 +01003110 memset(&node, 0, sizeof node);
Radek Krejci51673202016-11-01 17:00:32 +01003111 node.value_str = dflt;
Michal Vasko1dca6882015-10-22 14:29:42 +02003112 node.value_type = type->base;
Radek Krejci37b756f2016-01-18 10:15:03 +01003113 node.schema = calloc(1, sizeof (struct lys_node_leaf));
Michal Vasko253035f2015-12-17 16:58:13 +01003114 if (!node.schema) {
3115 LOGMEM;
3116 return -1;
3117 }
Radek Krejcibad2f172016-08-02 11:04:15 +02003118 node.schema->name = strdup("fake-default");
Michal Vasko253035f2015-12-17 16:58:13 +01003119 if (!node.schema->name) {
3120 LOGMEM;
Michal Vaskof49eda02016-07-21 12:17:01 +02003121 free(node.schema);
Michal Vasko253035f2015-12-17 16:58:13 +01003122 return -1;
3123 }
Michal Vasko56826402016-03-02 11:11:37 +01003124 node.schema->module = module;
Radek Krejci37b756f2016-01-18 10:15:03 +01003125 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
Michal Vasko1dca6882015-10-22 14:29:42 +02003126
Radek Krejci37b756f2016-01-18 10:15:03 +01003127 if (type->base == LY_TYPE_LEAFREF) {
Michal Vasko1dca6882015-10-22 14:29:42 +02003128 if (!type->info.lref.target) {
3129 ret = EXIT_FAILURE;
3130 goto finish;
3131 }
Radek Krejci51673202016-11-01 17:00:32 +01003132 ret = check_default(&type->info.lref.target->type, &dflt, module);
3133 if (!ret) {
3134 /* adopt possibly changed default value to its canonical form */
3135 if (*value) {
3136 *value = dflt;
3137 }
3138 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003139 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01003140 if (!lyp_parse_value(&((struct lys_node_leaf *)node.schema)->type, &node.value_str, NULL, &node, 1, 1)) {
Radek Krejci5dca5932016-11-04 14:30:47 +01003141 /* possible forward reference */
3142 ret = 1;
Radek Krejcibad2f172016-08-02 11:04:15 +02003143 if (base_tpdf) {
Radek Krejci9ad23f42016-10-31 15:46:52 +01003144 /* default value is defined in some base typedef */
Radek Krejcibad2f172016-08-02 11:04:15 +02003145 if ((type->base == LY_TYPE_BITS && type->der->type.der) ||
3146 (type->base == LY_TYPE_ENUM && type->der->type.der)) {
3147 /* we have refined bits/enums */
3148 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
3149 "Invalid value \"%s\" of the default statement inherited to \"%s\" from \"%s\" base type.",
Radek Krejci51673202016-11-01 17:00:32 +01003150 dflt, type->parent->name, base_tpdf->name);
Radek Krejcibad2f172016-08-02 11:04:15 +02003151 }
3152 }
Radek Krejci51673202016-11-01 17:00:32 +01003153 } else {
3154 /* success - adopt canonical form from the node into the default value */
3155 if (dflt != node.value_str) {
3156 /* this can happen only if we have non-inherited default value,
3157 * inherited default values are already in canonical form */
3158 assert(dflt == *value);
3159 *value = node.value_str;
3160 }
Michal Vasko3767fb22016-07-21 12:10:57 +02003161 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003162 }
3163
3164finish:
3165 if (node.value_type == LY_TYPE_BITS) {
3166 free(node.value.bit);
3167 }
3168 free((char *)node.schema->name);
3169 free(node.schema);
3170
3171 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003172}
3173
Michal Vasko730dfdf2015-08-11 14:48:05 +02003174/**
3175 * @brief Check a key for mandatory attributes. Logs directly.
3176 *
3177 * @param[in] key The key to check.
3178 * @param[in] flags What flags to check.
3179 * @param[in] list The list of all the keys.
3180 * @param[in] index Index of the key in the key list.
3181 * @param[in] name The name of the keys.
3182 * @param[in] len The name length.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003183 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003184 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003185 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003186static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003187check_key(struct lys_node_list *list, int index, const char *name, int len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003188{
Radek Krejciadb57612016-02-16 13:34:34 +01003189 struct lys_node_leaf *key = list->keys[index];
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003190 char *dup = NULL;
3191 int j;
3192
3193 /* existence */
3194 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02003195 if (name[len] != '\0') {
3196 dup = strdup(name);
Michal Vasko253035f2015-12-17 16:58:13 +01003197 if (!dup) {
3198 LOGMEM;
3199 return -1;
3200 }
Michal Vaskof02e3742015-08-05 16:27:02 +02003201 dup[len] = '\0';
3202 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003203 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003204 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, list, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003205 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003206 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003207 }
3208
3209 /* uniqueness */
3210 for (j = index - 1; j >= 0; j--) {
Radek Krejciadb57612016-02-16 13:34:34 +01003211 if (key == list->keys[j]) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003212 LOGVAL(LYE_KEY_DUP, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003213 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003214 }
3215 }
3216
3217 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02003218 if (key->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003219 LOGVAL(LYE_KEY_NLEAF, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003220 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003221 }
3222
3223 /* type of the leaf is not built-in empty */
Radek Krejcic3738db2016-09-15 15:51:21 +02003224 if (key->type.base == LY_TYPE_EMPTY && key->module->version < 2) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003225 LOGVAL(LYE_KEY_TYPE, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003226 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003227 }
3228
3229 /* config attribute is the same as of the list */
Radek Krejci5c08a992016-11-02 13:30:04 +01003230 if ((key->flags & LYS_CONFIG_MASK) && (list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003231 LOGVAL(LYE_KEY_CONFIG, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003232 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003233 }
3234
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003235 /* key is not placed from augment */
3236 if (key->parent->nodetype == LYS_AUGMENT) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003237 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, key, key->name);
3238 LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key inserted from augment.");
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003239 return -1;
3240 }
3241
Radek Krejci3f21ada2016-08-01 13:34:31 +02003242 /* key is not when/if-feature -conditional */
3243 j = 0;
3244 if (key->when || (key->iffeature_size && (j = 1))) {
3245 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, key, j ? "if-feature" : "when", "leaf");
3246 LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key definition cannot depend on a \"%s\" condition.",
3247 j ? "if-feature" : "when");
Radek Krejci581ce772015-11-10 17:22:40 +01003248 return -1;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003249 }
3250
Michal Vasko0b85aa82016-03-07 14:37:43 +01003251 return EXIT_SUCCESS;
Michal Vasko184521f2015-09-24 13:14:26 +02003252}
Michal Vasko730dfdf2015-08-11 14:48:05 +02003253
3254/**
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003255 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003256 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003257 * @param[in] parent The parent node of the unique structure.
Michal Vasko0b85aa82016-03-07 14:37:43 +01003258 * @param[in] uniq_str_path One path from the unique string.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003259 *
3260 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
3261 */
3262int
Radek Krejcid09d1a52016-08-11 14:05:45 +02003263resolve_unique(struct lys_node *parent, const char *uniq_str_path, uint8_t *trg_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003264{
Radek Krejci581ce772015-11-10 17:22:40 +01003265 int rc;
Michal Vasko1e62a092015-12-01 12:27:20 +01003266 const struct lys_node *leaf = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003267
Radek Krejcif3c71de2016-04-11 12:45:46 +02003268 rc = resolve_descendant_schema_nodeid(uniq_str_path, parent->child, LYS_LEAF, 1, 1, &leaf);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003269 if (rc || !leaf) {
Michal Vasko0b85aa82016-03-07 14:37:43 +01003270 if (rc) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003271 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003272 if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003273 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, parent, uniq_str_path[rc - 1], &uniq_str_path[rc - 1]);
Radek Krejcif3c71de2016-04-11 12:45:46 +02003274 } else if (rc == -2) {
Michal Vaskoc66c6d82016-04-12 11:37:31 +02003275 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Unique argument references list.");
Radek Krejci581ce772015-11-10 17:22:40 +01003276 }
Michal Vasko0b85aa82016-03-07 14:37:43 +01003277 rc = -1;
Michal Vasko0b85aa82016-03-07 14:37:43 +01003278 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01003279 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3280 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target leaf not found.");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003281 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003282 }
Radek Krejci581ce772015-11-10 17:22:40 +01003283 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003284 }
Michal Vasko9bb061b2016-02-12 11:00:19 +01003285 if (leaf->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003286 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3287 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target is not a leaf.");
Radek Krejcid09d1a52016-08-11 14:05:45 +02003288 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003289 }
3290
Radek Krejcicf509982015-12-15 09:22:44 +01003291 /* check status */
Radek Krejci48464ed2016-03-17 15:44:09 +01003292 if (lyp_check_status(parent->flags, parent->module, parent->name, leaf->flags, leaf->module, leaf->name, leaf)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003293 return -1;
3294 }
3295
Radek Krejcid09d1a52016-08-11 14:05:45 +02003296 /* check that all unique's targets are of the same config type */
3297 if (*trg_type) {
3298 if (((*trg_type == 1) && (leaf->flags & LYS_CONFIG_R)) || ((*trg_type == 2) && (leaf->flags & LYS_CONFIG_W))) {
3299 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3300 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent,
3301 "Leaf \"%s\" referenced in unique statement is config %s, but previous referenced leaf is config %s.",
3302 uniq_str_path, *trg_type == 1 ? "false" : "true", *trg_type == 1 ? "true" : "false");
3303 return -1;
3304 }
3305 } else {
3306 /* first unique */
3307 if (leaf->flags & LYS_CONFIG_W) {
3308 *trg_type = 1;
3309 } else {
3310 *trg_type = 2;
3311 }
3312 }
3313
Radek Krejcica7efb72016-01-18 13:06:01 +01003314 /* set leaf's unique flag */
3315 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
3316
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003317 return EXIT_SUCCESS;
3318
3319error:
3320
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003321 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003322}
3323
Radek Krejci0c0086a2016-03-24 15:20:28 +01003324void
Michal Vasko23b61ec2015-08-19 11:19:50 +02003325unres_data_del(struct unres_data *unres, uint32_t i)
3326{
3327 /* there are items after the one deleted */
3328 if (i+1 < unres->count) {
3329 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02003330 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003331
3332 /* deleting the last item */
3333 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02003334 free(unres->node);
3335 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003336 }
3337
3338 /* if there are no items after and it is not the last one, just move the counter */
3339 --unres->count;
3340}
3341
Michal Vasko0491ab32015-08-19 14:28:29 +02003342/**
3343 * @brief Resolve (find) a data node from a specific module. Does not log.
3344 *
3345 * @param[in] mod Module to search in.
3346 * @param[in] name Name of the data node.
3347 * @param[in] nam_len Length of the name.
3348 * @param[in] start Data node to start the search from.
3349 * @param[in,out] parents Resolved nodes. If there are some parents,
3350 * they are replaced (!!) with the resolvents.
3351 *
Michal Vasko2471e7f2016-04-11 11:00:15 +02003352 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko0491ab32015-08-19 14:28:29 +02003353 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003354static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003355resolve_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 +02003356{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003357 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02003358 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003359 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003360
Michal Vasko23b61ec2015-08-19 11:19:50 +02003361 if (!parents->count) {
3362 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003363 parents->node = malloc(sizeof *parents->node);
Michal Vasko253035f2015-12-17 16:58:13 +01003364 if (!parents->node) {
3365 LOGMEM;
Michal Vasko2471e7f2016-04-11 11:00:15 +02003366 return -1;
Michal Vasko253035f2015-12-17 16:58:13 +01003367 }
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 Vaskoc3d9f8c2015-07-31 14:37:24 +02003378 if (node->schema->module == mod && !strncmp(node->schema->name, name, nam_len)
3379 && 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);
3389 if (!parents->node) {
3390 return EXIT_FAILURE;
3391 }
Michal Vaskocf024702015-10-08 15:01:42 +02003392 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003393 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003394 }
3395 }
3396 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003397
3398 if (!flag) {
3399 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003400 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02003401 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003402 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02003403 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003404 }
3405
Michal Vasko0491ab32015-08-19 14:28:29 +02003406 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02003407}
3408
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003409/**
3410 * @brief Resolve (find) a data node. Does not log.
3411 *
Radek Krejci581ce772015-11-10 17:22:40 +01003412 * @param[in] mod_name Module name of the data node.
3413 * @param[in] mod_name_len Length of the module name.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003414 * @param[in] name Name of the data node.
3415 * @param[in] nam_len Length of the name.
3416 * @param[in] start Data node to start the search from.
3417 * @param[in,out] parents Resolved nodes. If there are some parents,
3418 * they are replaced (!!) with the resolvents.
3419 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003420 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003421 */
Radek Krejcic5090c32015-08-12 09:46:19 +02003422static int
Radek Krejci581ce772015-11-10 17:22:40 +01003423resolve_data_node(const char *mod_name, int mod_name_len, const char *name, int name_len, struct lyd_node *start,
Michal Vasko23b61ec2015-08-19 11:19:50 +02003424 struct unres_data *parents)
Radek Krejcic5090c32015-08-12 09:46:19 +02003425{
Michal Vasko1e62a092015-12-01 12:27:20 +01003426 const struct lys_module *mod;
Michal Vasko31fc3672015-10-21 12:08:13 +02003427 char *str;
Radek Krejcic5090c32015-08-12 09:46:19 +02003428
Michal Vasko23b61ec2015-08-19 11:19:50 +02003429 assert(start);
3430
Michal Vasko31fc3672015-10-21 12:08:13 +02003431 if (mod_name) {
3432 /* we have mod_name, find appropriate module */
3433 str = strndup(mod_name, mod_name_len);
Michal Vasko253035f2015-12-17 16:58:13 +01003434 if (!str) {
3435 LOGMEM;
3436 return -1;
3437 }
Michal Vasko31fc3672015-10-21 12:08:13 +02003438 mod = ly_ctx_get_module(start->schema->module->ctx, str, NULL);
3439 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02003440 if (!mod) {
3441 /* invalid prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003442 return -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02003443 }
3444 } else {
3445 /* no prefix, module is the same as of current node */
3446 mod = start->schema->module;
3447 }
3448
3449 return resolve_data(mod, name, name_len, start, parents);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003450}
3451
Michal Vasko730dfdf2015-08-11 14:48:05 +02003452/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003453 * @brief Resolve a path predicate (leafref) in JSON data context. Logs directly
Radek Krejci48464ed2016-03-17 15:44:09 +01003454 * only specific errors, general no-resolvent error is left to the caller.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003455 *
Michal Vaskobb211122015-08-19 14:03:11 +02003456 * @param[in] pred Predicate to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003457 * @param[in] node Node from which the predicate is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02003458 * @param[in,out] node_match Nodes satisfying the restriction
3459 * without the predicate. Nodes not
3460 * satisfying the predicate are removed.
Michal Vasko0491ab32015-08-19 14:28:29 +02003461 * @param[out] parsed Number of characters parsed, negative on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003462 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003463 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003464 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003465static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003466resolve_path_predicate_data(const char *pred, struct lyd_node *node, struct unres_data *node_match,
Radek Krejci010e54b2016-03-15 09:40:34 +01003467 int *parsed)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003468{
Michal Vasko730dfdf2015-08-11 14:48:05 +02003469 /* ... /node[source = destination] ... */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003470 struct unres_data source_match, dest_match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003471 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vasko0491ab32015-08-19 14:28:29 +02003472 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed_loc = 0, pke_parsed = 0;
3473 int has_predicate, dest_parent_times, i, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003474 uint32_t j;
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003475 struct lyd_node_leaf_list *leaf_dst, *leaf_src;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003476
3477 source_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003478 source_match.node = malloc(sizeof *source_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003479 if (!source_match.node) {
3480 LOGMEM;
3481 return -1;
3482 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003483 dest_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003484 dest_match.node = malloc(sizeof *dest_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003485 if (!dest_match.node) {
3486 LOGMEM;
3487 return -1;
3488 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003489
3490 do {
3491 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
3492 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003493 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, pred[-i], &pred[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003494 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003495 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003496 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003497 parsed_loc += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003498 pred += i;
3499
Michal Vasko23b61ec2015-08-19 11:19:50 +02003500 for (j = 0; j < node_match->count;) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003501 /* source */
Michal Vaskocf024702015-10-08 15:01:42 +02003502 source_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02003503
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003504 /* must be leaf (key of a list) */
Radek Krejci581ce772015-11-10 17:22:40 +01003505 if ((rc = resolve_data_node(sour_pref, sour_pref_len, source, sour_len, node_match->node[j],
Michal Vaskocf024702015-10-08 15:01:42 +02003506 &source_match)) || (source_match.count != 1) || (source_match.node[0]->schema->nodetype != LYS_LEAF)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003507 i = 0;
3508 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003509 }
3510
3511 /* destination */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003512 dest_match.node[0] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003513 dest_parent_times = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003514 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3515 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003516 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003517 rc = -1;
3518 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003519 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003520 pke_parsed = i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003521 for (i = 0; i < dest_parent_times; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02003522 dest_match.node[0] = dest_match.node[0]->parent;
3523 if (!dest_match.node[0]) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003524 i = 0;
Michal Vasko0491ab32015-08-19 14:28:29 +02003525 rc = EXIT_FAILURE;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003526 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003527 }
3528 }
3529 while (1) {
Radek Krejci581ce772015-11-10 17:22:40 +01003530 if ((rc = resolve_data_node(dest_pref, dest_pref_len, dest, dest_len, dest_match.node[0],
Michal Vasko0491ab32015-08-19 14:28:29 +02003531 &dest_match)) || (dest_match.count != 1)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003532 i = 0;
3533 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003534 }
3535
3536 if (pke_len == pke_parsed) {
3537 break;
3538 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003539 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003540 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003541 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003542 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003543 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003544 }
3545 pke_parsed += i;
3546 }
3547
3548 /* check match between source and destination nodes */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003549 leaf_dst = (struct lyd_node_leaf_list *)dest_match.node[0];
3550 while (leaf_dst->value_type == LY_TYPE_LEAFREF) {
3551 leaf_dst = (struct lyd_node_leaf_list *)leaf_dst->value.leafref;
3552 }
3553 leaf_src = (struct lyd_node_leaf_list *)source_match.node[0];
3554 while (leaf_src->value_type == LY_TYPE_LEAFREF) {
3555 leaf_src = (struct lyd_node_leaf_list *)leaf_src->value.leafref;
3556 }
3557 if (leaf_src->value_type != leaf_dst->value_type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003558 goto remove_leafref;
3559 }
3560
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003561 if (!ly_strequal(leaf_src->value_str, leaf_dst->value_str, 1)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003562 goto remove_leafref;
3563 }
3564
3565 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003566 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003567 continue;
3568
3569remove_leafref:
3570 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003571 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003572 }
3573 } while (has_predicate);
3574
Michal Vaskocf024702015-10-08 15:01:42 +02003575 free(source_match.node);
3576 free(dest_match.node);
Michal Vasko0491ab32015-08-19 14:28:29 +02003577 if (parsed) {
3578 *parsed = parsed_loc;
3579 }
3580 return EXIT_SUCCESS;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003581
3582error:
3583
3584 if (source_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003585 free(source_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003586 }
3587 if (dest_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003588 free(dest_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003589 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003590 if (parsed) {
3591 *parsed = -parsed_loc+i;
3592 }
3593 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003594}
3595
Michal Vasko730dfdf2015-08-11 14:48:05 +02003596/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003597 * @brief Resolve a path (leafref) in JSON data context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003598 *
Michal Vaskocf024702015-10-08 15:01:42 +02003599 * @param[in] node Leafref data node.
Michal Vasko23b61ec2015-08-19 11:19:50 +02003600 * @param[in] path Path of the leafref.
Radek Krejci48464ed2016-03-17 15:44:09 +01003601 * @param[out] ret Matching nodes. Expects an empty, but allocated structure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003602 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003603 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003604 */
Michal Vasko184521f2015-09-24 13:14:26 +02003605static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003606resolve_path_arg_data(struct lyd_node *node, const char *path, struct unres_data *ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003607{
Radek Krejci71b795b2015-08-10 16:20:39 +02003608 struct lyd_node *data = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003609 const char *prefix, *name;
Michal Vasko0491ab32015-08-19 14:28:29 +02003610 int pref_len, nam_len, has_predicate, parent_times, i, parsed, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003611 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003612
Michal Vaskocf024702015-10-08 15:01:42 +02003613 assert(node && path && ret && !ret->count);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003614
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003615 parent_times = 0;
Michal Vaskod9173342015-08-17 14:35:36 +02003616 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003617
3618 /* searching for nodeset */
3619 do {
Radek Krejcif7ed4c32016-10-27 16:20:03 +02003620 if ((i = parse_path_arg(node->schema->module, path, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003621 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path[-i], &path[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003622 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003623 goto error;
3624 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003625 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003626 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003627
Michal Vasko23b61ec2015-08-19 11:19:50 +02003628 if (!ret->count) {
Michal Vaskobfd98e62016-09-02 09:50:05 +02003629 if (parent_times > 0) {
3630 data = node;
3631 for (i = 1; i < parent_times; ++i) {
3632 data = data->parent;
Michal Vasko253035f2015-12-17 16:58:13 +01003633 }
Michal Vaskobfd98e62016-09-02 09:50:05 +02003634 } else if (!parent_times) {
3635 data = node->child;
3636 } else {
3637 /* absolute path */
3638 for (data = node; data->parent; data = data->parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003639 }
3640
Michal Vaskobfd98e62016-09-02 09:50:05 +02003641 /* we may still be parsing it and the pointer is not correct yet */
3642 if (data->prev) {
3643 while (data->prev->next) {
3644 data = data->prev;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003645 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003646 }
3647 }
3648
3649 /* node identifier */
Radek Krejci581ce772015-11-10 17:22:40 +01003650 if ((rc = resolve_data_node(prefix, pref_len, name, nam_len, data, ret))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003651 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003652 LOGVAL(LYE_INELEM_LEN, LY_VLOG_LYD, node, nam_len, name);
Michal Vasko184521f2015-09-24 13:14:26 +02003653 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003654 goto error;
3655 }
3656
3657 if (has_predicate) {
3658 /* we have predicate, so the current results must be lists */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003659 for (j = 0; j < ret->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02003660 if (ret->node[j]->schema->nodetype == LYS_LIST &&
3661 ((struct lys_node_list *)ret->node[0]->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003662 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003663 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003664 continue;
3665 }
3666
3667 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003668 unres_data_del(ret, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003669 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003670 if ((rc = resolve_path_predicate_data(path, node, ret, &i))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003671 if (rc == -1) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003672 LOGVAL(LYE_NORESOLV, LY_VLOG_LYD, node, "leafref", path);
Michal Vasko184521f2015-09-24 13:14:26 +02003673 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003674 goto error;
3675 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003676 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003677 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003678
Michal Vasko23b61ec2015-08-19 11:19:50 +02003679 if (!ret->count) {
Michal Vasko0491ab32015-08-19 14:28:29 +02003680 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003681 goto error;
3682 }
3683 }
3684 } while (path[0] != '\0');
3685
Michal Vaskof02e3742015-08-05 16:27:02 +02003686 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003687
3688error:
3689
Michal Vaskocf024702015-10-08 15:01:42 +02003690 free(ret->node);
3691 ret->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003692 ret->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003693
Michal Vasko0491ab32015-08-19 14:28:29 +02003694 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003695}
3696
Michal Vaskoe27516a2016-10-10 17:55:31 +00003697static int
3698resolve_path_arg_schema_valid_dep_flag(const struct lys_node *op_node, const struct lys_node *first_node, int abs_path)
3699{
3700 int dep1, dep2;
3701 const struct lys_node *node;
3702
3703 if (lys_parent(op_node)) {
3704 /* inner operation (notif/action) */
3705 if (abs_path) {
3706 return 1;
3707 } else {
3708 /* compare depth of both nodes */
3709 for (dep1 = 0, node = op_node; lys_parent(node); node = lys_parent(node));
3710 for (dep2 = 0, node = first_node; lys_parent(node); node = lys_parent(node));
3711 if ((dep2 > dep1) || ((dep2 == dep1) && (op_node != first_node))) {
3712 return 1;
3713 }
3714 }
3715 } else {
3716 /* top-level operation (notif/rpc) */
3717 if (op_node != first_node) {
3718 return 1;
3719 }
3720 }
3721
3722 return 0;
3723}
3724
Michal Vasko730dfdf2015-08-11 14:48:05 +02003725/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003726 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003727 *
Michal Vaskobb211122015-08-19 14:03:11 +02003728 * @param[in] path Path to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003729 * @param[in] context_node Predicate context node (where the predicate is placed).
3730 * @param[in] parent Path context node (where the path begins/is placed).
Michal Vaskoe27516a2016-10-10 17:55:31 +00003731 * @param[in] op_node Optional node if the leafref is in an operation (action/rpc/notif).
Michal Vasko730dfdf2015-08-11 14:48:05 +02003732 *
Michal Vasko184521f2015-09-24 13:14:26 +02003733 * @return 0 on forward reference, otherwise the number
3734 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003735 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003736 */
Michal Vasko1f76a282015-08-04 16:16:53 +02003737static int
Radek Krejciadb57612016-02-16 13:34:34 +01003738resolve_path_predicate_schema(const char *path, const struct lys_node *context_node,
Michal Vaskoe27516a2016-10-10 17:55:31 +00003739 struct lys_node *parent, const struct lys_node *op_node)
Michal Vasko1f76a282015-08-04 16:16:53 +02003740{
Michal Vasko1e62a092015-12-01 12:27:20 +01003741 const struct lys_node *src_node, *dst_node;
Michal Vasko1f76a282015-08-04 16:16:53 +02003742 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vaskof9b35d92016-10-21 15:19:30 +02003743 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, pke_parsed, parsed = 0;
3744 int has_predicate, dest_parent_times, i, rc, first_iter;
Michal Vasko1f76a282015-08-04 16:16:53 +02003745
3746 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02003747 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02003748 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003749 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003750 return -parsed+i;
3751 }
3752 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003753 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02003754
Michal Vasko58090902015-08-13 14:04:15 +02003755 /* source (must be leaf) */
Michal Vasko36cbaa42015-12-14 13:15:48 +01003756 if (!sour_pref) {
Radek Krejciadb57612016-02-16 13:34:34 +01003757 sour_pref = context_node->module->name;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003758 }
Radek Krejciadb57612016-02-16 13:34:34 +01003759 rc = lys_get_sibling(context_node->child, sour_pref, sour_pref_len, source, sour_len,
Michal Vasko59ad4582016-09-16 13:15:41 +02003760 LYS_LEAF | LYS_LEAFLIST | LYS_AUGMENT, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003761 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003762 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02003763 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003764 }
3765
3766 /* destination */
Michal Vaskof9b35d92016-10-21 15:19:30 +02003767 dest_parent_times = 0;
3768 pke_parsed = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003769 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3770 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003771 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 +02003772 return -parsed;
3773 }
3774 pke_parsed += i;
3775
Radek Krejciadb57612016-02-16 13:34:34 +01003776 for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
Michal Vaskofbaead72016-10-07 10:54:48 +02003777 /* path is supposed to be evaluated in data tree, so we have to skip
3778 * all schema nodes that cannot be instantiated in data tree */
3779 for (dst_node = lys_parent(dst_node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003780 dst_node && !(dst_node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Michal Vaskofbaead72016-10-07 10:54:48 +02003781 dst_node = lys_parent(dst_node));
3782
Michal Vasko1f76a282015-08-04 16:16:53 +02003783 if (!dst_node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003784 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003785 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003786 }
3787 }
Michal Vaskoe27516a2016-10-10 17:55:31 +00003788 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003789 while (1) {
Michal Vasko36cbaa42015-12-14 13:15:48 +01003790 if (!dest_pref) {
3791 dest_pref = dst_node->module->name;
3792 }
3793 rc = lys_get_sibling(dst_node->child, dest_pref, dest_pref_len, dest, dest_len,
Michal Vasko165dc4a2015-10-23 09:44:27 +02003794 LYS_CONTAINER | LYS_LIST | LYS_LEAF | LYS_AUGMENT, &dst_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003795 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003796 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003797 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003798 }
3799
Michal Vaskoe27516a2016-10-10 17:55:31 +00003800 if (first_iter) {
3801 if (resolve_path_arg_schema_valid_dep_flag(op_node, dst_node, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01003802 parent->flags |= LYS_LEAFREF_DEP;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003803 }
3804 first_iter = 0;
3805 }
3806
Michal Vasko1f76a282015-08-04 16:16:53 +02003807 if (pke_len == pke_parsed) {
3808 break;
3809 }
3810
3811 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
3812 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003813 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent,
Radek Krejciadb57612016-02-16 13:34:34 +01003814 (path_key_expr+pke_parsed)[-i], (path_key_expr+pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003815 return -parsed;
3816 }
3817 pke_parsed += i;
3818 }
3819
3820 /* check source - dest match */
Michal Vasko59ad4582016-09-16 13:15:41 +02003821 if (dst_node->nodetype != src_node->nodetype) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003822 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko59ad4582016-09-16 13:15:41 +02003823 LOGVAL(LYE_SPEC, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "Destination node is not a %s, but a %s.",
3824 strnodetype(src_node->nodetype), strnodetype(dst_node->nodetype));
Michal Vasko184521f2015-09-24 13:14:26 +02003825 return -parsed;
3826 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003827 } while (has_predicate);
3828
3829 return parsed;
3830}
3831
Michal Vasko730dfdf2015-08-11 14:48:05 +02003832/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003833 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003834 *
Michal Vaskobb211122015-08-19 14:03:11 +02003835 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003836 * @param[in] parent_node Parent of the leafref.
Radek Krejci2f12f852016-01-08 12:59:57 +01003837 * @param[in] parent_tpdf Flag if the parent node is actually typedef, in that case the path
3838 * has to contain absolute path
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003839 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003840 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003841 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003842 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003843static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003844resolve_path_arg_schema(const char *path, struct lys_node *parent, int parent_tpdf,
Michal Vasko36cbaa42015-12-14 13:15:48 +01003845 const struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02003846{
Michal Vaskoe27516a2016-10-10 17:55:31 +00003847 const struct lys_node *node, *op_node = NULL;
Radek Krejci990af1f2016-11-09 13:53:36 +01003848 const struct lys_module *mod;
3849 struct lys_module *mod_start;
Michal Vasko1f76a282015-08-04 16:16:53 +02003850 const char *id, *prefix, *name;
3851 int pref_len, nam_len, parent_times, has_predicate;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003852 int i, first_iter, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02003853
Michal Vasko184521f2015-09-24 13:14:26 +02003854 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003855 parent_times = 0;
3856 id = path;
3857
Michal Vaskoe27516a2016-10-10 17:55:31 +00003858 /* find operation schema we are in, if applicable */
Michal Vaskoe9914d12016-10-07 14:32:37 +02003859 if (!parent_tpdf) {
Michal Vaskoe27516a2016-10-10 17:55:31 +00003860 for (op_node = lys_parent(parent);
3861 op_node && !(op_node->nodetype & (LYS_ACTION | LYS_NOTIF | LYS_RPC));
3862 op_node = lys_parent(op_node));
Michal Vaskoe9914d12016-10-07 14:32:37 +02003863 }
3864
Radek Krejci990af1f2016-11-09 13:53:36 +01003865 mod_start = lys_node_module(parent);
Michal Vasko1f76a282015-08-04 16:16:53 +02003866 do {
Radek Krejci990af1f2016-11-09 13:53:36 +01003867 if ((i = parse_path_arg(mod_start, id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003868 LOGVAL(LYE_INCHAR, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, id[-i], &id[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003869 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003870 }
3871 id += i;
3872
Michal Vasko184521f2015-09-24 13:14:26 +02003873 if (first_iter) {
Michal Vasko1f76a282015-08-04 16:16:53 +02003874 if (parent_times == -1) {
Radek Krejcic071c542016-01-27 14:57:51 +01003875 /* resolve prefix of the module */
Radek Krejci990af1f2016-11-09 13:53:36 +01003876 mod = prefix ? lys_get_import_module(mod_start, NULL, 0, prefix, pref_len) : mod_start;
3877 if (!mod) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003878 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3879 "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003880 return EXIT_FAILURE;
Michal Vasko58090902015-08-13 14:04:15 +02003881 }
Radek Krejci990af1f2016-11-09 13:53:36 +01003882 if (!mod->implemented) {
Radek Krejci2eee5c02016-12-06 19:18:05 +01003883 mod = lys_implemented_module(mod);
Radek Krejci990af1f2016-11-09 13:53:36 +01003884 if (!mod->implemented) {
3885 /* make the found module implemented */
3886 if (lys_set_implemented(mod)) {
3887 return EXIT_FAILURE;
3888 }
3889 }
3890 }
3891 /* get start node */
3892 if (!mod->data) {
3893 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3894 "leafref", path);
3895 return EXIT_FAILURE;
3896 }
3897 node = mod->data;
3898
Michal Vasko1f76a282015-08-04 16:16:53 +02003899 } else if (parent_times > 0) {
Radek Krejci2f12f852016-01-08 12:59:57 +01003900 if (parent_tpdf) {
3901 /* the path is not allowed to contain relative path since we are in top level typedef */
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003902 LOGVAL(LYE_NORESOLV, 0, NULL, "leafref", path);
Radek Krejci2f12f852016-01-08 12:59:57 +01003903 return -1;
3904 }
3905
Michal Vasko94458082016-10-07 14:34:36 +02003906 /* we are looking for a sibling of a node, node it's parent (that is why parent_times - 1) */
3907 for (i = 0, node = parent; i < parent_times - 1; i++) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02003908 /* path is supposed to be evaluated in data tree, so we have to skip
3909 * all schema nodes that cannot be instantiated in data tree */
3910 for (node = lys_parent(node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003911 node && !(node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Radek Krejci3a5501d2016-07-18 22:03:34 +02003912 node = lys_parent(node));
3913
Michal Vasko1f76a282015-08-04 16:16:53 +02003914 if (!node) {
Michal Vaskoe9914d12016-10-07 14:32:37 +02003915 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003916 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003917 }
3918 }
Radek Krejci990af1f2016-11-09 13:53:36 +01003919
3920 /* now we have to check that if we are going into a node from a different module,
3921 * the module is implemented (so its augments are applied) */
3922 mod = prefix ? lys_get_import_module(mod_start, NULL, 0, prefix, pref_len) : mod_start;
3923 if (!mod) {
3924 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
3925 return EXIT_FAILURE;
3926 }
3927 if (!mod->implemented) {
Radek Krejci2eee5c02016-12-06 19:18:05 +01003928 mod = lys_implemented_module(mod);
Radek Krejci990af1f2016-11-09 13:53:36 +01003929 if (!mod->implemented) {
3930 /* make the found module implemented */
3931 if (lys_set_implemented(mod)) {
3932 return EXIT_FAILURE;
3933 }
3934 }
3935 }
Michal Vaskoe01eca52015-08-13 14:42:02 +02003936 } else {
3937 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003938 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003939 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003940 } else {
Radek Krejci990af1f2016-11-09 13:53:36 +01003941 /* we have to first check that the module we are going into is implemented */
3942 mod = prefix ? lys_get_import_module(mod_start, NULL, 0, prefix, pref_len) : mod_start;
3943 if (!mod) {
3944 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
3945 return EXIT_FAILURE;
3946 }
3947 if (!mod->implemented) {
Radek Krejci2eee5c02016-12-06 19:18:05 +01003948 mod = lys_implemented_module(mod);
Radek Krejci990af1f2016-11-09 13:53:36 +01003949 if (!mod->implemented) {
3950 /* make the found module implemented */
3951 if (lys_set_implemented(mod)) {
3952 return EXIT_FAILURE;
3953 }
3954 }
3955 }
3956
Michal Vasko7dc71d02016-03-15 10:42:28 +01003957 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02003958 if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko2f5aceb2016-03-22 10:24:14 +01003959 LOGVAL(LYE_INCHAR, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, name[0], name);
Michal Vasko7dc71d02016-03-15 10:42:28 +01003960 return -1;
3961 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003962 node = node->child;
Radek Krejci43ccc4c2016-10-18 20:40:06 +02003963 if (!node) {
3964 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3965 "leafref", path);
3966 return EXIT_FAILURE;
3967 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003968 }
3969
Michal Vasko4f0dad02016-02-15 14:08:23 +01003970 if (!prefix) {
Radek Krejci990af1f2016-11-09 13:53:36 +01003971 prefix = mod_start->name;
Michal Vasko4f0dad02016-02-15 14:08:23 +01003972 }
3973
Michal Vasko36cbaa42015-12-14 13:15:48 +01003974 rc = lys_get_sibling(node, prefix, pref_len, name, nam_len, LYS_ANY & ~(LYS_USES | LYS_GROUPING), &node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003975 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003976 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko7a55bea2016-05-02 14:51:20 +02003977 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003978 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003979
Michal Vaskoe27516a2016-10-10 17:55:31 +00003980 if (first_iter) {
3981 /* set external dependency flag, we can decide based on the first found node */
3982 if (!parent_tpdf && op_node && parent_times &&
3983 resolve_path_arg_schema_valid_dep_flag(op_node, node, (parent_times == -1 ? 1 : 0))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01003984 parent->flags |= LYS_LEAFREF_DEP;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003985 }
3986 first_iter = 0;
3987 }
3988
Michal Vasko1f76a282015-08-04 16:16:53 +02003989 if (has_predicate) {
3990 /* we have predicate, so the current result must be list */
3991 if (node->nodetype != LYS_LIST) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003992 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003993 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003994 }
3995
Michal Vaskoe27516a2016-10-10 17:55:31 +00003996 i = resolve_path_predicate_schema(id, node, parent, op_node);
Radek Krejci27fe55e2016-09-13 17:13:35 +02003997 if (i <= 0) {
3998 if (i == 0) {
3999 return EXIT_FAILURE;
4000 } else { /* i < 0 */
4001 return -1;
4002 }
Michal Vasko1f76a282015-08-04 16:16:53 +02004003 }
4004 id += i;
Michal Vaskof9b35d92016-10-21 15:19:30 +02004005 has_predicate = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02004006 }
4007 } while (id[0]);
4008
Michal Vaskoca917682016-07-25 11:00:37 +02004009 /* the target must be leaf or leaf-list (in YANG 1.1 only) */
Radek Krejci2a5a9602016-11-04 10:21:13 +01004010 if ((node->nodetype != LYS_LEAF) && (node->nodetype != LYS_LEAFLIST)) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02004011 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Radek Krejcid47daf62016-08-22 16:23:38 +02004012 LOGVAL(LYE_SPEC, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
Radek Krejci2a5a9602016-11-04 10:21:13 +01004013 "Leafref target \"%s\" is not a leaf nor a leaf-list.", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004014 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02004015 }
4016
Radek Krejcicf509982015-12-15 09:22:44 +01004017 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01004018 if (lyp_check_status(parent->flags, parent->module, parent->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01004019 node->flags, node->module, node->name, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01004020 return -1;
4021 }
4022
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004023 if (ret) {
4024 *ret = node;
4025 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02004026
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004027 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02004028}
4029
Michal Vasko730dfdf2015-08-11 14:48:05 +02004030/**
Michal Vaskof39142b2015-10-21 11:40:05 +02004031 * @brief Resolve instance-identifier predicate in JSON data format.
4032 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004033 *
Michal Vaskobb211122015-08-19 14:03:11 +02004034 * @param[in] pred Predicate to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004035 * @param[in,out] node_match Nodes matching the restriction without
4036 * the predicate. Nodes not satisfying
4037 * the predicate are removed.
4038 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004039 * @return Number of characters successfully parsed,
4040 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004041 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004042static int
Michal Vaskof39142b2015-10-21 11:40:05 +02004043resolve_predicate(const char *pred, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004044{
Michal Vasko730dfdf2015-08-11 14:48:05 +02004045 /* ... /node[target = value] ... */
Michal Vaskob2f40be2016-09-08 16:03:48 +02004046 struct lyd_node *target;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004047 const char *model, *name, *value;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004048 int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed, pred_iter, k;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004049 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004050
Michal Vasko1f2cc332015-08-19 11:18:32 +02004051 assert(pred && node_match->count);
4052
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004053 idx = -1;
4054 parsed = 0;
4055
Michal Vaskob2f40be2016-09-08 16:03:48 +02004056 pred_iter = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004057 do {
Michal Vaskof39142b2015-10-21 11:40:05 +02004058 if ((i = parse_predicate(pred, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004059 return -parsed+i;
4060 }
4061 parsed += i;
4062 pred += i;
4063
4064 if (isdigit(name[0])) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004065 /* pos */
4066 assert(!value);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004067 idx = atoi(name);
Michal Vaskob2f40be2016-09-08 16:03:48 +02004068 } else if (name[0] != '.') {
4069 /* list keys */
4070 if (pred_iter < 0) {
4071 pred_iter = 1;
4072 } else {
4073 ++pred_iter;
4074 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004075 }
4076
Michal Vaskof2f28a12016-09-09 12:43:06 +02004077 for (cur_idx = 1, j = 0; j < node_match->count; ++cur_idx) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004078 /* target */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004079 if (name[0] == '.') {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004080 /* leaf-list value */
Michal Vaskocf024702015-10-08 15:01:42 +02004081 if (node_match->node[j]->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004082 goto remove_instid;
4083 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004084
4085 target = node_match->node[j];
4086 /* check the value */
4087 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
4088 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
4089 goto remove_instid;
4090 }
4091
4092 } else if (!value) {
4093 /* keyless list position */
4094 if ((node_match->node[j]->schema->nodetype != LYS_LIST)
4095 || ((struct lys_node_list *)node_match->node[j]->schema)->keys) {
4096 goto remove_instid;
4097 }
4098
4099 if (idx != cur_idx) {
4100 goto remove_instid;
4101 }
4102
4103 } else {
4104 /* list key value */
Michal Vaskocf024702015-10-08 15:01:42 +02004105 if (node_match->node[j]->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004106 goto remove_instid;
4107 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004108
4109 /* key module must match the list module */
4110 if (strncmp(node_match->node[j]->schema->module->name, model, mod_len)
4111 || node_match->node[j]->schema->module->name[mod_len]) {
4112 goto remove_instid;
4113 }
4114 /* find the key leaf */
Michal Vasko045182c2016-09-09 12:44:07 +02004115 for (k = 1, target = node_match->node[j]->child; target && (k < pred_iter); k++, target = target->next);
Michal Vaskob2f40be2016-09-08 16:03:48 +02004116 if (!target) {
4117 goto remove_instid;
4118 }
4119 if ((struct lys_node_leaf *)target->schema !=
4120 ((struct lys_node_list *)node_match->node[j]->schema)->keys[pred_iter - 1]) {
4121 goto remove_instid;
4122 }
4123
4124 /* check the value */
4125 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
4126 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
4127 goto remove_instid;
4128 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004129 }
4130
Michal Vaskob2f40be2016-09-08 16:03:48 +02004131 /* instid is ok, continue check with the next one */
Michal Vasko1f2cc332015-08-19 11:18:32 +02004132 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004133 continue;
4134
4135remove_instid:
Michal Vaskob2f40be2016-09-08 16:03:48 +02004136 /* does not fulfill conditions, remove instid record */
Michal Vasko1f2cc332015-08-19 11:18:32 +02004137 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004138 }
4139 } while (has_predicate);
4140
Michal Vaskob2f40be2016-09-08 16:03:48 +02004141 /* check that all list keys were specified */
4142 if ((pred_iter > 0) && node_match->count) {
Michal Vasko045182c2016-09-09 12:44:07 +02004143 j = 0;
4144 while (j < node_match->count) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004145 assert(node_match->node[j]->schema->nodetype == LYS_LIST);
4146 if (pred_iter < ((struct lys_node_list *)node_match->node[j]->schema)->keys_size) {
4147 /* not enough predicates, just remove the list instance */
4148 unres_data_del(node_match, j);
Michal Vasko045182c2016-09-09 12:44:07 +02004149 } else {
4150 ++j;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004151 }
4152 }
4153
4154 if (!node_match->count) {
4155 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier is missing some list keys.");
4156 }
4157 }
4158
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004159 return parsed;
4160}
4161
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004162int
4163lys_check_xpath(struct lys_node *node, int check_place)
Michal Vasko9e635ac2016-10-17 11:44:09 +02004164{
4165 struct lys_node *parent, *elem;
4166 struct lyxp_set set;
4167 uint32_t i;
4168 int rc;
4169
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004170 if (check_place) {
4171 parent = node;
4172 while (parent) {
4173 if (parent->nodetype == LYS_GROUPING) {
4174 /* unresolved grouping, skip for now (will be checked later) */
Michal Vasko9e635ac2016-10-17 11:44:09 +02004175 return EXIT_SUCCESS;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004176 }
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004177 if (parent->nodetype == LYS_AUGMENT) {
4178 if (!((struct lys_node_augment *)parent)->target) {
Radek Krejcidf46e222016-11-08 11:57:37 +01004179 /* unresolved augment */
4180 if (parent->module->implemented) {
4181 /* skip for now (will be checked later) */
4182 return EXIT_FAILURE;
4183 } else {
4184 /* not implemented augment, skip resolving */
4185 return EXIT_SUCCESS;
4186 }
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004187 } else {
4188 parent = ((struct lys_node_augment *)parent)->target;
4189 continue;
4190 }
4191 }
4192 parent = parent->parent;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004193 }
Michal Vasko9e635ac2016-10-17 11:44:09 +02004194 }
4195
4196 rc = lyxp_node_atomize(node, &set);
4197 if (rc) {
4198 return rc;
4199 }
4200
4201 for (parent = node; parent && !(parent->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); parent = lys_parent(parent));
4202
4203 for (i = 0; i < set.used; ++i) {
4204 /* skip roots'n'stuff */
4205 if (set.val.snodes[i].type == LYXP_NODE_ELEM) {
4206 /* XPath expression cannot reference "lower" status than the node that has the definition */
4207 if (lyp_check_status(node->flags, lys_node_module(node), node->name, set.val.snodes[i].snode->flags,
4208 lys_node_module(set.val.snodes[i].snode), set.val.snodes[i].snode->name, node)) {
4209 return -1;
4210 }
4211
4212 if (parent) {
4213 for (elem = set.val.snodes[i].snode; elem && (elem != parent); elem = lys_parent(elem));
4214 if (!elem) {
4215 /* not in node's RPC or notification subtree, set the flag */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01004216 node->flags |= LYS_XPATH_DEP;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004217 break;
4218 }
4219 }
4220 }
4221 }
4222
4223 free(set.val.snodes);
4224 return EXIT_SUCCESS;
4225}
4226
Radek Krejcif71f48f2016-10-25 16:37:24 +02004227static int
4228check_leafref_config(struct lys_node_leaf *leaf, struct lys_type *type)
4229{
4230 int i;
4231
4232 if (type->base == LY_TYPE_LEAFREF) {
4233 if ((leaf->flags & LYS_CONFIG_W) && type->info.lref.target && (type->info.lref.target->flags & LYS_CONFIG_R)) {
4234 LOGVAL(LYE_SPEC, LY_VLOG_LYS, leaf, "The %s is config but refers to a non-config %s.",
4235 strnodetype(leaf->nodetype), strnodetype(type->info.lref.target->nodetype));
4236 return -1;
4237 }
4238 /* we can skip the test in case the leafref is not yet resolved. In that case the test is done in the time
4239 * of leafref resolving (lys_leaf_add_leafref_target()) */
4240 } else if (type->base == LY_TYPE_UNION) {
4241 for (i = 0; i < type->info.uni.count; i++) {
4242 if (check_leafref_config(leaf, &type->info.uni.types[i])) {
4243 return -1;
4244 }
4245 }
4246 }
4247 return 0;
4248}
4249
Michal Vasko9e635ac2016-10-17 11:44:09 +02004250/**
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004251 * @brief Passes config flag down to children, skips nodes without config flags.
4252 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004253 *
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004254 * @param[in] node Siblings and their children to have flags changed.
Michal Vaskoe022a562016-09-27 14:24:15 +02004255 * @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 +02004256 * @param[in] flags Flags to assign to all the nodes.
Radek Krejcib3142312016-11-09 11:04:12 +01004257 * @param[in,out] unres List of unresolved items.
Michal Vaskoa86508c2016-08-26 14:30:19 +02004258 *
4259 * @return 0 on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004260 */
Michal Vaskoa86508c2016-08-26 14:30:19 +02004261static int
Radek Krejcib3142312016-11-09 11:04:12 +01004262inherit_config_flag(struct lys_node *node, int flags, int clear, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004263{
Radek Krejcif71f48f2016-10-25 16:37:24 +02004264 struct lys_node_leaf *leaf;
4265
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004266 assert(!(flags ^ (flags & LYS_CONFIG_MASK)));
Radek Krejci1d82ef62015-08-07 14:44:40 +02004267 LY_TREE_FOR(node, node) {
Radek Krejcib3142312016-11-09 11:04:12 +01004268 if (lys_has_xpath(node) && unres_schema_add_node(node->module, unres, node, UNRES_XPATH, NULL) == -1) {
Michal Vasko9e635ac2016-10-17 11:44:09 +02004269 return -1;
4270 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004271 if (clear) {
4272 node->flags &= ~LYS_CONFIG_MASK;
Michal Vaskoc2a8d362016-09-29 08:50:13 +02004273 node->flags &= ~LYS_CONFIG_SET;
Michal Vaskoe022a562016-09-27 14:24:15 +02004274 } else {
4275 if (node->flags & LYS_CONFIG_SET) {
4276 /* skip nodes with an explicit config value */
4277 if ((flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
4278 LOGVAL(LYE_INARG, LY_VLOG_LYS, node, "true", "config");
4279 LOGVAL(LYE_SPEC, LY_VLOG_LYS, node, "State nodes cannot have configuration nodes as children.");
4280 return -1;
4281 }
4282 continue;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004283 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004284
4285 if (!(node->nodetype & (LYS_USES | LYS_GROUPING))) {
4286 node->flags = (node->flags & ~LYS_CONFIG_MASK) | flags;
4287 /* check that configuration lists have keys */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004288 if ((node->nodetype == LYS_LIST) && (node->flags & LYS_CONFIG_W)
4289 && !((struct lys_node_list *)node)->keys_size) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004290 LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_LYS, node, "key", "list");
4291 return -1;
4292 }
4293 }
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004294 }
Radek Krejcibf2abff2016-08-23 15:51:52 +02004295 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Radek Krejcib3142312016-11-09 11:04:12 +01004296 if (inherit_config_flag(node->child, flags, clear, unres)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004297 return -1;
4298 }
Radek Krejcif71f48f2016-10-25 16:37:24 +02004299 } else if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
4300 leaf = (struct lys_node_leaf *)node;
4301 if (check_leafref_config(leaf, &leaf->type)) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02004302 return -1;
4303 }
4304 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004305 }
Michal Vaskoa86508c2016-08-26 14:30:19 +02004306
4307 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004308}
4309
Michal Vasko730dfdf2015-08-11 14:48:05 +02004310/**
Michal Vasko7178e692016-02-12 15:58:05 +01004311 * @brief Resolve augment target. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004312 *
Michal Vaskobb211122015-08-19 14:03:11 +02004313 * @param[in] aug Augment to use.
Michal Vasko3edeaf72016-02-11 13:17:43 +01004314 * @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 +01004315 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004316 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004317 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004318 */
Michal Vasko7178e692016-02-12 15:58:05 +01004319static int
Radek Krejcib3142312016-11-09 11:04:12 +01004320resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004321{
Michal Vaskoe022a562016-09-27 14:24:15 +02004322 int rc, clear_config;
Michal Vasko1d87a922015-08-21 12:57:16 +02004323 struct lys_node *sub;
Pavol Vican47319932016-08-29 09:14:47 +02004324 const struct lys_node *aug_target, *parent;
Radek Krejci27fe55e2016-09-13 17:13:35 +02004325 struct lys_module *mod;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004326
Michal Vasko15b36692016-08-26 15:29:54 +02004327 assert(aug && !aug->target);
Radek Krejcidf46e222016-11-08 11:57:37 +01004328 mod = lys_main_module(aug->module);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004329
Michal Vasko15b36692016-08-26 15:29:54 +02004330 /* resolve target node */
Radek Krejcidf46e222016-11-08 11:57:37 +01004331 rc = resolve_augment_schema_nodeid(aug->target_name, siblings, (siblings ? NULL : aug->module), mod->implemented, &aug_target);
Michal Vasko15b36692016-08-26 15:29:54 +02004332 if (rc == -1) {
4333 return -1;
Radek Krejci5fb4c382016-11-28 09:21:42 +01004334 } else if (rc > 0) {
Michal Vasko15b36692016-08-26 15:29:54 +02004335 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, aug, aug->target_name[rc - 1], &aug->target_name[rc - 1]);
4336 return -1;
Radek Krejci5fb4c382016-11-28 09:21:42 +01004337 } else if (rc == 0 && aug->target) {
4338 /* augment was resolved as a side effect of setting module implemented when
4339 * resolving augment schema nodeid, so we are done here */
4340 return 0;
Michal Vasko15b36692016-08-26 15:29:54 +02004341 }
Radek Krejcidf46e222016-11-08 11:57:37 +01004342 if (!aug_target && mod->implemented) {
Michal Vasko15b36692016-08-26 15:29:54 +02004343 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
4344 return EXIT_FAILURE;
4345 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02004346 /* check that we want to connect augment into its target */
Radek Krejci27fe55e2016-09-13 17:13:35 +02004347 if (!mod->implemented) {
4348 /* it must be augment only to the same module,
4349 * otherwise we do not apply augment in not-implemented
4350 * module. If the module is set to be implemented in future,
4351 * the augment is being resolved and checked again */
Radek Krejcidf46e222016-11-08 11:57:37 +01004352 if (!aug_target) {
4353 /* target was not even resolved */
4354 return EXIT_SUCCESS;
4355 }
4356 /* target was resolved, but it may refer another module */
4357 for (sub = (struct lys_node *)aug_target; sub; sub = lys_parent(sub)) {
Radek Krejci27fe55e2016-09-13 17:13:35 +02004358 if (lys_node_module(sub) != mod) {
4359 /* this is not an implemented module and the augment
4360 * target some other module, so avoid its connecting
4361 * to the target */
4362 return EXIT_SUCCESS;
4363 }
4364 }
4365 }
4366
Michal Vasko15b36692016-08-26 15:29:54 +02004367 if (!aug->child) {
4368 /* nothing to do */
4369 LOGWRN("Augment \"%s\" without children.", aug->target_name);
Radek Krejci27fe55e2016-09-13 17:13:35 +02004370 goto success;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004371 }
4372
Michal Vaskod58d5962016-03-02 14:29:41 +01004373 /* check for mandatory nodes - if the target node is in another module
4374 * the added nodes cannot be mandatory
4375 */
Michal Vasko15b36692016-08-26 15:29:54 +02004376 if (!aug->parent && (lys_node_module((struct lys_node *)aug) != lys_node_module(aug_target))
Radek Krejcidf24cbe2016-11-08 11:55:51 +01004377 && (rc = lyp_check_mandatory_augment(aug, aug_target))) {
Radek Krejcie00d2312016-08-12 15:27:49 +02004378 return rc;
Michal Vaskod58d5962016-03-02 14:29:41 +01004379 }
4380
Michal Vasko07e89ef2016-03-03 13:28:57 +01004381 /* check augment target type and then augment nodes type */
Michal Vasko15b36692016-08-26 15:29:54 +02004382 if (aug_target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF)) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004383 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004384 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES | LYS_CHOICE))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004385 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4386 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko15b36692016-08-26 15:29:54 +02004387 strnodetype(aug_target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004388 return -1;
4389 }
4390 }
Michal Vasko15b36692016-08-26 15:29:54 +02004391 } else if (aug_target->nodetype == LYS_CHOICE) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004392 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004393 if (!(sub->nodetype & (LYS_CASE | LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004394 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4395 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko15b36692016-08-26 15:29:54 +02004396 strnodetype(aug_target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004397 return -1;
4398 }
4399 }
4400 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01004401 LOGVAL(LYE_INARG, LY_VLOG_LYS, aug, aug->target_name, "target-node");
Michal Vasko15b36692016-08-26 15:29:54 +02004402 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Invalid augment target node type \"%s\".", strnodetype(aug_target->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004403 return -1;
4404 }
4405
Radek Krejcic071c542016-01-27 14:57:51 +01004406 /* check identifier uniqueness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02004407 LY_TREE_FOR(aug->child, sub) {
Michal Vasko15b36692016-08-26 15:29:54 +02004408 if (lys_check_id(sub, (struct lys_node *)aug_target, NULL)) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02004409 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02004410 }
4411 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004412
Michal Vasko15b36692016-08-26 15:29:54 +02004413 /* finally reconnect augmenting data into the target - add them to the target child list,
4414 * by setting aug->target we know the augment is fully resolved now */
4415 aug->target = (struct lys_node *)aug_target;
4416 if (aug->target->child) {
4417 sub = aug->target->child->prev; /* remember current target's last node */
4418 sub->next = aug->child; /* connect augmenting data after target's last node */
4419 aug->target->child->prev = aug->child->prev; /* new target's last node is last augmenting node */
4420 aug->child->prev = sub; /* finish connecting of both child lists */
4421 } else {
4422 aug->target->child = aug->child;
4423 }
4424
Michal Vasko9e635ac2016-10-17 11:44:09 +02004425 /* inherit config information from actual parent */
4426 for(parent = aug_target; parent && !(parent->nodetype & (LYS_NOTIF | LYS_INPUT | LYS_OUTPUT | LYS_RPC)); parent = lys_parent(parent));
4427 clear_config = (parent) ? 1 : 0;
4428 LY_TREE_FOR(aug->child, sub) {
Radek Krejcib3142312016-11-09 11:04:12 +01004429 if (inherit_config_flag(sub, aug_target->flags & LYS_CONFIG_MASK, clear_config, unres)) {
Michal Vasko9e635ac2016-10-17 11:44:09 +02004430 return -1;
4431 }
4432 }
4433
Radek Krejci27fe55e2016-09-13 17:13:35 +02004434success:
4435 if (mod->implemented) {
4436 /* make target modules also implemented */
4437 for (sub = aug->target; sub; sub = lys_parent(sub)) {
4438 if (lys_set_implemented(sub->module)) {
4439 return -1;
4440 }
4441 }
4442 }
4443
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004444 return EXIT_SUCCESS;
4445}
4446
Michal Vasko730dfdf2015-08-11 14:48:05 +02004447/**
Pavol Vican855ca622016-09-05 13:07:54 +02004448 * @brief Resolve (find) choice default case. Does not log.
4449 *
4450 * @param[in] choic Choice to use.
4451 * @param[in] dflt Name of the default case.
4452 *
4453 * @return Pointer to the default node or NULL.
4454 */
4455static struct lys_node *
4456resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
4457{
4458 struct lys_node *child, *ret;
4459
4460 LY_TREE_FOR(choic->child, child) {
4461 if (child->nodetype == LYS_USES) {
4462 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
4463 if (ret) {
4464 return ret;
4465 }
4466 }
4467
4468 if (ly_strequal(child->name, dflt, 1) && (child->nodetype & (LYS_ANYDATA | LYS_CASE
Radek Krejci2f792db2016-09-12 10:52:33 +02004469 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE))) {
Pavol Vican855ca622016-09-05 13:07:54 +02004470 return child;
4471 }
4472 }
4473
4474 return NULL;
4475}
4476
4477/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02004478 * @brief Resolve uses, apply augments, refines. Logs directly.
4479 *
Michal Vaskobb211122015-08-19 14:03:11 +02004480 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004481 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004482 *
Michal Vaskodef0db12015-10-07 13:22:48 +02004483 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004484 */
Michal Vasko184521f2015-09-24 13:14:26 +02004485static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004486resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004487{
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004488 struct ly_ctx *ctx = uses->module->ctx; /* shortcut */
Pavol Vican855ca622016-09-05 13:07:54 +02004489 struct lys_node *node = NULL, *next, *iter, **refine_nodes = NULL;
Pavol Vican55abd332016-07-12 15:54:49 +02004490 struct lys_node *node_aux, *parent, *tmp;
Radek Krejci200bf712016-08-16 17:11:04 +02004491 struct lys_node_leaflist *llist;
4492 struct lys_node_leaf *leaf;
Radek Krejci76512572015-08-04 09:47:08 +02004493 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004494 struct lys_restr *must, **old_must;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004495 struct lys_iffeature *iff, **old_iff;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004496 int i, j, k, rc;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004497 uint8_t size, *old_size;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004498 unsigned int usize, usize1, usize2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004499
Michal Vasko71e1aa82015-08-12 12:17:51 +02004500 assert(uses->grp);
Michal Vaskoe7708512016-03-11 10:26:55 +01004501 /* HACK just check that the grouping is resolved */
Michal Vaskodef0db12015-10-07 13:22:48 +02004502 assert(!uses->grp->nacm);
Michal Vasko71e1aa82015-08-12 12:17:51 +02004503
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004504 if (!uses->grp->child) {
4505 /* grouping without children, warning was already displayed */
4506 return EXIT_SUCCESS;
4507 }
4508
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004509 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01004510 LY_TREE_FOR(uses->grp->child, node_aux) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004511 node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, uses->nacm, unres, 0);
Michal Vasko1e62a092015-12-01 12:27:20 +01004512 if (!node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004513 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, uses->grp->name, "uses");
4514 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Copying data from grouping failed.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004515 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004516 }
Pavol Vican55abd332016-07-12 15:54:49 +02004517 /* test the name of siblings */
4518 LY_TREE_FOR((uses->parent) ? uses->parent->child : lys_main_module(uses->module)->data, tmp) {
Pavol Vican2510ddc2016-07-18 16:23:44 +02004519 if (!(tmp->nodetype & (LYS_USES | LYS_GROUPING | LYS_CASE)) && ly_strequal(tmp->name, node_aux->name, 1)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004520 goto fail;
Pavol Vican55abd332016-07-12 15:54:49 +02004521 }
4522 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004523 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004524
Michal Vaskodef0db12015-10-07 13:22:48 +02004525 /* we managed to copy the grouping, the rest must be possible to resolve */
4526
Pavol Vican855ca622016-09-05 13:07:54 +02004527 if (uses->refine_size) {
4528 refine_nodes = malloc(uses->refine_size * sizeof *refine_nodes);
4529 if (!refine_nodes) {
4530 LOGMEM;
4531 goto fail;
4532 }
4533 }
4534
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004535 /* apply refines */
4536 for (i = 0; i < uses->refine_size; i++) {
4537 rfn = &uses->refine[i];
Michal Vasko3edeaf72016-02-11 13:17:43 +01004538 rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child, LYS_NO_RPC_NOTIF_NODE,
Radek Krejcif3c71de2016-04-11 12:45:46 +02004539 1, 0, (const struct lys_node **)&node);
Michal Vasko9bb061b2016-02-12 11:00:19 +01004540 if (rc || !node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004541 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004542 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004543 }
4544
Radek Krejci1d82ef62015-08-07 14:44:40 +02004545 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004546 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
4547 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Refine substatements not applicable to the target-node.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004548 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004549 }
Pavol Vican855ca622016-09-05 13:07:54 +02004550 refine_nodes[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004551
4552 /* description on any nodetype */
4553 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004554 lydict_remove(ctx, node->dsc);
4555 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004556 }
4557
4558 /* reference on any nodetype */
4559 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004560 lydict_remove(ctx, node->ref);
4561 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004562 }
4563
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004564 /* config on any nodetype,
4565 * in case of notification or rpc/action, the config is not applicable (there is no config status) */
4566 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004567 node->flags &= ~LYS_CONFIG_MASK;
4568 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004569 }
4570
4571 /* default value ... */
Radek Krejci200bf712016-08-16 17:11:04 +02004572 if (rfn->dflt_size) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004573 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004574 /* leaf */
Radek Krejci200bf712016-08-16 17:11:04 +02004575 leaf = (struct lys_node_leaf *)node;
4576
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004577 /* replace default value */
Radek Krejci200bf712016-08-16 17:11:04 +02004578 lydict_remove(ctx, leaf->dflt);
4579 leaf->dflt = lydict_insert(ctx, rfn->dflt[0], 0);
4580
4581 /* check the default value */
Radek Krejci51673202016-11-01 17:00:32 +01004582 if (unres_schema_add_node(leaf->module, unres, &leaf->type, UNRES_TYPE_DFLT,
4583 (struct lys_node *)(&leaf->dflt)) == -1) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004584 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004585 }
Radek Krejci200bf712016-08-16 17:11:04 +02004586 } else if (node->nodetype == LYS_LEAFLIST) {
4587 /* leaf-list */
4588 llist = (struct lys_node_leaflist *)node;
4589
4590 /* remove complete set of defaults in target */
4591 for (i = 0; i < llist->dflt_size; i++) {
4592 lydict_remove(ctx, llist->dflt[i]);
4593 }
4594 free(llist->dflt);
4595
4596 /* copy the default set from refine */
4597 llist->dflt_size = rfn->dflt_size;
4598 llist->dflt = malloc(llist->dflt_size * sizeof *llist->dflt);
4599 for (i = 0; i < llist->dflt_size; i++) {
4600 llist->dflt[i] = lydict_insert(ctx, rfn->dflt[i], 0);
4601 }
4602
4603 /* check default value */
4604 for (i = 0; i < llist->dflt_size; i++) {
Radek Krejci51673202016-11-01 17:00:32 +01004605 if (unres_schema_add_node(llist->module, unres, &llist->type, UNRES_TYPE_DFLT,
4606 (struct lys_node *)(&llist->dflt[i])) == -1) {
Pavol Vican855ca622016-09-05 13:07:54 +02004607 goto fail;
Radek Krejci200bf712016-08-16 17:11:04 +02004608 }
4609 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004610 }
4611 }
4612
4613 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02004614 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004615 if (node->nodetype & (LYS_LEAF | LYS_ANYDATA | LYS_CHOICE)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004616 /* remove current value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004617 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004618
4619 /* set new value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004620 node->flags |= (rfn->flags & LYS_MAND_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004621 }
Pavol Vican855ca622016-09-05 13:07:54 +02004622 if (rfn->flags & LYS_MAND_TRUE) {
4623 /* check if node has default value */
4624 if ((node->nodetype & LYS_LEAF) && ((struct lys_node_leaf *)node)->dflt) {
4625 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"mandatory\" statement is forbidden on leaf with \"default\".");
4626 goto fail;
4627 }
4628 if ((node->nodetype & LYS_CHOICE) && ((struct lys_node_choice *)node)->dflt) {
4629 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"mandatory\" statement is forbidden on choices with \"default\".");
4630 goto fail;
4631 }
4632 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004633 }
4634
4635 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004636 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
4637 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
4638 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004639 }
4640
4641 /* min/max-elements on list or leaf-list */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004642 if (node->nodetype == LYS_LIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004643 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004644 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004645 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004646 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004647 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004648 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02004649 } else if (node->nodetype == LYS_LEAFLIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004650 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004651 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004652 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004653 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004654 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004655 }
4656 }
4657
4658 /* must in leaf, leaf-list, list, container or anyxml */
4659 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004660 switch (node->nodetype) {
4661 case LYS_LEAF:
4662 old_size = &((struct lys_node_leaf *)node)->must_size;
4663 old_must = &((struct lys_node_leaf *)node)->must;
4664 break;
4665 case LYS_LEAFLIST:
4666 old_size = &((struct lys_node_leaflist *)node)->must_size;
4667 old_must = &((struct lys_node_leaflist *)node)->must;
4668 break;
4669 case LYS_LIST:
4670 old_size = &((struct lys_node_list *)node)->must_size;
4671 old_must = &((struct lys_node_list *)node)->must;
4672 break;
4673 case LYS_CONTAINER:
4674 old_size = &((struct lys_node_container *)node)->must_size;
4675 old_must = &((struct lys_node_container *)node)->must;
4676 break;
4677 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02004678 case LYS_ANYDATA:
4679 old_size = &((struct lys_node_anydata *)node)->must_size;
4680 old_must = &((struct lys_node_anydata *)node)->must;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004681 break;
4682 default:
4683 LOGINT;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004684 goto fail;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004685 }
4686
4687 size = *old_size + rfn->must_size;
4688 must = realloc(*old_must, size * sizeof *rfn->must);
4689 if (!must) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004690 LOGMEM;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004691 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004692 }
Pavol Vican855ca622016-09-05 13:07:54 +02004693 for (k = 0, j = *old_size; k < rfn->must_size; k++, j++) {
4694 must[j].expr = lydict_insert(ctx, rfn->must[k].expr, 0);
4695 must[j].dsc = lydict_insert(ctx, rfn->must[k].dsc, 0);
4696 must[j].ref = lydict_insert(ctx, rfn->must[k].ref, 0);
4697 must[j].eapptag = lydict_insert(ctx, rfn->must[k].eapptag, 0);
4698 must[j].emsg = lydict_insert(ctx, rfn->must[k].emsg, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004699 }
4700
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004701 *old_must = must;
4702 *old_size = size;
Michal Vasko508a50d2016-09-07 14:50:33 +02004703
4704 /* check XPath dependencies again */
4705 if (unres_schema_add_node(node->module, unres, node, UNRES_XPATH, NULL) == -1) {
4706 goto fail;
4707 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004708 }
Radek Krejci363bd4a2016-07-29 14:30:20 +02004709
4710 /* if-feature in leaf, leaf-list, list, container or anyxml */
4711 if (rfn->iffeature_size) {
4712 old_size = &node->iffeature_size;
4713 old_iff = &node->iffeature;
4714
4715 size = *old_size + rfn->iffeature_size;
4716 iff = realloc(*old_iff, size * sizeof *rfn->iffeature);
4717 if (!iff) {
4718 LOGMEM;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004719 goto fail;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004720 }
Pavol Vican855ca622016-09-05 13:07:54 +02004721 for (k = 0, j = *old_size; k < rfn->iffeature_size; k++, j++) {
4722 resolve_iffeature_getsizes(&rfn->iffeature[k], &usize1, &usize2);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004723 if (usize1) {
4724 /* there is something to duplicate */
4725 /* duplicate compiled expression */
4726 usize = (usize1 / 4) + (usize1 % 4) ? 1 : 0;
4727 iff[j].expr = malloc(usize * sizeof *iff[j].expr);
Pavol Vican855ca622016-09-05 13:07:54 +02004728 memcpy(iff[j].expr, rfn->iffeature[k].expr, usize * sizeof *iff[j].expr);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004729
4730 /* duplicate list of feature pointers */
Pavol Vican855ca622016-09-05 13:07:54 +02004731 iff[j].features = malloc(usize2 * sizeof *iff[k].features);
4732 memcpy(iff[j].features, rfn->iffeature[k].features, usize2 * sizeof *iff[j].features);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004733 }
4734 }
4735
4736 *old_iff = iff;
4737 *old_size = size;
4738 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004739 }
4740
4741 /* apply augments */
4742 for (i = 0; i < uses->augment_size; i++) {
Radek Krejcib3142312016-11-09 11:04:12 +01004743 rc = resolve_augment(&uses->augment[i], uses->child, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004744 if (rc) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004745 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004746 }
4747 }
4748
Pavol Vican855ca622016-09-05 13:07:54 +02004749 /* check refines */
4750 for (i = 0; i < uses->refine_size; i++) {
4751 node = refine_nodes[i];
4752 rfn = &uses->refine[i];
4753
4754 /* config on any nodetype */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004755 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Pavol Vican855ca622016-09-05 13:07:54 +02004756 for (parent = lys_parent(node); parent && parent->nodetype == LYS_USES; parent = lys_parent(parent));
Radek Krejci5c08a992016-11-02 13:30:04 +01004757 if (parent && parent->nodetype != LYS_GROUPING && (parent->flags & LYS_CONFIG_MASK) &&
Pavol Vican855ca622016-09-05 13:07:54 +02004758 ((parent->flags & LYS_CONFIG_MASK) != (rfn->flags & LYS_CONFIG_MASK)) &&
4759 (rfn->flags & LYS_CONFIG_W)) {
4760 /* setting config true under config false is prohibited */
4761 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
4762 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4763 "changing config from 'false' to 'true' is prohibited while "
4764 "the target's parent is still config 'false'.");
4765 goto fail;
4766 }
4767
4768 /* inherit config change to the target children */
4769 LY_TREE_DFS_BEGIN(node->child, next, iter) {
4770 if (rfn->flags & LYS_CONFIG_W) {
4771 if (iter->flags & LYS_CONFIG_SET) {
4772 /* config is set explicitely, go to next sibling */
4773 next = NULL;
4774 goto nextsibling;
4775 }
4776 } else { /* LYS_CONFIG_R */
4777 if ((iter->flags & LYS_CONFIG_SET) && (iter->flags & LYS_CONFIG_W)) {
4778 /* error - we would have config data under status data */
4779 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
4780 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4781 "changing config from 'true' to 'false' is prohibited while the target "
4782 "has still a children with explicit config 'true'.");
4783 goto fail;
4784 }
4785 }
4786 /* change config */
4787 iter->flags &= ~LYS_CONFIG_MASK;
4788 iter->flags |= (rfn->flags & LYS_CONFIG_MASK);
4789
4790 /* select next iter - modified LY_TREE_DFS_END */
4791 if (iter->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
4792 next = NULL;
4793 } else {
4794 next = iter->child;
4795 }
4796nextsibling:
4797 if (!next) {
4798 /* try siblings */
4799 next = iter->next;
4800 }
4801 while (!next) {
4802 /* parent is already processed, go to its sibling */
4803 iter = lys_parent(iter);
4804
4805 /* no siblings, go back through parents */
4806 if (iter == node) {
4807 /* we are done, no next element to process */
4808 break;
4809 }
4810 next = iter->next;
4811 }
4812 }
4813 }
4814
4815 /* default value */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004816 if (rfn->dflt_size) {
4817 if (node->nodetype == LYS_CHOICE) {
4818 /* choice */
4819 ((struct lys_node_choice *)node)->dflt = resolve_choice_dflt((struct lys_node_choice *)node,
4820 rfn->dflt[0]);
4821 if (!((struct lys_node_choice *)node)->dflt) {
4822 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->dflt[0], "default");
4823 goto fail;
4824 }
4825 if (lyp_check_mandatory_choice(node)) {
4826 goto fail;
4827 }
Pavol Vican855ca622016-09-05 13:07:54 +02004828 }
4829 }
4830
4831 /* min/max-elements on list or leaf-list */
4832 if (node->nodetype == LYS_LIST) {
4833 if (((struct lys_node_list *)node)->min > ((struct lys_node_list *)node)->max) {
4834 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
4835 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "\"min-elements\" is bigger than \"max-elements\".");
4836 goto fail;
4837 }
4838 } else if (node->nodetype == LYS_LEAFLIST) {
4839 if (((struct lys_node_leaflist *)node)->min > ((struct lys_node_leaflist *)node)->max) {
4840 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
4841 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "\"min-elements\" is bigger than \"max-elements\".");
4842 goto fail;
4843 }
4844 }
4845
4846 /* additional checks */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004847 /* default value with mandatory/min-elements */
Pavol Vican855ca622016-09-05 13:07:54 +02004848 if (node->nodetype == LYS_LEAFLIST) {
4849 llist = (struct lys_node_leaflist *)node;
4850 if (llist->dflt_size && llist->min) {
4851 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, rfn->dflt_size ? "default" : "min-elements", "refine");
4852 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
4853 "The \"min-elements\" statement with non-zero value is forbidden on leaf-lists with the \"default\" statement.");
4854 goto fail;
4855 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004856 } else if (node->nodetype == LYS_LEAF) {
4857 leaf = (struct lys_node_leaf *)node;
4858 if (leaf->dflt && (leaf->flags & LYS_MAND_TRUE)) {
4859 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, rfn->dflt_size ? "default" : "mandatory", "refine");
4860 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
4861 "The \"mandatory\" statement is forbidden on leafs with the \"default\" statement.");
4862 goto fail;
4863 }
Pavol Vican855ca622016-09-05 13:07:54 +02004864 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004865
Pavol Vican855ca622016-09-05 13:07:54 +02004866 /* check for mandatory node in default case, first find the closest parent choice to the changed node */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004867 if ((rfn->flags & LYS_MAND_TRUE) || rfn->mod.list.min) {
Pavol Vican855ca622016-09-05 13:07:54 +02004868 for (parent = node->parent;
4869 parent && !(parent->nodetype & (LYS_CHOICE | LYS_GROUPING | LYS_ACTION | LYS_USES));
4870 parent = parent->parent) {
4871 if (parent->nodetype == LYS_CONTAINER && ((struct lys_node_container *)parent)->presence) {
4872 /* stop also on presence containers */
4873 break;
4874 }
4875 }
4876 /* and if it is a choice with the default case, check it for presence of a mandatory node in it */
4877 if (parent && parent->nodetype == LYS_CHOICE && ((struct lys_node_choice *)parent)->dflt) {
4878 if (lyp_check_mandatory_choice(parent)) {
4879 goto fail;
4880 }
4881 }
4882 }
4883 }
4884 free(refine_nodes);
4885
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004886 return EXIT_SUCCESS;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004887
4888fail:
4889 LY_TREE_FOR_SAFE(uses->child, next, iter) {
4890 lys_node_free(iter, NULL, 0);
4891 }
Pavol Vican855ca622016-09-05 13:07:54 +02004892 free(refine_nodes);
Michal Vaskoa86508c2016-08-26 14:30:19 +02004893 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004894}
4895
Radek Krejci018f1f52016-08-03 16:01:20 +02004896static int
4897identity_backlink_update(struct lys_ident *der, struct lys_ident *base)
4898{
4899 int i;
4900
4901 assert(der && base);
4902
Radek Krejci018f1f52016-08-03 16:01:20 +02004903 if (!base->der) {
Radek Krejci85a54be2016-10-20 12:39:56 +02004904 /* create a set for backlinks if it does not exist */
4905 base->der = ly_set_new();
Radek Krejci018f1f52016-08-03 16:01:20 +02004906 }
Radek Krejci85a54be2016-10-20 12:39:56 +02004907 /* store backlink */
4908 ly_set_add(base->der, der, LY_SET_OPT_USEASLIST);
Radek Krejci018f1f52016-08-03 16:01:20 +02004909
Radek Krejci85a54be2016-10-20 12:39:56 +02004910 /* do it recursively */
Radek Krejci018f1f52016-08-03 16:01:20 +02004911 for (i = 0; i < base->base_size; i++) {
4912 if (identity_backlink_update(der, base->base[i])) {
4913 return EXIT_FAILURE;
4914 }
4915 }
4916
4917 return EXIT_SUCCESS;
4918}
4919
Michal Vasko730dfdf2015-08-11 14:48:05 +02004920/**
4921 * @brief Resolve base identity recursively. Does not log.
4922 *
4923 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004924 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004925 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004926 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004927 *
Radek Krejci219fa612016-08-15 10:36:51 +02004928 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on crucial error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004929 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004930static int
Michal Vasko1e62a092015-12-01 12:27:20 +01004931resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Radek Krejci018f1f52016-08-03 16:01:20 +02004932 struct unres_schema *unres, struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004933{
Michal Vaskof02e3742015-08-05 16:27:02 +02004934 uint32_t i, j;
Radek Krejci018f1f52016-08-03 16:01:20 +02004935 struct lys_ident *base = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004936
Radek Krejcicf509982015-12-15 09:22:44 +01004937 assert(ret);
4938
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004939 /* search module */
4940 for (i = 0; i < module->ident_size; i++) {
4941 if (!strcmp(basename, module->ident[i].name)) {
4942
4943 if (!ident) {
4944 /* just search for type, so do not modify anything, just return
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004945 * the base identity pointer */
Radek Krejcicf509982015-12-15 09:22:44 +01004946 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004947 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004948 }
4949
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004950 base = &module->ident[i];
4951 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004952 }
4953 }
4954
4955 /* search submodules */
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004956 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
4957 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
4958 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004959
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004960 if (!ident) {
4961 *ret = &module->inc[j].submodule->ident[i];
4962 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004963 }
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004964
4965 base = &module->inc[j].submodule->ident[i];
4966 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004967 }
4968 }
4969 }
4970
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004971matchfound:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004972 /* we found it somewhere */
Radek Krejcibabbff82016-02-19 13:31:37 +01004973 if (base) {
Radek Krejci018f1f52016-08-03 16:01:20 +02004974 /* is it already completely resolved? */
4975 for (i = 0; i < unres->count; i++) {
Radek Krejciba7b1cc2016-08-08 13:44:43 +02004976 if ((unres->item[i] == base) && (unres->type[i] == UNRES_IDENT)) {
Radek Krejci018f1f52016-08-03 16:01:20 +02004977 /* identity found, but not yet resolved, so do not return it in *res and try it again later */
4978
4979 /* simple check for circular reference,
4980 * the complete check is done as a side effect of using only completely
4981 * resolved identities (previous check of unres content) */
4982 if (ly_strequal((const char *)unres->str_snode[i], ident->name, 1)) {
4983 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, basename, "base");
4984 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Circular reference of \"%s\" identity.", basename);
Radek Krejci219fa612016-08-15 10:36:51 +02004985 return -1;
Radek Krejci018f1f52016-08-03 16:01:20 +02004986 }
4987
Radek Krejci06f64ed2016-08-15 11:07:44 +02004988 return EXIT_FAILURE;
Radek Krejcibabbff82016-02-19 13:31:37 +01004989 }
4990 }
Radek Krejci018f1f52016-08-03 16:01:20 +02004991
Radek Krejcibabbff82016-02-19 13:31:37 +01004992 /* checks done, store the result */
Radek Krejci018f1f52016-08-03 16:01:20 +02004993 *ret = base;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02004994 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004995 }
4996
Radek Krejci219fa612016-08-15 10:36:51 +02004997 /* base not found (maybe a forward reference) */
4998 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004999}
5000
Michal Vasko730dfdf2015-08-11 14:48:05 +02005001/**
5002 * @brief Resolve base identity. Logs directly.
5003 *
5004 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02005005 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005006 * @param[in] basename Base name of the identity.
Radek Krejcibabbff82016-02-19 13:31:37 +01005007 * @param[in] parent Either "type" or "identity".
Radek Krejcicf509982015-12-15 09:22:44 +01005008 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005009 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005010 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005011 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005012static int
Michal Vaskof2d43962016-09-02 11:10:16 +02005013resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char *parent,
Radek Krejci018f1f52016-08-03 16:01:20 +02005014 struct lys_type *type, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005015{
5016 const char *name;
Radek Krejci219fa612016-08-15 10:36:51 +02005017 int mod_name_len = 0, rc;
Radek Krejcicf509982015-12-15 09:22:44 +01005018 struct lys_ident *target, **ret;
Radek Krejci4372b4e2016-04-14 17:42:16 +02005019 uint16_t flags;
Radek Krejcicf509982015-12-15 09:22:44 +01005020 struct lys_module *mod;
5021
5022 assert((ident && !type) || (!ident && type));
5023
5024 if (!type) {
5025 /* have ident to resolve */
5026 ret = &target;
5027 flags = ident->flags;
5028 mod = ident->module;
5029 } else {
5030 /* have type to fill */
Michal Vaskof2d43962016-09-02 11:10:16 +02005031 ++type->info.ident.count;
5032 type->info.ident.ref = ly_realloc(type->info.ident.ref, type->info.ident.count * sizeof *type->info.ident.ref);
5033 if (!type->info.ident.ref) {
5034 LOGMEM;
5035 return -1;
5036 }
5037
5038 ret = &type->info.ident.ref[type->info.ident.count - 1];
Radek Krejcicf509982015-12-15 09:22:44 +01005039 flags = type->parent->flags;
5040 mod = type->parent->module;
5041 }
Michal Vaskof2006002016-04-21 16:28:15 +02005042 *ret = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005043
5044 /* search for the base identity */
5045 name = strchr(basename, ':');
5046 if (name) {
5047 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02005048 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005049 name++;
5050
Michal Vasko2d851a92015-10-20 16:16:36 +02005051 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005052 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02005053 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005054 }
5055 } else {
5056 name = basename;
5057 }
5058
Radek Krejcic071c542016-01-27 14:57:51 +01005059 /* get module where to search */
5060 module = lys_get_import_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len);
5061 if (!module) {
5062 /* identity refers unknown data model */
Radek Krejci02a04992016-03-17 16:06:37 +01005063 LOGVAL(LYE_INMOD, LY_VLOG_NONE, NULL, basename);
Radek Krejcic071c542016-01-27 14:57:51 +01005064 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005065 }
5066
Radek Krejcic071c542016-01-27 14:57:51 +01005067 /* search in the identified module ... */
Radek Krejci219fa612016-08-15 10:36:51 +02005068 rc = resolve_base_ident_sub(module, ident, name, unres, ret);
5069 if (!rc) {
5070 assert(*ret);
5071
5072 /* check status */
5073 if (lyp_check_status(flags, mod, ident ? ident->name : "of type",
5074 (*ret)->flags, (*ret)->module, (*ret)->name, NULL)) {
5075 rc = -1;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02005076 } else {
5077 if (ident) {
5078 ident->base[ident->base_size++] = *ret;
5079
5080 /* maintain backlinks to the derived identities */
5081 rc = identity_backlink_update(ident, *ret) ? -1 : EXIT_SUCCESS;
5082 }
Radek Krejci219fa612016-08-15 10:36:51 +02005083 }
5084 } else if (rc == EXIT_FAILURE) {
5085 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, parent, basename);
Pavol Vican053a2882016-09-05 14:40:33 +02005086 if (type) {
5087 --type->info.ident.count;
5088 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005089 }
5090
Radek Krejci219fa612016-08-15 10:36:51 +02005091 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005092}
5093
Michal Vasko730dfdf2015-08-11 14:48:05 +02005094/**
Michal Vaskof39142b2015-10-21 11:40:05 +02005095 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005096 *
Michal Vaskof2d43962016-09-02 11:10:16 +02005097 * @param[in] type Identityref type.
Michal Vaskofb0873c2015-08-21 09:00:07 +02005098 * @param[in] ident_name Identityref name.
Radek Krejciadb57612016-02-16 13:34:34 +01005099 * @param[in] node Node where the identityref is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02005100 *
5101 * @return Pointer to the identity resolvent, NULL on error.
5102 */
Radek Krejcia52656e2015-08-05 13:41:50 +02005103struct lys_ident *
Michal Vaskof2d43962016-09-02 11:10:16 +02005104resolve_identref(struct lys_type *type, const char *ident_name, struct lyd_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005105{
Radek Krejci639491e2016-12-05 13:30:42 +01005106 const char *mod_name, *name, *mod_name_iter;
Radek Krejci85a54be2016-10-20 12:39:56 +02005107 int mod_name_len, rc, i;
5108 unsigned int u;
Michal Vaskof2d43962016-09-02 11:10:16 +02005109 struct lys_ident *der, *cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005110
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005111 assert(type && ident_name && node);
5112
Michal Vaskof2d43962016-09-02 11:10:16 +02005113 if (!type || (!type->info.ident.count && !type->der) || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005114 return NULL;
5115 }
5116
Michal Vaskoc633ca02015-08-21 14:03:51 +02005117 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, NULL);
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005118 if (rc < 1) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005119 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005120 return NULL;
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005121 } else if (rc < (signed)strlen(ident_name)) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005122 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[rc], &ident_name[rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005123 return NULL;
5124 }
Radek Krejcif32c5f62016-12-05 09:27:38 +01005125 if (!mod_name) {
5126 /* no prefix, identity must be defined in the same module as node */
Radek Krejci639491e2016-12-05 13:30:42 +01005127 mod_name = lys_main_module(node->schema->module)->name;
Radek Krejcif32c5f62016-12-05 09:27:38 +01005128 mod_name_len = strlen(mod_name);
5129 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02005130
Michal Vaskof2d43962016-09-02 11:10:16 +02005131 /* go through all the bases in all the derived types */
5132 while (type->der) {
5133 for (i = 0; i < type->info.ident.count; ++i) {
5134 cur = type->info.ident.ref[i];
Radek Krejci639491e2016-12-05 13:30:42 +01005135 mod_name_iter = lys_main_module(cur->module)->name;
Radek Krejcif32c5f62016-12-05 09:27:38 +01005136 if (!strcmp(cur->name, name) &&
Radek Krejci639491e2016-12-05 13:30:42 +01005137 !strncmp(mod_name_iter, mod_name, mod_name_len) && !mod_name_iter[mod_name_len]) {
Michal Vaskof2d43962016-09-02 11:10:16 +02005138 goto match;
5139 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02005140
Radek Krejci85a54be2016-10-20 12:39:56 +02005141 if (cur->der) {
5142 /* there are also some derived identities */
5143 for (u = 0; u < cur->der->number; u++) {
5144 der = (struct lys_ident *)cur->der->set.g[u]; /* shortcut */
Radek Krejci639491e2016-12-05 13:30:42 +01005145 mod_name_iter = lys_main_module(der->module)->name;
Radek Krejci85a54be2016-10-20 12:39:56 +02005146 if (!strcmp(der->name, name) &&
Radek Krejci639491e2016-12-05 13:30:42 +01005147 !strncmp(mod_name_iter, mod_name, mod_name_len) && !mod_name_iter[mod_name_len]) {
Radek Krejci85a54be2016-10-20 12:39:56 +02005148 /* we have match */
5149 cur = der;
5150 goto match;
5151 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005152 }
5153 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005154 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005155 type = &type->der->type;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005156 }
5157
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005158 LOGVAL(LYE_INRESOLV, LY_VLOG_LYD, node, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005159 return NULL;
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005160
5161match:
Michal Vaskof2d43962016-09-02 11:10:16 +02005162 for (i = 0; i < cur->iffeature_size; i++) {
5163 if (!resolve_iffeature(&cur->iffeature[i])) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005164 LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, cur->name, node->schema->name);
5165 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, "Identity \"%s\" is disabled by its if-feature condition.", cur->name);
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005166 return NULL;
5167 }
5168 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005169 return cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005170}
5171
Michal Vasko730dfdf2015-08-11 14:48:05 +02005172/**
Michal Vaskobb211122015-08-19 14:03:11 +02005173 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005174 *
Michal Vaskobb211122015-08-19 14:03:11 +02005175 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005176 * @param[in] unres Specific unres item.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005177 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005178 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005179 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005180static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005181resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005182{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005183 int rc;
Radek Krejci010e54b2016-03-15 09:40:34 +01005184 struct lys_node *par_grp;
Michal Vaskoe91afce2015-08-12 12:21:00 +02005185
Radek Krejci010e54b2016-03-15 09:40:34 +01005186 /* HACK: when a grouping has uses inside, all such uses have to be resolved before the grouping itself
5187 * is used in some uses. When we see such a uses, the grouping's nacm member (not used in grouping)
5188 * is used to store number of so far unresolved uses. The grouping cannot be used unless the nacm
5189 * value is decreased back to 0. To remember that the uses already increased grouping's nacm, the
5190 * LYS_USESGRP flag is used. */
Michal Vaskodcf98e62016-05-05 17:53:53 +02005191 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 +02005192
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005193 if (!uses->grp) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01005194 rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
5195 if (rc == -1) {
Michal Vasko92981a62016-10-14 10:25:16 +02005196 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005197 return -1;
5198 } else if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005199 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005200 return -1;
5201 } else if (!uses->grp) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005202 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005203 /* hack - in contrast to lys_node, lys_node_grp has bigger nacm field
5204 * (and smaller flags - it uses only a limited set of flags)
5205 */
5206 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci010e54b2016-03-15 09:40:34 +01005207 uses->flags |= LYS_USESGRP;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005208 }
Michal Vasko92981a62016-10-14 10:25:16 +02005209 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005210 return EXIT_FAILURE;
Michal Vasko12e30842015-08-04 11:54:00 +02005211 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005212 }
5213
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005214 if (uses->grp->nacm) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005215 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005216 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci010e54b2016-03-15 09:40:34 +01005217 uses->flags |= LYS_USESGRP;
Radek Krejcie00d2312016-08-12 15:27:49 +02005218 } else {
5219 /* instantiate grouping only when it is completely resolved */
5220 uses->grp = NULL;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005221 }
Michal Vasko92981a62016-10-14 10:25:16 +02005222 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005223 return EXIT_FAILURE;
5224 }
5225
Radek Krejci48464ed2016-03-17 15:44:09 +01005226 rc = resolve_uses(uses, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005227 if (!rc) {
5228 /* decrease unres count only if not first try */
Radek Krejci010e54b2016-03-15 09:40:34 +01005229 if (par_grp && (uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005230 if (!((struct lys_node_grp *)par_grp)->nacm) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005231 LOGINT;
5232 return -1;
5233 }
Radek Krejci4372b4e2016-04-14 17:42:16 +02005234 ((struct lys_node_grp *)par_grp)->nacm--;
Radek Krejci010e54b2016-03-15 09:40:34 +01005235 uses->flags &= ~LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005236 }
Radek Krejcicf509982015-12-15 09:22:44 +01005237
5238 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005239 if (lyp_check_status(uses->flags, uses->module, "of uses",
Radek Krejciadb57612016-02-16 13:34:34 +01005240 uses->grp->flags, uses->grp->module, uses->grp->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005241 (struct lys_node *)uses)) {
Radek Krejcicf509982015-12-15 09:22:44 +01005242 return -1;
5243 }
5244
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005245 return EXIT_SUCCESS;
5246 }
5247
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005248 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005249}
5250
Michal Vasko730dfdf2015-08-11 14:48:05 +02005251/**
Michal Vasko9957e592015-08-17 15:04:09 +02005252 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005253 *
Michal Vaskobb211122015-08-19 14:03:11 +02005254 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005255 * @param[in] keys_str Keys node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005256 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005257 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005258 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005259static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005260resolve_list_keys(struct lys_node_list *list, const char *keys_str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005261{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005262 int i, len, rc;
Michal Vasko4f0dad02016-02-15 14:08:23 +01005263 const char *value;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005264
5265 for (i = 0; i < list->keys_size; ++i) {
Radek Krejci5c08a992016-11-02 13:30:04 +01005266 if (!list->child) {
5267 /* no child, possible forward reference */
5268 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
5269 return EXIT_FAILURE;
5270 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005271 /* get the key name */
5272 if ((value = strpbrk(keys_str, " \t\n"))) {
5273 len = value - keys_str;
5274 while (isspace(value[0])) {
5275 value++;
5276 }
5277 } else {
5278 len = strlen(keys_str);
5279 }
5280
Radek Krejcic4283442016-04-22 09:19:27 +02005281 rc = lys_get_sibling(list->child, lys_main_module(list->module)->name, 0, keys_str, len, LYS_LEAF, (const struct lys_node **)&list->keys[i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005282 if (rc) {
Michal Vasko7a55bea2016-05-02 14:51:20 +02005283 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
5284 return EXIT_FAILURE;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005285 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005286
Radek Krejci48464ed2016-03-17 15:44:09 +01005287 if (check_key(list, i, keys_str, len)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005288 /* check_key logs */
5289 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005290 }
5291
Radek Krejcicf509982015-12-15 09:22:44 +01005292 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005293 if (lyp_check_status(list->flags, list->module, list->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005294 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
5295 (struct lys_node *)list->keys[i])) {
Radek Krejcicf509982015-12-15 09:22:44 +01005296 return -1;
5297 }
5298
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005299 /* prepare for next iteration */
5300 while (value && isspace(value[0])) {
5301 value++;
5302 }
5303 keys_str = value;
5304 }
5305
Michal Vaskof02e3742015-08-05 16:27:02 +02005306 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005307}
5308
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005309/**
Michal Vaskobf19d252015-10-08 15:39:17 +02005310 * @brief Resolve (check) all must conditions of \p node.
5311 * Logs directly.
5312 *
5313 * @param[in] node Data node with optional must statements.
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005314 * @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 +02005315 *
5316 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
5317 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005318static int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005319resolve_must(struct lyd_node *node, int inout_parent, int ignore_fail)
Michal Vaskof02e3742015-08-05 16:27:02 +02005320{
Michal Vaskobf19d252015-10-08 15:39:17 +02005321 uint8_t i, must_size;
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005322 struct lys_node *schema;
Michal Vaskobf19d252015-10-08 15:39:17 +02005323 struct lys_restr *must;
5324 struct lyxp_set set;
5325
5326 assert(node);
5327 memset(&set, 0, sizeof set);
5328
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005329 if (inout_parent) {
5330 for (schema = lys_parent(node->schema);
5331 schema && (schema->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES));
5332 schema = lys_parent(schema));
5333 if (!schema || !(schema->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5334 LOGINT;
5335 return -1;
5336 }
5337 must_size = ((struct lys_node_inout *)schema)->must_size;
5338 must = ((struct lys_node_inout *)schema)->must;
5339
5340 /* context node is the RPC/action */
5341 node = node->parent;
5342 if (!(node->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
5343 LOGINT;
5344 return -1;
5345 }
5346 } else {
5347 switch (node->schema->nodetype) {
5348 case LYS_CONTAINER:
5349 must_size = ((struct lys_node_container *)node->schema)->must_size;
5350 must = ((struct lys_node_container *)node->schema)->must;
5351 break;
5352 case LYS_LEAF:
5353 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
5354 must = ((struct lys_node_leaf *)node->schema)->must;
5355 break;
5356 case LYS_LEAFLIST:
5357 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
5358 must = ((struct lys_node_leaflist *)node->schema)->must;
5359 break;
5360 case LYS_LIST:
5361 must_size = ((struct lys_node_list *)node->schema)->must_size;
5362 must = ((struct lys_node_list *)node->schema)->must;
5363 break;
5364 case LYS_ANYXML:
5365 case LYS_ANYDATA:
5366 must_size = ((struct lys_node_anydata *)node->schema)->must_size;
5367 must = ((struct lys_node_anydata *)node->schema)->must;
5368 break;
5369 case LYS_NOTIF:
5370 must_size = ((struct lys_node_notif *)node->schema)->must_size;
5371 must = ((struct lys_node_notif *)node->schema)->must;
5372 break;
5373 default:
5374 must_size = 0;
5375 break;
5376 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005377 }
5378
5379 for (i = 0; i < must_size; ++i) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005380 if (lyxp_eval(must[i].expr, node, LYXP_NODE_ELEM, lyd_node_module(node), &set, LYXP_MUST)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02005381 return -1;
5382 }
5383
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005384 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_MUST);
Michal Vaskobf19d252015-10-08 15:39:17 +02005385
Michal Vasko8146d4c2016-05-09 15:50:29 +02005386 if (!set.val.bool) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005387 if (ignore_fail) {
5388 LOGVRB("Must condition \"%s\" not satisfied, but it is not required.", must[i].expr);
5389 } else {
5390 LOGVAL(LYE_NOMUST, LY_VLOG_LYD, node, must[i].expr);
5391 if (must[i].emsg) {
5392 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, must[i].emsg);
5393 }
5394 if (must[i].eapptag) {
5395 strncpy(((struct ly_err *)&ly_errno)->apptag, must[i].eapptag, LY_APPTAG_LEN - 1);
5396 }
5397 return 1;
Michal Vasko6ac68282016-04-11 10:56:47 +02005398 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005399 }
5400 }
5401
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005402 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02005403}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005404
Michal Vaskobf19d252015-10-08 15:39:17 +02005405/**
Michal Vasko508a50d2016-09-07 14:50:33 +02005406 * @brief Resolve (find) when condition schema context node. Does not log.
5407 *
5408 * @param[in] schema Schema node with the when condition.
5409 * @param[out] ctx_snode When schema context node.
5410 * @param[out] ctx_snode_type Schema context node type.
5411 */
5412void
5413resolve_when_ctx_snode(const struct lys_node *schema, struct lys_node **ctx_snode, enum lyxp_node_type *ctx_snode_type)
5414{
5415 const struct lys_node *sparent;
5416
5417 /* find a not schema-only node */
5418 *ctx_snode_type = LYXP_NODE_ELEM;
5419 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
5420 if (schema->nodetype == LYS_AUGMENT) {
5421 sparent = ((struct lys_node_augment *)schema)->target;
5422 } else {
5423 sparent = schema->parent;
5424 }
5425 if (!sparent) {
5426 /* context node is the document root (fake root in our case) */
5427 if (schema->flags & LYS_CONFIG_W) {
5428 *ctx_snode_type = LYXP_NODE_ROOT_CONFIG;
5429 } else {
Michal Vaskob94a5e42016-09-08 14:01:56 +02005430 *ctx_snode_type = LYXP_NODE_ROOT;
Michal Vasko508a50d2016-09-07 14:50:33 +02005431 }
Michal Vasko2d2aec12016-09-08 11:42:50 +02005432 /* we need the first top-level sibling, but no uses or groupings */
Michal Vaskob94a5e42016-09-08 14:01:56 +02005433 schema = lys_getnext(NULL, NULL, lys_node_module(schema), 0);
Michal Vasko508a50d2016-09-07 14:50:33 +02005434 break;
5435 }
5436 schema = sparent;
5437 }
5438
5439 *ctx_snode = (struct lys_node *)schema;
5440}
5441
5442/**
Michal Vaskocf024702015-10-08 15:01:42 +02005443 * @brief Resolve (find) when condition context node. Does not log.
5444 *
5445 * @param[in] node Data node, whose conditional definition is being decided.
Michal Vasko508a50d2016-09-07 14:50:33 +02005446 * @param[in] schema Schema node with the when condition.
Michal Vaskoa59495d2016-08-22 09:18:58 +02005447 * @param[out] ctx_node Context node.
5448 * @param[out] ctx_node_type Context node type.
Michal Vaskocf024702015-10-08 15:01:42 +02005449 *
Michal Vaskoa59495d2016-08-22 09:18:58 +02005450 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vaskocf024702015-10-08 15:01:42 +02005451 */
Michal Vaskoa59495d2016-08-22 09:18:58 +02005452static int
5453resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema, struct lyd_node **ctx_node,
5454 enum lyxp_node_type *ctx_node_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005455{
Michal Vaskocf024702015-10-08 15:01:42 +02005456 struct lyd_node *parent;
5457 struct lys_node *sparent;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005458 enum lyxp_node_type node_type;
Michal Vaskocf024702015-10-08 15:01:42 +02005459 uint16_t i, data_depth, schema_depth;
5460
Michal Vasko508a50d2016-09-07 14:50:33 +02005461 resolve_when_ctx_snode(schema, &schema, &node_type);
Michal Vaskocf024702015-10-08 15:01:42 +02005462
Michal Vaskofe989752016-09-08 08:47:26 +02005463 if (node_type == LYXP_NODE_ELEM) {
5464 /* standard element context node */
5465 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
5466 for (sparent = schema, schema_depth = 0;
5467 sparent;
5468 sparent = (sparent->nodetype == LYS_AUGMENT ? ((struct lys_node_augment *)sparent)->target : sparent->parent)) {
5469 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_NOTIF | LYS_RPC)) {
5470 ++schema_depth;
5471 }
Michal Vaskocf024702015-10-08 15:01:42 +02005472 }
Michal Vaskofe989752016-09-08 08:47:26 +02005473 if (data_depth < schema_depth) {
5474 return -1;
5475 }
Michal Vaskocf024702015-10-08 15:01:42 +02005476
Michal Vasko956e8542016-08-26 09:43:35 +02005477 /* find the corresponding data node */
5478 for (i = 0; i < data_depth - schema_depth; ++i) {
5479 node = node->parent;
5480 }
Michal Vaskoa59495d2016-08-22 09:18:58 +02005481 if (node->schema != schema) {
5482 return -1;
5483 }
Michal Vaskofe989752016-09-08 08:47:26 +02005484 } else {
5485 /* root context node */
5486 while (node->parent) {
5487 node = node->parent;
5488 }
5489 while (node->prev->next) {
5490 node = node->prev;
5491 }
Michal Vaskocf024702015-10-08 15:01:42 +02005492 }
5493
Michal Vaskoa59495d2016-08-22 09:18:58 +02005494 *ctx_node = node;
5495 *ctx_node_type = node_type;
5496 return EXIT_SUCCESS;
Michal Vaskocf024702015-10-08 15:01:42 +02005497}
5498
Michal Vasko76c3bd32016-08-24 16:02:52 +02005499/**
5500 * @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 +01005501 * The context node is adjusted if needed.
Michal Vasko76c3bd32016-08-24 16:02:52 +02005502 *
5503 * @param[in] snode Schema node, whose children instances need to be unlinked.
5504 * @param[in,out] node Data siblings where to look for the children of \p snode. If it is unlinked,
5505 * it is moved to point to another sibling still in the original tree.
5506 * @param[in,out] ctx_node When context node, adjusted if needed.
5507 * @param[in] ctx_node_type Context node type, just for information to detect invalid situations.
5508 * @param[out] unlinked_nodes Unlinked siblings. Can be safely appended to \p node afterwards.
5509 * Ordering may change, but there will be no semantic change.
5510 *
5511 * @return EXIT_SUCCESS on success, -1 on error.
5512 */
5513static int
5514resolve_when_unlink_nodes(struct lys_node *snode, struct lyd_node **node, struct lyd_node **ctx_node,
5515 enum lyxp_node_type ctx_node_type, struct lyd_node **unlinked_nodes)
5516{
5517 struct lyd_node *next, *elem;
5518
5519 switch (snode->nodetype) {
5520 case LYS_AUGMENT:
5521 case LYS_USES:
5522 case LYS_CHOICE:
5523 case LYS_CASE:
5524 LY_TREE_FOR(snode->child, snode) {
5525 if (resolve_when_unlink_nodes(snode, node, ctx_node, ctx_node_type, unlinked_nodes)) {
5526 return -1;
5527 }
5528 }
5529 break;
5530 case LYS_CONTAINER:
5531 case LYS_LIST:
5532 case LYS_LEAF:
5533 case LYS_LEAFLIST:
5534 case LYS_ANYXML:
5535 case LYS_ANYDATA:
5536 LY_TREE_FOR_SAFE(lyd_first_sibling(*node), next, elem) {
5537 if (elem->schema == snode) {
5538
5539 if (elem == *ctx_node) {
5540 /* We are going to unlink our context node! This normally cannot happen,
5541 * but we use normal top-level data nodes for faking a document root node,
5542 * so if this is the context node, we just use the next top-level node.
5543 * Additionally, it can even happen that there are no top-level data nodes left,
5544 * all were unlinked, so in this case we pass NULL as the context node/data tree,
5545 * lyxp_eval() can handle this special situation.
5546 */
5547 if (ctx_node_type == LYXP_NODE_ELEM) {
5548 LOGINT;
5549 return -1;
5550 }
5551
5552 if (elem->prev == elem) {
5553 /* unlinking last top-level element, use an empty data tree */
5554 *ctx_node = NULL;
5555 } else {
5556 /* in this case just use the previous/last top-level data node */
5557 *ctx_node = elem->prev;
5558 }
5559 } else if (elem == *node) {
5560 /* We are going to unlink the currently processed node. This does not matter that
5561 * much, but we would lose access to the original data tree, so just move our
5562 * pointer somewhere still inside it.
5563 */
5564 if ((*node)->prev != *node) {
5565 *node = (*node)->prev;
5566 } else {
5567 /* the processed node with sibings were all unlinked, oh well */
5568 *node = NULL;
5569 }
5570 }
5571
5572 /* temporarily unlink the node */
5573 lyd_unlink(elem);
5574 if (*unlinked_nodes) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005575 if (lyd_insert_after((*unlinked_nodes)->prev, elem)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005576 LOGINT;
5577 return -1;
5578 }
5579 } else {
5580 *unlinked_nodes = elem;
5581 }
5582
5583 if (snode->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_ANYDATA)) {
5584 /* there can be only one instance */
5585 break;
5586 }
5587 }
5588 }
5589 break;
5590 default:
5591 LOGINT;
5592 return -1;
5593 }
5594
5595 return EXIT_SUCCESS;
5596}
5597
5598/**
5599 * @brief Relink the unlinked nodes back.
5600 *
5601 * @param[in] node Data node to link the nodes back to. It can actually be the adjusted context node,
5602 * we simply need a sibling from the original data tree.
5603 * @param[in] unlinked_nodes Unlinked nodes to relink to \p node.
5604 * @param[in] ctx_node_type Context node type to distinguish between \p node being the parent
5605 * or the sibling of \p unlinked_nodes.
5606 *
5607 * @return EXIT_SUCCESS on success, -1 on error.
5608 */
5609static int
5610resolve_when_relink_nodes(struct lyd_node *node, struct lyd_node *unlinked_nodes, enum lyxp_node_type ctx_node_type)
5611{
5612 struct lyd_node *elem;
5613
5614 LY_TREE_FOR_SAFE(unlinked_nodes, unlinked_nodes, elem) {
Michal Vaskode1feeb2016-12-20 14:48:42 +01005615 lyd_unlink(elem);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005616 if (ctx_node_type == LYXP_NODE_ELEM) {
5617 if (lyd_insert(node, elem)) {
5618 return -1;
5619 }
5620 } else {
5621 if (lyd_insert_after(node, elem)) {
5622 return -1;
5623 }
5624 }
5625 }
5626
5627 return EXIT_SUCCESS;
5628}
5629
Radek Krejci03b71f72016-03-16 11:10:09 +01005630int
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005631resolve_applies_must(const struct lyd_node *node)
Radek Krejci01696bf2016-03-18 13:19:36 +01005632{
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005633 int ret = 0;
5634 uint8_t must_size;
5635 struct lys_node *schema, *iter;
Radek Krejci46165822016-08-26 14:06:27 +02005636
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005637 assert(node);
5638
5639 schema = node->schema;
5640
5641 /* their own must */
Radek Krejci46165822016-08-26 14:06:27 +02005642 switch (schema->nodetype) {
Radek Krejci01696bf2016-03-18 13:19:36 +01005643 case LYS_CONTAINER:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005644 must_size = ((struct lys_node_container *)schema)->must_size;
5645 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005646 case LYS_LEAF:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005647 must_size = ((struct lys_node_leaf *)schema)->must_size;
5648 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005649 case LYS_LEAFLIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005650 must_size = ((struct lys_node_leaflist *)schema)->must_size;
5651 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005652 case LYS_LIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005653 must_size = ((struct lys_node_list *)schema)->must_size;
5654 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005655 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02005656 case LYS_ANYDATA:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005657 must_size = ((struct lys_node_anydata *)schema)->must_size;
5658 break;
5659 case LYS_NOTIF:
5660 must_size = ((struct lys_node_notif *)schema)->must_size;
5661 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005662 default:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005663 must_size = 0;
5664 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005665 }
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005666
5667 if (must_size) {
5668 ++ret;
5669 }
5670
5671 /* schema may be a direct data child of input/output with must (but it must be first, it needs to be evaluated only once) */
5672 if (!node->prev->next) {
5673 for (iter = lys_parent(schema); iter && (iter->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES)); iter = lys_parent(iter));
5674 if (iter && (iter->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5675 ret += 0x2;
5676 }
5677 }
5678
5679 return ret;
Radek Krejci01696bf2016-03-18 13:19:36 +01005680}
5681
5682int
Radek Krejci46165822016-08-26 14:06:27 +02005683resolve_applies_when(const struct lys_node *schema, int mode, const struct lys_node *stop)
Radek Krejci03b71f72016-03-16 11:10:09 +01005684{
Radek Krejci46165822016-08-26 14:06:27 +02005685 const struct lys_node *parent;
Radek Krejci03b71f72016-03-16 11:10:09 +01005686
Radek Krejci46165822016-08-26 14:06:27 +02005687 assert(schema);
Radek Krejci03b71f72016-03-16 11:10:09 +01005688
Radek Krejci46165822016-08-26 14:06:27 +02005689 if (!(schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)schema)->when)) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005690 return 1;
5691 }
5692
Radek Krejci46165822016-08-26 14:06:27 +02005693 parent = schema;
Radek Krejci03b71f72016-03-16 11:10:09 +01005694 goto check_augment;
5695
Radek Krejci46165822016-08-26 14:06:27 +02005696 while (parent) {
5697 /* stop conditions */
5698 if (!mode) {
5699 /* stop on node that can be instantiated in data tree */
5700 if (!(parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
5701 break;
5702 }
5703 } else {
5704 /* stop on the specified node */
5705 if (parent == stop) {
5706 break;
5707 }
5708 }
5709
5710 if (((const struct lys_node_uses *)parent)->when) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005711 return 1;
5712 }
5713check_augment:
5714
5715 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) &&
Radek Krejci46165822016-08-26 14:06:27 +02005716 (((const struct lys_node_augment *)parent->parent)->when))) {
Michal Vaskoe3655562016-08-24 15:56:17 +02005717 return 1;
Radek Krejci03b71f72016-03-16 11:10:09 +01005718 }
5719 parent = lys_parent(parent);
5720 }
5721
5722 return 0;
5723}
5724
Michal Vaskocf024702015-10-08 15:01:42 +02005725/**
5726 * @brief Resolve (check) all when conditions relevant for \p node.
5727 * Logs directly.
5728 *
5729 * @param[in] node Data node, whose conditional reference, if such, is being decided.
Michal Vaskocf024702015-10-08 15:01:42 +02005730 *
Radek Krejci03b71f72016-03-16 11:10:09 +01005731 * @return
5732 * -1 - error, ly_errno is set
5733 * 0 - true "when" statement
Radek Krejci46165822016-08-26 14:06:27 +02005734 * 0, ly_vecode = LYVE_NOWHEN - false "when" statement
Radek Krejci03b71f72016-03-16 11:10:09 +01005735 * 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 +02005736 */
Radek Krejci46165822016-08-26 14:06:27 +02005737int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005738resolve_when(struct lyd_node *node, int *result, int ignore_fail)
Michal Vaskocf024702015-10-08 15:01:42 +02005739{
Michal Vasko76c3bd32016-08-24 16:02:52 +02005740 struct lyd_node *ctx_node = NULL, *unlinked_nodes, *tmp_node;
Michal Vasko90fc2a32016-08-24 15:58:58 +02005741 struct lys_node *sparent;
Michal Vaskocf024702015-10-08 15:01:42 +02005742 struct lyxp_set set;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005743 enum lyxp_node_type ctx_node_type;
Radek Krejci51093642016-03-29 10:14:59 +02005744 int rc = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02005745
5746 assert(node);
5747 memset(&set, 0, sizeof set);
5748
5749 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)node->schema)->when)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005750 /* make the node dummy for the evaluation */
5751 node->validity |= LYD_VAL_INUSE;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005752 rc = lyxp_eval(((struct lys_node_container *)node->schema)->when->cond, node, LYXP_NODE_ELEM, lyd_node_module(node),
5753 &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005754 node->validity &= ~LYD_VAL_INUSE;
Radek Krejci03b71f72016-03-16 11:10:09 +01005755 if (rc) {
5756 if (rc == 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005757 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005758 }
Radek Krejci51093642016-03-29 10:14:59 +02005759 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005760 }
5761
Radek Krejci03b71f72016-03-16 11:10:09 +01005762 /* set boolean result of the condition */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005763 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02005764 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01005765 node->when_status |= LYD_WHEN_FALSE;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005766 if (ignore_fail) {
5767 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
5768 ((struct lys_node_container *)node->schema)->when->cond);
5769 } else {
5770 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
5771 goto cleanup;
5772 }
Michal Vaskocf024702015-10-08 15:01:42 +02005773 }
Radek Krejci51093642016-03-29 10:14:59 +02005774
5775 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005776 lyxp_set_cast(&set, LYXP_SET_EMPTY, node, lyd_node_module(node), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005777 }
5778
Michal Vasko90fc2a32016-08-24 15:58:58 +02005779 sparent = node->schema;
Michal Vaskocf024702015-10-08 15:01:42 +02005780 goto check_augment;
5781
5782 /* check when in every schema node that affects node */
Michal Vasko90fc2a32016-08-24 15:58:58 +02005783 while (sparent && (sparent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
5784 if (((struct lys_node_uses *)sparent)->when) {
Michal Vaskocf024702015-10-08 15:01:42 +02005785 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005786 rc = resolve_when_ctx_node(node, sparent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02005787 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02005788 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02005789 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005790 }
5791 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02005792
5793 unlinked_nodes = NULL;
5794 /* we do not want our node pointer to change */
5795 tmp_node = node;
5796 rc = resolve_when_unlink_nodes(sparent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
5797 if (rc) {
5798 goto cleanup;
5799 }
5800
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005801 rc = lyxp_eval(((struct lys_node_uses *)sparent)->when->cond, ctx_node, ctx_node_type, lys_node_module(sparent),
5802 &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005803
5804 if (unlinked_nodes && ctx_node) {
5805 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
5806 rc = -1;
5807 goto cleanup;
5808 }
5809 }
5810
Radek Krejci03b71f72016-03-16 11:10:09 +01005811 if (rc) {
5812 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005813 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005814 }
Radek Krejci51093642016-03-29 10:14:59 +02005815 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005816 }
5817
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005818 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02005819 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01005820 node->when_status |= LYD_WHEN_FALSE;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005821 if (ignore_fail) {
5822 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
5823 ((struct lys_node_uses *)sparent)->when->cond);
5824 } else {
5825 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
5826 goto cleanup;
5827 }
Michal Vaskocf024702015-10-08 15:01:42 +02005828 }
Radek Krejci51093642016-03-29 10:14:59 +02005829
5830 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005831 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005832 }
5833
5834check_augment:
Michal Vasko90fc2a32016-08-24 15:58:58 +02005835 if ((sparent->parent && (sparent->parent->nodetype == LYS_AUGMENT) && (((struct lys_node_augment *)sparent->parent)->when))) {
Michal Vaskocf024702015-10-08 15:01:42 +02005836 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005837 rc = resolve_when_ctx_node(node, sparent->parent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02005838 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02005839 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02005840 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005841 }
5842 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02005843
5844 unlinked_nodes = NULL;
5845 tmp_node = node;
5846 rc = resolve_when_unlink_nodes(sparent->parent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
5847 if (rc) {
5848 goto cleanup;
5849 }
5850
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005851 rc = lyxp_eval(((struct lys_node_augment *)sparent->parent)->when->cond, ctx_node, ctx_node_type,
5852 lys_node_module(sparent->parent), &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005853
5854 /* reconnect nodes, if ctx_node is NULL then all the nodes were unlinked, but linked together,
5855 * so the tree did not actually change and there is nothing for us to do
5856 */
5857 if (unlinked_nodes && ctx_node) {
5858 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
5859 rc = -1;
5860 goto cleanup;
5861 }
5862 }
5863
Radek Krejci03b71f72016-03-16 11:10:09 +01005864 if (rc) {
5865 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005866 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005867 }
Radek Krejci51093642016-03-29 10:14:59 +02005868 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005869 }
5870
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005871 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent->parent), LYXP_WHEN);
Michal Vaskocf024702015-10-08 15:01:42 +02005872
Michal Vasko8146d4c2016-05-09 15:50:29 +02005873 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01005874 node->when_status |= LYD_WHEN_FALSE;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005875 if (ignore_fail) {
5876 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
5877 ((struct lys_node_augment *)sparent->parent)->when->cond);
5878 } else {
5879 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
5880 goto cleanup;
5881 }
Michal Vaskocf024702015-10-08 15:01:42 +02005882 }
Radek Krejci51093642016-03-29 10:14:59 +02005883
5884 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005885 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent->parent), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005886 }
5887
Michal Vasko90fc2a32016-08-24 15:58:58 +02005888 sparent = lys_parent(sparent);
Michal Vaskocf024702015-10-08 15:01:42 +02005889 }
5890
Radek Krejci0b7704f2016-03-18 12:16:14 +01005891 node->when_status |= LYD_WHEN_TRUE;
Radek Krejci03b71f72016-03-16 11:10:09 +01005892
Radek Krejci51093642016-03-29 10:14:59 +02005893cleanup:
Radek Krejci51093642016-03-29 10:14:59 +02005894 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005895 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node ? ctx_node : node, NULL, 0);
Radek Krejci51093642016-03-29 10:14:59 +02005896
Radek Krejci46165822016-08-26 14:06:27 +02005897 if (result) {
5898 if (node->when_status & LYD_WHEN_TRUE) {
5899 *result = 1;
5900 } else {
5901 *result = 0;
5902 }
5903 }
5904
Radek Krejci51093642016-03-29 10:14:59 +02005905 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005906}
5907
Radek Krejcicbb473e2016-09-16 14:48:32 +02005908static int
5909check_leafref_features(struct lys_type *type)
5910{
5911 struct lys_node *iter;
5912 struct ly_set *src_parents, *trg_parents, *features;
5913 unsigned int i, j, size, x;
5914 int ret = EXIT_SUCCESS;
5915
5916 assert(type->parent);
5917
5918 src_parents = ly_set_new();
5919 trg_parents = ly_set_new();
5920 features = ly_set_new();
5921
5922 /* get parents chain of source (leafref) */
5923 for (iter = (struct lys_node *)type->parent; iter; iter = iter->parent) {
5924 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
5925 continue;
5926 }
5927 ly_set_add(src_parents, iter, LY_SET_OPT_USEASLIST);
5928 }
5929 /* get parents chain of target */
5930 for (iter = (struct lys_node *)type->info.lref.target; iter; iter = iter->parent) {
5931 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
5932 continue;
5933 }
5934 ly_set_add(trg_parents, iter, LY_SET_OPT_USEASLIST);
5935 }
5936
5937 /* compare the features used in if-feature statements in the rest of both
5938 * chains of parents. The set of features used for target must be a subset
5939 * of features used for the leafref. This is not a perfect, we should compare
5940 * the truth tables but it could require too much resources, so we simplify that */
5941 for (i = 0; i < src_parents->number; i++) {
5942 iter = src_parents->set.s[i]; /* shortcut */
5943 if (!iter->iffeature_size) {
5944 continue;
5945 }
5946 for (j = 0; j < iter->iffeature_size; j++) {
5947 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
5948 for (; size; size--) {
5949 if (!iter->iffeature[j].features[size - 1]) {
5950 /* not yet resolved feature, postpone this check */
5951 ret = EXIT_FAILURE;
5952 goto cleanup;
5953 }
5954 ly_set_add(features, iter->iffeature[j].features[size - 1], 0);
5955 }
5956 }
5957 }
5958 x = features->number;
5959 for (i = 0; i < trg_parents->number; i++) {
5960 iter = trg_parents->set.s[i]; /* shortcut */
5961 if (!iter->iffeature_size) {
5962 continue;
5963 }
5964 for (j = 0; j < iter->iffeature_size; j++) {
5965 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
5966 for (; size; size--) {
5967 if (!iter->iffeature[j].features[size - 1]) {
5968 /* not yet resolved feature, postpone this check */
5969 ret = EXIT_FAILURE;
5970 goto cleanup;
5971 }
5972 if ((unsigned int)ly_set_add(features, iter->iffeature[j].features[size - 1], 0) >= x) {
5973 /* the feature is not present in features set of target's parents chain */
5974 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, type->parent, "leafref", type->info.lref.path);
5975 LOGVAL(LYE_SPEC, LY_VLOG_LYS, type->parent,
5976 "Leafref is not conditional based on \"%s\" feature as its target.",
5977 iter->iffeature[j].features[size - 1]->name);
5978 ret = -1;
5979 goto cleanup;
5980 }
5981 }
5982 }
5983 }
5984
5985cleanup:
5986 ly_set_free(features);
5987 ly_set_free(src_parents);
5988 ly_set_free(trg_parents);
5989
5990 return ret;
5991}
5992
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005993/**
Michal Vaskobb211122015-08-19 14:03:11 +02005994 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005995 *
5996 * @param[in] mod Main module.
5997 * @param[in] item Item to resolve. Type determined by \p type.
5998 * @param[in] type Type of the unresolved item.
5999 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02006000 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006001 *
6002 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
6003 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006004static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006005resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Radek Krejci48464ed2016-03-17 15:44:09 +01006006 struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006007{
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006008 /* has_str - whether the str_snode is a string in a dictionary that needs to be freed */
Radek Krejcic79c6b12016-07-26 15:11:49 +02006009 int rc = -1, has_str = 0, tpdf_flag = 0, i, k;
6010 unsigned int j;
Radek Krejcic13db382016-08-16 10:52:42 +02006011 struct lys_node *node, *par_grp;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006012 const char *expr;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006013
Radek Krejcic79c6b12016-07-26 15:11:49 +02006014 struct ly_set *refs, *procs;
6015 struct lys_feature *ref, *feat;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006016 struct lys_ident *ident;
6017 struct lys_type *stype;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006018 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01006019 struct lyxml_elem *yin;
Pavol Vicana0e4e672016-02-24 12:20:04 +01006020 struct yang_type *yang;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006021 struct unres_list_uniq *unique_info;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006022 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006023
6024 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006025 case UNRES_IDENT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006026 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006027 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006028 ident = item;
6029
Radek Krejci018f1f52016-08-03 16:01:20 +02006030 rc = resolve_base_ident(mod, ident, expr, "identity", NULL, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006031 break;
6032 case UNRES_TYPE_IDENTREF:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006033 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006034 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006035 stype = item;
6036
Radek Krejci018f1f52016-08-03 16:01:20 +02006037 rc = resolve_base_ident(mod, NULL, expr, "type", stype, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006038 break;
6039 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02006040 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006041 stype = item;
6042
Radek Krejci2f12f852016-01-08 12:59:57 +01006043 /* HACK - when there is no parent, we are in top level typedef and in that
6044 * case, the path has to contain absolute path, so we let the resolve_path_arg_schema()
6045 * know it via tpdf_flag */
6046 if (!node) {
Radek Krejci4f78b532016-02-17 13:43:00 +01006047 tpdf_flag = 1;
Radek Krejci2f12f852016-01-08 12:59:57 +01006048 node = (struct lys_node *)stype->parent;
6049 }
6050
Radek Krejci27fe55e2016-09-13 17:13:35 +02006051 if (!lys_node_module(node)->implemented) {
6052 /* not implemented module, don't bother with resolving the leafref
Radek Krejci990af1f2016-11-09 13:53:36 +01006053 * if the module is set to be implemented, the path will be resolved then */
Radek Krejci27fe55e2016-09-13 17:13:35 +02006054 rc = 0;
6055 break;
6056 }
Radek Krejci48464ed2016-03-17 15:44:09 +01006057 rc = resolve_path_arg_schema(stype->info.lref.path, node, tpdf_flag,
Michal Vasko1e62a092015-12-01 12:27:20 +01006058 (const struct lys_node **)&stype->info.lref.target);
Michal Vasko01c6fd22016-05-20 11:43:05 +02006059 if (!tpdf_flag && !rc) {
6060 assert(stype->info.lref.target);
Radek Krejcicbb473e2016-09-16 14:48:32 +02006061 /* check if leafref and its target are under a common if-features */
6062 rc = check_leafref_features(stype);
6063 if (rc) {
6064 break;
6065 }
6066
Radek Krejci46c4cd72016-01-21 15:13:52 +01006067 /* store the backlink from leafref target */
Michal Vasko01c6fd22016-05-20 11:43:05 +02006068 if (lys_leaf_add_leafref_target(stype->info.lref.target, (struct lys_node *)stype->parent)) {
6069 rc = -1;
Radek Krejci46c4cd72016-01-21 15:13:52 +01006070 }
Radek Krejci46c4cd72016-01-21 15:13:52 +01006071 }
6072
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006073 break;
Radek Krejci3a5501d2016-07-18 22:03:34 +02006074 case UNRES_TYPE_DER_TPDF:
6075 tpdf_flag = 1;
6076 /* no break */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006077 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01006078 /* parent */
6079 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006080 stype = item;
6081
Michal Vasko88c29542015-11-27 14:57:53 +01006082 /* HACK type->der is temporarily unparsed type statement */
6083 yin = (struct lyxml_elem *)stype->der;
6084 stype->der = NULL;
6085
Pavol Vicana0e4e672016-02-24 12:20:04 +01006086 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6087 yang = (struct yang_type *)yin;
Radek Krejci3a5501d2016-07-18 22:03:34 +02006088 rc = yang_check_type(mod, node, yang, tpdf_flag, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006089
6090 if (rc) {
Pavol Vican8bd72e42016-08-29 09:53:05 +02006091 /* may try again later */
6092 stype->der = (struct lys_tpdf *)yang;
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006093 } else {
6094 /* we need to always be able to free this, it's safe only in this case */
Pavol Vican5f0316a2016-04-05 21:21:11 +02006095 lydict_remove(mod->ctx, yang->name);
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006096 free(yang);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006097 }
6098
Michal Vasko88c29542015-11-27 14:57:53 +01006099 } else {
Radek Krejci3a5501d2016-07-18 22:03:34 +02006100 rc = fill_yin_type(mod, node, yin, stype, tpdf_flag, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006101 if (!rc) {
6102 /* we need to always be able to free this, it's safe only in this case */
6103 lyxml_free(mod->ctx, yin);
6104 } else {
6105 /* may try again later, put all back how it was */
6106 stype->der = (struct lys_tpdf *)yin;
6107 }
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006108 }
Radek Krejcic13db382016-08-16 10:52:42 +02006109 if (rc == EXIT_SUCCESS) {
Radek Krejci2c2fce82016-08-01 13:52:26 +02006110 /* it does not make sense to have leaf-list of empty type */
6111 if (!tpdf_flag && node->nodetype == LYS_LEAFLIST && stype->base == LY_TYPE_EMPTY) {
6112 LOGWRN("The leaf-list \"%s\" is of \"empty\" type, which does not make sense.", node->name);
6113 }
Radek Krejci9b6aad22016-09-20 15:55:51 +02006114 } else if (rc == EXIT_FAILURE && stype->base != LY_TYPE_ERR) {
Radek Krejcic13db382016-08-16 10:52:42 +02006115 /* forward reference - in case the type is in grouping, we have to make the grouping unusable
6116 * by uses statement until the type is resolved. We do that the same way as uses statements inside
6117 * grouping - the grouping's nacm member (not used un grouping) is used to increase the number of
6118 * 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 +02006119 * 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 +02006120 * of the type's base member. */
6121 for (par_grp = node; par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
6122 if (par_grp) {
6123 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci9b6aad22016-09-20 15:55:51 +02006124 stype->base = LY_TYPE_ERR;
Radek Krejcic13db382016-08-16 10:52:42 +02006125 }
Radek Krejci2c2fce82016-08-01 13:52:26 +02006126 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006127 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006128 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006129 iff_data = str_snode;
6130 rc = resolve_feature(iff_data->fname, strlen(iff_data->fname), iff_data->node, item);
Radek Krejci9ff0a922016-07-14 13:08:05 +02006131 if (!rc) {
6132 /* success */
Radek Krejci9de2c042016-10-19 16:53:06 +02006133 if (iff_data->infeature) {
6134 /* store backlink into the target feature to allow reverse changes in case of changing feature status */
6135 feat = *((struct lys_feature **)item);
6136 if (!feat->depfeatures) {
6137 feat->depfeatures = ly_set_new();
6138 }
Radek Krejci85a54be2016-10-20 12:39:56 +02006139 ly_set_add(feat->depfeatures, iff_data->node, LY_SET_OPT_USEASLIST);
Radek Krejci9de2c042016-10-19 16:53:06 +02006140 }
6141 /* cleanup temporary data */
Radek Krejcicbb473e2016-09-16 14:48:32 +02006142 lydict_remove(mod->ctx, iff_data->fname);
6143 free(iff_data);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006144 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006145 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006146 case UNRES_FEATURE:
6147 feat = (struct lys_feature *)item;
6148
6149 if (feat->iffeature_size) {
6150 refs = ly_set_new();
6151 procs = ly_set_new();
6152 ly_set_add(procs, feat, 0);
6153
6154 while (procs->number) {
6155 ref = procs->set.g[procs->number - 1];
6156 ly_set_rm_index(procs, procs->number - 1);
6157
6158 for (i = 0; i < ref->iffeature_size; i++) {
6159 resolve_iffeature_getsizes(&ref->iffeature[i], NULL, &j);
6160 for (; j > 0 ; j--) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006161 if (ref->iffeature[i].features[j - 1]) {
Radek Krejcic79c6b12016-07-26 15:11:49 +02006162 if (ref->iffeature[i].features[j - 1] == feat) {
6163 LOGVAL(LYE_CIRC_FEATURES, LY_VLOG_NONE, NULL, feat->name);
6164 goto featurecheckdone;
6165 }
6166
6167 if (ref->iffeature[i].features[j - 1]->iffeature_size) {
6168 k = refs->number;
6169 if (ly_set_add(refs, ref->iffeature[i].features[j - 1], 0) == k) {
6170 /* not yet seen feature, add it for processing */
6171 ly_set_add(procs, ref->iffeature[i].features[j - 1], 0);
6172 }
6173 }
6174 } else {
6175 /* forward reference */
6176 rc = EXIT_FAILURE;
6177 goto featurecheckdone;
6178 }
6179 }
6180
6181 }
6182 }
6183 rc = EXIT_SUCCESS;
6184
6185featurecheckdone:
6186 ly_set_free(refs);
6187 ly_set_free(procs);
6188 }
6189
6190 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006191 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006192 rc = resolve_unres_schema_uses(item, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006193 break;
6194 case UNRES_TYPE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006195 stype = item;
6196
Radek Krejci51673202016-11-01 17:00:32 +01006197 rc = check_default(stype, (const char **)str_snode, mod);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006198 break;
6199 case UNRES_CHOICE_DFLT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006200 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006201 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006202 choic = item;
6203
Radek Krejcie00d2312016-08-12 15:27:49 +02006204 if (!choic->dflt) {
6205 choic->dflt = resolve_choice_dflt(choic, expr);
6206 }
Michal Vasko7955b362015-09-04 14:18:15 +02006207 if (choic->dflt) {
Radek Krejcie00d2312016-08-12 15:27:49 +02006208 rc = lyp_check_mandatory_choice((struct lys_node *)choic);
Michal Vasko7955b362015-09-04 14:18:15 +02006209 } else {
6210 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006211 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006212 break;
6213 case UNRES_LIST_KEYS:
Radek Krejci5c08a992016-11-02 13:30:04 +01006214 rc = resolve_list_keys(item, ((struct lys_node_list *)item)->keys_str);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006215 break;
6216 case UNRES_LIST_UNIQ:
Radek Krejcid09d1a52016-08-11 14:05:45 +02006217 unique_info = (struct unres_list_uniq *)item;
6218 rc = resolve_unique(unique_info->list, unique_info->expr, unique_info->trg_type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006219 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006220 case UNRES_AUGMENT:
Radek Krejcib3142312016-11-09 11:04:12 +01006221 rc = resolve_augment(item, NULL, unres);
Michal Vasko7178e692016-02-12 15:58:05 +01006222 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006223 case UNRES_XPATH:
6224 node = (struct lys_node *)item;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02006225 rc = lys_check_xpath(node, 1);
Michal Vasko508a50d2016-09-07 14:50:33 +02006226 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006227 default:
6228 LOGINT;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006229 break;
6230 }
6231
Radek Krejci54081ce2016-08-12 15:21:47 +02006232 if (has_str && !rc) {
6233 /* the string is no more needed in case of success.
6234 * In case of forward reference, we will try to resolve the string later */
Radek Krejci4f78b532016-02-17 13:43:00 +01006235 lydict_remove(mod->ctx, str_snode);
6236 }
6237
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006238 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006239}
6240
Michal Vaskof02e3742015-08-05 16:27:02 +02006241/* logs directly */
6242static void
Radek Krejci48464ed2016-03-17 15:44:09 +01006243print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006244{
Michal Vaskocb34dc62016-05-20 14:38:37 +02006245 struct lyxml_elem *xml;
6246 struct lyxml_attr *attr;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006247 struct unres_iffeat_data *iff_data;
Radek Krejci76e15e12016-06-22 11:02:24 +02006248 const char *type_name = NULL;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006249
Michal Vaskof02e3742015-08-05 16:27:02 +02006250 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02006251 case UNRES_IDENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006252 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identity", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006253 break;
6254 case UNRES_TYPE_IDENTREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006255 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identityref", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006256 break;
6257 case UNRES_TYPE_LEAFREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006258 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "leafref",
6259 ((struct lys_type *)item)->info.lref.path);
Michal Vaskof02e3742015-08-05 16:27:02 +02006260 break;
Radek Krejci3a5501d2016-07-18 22:03:34 +02006261 case UNRES_TYPE_DER_TPDF:
Michal Vaskof02e3742015-08-05 16:27:02 +02006262 case UNRES_TYPE_DER:
Michal Vaskocb34dc62016-05-20 14:38:37 +02006263 xml = (struct lyxml_elem *)((struct lys_type *)item)->der;
6264 if (xml->flags & LY_YANG_STRUCTURE_FLAG) {
6265 type_name = ((struct yang_type *)xml)->name;
6266 } else {
6267 LY_TREE_FOR(xml->attr, attr) {
6268 if ((attr->type == LYXML_ATTR_STD) && !strcmp(attr->name, "name")) {
6269 type_name = attr->value;
6270 break;
6271 }
6272 }
6273 assert(attr);
6274 }
6275 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "derived type", type_name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006276 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006277 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006278 iff_data = str_node;
6279 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "if-feature", iff_data->fname);
Michal Vaskof02e3742015-08-05 16:27:02 +02006280 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006281 case UNRES_FEATURE:
6282 LOGVRB("There are unresolved if-features for \"%s\" feature circular dependency check, it will be attempted later",
6283 ((struct lys_feature *)item)->name);
6284 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006285 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006286 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "uses", ((struct lys_node_uses *)item)->name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006287 break;
6288 case UNRES_TYPE_DFLT:
Radek Krejci2e2de832016-10-13 16:12:26 +02006289 if (str_node) {
6290 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "type default", (char *)str_node);
6291 } /* else no default value in the type itself, but we are checking some restrictions against
6292 * possible default value of some base type. The failure is caused by not resolved base type,
6293 * so it was already reported */
Michal Vaskof02e3742015-08-05 16:27:02 +02006294 break;
6295 case UNRES_CHOICE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006296 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "choice default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006297 break;
6298 case UNRES_LIST_KEYS:
Radek Krejci48464ed2016-03-17 15:44:09 +01006299 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list keys", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006300 break;
6301 case UNRES_LIST_UNIQ:
Radek Krejci48464ed2016-03-17 15:44:09 +01006302 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list unique", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006303 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006304 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006305 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "augment target",
6306 ((struct lys_node_augment *)item)->target_name);
Michal Vasko7178e692016-02-12 15:58:05 +01006307 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006308 case UNRES_XPATH:
Michal Vasko0d198372016-11-16 11:40:03 +01006309 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "XPath expressions of",
6310 ((struct lys_node *)item)->name);
Michal Vasko508a50d2016-09-07 14:50:33 +02006311 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006312 default:
6313 LOGINT;
Michal Vaskof02e3742015-08-05 16:27:02 +02006314 break;
6315 }
6316}
6317
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006318/**
Michal Vaskobb211122015-08-19 14:03:11 +02006319 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006320 *
6321 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006322 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006323 *
Michal Vasko92b8a382015-08-19 14:03:49 +02006324 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006325 */
Michal Vaskof02e3742015-08-05 16:27:02 +02006326int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006327resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02006328{
Radek Krejci010e54b2016-03-15 09:40:34 +01006329 uint32_t i, resolved = 0, unres_count, res_count;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006330 int rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006331
6332 assert(unres);
6333
Michal Vaskoe8734262016-09-29 14:12:06 +02006334 LOGVRB("Resolving \"%s\" unresolved schema nodes and their constraints...", mod->name);
Radek Krejci010e54b2016-03-15 09:40:34 +01006335 ly_vlog_hide(1);
Michal Vasko51054ca2015-08-12 12:20:00 +02006336
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006337 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02006338 do {
Michal Vasko88c29542015-11-27 14:57:53 +01006339 unres_count = 0;
6340 res_count = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02006341
6342 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006343 /* UNRES_TYPE_LEAFREF must be resolved (for storing leafref target pointers);
Radek Krejcic79c6b12016-07-26 15:11:49 +02006344 * if-features are resolved here to make sure that we will have all if-features for
6345 * later check of feature circular dependency */
Radek Krejci018f1f52016-08-03 16:01:20 +02006346 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006347 continue;
6348 }
Radek Krejci018f1f52016-08-03 16:01:20 +02006349 /* processes UNRES_USES, UNRES_IFFEAT, UNRES_TYPE_DER, UNRES_TYPE_DER_TPDF, UNRES_TYPE_LEAFREF,
Radek Krejci818b0c52016-11-09 15:10:51 +01006350 * UNRES_AUGMENT, UNRES_CHOICE_DFLT and UNRES_IDENT */
Michal Vasko51054ca2015-08-12 12:20:00 +02006351
Michal Vasko88c29542015-11-27 14:57:53 +01006352 ++unres_count;
Radek Krejci48464ed2016-03-17 15:44:09 +01006353 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006354 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006355 unres->type[i] = UNRES_RESOLVED;
6356 ++resolved;
Michal Vasko88c29542015-11-27 14:57:53 +01006357 ++res_count;
Michal Vasko89e15322015-08-17 15:46:55 +02006358 } else if (rc == -1) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006359 ly_vlog_hide(0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02006360 /* print the error */
6361 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006362 return -1;
Radek Krejcic2a180f2016-06-22 13:28:16 +02006363 } else {
6364 /* forward reference, erase ly_errno */
Radek Krejci00a0e712016-10-26 10:24:46 +02006365 ly_err_clean(1);
Michal Vasko51054ca2015-08-12 12:20:00 +02006366 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006367 }
Michal Vasko88c29542015-11-27 14:57:53 +01006368 } while (res_count && (res_count < unres_count));
Michal Vasko51054ca2015-08-12 12:20:00 +02006369
Michal Vasko88c29542015-11-27 14:57:53 +01006370 if (res_count < unres_count) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006371 /* just print the errors */
6372 ly_vlog_hide(0);
6373
6374 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006375 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006376 continue;
6377 }
6378 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
6379 }
Michal Vasko92b8a382015-08-19 14:03:49 +02006380 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006381 }
6382
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006383 /* the rest */
6384 for (i = 0; i < unres->count; ++i) {
6385 if (unres->type[i] == UNRES_RESOLVED) {
6386 continue;
6387 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02006388
Radek Krejci48464ed2016-03-17 15:44:09 +01006389 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01006390 if (rc == 0) {
Pavol Vican88e16c92016-09-07 15:41:50 +02006391 if (unres->type[i] == UNRES_LIST_UNIQ) {
6392 /* free the allocated structure */
6393 free(unres->item[i]);
6394 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006395 unres->type[i] = UNRES_RESOLVED;
6396 ++resolved;
6397 } else if (rc == -1) {
6398 ly_vlog_hide(0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02006399 /* print the error */
6400 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
6401 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006402 }
6403 }
6404
Radek Krejci010e54b2016-03-15 09:40:34 +01006405 ly_vlog_hide(0);
6406
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006407 if (resolved < unres->count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006408 /* try to resolve the unresolved nodes again, it will not resolve anything, but it will print
6409 * all the validation errors
6410 */
6411 for (i = 0; i < unres->count; ++i) {
6412 if (unres->type[i] == UNRES_RESOLVED) {
6413 continue;
6414 }
Radek Krejcib3142312016-11-09 11:04:12 +01006415 if (unres->type[i] == UNRES_XPATH) {
6416 /* unresolvable XPaths are actually supposed to be warnings - they may be
6417 * unresolved due to the not implemented target module so it shouldn't avoid
6418 * parsing the module, but we still want to announce some issue here */
6419 ly_vlog_hide(0xff);
6420 }
Radek Krejci48464ed2016-03-17 15:44:09 +01006421 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejcib3142312016-11-09 11:04:12 +01006422 if (unres->type[i] == UNRES_XPATH && *ly_vlog_hide_location() == 0xff) {
6423 unres->type[i] = UNRES_RESOLVED;
6424 resolved++;
6425 ly_vlog_hide(0);
6426 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006427 }
Radek Krejcib3142312016-11-09 11:04:12 +01006428 if (resolved < unres->count) {
6429 return -1;
6430 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006431 }
6432
Michal Vaskoe8734262016-09-29 14:12:06 +02006433 LOGVRB("All \"%s\" schema nodes and constraints resolved.", mod->name);
Radek Krejcic071c542016-01-27 14:57:51 +01006434 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006435 return EXIT_SUCCESS;
6436}
6437
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006438/**
Michal Vaskobb211122015-08-19 14:03:11 +02006439 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006440 *
6441 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006442 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006443 * @param[in] item Item to resolve. Type determined by \p type.
6444 * @param[in] type Type of the unresolved item.
6445 * @param[in] str String argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006446 *
Michal Vasko3767fb22016-07-21 12:10:57 +02006447 * @return EXIT_SUCCESS on success, EXIT_FAILURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006448 */
6449int
Radek Krejci48464ed2016-03-17 15:44:09 +01006450unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
6451 const char *str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006452{
Radek Krejci54081ce2016-08-12 15:21:47 +02006453 int rc;
6454 const char *dictstr;
6455
6456 dictstr = lydict_insert(mod->ctx, str, 0);
6457 rc = unres_schema_add_node(mod, unres, item, type, (struct lys_node *)dictstr);
6458
6459 if (rc == -1) {
6460 lydict_remove(mod->ctx, dictstr);
6461 }
6462 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006463}
6464
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006465/**
Michal Vaskobb211122015-08-19 14:03:11 +02006466 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006467 *
6468 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006469 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006470 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01006471 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006472 * @param[in] snode Schema node argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006473 *
Michal Vasko3767fb22016-07-21 12:10:57 +02006474 * @return EXIT_SUCCESS on success, EXIT_FIALURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006475 */
6476int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006477unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Radek Krejci48464ed2016-03-17 15:44:09 +01006478 struct lys_node *snode)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006479{
Michal Vaskoef486d72016-09-27 12:10:44 +02006480 int rc, log_hidden;
Radek Krejci850a5de2016-11-08 14:06:40 +01006481 uint32_t u;
Michal Vasko88c29542015-11-27 14:57:53 +01006482 struct lyxml_elem *yin;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006483
Michal Vasko9bf425b2015-10-22 11:42:03 +02006484 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
6485 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006486
Radek Krejci850a5de2016-11-08 14:06:40 +01006487 /* check for duplicities in unres */
6488 for (u = 0; u < unres->count; u++) {
6489 if (unres->type[u] == type && unres->item[u] == item &&
6490 unres->str_snode[u] == snode && unres->module[u] == mod) {
6491 /* duplication, will be resolved later */
6492 return EXIT_FAILURE;
6493 }
6494 }
6495
Michal Vaskoef486d72016-09-27 12:10:44 +02006496 if (*ly_vlog_hide_location()) {
6497 log_hidden = 1;
6498 } else {
6499 log_hidden = 0;
6500 ly_vlog_hide(1);
6501 }
Radek Krejci48464ed2016-03-17 15:44:09 +01006502 rc = resolve_unres_schema_item(mod, item, type, snode, unres);
Michal Vaskoef486d72016-09-27 12:10:44 +02006503 if (!log_hidden) {
6504 ly_vlog_hide(0);
6505 }
6506
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006507 if (rc != EXIT_FAILURE) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006508 if (rc == -1 && ly_errno == LY_EVALID) {
Radek Krejci2467a492016-10-24 15:16:59 +02006509 ly_err_repeat();
Radek Krejci010e54b2016-03-15 09:40:34 +01006510 }
Radek Krejcid09d1a52016-08-11 14:05:45 +02006511 if (type == UNRES_LIST_UNIQ) {
6512 /* free the allocated structure */
6513 free(item);
Pavol Vican88e16c92016-09-07 15:41:50 +02006514 } else if (rc == -1 && type == UNRES_IFFEAT) {
6515 /* free the allocated resources */
6516 free(*((char **)item));
6517 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006518 return rc;
Radek Krejcif347abc2016-06-22 10:18:47 +02006519 } else {
6520 /* erase info about validation errors */
Radek Krejci00a0e712016-10-26 10:24:46 +02006521 ly_err_clean(1);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006522 }
6523
Radek Krejci48464ed2016-03-17 15:44:09 +01006524 print_unres_schema_item_fail(item, type, snode);
Michal Vaskof02e3742015-08-05 16:27:02 +02006525
Michal Vasko88c29542015-11-27 14:57:53 +01006526 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
Radek Krejci3a5501d2016-07-18 22:03:34 +02006527 if (type == UNRES_TYPE_DER || type == UNRES_TYPE_DER_TPDF) {
Michal Vasko88c29542015-11-27 14:57:53 +01006528 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
Pavol Vicana0e4e672016-02-24 12:20:04 +01006529 if (!(yin->flags & LY_YANG_STRUCTURE_FLAG)) {
6530 lyxml_unlink_elem(mod->ctx, yin, 1);
6531 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
6532 }
Michal Vasko88c29542015-11-27 14:57:53 +01006533 }
6534
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006535 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01006536 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
6537 if (!unres->item) {
6538 LOGMEM;
6539 return -1;
6540 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006541 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01006542 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
6543 if (!unres->type) {
6544 LOGMEM;
6545 return -1;
6546 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006547 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01006548 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
6549 if (!unres->str_snode) {
6550 LOGMEM;
6551 return -1;
6552 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006553 unres->str_snode[unres->count-1] = snode;
Radek Krejcic071c542016-01-27 14:57:51 +01006554 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
6555 if (!unres->module) {
6556 LOGMEM;
6557 return -1;
6558 }
6559 unres->module[unres->count-1] = mod;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006560
Michal Vasko3767fb22016-07-21 12:10:57 +02006561 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006562}
6563
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006564/**
Michal Vaskobb211122015-08-19 14:03:11 +02006565 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006566 *
6567 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006568 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006569 * @param[in] item Old item to be resolved.
6570 * @param[in] type Type of the old unresolved item.
6571 * @param[in] new_item New item to use in the duplicate.
6572 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02006573 * @return EXIT_SUCCESS on success, EXIT_FAILURE if item is not in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006574 */
Michal Vaskodad19402015-08-06 09:51:53 +02006575int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006576unres_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 +02006577{
6578 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006579 struct unres_list_uniq aux_uniq;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006580 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006581
Michal Vaskocf024702015-10-08 15:01:42 +02006582 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006583
Radek Krejcid09d1a52016-08-11 14:05:45 +02006584 /* hack for UNRES_LIST_UNIQ, which stores multiple items behind its item */
6585 if (type == UNRES_LIST_UNIQ) {
6586 aux_uniq.list = item;
6587 aux_uniq.expr = ((struct unres_list_uniq *)new_item)->expr;
6588 item = &aux_uniq;
6589 }
Michal Vasko878e38d2016-09-05 12:17:53 +02006590 i = unres_schema_find(unres, -1, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006591
6592 if (i == -1) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006593 if (type == UNRES_LIST_UNIQ) {
6594 free(new_item);
6595 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02006596 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006597 }
6598
Radek Krejcic79c6b12016-07-26 15:11:49 +02006599 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT) ||
Radek Krejcib69f3232016-09-16 17:41:07 +02006600 (type == UNRES_FEATURE) || (type == UNRES_LIST_UNIQ)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01006601 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006602 LOGINT;
6603 return -1;
6604 }
Radek Krejcicbb473e2016-09-16 14:48:32 +02006605 } else if (type == UNRES_IFFEAT) {
6606 /* duplicate unres_iffeature_data */
6607 iff_data = malloc(sizeof *iff_data);
6608 iff_data->fname = lydict_insert(mod->ctx, ((struct unres_iffeat_data *)unres->str_snode[i])->fname, 0);
6609 iff_data->node = ((struct unres_iffeat_data *)unres->str_snode[i])->node;
6610 if (unres_schema_add_node(mod, unres, new_item, type, (struct lys_node *)iff_data) == -1) {
6611 LOGINT;
6612 return -1;
6613 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006614 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01006615 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006616 LOGINT;
6617 return -1;
6618 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006619 }
Michal Vaskodad19402015-08-06 09:51:53 +02006620
6621 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006622}
6623
Michal Vaskof02e3742015-08-05 16:27:02 +02006624/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006625int
Michal Vasko878e38d2016-09-05 12:17:53 +02006626unres_schema_find(struct unres_schema *unres, int start_on_backwards, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006627{
Michal Vasko878e38d2016-09-05 12:17:53 +02006628 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006629 struct unres_list_uniq *aux_uniq1, *aux_uniq2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006630
Michal Vasko878e38d2016-09-05 12:17:53 +02006631 if (start_on_backwards > 0) {
6632 i = start_on_backwards;
6633 } else {
6634 i = unres->count - 1;
6635 }
6636 for (; i > -1; i--) {
6637 if (unres->type[i] != type) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006638 continue;
6639 }
6640 if (type != UNRES_LIST_UNIQ) {
Michal Vasko878e38d2016-09-05 12:17:53 +02006641 if (unres->item[i] == item) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006642 break;
6643 }
6644 } else {
6645 aux_uniq1 = (struct unres_list_uniq *)unres->item[i - 1];
6646 aux_uniq2 = (struct unres_list_uniq *)item;
6647 if ((aux_uniq1->list == aux_uniq2->list) && ly_strequal(aux_uniq1->expr, aux_uniq2->expr, 0)) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006648 break;
6649 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006650 }
6651 }
6652
Michal Vasko878e38d2016-09-05 12:17:53 +02006653 return i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006654}
Michal Vasko8bcdf292015-08-19 14:04:43 +02006655
Michal Vaskoede9c472016-06-07 09:38:15 +02006656static void
6657unres_schema_free_item(struct ly_ctx *ctx, struct unres_schema *unres, uint32_t i)
6658{
6659 struct lyxml_elem *yin;
6660 struct yang_type *yang;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006661 struct unres_iffeat_data *iff_data;
Michal Vaskoede9c472016-06-07 09:38:15 +02006662
6663 switch (unres->type[i]) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02006664 case UNRES_TYPE_DER_TPDF:
Michal Vaskoede9c472016-06-07 09:38:15 +02006665 case UNRES_TYPE_DER:
6666 yin = (struct lyxml_elem *)((struct lys_type *)unres->item[i])->der;
6667 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6668 yang =(struct yang_type *)yin;
Pavol Vicancf2af4d2016-12-21 14:13:06 +01006669 ((struct lys_type *)unres->item[i])->base = yang->base;
Michal Vaskoede9c472016-06-07 09:38:15 +02006670 lydict_remove(ctx, yang->name);
6671 free(yang);
Pavol Vicancf2af4d2016-12-21 14:13:06 +01006672 if (((struct lys_type *)unres->item[i])->base == LY_TYPE_UNION) {
6673 yang_free_type_union(ctx, (struct lys_type *)unres->item[i]);
6674 }
Michal Vaskoede9c472016-06-07 09:38:15 +02006675 } else {
6676 lyxml_free(ctx, yin);
6677 }
6678 break;
Pavol Vican88e16c92016-09-07 15:41:50 +02006679 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006680 iff_data = (struct unres_iffeat_data *)unres->str_snode[i];
6681 lydict_remove(ctx, iff_data->fname);
6682 free(unres->str_snode[i]);
Pavol Vican88e16c92016-09-07 15:41:50 +02006683 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02006684 case UNRES_IDENT:
6685 case UNRES_TYPE_IDENTREF:
Michal Vaskoede9c472016-06-07 09:38:15 +02006686 case UNRES_CHOICE_DFLT:
6687 case UNRES_LIST_KEYS:
Michal Vaskoede9c472016-06-07 09:38:15 +02006688 lydict_remove(ctx, (const char *)unres->str_snode[i]);
6689 break;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006690 case UNRES_LIST_UNIQ:
6691 free(unres->item[i]);
6692 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02006693 default:
6694 break;
6695 }
6696 unres->type[i] = UNRES_RESOLVED;
6697}
6698
Michal Vasko88c29542015-11-27 14:57:53 +01006699void
Radek Krejcic071c542016-01-27 14:57:51 +01006700unres_schema_free(struct lys_module *module, struct unres_schema **unres)
Michal Vasko88c29542015-11-27 14:57:53 +01006701{
6702 uint32_t i;
Radek Krejcic071c542016-01-27 14:57:51 +01006703 unsigned int unresolved = 0;
Michal Vasko88c29542015-11-27 14:57:53 +01006704
Radek Krejcic071c542016-01-27 14:57:51 +01006705 if (!unres || !(*unres)) {
6706 return;
Michal Vasko88c29542015-11-27 14:57:53 +01006707 }
6708
Radek Krejcic071c542016-01-27 14:57:51 +01006709 assert(module || (*unres)->count == 0);
6710
6711 for (i = 0; i < (*unres)->count; ++i) {
6712 if ((*unres)->module[i] != module) {
6713 if ((*unres)->type[i] != UNRES_RESOLVED) {
6714 unresolved++;
6715 }
6716 continue;
6717 }
Michal Vaskoede9c472016-06-07 09:38:15 +02006718
6719 /* free heap memory for the specific item */
6720 unres_schema_free_item(module->ctx, *unres, i);
Radek Krejcic071c542016-01-27 14:57:51 +01006721 }
6722
Michal Vaskoede9c472016-06-07 09:38:15 +02006723 /* free it all */
Radek Krejcic071c542016-01-27 14:57:51 +01006724 if (!module || (!unresolved && !module->type)) {
6725 free((*unres)->item);
6726 free((*unres)->type);
6727 free((*unres)->str_snode);
6728 free((*unres)->module);
Radek Krejcic071c542016-01-27 14:57:51 +01006729 free((*unres));
6730 (*unres) = NULL;
6731 }
Michal Vasko88c29542015-11-27 14:57:53 +01006732}
6733
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006734/**
6735 * @brief Resolve instance-identifier in JSON data format. Logs directly.
6736 *
6737 * @param[in] data Data node where the path is used
6738 * @param[in] path Instance-identifier node value.
6739 * @param[in,out] ret Resolved instance or NULL.
6740 *
6741 * @return 0 on success (even if unresolved and \p ret is NULL), -1 on error.
6742 */
6743static int
6744resolve_instid(struct lyd_node *data, const char *path, int req_inst, struct lyd_node **ret)
6745{
6746 int i = 0, j;
6747 const struct lys_module *mod;
6748 struct ly_ctx *ctx = data->schema->module->ctx;
6749 const char *model, *name;
6750 char *str;
6751 int mod_len, name_len, has_predicate;
6752 struct unres_data node_match;
6753
6754 memset(&node_match, 0, sizeof node_match);
6755 *ret = NULL;
6756
6757 /* we need root to resolve absolute path */
6758 for (; data->parent; data = data->parent);
6759 /* we're still parsing it and the pointer is not correct yet */
6760 if (data->prev) {
6761 for (; data->prev->next; data = data->prev);
6762 }
6763
6764 /* search for the instance node */
6765 while (path[i]) {
6766 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
6767 if (j <= 0) {
6768 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
6769 goto error;
6770 }
6771 i += j;
6772
6773 str = strndup(model, mod_len);
6774 if (!str) {
6775 LOGMEM;
6776 goto error;
6777 }
6778 mod = ly_ctx_get_module(ctx, str, NULL);
6779 free(str);
6780
6781 if (resolve_data(mod, name, name_len, data, &node_match)) {
6782 /* no instance exists */
6783 break;
6784 }
6785
6786 if (has_predicate) {
6787 /* we have predicate, so the current results must be list or leaf-list */
6788 j = resolve_predicate(&path[i], &node_match);
6789 if (j < 1) {
6790 LOGVAL(LYE_INPRED, LY_VLOG_LYD, data, &path[i-j]);
6791 goto error;
6792 }
6793 i += j;
6794
6795 if (!node_match.count) {
6796 /* no instance exists */
6797 break;
6798 }
6799 }
6800 }
6801
6802 if (!node_match.count) {
6803 /* no instance exists */
6804 if (req_inst > -1) {
6805 LOGVAL(LYE_NOREQINS, LY_VLOG_NONE, NULL, path);
6806 return EXIT_FAILURE;
6807 }
6808 LOGVRB("There is no instance of \"%s\", but it is not required.", path);
6809 return EXIT_SUCCESS;
6810 } else if (node_match.count > 1) {
6811 /* instance identifier must resolve to a single node */
6812 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
6813 goto error;
6814 } else {
6815 /* we have required result, remember it and cleanup */
6816 *ret = node_match.node[0];
6817 free(node_match.node);
6818 return EXIT_SUCCESS;
6819 }
6820
6821error:
6822 /* cleanup */
6823 free(node_match.node);
6824 return -1;
6825}
6826
6827static int
6828resolve_leafref(struct lyd_node_leaf_list *leaf, const char *path, int req_inst, struct lyd_node **ret)
Radek Krejci7de36cf2016-09-12 16:18:50 +02006829{
Radek Krejci7de36cf2016-09-12 16:18:50 +02006830 struct unres_data matches;
6831 uint32_t i;
6832
Radek Krejci9b6aad22016-09-20 15:55:51 +02006833 /* init */
Radek Krejci7de36cf2016-09-12 16:18:50 +02006834 memset(&matches, 0, sizeof matches);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006835 *ret = NULL;
Radek Krejci7de36cf2016-09-12 16:18:50 +02006836
6837 /* EXIT_FAILURE return keeps leaf->value.lefref NULL, handled later */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006838 if (resolve_path_arg_data((struct lyd_node *)leaf, path, &matches) == -1) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02006839 return -1;
6840 }
6841
6842 /* check that value matches */
6843 for (i = 0; i < matches.count; ++i) {
Radek Krejci1899d6a2016-11-03 13:48:07 +01006844 /* not that the value is already in canonical form since the parsers does the conversion,
6845 * so we can simply compare just the values */
Radek Krejci7de36cf2016-09-12 16:18:50 +02006846 if (ly_strequal(leaf->value_str, ((struct lyd_node_leaf_list *)matches.node[i])->value_str, 1)) {
Radek Krejci1899d6a2016-11-03 13:48:07 +01006847 /* we have the match */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006848 *ret = matches.node[i];
Radek Krejci7de36cf2016-09-12 16:18:50 +02006849 break;
6850 }
6851 }
6852
6853 free(matches.node);
6854
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006855 if (!*ret) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02006856 /* reference not found */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006857 if (req_inst > -1) {
6858 LOGVAL(LYE_NOLEAFREF, LY_VLOG_LYD, leaf, path, leaf->value_str);
Radek Krejci7de36cf2016-09-12 16:18:50 +02006859 return EXIT_FAILURE;
6860 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006861 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 +02006862 }
6863 }
6864
6865 return EXIT_SUCCESS;
6866}
6867
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006868/* ignore fail because we are parsing edit-config, get, or get-config - but only if the union includes leafref or instid */
Radek Krejci9b6aad22016-09-20 15:55:51 +02006869static int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006870resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type, int ignore_fail)
Radek Krejci9b6aad22016-09-20 15:55:51 +02006871{
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006872 struct lys_type *t;
Michal Vaskob1ac8722017-01-02 13:04:25 +01006873 struct lyd_node *ret, *par, *op_node;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006874 int found, hidden, success = 0;
6875 const char *json_val = NULL;
Radek Krejci9b6aad22016-09-20 15:55:51 +02006876
6877 assert(type->base == LY_TYPE_UNION);
6878
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006879 if ((leaf->value_type == LY_TYPE_UNION) || (leaf->value_type == (LY_TYPE_INST | LY_TYPE_INST_UNRES))) {
6880 /* either NULL or instid previously converted to JSON */
6881 json_val = leaf->value.string;
6882 }
Michal Vasko1c8567a2017-01-05 13:42:27 +01006883
6884 if ((leaf->value_type & LY_DATA_TYPE_MASK) == LY_TYPE_BITS) {
6885 free(leaf->value.bit);
6886 }
Radek Krejci9b6aad22016-09-20 15:55:51 +02006887 memset(&leaf->value, 0, sizeof leaf->value);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006888
6889 /* turn logging off, we are going to try to validate the value with all the types in order */
6890 hidden = *ly_vlog_hide_location();
6891 ly_vlog_hide(1);
6892
6893 t = NULL;
6894 found = 0;
6895 while ((t = lyp_get_next_union_type(type, t, &found))) {
6896 found = 0;
6897
6898 switch (t->base) {
6899 case LY_TYPE_LEAFREF:
6900 if (!resolve_leafref(leaf, t->info.lref.path, (ignore_fail ? -1 : t->info.lref.req), &ret)) {
Michal Vaskob1ac8722017-01-02 13:04:25 +01006901 if (ret && !(leaf->schema->flags & LYS_LEAFREF_DEP)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006902 /* valid resolved */
6903 leaf->value.leafref = ret;
6904 leaf->value_type = LY_TYPE_LEAFREF;
6905 } else {
6906 /* valid unresolved */
6907 if (!lyp_parse_value(t, &leaf->value_str, NULL, leaf, 1, 0)) {
6908 return -1;
6909 }
6910 }
6911
6912 success = 1;
6913 }
6914 break;
6915 case LY_TYPE_INST:
6916 if (!resolve_instid((struct lyd_node *)leaf, (json_val ? json_val : leaf->value_str),
6917 (ignore_fail ? -1 : t->info.inst.req), &ret)) {
6918 if (ret) {
Michal Vaskob1ac8722017-01-02 13:04:25 +01006919 for (op_node = (struct lyd_node *)leaf;
6920 op_node && !(op_node->schema->nodetype & (LYS_RPC | LYS_NOTIF | LYS_ACTION));
6921 op_node = op_node->parent);
6922 if (op_node) {
6923 /* this is an RPC/notif/action */
6924 for (par = ret->parent; par && (par != op_node); par = par->parent);
6925 if (!par) {
6926 /* target instance is outside the operation - do not store the pointer */
6927 ret = NULL;
6928 }
6929 }
6930 }
6931 if (ret) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006932 /* valid resolved */
6933 leaf->value.instance = ret;
6934 leaf->value_type = LY_TYPE_INST;
6935
6936 if (json_val) {
6937 lydict_remove(leaf->schema->module->ctx, leaf->value_str);
6938 leaf->value_str = json_val;
6939 json_val = NULL;
6940 }
6941 } else {
6942 /* valid unresolved */
6943 if (json_val) {
6944 /* put the JSON val back */
6945 leaf->value.string = json_val;
6946 json_val = NULL;
6947 } else {
6948 leaf->value.instance = NULL;
6949 }
6950 leaf->value_type = LY_TYPE_INST | LY_TYPE_INST_UNRES;
6951 }
6952
6953 success = 1;
6954 }
6955 break;
6956 default:
6957 if (lyp_parse_value(t, &leaf->value_str, NULL, leaf, 1, 0)) {
6958 success = 1;
6959 }
6960 break;
6961 }
6962
6963 if (success) {
6964 break;
6965 }
6966
6967 /* erase information about errors - they are false or irrelevant
6968 * and will be replaced by a single error messages */
6969 ly_err_clean(1);
6970
6971 /* erase possible present and invalid value data */
6972 if (t->base == LY_TYPE_BITS) {
6973 free(leaf->value.bit);
6974 }
6975 memset(&leaf->value, 0, sizeof leaf->value);
6976 }
6977
6978 /* turn logging back on */
6979 if (!hidden) {
6980 ly_vlog_hide(0);
6981 }
6982
6983 if (json_val) {
6984 if (!success) {
6985 /* put the value back for now */
6986 assert(leaf->value_type == LY_TYPE_UNION);
6987 leaf->value.string = json_val;
6988 } else {
6989 /* value was ultimately useless, but we could not have known */
6990 lydict_remove(leaf->schema->module->ctx, json_val);
6991 }
6992 }
6993
6994 if (!success && (!ignore_fail || !type->info.uni.has_ptr_type)) {
6995 /* not found and it is required */
6996 LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, leaf->value_str ? leaf->value_str : "", leaf->schema->name);
Radek Krejci9b6aad22016-09-20 15:55:51 +02006997 return EXIT_FAILURE;
6998 }
6999
7000 return EXIT_SUCCESS;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007001
Radek Krejci9b6aad22016-09-20 15:55:51 +02007002}
7003
Michal Vasko8bcdf292015-08-19 14:04:43 +02007004/**
7005 * @brief Resolve a single unres data item. Logs directly.
7006 *
Michal Vaskocf024702015-10-08 15:01:42 +02007007 * @param[in] node Data node to resolve.
Michal Vaskocf024702015-10-08 15:01:42 +02007008 * @param[in] type Type of the unresolved item.
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007009 * @param[in] ignore_fails Flag whether to ignore any false condition or unresolved nodes (e.g., for LYD_OPT_EDIT).
Michal Vasko8bcdf292015-08-19 14:04:43 +02007010 *
7011 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
7012 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02007013int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007014resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type, int ignore_fail)
Michal Vasko8bcdf292015-08-19 14:04:43 +02007015{
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007016 int rc, req_inst;
Michal Vasko83a6c462015-10-08 16:43:53 +02007017 struct lyd_node_leaf_list *leaf;
Michal Vaskob1ac8722017-01-02 13:04:25 +01007018 struct lyd_node *ret, *op_node, *par;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007019 struct lys_node_leaf *sleaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007020
Michal Vasko83a6c462015-10-08 16:43:53 +02007021 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02007022 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007023
Michal Vaskocf024702015-10-08 15:01:42 +02007024 switch (type) {
7025 case UNRES_LEAFREF:
7026 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007027 assert(leaf->validity & LYD_VAL_LEAFREF);
7028 req_inst = (ignore_fail ? -1 : sleaf->type.info.lref.req);
7029 rc = resolve_leafref(leaf, sleaf->type.info.lref.path, req_inst, &ret);
7030 if (!rc) {
Michal Vaskob1ac8722017-01-02 13:04:25 +01007031 if (ret && !(leaf->schema->flags & LYS_LEAFREF_DEP)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007032 /* valid resolved */
Michal Vasko1c8567a2017-01-05 13:42:27 +01007033 if ((leaf->value_type & LY_DATA_TYPE_MASK) == LY_TYPE_BITS) {
7034 free(leaf->value.bit);
7035 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007036 leaf->value.leafref = ret;
7037 leaf->value_type = LY_TYPE_LEAFREF;
7038 } else {
7039 /* valid unresolved */
7040 if (!(leaf->value_type & LY_TYPE_LEAFREF_UNRES)) {
7041 if (!lyp_parse_value(&sleaf->type, &leaf->value_str, NULL, leaf, 1, 0)) {
7042 return -1;
7043 }
7044 }
7045 }
7046 leaf->validity &= ~LYD_VAL_LEAFREF;
7047 } else {
7048 return rc;
7049 }
7050 break;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007051
Michal Vaskocf024702015-10-08 15:01:42 +02007052 case UNRES_INSTID:
Radek Krejci7de36cf2016-09-12 16:18:50 +02007053 assert(sleaf->type.base == LY_TYPE_INST);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007054 req_inst = (ignore_fail ? -1 : sleaf->type.info.inst.req);
7055 rc = resolve_instid(node, leaf->value_str, req_inst, &ret);
7056 if (!rc) {
7057 if (ret) {
Michal Vaskob1ac8722017-01-02 13:04:25 +01007058 for (op_node = (struct lyd_node *)leaf;
7059 op_node && !(op_node->schema->nodetype & (LYS_RPC | LYS_NOTIF | LYS_ACTION));
7060 op_node = op_node->parent);
7061 if (op_node) {
7062 /* this is an RPC/notif/action */
7063 for (par = ret->parent; par && (par != op_node); par = par->parent);
7064 if (!par) {
7065 /* target instance is outside the operation - do not store the pointer */
7066 ret = NULL;
7067 }
7068 }
7069 }
7070 if (ret) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007071 /* valid resolved */
7072 leaf->value.instance = ret;
7073 leaf->value_type = LY_TYPE_INST;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007074 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007075 /* valid unresolved */
7076 leaf->value.instance = NULL;
7077 leaf->value_type = LY_TYPE_INST | LY_TYPE_INST_UNRES;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007078 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007079 } else {
7080 return rc;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007081 }
Michal Vaskocf024702015-10-08 15:01:42 +02007082 break;
7083
Radek Krejci7de36cf2016-09-12 16:18:50 +02007084 case UNRES_UNION:
7085 assert(sleaf->type.base == LY_TYPE_UNION);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007086 return resolve_union(leaf, &sleaf->type, ignore_fail);
Radek Krejci7de36cf2016-09-12 16:18:50 +02007087
Michal Vaskocf024702015-10-08 15:01:42 +02007088 case UNRES_WHEN:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007089 if ((rc = resolve_when(node, NULL, ignore_fail))) {
Michal Vaskocf024702015-10-08 15:01:42 +02007090 return rc;
7091 }
7092 break;
7093
Michal Vaskobf19d252015-10-08 15:39:17 +02007094 case UNRES_MUST:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007095 if ((rc = resolve_must(node, 0, ignore_fail))) {
Michal Vaskoc8c810c2016-09-15 14:02:00 +02007096 return rc;
7097 }
7098 break;
7099
7100 case UNRES_MUST_INOUT:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007101 if ((rc = resolve_must(node, 1, ignore_fail))) {
Michal Vaskobf19d252015-10-08 15:39:17 +02007102 return rc;
7103 }
7104 break;
7105
Michal Vaskocf024702015-10-08 15:01:42 +02007106 default:
Michal Vasko8bcdf292015-08-19 14:04:43 +02007107 LOGINT;
7108 return -1;
7109 }
7110
7111 return EXIT_SUCCESS;
7112}
7113
7114/**
Radek Krejci0b7704f2016-03-18 12:16:14 +01007115 * @brief add data unres item
Michal Vasko8bcdf292015-08-19 14:04:43 +02007116 *
7117 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02007118 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007119 *
Radek Krejci0b7704f2016-03-18 12:16:14 +01007120 * @return 0 on success, -1 on error.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007121 */
7122int
Radek Krejci0b7704f2016-03-18 12:16:14 +01007123unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02007124{
Radek Krejci03b71f72016-03-16 11:10:09 +01007125 assert(unres && node);
Michal Vaskoc4280842016-04-19 16:10:42 +02007126 assert((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)
Radek Krejcibacc7442016-10-27 13:39:56 +02007127 || (type == UNRES_MUST_INOUT) || (type == UNRES_UNION));
Michal Vasko8bcdf292015-08-19 14:04:43 +02007128
Radek Krejci03b71f72016-03-16 11:10:09 +01007129 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01007130 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
7131 if (!unres->node) {
7132 LOGMEM;
7133 return -1;
7134 }
Michal Vaskocf024702015-10-08 15:01:42 +02007135 unres->node[unres->count - 1] = node;
Michal Vasko253035f2015-12-17 16:58:13 +01007136 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
7137 if (!unres->type) {
7138 LOGMEM;
7139 return -1;
7140 }
Michal Vaskocf024702015-10-08 15:01:42 +02007141 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007142
Radek Krejci0b7704f2016-03-18 12:16:14 +01007143 if (type == UNRES_WHEN) {
7144 /* remove previous result */
7145 node->when_status = LYD_WHEN;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007146 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007147
7148 return EXIT_SUCCESS;
7149}
7150
7151/**
7152 * @brief Resolve every unres data item in the structure. Logs directly.
7153 *
Radek Krejci082c84f2016-10-17 16:33:06 +02007154 * If options includes LYD_OPT_TRUSTED, the data are considered trusted (when, must conditions are not expected,
7155 * unresolved leafrefs/instids are accepted).
7156 *
7157 * If options includes LYD_OPT_NOAUTODEL, the false resulting when condition on non-default nodes, the error is raised.
7158 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007159 * @param[in] unres Unres data structure to use.
Radek Krejci082c84f2016-10-17 16:33:06 +02007160 * @param[in,out] root Root node of the data tree, can be changed due to autodeletion.
7161 * @param[in] options Data options as described above.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007162 *
7163 * @return EXIT_SUCCESS on success, -1 on error.
7164 */
7165int
Radek Krejci082c84f2016-10-17 16:33:06 +02007166resolve_unres_data(struct unres_data *unres, struct lyd_node **root, int options)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007167{
Radek Krejci0c0086a2016-03-24 15:20:28 +01007168 uint32_t i, j, first = 1, resolved = 0, del_items = 0, when_stmt = 0;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007169 int rc, progress, ignore_fails;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007170 struct lyd_node *parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007171
Radek Krejci082c84f2016-10-17 16:33:06 +02007172 assert(root);
Radek Krejci03b71f72016-03-16 11:10:09 +01007173 assert(unres);
Radek Krejci03b71f72016-03-16 11:10:09 +01007174
7175 if (!unres->count) {
7176 return EXIT_SUCCESS;
7177 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007178
Michal Vaskoad2e44a2017-01-03 10:31:35 +01007179 if (options & (LYD_OPT_TRUSTED | LYD_OPT_NOTIF_FILTER | LYD_OPT_GET | LYD_OPT_GETCONFIG | LYD_OPT_EDIT)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007180 ignore_fails = 1;
7181 } else {
7182 ignore_fails = 0;
7183 }
7184
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02007185 LOGVRB("Resolving unresolved data nodes and their constraints...");
Radek Krejci010e54b2016-03-15 09:40:34 +01007186 ly_vlog_hide(1);
7187
Radek Krejci0b7704f2016-03-18 12:16:14 +01007188 /* when-stmt first */
Radek Krejci010e54b2016-03-15 09:40:34 +01007189 do {
Radek Krejci00a0e712016-10-26 10:24:46 +02007190 ly_err_clean(1);
Radek Krejci010e54b2016-03-15 09:40:34 +01007191 progress = 0;
Michal Vasko6df94132016-09-22 11:08:09 +02007192 for (i = 0; i < unres->count; i++) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007193 if (unres->type[i] != UNRES_WHEN) {
7194 continue;
7195 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007196 if (first) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007197 /* count when-stmt nodes in unres list */
7198 when_stmt++;
7199 }
7200
7201 /* resolve when condition only when all parent when conditions are already resolved */
7202 for (parent = unres->node[i]->parent;
7203 parent && LYD_WHEN_DONE(parent->when_status);
7204 parent = parent->parent) {
7205 if (!parent->parent && (parent->when_status & LYD_WHEN_FALSE)) {
7206 /* the parent node was already unlinked, do not resolve this node,
7207 * it will be removed anyway, so just mark it as resolved
7208 */
7209 unres->node[i]->when_status |= LYD_WHEN_FALSE;
7210 unres->type[i] = UNRES_RESOLVED;
7211 resolved++;
7212 break;
7213 }
7214 }
7215 if (parent) {
7216 continue;
7217 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007218
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007219 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fails);
Radek Krejci010e54b2016-03-15 09:40:34 +01007220 if (!rc) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007221 if (unres->node[i]->when_status & LYD_WHEN_FALSE) {
Radek Krejci082c84f2016-10-17 16:33:06 +02007222 if ((options & LYD_OPT_NOAUTODEL) && !unres->node[i]->dflt) {
Radek Krejci03b71f72016-03-16 11:10:09 +01007223 /* false when condition */
7224 ly_vlog_hide(0);
Radek Krejci2467a492016-10-24 15:16:59 +02007225 ly_err_repeat();
Radek Krejci03b71f72016-03-16 11:10:09 +01007226 return -1;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007227 } /* follows else */
7228
Radek Krejci0c0086a2016-03-24 15:20:28 +01007229 /* only unlink now, the subtree can contain another nodes stored in the unres list */
7230 /* if it has parent non-presence containers that would be empty, we should actually
7231 * remove the container
7232 */
Radek Krejci2537fd32016-09-07 16:22:41 +02007233 for (parent = unres->node[i];
7234 parent->parent && parent->parent->schema->nodetype == LYS_CONTAINER;
7235 parent = parent->parent) {
7236 if (((struct lys_node_container *)parent->parent->schema)->presence) {
7237 /* presence container */
7238 break;
Radek Krejci0c0086a2016-03-24 15:20:28 +01007239 }
Radek Krejci2537fd32016-09-07 16:22:41 +02007240 if (parent->next || parent->prev != parent) {
7241 /* non empty (the child we are in and we are going to remove is not the only child) */
7242 break;
7243 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007244 }
Radek Krejci2537fd32016-09-07 16:22:41 +02007245 unres->node[i] = parent;
Radek Krejci0c0086a2016-03-24 15:20:28 +01007246
Radek Krejci0b7704f2016-03-18 12:16:14 +01007247 /* auto-delete */
7248 LOGVRB("auto-delete node \"%s\" due to when condition (%s)", ly_errpath(),
7249 ((struct lys_node_leaf *)unres->node[i]->schema)->when->cond);
Radek Krejci0c0086a2016-03-24 15:20:28 +01007250 if (*root && *root == unres->node[i]) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007251 *root = (*root)->next;
Radek Krejci03b71f72016-03-16 11:10:09 +01007252 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007253
Radek Krejci0b7704f2016-03-18 12:16:14 +01007254 lyd_unlink(unres->node[i]);
7255 unres->type[i] = UNRES_DELETE;
7256 del_items++;
Radek Krejci51fd8162016-03-24 15:49:51 +01007257
7258 /* update the rest of unres items */
7259 for (j = 0; j < unres->count; j++) {
Radek Krejci3db819b2016-03-24 16:29:48 +01007260 if (unres->type[j] == UNRES_RESOLVED || unres->type[j] == UNRES_DELETE) {
Radek Krejci51fd8162016-03-24 15:49:51 +01007261 continue;
7262 }
7263
7264 /* test if the node is in subtree to be deleted */
7265 for (parent = unres->node[j]; parent; parent = parent->parent) {
7266 if (parent == unres->node[i]) {
7267 /* yes, it is */
7268 unres->type[j] = UNRES_RESOLVED;
7269 resolved++;
7270 break;
7271 }
7272 }
7273 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007274 } else {
7275 unres->type[i] = UNRES_RESOLVED;
Radek Krejci03b71f72016-03-16 11:10:09 +01007276 }
Radek Krejci00a0e712016-10-26 10:24:46 +02007277 ly_err_clean(1);
Radek Krejci010e54b2016-03-15 09:40:34 +01007278 resolved++;
7279 progress = 1;
7280 } else if (rc == -1) {
7281 ly_vlog_hide(0);
Michal Vasko76e73402016-08-24 16:00:13 +02007282 /* print only this last error */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007283 resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fails);
Radek Krejci010e54b2016-03-15 09:40:34 +01007284 return -1;
Radek Krejci2467a492016-10-24 15:16:59 +02007285 } /* else forward reference */
Radek Krejci010e54b2016-03-15 09:40:34 +01007286 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007287 first = 0;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007288 } while (progress && resolved < when_stmt);
Radek Krejci010e54b2016-03-15 09:40:34 +01007289
Radek Krejci0b7704f2016-03-18 12:16:14 +01007290 /* do we have some unresolved when-stmt? */
Radek Krejcid940d732016-03-24 16:02:28 +01007291 if (when_stmt > resolved) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007292 ly_vlog_hide(0);
Radek Krejci2467a492016-10-24 15:16:59 +02007293 ly_err_repeat();
Radek Krejci0b7704f2016-03-18 12:16:14 +01007294 return -1;
7295 }
7296
7297 for (i = 0; del_items && i < unres->count; i++) {
7298 /* we had some when-stmt resulted to false, so now we have to sanitize the unres list */
7299 if (unres->type[i] != UNRES_DELETE) {
7300 continue;
7301 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007302 if (!unres->node[i]) {
7303 unres->type[i] = UNRES_RESOLVED;
7304 del_items--;
7305 continue;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007306 }
7307
7308 /* really remove the complete subtree */
7309 lyd_free(unres->node[i]);
7310 unres->type[i] = UNRES_RESOLVED;
7311 del_items--;
7312 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007313 ly_vlog_hide(0);
Radek Krejci010e54b2016-03-15 09:40:34 +01007314
7315 /* rest */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007316 for (i = 0; i < unres->count; ++i) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007317 if (unres->type[i] == UNRES_RESOLVED) {
7318 continue;
7319 }
Radek Krejci082c84f2016-10-17 16:33:06 +02007320 assert(!(options & LYD_OPT_TRUSTED) || ((unres->type[i] != UNRES_MUST) && (unres->type[i] != UNRES_MUST_INOUT)));
Radek Krejci010e54b2016-03-15 09:40:34 +01007321
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007322 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fails);
7323 if (rc) {
7324 /* since when was already resolved, a forward reference is an error */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007325 return -1;
7326 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007327
7328 unres->type[i] = UNRES_RESOLVED;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007329 }
7330
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02007331 LOGVRB("All data nodes and constraints resolved.");
Radek Krejci010e54b2016-03-15 09:40:34 +01007332 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007333 return EXIT_SUCCESS;
7334}