blob: 7d2540ba753d57ce8959af34ddde9d14ef6bb217 [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 Vasko53adfc72017-01-06 10:39:10 +01002200 /* is the predicate a number? */
2201 if (((r = parse_schema_json_predicate(predicate, &name, &nam_len, &value, &val_len, &has_predicate)) < 1)
2202 || !strncmp(name, ".", nam_len)) {
2203 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
2204 return -1;
2205 }
2206
2207 if (isdigit(name[0])) {
2208 if (position == atoi(name)) {
2209 /* match */
2210 *parsed += r;
2211 return 0;
2212 } else {
2213 /* not a match */
2214 return 1;
2215 }
2216 }
2217
2218 if (!((struct lys_node_list *)node->schema)->keys_size) {
2219 /* no keys in schema - causes an error later */
2220 return 0;
2221 }
2222
Michal Vaskof29903d2016-04-18 13:13:10 +02002223 key = (struct lyd_node_leaf_list *)node->child;
Michal Vasko53adfc72017-01-06 10:39:10 +01002224 if (!key) {
2225 /* it is not a position, so we need a key for it to be a match */
2226 return 1;
2227 }
2228
2229 /* go through all the keys */
2230 i = 0;
2231 goto check_parsed_values;
2232
2233 for (; i < ((struct lys_node_list *)node->schema)->keys_size; ++i) {
Michal Vasko22448d32016-03-16 13:17:29 +01002234 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002235 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, node_name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002236 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002237 }
2238
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002239 if (((r = parse_schema_json_predicate(predicate, &name, &nam_len, &value, &val_len, &has_predicate)) < 1)
2240 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002241 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
Michal Vaskof29903d2016-04-18 13:13:10 +02002242 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002243 }
2244
Michal Vasko53adfc72017-01-06 10:39:10 +01002245check_parsed_values:
Michal Vasko22448d32016-03-16 13:17:29 +01002246 predicate += r;
2247 *parsed += r;
2248
Michal Vaskof29903d2016-04-18 13:13:10 +02002249 if (strncmp(key->schema->name, name, nam_len) || key->schema->name[nam_len]) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002250 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002251 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002252 }
2253
Michal Vasko9ba34de2016-12-07 12:21:19 +01002254 /* make value canonical */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01002255 if ((key->value_type & LY_TYPE_IDENT)
Michal Vasko6a938d62016-12-21 09:21:30 +01002256 && !strncmp(key->value_str, lyd_node_module(node)->name, strlen(lyd_node_module(node)->name))
2257 && (key->value_str[strlen(lyd_node_module(node)->name)] == ':')) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002258 key_val = key->value_str + strlen(lyd_node_module(node)->name) + 1;
2259 } else {
2260 key_val = key->value_str;
2261 }
2262
Michal Vasko22448d32016-03-16 13:17:29 +01002263 /* value does not match */
Michal Vasko9ba34de2016-12-07 12:21:19 +01002264 if (strncmp(key_val, value, val_len) || key_val[val_len]) {
Michal Vasko22448d32016-03-16 13:17:29 +01002265 return 1;
2266 }
Michal Vaskof29903d2016-04-18 13:13:10 +02002267
2268 key = (struct lyd_node_leaf_list *)key->next;
Michal Vasko22448d32016-03-16 13:17:29 +01002269 }
2270
2271 if (has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002272 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko22448d32016-03-16 13:17:29 +01002273 return -1;
2274 }
2275
2276 return 0;
2277}
2278
Radek Krejci45826012016-08-24 15:07:57 +02002279/**
2280 * @brief get the closest parent of the node (or the node itself) identified by the nodeid (path)
2281 *
2282 * @param[in] nodeid Node data path to find
2283 * @param[in] llist_value If the \p nodeid identifies leaf-list, this is expected value of the leaf-list instance.
2284 * @param[in] options Bitmask of options flags, see @ref pathoptions.
2285 * @param[out] parsed Number of characters processed in \p id
2286 * @return The closes parent (or the node itself) from the path
2287 */
Michal Vasko22448d32016-03-16 13:17:29 +01002288struct lyd_node *
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002289resolve_partial_json_data_nodeid(const char *nodeid, const char *llist_value, struct lyd_node *start, int options,
2290 int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002291{
Michal Vasko10728b52016-04-07 14:26:29 +02002292 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko9ba34de2016-12-07 12:21:19 +01002293 const char *id, *mod_name, *name, *pred_name, *data_val;
Michal Vasko58c2aab2017-01-05 10:02:05 +01002294 int r, ret, mod_name_len, nam_len, is_relative = -1, list_instance_position;
Michal Vasko9ba34de2016-12-07 12:21:19 +01002295 int has_predicate, last_parsed, llval_len, pred_name_len, last_has_pred;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002296 struct lyd_node *sibling, *last_match = NULL;
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002297 struct lyd_node_leaf_list *llist;
Michal Vasko22448d32016-03-16 13:17:29 +01002298 const struct lys_module *prefix_mod, *prev_mod;
2299 struct ly_ctx *ctx;
2300
2301 assert(nodeid && start && parsed);
2302
2303 ctx = start->schema->module->ctx;
2304 id = nodeid;
2305
2306 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 +01002307 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002308 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002309 return NULL;
2310 }
2311 id += r;
2312 /* add it to parsed only after the data node was actually found */
2313 last_parsed = r;
2314
2315 if (is_relative) {
Michal Vasko1adc7242016-11-16 11:05:28 +01002316 prev_mod = lyd_node_module(start);
Michal Vasko22448d32016-03-16 13:17:29 +01002317 start = start->child;
2318 } else {
2319 for (; start->parent; start = start->parent);
Michal Vasko1adc7242016-11-16 11:05:28 +01002320 prev_mod = lyd_node_module(start);
Michal Vasko22448d32016-03-16 13:17:29 +01002321 }
2322
2323 while (1) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002324 list_instance_position = 0;
2325
Michal Vasko22448d32016-03-16 13:17:29 +01002326 LY_TREE_FOR(start, sibling) {
Michal Vasko945b96b2016-10-18 11:49:12 +02002327 /* RPC/action data check, return simply invalid argument, because the data tree is invalid */
Michal Vasko2411b942016-03-23 13:50:03 +01002328 if (lys_parent(sibling->schema)) {
2329 if (options & LYD_PATH_OPT_OUTPUT) {
2330 if (lys_parent(sibling->schema)->nodetype == LYS_INPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002331 LOGERR(LY_EINVAL, "Provided data tree includes some RPC input nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002332 *parsed = -1;
2333 return NULL;
2334 }
2335 } else {
2336 if (lys_parent(sibling->schema)->nodetype == LYS_OUTPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002337 LOGERR(LY_EINVAL, "Provided data tree includes some RPC output nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002338 *parsed = -1;
2339 return NULL;
2340 }
2341 }
2342 }
2343
Michal Vasko22448d32016-03-16 13:17:29 +01002344 /* name match */
2345 if (!strncmp(name, sibling->schema->name, nam_len) && !sibling->schema->name[nam_len]) {
2346
2347 /* module check */
2348 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002349 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko22448d32016-03-16 13:17:29 +01002350 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002351 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002352 return NULL;
2353 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002354
2355 if (ly_buf_used && module_name[0]) {
2356 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2357 }
2358 ly_buf_used++;
2359
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002360 memmove(module_name, mod_name, mod_name_len);
Michal Vasko22448d32016-03-16 13:17:29 +01002361 module_name[mod_name_len] = '\0';
2362 /* will also find an augment module */
2363 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002364
2365 if (buf_backup) {
2366 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002367 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002368 free(buf_backup);
2369 buf_backup = NULL;
2370 }
2371 ly_buf_used--;
2372
Michal Vasko22448d32016-03-16 13:17:29 +01002373 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002374 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2375 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2376 free(str);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002377 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002378 return NULL;
2379 }
2380 } else {
2381 prefix_mod = prev_mod;
2382 }
Michal Vasko1adc7242016-11-16 11:05:28 +01002383 if (prefix_mod != lyd_node_module(sibling)) {
Michal Vasko22448d32016-03-16 13:17:29 +01002384 continue;
2385 }
2386
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002387 /* leaf-list, did we find it with the correct value or not? */
Michal Vasko22448d32016-03-16 13:17:29 +01002388 if (sibling->schema->nodetype == LYS_LEAFLIST) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002389 llist = (struct lyd_node_leaf_list *)sibling;
2390
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002391 last_has_pred = 0;
Michal Vaskof0a50972016-10-19 11:33:55 +02002392 if (has_predicate) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002393 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 +02002394 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2395 *parsed = -1;
2396 return NULL;
2397 }
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002398 if ((pred_name[0] != '.') || (pred_name_len != 1)) {
2399 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[1], id + 1);
2400 *parsed = -1;
2401 return NULL;
2402 }
Michal Vaskof0a50972016-10-19 11:33:55 +02002403 } else {
2404 r = 0;
2405 if (llist_value) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002406 llval_len = strlen(llist_value);
Michal Vaskof0a50972016-10-19 11:33:55 +02002407 }
2408 }
2409
Michal Vasko9ba34de2016-12-07 12:21:19 +01002410 /* make value canonical */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01002411 if ((llist->value_type & LY_TYPE_IDENT)
Michal Vasko6a938d62016-12-21 09:21:30 +01002412 && !strncmp(llist->value_str, lyd_node_module(sibling)->name, strlen(lyd_node_module(sibling)->name))
2413 && (llist->value_str[strlen(lyd_node_module(sibling)->name)] == ':')) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002414 data_val = llist->value_str + strlen(lyd_node_module(sibling)->name) + 1;
2415 } else {
2416 data_val = llist->value_str;
2417 }
2418
2419 if ((!llist_value && data_val && data_val[0])
2420 || (llist_value && (strncmp(llist_value, data_val, llval_len) || data_val[llval_len]))) {
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002421 continue;
2422 }
Michal Vasko9ba34de2016-12-07 12:21:19 +01002423
Michal Vaskof0a50972016-10-19 11:33:55 +02002424 id += r;
2425 last_parsed += r;
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002426 has_predicate = last_has_pred;
Michal Vaskof0a50972016-10-19 11:33:55 +02002427
Radek Krejci45826012016-08-24 15:07:57 +02002428 } else if (sibling->schema->nodetype == LYS_LIST) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002429 /* 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 +01002430 if (!has_predicate) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002431 /* none match */
2432 return last_match;
Michal Vasko22448d32016-03-16 13:17:29 +01002433 }
Michal Vasko58c2aab2017-01-05 10:02:05 +01002434
2435 ++list_instance_position;
2436 r = 0;
2437 ret = resolve_partial_json_data_list_predicate(id, name, sibling, list_instance_position, &r);
Michal Vasko22448d32016-03-16 13:17:29 +01002438 if (ret == -1) {
Michal Vasko238bd2f2016-03-23 09:39:01 +01002439 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002440 return NULL;
2441 } else if (ret == 1) {
2442 /* this list instance does not match */
2443 continue;
2444 }
2445 id += r;
2446 last_parsed += r;
2447 }
2448
2449 *parsed += last_parsed;
2450
2451 /* the result node? */
2452 if (!id[0]) {
2453 return sibling;
2454 }
2455
2456 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002457 if (sibling->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002458 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002459 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002460 return NULL;
2461 }
Michal Vaskoc6c52cf2016-03-29 11:53:04 +02002462 last_match = sibling;
Michal Vaskofc11b682016-11-18 09:52:41 +01002463 prev_mod = lyd_node_module(sibling);
Michal Vasko22448d32016-03-16 13:17:29 +01002464 start = sibling->child;
Michal Vasko22448d32016-03-16 13:17:29 +01002465 break;
2466 }
2467 }
2468
2469 /* no match, return last match */
2470 if (!sibling) {
2471 return last_match;
2472 }
2473
2474 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 +01002475 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002476 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002477 return NULL;
2478 }
2479 id += r;
2480 last_parsed = r;
2481 }
2482
2483 /* cannot get here */
2484 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002485 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002486 return NULL;
2487}
2488
Michal Vasko3edeaf72016-02-11 13:17:43 +01002489/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02002490 * @brief Resolves length or range intervals. Does not log.
Michal Vaskoaeb51802016-04-11 10:58:47 +02002491 * Syntax is assumed to be correct, *ret MUST be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002492 *
Michal Vaskoaeb51802016-04-11 10:58:47 +02002493 * @param[in] str_restr Restriction as a string.
2494 * @param[in] type Type of the restriction.
2495 * @param[out] ret Final interval structure that starts with
2496 * the interval of the initial type, continues with intervals
2497 * of any superior types derived from the initial one, and
2498 * finishes with intervals from our \p type.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002499 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002500 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002501 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002502int
Michal Vaskoaeb51802016-04-11 10:58:47 +02002503resolve_len_ran_interval(const char *str_restr, struct lys_type *type, struct len_ran_intv **ret)
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002504{
2505 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002506 int kind;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002507 int64_t local_smin, local_smax, local_fmin, local_fmax;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002508 uint64_t local_umin, local_umax;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002509 uint8_t local_fdig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002510 const char *seg_ptr, *ptr;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002511 struct len_ran_intv *local_intv = NULL, *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002512
2513 switch (type->base) {
2514 case LY_TYPE_BINARY:
2515 kind = 0;
2516 local_umin = 0;
2517 local_umax = 18446744073709551615UL;
2518
2519 if (!str_restr && type->info.binary.length) {
2520 str_restr = type->info.binary.length->expr;
2521 }
2522 break;
2523 case LY_TYPE_DEC64:
2524 kind = 2;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002525 local_fmin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2526 local_fmax = __INT64_C(9223372036854775807);
2527 local_fdig = type->info.dec64.dig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002528
2529 if (!str_restr && type->info.dec64.range) {
2530 str_restr = type->info.dec64.range->expr;
2531 }
2532 break;
2533 case LY_TYPE_INT8:
2534 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002535 local_smin = __INT64_C(-128);
2536 local_smax = __INT64_C(127);
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_INT16:
2543 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002544 local_smin = __INT64_C(-32768);
2545 local_smax = __INT64_C(32767);
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_INT32:
2552 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002553 local_smin = __INT64_C(-2147483648);
2554 local_smax = __INT64_C(2147483647);
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_INT64:
2561 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002562 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2563 local_smax = __INT64_C(9223372036854775807);
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_UINT8:
2570 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002571 local_umin = __UINT64_C(0);
2572 local_umax = __UINT64_C(255);
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_UINT16:
2579 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002580 local_umin = __UINT64_C(0);
2581 local_umax = __UINT64_C(65535);
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_UINT32:
2588 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002589 local_umin = __UINT64_C(0);
2590 local_umax = __UINT64_C(4294967295);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002591
2592 if (!str_restr && type->info.num.range) {
2593 str_restr = type->info.num.range->expr;
2594 }
2595 break;
2596 case LY_TYPE_UINT64:
2597 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002598 local_umin = __UINT64_C(0);
2599 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002600
2601 if (!str_restr && type->info.num.range) {
2602 str_restr = type->info.num.range->expr;
2603 }
2604 break;
2605 case LY_TYPE_STRING:
2606 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002607 local_umin = __UINT64_C(0);
2608 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002609
2610 if (!str_restr && type->info.str.length) {
2611 str_restr = type->info.str.length->expr;
2612 }
2613 break;
2614 default:
2615 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002616 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002617 }
2618
2619 /* process superior types */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002620 if (type->der) {
2621 if (resolve_len_ran_interval(NULL, &type->der->type, &intv)) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002622 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002623 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02002624 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002625 assert(!intv || (intv->kind == kind));
2626 }
2627
2628 if (!str_restr) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002629 /* we do not have any restriction, return superior ones */
2630 *ret = intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002631 return EXIT_SUCCESS;
2632 }
2633
2634 /* adjust local min and max */
2635 if (intv) {
2636 tmp_intv = intv;
2637
2638 if (kind == 0) {
2639 local_umin = tmp_intv->value.uval.min;
2640 } else if (kind == 1) {
2641 local_smin = tmp_intv->value.sval.min;
2642 } else if (kind == 2) {
2643 local_fmin = tmp_intv->value.fval.min;
2644 }
2645
2646 while (tmp_intv->next) {
2647 tmp_intv = tmp_intv->next;
2648 }
2649
2650 if (kind == 0) {
2651 local_umax = tmp_intv->value.uval.max;
2652 } else if (kind == 1) {
2653 local_smax = tmp_intv->value.sval.max;
2654 } else if (kind == 2) {
2655 local_fmax = tmp_intv->value.fval.max;
2656 }
2657 }
2658
2659 /* finally parse our restriction */
2660 seg_ptr = str_restr;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002661 tmp_intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002662 while (1) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002663 if (!tmp_local_intv) {
2664 assert(!local_intv);
2665 local_intv = malloc(sizeof *local_intv);
2666 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002667 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002668 tmp_local_intv->next = malloc(sizeof *tmp_local_intv);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002669 tmp_local_intv = tmp_local_intv->next;
2670 }
Michal Vasko253035f2015-12-17 16:58:13 +01002671 if (!tmp_local_intv) {
2672 LOGMEM;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002673 goto error;
Michal Vasko253035f2015-12-17 16:58:13 +01002674 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002675
2676 tmp_local_intv->kind = kind;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002677 tmp_local_intv->type = type;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002678 tmp_local_intv->next = NULL;
2679
2680 /* min */
2681 ptr = seg_ptr;
2682 while (isspace(ptr[0])) {
2683 ++ptr;
2684 }
2685 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2686 if (kind == 0) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002687 tmp_local_intv->value.uval.min = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002688 } else if (kind == 1) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002689 tmp_local_intv->value.sval.min = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002690 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002691 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.min)) {
2692 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2693 goto error;
2694 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002695 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002696 } else if (!strncmp(ptr, "min", 3)) {
2697 if (kind == 0) {
2698 tmp_local_intv->value.uval.min = local_umin;
2699 } else if (kind == 1) {
2700 tmp_local_intv->value.sval.min = local_smin;
2701 } else if (kind == 2) {
2702 tmp_local_intv->value.fval.min = local_fmin;
2703 }
2704
2705 ptr += 3;
2706 } else if (!strncmp(ptr, "max", 3)) {
2707 if (kind == 0) {
2708 tmp_local_intv->value.uval.min = local_umax;
2709 } else if (kind == 1) {
2710 tmp_local_intv->value.sval.min = local_smax;
2711 } else if (kind == 2) {
2712 tmp_local_intv->value.fval.min = local_fmax;
2713 }
2714
2715 ptr += 3;
2716 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002717 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002718 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002719 }
2720
2721 while (isspace(ptr[0])) {
2722 ptr++;
2723 }
2724
2725 /* no interval or interval */
2726 if ((ptr[0] == '|') || !ptr[0]) {
2727 if (kind == 0) {
2728 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
2729 } else if (kind == 1) {
2730 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
2731 } else if (kind == 2) {
2732 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
2733 }
2734 } else if (!strncmp(ptr, "..", 2)) {
2735 /* skip ".." */
2736 ptr += 2;
2737 while (isspace(ptr[0])) {
2738 ++ptr;
2739 }
2740
2741 /* max */
2742 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2743 if (kind == 0) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002744 tmp_local_intv->value.uval.max = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002745 } else if (kind == 1) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002746 tmp_local_intv->value.sval.max = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002747 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002748 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.max)) {
2749 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2750 goto error;
2751 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002752 }
2753 } else if (!strncmp(ptr, "max", 3)) {
2754 if (kind == 0) {
2755 tmp_local_intv->value.uval.max = local_umax;
2756 } else if (kind == 1) {
2757 tmp_local_intv->value.sval.max = local_smax;
2758 } else if (kind == 2) {
2759 tmp_local_intv->value.fval.max = local_fmax;
2760 }
2761 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002762 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002763 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002764 }
2765 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002766 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002767 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002768 }
2769
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002770 /* check min and max in correct order*/
2771 if (kind == 0) {
2772 /* current segment */
2773 if (tmp_local_intv->value.uval.min > tmp_local_intv->value.uval.max) {
2774 goto error;
2775 }
2776 if (tmp_local_intv->value.uval.min < local_umin || tmp_local_intv->value.uval.max > local_umax) {
2777 goto error;
2778 }
2779 /* segments sholud be ascending order */
Pavol Vican69f62c92016-08-30 09:06:25 +02002780 if (tmp_intv && (tmp_intv->value.uval.max >= tmp_local_intv->value.uval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002781 goto error;
2782 }
2783 } else if (kind == 1) {
2784 if (tmp_local_intv->value.sval.min > tmp_local_intv->value.sval.max) {
2785 goto error;
2786 }
2787 if (tmp_local_intv->value.sval.min < local_smin || tmp_local_intv->value.sval.max > local_smax) {
2788 goto error;
2789 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002790 if (tmp_intv && (tmp_intv->value.sval.max >= tmp_local_intv->value.sval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002791 goto error;
2792 }
2793 } else if (kind == 2) {
2794 if (tmp_local_intv->value.fval.min > tmp_local_intv->value.fval.max) {
2795 goto error;
2796 }
2797 if (tmp_local_intv->value.fval.min < local_fmin || tmp_local_intv->value.fval.max > local_fmax) {
2798 goto error;
2799 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002800 if (tmp_intv && (tmp_intv->value.fval.max >= tmp_local_intv->value.fval.min)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002801 /* fraction-digits value is always the same (it cannot be changed in derived types) */
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002802 goto error;
2803 }
2804 }
2805
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002806 /* next segment (next OR) */
2807 seg_ptr = strchr(seg_ptr, '|');
2808 if (!seg_ptr) {
2809 break;
2810 }
2811 seg_ptr++;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002812 tmp_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002813 }
2814
2815 /* check local restrictions against superior ones */
2816 if (intv) {
2817 tmp_intv = intv;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002818 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002819
2820 while (tmp_local_intv && tmp_intv) {
2821 /* reuse local variables */
2822 if (kind == 0) {
2823 local_umin = tmp_local_intv->value.uval.min;
2824 local_umax = tmp_local_intv->value.uval.max;
2825
2826 /* it must be in this interval */
2827 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
2828 /* this interval is covered, next one */
2829 if (local_umax <= tmp_intv->value.uval.max) {
2830 tmp_local_intv = tmp_local_intv->next;
2831 continue;
2832 /* ascending order of restrictions -> fail */
2833 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002834 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002835 }
2836 }
2837 } else if (kind == 1) {
2838 local_smin = tmp_local_intv->value.sval.min;
2839 local_smax = tmp_local_intv->value.sval.max;
2840
2841 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
2842 if (local_smax <= tmp_intv->value.sval.max) {
2843 tmp_local_intv = tmp_local_intv->next;
2844 continue;
2845 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002846 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002847 }
2848 }
2849 } else if (kind == 2) {
2850 local_fmin = tmp_local_intv->value.fval.min;
2851 local_fmax = tmp_local_intv->value.fval.max;
2852
Michal Vasko4d1f0482016-09-19 14:35:06 +02002853 if ((dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.min, local_fdig) > -1)
Pavol Vican3c8ee2b2016-09-29 13:18:13 +02002854 && (dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002855 if (dec64cmp(local_fmax, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002856 tmp_local_intv = tmp_local_intv->next;
2857 continue;
2858 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002859 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002860 }
2861 }
2862 }
2863
2864 tmp_intv = tmp_intv->next;
2865 }
2866
2867 /* some interval left uncovered -> fail */
2868 if (tmp_local_intv) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002869 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002870 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002871 }
2872
Michal Vaskoaeb51802016-04-11 10:58:47 +02002873 /* append the local intervals to all the intervals of the superior types, return it all */
2874 if (intv) {
2875 for (tmp_intv = intv; tmp_intv->next; tmp_intv = tmp_intv->next);
2876 tmp_intv->next = local_intv;
2877 } else {
2878 intv = local_intv;
2879 }
2880 *ret = intv;
2881
2882 return EXIT_SUCCESS;
2883
2884error:
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002885 while (intv) {
2886 tmp_intv = intv->next;
2887 free(intv);
2888 intv = tmp_intv;
2889 }
Michal Vaskoaeb51802016-04-11 10:58:47 +02002890 while (local_intv) {
2891 tmp_local_intv = local_intv->next;
2892 free(local_intv);
2893 local_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002894 }
2895
Michal Vaskoaeb51802016-04-11 10:58:47 +02002896 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002897}
2898
Michal Vasko730dfdf2015-08-11 14:48:05 +02002899/**
Michal Vasko01c6fd22016-05-20 11:43:05 +02002900 * @brief Resolve a typedef, return only resolved typedefs if derived. If leafref, it must be
2901 * resolved for this function to return it. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002902 *
2903 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02002904 * @param[in] mod_name Typedef name module name.
2905 * @param[in] module Main module.
2906 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002907 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002908 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002909 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002910 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002911int
Michal Vasko1e62a092015-12-01 12:27:20 +01002912resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
2913 const struct lys_node *parent, struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002914{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002915 int i, j;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002916 struct lys_tpdf *tpdf, *match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002917 int tpdf_size;
2918
Michal Vasko1dca6882015-10-22 14:29:42 +02002919 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002920 /* no prefix, try built-in types */
2921 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
2922 if (!strcmp(ly_types[i].def->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002923 if (ret) {
2924 *ret = ly_types[i].def;
2925 }
2926 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002927 }
2928 }
2929 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02002930 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002931 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02002932 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002933 }
2934 }
2935
Michal Vasko1dca6882015-10-22 14:29:42 +02002936 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002937 /* search in local typedefs */
2938 while (parent) {
2939 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02002940 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02002941 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
2942 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002943 break;
2944
Radek Krejci76512572015-08-04 09:47:08 +02002945 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02002946 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
2947 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002948 break;
2949
Radek Krejci76512572015-08-04 09:47:08 +02002950 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02002951 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
2952 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002953 break;
2954
Radek Krejci76512572015-08-04 09:47:08 +02002955 case LYS_RPC:
Michal Vasko44fb6382016-06-29 11:12:27 +02002956 case LYS_ACTION:
2957 tpdf_size = ((struct lys_node_rpc_action *)parent)->tpdf_size;
2958 tpdf = ((struct lys_node_rpc_action *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002959 break;
2960
Radek Krejci76512572015-08-04 09:47:08 +02002961 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02002962 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
2963 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002964 break;
2965
Radek Krejci76512572015-08-04 09:47:08 +02002966 case LYS_INPUT:
2967 case LYS_OUTPUT:
Michal Vasko44fb6382016-06-29 11:12:27 +02002968 tpdf_size = ((struct lys_node_inout *)parent)->tpdf_size;
2969 tpdf = ((struct lys_node_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002970 break;
2971
2972 default:
Michal Vaskodcf98e62016-05-05 17:53:53 +02002973 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002974 continue;
2975 }
2976
2977 for (i = 0; i < tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002978 if (!strcmp(tpdf[i].name, name) && tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002979 match = &tpdf[i];
2980 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002981 }
2982 }
2983
Michal Vaskodcf98e62016-05-05 17:53:53 +02002984 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002985 }
Radek Krejcic071c542016-01-27 14:57:51 +01002986 } else {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002987 /* get module where to search */
Michal Vaskob6729c62015-10-21 12:09:47 +02002988 module = lys_get_import_module(module, NULL, 0, mod_name, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02002989 if (!module) {
2990 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002991 }
2992 }
2993
2994 /* search in top level typedefs */
2995 for (i = 0; i < module->tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002996 if (!strcmp(module->tpdf[i].name, name) && module->tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002997 match = &module->tpdf[i];
2998 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002999 }
3000 }
3001
3002 /* search in submodules */
Radek Krejcic071c542016-01-27 14:57:51 +01003003 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003004 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
Radek Krejcic13db382016-08-16 10:52:42 +02003005 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 +02003006 match = &module->inc[i].submodule->tpdf[j];
3007 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003008 }
3009 }
3010 }
3011
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003012 return EXIT_FAILURE;
Michal Vasko01c6fd22016-05-20 11:43:05 +02003013
3014check_leafref:
3015 if (ret) {
3016 *ret = match;
3017 }
3018 if (match->type.base == LY_TYPE_LEAFREF) {
3019 while (!match->type.info.lref.path) {
3020 match = match->type.der;
3021 assert(match);
3022 }
Michal Vasko01c6fd22016-05-20 11:43:05 +02003023 }
3024 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003025}
3026
Michal Vasko1dca6882015-10-22 14:29:42 +02003027/**
3028 * @brief Check the default \p value of the \p type. Logs directly.
3029 *
3030 * @param[in] type Type definition to use.
3031 * @param[in] value Default value to check.
Michal Vasko56826402016-03-02 11:11:37 +01003032 * @param[in] module Type module.
Michal Vasko1dca6882015-10-22 14:29:42 +02003033 *
3034 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3035 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003036static int
Radek Krejci51673202016-11-01 17:00:32 +01003037check_default(struct lys_type *type, const char **value, struct lys_module *module)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003038{
Radek Krejcibad2f172016-08-02 11:04:15 +02003039 struct lys_tpdf *base_tpdf = NULL;
Michal Vasko1dca6882015-10-22 14:29:42 +02003040 struct lyd_node_leaf_list node;
Radek Krejci51673202016-11-01 17:00:32 +01003041 const char *dflt = NULL;
Radek Krejci37b756f2016-01-18 10:15:03 +01003042 int ret = EXIT_SUCCESS;
Michal Vasko1dca6882015-10-22 14:29:42 +02003043
Radek Krejci51673202016-11-01 17:00:32 +01003044 assert(value);
3045
Radek Krejcic13db382016-08-16 10:52:42 +02003046 if (type->base <= LY_TYPE_DER) {
Michal Vasko478c4652016-07-21 12:55:01 +02003047 /* the type was not resolved yet, nothing to do for now */
3048 return EXIT_FAILURE;
3049 }
3050
Radek Krejci51673202016-11-01 17:00:32 +01003051 dflt = *value;
3052 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003053 /* we do not have a new default value, so is there any to check even, in some base type? */
3054 for (base_tpdf = type->der; base_tpdf->type.der; base_tpdf = base_tpdf->type.der) {
3055 if (base_tpdf->dflt) {
Radek Krejci51673202016-11-01 17:00:32 +01003056 dflt = base_tpdf->dflt;
Michal Vasko478c4652016-07-21 12:55:01 +02003057 break;
3058 }
3059 }
3060
Radek Krejci51673202016-11-01 17:00:32 +01003061 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003062 /* no default value, nothing to check, all is well */
3063 return EXIT_SUCCESS;
3064 }
3065
3066 /* 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)? */
3067 switch (type->base) {
Michal Vasko478c4652016-07-21 12:55:01 +02003068 case LY_TYPE_IDENT:
3069 case LY_TYPE_INST:
3070 case LY_TYPE_LEAFREF:
3071 case LY_TYPE_BOOL:
3072 case LY_TYPE_EMPTY:
3073 /* these have no restrictions, so we would do the exact same work as the unres in the base typedef */
3074 return EXIT_SUCCESS;
Radek Krejcibad2f172016-08-02 11:04:15 +02003075 case LY_TYPE_BITS:
3076 /* the default value must match the restricted list of values, if the type was restricted */
3077 if (type->info.bits.count) {
3078 break;
3079 }
3080 return EXIT_SUCCESS;
3081 case LY_TYPE_ENUM:
3082 /* the default value must match the restricted list of values, if the type was restricted */
3083 if (type->info.enums.count) {
3084 break;
3085 }
3086 return EXIT_SUCCESS;
Michal Vasko478c4652016-07-21 12:55:01 +02003087 case LY_TYPE_DEC64:
3088 if (type->info.dec64.range) {
3089 break;
3090 }
3091 return EXIT_SUCCESS;
3092 case LY_TYPE_BINARY:
3093 if (type->info.binary.length) {
3094 break;
3095 }
3096 return EXIT_SUCCESS;
3097 case LY_TYPE_INT8:
3098 case LY_TYPE_INT16:
3099 case LY_TYPE_INT32:
3100 case LY_TYPE_INT64:
3101 case LY_TYPE_UINT8:
3102 case LY_TYPE_UINT16:
3103 case LY_TYPE_UINT32:
3104 case LY_TYPE_UINT64:
3105 if (type->info.num.range) {
3106 break;
3107 }
3108 return EXIT_SUCCESS;
3109 case LY_TYPE_STRING:
3110 if (type->info.str.length || type->info.str.patterns) {
3111 break;
3112 }
3113 return EXIT_SUCCESS;
3114 case LY_TYPE_UNION:
3115 /* way too much trouble learning whether we need to check the default again, so just do it */
3116 break;
3117 default:
3118 LOGINT;
3119 return -1;
3120 }
Radek Krejci55a161c2016-09-05 17:13:25 +02003121 } else if (type->base == LY_TYPE_EMPTY) {
3122 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "default", type->parent->name);
3123 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"empty\" data type cannot have a default value.");
3124 return -1;
Michal Vasko478c4652016-07-21 12:55:01 +02003125 }
3126
Michal Vasko1dca6882015-10-22 14:29:42 +02003127 /* dummy leaf */
Radek Krejci4fe36bd2016-03-17 16:47:16 +01003128 memset(&node, 0, sizeof node);
Radek Krejci51673202016-11-01 17:00:32 +01003129 node.value_str = dflt;
Michal Vasko1dca6882015-10-22 14:29:42 +02003130 node.value_type = type->base;
Radek Krejci37b756f2016-01-18 10:15:03 +01003131 node.schema = calloc(1, sizeof (struct lys_node_leaf));
Michal Vasko253035f2015-12-17 16:58:13 +01003132 if (!node.schema) {
3133 LOGMEM;
3134 return -1;
3135 }
Radek Krejcibad2f172016-08-02 11:04:15 +02003136 node.schema->name = strdup("fake-default");
Michal Vasko253035f2015-12-17 16:58:13 +01003137 if (!node.schema->name) {
3138 LOGMEM;
Michal Vaskof49eda02016-07-21 12:17:01 +02003139 free(node.schema);
Michal Vasko253035f2015-12-17 16:58:13 +01003140 return -1;
3141 }
Michal Vasko56826402016-03-02 11:11:37 +01003142 node.schema->module = module;
Radek Krejci37b756f2016-01-18 10:15:03 +01003143 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
Michal Vasko1dca6882015-10-22 14:29:42 +02003144
Radek Krejci37b756f2016-01-18 10:15:03 +01003145 if (type->base == LY_TYPE_LEAFREF) {
Michal Vasko1dca6882015-10-22 14:29:42 +02003146 if (!type->info.lref.target) {
3147 ret = EXIT_FAILURE;
3148 goto finish;
3149 }
Radek Krejci51673202016-11-01 17:00:32 +01003150 ret = check_default(&type->info.lref.target->type, &dflt, module);
3151 if (!ret) {
3152 /* adopt possibly changed default value to its canonical form */
3153 if (*value) {
3154 *value = dflt;
3155 }
3156 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003157 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01003158 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 +01003159 /* possible forward reference */
3160 ret = 1;
Radek Krejcibad2f172016-08-02 11:04:15 +02003161 if (base_tpdf) {
Radek Krejci9ad23f42016-10-31 15:46:52 +01003162 /* default value is defined in some base typedef */
Radek Krejcibad2f172016-08-02 11:04:15 +02003163 if ((type->base == LY_TYPE_BITS && type->der->type.der) ||
3164 (type->base == LY_TYPE_ENUM && type->der->type.der)) {
3165 /* we have refined bits/enums */
3166 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
3167 "Invalid value \"%s\" of the default statement inherited to \"%s\" from \"%s\" base type.",
Radek Krejci51673202016-11-01 17:00:32 +01003168 dflt, type->parent->name, base_tpdf->name);
Radek Krejcibad2f172016-08-02 11:04:15 +02003169 }
3170 }
Radek Krejci51673202016-11-01 17:00:32 +01003171 } else {
3172 /* success - adopt canonical form from the node into the default value */
3173 if (dflt != node.value_str) {
3174 /* this can happen only if we have non-inherited default value,
3175 * inherited default values are already in canonical form */
3176 assert(dflt == *value);
3177 *value = node.value_str;
3178 }
Michal Vasko3767fb22016-07-21 12:10:57 +02003179 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003180 }
3181
3182finish:
3183 if (node.value_type == LY_TYPE_BITS) {
3184 free(node.value.bit);
3185 }
3186 free((char *)node.schema->name);
3187 free(node.schema);
3188
3189 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003190}
3191
Michal Vasko730dfdf2015-08-11 14:48:05 +02003192/**
3193 * @brief Check a key for mandatory attributes. Logs directly.
3194 *
3195 * @param[in] key The key to check.
3196 * @param[in] flags What flags to check.
3197 * @param[in] list The list of all the keys.
3198 * @param[in] index Index of the key in the key list.
3199 * @param[in] name The name of the keys.
3200 * @param[in] len The name length.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003201 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003202 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003203 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003204static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003205check_key(struct lys_node_list *list, int index, const char *name, int len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003206{
Radek Krejciadb57612016-02-16 13:34:34 +01003207 struct lys_node_leaf *key = list->keys[index];
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003208 char *dup = NULL;
3209 int j;
3210
3211 /* existence */
3212 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02003213 if (name[len] != '\0') {
3214 dup = strdup(name);
Michal Vasko253035f2015-12-17 16:58:13 +01003215 if (!dup) {
3216 LOGMEM;
3217 return -1;
3218 }
Michal Vaskof02e3742015-08-05 16:27:02 +02003219 dup[len] = '\0';
3220 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003221 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003222 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, list, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003223 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003224 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003225 }
3226
3227 /* uniqueness */
3228 for (j = index - 1; j >= 0; j--) {
Radek Krejciadb57612016-02-16 13:34:34 +01003229 if (key == list->keys[j]) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003230 LOGVAL(LYE_KEY_DUP, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003231 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003232 }
3233 }
3234
3235 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02003236 if (key->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003237 LOGVAL(LYE_KEY_NLEAF, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003238 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003239 }
3240
3241 /* type of the leaf is not built-in empty */
Radek Krejcic3738db2016-09-15 15:51:21 +02003242 if (key->type.base == LY_TYPE_EMPTY && key->module->version < 2) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003243 LOGVAL(LYE_KEY_TYPE, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003244 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003245 }
3246
3247 /* config attribute is the same as of the list */
Radek Krejci5c08a992016-11-02 13:30:04 +01003248 if ((key->flags & LYS_CONFIG_MASK) && (list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003249 LOGVAL(LYE_KEY_CONFIG, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003250 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003251 }
3252
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003253 /* key is not placed from augment */
3254 if (key->parent->nodetype == LYS_AUGMENT) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003255 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, key, key->name);
3256 LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key inserted from augment.");
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003257 return -1;
3258 }
3259
Radek Krejci3f21ada2016-08-01 13:34:31 +02003260 /* key is not when/if-feature -conditional */
3261 j = 0;
3262 if (key->when || (key->iffeature_size && (j = 1))) {
3263 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, key, j ? "if-feature" : "when", "leaf");
3264 LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key definition cannot depend on a \"%s\" condition.",
3265 j ? "if-feature" : "when");
Radek Krejci581ce772015-11-10 17:22:40 +01003266 return -1;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003267 }
3268
Michal Vasko0b85aa82016-03-07 14:37:43 +01003269 return EXIT_SUCCESS;
Michal Vasko184521f2015-09-24 13:14:26 +02003270}
Michal Vasko730dfdf2015-08-11 14:48:05 +02003271
3272/**
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003273 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003274 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003275 * @param[in] parent The parent node of the unique structure.
Michal Vasko0b85aa82016-03-07 14:37:43 +01003276 * @param[in] uniq_str_path One path from the unique string.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003277 *
3278 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
3279 */
3280int
Radek Krejcid09d1a52016-08-11 14:05:45 +02003281resolve_unique(struct lys_node *parent, const char *uniq_str_path, uint8_t *trg_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003282{
Radek Krejci581ce772015-11-10 17:22:40 +01003283 int rc;
Michal Vasko1e62a092015-12-01 12:27:20 +01003284 const struct lys_node *leaf = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003285
Radek Krejcif3c71de2016-04-11 12:45:46 +02003286 rc = resolve_descendant_schema_nodeid(uniq_str_path, parent->child, LYS_LEAF, 1, 1, &leaf);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003287 if (rc || !leaf) {
Michal Vasko0b85aa82016-03-07 14:37:43 +01003288 if (rc) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003289 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003290 if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003291 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, parent, uniq_str_path[rc - 1], &uniq_str_path[rc - 1]);
Radek Krejcif3c71de2016-04-11 12:45:46 +02003292 } else if (rc == -2) {
Michal Vaskoc66c6d82016-04-12 11:37:31 +02003293 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Unique argument references list.");
Radek Krejci581ce772015-11-10 17:22:40 +01003294 }
Michal Vasko0b85aa82016-03-07 14:37:43 +01003295 rc = -1;
Michal Vasko0b85aa82016-03-07 14:37:43 +01003296 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01003297 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3298 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target leaf not found.");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003299 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003300 }
Radek Krejci581ce772015-11-10 17:22:40 +01003301 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003302 }
Michal Vasko9bb061b2016-02-12 11:00:19 +01003303 if (leaf->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003304 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3305 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target is not a leaf.");
Radek Krejcid09d1a52016-08-11 14:05:45 +02003306 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003307 }
3308
Radek Krejcicf509982015-12-15 09:22:44 +01003309 /* check status */
Radek Krejci48464ed2016-03-17 15:44:09 +01003310 if (lyp_check_status(parent->flags, parent->module, parent->name, leaf->flags, leaf->module, leaf->name, leaf)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003311 return -1;
3312 }
3313
Radek Krejcid09d1a52016-08-11 14:05:45 +02003314 /* check that all unique's targets are of the same config type */
3315 if (*trg_type) {
3316 if (((*trg_type == 1) && (leaf->flags & LYS_CONFIG_R)) || ((*trg_type == 2) && (leaf->flags & LYS_CONFIG_W))) {
3317 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3318 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent,
3319 "Leaf \"%s\" referenced in unique statement is config %s, but previous referenced leaf is config %s.",
3320 uniq_str_path, *trg_type == 1 ? "false" : "true", *trg_type == 1 ? "true" : "false");
3321 return -1;
3322 }
3323 } else {
3324 /* first unique */
3325 if (leaf->flags & LYS_CONFIG_W) {
3326 *trg_type = 1;
3327 } else {
3328 *trg_type = 2;
3329 }
3330 }
3331
Radek Krejcica7efb72016-01-18 13:06:01 +01003332 /* set leaf's unique flag */
3333 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
3334
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003335 return EXIT_SUCCESS;
3336
3337error:
3338
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003339 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003340}
3341
Radek Krejci0c0086a2016-03-24 15:20:28 +01003342void
Michal Vasko23b61ec2015-08-19 11:19:50 +02003343unres_data_del(struct unres_data *unres, uint32_t i)
3344{
3345 /* there are items after the one deleted */
3346 if (i+1 < unres->count) {
3347 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02003348 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003349
3350 /* deleting the last item */
3351 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02003352 free(unres->node);
3353 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003354 }
3355
3356 /* if there are no items after and it is not the last one, just move the counter */
3357 --unres->count;
3358}
3359
Michal Vasko0491ab32015-08-19 14:28:29 +02003360/**
3361 * @brief Resolve (find) a data node from a specific module. Does not log.
3362 *
3363 * @param[in] mod Module to search in.
3364 * @param[in] name Name of the data node.
3365 * @param[in] nam_len Length of the name.
3366 * @param[in] start Data node to start the search from.
3367 * @param[in,out] parents Resolved nodes. If there are some parents,
3368 * they are replaced (!!) with the resolvents.
3369 *
Michal Vasko2471e7f2016-04-11 11:00:15 +02003370 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko0491ab32015-08-19 14:28:29 +02003371 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003372static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003373resolve_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 +02003374{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003375 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02003376 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003377 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003378
Michal Vasko23b61ec2015-08-19 11:19:50 +02003379 if (!parents->count) {
3380 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003381 parents->node = malloc(sizeof *parents->node);
Michal Vasko253035f2015-12-17 16:58:13 +01003382 if (!parents->node) {
3383 LOGMEM;
Michal Vasko2471e7f2016-04-11 11:00:15 +02003384 return -1;
Michal Vasko253035f2015-12-17 16:58:13 +01003385 }
Michal Vaskocf024702015-10-08 15:01:42 +02003386 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003387 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003388 for (i = 0; i < parents->count;) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02003389 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003390 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003391 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003392 continue;
3393 }
3394 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02003395 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003396 if (node->schema->module == mod && !strncmp(node->schema->name, name, nam_len)
3397 && node->schema->name[nam_len] == '\0') {
3398 /* matching target */
3399 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02003400 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02003401 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003402 flag = 1;
3403 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02003404 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003405 ++parents->count;
Michal Vasko253035f2015-12-17 16:58:13 +01003406 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
3407 if (!parents->node) {
3408 return EXIT_FAILURE;
3409 }
Michal Vaskocf024702015-10-08 15:01:42 +02003410 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003411 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003412 }
3413 }
3414 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003415
3416 if (!flag) {
3417 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003418 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02003419 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003420 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02003421 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003422 }
3423
Michal Vasko0491ab32015-08-19 14:28:29 +02003424 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02003425}
3426
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003427/**
3428 * @brief Resolve (find) a data node. Does not log.
3429 *
Radek Krejci581ce772015-11-10 17:22:40 +01003430 * @param[in] mod_name Module name of the data node.
3431 * @param[in] mod_name_len Length of the module name.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003432 * @param[in] name Name of the data node.
3433 * @param[in] nam_len Length of the name.
3434 * @param[in] start Data node to start the search from.
3435 * @param[in,out] parents Resolved nodes. If there are some parents,
3436 * they are replaced (!!) with the resolvents.
3437 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003438 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003439 */
Radek Krejcic5090c32015-08-12 09:46:19 +02003440static int
Radek Krejci581ce772015-11-10 17:22:40 +01003441resolve_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 +02003442 struct unres_data *parents)
Radek Krejcic5090c32015-08-12 09:46:19 +02003443{
Michal Vasko1e62a092015-12-01 12:27:20 +01003444 const struct lys_module *mod;
Michal Vasko31fc3672015-10-21 12:08:13 +02003445 char *str;
Radek Krejcic5090c32015-08-12 09:46:19 +02003446
Michal Vasko23b61ec2015-08-19 11:19:50 +02003447 assert(start);
3448
Michal Vasko31fc3672015-10-21 12:08:13 +02003449 if (mod_name) {
3450 /* we have mod_name, find appropriate module */
3451 str = strndup(mod_name, mod_name_len);
Michal Vasko253035f2015-12-17 16:58:13 +01003452 if (!str) {
3453 LOGMEM;
3454 return -1;
3455 }
Michal Vasko31fc3672015-10-21 12:08:13 +02003456 mod = ly_ctx_get_module(start->schema->module->ctx, str, NULL);
3457 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02003458 if (!mod) {
3459 /* invalid prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003460 return -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02003461 }
3462 } else {
3463 /* no prefix, module is the same as of current node */
3464 mod = start->schema->module;
3465 }
3466
3467 return resolve_data(mod, name, name_len, start, parents);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003468}
3469
Michal Vasko730dfdf2015-08-11 14:48:05 +02003470/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003471 * @brief Resolve a path predicate (leafref) in JSON data context. Logs directly
Radek Krejci48464ed2016-03-17 15:44:09 +01003472 * only specific errors, general no-resolvent error is left to the caller.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003473 *
Michal Vaskobb211122015-08-19 14:03:11 +02003474 * @param[in] pred Predicate to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003475 * @param[in] node Node from which the predicate is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02003476 * @param[in,out] node_match Nodes satisfying the restriction
3477 * without the predicate. Nodes not
3478 * satisfying the predicate are removed.
Michal Vasko0491ab32015-08-19 14:28:29 +02003479 * @param[out] parsed Number of characters parsed, negative on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003480 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003481 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003482 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003483static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003484resolve_path_predicate_data(const char *pred, struct lyd_node *node, struct unres_data *node_match,
Radek Krejci010e54b2016-03-15 09:40:34 +01003485 int *parsed)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003486{
Michal Vasko730dfdf2015-08-11 14:48:05 +02003487 /* ... /node[source = destination] ... */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003488 struct unres_data source_match, dest_match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003489 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vasko0491ab32015-08-19 14:28:29 +02003490 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed_loc = 0, pke_parsed = 0;
3491 int has_predicate, dest_parent_times, i, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003492 uint32_t j;
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003493 struct lyd_node_leaf_list *leaf_dst, *leaf_src;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003494
3495 source_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003496 source_match.node = malloc(sizeof *source_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003497 if (!source_match.node) {
3498 LOGMEM;
3499 return -1;
3500 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003501 dest_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003502 dest_match.node = malloc(sizeof *dest_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003503 if (!dest_match.node) {
3504 LOGMEM;
3505 return -1;
3506 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003507
3508 do {
3509 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
3510 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003511 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, pred[-i], &pred[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003512 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003513 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003514 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003515 parsed_loc += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003516 pred += i;
3517
Michal Vasko23b61ec2015-08-19 11:19:50 +02003518 for (j = 0; j < node_match->count;) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003519 /* source */
Michal Vaskocf024702015-10-08 15:01:42 +02003520 source_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02003521
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003522 /* must be leaf (key of a list) */
Radek Krejci581ce772015-11-10 17:22:40 +01003523 if ((rc = resolve_data_node(sour_pref, sour_pref_len, source, sour_len, node_match->node[j],
Michal Vaskocf024702015-10-08 15:01:42 +02003524 &source_match)) || (source_match.count != 1) || (source_match.node[0]->schema->nodetype != LYS_LEAF)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003525 i = 0;
3526 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003527 }
3528
3529 /* destination */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003530 dest_match.node[0] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003531 dest_parent_times = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003532 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3533 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003534 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003535 rc = -1;
3536 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003537 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003538 pke_parsed = i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003539 for (i = 0; i < dest_parent_times; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02003540 dest_match.node[0] = dest_match.node[0]->parent;
3541 if (!dest_match.node[0]) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003542 i = 0;
Michal Vasko0491ab32015-08-19 14:28:29 +02003543 rc = EXIT_FAILURE;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003544 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003545 }
3546 }
3547 while (1) {
Radek Krejci581ce772015-11-10 17:22:40 +01003548 if ((rc = resolve_data_node(dest_pref, dest_pref_len, dest, dest_len, dest_match.node[0],
Michal Vasko0491ab32015-08-19 14:28:29 +02003549 &dest_match)) || (dest_match.count != 1)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003550 i = 0;
3551 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003552 }
3553
3554 if (pke_len == pke_parsed) {
3555 break;
3556 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003557 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 +02003558 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003559 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003560 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003561 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003562 }
3563 pke_parsed += i;
3564 }
3565
3566 /* check match between source and destination nodes */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003567 leaf_dst = (struct lyd_node_leaf_list *)dest_match.node[0];
3568 while (leaf_dst->value_type == LY_TYPE_LEAFREF) {
3569 leaf_dst = (struct lyd_node_leaf_list *)leaf_dst->value.leafref;
3570 }
3571 leaf_src = (struct lyd_node_leaf_list *)source_match.node[0];
3572 while (leaf_src->value_type == LY_TYPE_LEAFREF) {
3573 leaf_src = (struct lyd_node_leaf_list *)leaf_src->value.leafref;
3574 }
3575 if (leaf_src->value_type != leaf_dst->value_type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003576 goto remove_leafref;
3577 }
3578
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003579 if (!ly_strequal(leaf_src->value_str, leaf_dst->value_str, 1)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003580 goto remove_leafref;
3581 }
3582
3583 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003584 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003585 continue;
3586
3587remove_leafref:
3588 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003589 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003590 }
3591 } while (has_predicate);
3592
Michal Vaskocf024702015-10-08 15:01:42 +02003593 free(source_match.node);
3594 free(dest_match.node);
Michal Vasko0491ab32015-08-19 14:28:29 +02003595 if (parsed) {
3596 *parsed = parsed_loc;
3597 }
3598 return EXIT_SUCCESS;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003599
3600error:
3601
3602 if (source_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003603 free(source_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003604 }
3605 if (dest_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003606 free(dest_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003607 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003608 if (parsed) {
3609 *parsed = -parsed_loc+i;
3610 }
3611 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003612}
3613
Michal Vasko730dfdf2015-08-11 14:48:05 +02003614/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003615 * @brief Resolve a path (leafref) in JSON data context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003616 *
Michal Vaskocf024702015-10-08 15:01:42 +02003617 * @param[in] node Leafref data node.
Michal Vasko23b61ec2015-08-19 11:19:50 +02003618 * @param[in] path Path of the leafref.
Radek Krejci48464ed2016-03-17 15:44:09 +01003619 * @param[out] ret Matching nodes. Expects an empty, but allocated structure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003620 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003621 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003622 */
Michal Vasko184521f2015-09-24 13:14:26 +02003623static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003624resolve_path_arg_data(struct lyd_node *node, const char *path, struct unres_data *ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003625{
Radek Krejci71b795b2015-08-10 16:20:39 +02003626 struct lyd_node *data = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003627 const char *prefix, *name;
Michal Vasko0491ab32015-08-19 14:28:29 +02003628 int pref_len, nam_len, has_predicate, parent_times, i, parsed, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003629 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003630
Michal Vaskocf024702015-10-08 15:01:42 +02003631 assert(node && path && ret && !ret->count);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003632
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003633 parent_times = 0;
Michal Vaskod9173342015-08-17 14:35:36 +02003634 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003635
3636 /* searching for nodeset */
3637 do {
Radek Krejcif7ed4c32016-10-27 16:20:03 +02003638 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 +01003639 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path[-i], &path[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003640 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003641 goto error;
3642 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003643 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003644 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003645
Michal Vasko23b61ec2015-08-19 11:19:50 +02003646 if (!ret->count) {
Michal Vaskobfd98e62016-09-02 09:50:05 +02003647 if (parent_times > 0) {
3648 data = node;
3649 for (i = 1; i < parent_times; ++i) {
3650 data = data->parent;
Michal Vasko253035f2015-12-17 16:58:13 +01003651 }
Michal Vaskobfd98e62016-09-02 09:50:05 +02003652 } else if (!parent_times) {
3653 data = node->child;
3654 } else {
3655 /* absolute path */
3656 for (data = node; data->parent; data = data->parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003657 }
3658
Michal Vaskobfd98e62016-09-02 09:50:05 +02003659 /* we may still be parsing it and the pointer is not correct yet */
3660 if (data->prev) {
3661 while (data->prev->next) {
3662 data = data->prev;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003663 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003664 }
3665 }
3666
3667 /* node identifier */
Radek Krejci581ce772015-11-10 17:22:40 +01003668 if ((rc = resolve_data_node(prefix, pref_len, name, nam_len, data, ret))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003669 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003670 LOGVAL(LYE_INELEM_LEN, LY_VLOG_LYD, node, nam_len, name);
Michal Vasko184521f2015-09-24 13:14:26 +02003671 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003672 goto error;
3673 }
3674
3675 if (has_predicate) {
3676 /* we have predicate, so the current results must be lists */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003677 for (j = 0; j < ret->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02003678 if (ret->node[j]->schema->nodetype == LYS_LIST &&
3679 ((struct lys_node_list *)ret->node[0]->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003680 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003681 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003682 continue;
3683 }
3684
3685 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003686 unres_data_del(ret, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003687 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003688 if ((rc = resolve_path_predicate_data(path, node, ret, &i))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003689 if (rc == -1) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003690 LOGVAL(LYE_NORESOLV, LY_VLOG_LYD, node, "leafref", path);
Michal Vasko184521f2015-09-24 13:14:26 +02003691 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003692 goto error;
3693 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003694 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003695 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003696
Michal Vasko23b61ec2015-08-19 11:19:50 +02003697 if (!ret->count) {
Michal Vasko0491ab32015-08-19 14:28:29 +02003698 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003699 goto error;
3700 }
3701 }
3702 } while (path[0] != '\0');
3703
Michal Vaskof02e3742015-08-05 16:27:02 +02003704 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003705
3706error:
3707
Michal Vaskocf024702015-10-08 15:01:42 +02003708 free(ret->node);
3709 ret->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003710 ret->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003711
Michal Vasko0491ab32015-08-19 14:28:29 +02003712 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003713}
3714
Michal Vaskoe27516a2016-10-10 17:55:31 +00003715static int
3716resolve_path_arg_schema_valid_dep_flag(const struct lys_node *op_node, const struct lys_node *first_node, int abs_path)
3717{
3718 int dep1, dep2;
3719 const struct lys_node *node;
3720
3721 if (lys_parent(op_node)) {
3722 /* inner operation (notif/action) */
3723 if (abs_path) {
3724 return 1;
3725 } else {
3726 /* compare depth of both nodes */
3727 for (dep1 = 0, node = op_node; lys_parent(node); node = lys_parent(node));
3728 for (dep2 = 0, node = first_node; lys_parent(node); node = lys_parent(node));
3729 if ((dep2 > dep1) || ((dep2 == dep1) && (op_node != first_node))) {
3730 return 1;
3731 }
3732 }
3733 } else {
3734 /* top-level operation (notif/rpc) */
3735 if (op_node != first_node) {
3736 return 1;
3737 }
3738 }
3739
3740 return 0;
3741}
3742
Michal Vasko730dfdf2015-08-11 14:48:05 +02003743/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003744 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003745 *
Michal Vaskobb211122015-08-19 14:03:11 +02003746 * @param[in] path Path to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003747 * @param[in] context_node Predicate context node (where the predicate is placed).
3748 * @param[in] parent Path context node (where the path begins/is placed).
Michal Vaskoe27516a2016-10-10 17:55:31 +00003749 * @param[in] op_node Optional node if the leafref is in an operation (action/rpc/notif).
Michal Vasko730dfdf2015-08-11 14:48:05 +02003750 *
Michal Vasko184521f2015-09-24 13:14:26 +02003751 * @return 0 on forward reference, otherwise the number
3752 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003753 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003754 */
Michal Vasko1f76a282015-08-04 16:16:53 +02003755static int
Radek Krejciadb57612016-02-16 13:34:34 +01003756resolve_path_predicate_schema(const char *path, const struct lys_node *context_node,
Michal Vaskoe27516a2016-10-10 17:55:31 +00003757 struct lys_node *parent, const struct lys_node *op_node)
Michal Vasko1f76a282015-08-04 16:16:53 +02003758{
Michal Vasko1e62a092015-12-01 12:27:20 +01003759 const struct lys_node *src_node, *dst_node;
Michal Vasko1f76a282015-08-04 16:16:53 +02003760 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vaskof9b35d92016-10-21 15:19:30 +02003761 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, pke_parsed, parsed = 0;
3762 int has_predicate, dest_parent_times, i, rc, first_iter;
Michal Vasko1f76a282015-08-04 16:16:53 +02003763
3764 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02003765 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02003766 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003767 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003768 return -parsed+i;
3769 }
3770 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003771 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02003772
Michal Vasko58090902015-08-13 14:04:15 +02003773 /* source (must be leaf) */
Michal Vasko36cbaa42015-12-14 13:15:48 +01003774 if (!sour_pref) {
Radek Krejciadb57612016-02-16 13:34:34 +01003775 sour_pref = context_node->module->name;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003776 }
Radek Krejciadb57612016-02-16 13:34:34 +01003777 rc = lys_get_sibling(context_node->child, sour_pref, sour_pref_len, source, sour_len,
Michal Vasko59ad4582016-09-16 13:15:41 +02003778 LYS_LEAF | LYS_LEAFLIST | LYS_AUGMENT, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003779 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003780 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02003781 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003782 }
3783
3784 /* destination */
Michal Vaskof9b35d92016-10-21 15:19:30 +02003785 dest_parent_times = 0;
3786 pke_parsed = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003787 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3788 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003789 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 +02003790 return -parsed;
3791 }
3792 pke_parsed += i;
3793
Radek Krejciadb57612016-02-16 13:34:34 +01003794 for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
Michal Vaskofbaead72016-10-07 10:54:48 +02003795 /* path is supposed to be evaluated in data tree, so we have to skip
3796 * all schema nodes that cannot be instantiated in data tree */
3797 for (dst_node = lys_parent(dst_node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003798 dst_node && !(dst_node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Michal Vaskofbaead72016-10-07 10:54:48 +02003799 dst_node = lys_parent(dst_node));
3800
Michal Vasko1f76a282015-08-04 16:16:53 +02003801 if (!dst_node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003802 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003803 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003804 }
3805 }
Michal Vaskoe27516a2016-10-10 17:55:31 +00003806 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003807 while (1) {
Michal Vasko36cbaa42015-12-14 13:15:48 +01003808 if (!dest_pref) {
3809 dest_pref = dst_node->module->name;
3810 }
3811 rc = lys_get_sibling(dst_node->child, dest_pref, dest_pref_len, dest, dest_len,
Michal Vasko165dc4a2015-10-23 09:44:27 +02003812 LYS_CONTAINER | LYS_LIST | LYS_LEAF | LYS_AUGMENT, &dst_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003813 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003814 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003815 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003816 }
3817
Michal Vaskoe27516a2016-10-10 17:55:31 +00003818 if (first_iter) {
3819 if (resolve_path_arg_schema_valid_dep_flag(op_node, dst_node, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01003820 parent->flags |= LYS_LEAFREF_DEP;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003821 }
3822 first_iter = 0;
3823 }
3824
Michal Vasko1f76a282015-08-04 16:16:53 +02003825 if (pke_len == pke_parsed) {
3826 break;
3827 }
3828
3829 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
3830 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003831 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent,
Radek Krejciadb57612016-02-16 13:34:34 +01003832 (path_key_expr+pke_parsed)[-i], (path_key_expr+pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003833 return -parsed;
3834 }
3835 pke_parsed += i;
3836 }
3837
3838 /* check source - dest match */
Michal Vasko59ad4582016-09-16 13:15:41 +02003839 if (dst_node->nodetype != src_node->nodetype) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003840 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko59ad4582016-09-16 13:15:41 +02003841 LOGVAL(LYE_SPEC, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "Destination node is not a %s, but a %s.",
3842 strnodetype(src_node->nodetype), strnodetype(dst_node->nodetype));
Michal Vasko184521f2015-09-24 13:14:26 +02003843 return -parsed;
3844 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003845 } while (has_predicate);
3846
3847 return parsed;
3848}
3849
Michal Vasko730dfdf2015-08-11 14:48:05 +02003850/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003851 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003852 *
Michal Vaskobb211122015-08-19 14:03:11 +02003853 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003854 * @param[in] parent_node Parent of the leafref.
Radek Krejci2f12f852016-01-08 12:59:57 +01003855 * @param[in] parent_tpdf Flag if the parent node is actually typedef, in that case the path
3856 * has to contain absolute path
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003857 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003858 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003859 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003860 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003861static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003862resolve_path_arg_schema(const char *path, struct lys_node *parent, int parent_tpdf,
Michal Vasko36cbaa42015-12-14 13:15:48 +01003863 const struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02003864{
Michal Vaskoe27516a2016-10-10 17:55:31 +00003865 const struct lys_node *node, *op_node = NULL;
Radek Krejci990af1f2016-11-09 13:53:36 +01003866 const struct lys_module *mod;
3867 struct lys_module *mod_start;
Michal Vasko1f76a282015-08-04 16:16:53 +02003868 const char *id, *prefix, *name;
3869 int pref_len, nam_len, parent_times, has_predicate;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003870 int i, first_iter, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02003871
Michal Vasko184521f2015-09-24 13:14:26 +02003872 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003873 parent_times = 0;
3874 id = path;
3875
Michal Vaskoe27516a2016-10-10 17:55:31 +00003876 /* find operation schema we are in, if applicable */
Michal Vaskoe9914d12016-10-07 14:32:37 +02003877 if (!parent_tpdf) {
Michal Vaskoe27516a2016-10-10 17:55:31 +00003878 for (op_node = lys_parent(parent);
3879 op_node && !(op_node->nodetype & (LYS_ACTION | LYS_NOTIF | LYS_RPC));
3880 op_node = lys_parent(op_node));
Michal Vaskoe9914d12016-10-07 14:32:37 +02003881 }
3882
Radek Krejci990af1f2016-11-09 13:53:36 +01003883 mod_start = lys_node_module(parent);
Michal Vasko1f76a282015-08-04 16:16:53 +02003884 do {
Radek Krejci990af1f2016-11-09 13:53:36 +01003885 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 +01003886 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 +02003887 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003888 }
3889 id += i;
3890
Michal Vasko184521f2015-09-24 13:14:26 +02003891 if (first_iter) {
Michal Vasko1f76a282015-08-04 16:16:53 +02003892 if (parent_times == -1) {
Radek Krejcic071c542016-01-27 14:57:51 +01003893 /* resolve prefix of the module */
Radek Krejci990af1f2016-11-09 13:53:36 +01003894 mod = prefix ? lys_get_import_module(mod_start, NULL, 0, prefix, pref_len) : mod_start;
3895 if (!mod) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003896 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3897 "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003898 return EXIT_FAILURE;
Michal Vasko58090902015-08-13 14:04:15 +02003899 }
Radek Krejci990af1f2016-11-09 13:53:36 +01003900 if (!mod->implemented) {
Radek Krejci2eee5c02016-12-06 19:18:05 +01003901 mod = lys_implemented_module(mod);
Radek Krejci990af1f2016-11-09 13:53:36 +01003902 if (!mod->implemented) {
3903 /* make the found module implemented */
3904 if (lys_set_implemented(mod)) {
3905 return EXIT_FAILURE;
3906 }
3907 }
3908 }
3909 /* get start node */
3910 if (!mod->data) {
3911 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3912 "leafref", path);
3913 return EXIT_FAILURE;
3914 }
3915 node = mod->data;
3916
Michal Vasko1f76a282015-08-04 16:16:53 +02003917 } else if (parent_times > 0) {
Radek Krejci2f12f852016-01-08 12:59:57 +01003918 if (parent_tpdf) {
3919 /* the path is not allowed to contain relative path since we are in top level typedef */
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003920 LOGVAL(LYE_NORESOLV, 0, NULL, "leafref", path);
Radek Krejci2f12f852016-01-08 12:59:57 +01003921 return -1;
3922 }
3923
Michal Vasko94458082016-10-07 14:34:36 +02003924 /* we are looking for a sibling of a node, node it's parent (that is why parent_times - 1) */
3925 for (i = 0, node = parent; i < parent_times - 1; i++) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02003926 /* path is supposed to be evaluated in data tree, so we have to skip
3927 * all schema nodes that cannot be instantiated in data tree */
3928 for (node = lys_parent(node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003929 node && !(node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Radek Krejci3a5501d2016-07-18 22:03:34 +02003930 node = lys_parent(node));
3931
Michal Vasko1f76a282015-08-04 16:16:53 +02003932 if (!node) {
Michal Vaskoe9914d12016-10-07 14:32:37 +02003933 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003934 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003935 }
3936 }
Radek Krejci990af1f2016-11-09 13:53:36 +01003937
3938 /* now we have to check that if we are going into a node from a different module,
3939 * the module is implemented (so its augments are applied) */
3940 mod = prefix ? lys_get_import_module(mod_start, NULL, 0, prefix, pref_len) : mod_start;
3941 if (!mod) {
3942 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
3943 return EXIT_FAILURE;
3944 }
3945 if (!mod->implemented) {
Radek Krejci2eee5c02016-12-06 19:18:05 +01003946 mod = lys_implemented_module(mod);
Radek Krejci990af1f2016-11-09 13:53:36 +01003947 if (!mod->implemented) {
3948 /* make the found module implemented */
3949 if (lys_set_implemented(mod)) {
3950 return EXIT_FAILURE;
3951 }
3952 }
3953 }
Michal Vaskoe01eca52015-08-13 14:42:02 +02003954 } else {
3955 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003956 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003957 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003958 } else {
Radek Krejci990af1f2016-11-09 13:53:36 +01003959 /* we have to first check that the module we are going into is implemented */
3960 mod = prefix ? lys_get_import_module(mod_start, NULL, 0, prefix, pref_len) : mod_start;
3961 if (!mod) {
3962 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
3963 return EXIT_FAILURE;
3964 }
3965 if (!mod->implemented) {
Radek Krejci2eee5c02016-12-06 19:18:05 +01003966 mod = lys_implemented_module(mod);
Radek Krejci990af1f2016-11-09 13:53:36 +01003967 if (!mod->implemented) {
3968 /* make the found module implemented */
3969 if (lys_set_implemented(mod)) {
3970 return EXIT_FAILURE;
3971 }
3972 }
3973 }
3974
Michal Vasko7dc71d02016-03-15 10:42:28 +01003975 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02003976 if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko2f5aceb2016-03-22 10:24:14 +01003977 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 +01003978 return -1;
3979 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003980 node = node->child;
Radek Krejci43ccc4c2016-10-18 20:40:06 +02003981 if (!node) {
3982 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3983 "leafref", path);
3984 return EXIT_FAILURE;
3985 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003986 }
3987
Michal Vasko4f0dad02016-02-15 14:08:23 +01003988 if (!prefix) {
Radek Krejci990af1f2016-11-09 13:53:36 +01003989 prefix = mod_start->name;
Michal Vasko4f0dad02016-02-15 14:08:23 +01003990 }
3991
Michal Vasko36cbaa42015-12-14 13:15:48 +01003992 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 +02003993 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003994 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko7a55bea2016-05-02 14:51:20 +02003995 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003996 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003997
Michal Vaskoe27516a2016-10-10 17:55:31 +00003998 if (first_iter) {
3999 /* set external dependency flag, we can decide based on the first found node */
4000 if (!parent_tpdf && op_node && parent_times &&
4001 resolve_path_arg_schema_valid_dep_flag(op_node, node, (parent_times == -1 ? 1 : 0))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01004002 parent->flags |= LYS_LEAFREF_DEP;
Michal Vaskoe27516a2016-10-10 17:55:31 +00004003 }
4004 first_iter = 0;
4005 }
4006
Michal Vasko1f76a282015-08-04 16:16:53 +02004007 if (has_predicate) {
4008 /* we have predicate, so the current result must be list */
4009 if (node->nodetype != LYS_LIST) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02004010 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004011 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02004012 }
4013
Michal Vaskoe27516a2016-10-10 17:55:31 +00004014 i = resolve_path_predicate_schema(id, node, parent, op_node);
Radek Krejci27fe55e2016-09-13 17:13:35 +02004015 if (i <= 0) {
4016 if (i == 0) {
4017 return EXIT_FAILURE;
4018 } else { /* i < 0 */
4019 return -1;
4020 }
Michal Vasko1f76a282015-08-04 16:16:53 +02004021 }
4022 id += i;
Michal Vaskof9b35d92016-10-21 15:19:30 +02004023 has_predicate = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02004024 }
4025 } while (id[0]);
4026
Michal Vaskoca917682016-07-25 11:00:37 +02004027 /* the target must be leaf or leaf-list (in YANG 1.1 only) */
Radek Krejci2a5a9602016-11-04 10:21:13 +01004028 if ((node->nodetype != LYS_LEAF) && (node->nodetype != LYS_LEAFLIST)) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02004029 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Radek Krejcid47daf62016-08-22 16:23:38 +02004030 LOGVAL(LYE_SPEC, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
Radek Krejci2a5a9602016-11-04 10:21:13 +01004031 "Leafref target \"%s\" is not a leaf nor a leaf-list.", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004032 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02004033 }
4034
Radek Krejcicf509982015-12-15 09:22:44 +01004035 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01004036 if (lyp_check_status(parent->flags, parent->module, parent->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01004037 node->flags, node->module, node->name, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01004038 return -1;
4039 }
4040
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004041 if (ret) {
4042 *ret = node;
4043 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02004044
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004045 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02004046}
4047
Michal Vasko730dfdf2015-08-11 14:48:05 +02004048/**
Michal Vaskof39142b2015-10-21 11:40:05 +02004049 * @brief Resolve instance-identifier predicate in JSON data format.
4050 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004051 *
Michal Vaskobb211122015-08-19 14:03:11 +02004052 * @param[in] pred Predicate to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004053 * @param[in,out] node_match Nodes matching the restriction without
4054 * the predicate. Nodes not satisfying
4055 * the predicate are removed.
4056 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004057 * @return Number of characters successfully parsed,
4058 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004059 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004060static int
Michal Vaskof39142b2015-10-21 11:40:05 +02004061resolve_predicate(const char *pred, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004062{
Michal Vasko730dfdf2015-08-11 14:48:05 +02004063 /* ... /node[target = value] ... */
Michal Vaskob2f40be2016-09-08 16:03:48 +02004064 struct lyd_node *target;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004065 const char *model, *name, *value;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004066 int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed, pred_iter, k;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004067 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004068
Michal Vasko1f2cc332015-08-19 11:18:32 +02004069 assert(pred && node_match->count);
4070
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004071 idx = -1;
4072 parsed = 0;
4073
Michal Vaskob2f40be2016-09-08 16:03:48 +02004074 pred_iter = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004075 do {
Michal Vaskof39142b2015-10-21 11:40:05 +02004076 if ((i = parse_predicate(pred, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004077 return -parsed+i;
4078 }
4079 parsed += i;
4080 pred += i;
4081
4082 if (isdigit(name[0])) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004083 /* pos */
4084 assert(!value);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004085 idx = atoi(name);
Michal Vaskob2f40be2016-09-08 16:03:48 +02004086 } else if (name[0] != '.') {
4087 /* list keys */
4088 if (pred_iter < 0) {
4089 pred_iter = 1;
4090 } else {
4091 ++pred_iter;
4092 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004093 }
4094
Michal Vaskof2f28a12016-09-09 12:43:06 +02004095 for (cur_idx = 1, j = 0; j < node_match->count; ++cur_idx) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004096 /* target */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004097 if (name[0] == '.') {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004098 /* leaf-list value */
Michal Vaskocf024702015-10-08 15:01:42 +02004099 if (node_match->node[j]->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004100 goto remove_instid;
4101 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004102
4103 target = node_match->node[j];
4104 /* check the value */
4105 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
4106 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
4107 goto remove_instid;
4108 }
4109
4110 } else if (!value) {
4111 /* keyless list position */
4112 if ((node_match->node[j]->schema->nodetype != LYS_LIST)
4113 || ((struct lys_node_list *)node_match->node[j]->schema)->keys) {
4114 goto remove_instid;
4115 }
4116
4117 if (idx != cur_idx) {
4118 goto remove_instid;
4119 }
4120
4121 } else {
4122 /* list key value */
Michal Vaskocf024702015-10-08 15:01:42 +02004123 if (node_match->node[j]->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004124 goto remove_instid;
4125 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004126
4127 /* key module must match the list module */
4128 if (strncmp(node_match->node[j]->schema->module->name, model, mod_len)
4129 || node_match->node[j]->schema->module->name[mod_len]) {
4130 goto remove_instid;
4131 }
4132 /* find the key leaf */
Michal Vasko045182c2016-09-09 12:44:07 +02004133 for (k = 1, target = node_match->node[j]->child; target && (k < pred_iter); k++, target = target->next);
Michal Vaskob2f40be2016-09-08 16:03:48 +02004134 if (!target) {
4135 goto remove_instid;
4136 }
4137 if ((struct lys_node_leaf *)target->schema !=
4138 ((struct lys_node_list *)node_match->node[j]->schema)->keys[pred_iter - 1]) {
4139 goto remove_instid;
4140 }
4141
4142 /* check the value */
4143 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
4144 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
4145 goto remove_instid;
4146 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004147 }
4148
Michal Vaskob2f40be2016-09-08 16:03:48 +02004149 /* instid is ok, continue check with the next one */
Michal Vasko1f2cc332015-08-19 11:18:32 +02004150 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004151 continue;
4152
4153remove_instid:
Michal Vaskob2f40be2016-09-08 16:03:48 +02004154 /* does not fulfill conditions, remove instid record */
Michal Vasko1f2cc332015-08-19 11:18:32 +02004155 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004156 }
4157 } while (has_predicate);
4158
Michal Vaskob2f40be2016-09-08 16:03:48 +02004159 /* check that all list keys were specified */
4160 if ((pred_iter > 0) && node_match->count) {
Michal Vasko045182c2016-09-09 12:44:07 +02004161 j = 0;
4162 while (j < node_match->count) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004163 assert(node_match->node[j]->schema->nodetype == LYS_LIST);
4164 if (pred_iter < ((struct lys_node_list *)node_match->node[j]->schema)->keys_size) {
4165 /* not enough predicates, just remove the list instance */
4166 unres_data_del(node_match, j);
Michal Vasko045182c2016-09-09 12:44:07 +02004167 } else {
4168 ++j;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004169 }
4170 }
4171
4172 if (!node_match->count) {
4173 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier is missing some list keys.");
4174 }
4175 }
4176
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004177 return parsed;
4178}
4179
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004180int
4181lys_check_xpath(struct lys_node *node, int check_place)
Michal Vasko9e635ac2016-10-17 11:44:09 +02004182{
4183 struct lys_node *parent, *elem;
4184 struct lyxp_set set;
4185 uint32_t i;
4186 int rc;
4187
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004188 if (check_place) {
4189 parent = node;
4190 while (parent) {
4191 if (parent->nodetype == LYS_GROUPING) {
4192 /* unresolved grouping, skip for now (will be checked later) */
Michal Vasko9e635ac2016-10-17 11:44:09 +02004193 return EXIT_SUCCESS;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004194 }
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004195 if (parent->nodetype == LYS_AUGMENT) {
4196 if (!((struct lys_node_augment *)parent)->target) {
Radek Krejcidf46e222016-11-08 11:57:37 +01004197 /* unresolved augment */
4198 if (parent->module->implemented) {
4199 /* skip for now (will be checked later) */
4200 return EXIT_FAILURE;
4201 } else {
4202 /* not implemented augment, skip resolving */
4203 return EXIT_SUCCESS;
4204 }
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004205 } else {
4206 parent = ((struct lys_node_augment *)parent)->target;
4207 continue;
4208 }
4209 }
4210 parent = parent->parent;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004211 }
Michal Vasko9e635ac2016-10-17 11:44:09 +02004212 }
4213
4214 rc = lyxp_node_atomize(node, &set);
4215 if (rc) {
4216 return rc;
4217 }
4218
4219 for (parent = node; parent && !(parent->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); parent = lys_parent(parent));
4220
4221 for (i = 0; i < set.used; ++i) {
4222 /* skip roots'n'stuff */
4223 if (set.val.snodes[i].type == LYXP_NODE_ELEM) {
4224 /* XPath expression cannot reference "lower" status than the node that has the definition */
4225 if (lyp_check_status(node->flags, lys_node_module(node), node->name, set.val.snodes[i].snode->flags,
4226 lys_node_module(set.val.snodes[i].snode), set.val.snodes[i].snode->name, node)) {
4227 return -1;
4228 }
4229
4230 if (parent) {
4231 for (elem = set.val.snodes[i].snode; elem && (elem != parent); elem = lys_parent(elem));
4232 if (!elem) {
4233 /* not in node's RPC or notification subtree, set the flag */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01004234 node->flags |= LYS_XPATH_DEP;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004235 break;
4236 }
4237 }
4238 }
4239 }
4240
4241 free(set.val.snodes);
4242 return EXIT_SUCCESS;
4243}
4244
Radek Krejcif71f48f2016-10-25 16:37:24 +02004245static int
4246check_leafref_config(struct lys_node_leaf *leaf, struct lys_type *type)
4247{
4248 int i;
4249
4250 if (type->base == LY_TYPE_LEAFREF) {
4251 if ((leaf->flags & LYS_CONFIG_W) && type->info.lref.target && (type->info.lref.target->flags & LYS_CONFIG_R)) {
4252 LOGVAL(LYE_SPEC, LY_VLOG_LYS, leaf, "The %s is config but refers to a non-config %s.",
4253 strnodetype(leaf->nodetype), strnodetype(type->info.lref.target->nodetype));
4254 return -1;
4255 }
4256 /* we can skip the test in case the leafref is not yet resolved. In that case the test is done in the time
4257 * of leafref resolving (lys_leaf_add_leafref_target()) */
4258 } else if (type->base == LY_TYPE_UNION) {
4259 for (i = 0; i < type->info.uni.count; i++) {
4260 if (check_leafref_config(leaf, &type->info.uni.types[i])) {
4261 return -1;
4262 }
4263 }
4264 }
4265 return 0;
4266}
4267
Michal Vasko9e635ac2016-10-17 11:44:09 +02004268/**
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004269 * @brief Passes config flag down to children, skips nodes without config flags.
4270 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004271 *
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004272 * @param[in] node Siblings and their children to have flags changed.
Michal Vaskoe022a562016-09-27 14:24:15 +02004273 * @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 +02004274 * @param[in] flags Flags to assign to all the nodes.
Radek Krejcib3142312016-11-09 11:04:12 +01004275 * @param[in,out] unres List of unresolved items.
Michal Vaskoa86508c2016-08-26 14:30:19 +02004276 *
4277 * @return 0 on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004278 */
Michal Vaskoa86508c2016-08-26 14:30:19 +02004279static int
Radek Krejcib3142312016-11-09 11:04:12 +01004280inherit_config_flag(struct lys_node *node, int flags, int clear, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004281{
Radek Krejcif71f48f2016-10-25 16:37:24 +02004282 struct lys_node_leaf *leaf;
4283
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004284 assert(!(flags ^ (flags & LYS_CONFIG_MASK)));
Radek Krejci1d82ef62015-08-07 14:44:40 +02004285 LY_TREE_FOR(node, node) {
Radek Krejcib3142312016-11-09 11:04:12 +01004286 if (lys_has_xpath(node) && unres_schema_add_node(node->module, unres, node, UNRES_XPATH, NULL) == -1) {
Michal Vasko9e635ac2016-10-17 11:44:09 +02004287 return -1;
4288 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004289 if (clear) {
4290 node->flags &= ~LYS_CONFIG_MASK;
Michal Vaskoc2a8d362016-09-29 08:50:13 +02004291 node->flags &= ~LYS_CONFIG_SET;
Michal Vaskoe022a562016-09-27 14:24:15 +02004292 } else {
4293 if (node->flags & LYS_CONFIG_SET) {
4294 /* skip nodes with an explicit config value */
4295 if ((flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
4296 LOGVAL(LYE_INARG, LY_VLOG_LYS, node, "true", "config");
4297 LOGVAL(LYE_SPEC, LY_VLOG_LYS, node, "State nodes cannot have configuration nodes as children.");
4298 return -1;
4299 }
4300 continue;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004301 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004302
4303 if (!(node->nodetype & (LYS_USES | LYS_GROUPING))) {
4304 node->flags = (node->flags & ~LYS_CONFIG_MASK) | flags;
4305 /* check that configuration lists have keys */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004306 if ((node->nodetype == LYS_LIST) && (node->flags & LYS_CONFIG_W)
4307 && !((struct lys_node_list *)node)->keys_size) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004308 LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_LYS, node, "key", "list");
4309 return -1;
4310 }
4311 }
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004312 }
Radek Krejcibf2abff2016-08-23 15:51:52 +02004313 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Radek Krejcib3142312016-11-09 11:04:12 +01004314 if (inherit_config_flag(node->child, flags, clear, unres)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004315 return -1;
4316 }
Radek Krejcif71f48f2016-10-25 16:37:24 +02004317 } else if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
4318 leaf = (struct lys_node_leaf *)node;
4319 if (check_leafref_config(leaf, &leaf->type)) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02004320 return -1;
4321 }
4322 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004323 }
Michal Vaskoa86508c2016-08-26 14:30:19 +02004324
4325 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004326}
4327
Michal Vasko730dfdf2015-08-11 14:48:05 +02004328/**
Michal Vasko7178e692016-02-12 15:58:05 +01004329 * @brief Resolve augment target. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004330 *
Michal Vaskobb211122015-08-19 14:03:11 +02004331 * @param[in] aug Augment to use.
Michal Vasko3edeaf72016-02-11 13:17:43 +01004332 * @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 +01004333 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004334 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004335 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004336 */
Michal Vasko7178e692016-02-12 15:58:05 +01004337static int
Radek Krejcib3142312016-11-09 11:04:12 +01004338resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004339{
Michal Vaskoe022a562016-09-27 14:24:15 +02004340 int rc, clear_config;
Michal Vasko1d87a922015-08-21 12:57:16 +02004341 struct lys_node *sub;
Pavol Vican47319932016-08-29 09:14:47 +02004342 const struct lys_node *aug_target, *parent;
Radek Krejci27fe55e2016-09-13 17:13:35 +02004343 struct lys_module *mod;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004344
Michal Vasko15b36692016-08-26 15:29:54 +02004345 assert(aug && !aug->target);
Radek Krejcidf46e222016-11-08 11:57:37 +01004346 mod = lys_main_module(aug->module);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004347
Michal Vasko15b36692016-08-26 15:29:54 +02004348 /* resolve target node */
Radek Krejcidf46e222016-11-08 11:57:37 +01004349 rc = resolve_augment_schema_nodeid(aug->target_name, siblings, (siblings ? NULL : aug->module), mod->implemented, &aug_target);
Michal Vasko15b36692016-08-26 15:29:54 +02004350 if (rc == -1) {
4351 return -1;
Radek Krejci5fb4c382016-11-28 09:21:42 +01004352 } else if (rc > 0) {
Michal Vasko15b36692016-08-26 15:29:54 +02004353 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, aug, aug->target_name[rc - 1], &aug->target_name[rc - 1]);
4354 return -1;
Radek Krejci5fb4c382016-11-28 09:21:42 +01004355 } else if (rc == 0 && aug->target) {
4356 /* augment was resolved as a side effect of setting module implemented when
4357 * resolving augment schema nodeid, so we are done here */
4358 return 0;
Michal Vasko15b36692016-08-26 15:29:54 +02004359 }
Radek Krejcidf46e222016-11-08 11:57:37 +01004360 if (!aug_target && mod->implemented) {
Michal Vasko15b36692016-08-26 15:29:54 +02004361 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
4362 return EXIT_FAILURE;
4363 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02004364 /* check that we want to connect augment into its target */
Radek Krejci27fe55e2016-09-13 17:13:35 +02004365 if (!mod->implemented) {
4366 /* it must be augment only to the same module,
4367 * otherwise we do not apply augment in not-implemented
4368 * module. If the module is set to be implemented in future,
4369 * the augment is being resolved and checked again */
Radek Krejcidf46e222016-11-08 11:57:37 +01004370 if (!aug_target) {
4371 /* target was not even resolved */
4372 return EXIT_SUCCESS;
4373 }
4374 /* target was resolved, but it may refer another module */
4375 for (sub = (struct lys_node *)aug_target; sub; sub = lys_parent(sub)) {
Radek Krejci27fe55e2016-09-13 17:13:35 +02004376 if (lys_node_module(sub) != mod) {
4377 /* this is not an implemented module and the augment
4378 * target some other module, so avoid its connecting
4379 * to the target */
4380 return EXIT_SUCCESS;
4381 }
4382 }
4383 }
4384
Michal Vasko15b36692016-08-26 15:29:54 +02004385 if (!aug->child) {
4386 /* nothing to do */
4387 LOGWRN("Augment \"%s\" without children.", aug->target_name);
Radek Krejci27fe55e2016-09-13 17:13:35 +02004388 goto success;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004389 }
4390
Michal Vaskod58d5962016-03-02 14:29:41 +01004391 /* check for mandatory nodes - if the target node is in another module
4392 * the added nodes cannot be mandatory
4393 */
Michal Vasko15b36692016-08-26 15:29:54 +02004394 if (!aug->parent && (lys_node_module((struct lys_node *)aug) != lys_node_module(aug_target))
Radek Krejcidf24cbe2016-11-08 11:55:51 +01004395 && (rc = lyp_check_mandatory_augment(aug, aug_target))) {
Radek Krejcie00d2312016-08-12 15:27:49 +02004396 return rc;
Michal Vaskod58d5962016-03-02 14:29:41 +01004397 }
4398
Michal Vasko07e89ef2016-03-03 13:28:57 +01004399 /* check augment target type and then augment nodes type */
Michal Vasko15b36692016-08-26 15:29:54 +02004400 if (aug_target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF)) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004401 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004402 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES | LYS_CHOICE))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004403 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4404 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko15b36692016-08-26 15:29:54 +02004405 strnodetype(aug_target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004406 return -1;
4407 }
4408 }
Michal Vasko15b36692016-08-26 15:29:54 +02004409 } else if (aug_target->nodetype == LYS_CHOICE) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004410 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004411 if (!(sub->nodetype & (LYS_CASE | LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004412 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4413 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko15b36692016-08-26 15:29:54 +02004414 strnodetype(aug_target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004415 return -1;
4416 }
4417 }
4418 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01004419 LOGVAL(LYE_INARG, LY_VLOG_LYS, aug, aug->target_name, "target-node");
Michal Vasko15b36692016-08-26 15:29:54 +02004420 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Invalid augment target node type \"%s\".", strnodetype(aug_target->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004421 return -1;
4422 }
4423
Radek Krejcic071c542016-01-27 14:57:51 +01004424 /* check identifier uniqueness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02004425 LY_TREE_FOR(aug->child, sub) {
Michal Vasko15b36692016-08-26 15:29:54 +02004426 if (lys_check_id(sub, (struct lys_node *)aug_target, NULL)) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02004427 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02004428 }
4429 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004430
Michal Vasko15b36692016-08-26 15:29:54 +02004431 /* finally reconnect augmenting data into the target - add them to the target child list,
4432 * by setting aug->target we know the augment is fully resolved now */
4433 aug->target = (struct lys_node *)aug_target;
4434 if (aug->target->child) {
4435 sub = aug->target->child->prev; /* remember current target's last node */
4436 sub->next = aug->child; /* connect augmenting data after target's last node */
4437 aug->target->child->prev = aug->child->prev; /* new target's last node is last augmenting node */
4438 aug->child->prev = sub; /* finish connecting of both child lists */
4439 } else {
4440 aug->target->child = aug->child;
4441 }
4442
Michal Vasko9e635ac2016-10-17 11:44:09 +02004443 /* inherit config information from actual parent */
4444 for(parent = aug_target; parent && !(parent->nodetype & (LYS_NOTIF | LYS_INPUT | LYS_OUTPUT | LYS_RPC)); parent = lys_parent(parent));
4445 clear_config = (parent) ? 1 : 0;
4446 LY_TREE_FOR(aug->child, sub) {
Radek Krejcib3142312016-11-09 11:04:12 +01004447 if (inherit_config_flag(sub, aug_target->flags & LYS_CONFIG_MASK, clear_config, unres)) {
Michal Vasko9e635ac2016-10-17 11:44:09 +02004448 return -1;
4449 }
4450 }
4451
Radek Krejci27fe55e2016-09-13 17:13:35 +02004452success:
4453 if (mod->implemented) {
4454 /* make target modules also implemented */
4455 for (sub = aug->target; sub; sub = lys_parent(sub)) {
4456 if (lys_set_implemented(sub->module)) {
4457 return -1;
4458 }
4459 }
4460 }
4461
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004462 return EXIT_SUCCESS;
4463}
4464
Michal Vasko730dfdf2015-08-11 14:48:05 +02004465/**
Pavol Vican855ca622016-09-05 13:07:54 +02004466 * @brief Resolve (find) choice default case. Does not log.
4467 *
4468 * @param[in] choic Choice to use.
4469 * @param[in] dflt Name of the default case.
4470 *
4471 * @return Pointer to the default node or NULL.
4472 */
4473static struct lys_node *
4474resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
4475{
4476 struct lys_node *child, *ret;
4477
4478 LY_TREE_FOR(choic->child, child) {
4479 if (child->nodetype == LYS_USES) {
4480 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
4481 if (ret) {
4482 return ret;
4483 }
4484 }
4485
4486 if (ly_strequal(child->name, dflt, 1) && (child->nodetype & (LYS_ANYDATA | LYS_CASE
Radek Krejci2f792db2016-09-12 10:52:33 +02004487 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE))) {
Pavol Vican855ca622016-09-05 13:07:54 +02004488 return child;
4489 }
4490 }
4491
4492 return NULL;
4493}
4494
4495/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02004496 * @brief Resolve uses, apply augments, refines. Logs directly.
4497 *
Michal Vaskobb211122015-08-19 14:03:11 +02004498 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004499 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004500 *
Michal Vaskodef0db12015-10-07 13:22:48 +02004501 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004502 */
Michal Vasko184521f2015-09-24 13:14:26 +02004503static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004504resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004505{
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004506 struct ly_ctx *ctx = uses->module->ctx; /* shortcut */
Pavol Vican855ca622016-09-05 13:07:54 +02004507 struct lys_node *node = NULL, *next, *iter, **refine_nodes = NULL;
Pavol Vican55abd332016-07-12 15:54:49 +02004508 struct lys_node *node_aux, *parent, *tmp;
Radek Krejci200bf712016-08-16 17:11:04 +02004509 struct lys_node_leaflist *llist;
4510 struct lys_node_leaf *leaf;
Radek Krejci76512572015-08-04 09:47:08 +02004511 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004512 struct lys_restr *must, **old_must;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004513 struct lys_iffeature *iff, **old_iff;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004514 int i, j, k, rc;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004515 uint8_t size, *old_size;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004516 unsigned int usize, usize1, usize2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004517
Michal Vasko71e1aa82015-08-12 12:17:51 +02004518 assert(uses->grp);
Michal Vaskoe7708512016-03-11 10:26:55 +01004519 /* HACK just check that the grouping is resolved */
Michal Vaskodef0db12015-10-07 13:22:48 +02004520 assert(!uses->grp->nacm);
Michal Vasko71e1aa82015-08-12 12:17:51 +02004521
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004522 if (!uses->grp->child) {
4523 /* grouping without children, warning was already displayed */
4524 return EXIT_SUCCESS;
4525 }
4526
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004527 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01004528 LY_TREE_FOR(uses->grp->child, node_aux) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004529 node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, uses->nacm, unres, 0);
Michal Vasko1e62a092015-12-01 12:27:20 +01004530 if (!node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004531 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, uses->grp->name, "uses");
4532 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Copying data from grouping failed.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004533 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004534 }
Pavol Vican55abd332016-07-12 15:54:49 +02004535 /* test the name of siblings */
4536 LY_TREE_FOR((uses->parent) ? uses->parent->child : lys_main_module(uses->module)->data, tmp) {
Pavol Vican2510ddc2016-07-18 16:23:44 +02004537 if (!(tmp->nodetype & (LYS_USES | LYS_GROUPING | LYS_CASE)) && ly_strequal(tmp->name, node_aux->name, 1)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004538 goto fail;
Pavol Vican55abd332016-07-12 15:54:49 +02004539 }
4540 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004541 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004542
Michal Vaskodef0db12015-10-07 13:22:48 +02004543 /* we managed to copy the grouping, the rest must be possible to resolve */
4544
Pavol Vican855ca622016-09-05 13:07:54 +02004545 if (uses->refine_size) {
4546 refine_nodes = malloc(uses->refine_size * sizeof *refine_nodes);
4547 if (!refine_nodes) {
4548 LOGMEM;
4549 goto fail;
4550 }
4551 }
4552
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004553 /* apply refines */
4554 for (i = 0; i < uses->refine_size; i++) {
4555 rfn = &uses->refine[i];
Michal Vasko3edeaf72016-02-11 13:17:43 +01004556 rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child, LYS_NO_RPC_NOTIF_NODE,
Radek Krejcif3c71de2016-04-11 12:45:46 +02004557 1, 0, (const struct lys_node **)&node);
Michal Vasko9bb061b2016-02-12 11:00:19 +01004558 if (rc || !node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004559 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004560 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004561 }
4562
Radek Krejci1d82ef62015-08-07 14:44:40 +02004563 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004564 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
4565 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Refine substatements not applicable to the target-node.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004566 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004567 }
Pavol Vican855ca622016-09-05 13:07:54 +02004568 refine_nodes[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004569
4570 /* description on any nodetype */
4571 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004572 lydict_remove(ctx, node->dsc);
4573 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004574 }
4575
4576 /* reference on any nodetype */
4577 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004578 lydict_remove(ctx, node->ref);
4579 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004580 }
4581
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004582 /* config on any nodetype,
4583 * in case of notification or rpc/action, the config is not applicable (there is no config status) */
4584 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004585 node->flags &= ~LYS_CONFIG_MASK;
4586 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004587 }
4588
4589 /* default value ... */
Radek Krejci200bf712016-08-16 17:11:04 +02004590 if (rfn->dflt_size) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004591 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004592 /* leaf */
Radek Krejci200bf712016-08-16 17:11:04 +02004593 leaf = (struct lys_node_leaf *)node;
4594
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004595 /* replace default value */
Radek Krejci200bf712016-08-16 17:11:04 +02004596 lydict_remove(ctx, leaf->dflt);
4597 leaf->dflt = lydict_insert(ctx, rfn->dflt[0], 0);
4598
4599 /* check the default value */
Radek Krejci51673202016-11-01 17:00:32 +01004600 if (unres_schema_add_node(leaf->module, unres, &leaf->type, UNRES_TYPE_DFLT,
4601 (struct lys_node *)(&leaf->dflt)) == -1) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004602 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004603 }
Radek Krejci200bf712016-08-16 17:11:04 +02004604 } else if (node->nodetype == LYS_LEAFLIST) {
4605 /* leaf-list */
4606 llist = (struct lys_node_leaflist *)node;
4607
4608 /* remove complete set of defaults in target */
4609 for (i = 0; i < llist->dflt_size; i++) {
4610 lydict_remove(ctx, llist->dflt[i]);
4611 }
4612 free(llist->dflt);
4613
4614 /* copy the default set from refine */
4615 llist->dflt_size = rfn->dflt_size;
4616 llist->dflt = malloc(llist->dflt_size * sizeof *llist->dflt);
4617 for (i = 0; i < llist->dflt_size; i++) {
4618 llist->dflt[i] = lydict_insert(ctx, rfn->dflt[i], 0);
4619 }
4620
4621 /* check default value */
4622 for (i = 0; i < llist->dflt_size; i++) {
Radek Krejci51673202016-11-01 17:00:32 +01004623 if (unres_schema_add_node(llist->module, unres, &llist->type, UNRES_TYPE_DFLT,
4624 (struct lys_node *)(&llist->dflt[i])) == -1) {
Pavol Vican855ca622016-09-05 13:07:54 +02004625 goto fail;
Radek Krejci200bf712016-08-16 17:11:04 +02004626 }
4627 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004628 }
4629 }
4630
4631 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02004632 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004633 if (node->nodetype & (LYS_LEAF | LYS_ANYDATA | LYS_CHOICE)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004634 /* remove current value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004635 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004636
4637 /* set new value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004638 node->flags |= (rfn->flags & LYS_MAND_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004639 }
Pavol Vican855ca622016-09-05 13:07:54 +02004640 if (rfn->flags & LYS_MAND_TRUE) {
4641 /* check if node has default value */
4642 if ((node->nodetype & LYS_LEAF) && ((struct lys_node_leaf *)node)->dflt) {
4643 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"mandatory\" statement is forbidden on leaf with \"default\".");
4644 goto fail;
4645 }
4646 if ((node->nodetype & LYS_CHOICE) && ((struct lys_node_choice *)node)->dflt) {
4647 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"mandatory\" statement is forbidden on choices with \"default\".");
4648 goto fail;
4649 }
4650 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004651 }
4652
4653 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004654 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
4655 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
4656 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004657 }
4658
4659 /* min/max-elements on list or leaf-list */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004660 if (node->nodetype == LYS_LIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004661 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004662 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004663 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004664 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004665 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004666 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02004667 } else if (node->nodetype == LYS_LEAFLIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004668 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004669 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004670 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004671 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004672 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004673 }
4674 }
4675
4676 /* must in leaf, leaf-list, list, container or anyxml */
4677 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004678 switch (node->nodetype) {
4679 case LYS_LEAF:
4680 old_size = &((struct lys_node_leaf *)node)->must_size;
4681 old_must = &((struct lys_node_leaf *)node)->must;
4682 break;
4683 case LYS_LEAFLIST:
4684 old_size = &((struct lys_node_leaflist *)node)->must_size;
4685 old_must = &((struct lys_node_leaflist *)node)->must;
4686 break;
4687 case LYS_LIST:
4688 old_size = &((struct lys_node_list *)node)->must_size;
4689 old_must = &((struct lys_node_list *)node)->must;
4690 break;
4691 case LYS_CONTAINER:
4692 old_size = &((struct lys_node_container *)node)->must_size;
4693 old_must = &((struct lys_node_container *)node)->must;
4694 break;
4695 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02004696 case LYS_ANYDATA:
4697 old_size = &((struct lys_node_anydata *)node)->must_size;
4698 old_must = &((struct lys_node_anydata *)node)->must;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004699 break;
4700 default:
4701 LOGINT;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004702 goto fail;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004703 }
4704
4705 size = *old_size + rfn->must_size;
4706 must = realloc(*old_must, size * sizeof *rfn->must);
4707 if (!must) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004708 LOGMEM;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004709 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004710 }
Pavol Vican855ca622016-09-05 13:07:54 +02004711 for (k = 0, j = *old_size; k < rfn->must_size; k++, j++) {
4712 must[j].expr = lydict_insert(ctx, rfn->must[k].expr, 0);
4713 must[j].dsc = lydict_insert(ctx, rfn->must[k].dsc, 0);
4714 must[j].ref = lydict_insert(ctx, rfn->must[k].ref, 0);
4715 must[j].eapptag = lydict_insert(ctx, rfn->must[k].eapptag, 0);
4716 must[j].emsg = lydict_insert(ctx, rfn->must[k].emsg, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004717 }
4718
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004719 *old_must = must;
4720 *old_size = size;
Michal Vasko508a50d2016-09-07 14:50:33 +02004721
4722 /* check XPath dependencies again */
4723 if (unres_schema_add_node(node->module, unres, node, UNRES_XPATH, NULL) == -1) {
4724 goto fail;
4725 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004726 }
Radek Krejci363bd4a2016-07-29 14:30:20 +02004727
4728 /* if-feature in leaf, leaf-list, list, container or anyxml */
4729 if (rfn->iffeature_size) {
4730 old_size = &node->iffeature_size;
4731 old_iff = &node->iffeature;
4732
4733 size = *old_size + rfn->iffeature_size;
4734 iff = realloc(*old_iff, size * sizeof *rfn->iffeature);
4735 if (!iff) {
4736 LOGMEM;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004737 goto fail;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004738 }
Pavol Vican855ca622016-09-05 13:07:54 +02004739 for (k = 0, j = *old_size; k < rfn->iffeature_size; k++, j++) {
4740 resolve_iffeature_getsizes(&rfn->iffeature[k], &usize1, &usize2);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004741 if (usize1) {
4742 /* there is something to duplicate */
4743 /* duplicate compiled expression */
4744 usize = (usize1 / 4) + (usize1 % 4) ? 1 : 0;
4745 iff[j].expr = malloc(usize * sizeof *iff[j].expr);
Pavol Vican855ca622016-09-05 13:07:54 +02004746 memcpy(iff[j].expr, rfn->iffeature[k].expr, usize * sizeof *iff[j].expr);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004747
4748 /* duplicate list of feature pointers */
Pavol Vican855ca622016-09-05 13:07:54 +02004749 iff[j].features = malloc(usize2 * sizeof *iff[k].features);
4750 memcpy(iff[j].features, rfn->iffeature[k].features, usize2 * sizeof *iff[j].features);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004751 }
4752 }
4753
4754 *old_iff = iff;
4755 *old_size = size;
4756 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004757 }
4758
4759 /* apply augments */
4760 for (i = 0; i < uses->augment_size; i++) {
Radek Krejcib3142312016-11-09 11:04:12 +01004761 rc = resolve_augment(&uses->augment[i], uses->child, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004762 if (rc) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004763 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004764 }
4765 }
4766
Pavol Vican855ca622016-09-05 13:07:54 +02004767 /* check refines */
4768 for (i = 0; i < uses->refine_size; i++) {
4769 node = refine_nodes[i];
4770 rfn = &uses->refine[i];
4771
4772 /* config on any nodetype */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004773 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Pavol Vican855ca622016-09-05 13:07:54 +02004774 for (parent = lys_parent(node); parent && parent->nodetype == LYS_USES; parent = lys_parent(parent));
Radek Krejci5c08a992016-11-02 13:30:04 +01004775 if (parent && parent->nodetype != LYS_GROUPING && (parent->flags & LYS_CONFIG_MASK) &&
Pavol Vican855ca622016-09-05 13:07:54 +02004776 ((parent->flags & LYS_CONFIG_MASK) != (rfn->flags & LYS_CONFIG_MASK)) &&
4777 (rfn->flags & LYS_CONFIG_W)) {
4778 /* setting config true under config false is prohibited */
4779 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
4780 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4781 "changing config from 'false' to 'true' is prohibited while "
4782 "the target's parent is still config 'false'.");
4783 goto fail;
4784 }
4785
4786 /* inherit config change to the target children */
4787 LY_TREE_DFS_BEGIN(node->child, next, iter) {
4788 if (rfn->flags & LYS_CONFIG_W) {
4789 if (iter->flags & LYS_CONFIG_SET) {
4790 /* config is set explicitely, go to next sibling */
4791 next = NULL;
4792 goto nextsibling;
4793 }
4794 } else { /* LYS_CONFIG_R */
4795 if ((iter->flags & LYS_CONFIG_SET) && (iter->flags & LYS_CONFIG_W)) {
4796 /* error - we would have config data under status data */
4797 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
4798 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4799 "changing config from 'true' to 'false' is prohibited while the target "
4800 "has still a children with explicit config 'true'.");
4801 goto fail;
4802 }
4803 }
4804 /* change config */
4805 iter->flags &= ~LYS_CONFIG_MASK;
4806 iter->flags |= (rfn->flags & LYS_CONFIG_MASK);
4807
4808 /* select next iter - modified LY_TREE_DFS_END */
4809 if (iter->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
4810 next = NULL;
4811 } else {
4812 next = iter->child;
4813 }
4814nextsibling:
4815 if (!next) {
4816 /* try siblings */
4817 next = iter->next;
4818 }
4819 while (!next) {
4820 /* parent is already processed, go to its sibling */
4821 iter = lys_parent(iter);
4822
4823 /* no siblings, go back through parents */
4824 if (iter == node) {
4825 /* we are done, no next element to process */
4826 break;
4827 }
4828 next = iter->next;
4829 }
4830 }
4831 }
4832
4833 /* default value */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004834 if (rfn->dflt_size) {
4835 if (node->nodetype == LYS_CHOICE) {
4836 /* choice */
4837 ((struct lys_node_choice *)node)->dflt = resolve_choice_dflt((struct lys_node_choice *)node,
4838 rfn->dflt[0]);
4839 if (!((struct lys_node_choice *)node)->dflt) {
4840 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->dflt[0], "default");
4841 goto fail;
4842 }
4843 if (lyp_check_mandatory_choice(node)) {
4844 goto fail;
4845 }
Pavol Vican855ca622016-09-05 13:07:54 +02004846 }
4847 }
4848
4849 /* min/max-elements on list or leaf-list */
4850 if (node->nodetype == LYS_LIST) {
4851 if (((struct lys_node_list *)node)->min > ((struct lys_node_list *)node)->max) {
4852 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
4853 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "\"min-elements\" is bigger than \"max-elements\".");
4854 goto fail;
4855 }
4856 } else if (node->nodetype == LYS_LEAFLIST) {
4857 if (((struct lys_node_leaflist *)node)->min > ((struct lys_node_leaflist *)node)->max) {
4858 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
4859 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "\"min-elements\" is bigger than \"max-elements\".");
4860 goto fail;
4861 }
4862 }
4863
4864 /* additional checks */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004865 /* default value with mandatory/min-elements */
Pavol Vican855ca622016-09-05 13:07:54 +02004866 if (node->nodetype == LYS_LEAFLIST) {
4867 llist = (struct lys_node_leaflist *)node;
4868 if (llist->dflt_size && llist->min) {
4869 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, rfn->dflt_size ? "default" : "min-elements", "refine");
4870 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
4871 "The \"min-elements\" statement with non-zero value is forbidden on leaf-lists with the \"default\" statement.");
4872 goto fail;
4873 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004874 } else if (node->nodetype == LYS_LEAF) {
4875 leaf = (struct lys_node_leaf *)node;
4876 if (leaf->dflt && (leaf->flags & LYS_MAND_TRUE)) {
4877 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, rfn->dflt_size ? "default" : "mandatory", "refine");
4878 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
4879 "The \"mandatory\" statement is forbidden on leafs with the \"default\" statement.");
4880 goto fail;
4881 }
Pavol Vican855ca622016-09-05 13:07:54 +02004882 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004883
Pavol Vican855ca622016-09-05 13:07:54 +02004884 /* check for mandatory node in default case, first find the closest parent choice to the changed node */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004885 if ((rfn->flags & LYS_MAND_TRUE) || rfn->mod.list.min) {
Pavol Vican855ca622016-09-05 13:07:54 +02004886 for (parent = node->parent;
4887 parent && !(parent->nodetype & (LYS_CHOICE | LYS_GROUPING | LYS_ACTION | LYS_USES));
4888 parent = parent->parent) {
4889 if (parent->nodetype == LYS_CONTAINER && ((struct lys_node_container *)parent)->presence) {
4890 /* stop also on presence containers */
4891 break;
4892 }
4893 }
4894 /* and if it is a choice with the default case, check it for presence of a mandatory node in it */
4895 if (parent && parent->nodetype == LYS_CHOICE && ((struct lys_node_choice *)parent)->dflt) {
4896 if (lyp_check_mandatory_choice(parent)) {
4897 goto fail;
4898 }
4899 }
4900 }
4901 }
4902 free(refine_nodes);
4903
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004904 return EXIT_SUCCESS;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004905
4906fail:
4907 LY_TREE_FOR_SAFE(uses->child, next, iter) {
4908 lys_node_free(iter, NULL, 0);
4909 }
Pavol Vican855ca622016-09-05 13:07:54 +02004910 free(refine_nodes);
Michal Vaskoa86508c2016-08-26 14:30:19 +02004911 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004912}
4913
Radek Krejci018f1f52016-08-03 16:01:20 +02004914static int
4915identity_backlink_update(struct lys_ident *der, struct lys_ident *base)
4916{
4917 int i;
4918
4919 assert(der && base);
4920
Radek Krejci018f1f52016-08-03 16:01:20 +02004921 if (!base->der) {
Radek Krejci85a54be2016-10-20 12:39:56 +02004922 /* create a set for backlinks if it does not exist */
4923 base->der = ly_set_new();
Radek Krejci018f1f52016-08-03 16:01:20 +02004924 }
Radek Krejci85a54be2016-10-20 12:39:56 +02004925 /* store backlink */
4926 ly_set_add(base->der, der, LY_SET_OPT_USEASLIST);
Radek Krejci018f1f52016-08-03 16:01:20 +02004927
Radek Krejci85a54be2016-10-20 12:39:56 +02004928 /* do it recursively */
Radek Krejci018f1f52016-08-03 16:01:20 +02004929 for (i = 0; i < base->base_size; i++) {
4930 if (identity_backlink_update(der, base->base[i])) {
4931 return EXIT_FAILURE;
4932 }
4933 }
4934
4935 return EXIT_SUCCESS;
4936}
4937
Michal Vasko730dfdf2015-08-11 14:48:05 +02004938/**
4939 * @brief Resolve base identity recursively. Does not log.
4940 *
4941 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004942 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004943 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004944 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004945 *
Radek Krejci219fa612016-08-15 10:36:51 +02004946 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on crucial error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004947 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004948static int
Michal Vasko1e62a092015-12-01 12:27:20 +01004949resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Radek Krejci018f1f52016-08-03 16:01:20 +02004950 struct unres_schema *unres, struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004951{
Michal Vaskof02e3742015-08-05 16:27:02 +02004952 uint32_t i, j;
Radek Krejci018f1f52016-08-03 16:01:20 +02004953 struct lys_ident *base = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004954
Radek Krejcicf509982015-12-15 09:22:44 +01004955 assert(ret);
4956
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004957 /* search module */
4958 for (i = 0; i < module->ident_size; i++) {
4959 if (!strcmp(basename, module->ident[i].name)) {
4960
4961 if (!ident) {
4962 /* just search for type, so do not modify anything, just return
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004963 * the base identity pointer */
Radek Krejcicf509982015-12-15 09:22:44 +01004964 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004965 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004966 }
4967
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004968 base = &module->ident[i];
4969 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004970 }
4971 }
4972
4973 /* search submodules */
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004974 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
4975 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
4976 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004977
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004978 if (!ident) {
4979 *ret = &module->inc[j].submodule->ident[i];
4980 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004981 }
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004982
4983 base = &module->inc[j].submodule->ident[i];
4984 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004985 }
4986 }
4987 }
4988
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004989matchfound:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004990 /* we found it somewhere */
Radek Krejcibabbff82016-02-19 13:31:37 +01004991 if (base) {
Radek Krejci018f1f52016-08-03 16:01:20 +02004992 /* is it already completely resolved? */
4993 for (i = 0; i < unres->count; i++) {
Radek Krejciba7b1cc2016-08-08 13:44:43 +02004994 if ((unres->item[i] == base) && (unres->type[i] == UNRES_IDENT)) {
Radek Krejci018f1f52016-08-03 16:01:20 +02004995 /* identity found, but not yet resolved, so do not return it in *res and try it again later */
4996
4997 /* simple check for circular reference,
4998 * the complete check is done as a side effect of using only completely
4999 * resolved identities (previous check of unres content) */
5000 if (ly_strequal((const char *)unres->str_snode[i], ident->name, 1)) {
5001 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, basename, "base");
5002 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Circular reference of \"%s\" identity.", basename);
Radek Krejci219fa612016-08-15 10:36:51 +02005003 return -1;
Radek Krejci018f1f52016-08-03 16:01:20 +02005004 }
5005
Radek Krejci06f64ed2016-08-15 11:07:44 +02005006 return EXIT_FAILURE;
Radek Krejcibabbff82016-02-19 13:31:37 +01005007 }
5008 }
Radek Krejci018f1f52016-08-03 16:01:20 +02005009
Radek Krejcibabbff82016-02-19 13:31:37 +01005010 /* checks done, store the result */
Radek Krejci018f1f52016-08-03 16:01:20 +02005011 *ret = base;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02005012 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005013 }
5014
Radek Krejci219fa612016-08-15 10:36:51 +02005015 /* base not found (maybe a forward reference) */
5016 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005017}
5018
Michal Vasko730dfdf2015-08-11 14:48:05 +02005019/**
5020 * @brief Resolve base identity. Logs directly.
5021 *
5022 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02005023 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005024 * @param[in] basename Base name of the identity.
Radek Krejcibabbff82016-02-19 13:31:37 +01005025 * @param[in] parent Either "type" or "identity".
Radek Krejcicf509982015-12-15 09:22:44 +01005026 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005027 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005028 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005029 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005030static int
Michal Vaskof2d43962016-09-02 11:10:16 +02005031resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char *parent,
Radek Krejci018f1f52016-08-03 16:01:20 +02005032 struct lys_type *type, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005033{
5034 const char *name;
Radek Krejci219fa612016-08-15 10:36:51 +02005035 int mod_name_len = 0, rc;
Radek Krejcicf509982015-12-15 09:22:44 +01005036 struct lys_ident *target, **ret;
Radek Krejci4372b4e2016-04-14 17:42:16 +02005037 uint16_t flags;
Radek Krejcicf509982015-12-15 09:22:44 +01005038 struct lys_module *mod;
5039
5040 assert((ident && !type) || (!ident && type));
5041
5042 if (!type) {
5043 /* have ident to resolve */
5044 ret = &target;
5045 flags = ident->flags;
5046 mod = ident->module;
5047 } else {
5048 /* have type to fill */
Michal Vaskof2d43962016-09-02 11:10:16 +02005049 ++type->info.ident.count;
5050 type->info.ident.ref = ly_realloc(type->info.ident.ref, type->info.ident.count * sizeof *type->info.ident.ref);
5051 if (!type->info.ident.ref) {
5052 LOGMEM;
5053 return -1;
5054 }
5055
5056 ret = &type->info.ident.ref[type->info.ident.count - 1];
Radek Krejcicf509982015-12-15 09:22:44 +01005057 flags = type->parent->flags;
5058 mod = type->parent->module;
5059 }
Michal Vaskof2006002016-04-21 16:28:15 +02005060 *ret = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005061
5062 /* search for the base identity */
5063 name = strchr(basename, ':');
5064 if (name) {
5065 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02005066 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005067 name++;
5068
Michal Vasko2d851a92015-10-20 16:16:36 +02005069 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005070 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02005071 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005072 }
5073 } else {
5074 name = basename;
5075 }
5076
Radek Krejcic071c542016-01-27 14:57:51 +01005077 /* get module where to search */
5078 module = lys_get_import_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len);
5079 if (!module) {
5080 /* identity refers unknown data model */
Radek Krejci02a04992016-03-17 16:06:37 +01005081 LOGVAL(LYE_INMOD, LY_VLOG_NONE, NULL, basename);
Radek Krejcic071c542016-01-27 14:57:51 +01005082 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005083 }
5084
Radek Krejcic071c542016-01-27 14:57:51 +01005085 /* search in the identified module ... */
Radek Krejci219fa612016-08-15 10:36:51 +02005086 rc = resolve_base_ident_sub(module, ident, name, unres, ret);
5087 if (!rc) {
5088 assert(*ret);
5089
5090 /* check status */
5091 if (lyp_check_status(flags, mod, ident ? ident->name : "of type",
5092 (*ret)->flags, (*ret)->module, (*ret)->name, NULL)) {
5093 rc = -1;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02005094 } else {
5095 if (ident) {
5096 ident->base[ident->base_size++] = *ret;
5097
5098 /* maintain backlinks to the derived identities */
5099 rc = identity_backlink_update(ident, *ret) ? -1 : EXIT_SUCCESS;
5100 }
Radek Krejci219fa612016-08-15 10:36:51 +02005101 }
5102 } else if (rc == EXIT_FAILURE) {
5103 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, parent, basename);
Pavol Vican053a2882016-09-05 14:40:33 +02005104 if (type) {
5105 --type->info.ident.count;
5106 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005107 }
5108
Radek Krejci219fa612016-08-15 10:36:51 +02005109 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005110}
5111
Michal Vasko730dfdf2015-08-11 14:48:05 +02005112/**
Michal Vaskof39142b2015-10-21 11:40:05 +02005113 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005114 *
Michal Vaskof2d43962016-09-02 11:10:16 +02005115 * @param[in] type Identityref type.
Michal Vaskofb0873c2015-08-21 09:00:07 +02005116 * @param[in] ident_name Identityref name.
Radek Krejciadb57612016-02-16 13:34:34 +01005117 * @param[in] node Node where the identityref is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02005118 *
5119 * @return Pointer to the identity resolvent, NULL on error.
5120 */
Radek Krejcia52656e2015-08-05 13:41:50 +02005121struct lys_ident *
Michal Vaskof2d43962016-09-02 11:10:16 +02005122resolve_identref(struct lys_type *type, const char *ident_name, struct lyd_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005123{
Radek Krejci639491e2016-12-05 13:30:42 +01005124 const char *mod_name, *name, *mod_name_iter;
Radek Krejci85a54be2016-10-20 12:39:56 +02005125 int mod_name_len, rc, i;
5126 unsigned int u;
Michal Vaskof2d43962016-09-02 11:10:16 +02005127 struct lys_ident *der, *cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005128
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005129 assert(type && ident_name && node);
5130
Michal Vaskof2d43962016-09-02 11:10:16 +02005131 if (!type || (!type->info.ident.count && !type->der) || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005132 return NULL;
5133 }
5134
Michal Vaskoc633ca02015-08-21 14:03:51 +02005135 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, NULL);
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005136 if (rc < 1) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005137 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005138 return NULL;
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005139 } else if (rc < (signed)strlen(ident_name)) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005140 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[rc], &ident_name[rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005141 return NULL;
5142 }
Radek Krejcif32c5f62016-12-05 09:27:38 +01005143 if (!mod_name) {
5144 /* no prefix, identity must be defined in the same module as node */
Radek Krejci639491e2016-12-05 13:30:42 +01005145 mod_name = lys_main_module(node->schema->module)->name;
Radek Krejcif32c5f62016-12-05 09:27:38 +01005146 mod_name_len = strlen(mod_name);
5147 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02005148
Michal Vaskof2d43962016-09-02 11:10:16 +02005149 /* go through all the bases in all the derived types */
5150 while (type->der) {
5151 for (i = 0; i < type->info.ident.count; ++i) {
5152 cur = type->info.ident.ref[i];
Radek Krejci639491e2016-12-05 13:30:42 +01005153 mod_name_iter = lys_main_module(cur->module)->name;
Radek Krejcif32c5f62016-12-05 09:27:38 +01005154 if (!strcmp(cur->name, name) &&
Radek Krejci639491e2016-12-05 13:30:42 +01005155 !strncmp(mod_name_iter, mod_name, mod_name_len) && !mod_name_iter[mod_name_len]) {
Michal Vaskof2d43962016-09-02 11:10:16 +02005156 goto match;
5157 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02005158
Radek Krejci85a54be2016-10-20 12:39:56 +02005159 if (cur->der) {
5160 /* there are also some derived identities */
5161 for (u = 0; u < cur->der->number; u++) {
5162 der = (struct lys_ident *)cur->der->set.g[u]; /* shortcut */
Radek Krejci639491e2016-12-05 13:30:42 +01005163 mod_name_iter = lys_main_module(der->module)->name;
Radek Krejci85a54be2016-10-20 12:39:56 +02005164 if (!strcmp(der->name, name) &&
Radek Krejci639491e2016-12-05 13:30:42 +01005165 !strncmp(mod_name_iter, mod_name, mod_name_len) && !mod_name_iter[mod_name_len]) {
Radek Krejci85a54be2016-10-20 12:39:56 +02005166 /* we have match */
5167 cur = der;
5168 goto match;
5169 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005170 }
5171 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005172 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005173 type = &type->der->type;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005174 }
5175
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005176 LOGVAL(LYE_INRESOLV, LY_VLOG_LYD, node, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005177 return NULL;
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005178
5179match:
Michal Vaskof2d43962016-09-02 11:10:16 +02005180 for (i = 0; i < cur->iffeature_size; i++) {
5181 if (!resolve_iffeature(&cur->iffeature[i])) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005182 LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, cur->name, node->schema->name);
5183 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 +02005184 return NULL;
5185 }
5186 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005187 return cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005188}
5189
Michal Vasko730dfdf2015-08-11 14:48:05 +02005190/**
Michal Vaskobb211122015-08-19 14:03:11 +02005191 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005192 *
Michal Vaskobb211122015-08-19 14:03:11 +02005193 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005194 * @param[in] unres Specific unres item.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005195 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005196 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005197 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005198static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005199resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005200{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005201 int rc;
Radek Krejci010e54b2016-03-15 09:40:34 +01005202 struct lys_node *par_grp;
Michal Vaskoe91afce2015-08-12 12:21:00 +02005203
Radek Krejci010e54b2016-03-15 09:40:34 +01005204 /* HACK: when a grouping has uses inside, all such uses have to be resolved before the grouping itself
5205 * is used in some uses. When we see such a uses, the grouping's nacm member (not used in grouping)
5206 * is used to store number of so far unresolved uses. The grouping cannot be used unless the nacm
5207 * value is decreased back to 0. To remember that the uses already increased grouping's nacm, the
5208 * LYS_USESGRP flag is used. */
Michal Vaskodcf98e62016-05-05 17:53:53 +02005209 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 +02005210
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005211 if (!uses->grp) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01005212 rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
5213 if (rc == -1) {
Michal Vasko92981a62016-10-14 10:25:16 +02005214 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005215 return -1;
5216 } else if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005217 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005218 return -1;
5219 } else if (!uses->grp) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005220 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005221 /* hack - in contrast to lys_node, lys_node_grp has bigger nacm field
5222 * (and smaller flags - it uses only a limited set of flags)
5223 */
5224 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci010e54b2016-03-15 09:40:34 +01005225 uses->flags |= LYS_USESGRP;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005226 }
Michal Vasko92981a62016-10-14 10:25:16 +02005227 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005228 return EXIT_FAILURE;
Michal Vasko12e30842015-08-04 11:54:00 +02005229 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005230 }
5231
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005232 if (uses->grp->nacm) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005233 if (par_grp && !(uses->flags & LYS_USESGRP)) {
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;
Radek Krejcie00d2312016-08-12 15:27:49 +02005236 } else {
5237 /* instantiate grouping only when it is completely resolved */
5238 uses->grp = NULL;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005239 }
Michal Vasko92981a62016-10-14 10:25:16 +02005240 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005241 return EXIT_FAILURE;
5242 }
5243
Radek Krejci48464ed2016-03-17 15:44:09 +01005244 rc = resolve_uses(uses, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005245 if (!rc) {
5246 /* decrease unres count only if not first try */
Radek Krejci010e54b2016-03-15 09:40:34 +01005247 if (par_grp && (uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005248 if (!((struct lys_node_grp *)par_grp)->nacm) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005249 LOGINT;
5250 return -1;
5251 }
Radek Krejci4372b4e2016-04-14 17:42:16 +02005252 ((struct lys_node_grp *)par_grp)->nacm--;
Radek Krejci010e54b2016-03-15 09:40:34 +01005253 uses->flags &= ~LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005254 }
Radek Krejcicf509982015-12-15 09:22:44 +01005255
5256 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005257 if (lyp_check_status(uses->flags, uses->module, "of uses",
Radek Krejciadb57612016-02-16 13:34:34 +01005258 uses->grp->flags, uses->grp->module, uses->grp->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005259 (struct lys_node *)uses)) {
Radek Krejcicf509982015-12-15 09:22:44 +01005260 return -1;
5261 }
5262
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005263 return EXIT_SUCCESS;
5264 }
5265
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005266 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005267}
5268
Michal Vasko730dfdf2015-08-11 14:48:05 +02005269/**
Michal Vasko9957e592015-08-17 15:04:09 +02005270 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005271 *
Michal Vaskobb211122015-08-19 14:03:11 +02005272 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005273 * @param[in] keys_str Keys node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005274 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005275 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005276 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005277static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005278resolve_list_keys(struct lys_node_list *list, const char *keys_str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005279{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005280 int i, len, rc;
Michal Vasko4f0dad02016-02-15 14:08:23 +01005281 const char *value;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005282
5283 for (i = 0; i < list->keys_size; ++i) {
Radek Krejci5c08a992016-11-02 13:30:04 +01005284 if (!list->child) {
5285 /* no child, possible forward reference */
5286 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
5287 return EXIT_FAILURE;
5288 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005289 /* get the key name */
5290 if ((value = strpbrk(keys_str, " \t\n"))) {
5291 len = value - keys_str;
5292 while (isspace(value[0])) {
5293 value++;
5294 }
5295 } else {
5296 len = strlen(keys_str);
5297 }
5298
Radek Krejcic4283442016-04-22 09:19:27 +02005299 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 +02005300 if (rc) {
Michal Vasko7a55bea2016-05-02 14:51:20 +02005301 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
5302 return EXIT_FAILURE;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005303 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005304
Radek Krejci48464ed2016-03-17 15:44:09 +01005305 if (check_key(list, i, keys_str, len)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005306 /* check_key logs */
5307 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005308 }
5309
Radek Krejcicf509982015-12-15 09:22:44 +01005310 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005311 if (lyp_check_status(list->flags, list->module, list->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005312 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
5313 (struct lys_node *)list->keys[i])) {
Radek Krejcicf509982015-12-15 09:22:44 +01005314 return -1;
5315 }
5316
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005317 /* prepare for next iteration */
5318 while (value && isspace(value[0])) {
5319 value++;
5320 }
5321 keys_str = value;
5322 }
5323
Michal Vaskof02e3742015-08-05 16:27:02 +02005324 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005325}
5326
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005327/**
Michal Vaskobf19d252015-10-08 15:39:17 +02005328 * @brief Resolve (check) all must conditions of \p node.
5329 * Logs directly.
5330 *
5331 * @param[in] node Data node with optional must statements.
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005332 * @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 +02005333 *
5334 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
5335 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005336static int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005337resolve_must(struct lyd_node *node, int inout_parent, int ignore_fail)
Michal Vaskof02e3742015-08-05 16:27:02 +02005338{
Michal Vaskobf19d252015-10-08 15:39:17 +02005339 uint8_t i, must_size;
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005340 struct lys_node *schema;
Michal Vaskobf19d252015-10-08 15:39:17 +02005341 struct lys_restr *must;
5342 struct lyxp_set set;
5343
5344 assert(node);
5345 memset(&set, 0, sizeof set);
5346
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005347 if (inout_parent) {
5348 for (schema = lys_parent(node->schema);
5349 schema && (schema->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES));
5350 schema = lys_parent(schema));
5351 if (!schema || !(schema->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5352 LOGINT;
5353 return -1;
5354 }
5355 must_size = ((struct lys_node_inout *)schema)->must_size;
5356 must = ((struct lys_node_inout *)schema)->must;
5357
5358 /* context node is the RPC/action */
5359 node = node->parent;
5360 if (!(node->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
5361 LOGINT;
5362 return -1;
5363 }
5364 } else {
5365 switch (node->schema->nodetype) {
5366 case LYS_CONTAINER:
5367 must_size = ((struct lys_node_container *)node->schema)->must_size;
5368 must = ((struct lys_node_container *)node->schema)->must;
5369 break;
5370 case LYS_LEAF:
5371 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
5372 must = ((struct lys_node_leaf *)node->schema)->must;
5373 break;
5374 case LYS_LEAFLIST:
5375 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
5376 must = ((struct lys_node_leaflist *)node->schema)->must;
5377 break;
5378 case LYS_LIST:
5379 must_size = ((struct lys_node_list *)node->schema)->must_size;
5380 must = ((struct lys_node_list *)node->schema)->must;
5381 break;
5382 case LYS_ANYXML:
5383 case LYS_ANYDATA:
5384 must_size = ((struct lys_node_anydata *)node->schema)->must_size;
5385 must = ((struct lys_node_anydata *)node->schema)->must;
5386 break;
5387 case LYS_NOTIF:
5388 must_size = ((struct lys_node_notif *)node->schema)->must_size;
5389 must = ((struct lys_node_notif *)node->schema)->must;
5390 break;
5391 default:
5392 must_size = 0;
5393 break;
5394 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005395 }
5396
5397 for (i = 0; i < must_size; ++i) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005398 if (lyxp_eval(must[i].expr, node, LYXP_NODE_ELEM, lyd_node_module(node), &set, LYXP_MUST)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02005399 return -1;
5400 }
5401
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005402 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_MUST);
Michal Vaskobf19d252015-10-08 15:39:17 +02005403
Michal Vasko8146d4c2016-05-09 15:50:29 +02005404 if (!set.val.bool) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005405 if (ignore_fail) {
5406 LOGVRB("Must condition \"%s\" not satisfied, but it is not required.", must[i].expr);
5407 } else {
5408 LOGVAL(LYE_NOMUST, LY_VLOG_LYD, node, must[i].expr);
5409 if (must[i].emsg) {
5410 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, must[i].emsg);
5411 }
5412 if (must[i].eapptag) {
5413 strncpy(((struct ly_err *)&ly_errno)->apptag, must[i].eapptag, LY_APPTAG_LEN - 1);
5414 }
5415 return 1;
Michal Vasko6ac68282016-04-11 10:56:47 +02005416 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005417 }
5418 }
5419
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005420 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02005421}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005422
Michal Vaskobf19d252015-10-08 15:39:17 +02005423/**
Michal Vasko508a50d2016-09-07 14:50:33 +02005424 * @brief Resolve (find) when condition schema context node. Does not log.
5425 *
5426 * @param[in] schema Schema node with the when condition.
5427 * @param[out] ctx_snode When schema context node.
5428 * @param[out] ctx_snode_type Schema context node type.
5429 */
5430void
5431resolve_when_ctx_snode(const struct lys_node *schema, struct lys_node **ctx_snode, enum lyxp_node_type *ctx_snode_type)
5432{
5433 const struct lys_node *sparent;
5434
5435 /* find a not schema-only node */
5436 *ctx_snode_type = LYXP_NODE_ELEM;
5437 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
5438 if (schema->nodetype == LYS_AUGMENT) {
5439 sparent = ((struct lys_node_augment *)schema)->target;
5440 } else {
5441 sparent = schema->parent;
5442 }
5443 if (!sparent) {
5444 /* context node is the document root (fake root in our case) */
5445 if (schema->flags & LYS_CONFIG_W) {
5446 *ctx_snode_type = LYXP_NODE_ROOT_CONFIG;
5447 } else {
Michal Vaskob94a5e42016-09-08 14:01:56 +02005448 *ctx_snode_type = LYXP_NODE_ROOT;
Michal Vasko508a50d2016-09-07 14:50:33 +02005449 }
Michal Vasko2d2aec12016-09-08 11:42:50 +02005450 /* we need the first top-level sibling, but no uses or groupings */
Michal Vaskob94a5e42016-09-08 14:01:56 +02005451 schema = lys_getnext(NULL, NULL, lys_node_module(schema), 0);
Michal Vasko508a50d2016-09-07 14:50:33 +02005452 break;
5453 }
5454 schema = sparent;
5455 }
5456
5457 *ctx_snode = (struct lys_node *)schema;
5458}
5459
5460/**
Michal Vaskocf024702015-10-08 15:01:42 +02005461 * @brief Resolve (find) when condition context node. Does not log.
5462 *
5463 * @param[in] node Data node, whose conditional definition is being decided.
Michal Vasko508a50d2016-09-07 14:50:33 +02005464 * @param[in] schema Schema node with the when condition.
Michal Vaskoa59495d2016-08-22 09:18:58 +02005465 * @param[out] ctx_node Context node.
5466 * @param[out] ctx_node_type Context node type.
Michal Vaskocf024702015-10-08 15:01:42 +02005467 *
Michal Vaskoa59495d2016-08-22 09:18:58 +02005468 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vaskocf024702015-10-08 15:01:42 +02005469 */
Michal Vaskoa59495d2016-08-22 09:18:58 +02005470static int
5471resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema, struct lyd_node **ctx_node,
5472 enum lyxp_node_type *ctx_node_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005473{
Michal Vaskocf024702015-10-08 15:01:42 +02005474 struct lyd_node *parent;
5475 struct lys_node *sparent;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005476 enum lyxp_node_type node_type;
Michal Vaskocf024702015-10-08 15:01:42 +02005477 uint16_t i, data_depth, schema_depth;
5478
Michal Vasko508a50d2016-09-07 14:50:33 +02005479 resolve_when_ctx_snode(schema, &schema, &node_type);
Michal Vaskocf024702015-10-08 15:01:42 +02005480
Michal Vaskofe989752016-09-08 08:47:26 +02005481 if (node_type == LYXP_NODE_ELEM) {
5482 /* standard element context node */
5483 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
5484 for (sparent = schema, schema_depth = 0;
5485 sparent;
5486 sparent = (sparent->nodetype == LYS_AUGMENT ? ((struct lys_node_augment *)sparent)->target : sparent->parent)) {
5487 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_NOTIF | LYS_RPC)) {
5488 ++schema_depth;
5489 }
Michal Vaskocf024702015-10-08 15:01:42 +02005490 }
Michal Vaskofe989752016-09-08 08:47:26 +02005491 if (data_depth < schema_depth) {
5492 return -1;
5493 }
Michal Vaskocf024702015-10-08 15:01:42 +02005494
Michal Vasko956e8542016-08-26 09:43:35 +02005495 /* find the corresponding data node */
5496 for (i = 0; i < data_depth - schema_depth; ++i) {
5497 node = node->parent;
5498 }
Michal Vaskoa59495d2016-08-22 09:18:58 +02005499 if (node->schema != schema) {
5500 return -1;
5501 }
Michal Vaskofe989752016-09-08 08:47:26 +02005502 } else {
5503 /* root context node */
5504 while (node->parent) {
5505 node = node->parent;
5506 }
5507 while (node->prev->next) {
5508 node = node->prev;
5509 }
Michal Vaskocf024702015-10-08 15:01:42 +02005510 }
5511
Michal Vaskoa59495d2016-08-22 09:18:58 +02005512 *ctx_node = node;
5513 *ctx_node_type = node_type;
5514 return EXIT_SUCCESS;
Michal Vaskocf024702015-10-08 15:01:42 +02005515}
5516
Michal Vasko76c3bd32016-08-24 16:02:52 +02005517/**
5518 * @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 +01005519 * The context node is adjusted if needed.
Michal Vasko76c3bd32016-08-24 16:02:52 +02005520 *
5521 * @param[in] snode Schema node, whose children instances need to be unlinked.
5522 * @param[in,out] node Data siblings where to look for the children of \p snode. If it is unlinked,
5523 * it is moved to point to another sibling still in the original tree.
5524 * @param[in,out] ctx_node When context node, adjusted if needed.
5525 * @param[in] ctx_node_type Context node type, just for information to detect invalid situations.
5526 * @param[out] unlinked_nodes Unlinked siblings. Can be safely appended to \p node afterwards.
5527 * Ordering may change, but there will be no semantic change.
5528 *
5529 * @return EXIT_SUCCESS on success, -1 on error.
5530 */
5531static int
5532resolve_when_unlink_nodes(struct lys_node *snode, struct lyd_node **node, struct lyd_node **ctx_node,
5533 enum lyxp_node_type ctx_node_type, struct lyd_node **unlinked_nodes)
5534{
5535 struct lyd_node *next, *elem;
5536
5537 switch (snode->nodetype) {
5538 case LYS_AUGMENT:
5539 case LYS_USES:
5540 case LYS_CHOICE:
5541 case LYS_CASE:
5542 LY_TREE_FOR(snode->child, snode) {
5543 if (resolve_when_unlink_nodes(snode, node, ctx_node, ctx_node_type, unlinked_nodes)) {
5544 return -1;
5545 }
5546 }
5547 break;
5548 case LYS_CONTAINER:
5549 case LYS_LIST:
5550 case LYS_LEAF:
5551 case LYS_LEAFLIST:
5552 case LYS_ANYXML:
5553 case LYS_ANYDATA:
5554 LY_TREE_FOR_SAFE(lyd_first_sibling(*node), next, elem) {
5555 if (elem->schema == snode) {
5556
5557 if (elem == *ctx_node) {
5558 /* We are going to unlink our context node! This normally cannot happen,
5559 * but we use normal top-level data nodes for faking a document root node,
5560 * so if this is the context node, we just use the next top-level node.
5561 * Additionally, it can even happen that there are no top-level data nodes left,
5562 * all were unlinked, so in this case we pass NULL as the context node/data tree,
5563 * lyxp_eval() can handle this special situation.
5564 */
5565 if (ctx_node_type == LYXP_NODE_ELEM) {
5566 LOGINT;
5567 return -1;
5568 }
5569
5570 if (elem->prev == elem) {
5571 /* unlinking last top-level element, use an empty data tree */
5572 *ctx_node = NULL;
5573 } else {
5574 /* in this case just use the previous/last top-level data node */
5575 *ctx_node = elem->prev;
5576 }
5577 } else if (elem == *node) {
5578 /* We are going to unlink the currently processed node. This does not matter that
5579 * much, but we would lose access to the original data tree, so just move our
5580 * pointer somewhere still inside it.
5581 */
5582 if ((*node)->prev != *node) {
5583 *node = (*node)->prev;
5584 } else {
5585 /* the processed node with sibings were all unlinked, oh well */
5586 *node = NULL;
5587 }
5588 }
5589
5590 /* temporarily unlink the node */
5591 lyd_unlink(elem);
5592 if (*unlinked_nodes) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005593 if (lyd_insert_after((*unlinked_nodes)->prev, elem)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005594 LOGINT;
5595 return -1;
5596 }
5597 } else {
5598 *unlinked_nodes = elem;
5599 }
5600
5601 if (snode->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_ANYDATA)) {
5602 /* there can be only one instance */
5603 break;
5604 }
5605 }
5606 }
5607 break;
5608 default:
5609 LOGINT;
5610 return -1;
5611 }
5612
5613 return EXIT_SUCCESS;
5614}
5615
5616/**
5617 * @brief Relink the unlinked nodes back.
5618 *
5619 * @param[in] node Data node to link the nodes back to. It can actually be the adjusted context node,
5620 * we simply need a sibling from the original data tree.
5621 * @param[in] unlinked_nodes Unlinked nodes to relink to \p node.
5622 * @param[in] ctx_node_type Context node type to distinguish between \p node being the parent
5623 * or the sibling of \p unlinked_nodes.
5624 *
5625 * @return EXIT_SUCCESS on success, -1 on error.
5626 */
5627static int
5628resolve_when_relink_nodes(struct lyd_node *node, struct lyd_node *unlinked_nodes, enum lyxp_node_type ctx_node_type)
5629{
5630 struct lyd_node *elem;
5631
5632 LY_TREE_FOR_SAFE(unlinked_nodes, unlinked_nodes, elem) {
Michal Vaskode1feeb2016-12-20 14:48:42 +01005633 lyd_unlink(elem);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005634 if (ctx_node_type == LYXP_NODE_ELEM) {
5635 if (lyd_insert(node, elem)) {
5636 return -1;
5637 }
5638 } else {
5639 if (lyd_insert_after(node, elem)) {
5640 return -1;
5641 }
5642 }
5643 }
5644
5645 return EXIT_SUCCESS;
5646}
5647
Radek Krejci03b71f72016-03-16 11:10:09 +01005648int
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005649resolve_applies_must(const struct lyd_node *node)
Radek Krejci01696bf2016-03-18 13:19:36 +01005650{
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005651 int ret = 0;
5652 uint8_t must_size;
5653 struct lys_node *schema, *iter;
Radek Krejci46165822016-08-26 14:06:27 +02005654
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005655 assert(node);
5656
5657 schema = node->schema;
5658
5659 /* their own must */
Radek Krejci46165822016-08-26 14:06:27 +02005660 switch (schema->nodetype) {
Radek Krejci01696bf2016-03-18 13:19:36 +01005661 case LYS_CONTAINER:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005662 must_size = ((struct lys_node_container *)schema)->must_size;
5663 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005664 case LYS_LEAF:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005665 must_size = ((struct lys_node_leaf *)schema)->must_size;
5666 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005667 case LYS_LEAFLIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005668 must_size = ((struct lys_node_leaflist *)schema)->must_size;
5669 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005670 case LYS_LIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005671 must_size = ((struct lys_node_list *)schema)->must_size;
5672 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005673 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02005674 case LYS_ANYDATA:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005675 must_size = ((struct lys_node_anydata *)schema)->must_size;
5676 break;
5677 case LYS_NOTIF:
5678 must_size = ((struct lys_node_notif *)schema)->must_size;
5679 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005680 default:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005681 must_size = 0;
5682 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005683 }
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005684
5685 if (must_size) {
5686 ++ret;
5687 }
5688
5689 /* schema may be a direct data child of input/output with must (but it must be first, it needs to be evaluated only once) */
5690 if (!node->prev->next) {
5691 for (iter = lys_parent(schema); iter && (iter->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES)); iter = lys_parent(iter));
5692 if (iter && (iter->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5693 ret += 0x2;
5694 }
5695 }
5696
5697 return ret;
Radek Krejci01696bf2016-03-18 13:19:36 +01005698}
5699
5700int
Radek Krejci46165822016-08-26 14:06:27 +02005701resolve_applies_when(const struct lys_node *schema, int mode, const struct lys_node *stop)
Radek Krejci03b71f72016-03-16 11:10:09 +01005702{
Radek Krejci46165822016-08-26 14:06:27 +02005703 const struct lys_node *parent;
Radek Krejci03b71f72016-03-16 11:10:09 +01005704
Radek Krejci46165822016-08-26 14:06:27 +02005705 assert(schema);
Radek Krejci03b71f72016-03-16 11:10:09 +01005706
Radek Krejci46165822016-08-26 14:06:27 +02005707 if (!(schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)schema)->when)) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005708 return 1;
5709 }
5710
Radek Krejci46165822016-08-26 14:06:27 +02005711 parent = schema;
Radek Krejci03b71f72016-03-16 11:10:09 +01005712 goto check_augment;
5713
Radek Krejci46165822016-08-26 14:06:27 +02005714 while (parent) {
5715 /* stop conditions */
5716 if (!mode) {
5717 /* stop on node that can be instantiated in data tree */
5718 if (!(parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
5719 break;
5720 }
5721 } else {
5722 /* stop on the specified node */
5723 if (parent == stop) {
5724 break;
5725 }
5726 }
5727
5728 if (((const struct lys_node_uses *)parent)->when) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005729 return 1;
5730 }
5731check_augment:
5732
5733 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) &&
Radek Krejci46165822016-08-26 14:06:27 +02005734 (((const struct lys_node_augment *)parent->parent)->when))) {
Michal Vaskoe3655562016-08-24 15:56:17 +02005735 return 1;
Radek Krejci03b71f72016-03-16 11:10:09 +01005736 }
5737 parent = lys_parent(parent);
5738 }
5739
5740 return 0;
5741}
5742
Michal Vaskocf024702015-10-08 15:01:42 +02005743/**
5744 * @brief Resolve (check) all when conditions relevant for \p node.
5745 * Logs directly.
5746 *
5747 * @param[in] node Data node, whose conditional reference, if such, is being decided.
Michal Vaskocf024702015-10-08 15:01:42 +02005748 *
Radek Krejci03b71f72016-03-16 11:10:09 +01005749 * @return
5750 * -1 - error, ly_errno is set
5751 * 0 - true "when" statement
Radek Krejci46165822016-08-26 14:06:27 +02005752 * 0, ly_vecode = LYVE_NOWHEN - false "when" statement
Radek Krejci03b71f72016-03-16 11:10:09 +01005753 * 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 +02005754 */
Radek Krejci46165822016-08-26 14:06:27 +02005755int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005756resolve_when(struct lyd_node *node, int *result, int ignore_fail)
Michal Vaskocf024702015-10-08 15:01:42 +02005757{
Michal Vasko76c3bd32016-08-24 16:02:52 +02005758 struct lyd_node *ctx_node = NULL, *unlinked_nodes, *tmp_node;
Michal Vasko90fc2a32016-08-24 15:58:58 +02005759 struct lys_node *sparent;
Michal Vaskocf024702015-10-08 15:01:42 +02005760 struct lyxp_set set;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005761 enum lyxp_node_type ctx_node_type;
Radek Krejci51093642016-03-29 10:14:59 +02005762 int rc = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02005763
5764 assert(node);
5765 memset(&set, 0, sizeof set);
5766
5767 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)node->schema)->when)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005768 /* make the node dummy for the evaluation */
5769 node->validity |= LYD_VAL_INUSE;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005770 rc = lyxp_eval(((struct lys_node_container *)node->schema)->when->cond, node, LYXP_NODE_ELEM, lyd_node_module(node),
5771 &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005772 node->validity &= ~LYD_VAL_INUSE;
Radek Krejci03b71f72016-03-16 11:10:09 +01005773 if (rc) {
5774 if (rc == 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005775 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005776 }
Radek Krejci51093642016-03-29 10:14:59 +02005777 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005778 }
5779
Radek Krejci03b71f72016-03-16 11:10:09 +01005780 /* set boolean result of the condition */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005781 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02005782 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01005783 node->when_status |= LYD_WHEN_FALSE;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005784 if (ignore_fail) {
5785 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
5786 ((struct lys_node_container *)node->schema)->when->cond);
5787 } else {
5788 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
5789 goto cleanup;
5790 }
Michal Vaskocf024702015-10-08 15:01:42 +02005791 }
Radek Krejci51093642016-03-29 10:14:59 +02005792
5793 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005794 lyxp_set_cast(&set, LYXP_SET_EMPTY, node, lyd_node_module(node), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005795 }
5796
Michal Vasko90fc2a32016-08-24 15:58:58 +02005797 sparent = node->schema;
Michal Vaskocf024702015-10-08 15:01:42 +02005798 goto check_augment;
5799
5800 /* check when in every schema node that affects node */
Michal Vasko90fc2a32016-08-24 15:58:58 +02005801 while (sparent && (sparent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
5802 if (((struct lys_node_uses *)sparent)->when) {
Michal Vaskocf024702015-10-08 15:01:42 +02005803 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005804 rc = resolve_when_ctx_node(node, sparent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02005805 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02005806 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02005807 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005808 }
5809 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02005810
5811 unlinked_nodes = NULL;
5812 /* we do not want our node pointer to change */
5813 tmp_node = node;
5814 rc = resolve_when_unlink_nodes(sparent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
5815 if (rc) {
5816 goto cleanup;
5817 }
5818
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005819 rc = lyxp_eval(((struct lys_node_uses *)sparent)->when->cond, ctx_node, ctx_node_type, lys_node_module(sparent),
5820 &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005821
5822 if (unlinked_nodes && ctx_node) {
5823 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
5824 rc = -1;
5825 goto cleanup;
5826 }
5827 }
5828
Radek Krejci03b71f72016-03-16 11:10:09 +01005829 if (rc) {
5830 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005831 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005832 }
Radek Krejci51093642016-03-29 10:14:59 +02005833 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005834 }
5835
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005836 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02005837 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01005838 node->when_status |= LYD_WHEN_FALSE;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005839 if (ignore_fail) {
5840 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
5841 ((struct lys_node_uses *)sparent)->when->cond);
5842 } else {
5843 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
5844 goto cleanup;
5845 }
Michal Vaskocf024702015-10-08 15:01:42 +02005846 }
Radek Krejci51093642016-03-29 10:14:59 +02005847
5848 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005849 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005850 }
5851
5852check_augment:
Michal Vasko90fc2a32016-08-24 15:58:58 +02005853 if ((sparent->parent && (sparent->parent->nodetype == LYS_AUGMENT) && (((struct lys_node_augment *)sparent->parent)->when))) {
Michal Vaskocf024702015-10-08 15:01:42 +02005854 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005855 rc = resolve_when_ctx_node(node, sparent->parent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02005856 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02005857 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02005858 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005859 }
5860 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02005861
5862 unlinked_nodes = NULL;
5863 tmp_node = node;
5864 rc = resolve_when_unlink_nodes(sparent->parent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
5865 if (rc) {
5866 goto cleanup;
5867 }
5868
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005869 rc = lyxp_eval(((struct lys_node_augment *)sparent->parent)->when->cond, ctx_node, ctx_node_type,
5870 lys_node_module(sparent->parent), &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005871
5872 /* reconnect nodes, if ctx_node is NULL then all the nodes were unlinked, but linked together,
5873 * so the tree did not actually change and there is nothing for us to do
5874 */
5875 if (unlinked_nodes && ctx_node) {
5876 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
5877 rc = -1;
5878 goto cleanup;
5879 }
5880 }
5881
Radek Krejci03b71f72016-03-16 11:10:09 +01005882 if (rc) {
5883 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005884 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005885 }
Radek Krejci51093642016-03-29 10:14:59 +02005886 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005887 }
5888
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005889 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent->parent), LYXP_WHEN);
Michal Vaskocf024702015-10-08 15:01:42 +02005890
Michal Vasko8146d4c2016-05-09 15:50:29 +02005891 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01005892 node->when_status |= LYD_WHEN_FALSE;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005893 if (ignore_fail) {
5894 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
5895 ((struct lys_node_augment *)sparent->parent)->when->cond);
5896 } else {
5897 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
5898 goto cleanup;
5899 }
Michal Vaskocf024702015-10-08 15:01:42 +02005900 }
Radek Krejci51093642016-03-29 10:14:59 +02005901
5902 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005903 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent->parent), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005904 }
5905
Michal Vasko90fc2a32016-08-24 15:58:58 +02005906 sparent = lys_parent(sparent);
Michal Vaskocf024702015-10-08 15:01:42 +02005907 }
5908
Radek Krejci0b7704f2016-03-18 12:16:14 +01005909 node->when_status |= LYD_WHEN_TRUE;
Radek Krejci03b71f72016-03-16 11:10:09 +01005910
Radek Krejci51093642016-03-29 10:14:59 +02005911cleanup:
Radek Krejci51093642016-03-29 10:14:59 +02005912 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005913 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node ? ctx_node : node, NULL, 0);
Radek Krejci51093642016-03-29 10:14:59 +02005914
Radek Krejci46165822016-08-26 14:06:27 +02005915 if (result) {
5916 if (node->when_status & LYD_WHEN_TRUE) {
5917 *result = 1;
5918 } else {
5919 *result = 0;
5920 }
5921 }
5922
Radek Krejci51093642016-03-29 10:14:59 +02005923 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005924}
5925
Radek Krejcicbb473e2016-09-16 14:48:32 +02005926static int
5927check_leafref_features(struct lys_type *type)
5928{
5929 struct lys_node *iter;
5930 struct ly_set *src_parents, *trg_parents, *features;
5931 unsigned int i, j, size, x;
5932 int ret = EXIT_SUCCESS;
5933
5934 assert(type->parent);
5935
5936 src_parents = ly_set_new();
5937 trg_parents = ly_set_new();
5938 features = ly_set_new();
5939
5940 /* get parents chain of source (leafref) */
5941 for (iter = (struct lys_node *)type->parent; iter; iter = iter->parent) {
5942 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
5943 continue;
5944 }
5945 ly_set_add(src_parents, iter, LY_SET_OPT_USEASLIST);
5946 }
5947 /* get parents chain of target */
5948 for (iter = (struct lys_node *)type->info.lref.target; iter; iter = iter->parent) {
5949 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
5950 continue;
5951 }
5952 ly_set_add(trg_parents, iter, LY_SET_OPT_USEASLIST);
5953 }
5954
5955 /* compare the features used in if-feature statements in the rest of both
5956 * chains of parents. The set of features used for target must be a subset
5957 * of features used for the leafref. This is not a perfect, we should compare
5958 * the truth tables but it could require too much resources, so we simplify that */
5959 for (i = 0; i < src_parents->number; i++) {
5960 iter = src_parents->set.s[i]; /* shortcut */
5961 if (!iter->iffeature_size) {
5962 continue;
5963 }
5964 for (j = 0; j < iter->iffeature_size; j++) {
5965 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
5966 for (; size; size--) {
5967 if (!iter->iffeature[j].features[size - 1]) {
5968 /* not yet resolved feature, postpone this check */
5969 ret = EXIT_FAILURE;
5970 goto cleanup;
5971 }
5972 ly_set_add(features, iter->iffeature[j].features[size - 1], 0);
5973 }
5974 }
5975 }
5976 x = features->number;
5977 for (i = 0; i < trg_parents->number; i++) {
5978 iter = trg_parents->set.s[i]; /* shortcut */
5979 if (!iter->iffeature_size) {
5980 continue;
5981 }
5982 for (j = 0; j < iter->iffeature_size; j++) {
5983 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
5984 for (; size; size--) {
5985 if (!iter->iffeature[j].features[size - 1]) {
5986 /* not yet resolved feature, postpone this check */
5987 ret = EXIT_FAILURE;
5988 goto cleanup;
5989 }
5990 if ((unsigned int)ly_set_add(features, iter->iffeature[j].features[size - 1], 0) >= x) {
5991 /* the feature is not present in features set of target's parents chain */
5992 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, type->parent, "leafref", type->info.lref.path);
5993 LOGVAL(LYE_SPEC, LY_VLOG_LYS, type->parent,
5994 "Leafref is not conditional based on \"%s\" feature as its target.",
5995 iter->iffeature[j].features[size - 1]->name);
5996 ret = -1;
5997 goto cleanup;
5998 }
5999 }
6000 }
6001 }
6002
6003cleanup:
6004 ly_set_free(features);
6005 ly_set_free(src_parents);
6006 ly_set_free(trg_parents);
6007
6008 return ret;
6009}
6010
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006011/**
Michal Vaskobb211122015-08-19 14:03:11 +02006012 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006013 *
6014 * @param[in] mod Main module.
6015 * @param[in] item Item to resolve. Type determined by \p type.
6016 * @param[in] type Type of the unresolved item.
6017 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02006018 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006019 *
6020 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
6021 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006022static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006023resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Radek Krejci48464ed2016-03-17 15:44:09 +01006024 struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006025{
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006026 /* has_str - whether the str_snode is a string in a dictionary that needs to be freed */
Radek Krejcic79c6b12016-07-26 15:11:49 +02006027 int rc = -1, has_str = 0, tpdf_flag = 0, i, k;
6028 unsigned int j;
Radek Krejcic13db382016-08-16 10:52:42 +02006029 struct lys_node *node, *par_grp;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006030 const char *expr;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006031
Radek Krejcic79c6b12016-07-26 15:11:49 +02006032 struct ly_set *refs, *procs;
6033 struct lys_feature *ref, *feat;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006034 struct lys_ident *ident;
6035 struct lys_type *stype;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006036 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01006037 struct lyxml_elem *yin;
Pavol Vicana0e4e672016-02-24 12:20:04 +01006038 struct yang_type *yang;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006039 struct unres_list_uniq *unique_info;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006040 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006041
6042 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006043 case UNRES_IDENT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006044 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006045 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006046 ident = item;
6047
Radek Krejci018f1f52016-08-03 16:01:20 +02006048 rc = resolve_base_ident(mod, ident, expr, "identity", NULL, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006049 break;
6050 case UNRES_TYPE_IDENTREF:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006051 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006052 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006053 stype = item;
6054
Radek Krejci018f1f52016-08-03 16:01:20 +02006055 rc = resolve_base_ident(mod, NULL, expr, "type", stype, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006056 break;
6057 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02006058 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006059 stype = item;
6060
Radek Krejci2f12f852016-01-08 12:59:57 +01006061 /* HACK - when there is no parent, we are in top level typedef and in that
6062 * case, the path has to contain absolute path, so we let the resolve_path_arg_schema()
6063 * know it via tpdf_flag */
6064 if (!node) {
Radek Krejci4f78b532016-02-17 13:43:00 +01006065 tpdf_flag = 1;
Radek Krejci2f12f852016-01-08 12:59:57 +01006066 node = (struct lys_node *)stype->parent;
6067 }
6068
Radek Krejci27fe55e2016-09-13 17:13:35 +02006069 if (!lys_node_module(node)->implemented) {
6070 /* not implemented module, don't bother with resolving the leafref
Radek Krejci990af1f2016-11-09 13:53:36 +01006071 * if the module is set to be implemented, the path will be resolved then */
Radek Krejci27fe55e2016-09-13 17:13:35 +02006072 rc = 0;
6073 break;
6074 }
Radek Krejci48464ed2016-03-17 15:44:09 +01006075 rc = resolve_path_arg_schema(stype->info.lref.path, node, tpdf_flag,
Michal Vasko1e62a092015-12-01 12:27:20 +01006076 (const struct lys_node **)&stype->info.lref.target);
Michal Vasko01c6fd22016-05-20 11:43:05 +02006077 if (!tpdf_flag && !rc) {
6078 assert(stype->info.lref.target);
Radek Krejcicbb473e2016-09-16 14:48:32 +02006079 /* check if leafref and its target are under a common if-features */
6080 rc = check_leafref_features(stype);
6081 if (rc) {
6082 break;
6083 }
6084
Radek Krejci46c4cd72016-01-21 15:13:52 +01006085 /* store the backlink from leafref target */
Michal Vasko01c6fd22016-05-20 11:43:05 +02006086 if (lys_leaf_add_leafref_target(stype->info.lref.target, (struct lys_node *)stype->parent)) {
6087 rc = -1;
Radek Krejci46c4cd72016-01-21 15:13:52 +01006088 }
Radek Krejci46c4cd72016-01-21 15:13:52 +01006089 }
6090
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006091 break;
Radek Krejci3a5501d2016-07-18 22:03:34 +02006092 case UNRES_TYPE_DER_TPDF:
6093 tpdf_flag = 1;
6094 /* no break */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006095 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01006096 /* parent */
6097 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006098 stype = item;
6099
Michal Vasko88c29542015-11-27 14:57:53 +01006100 /* HACK type->der is temporarily unparsed type statement */
6101 yin = (struct lyxml_elem *)stype->der;
6102 stype->der = NULL;
6103
Pavol Vicana0e4e672016-02-24 12:20:04 +01006104 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6105 yang = (struct yang_type *)yin;
Radek Krejci3a5501d2016-07-18 22:03:34 +02006106 rc = yang_check_type(mod, node, yang, tpdf_flag, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006107
6108 if (rc) {
Pavol Vican8bd72e42016-08-29 09:53:05 +02006109 /* may try again later */
6110 stype->der = (struct lys_tpdf *)yang;
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006111 } else {
6112 /* we need to always be able to free this, it's safe only in this case */
Pavol Vican5f0316a2016-04-05 21:21:11 +02006113 lydict_remove(mod->ctx, yang->name);
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006114 free(yang);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006115 }
6116
Michal Vasko88c29542015-11-27 14:57:53 +01006117 } else {
Radek Krejci3a5501d2016-07-18 22:03:34 +02006118 rc = fill_yin_type(mod, node, yin, stype, tpdf_flag, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006119 if (!rc) {
6120 /* we need to always be able to free this, it's safe only in this case */
6121 lyxml_free(mod->ctx, yin);
6122 } else {
6123 /* may try again later, put all back how it was */
6124 stype->der = (struct lys_tpdf *)yin;
6125 }
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006126 }
Radek Krejcic13db382016-08-16 10:52:42 +02006127 if (rc == EXIT_SUCCESS) {
Radek Krejci2c2fce82016-08-01 13:52:26 +02006128 /* it does not make sense to have leaf-list of empty type */
6129 if (!tpdf_flag && node->nodetype == LYS_LEAFLIST && stype->base == LY_TYPE_EMPTY) {
6130 LOGWRN("The leaf-list \"%s\" is of \"empty\" type, which does not make sense.", node->name);
6131 }
Radek Krejci9b6aad22016-09-20 15:55:51 +02006132 } else if (rc == EXIT_FAILURE && stype->base != LY_TYPE_ERR) {
Radek Krejcic13db382016-08-16 10:52:42 +02006133 /* forward reference - in case the type is in grouping, we have to make the grouping unusable
6134 * by uses statement until the type is resolved. We do that the same way as uses statements inside
6135 * grouping - the grouping's nacm member (not used un grouping) is used to increase the number of
6136 * so far unresolved items (uses and types). The grouping cannot be used unless the nacm value is 0.
Radek Krejci9b6aad22016-09-20 15:55:51 +02006137 * To remember that the grouping already increased grouping's nacm, the LY_TYPE_ERR is used as value
Radek Krejcic13db382016-08-16 10:52:42 +02006138 * of the type's base member. */
6139 for (par_grp = node; par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
6140 if (par_grp) {
6141 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci9b6aad22016-09-20 15:55:51 +02006142 stype->base = LY_TYPE_ERR;
Radek Krejcic13db382016-08-16 10:52:42 +02006143 }
Radek Krejci2c2fce82016-08-01 13:52:26 +02006144 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006145 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006146 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006147 iff_data = str_snode;
6148 rc = resolve_feature(iff_data->fname, strlen(iff_data->fname), iff_data->node, item);
Radek Krejci9ff0a922016-07-14 13:08:05 +02006149 if (!rc) {
6150 /* success */
Radek Krejci9de2c042016-10-19 16:53:06 +02006151 if (iff_data->infeature) {
6152 /* store backlink into the target feature to allow reverse changes in case of changing feature status */
6153 feat = *((struct lys_feature **)item);
6154 if (!feat->depfeatures) {
6155 feat->depfeatures = ly_set_new();
6156 }
Radek Krejci85a54be2016-10-20 12:39:56 +02006157 ly_set_add(feat->depfeatures, iff_data->node, LY_SET_OPT_USEASLIST);
Radek Krejci9de2c042016-10-19 16:53:06 +02006158 }
6159 /* cleanup temporary data */
Radek Krejcicbb473e2016-09-16 14:48:32 +02006160 lydict_remove(mod->ctx, iff_data->fname);
6161 free(iff_data);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006162 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006163 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006164 case UNRES_FEATURE:
6165 feat = (struct lys_feature *)item;
6166
6167 if (feat->iffeature_size) {
6168 refs = ly_set_new();
6169 procs = ly_set_new();
6170 ly_set_add(procs, feat, 0);
6171
6172 while (procs->number) {
6173 ref = procs->set.g[procs->number - 1];
6174 ly_set_rm_index(procs, procs->number - 1);
6175
6176 for (i = 0; i < ref->iffeature_size; i++) {
6177 resolve_iffeature_getsizes(&ref->iffeature[i], NULL, &j);
6178 for (; j > 0 ; j--) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006179 if (ref->iffeature[i].features[j - 1]) {
Radek Krejcic79c6b12016-07-26 15:11:49 +02006180 if (ref->iffeature[i].features[j - 1] == feat) {
6181 LOGVAL(LYE_CIRC_FEATURES, LY_VLOG_NONE, NULL, feat->name);
6182 goto featurecheckdone;
6183 }
6184
6185 if (ref->iffeature[i].features[j - 1]->iffeature_size) {
6186 k = refs->number;
6187 if (ly_set_add(refs, ref->iffeature[i].features[j - 1], 0) == k) {
6188 /* not yet seen feature, add it for processing */
6189 ly_set_add(procs, ref->iffeature[i].features[j - 1], 0);
6190 }
6191 }
6192 } else {
6193 /* forward reference */
6194 rc = EXIT_FAILURE;
6195 goto featurecheckdone;
6196 }
6197 }
6198
6199 }
6200 }
6201 rc = EXIT_SUCCESS;
6202
6203featurecheckdone:
6204 ly_set_free(refs);
6205 ly_set_free(procs);
6206 }
6207
6208 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006209 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006210 rc = resolve_unres_schema_uses(item, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006211 break;
6212 case UNRES_TYPE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006213 stype = item;
6214
Radek Krejci51673202016-11-01 17:00:32 +01006215 rc = check_default(stype, (const char **)str_snode, mod);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006216 break;
6217 case UNRES_CHOICE_DFLT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006218 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006219 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006220 choic = item;
6221
Radek Krejcie00d2312016-08-12 15:27:49 +02006222 if (!choic->dflt) {
6223 choic->dflt = resolve_choice_dflt(choic, expr);
6224 }
Michal Vasko7955b362015-09-04 14:18:15 +02006225 if (choic->dflt) {
Radek Krejcie00d2312016-08-12 15:27:49 +02006226 rc = lyp_check_mandatory_choice((struct lys_node *)choic);
Michal Vasko7955b362015-09-04 14:18:15 +02006227 } else {
6228 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006229 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006230 break;
6231 case UNRES_LIST_KEYS:
Radek Krejci5c08a992016-11-02 13:30:04 +01006232 rc = resolve_list_keys(item, ((struct lys_node_list *)item)->keys_str);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006233 break;
6234 case UNRES_LIST_UNIQ:
Radek Krejcid09d1a52016-08-11 14:05:45 +02006235 unique_info = (struct unres_list_uniq *)item;
6236 rc = resolve_unique(unique_info->list, unique_info->expr, unique_info->trg_type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006237 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006238 case UNRES_AUGMENT:
Radek Krejcib3142312016-11-09 11:04:12 +01006239 rc = resolve_augment(item, NULL, unres);
Michal Vasko7178e692016-02-12 15:58:05 +01006240 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006241 case UNRES_XPATH:
6242 node = (struct lys_node *)item;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02006243 rc = lys_check_xpath(node, 1);
Michal Vasko508a50d2016-09-07 14:50:33 +02006244 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006245 default:
6246 LOGINT;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006247 break;
6248 }
6249
Radek Krejci54081ce2016-08-12 15:21:47 +02006250 if (has_str && !rc) {
6251 /* the string is no more needed in case of success.
6252 * In case of forward reference, we will try to resolve the string later */
Radek Krejci4f78b532016-02-17 13:43:00 +01006253 lydict_remove(mod->ctx, str_snode);
6254 }
6255
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006256 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006257}
6258
Michal Vaskof02e3742015-08-05 16:27:02 +02006259/* logs directly */
6260static void
Radek Krejci48464ed2016-03-17 15:44:09 +01006261print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006262{
Michal Vaskocb34dc62016-05-20 14:38:37 +02006263 struct lyxml_elem *xml;
6264 struct lyxml_attr *attr;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006265 struct unres_iffeat_data *iff_data;
Radek Krejci76e15e12016-06-22 11:02:24 +02006266 const char *type_name = NULL;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006267
Michal Vaskof02e3742015-08-05 16:27:02 +02006268 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02006269 case UNRES_IDENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006270 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identity", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006271 break;
6272 case UNRES_TYPE_IDENTREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006273 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identityref", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006274 break;
6275 case UNRES_TYPE_LEAFREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006276 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "leafref",
6277 ((struct lys_type *)item)->info.lref.path);
Michal Vaskof02e3742015-08-05 16:27:02 +02006278 break;
Radek Krejci3a5501d2016-07-18 22:03:34 +02006279 case UNRES_TYPE_DER_TPDF:
Michal Vaskof02e3742015-08-05 16:27:02 +02006280 case UNRES_TYPE_DER:
Michal Vaskocb34dc62016-05-20 14:38:37 +02006281 xml = (struct lyxml_elem *)((struct lys_type *)item)->der;
6282 if (xml->flags & LY_YANG_STRUCTURE_FLAG) {
6283 type_name = ((struct yang_type *)xml)->name;
6284 } else {
6285 LY_TREE_FOR(xml->attr, attr) {
6286 if ((attr->type == LYXML_ATTR_STD) && !strcmp(attr->name, "name")) {
6287 type_name = attr->value;
6288 break;
6289 }
6290 }
6291 assert(attr);
6292 }
6293 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "derived type", type_name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006294 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006295 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006296 iff_data = str_node;
6297 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "if-feature", iff_data->fname);
Michal Vaskof02e3742015-08-05 16:27:02 +02006298 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006299 case UNRES_FEATURE:
6300 LOGVRB("There are unresolved if-features for \"%s\" feature circular dependency check, it will be attempted later",
6301 ((struct lys_feature *)item)->name);
6302 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006303 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006304 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "uses", ((struct lys_node_uses *)item)->name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006305 break;
6306 case UNRES_TYPE_DFLT:
Radek Krejci2e2de832016-10-13 16:12:26 +02006307 if (str_node) {
6308 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "type default", (char *)str_node);
6309 } /* else no default value in the type itself, but we are checking some restrictions against
6310 * possible default value of some base type. The failure is caused by not resolved base type,
6311 * so it was already reported */
Michal Vaskof02e3742015-08-05 16:27:02 +02006312 break;
6313 case UNRES_CHOICE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006314 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "choice default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006315 break;
6316 case UNRES_LIST_KEYS:
Radek Krejci48464ed2016-03-17 15:44:09 +01006317 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list keys", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006318 break;
6319 case UNRES_LIST_UNIQ:
Radek Krejci48464ed2016-03-17 15:44:09 +01006320 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list unique", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006321 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006322 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006323 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "augment target",
6324 ((struct lys_node_augment *)item)->target_name);
Michal Vasko7178e692016-02-12 15:58:05 +01006325 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006326 case UNRES_XPATH:
Michal Vasko0d198372016-11-16 11:40:03 +01006327 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "XPath expressions of",
6328 ((struct lys_node *)item)->name);
Michal Vasko508a50d2016-09-07 14:50:33 +02006329 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006330 default:
6331 LOGINT;
Michal Vaskof02e3742015-08-05 16:27:02 +02006332 break;
6333 }
6334}
6335
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006336/**
Michal Vaskobb211122015-08-19 14:03:11 +02006337 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006338 *
6339 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006340 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006341 *
Michal Vasko92b8a382015-08-19 14:03:49 +02006342 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006343 */
Michal Vaskof02e3742015-08-05 16:27:02 +02006344int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006345resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02006346{
Radek Krejci010e54b2016-03-15 09:40:34 +01006347 uint32_t i, resolved = 0, unres_count, res_count;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006348 int rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006349
6350 assert(unres);
6351
Michal Vaskoe8734262016-09-29 14:12:06 +02006352 LOGVRB("Resolving \"%s\" unresolved schema nodes and their constraints...", mod->name);
Radek Krejci010e54b2016-03-15 09:40:34 +01006353 ly_vlog_hide(1);
Michal Vasko51054ca2015-08-12 12:20:00 +02006354
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006355 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02006356 do {
Michal Vasko88c29542015-11-27 14:57:53 +01006357 unres_count = 0;
6358 res_count = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02006359
6360 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006361 /* UNRES_TYPE_LEAFREF must be resolved (for storing leafref target pointers);
Radek Krejcic79c6b12016-07-26 15:11:49 +02006362 * if-features are resolved here to make sure that we will have all if-features for
6363 * later check of feature circular dependency */
Radek Krejci018f1f52016-08-03 16:01:20 +02006364 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006365 continue;
6366 }
Radek Krejci018f1f52016-08-03 16:01:20 +02006367 /* processes UNRES_USES, UNRES_IFFEAT, UNRES_TYPE_DER, UNRES_TYPE_DER_TPDF, UNRES_TYPE_LEAFREF,
Radek Krejci818b0c52016-11-09 15:10:51 +01006368 * UNRES_AUGMENT, UNRES_CHOICE_DFLT and UNRES_IDENT */
Michal Vasko51054ca2015-08-12 12:20:00 +02006369
Michal Vasko88c29542015-11-27 14:57:53 +01006370 ++unres_count;
Radek Krejci48464ed2016-03-17 15:44:09 +01006371 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006372 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006373 unres->type[i] = UNRES_RESOLVED;
6374 ++resolved;
Michal Vasko88c29542015-11-27 14:57:53 +01006375 ++res_count;
Michal Vasko89e15322015-08-17 15:46:55 +02006376 } else if (rc == -1) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006377 ly_vlog_hide(0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02006378 /* print the error */
6379 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006380 return -1;
Radek Krejcic2a180f2016-06-22 13:28:16 +02006381 } else {
6382 /* forward reference, erase ly_errno */
Radek Krejci00a0e712016-10-26 10:24:46 +02006383 ly_err_clean(1);
Michal Vasko51054ca2015-08-12 12:20:00 +02006384 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006385 }
Michal Vasko88c29542015-11-27 14:57:53 +01006386 } while (res_count && (res_count < unres_count));
Michal Vasko51054ca2015-08-12 12:20:00 +02006387
Michal Vasko88c29542015-11-27 14:57:53 +01006388 if (res_count < unres_count) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006389 /* just print the errors */
6390 ly_vlog_hide(0);
6391
6392 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006393 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006394 continue;
6395 }
6396 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
6397 }
Michal Vasko92b8a382015-08-19 14:03:49 +02006398 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006399 }
6400
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006401 /* the rest */
6402 for (i = 0; i < unres->count; ++i) {
6403 if (unres->type[i] == UNRES_RESOLVED) {
6404 continue;
6405 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02006406
Radek Krejci48464ed2016-03-17 15:44:09 +01006407 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01006408 if (rc == 0) {
Pavol Vican88e16c92016-09-07 15:41:50 +02006409 if (unres->type[i] == UNRES_LIST_UNIQ) {
6410 /* free the allocated structure */
6411 free(unres->item[i]);
6412 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006413 unres->type[i] = UNRES_RESOLVED;
6414 ++resolved;
6415 } else if (rc == -1) {
6416 ly_vlog_hide(0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02006417 /* print the error */
6418 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
6419 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006420 }
6421 }
6422
Radek Krejci010e54b2016-03-15 09:40:34 +01006423 ly_vlog_hide(0);
6424
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006425 if (resolved < unres->count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006426 /* try to resolve the unresolved nodes again, it will not resolve anything, but it will print
6427 * all the validation errors
6428 */
6429 for (i = 0; i < unres->count; ++i) {
6430 if (unres->type[i] == UNRES_RESOLVED) {
6431 continue;
6432 }
Radek Krejcib3142312016-11-09 11:04:12 +01006433 if (unres->type[i] == UNRES_XPATH) {
6434 /* unresolvable XPaths are actually supposed to be warnings - they may be
6435 * unresolved due to the not implemented target module so it shouldn't avoid
6436 * parsing the module, but we still want to announce some issue here */
6437 ly_vlog_hide(0xff);
6438 }
Radek Krejci48464ed2016-03-17 15:44:09 +01006439 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejcib3142312016-11-09 11:04:12 +01006440 if (unres->type[i] == UNRES_XPATH && *ly_vlog_hide_location() == 0xff) {
6441 unres->type[i] = UNRES_RESOLVED;
6442 resolved++;
6443 ly_vlog_hide(0);
6444 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006445 }
Radek Krejcib3142312016-11-09 11:04:12 +01006446 if (resolved < unres->count) {
6447 return -1;
6448 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006449 }
6450
Michal Vaskoe8734262016-09-29 14:12:06 +02006451 LOGVRB("All \"%s\" schema nodes and constraints resolved.", mod->name);
Radek Krejcic071c542016-01-27 14:57:51 +01006452 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006453 return EXIT_SUCCESS;
6454}
6455
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006456/**
Michal Vaskobb211122015-08-19 14:03:11 +02006457 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006458 *
6459 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006460 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006461 * @param[in] item Item to resolve. Type determined by \p type.
6462 * @param[in] type Type of the unresolved item.
6463 * @param[in] str String argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006464 *
Michal Vasko3767fb22016-07-21 12:10:57 +02006465 * @return EXIT_SUCCESS on success, EXIT_FAILURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006466 */
6467int
Radek Krejci48464ed2016-03-17 15:44:09 +01006468unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
6469 const char *str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006470{
Radek Krejci54081ce2016-08-12 15:21:47 +02006471 int rc;
6472 const char *dictstr;
6473
6474 dictstr = lydict_insert(mod->ctx, str, 0);
6475 rc = unres_schema_add_node(mod, unres, item, type, (struct lys_node *)dictstr);
6476
6477 if (rc == -1) {
6478 lydict_remove(mod->ctx, dictstr);
6479 }
6480 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006481}
6482
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006483/**
Michal Vaskobb211122015-08-19 14:03:11 +02006484 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006485 *
6486 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006487 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006488 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01006489 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006490 * @param[in] snode Schema node argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006491 *
Michal Vasko3767fb22016-07-21 12:10:57 +02006492 * @return EXIT_SUCCESS on success, EXIT_FIALURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006493 */
6494int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006495unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Radek Krejci48464ed2016-03-17 15:44:09 +01006496 struct lys_node *snode)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006497{
Michal Vaskoef486d72016-09-27 12:10:44 +02006498 int rc, log_hidden;
Radek Krejci850a5de2016-11-08 14:06:40 +01006499 uint32_t u;
Michal Vasko88c29542015-11-27 14:57:53 +01006500 struct lyxml_elem *yin;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006501
Michal Vasko9bf425b2015-10-22 11:42:03 +02006502 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
6503 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006504
Radek Krejci850a5de2016-11-08 14:06:40 +01006505 /* check for duplicities in unres */
6506 for (u = 0; u < unres->count; u++) {
6507 if (unres->type[u] == type && unres->item[u] == item &&
6508 unres->str_snode[u] == snode && unres->module[u] == mod) {
6509 /* duplication, will be resolved later */
6510 return EXIT_FAILURE;
6511 }
6512 }
6513
Michal Vaskoef486d72016-09-27 12:10:44 +02006514 if (*ly_vlog_hide_location()) {
6515 log_hidden = 1;
6516 } else {
6517 log_hidden = 0;
6518 ly_vlog_hide(1);
6519 }
Radek Krejci48464ed2016-03-17 15:44:09 +01006520 rc = resolve_unres_schema_item(mod, item, type, snode, unres);
Michal Vaskoef486d72016-09-27 12:10:44 +02006521 if (!log_hidden) {
6522 ly_vlog_hide(0);
6523 }
6524
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006525 if (rc != EXIT_FAILURE) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006526 if (rc == -1 && ly_errno == LY_EVALID) {
Radek Krejci2467a492016-10-24 15:16:59 +02006527 ly_err_repeat();
Radek Krejci010e54b2016-03-15 09:40:34 +01006528 }
Radek Krejcid09d1a52016-08-11 14:05:45 +02006529 if (type == UNRES_LIST_UNIQ) {
6530 /* free the allocated structure */
6531 free(item);
Pavol Vican88e16c92016-09-07 15:41:50 +02006532 } else if (rc == -1 && type == UNRES_IFFEAT) {
6533 /* free the allocated resources */
6534 free(*((char **)item));
6535 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006536 return rc;
Radek Krejcif347abc2016-06-22 10:18:47 +02006537 } else {
6538 /* erase info about validation errors */
Radek Krejci00a0e712016-10-26 10:24:46 +02006539 ly_err_clean(1);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006540 }
6541
Radek Krejci48464ed2016-03-17 15:44:09 +01006542 print_unres_schema_item_fail(item, type, snode);
Michal Vaskof02e3742015-08-05 16:27:02 +02006543
Michal Vasko88c29542015-11-27 14:57:53 +01006544 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
Radek Krejci3a5501d2016-07-18 22:03:34 +02006545 if (type == UNRES_TYPE_DER || type == UNRES_TYPE_DER_TPDF) {
Michal Vasko88c29542015-11-27 14:57:53 +01006546 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
Pavol Vicana0e4e672016-02-24 12:20:04 +01006547 if (!(yin->flags & LY_YANG_STRUCTURE_FLAG)) {
6548 lyxml_unlink_elem(mod->ctx, yin, 1);
6549 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
6550 }
Michal Vasko88c29542015-11-27 14:57:53 +01006551 }
6552
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006553 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01006554 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
6555 if (!unres->item) {
6556 LOGMEM;
6557 return -1;
6558 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006559 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01006560 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
6561 if (!unres->type) {
6562 LOGMEM;
6563 return -1;
6564 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006565 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01006566 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
6567 if (!unres->str_snode) {
6568 LOGMEM;
6569 return -1;
6570 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006571 unres->str_snode[unres->count-1] = snode;
Radek Krejcic071c542016-01-27 14:57:51 +01006572 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
6573 if (!unres->module) {
6574 LOGMEM;
6575 return -1;
6576 }
6577 unres->module[unres->count-1] = mod;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006578
Michal Vasko3767fb22016-07-21 12:10:57 +02006579 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006580}
6581
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006582/**
Michal Vaskobb211122015-08-19 14:03:11 +02006583 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006584 *
6585 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006586 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006587 * @param[in] item Old item to be resolved.
6588 * @param[in] type Type of the old unresolved item.
6589 * @param[in] new_item New item to use in the duplicate.
6590 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02006591 * @return EXIT_SUCCESS on success, EXIT_FAILURE if item is not in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006592 */
Michal Vaskodad19402015-08-06 09:51:53 +02006593int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006594unres_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 +02006595{
6596 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006597 struct unres_list_uniq aux_uniq;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006598 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006599
Michal Vaskocf024702015-10-08 15:01:42 +02006600 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006601
Radek Krejcid09d1a52016-08-11 14:05:45 +02006602 /* hack for UNRES_LIST_UNIQ, which stores multiple items behind its item */
6603 if (type == UNRES_LIST_UNIQ) {
6604 aux_uniq.list = item;
6605 aux_uniq.expr = ((struct unres_list_uniq *)new_item)->expr;
6606 item = &aux_uniq;
6607 }
Michal Vasko878e38d2016-09-05 12:17:53 +02006608 i = unres_schema_find(unres, -1, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006609
6610 if (i == -1) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006611 if (type == UNRES_LIST_UNIQ) {
6612 free(new_item);
6613 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02006614 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006615 }
6616
Radek Krejcic79c6b12016-07-26 15:11:49 +02006617 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT) ||
Radek Krejcib69f3232016-09-16 17:41:07 +02006618 (type == UNRES_FEATURE) || (type == UNRES_LIST_UNIQ)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01006619 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006620 LOGINT;
6621 return -1;
6622 }
Radek Krejcicbb473e2016-09-16 14:48:32 +02006623 } else if (type == UNRES_IFFEAT) {
6624 /* duplicate unres_iffeature_data */
6625 iff_data = malloc(sizeof *iff_data);
6626 iff_data->fname = lydict_insert(mod->ctx, ((struct unres_iffeat_data *)unres->str_snode[i])->fname, 0);
6627 iff_data->node = ((struct unres_iffeat_data *)unres->str_snode[i])->node;
6628 if (unres_schema_add_node(mod, unres, new_item, type, (struct lys_node *)iff_data) == -1) {
6629 LOGINT;
6630 return -1;
6631 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006632 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01006633 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006634 LOGINT;
6635 return -1;
6636 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006637 }
Michal Vaskodad19402015-08-06 09:51:53 +02006638
6639 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006640}
6641
Michal Vaskof02e3742015-08-05 16:27:02 +02006642/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006643int
Michal Vasko878e38d2016-09-05 12:17:53 +02006644unres_schema_find(struct unres_schema *unres, int start_on_backwards, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006645{
Michal Vasko878e38d2016-09-05 12:17:53 +02006646 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006647 struct unres_list_uniq *aux_uniq1, *aux_uniq2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006648
Michal Vasko878e38d2016-09-05 12:17:53 +02006649 if (start_on_backwards > 0) {
6650 i = start_on_backwards;
6651 } else {
6652 i = unres->count - 1;
6653 }
6654 for (; i > -1; i--) {
6655 if (unres->type[i] != type) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006656 continue;
6657 }
6658 if (type != UNRES_LIST_UNIQ) {
Michal Vasko878e38d2016-09-05 12:17:53 +02006659 if (unres->item[i] == item) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006660 break;
6661 }
6662 } else {
6663 aux_uniq1 = (struct unres_list_uniq *)unres->item[i - 1];
6664 aux_uniq2 = (struct unres_list_uniq *)item;
6665 if ((aux_uniq1->list == aux_uniq2->list) && ly_strequal(aux_uniq1->expr, aux_uniq2->expr, 0)) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006666 break;
6667 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006668 }
6669 }
6670
Michal Vasko878e38d2016-09-05 12:17:53 +02006671 return i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006672}
Michal Vasko8bcdf292015-08-19 14:04:43 +02006673
Michal Vaskoede9c472016-06-07 09:38:15 +02006674static void
6675unres_schema_free_item(struct ly_ctx *ctx, struct unres_schema *unres, uint32_t i)
6676{
6677 struct lyxml_elem *yin;
6678 struct yang_type *yang;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006679 struct unres_iffeat_data *iff_data;
Michal Vaskoede9c472016-06-07 09:38:15 +02006680
6681 switch (unres->type[i]) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02006682 case UNRES_TYPE_DER_TPDF:
Michal Vaskoede9c472016-06-07 09:38:15 +02006683 case UNRES_TYPE_DER:
6684 yin = (struct lyxml_elem *)((struct lys_type *)unres->item[i])->der;
6685 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6686 yang =(struct yang_type *)yin;
Pavol Vicancf2af4d2016-12-21 14:13:06 +01006687 ((struct lys_type *)unres->item[i])->base = yang->base;
Michal Vaskoede9c472016-06-07 09:38:15 +02006688 lydict_remove(ctx, yang->name);
6689 free(yang);
Pavol Vicancf2af4d2016-12-21 14:13:06 +01006690 if (((struct lys_type *)unres->item[i])->base == LY_TYPE_UNION) {
6691 yang_free_type_union(ctx, (struct lys_type *)unres->item[i]);
6692 }
Michal Vaskoede9c472016-06-07 09:38:15 +02006693 } else {
6694 lyxml_free(ctx, yin);
6695 }
6696 break;
Pavol Vican88e16c92016-09-07 15:41:50 +02006697 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006698 iff_data = (struct unres_iffeat_data *)unres->str_snode[i];
6699 lydict_remove(ctx, iff_data->fname);
6700 free(unres->str_snode[i]);
Pavol Vican88e16c92016-09-07 15:41:50 +02006701 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02006702 case UNRES_IDENT:
6703 case UNRES_TYPE_IDENTREF:
Michal Vaskoede9c472016-06-07 09:38:15 +02006704 case UNRES_CHOICE_DFLT:
6705 case UNRES_LIST_KEYS:
Michal Vaskoede9c472016-06-07 09:38:15 +02006706 lydict_remove(ctx, (const char *)unres->str_snode[i]);
6707 break;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006708 case UNRES_LIST_UNIQ:
6709 free(unres->item[i]);
6710 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02006711 default:
6712 break;
6713 }
6714 unres->type[i] = UNRES_RESOLVED;
6715}
6716
Michal Vasko88c29542015-11-27 14:57:53 +01006717void
Radek Krejcic071c542016-01-27 14:57:51 +01006718unres_schema_free(struct lys_module *module, struct unres_schema **unres)
Michal Vasko88c29542015-11-27 14:57:53 +01006719{
6720 uint32_t i;
Radek Krejcic071c542016-01-27 14:57:51 +01006721 unsigned int unresolved = 0;
Michal Vasko88c29542015-11-27 14:57:53 +01006722
Radek Krejcic071c542016-01-27 14:57:51 +01006723 if (!unres || !(*unres)) {
6724 return;
Michal Vasko88c29542015-11-27 14:57:53 +01006725 }
6726
Radek Krejcic071c542016-01-27 14:57:51 +01006727 assert(module || (*unres)->count == 0);
6728
6729 for (i = 0; i < (*unres)->count; ++i) {
6730 if ((*unres)->module[i] != module) {
6731 if ((*unres)->type[i] != UNRES_RESOLVED) {
6732 unresolved++;
6733 }
6734 continue;
6735 }
Michal Vaskoede9c472016-06-07 09:38:15 +02006736
6737 /* free heap memory for the specific item */
6738 unres_schema_free_item(module->ctx, *unres, i);
Radek Krejcic071c542016-01-27 14:57:51 +01006739 }
6740
Michal Vaskoede9c472016-06-07 09:38:15 +02006741 /* free it all */
Radek Krejcic071c542016-01-27 14:57:51 +01006742 if (!module || (!unresolved && !module->type)) {
6743 free((*unres)->item);
6744 free((*unres)->type);
6745 free((*unres)->str_snode);
6746 free((*unres)->module);
Radek Krejcic071c542016-01-27 14:57:51 +01006747 free((*unres));
6748 (*unres) = NULL;
6749 }
Michal Vasko88c29542015-11-27 14:57:53 +01006750}
6751
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006752/**
6753 * @brief Resolve instance-identifier in JSON data format. Logs directly.
6754 *
6755 * @param[in] data Data node where the path is used
6756 * @param[in] path Instance-identifier node value.
6757 * @param[in,out] ret Resolved instance or NULL.
6758 *
6759 * @return 0 on success (even if unresolved and \p ret is NULL), -1 on error.
6760 */
6761static int
6762resolve_instid(struct lyd_node *data, const char *path, int req_inst, struct lyd_node **ret)
6763{
6764 int i = 0, j;
6765 const struct lys_module *mod;
6766 struct ly_ctx *ctx = data->schema->module->ctx;
6767 const char *model, *name;
6768 char *str;
6769 int mod_len, name_len, has_predicate;
6770 struct unres_data node_match;
6771
6772 memset(&node_match, 0, sizeof node_match);
6773 *ret = NULL;
6774
6775 /* we need root to resolve absolute path */
6776 for (; data->parent; data = data->parent);
6777 /* we're still parsing it and the pointer is not correct yet */
6778 if (data->prev) {
6779 for (; data->prev->next; data = data->prev);
6780 }
6781
6782 /* search for the instance node */
6783 while (path[i]) {
6784 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
6785 if (j <= 0) {
6786 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
6787 goto error;
6788 }
6789 i += j;
6790
6791 str = strndup(model, mod_len);
6792 if (!str) {
6793 LOGMEM;
6794 goto error;
6795 }
6796 mod = ly_ctx_get_module(ctx, str, NULL);
6797 free(str);
6798
6799 if (resolve_data(mod, name, name_len, data, &node_match)) {
6800 /* no instance exists */
6801 break;
6802 }
6803
6804 if (has_predicate) {
6805 /* we have predicate, so the current results must be list or leaf-list */
6806 j = resolve_predicate(&path[i], &node_match);
6807 if (j < 1) {
6808 LOGVAL(LYE_INPRED, LY_VLOG_LYD, data, &path[i-j]);
6809 goto error;
6810 }
6811 i += j;
6812
6813 if (!node_match.count) {
6814 /* no instance exists */
6815 break;
6816 }
6817 }
6818 }
6819
6820 if (!node_match.count) {
6821 /* no instance exists */
6822 if (req_inst > -1) {
6823 LOGVAL(LYE_NOREQINS, LY_VLOG_NONE, NULL, path);
6824 return EXIT_FAILURE;
6825 }
6826 LOGVRB("There is no instance of \"%s\", but it is not required.", path);
6827 return EXIT_SUCCESS;
6828 } else if (node_match.count > 1) {
6829 /* instance identifier must resolve to a single node */
6830 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
6831 goto error;
6832 } else {
6833 /* we have required result, remember it and cleanup */
6834 *ret = node_match.node[0];
6835 free(node_match.node);
6836 return EXIT_SUCCESS;
6837 }
6838
6839error:
6840 /* cleanup */
6841 free(node_match.node);
6842 return -1;
6843}
6844
6845static int
6846resolve_leafref(struct lyd_node_leaf_list *leaf, const char *path, int req_inst, struct lyd_node **ret)
Radek Krejci7de36cf2016-09-12 16:18:50 +02006847{
Radek Krejci7de36cf2016-09-12 16:18:50 +02006848 struct unres_data matches;
6849 uint32_t i;
6850
Radek Krejci9b6aad22016-09-20 15:55:51 +02006851 /* init */
Radek Krejci7de36cf2016-09-12 16:18:50 +02006852 memset(&matches, 0, sizeof matches);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006853 *ret = NULL;
Radek Krejci7de36cf2016-09-12 16:18:50 +02006854
6855 /* EXIT_FAILURE return keeps leaf->value.lefref NULL, handled later */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006856 if (resolve_path_arg_data((struct lyd_node *)leaf, path, &matches) == -1) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02006857 return -1;
6858 }
6859
6860 /* check that value matches */
6861 for (i = 0; i < matches.count; ++i) {
Radek Krejci1899d6a2016-11-03 13:48:07 +01006862 /* not that the value is already in canonical form since the parsers does the conversion,
6863 * so we can simply compare just the values */
Radek Krejci7de36cf2016-09-12 16:18:50 +02006864 if (ly_strequal(leaf->value_str, ((struct lyd_node_leaf_list *)matches.node[i])->value_str, 1)) {
Radek Krejci1899d6a2016-11-03 13:48:07 +01006865 /* we have the match */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006866 *ret = matches.node[i];
Radek Krejci7de36cf2016-09-12 16:18:50 +02006867 break;
6868 }
6869 }
6870
6871 free(matches.node);
6872
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006873 if (!*ret) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02006874 /* reference not found */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006875 if (req_inst > -1) {
6876 LOGVAL(LYE_NOLEAFREF, LY_VLOG_LYD, leaf, path, leaf->value_str);
Radek Krejci7de36cf2016-09-12 16:18:50 +02006877 return EXIT_FAILURE;
6878 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006879 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 +02006880 }
6881 }
6882
6883 return EXIT_SUCCESS;
6884}
6885
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006886/* ignore fail because we are parsing edit-config, get, or get-config - but only if the union includes leafref or instid */
Michal Vaskofd6c6502017-01-06 12:15:41 +01006887int
6888resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type, int store, int ignore_fail,
6889 struct lys_type **resolved_type)
Radek Krejci9b6aad22016-09-20 15:55:51 +02006890{
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006891 struct lys_type *t;
Michal Vaskob1ac8722017-01-02 13:04:25 +01006892 struct lyd_node *ret, *par, *op_node;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006893 int found, hidden, success = 0;
6894 const char *json_val = NULL;
Radek Krejci9b6aad22016-09-20 15:55:51 +02006895
6896 assert(type->base == LY_TYPE_UNION);
6897
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006898 if ((leaf->value_type == LY_TYPE_UNION) || (leaf->value_type == (LY_TYPE_INST | LY_TYPE_INST_UNRES))) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01006899 assert(store);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006900 /* either NULL or instid previously converted to JSON */
6901 json_val = leaf->value.string;
6902 }
Michal Vasko1c8567a2017-01-05 13:42:27 +01006903
Michal Vaskofd6c6502017-01-06 12:15:41 +01006904 if (store) {
6905 if ((leaf->value_type & LY_DATA_TYPE_MASK) == LY_TYPE_BITS) {
6906 free(leaf->value.bit);
6907 }
6908 memset(&leaf->value, 0, sizeof leaf->value);
Michal Vasko1c8567a2017-01-05 13:42:27 +01006909 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006910
6911 /* turn logging off, we are going to try to validate the value with all the types in order */
6912 hidden = *ly_vlog_hide_location();
6913 ly_vlog_hide(1);
6914
6915 t = NULL;
6916 found = 0;
6917 while ((t = lyp_get_next_union_type(type, t, &found))) {
6918 found = 0;
6919
6920 switch (t->base) {
6921 case LY_TYPE_LEAFREF:
6922 if (!resolve_leafref(leaf, t->info.lref.path, (ignore_fail ? -1 : t->info.lref.req), &ret)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01006923 if (store) {
6924 if (ret && !(leaf->schema->flags & LYS_LEAFREF_DEP)) {
6925 /* valid resolved */
6926 leaf->value.leafref = ret;
6927 leaf->value_type = LY_TYPE_LEAFREF;
6928 } else {
6929 /* valid unresolved */
6930 if (!lyp_parse_value(t, &leaf->value_str, NULL, leaf, 1, 0)) {
6931 return -1;
6932 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006933 }
6934 }
6935
6936 success = 1;
6937 }
6938 break;
6939 case LY_TYPE_INST:
6940 if (!resolve_instid((struct lyd_node *)leaf, (json_val ? json_val : leaf->value_str),
6941 (ignore_fail ? -1 : t->info.inst.req), &ret)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01006942 if (store) {
6943 if (ret) {
6944 for (op_node = (struct lyd_node *)leaf;
6945 op_node && !(op_node->schema->nodetype & (LYS_RPC | LYS_NOTIF | LYS_ACTION));
6946 op_node = op_node->parent);
6947 if (op_node) {
6948 /* this is an RPC/notif/action */
6949 for (par = ret->parent; par && (par != op_node); par = par->parent);
6950 if (!par) {
6951 /* target instance is outside the operation - do not store the pointer */
6952 ret = NULL;
6953 }
Michal Vaskob1ac8722017-01-02 13:04:25 +01006954 }
6955 }
Michal Vaskofd6c6502017-01-06 12:15:41 +01006956 if (ret) {
6957 /* valid resolved */
6958 leaf->value.instance = ret;
6959 leaf->value_type = LY_TYPE_INST;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006960
Michal Vaskofd6c6502017-01-06 12:15:41 +01006961 if (json_val) {
6962 lydict_remove(leaf->schema->module->ctx, leaf->value_str);
6963 leaf->value_str = json_val;
6964 json_val = NULL;
6965 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006966 } else {
Michal Vaskofd6c6502017-01-06 12:15:41 +01006967 /* valid unresolved */
6968 if (json_val) {
6969 /* put the JSON val back */
6970 leaf->value.string = json_val;
6971 json_val = NULL;
6972 } else {
6973 leaf->value.instance = NULL;
6974 }
6975 leaf->value_type = LY_TYPE_INST | LY_TYPE_INST_UNRES;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006976 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006977 }
6978
6979 success = 1;
6980 }
6981 break;
6982 default:
Michal Vaskofd6c6502017-01-06 12:15:41 +01006983 if (lyp_parse_value(t, &leaf->value_str, NULL, leaf, store, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006984 success = 1;
6985 }
6986 break;
6987 }
6988
6989 if (success) {
6990 break;
6991 }
6992
6993 /* erase information about errors - they are false or irrelevant
6994 * and will be replaced by a single error messages */
6995 ly_err_clean(1);
6996
6997 /* erase possible present and invalid value data */
Michal Vaskofd6c6502017-01-06 12:15:41 +01006998 if (store) {
6999 if (t->base == LY_TYPE_BITS) {
7000 free(leaf->value.bit);
7001 }
7002 memset(&leaf->value, 0, sizeof leaf->value);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007003 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007004 }
7005
7006 /* turn logging back on */
7007 if (!hidden) {
7008 ly_vlog_hide(0);
7009 }
7010
7011 if (json_val) {
7012 if (!success) {
7013 /* put the value back for now */
7014 assert(leaf->value_type == LY_TYPE_UNION);
7015 leaf->value.string = json_val;
7016 } else {
7017 /* value was ultimately useless, but we could not have known */
7018 lydict_remove(leaf->schema->module->ctx, json_val);
7019 }
7020 }
7021
Michal Vaskofd6c6502017-01-06 12:15:41 +01007022 if (success) {
7023 if (resolved_type) {
7024 *resolved_type = t;
7025 }
7026 } else if (!ignore_fail || !type->info.uni.has_ptr_type) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007027 /* not found and it is required */
7028 LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, leaf->value_str ? leaf->value_str : "", leaf->schema->name);
Radek Krejci9b6aad22016-09-20 15:55:51 +02007029 return EXIT_FAILURE;
7030 }
7031
7032 return EXIT_SUCCESS;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007033
Radek Krejci9b6aad22016-09-20 15:55:51 +02007034}
7035
Michal Vasko8bcdf292015-08-19 14:04:43 +02007036/**
7037 * @brief Resolve a single unres data item. Logs directly.
7038 *
Michal Vaskocf024702015-10-08 15:01:42 +02007039 * @param[in] node Data node to resolve.
Michal Vaskocf024702015-10-08 15:01:42 +02007040 * @param[in] type Type of the unresolved item.
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007041 * @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 +02007042 *
7043 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
7044 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02007045int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007046resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type, int ignore_fail)
Michal Vasko8bcdf292015-08-19 14:04:43 +02007047{
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007048 int rc, req_inst;
Michal Vasko83a6c462015-10-08 16:43:53 +02007049 struct lyd_node_leaf_list *leaf;
Michal Vaskob1ac8722017-01-02 13:04:25 +01007050 struct lyd_node *ret, *op_node, *par;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007051 struct lys_node_leaf *sleaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007052
Michal Vasko83a6c462015-10-08 16:43:53 +02007053 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02007054 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007055
Michal Vaskocf024702015-10-08 15:01:42 +02007056 switch (type) {
7057 case UNRES_LEAFREF:
7058 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007059 assert(leaf->validity & LYD_VAL_LEAFREF);
7060 req_inst = (ignore_fail ? -1 : sleaf->type.info.lref.req);
7061 rc = resolve_leafref(leaf, sleaf->type.info.lref.path, req_inst, &ret);
7062 if (!rc) {
Michal Vaskob1ac8722017-01-02 13:04:25 +01007063 if (ret && !(leaf->schema->flags & LYS_LEAFREF_DEP)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007064 /* valid resolved */
Michal Vasko1c8567a2017-01-05 13:42:27 +01007065 if ((leaf->value_type & LY_DATA_TYPE_MASK) == LY_TYPE_BITS) {
7066 free(leaf->value.bit);
7067 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007068 leaf->value.leafref = ret;
7069 leaf->value_type = LY_TYPE_LEAFREF;
7070 } else {
7071 /* valid unresolved */
7072 if (!(leaf->value_type & LY_TYPE_LEAFREF_UNRES)) {
7073 if (!lyp_parse_value(&sleaf->type, &leaf->value_str, NULL, leaf, 1, 0)) {
7074 return -1;
7075 }
7076 }
7077 }
7078 leaf->validity &= ~LYD_VAL_LEAFREF;
7079 } else {
7080 return rc;
7081 }
7082 break;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007083
Michal Vaskocf024702015-10-08 15:01:42 +02007084 case UNRES_INSTID:
Radek Krejci7de36cf2016-09-12 16:18:50 +02007085 assert(sleaf->type.base == LY_TYPE_INST);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007086 req_inst = (ignore_fail ? -1 : sleaf->type.info.inst.req);
7087 rc = resolve_instid(node, leaf->value_str, req_inst, &ret);
7088 if (!rc) {
7089 if (ret) {
Michal Vaskob1ac8722017-01-02 13:04:25 +01007090 for (op_node = (struct lyd_node *)leaf;
7091 op_node && !(op_node->schema->nodetype & (LYS_RPC | LYS_NOTIF | LYS_ACTION));
7092 op_node = op_node->parent);
7093 if (op_node) {
7094 /* this is an RPC/notif/action */
7095 for (par = ret->parent; par && (par != op_node); par = par->parent);
7096 if (!par) {
7097 /* target instance is outside the operation - do not store the pointer */
7098 ret = NULL;
7099 }
7100 }
7101 }
7102 if (ret) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007103 /* valid resolved */
7104 leaf->value.instance = ret;
7105 leaf->value_type = LY_TYPE_INST;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007106 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007107 /* valid unresolved */
7108 leaf->value.instance = NULL;
7109 leaf->value_type = LY_TYPE_INST | LY_TYPE_INST_UNRES;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007110 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007111 } else {
7112 return rc;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007113 }
Michal Vaskocf024702015-10-08 15:01:42 +02007114 break;
7115
Radek Krejci7de36cf2016-09-12 16:18:50 +02007116 case UNRES_UNION:
7117 assert(sleaf->type.base == LY_TYPE_UNION);
Michal Vaskofd6c6502017-01-06 12:15:41 +01007118 return resolve_union(leaf, &sleaf->type, 1, ignore_fail, NULL);
Radek Krejci7de36cf2016-09-12 16:18:50 +02007119
Michal Vaskocf024702015-10-08 15:01:42 +02007120 case UNRES_WHEN:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007121 if ((rc = resolve_when(node, NULL, ignore_fail))) {
Michal Vaskocf024702015-10-08 15:01:42 +02007122 return rc;
7123 }
7124 break;
7125
Michal Vaskobf19d252015-10-08 15:39:17 +02007126 case UNRES_MUST:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007127 if ((rc = resolve_must(node, 0, ignore_fail))) {
Michal Vaskoc8c810c2016-09-15 14:02:00 +02007128 return rc;
7129 }
7130 break;
7131
7132 case UNRES_MUST_INOUT:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007133 if ((rc = resolve_must(node, 1, ignore_fail))) {
Michal Vaskobf19d252015-10-08 15:39:17 +02007134 return rc;
7135 }
7136 break;
7137
Michal Vaskocf024702015-10-08 15:01:42 +02007138 default:
Michal Vasko8bcdf292015-08-19 14:04:43 +02007139 LOGINT;
7140 return -1;
7141 }
7142
7143 return EXIT_SUCCESS;
7144}
7145
7146/**
Radek Krejci0b7704f2016-03-18 12:16:14 +01007147 * @brief add data unres item
Michal Vasko8bcdf292015-08-19 14:04:43 +02007148 *
7149 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02007150 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007151 *
Radek Krejci0b7704f2016-03-18 12:16:14 +01007152 * @return 0 on success, -1 on error.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007153 */
7154int
Radek Krejci0b7704f2016-03-18 12:16:14 +01007155unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02007156{
Radek Krejci03b71f72016-03-16 11:10:09 +01007157 assert(unres && node);
Michal Vaskoc4280842016-04-19 16:10:42 +02007158 assert((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)
Radek Krejcibacc7442016-10-27 13:39:56 +02007159 || (type == UNRES_MUST_INOUT) || (type == UNRES_UNION));
Michal Vasko8bcdf292015-08-19 14:04:43 +02007160
Radek Krejci03b71f72016-03-16 11:10:09 +01007161 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01007162 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
7163 if (!unres->node) {
7164 LOGMEM;
7165 return -1;
7166 }
Michal Vaskocf024702015-10-08 15:01:42 +02007167 unres->node[unres->count - 1] = node;
Michal Vasko253035f2015-12-17 16:58:13 +01007168 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
7169 if (!unres->type) {
7170 LOGMEM;
7171 return -1;
7172 }
Michal Vaskocf024702015-10-08 15:01:42 +02007173 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007174
Radek Krejci0b7704f2016-03-18 12:16:14 +01007175 if (type == UNRES_WHEN) {
7176 /* remove previous result */
7177 node->when_status = LYD_WHEN;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007178 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007179
7180 return EXIT_SUCCESS;
7181}
7182
7183/**
7184 * @brief Resolve every unres data item in the structure. Logs directly.
7185 *
Radek Krejci082c84f2016-10-17 16:33:06 +02007186 * If options includes LYD_OPT_TRUSTED, the data are considered trusted (when, must conditions are not expected,
7187 * unresolved leafrefs/instids are accepted).
7188 *
7189 * If options includes LYD_OPT_NOAUTODEL, the false resulting when condition on non-default nodes, the error is raised.
7190 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007191 * @param[in] unres Unres data structure to use.
Radek Krejci082c84f2016-10-17 16:33:06 +02007192 * @param[in,out] root Root node of the data tree, can be changed due to autodeletion.
7193 * @param[in] options Data options as described above.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007194 *
7195 * @return EXIT_SUCCESS on success, -1 on error.
7196 */
7197int
Radek Krejci082c84f2016-10-17 16:33:06 +02007198resolve_unres_data(struct unres_data *unres, struct lyd_node **root, int options)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007199{
Radek Krejci0c0086a2016-03-24 15:20:28 +01007200 uint32_t i, j, first = 1, resolved = 0, del_items = 0, when_stmt = 0;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007201 int rc, progress, ignore_fails;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007202 struct lyd_node *parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007203
Radek Krejci082c84f2016-10-17 16:33:06 +02007204 assert(root);
Radek Krejci03b71f72016-03-16 11:10:09 +01007205 assert(unres);
Radek Krejci03b71f72016-03-16 11:10:09 +01007206
7207 if (!unres->count) {
7208 return EXIT_SUCCESS;
7209 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007210
Michal Vaskoad2e44a2017-01-03 10:31:35 +01007211 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 +01007212 ignore_fails = 1;
7213 } else {
7214 ignore_fails = 0;
7215 }
7216
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02007217 LOGVRB("Resolving unresolved data nodes and their constraints...");
Radek Krejci010e54b2016-03-15 09:40:34 +01007218 ly_vlog_hide(1);
7219
Radek Krejci0b7704f2016-03-18 12:16:14 +01007220 /* when-stmt first */
Radek Krejci010e54b2016-03-15 09:40:34 +01007221 do {
Radek Krejci00a0e712016-10-26 10:24:46 +02007222 ly_err_clean(1);
Radek Krejci010e54b2016-03-15 09:40:34 +01007223 progress = 0;
Michal Vasko6df94132016-09-22 11:08:09 +02007224 for (i = 0; i < unres->count; i++) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007225 if (unres->type[i] != UNRES_WHEN) {
7226 continue;
7227 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007228 if (first) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007229 /* count when-stmt nodes in unres list */
7230 when_stmt++;
7231 }
7232
7233 /* resolve when condition only when all parent when conditions are already resolved */
7234 for (parent = unres->node[i]->parent;
7235 parent && LYD_WHEN_DONE(parent->when_status);
7236 parent = parent->parent) {
7237 if (!parent->parent && (parent->when_status & LYD_WHEN_FALSE)) {
7238 /* the parent node was already unlinked, do not resolve this node,
7239 * it will be removed anyway, so just mark it as resolved
7240 */
7241 unres->node[i]->when_status |= LYD_WHEN_FALSE;
7242 unres->type[i] = UNRES_RESOLVED;
7243 resolved++;
7244 break;
7245 }
7246 }
7247 if (parent) {
7248 continue;
7249 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007250
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007251 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fails);
Radek Krejci010e54b2016-03-15 09:40:34 +01007252 if (!rc) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007253 if (unres->node[i]->when_status & LYD_WHEN_FALSE) {
Radek Krejci082c84f2016-10-17 16:33:06 +02007254 if ((options & LYD_OPT_NOAUTODEL) && !unres->node[i]->dflt) {
Radek Krejci03b71f72016-03-16 11:10:09 +01007255 /* false when condition */
7256 ly_vlog_hide(0);
Radek Krejci2467a492016-10-24 15:16:59 +02007257 ly_err_repeat();
Radek Krejci03b71f72016-03-16 11:10:09 +01007258 return -1;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007259 } /* follows else */
7260
Radek Krejci0c0086a2016-03-24 15:20:28 +01007261 /* only unlink now, the subtree can contain another nodes stored in the unres list */
7262 /* if it has parent non-presence containers that would be empty, we should actually
7263 * remove the container
7264 */
Radek Krejci2537fd32016-09-07 16:22:41 +02007265 for (parent = unres->node[i];
7266 parent->parent && parent->parent->schema->nodetype == LYS_CONTAINER;
7267 parent = parent->parent) {
7268 if (((struct lys_node_container *)parent->parent->schema)->presence) {
7269 /* presence container */
7270 break;
Radek Krejci0c0086a2016-03-24 15:20:28 +01007271 }
Radek Krejci2537fd32016-09-07 16:22:41 +02007272 if (parent->next || parent->prev != parent) {
7273 /* non empty (the child we are in and we are going to remove is not the only child) */
7274 break;
7275 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007276 }
Radek Krejci2537fd32016-09-07 16:22:41 +02007277 unres->node[i] = parent;
Radek Krejci0c0086a2016-03-24 15:20:28 +01007278
Radek Krejci0b7704f2016-03-18 12:16:14 +01007279 /* auto-delete */
7280 LOGVRB("auto-delete node \"%s\" due to when condition (%s)", ly_errpath(),
7281 ((struct lys_node_leaf *)unres->node[i]->schema)->when->cond);
Radek Krejci0c0086a2016-03-24 15:20:28 +01007282 if (*root && *root == unres->node[i]) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007283 *root = (*root)->next;
Radek Krejci03b71f72016-03-16 11:10:09 +01007284 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007285
Radek Krejci0b7704f2016-03-18 12:16:14 +01007286 lyd_unlink(unres->node[i]);
7287 unres->type[i] = UNRES_DELETE;
7288 del_items++;
Radek Krejci51fd8162016-03-24 15:49:51 +01007289
7290 /* update the rest of unres items */
7291 for (j = 0; j < unres->count; j++) {
Radek Krejci3db819b2016-03-24 16:29:48 +01007292 if (unres->type[j] == UNRES_RESOLVED || unres->type[j] == UNRES_DELETE) {
Radek Krejci51fd8162016-03-24 15:49:51 +01007293 continue;
7294 }
7295
7296 /* test if the node is in subtree to be deleted */
7297 for (parent = unres->node[j]; parent; parent = parent->parent) {
7298 if (parent == unres->node[i]) {
7299 /* yes, it is */
7300 unres->type[j] = UNRES_RESOLVED;
7301 resolved++;
7302 break;
7303 }
7304 }
7305 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007306 } else {
7307 unres->type[i] = UNRES_RESOLVED;
Radek Krejci03b71f72016-03-16 11:10:09 +01007308 }
Radek Krejci00a0e712016-10-26 10:24:46 +02007309 ly_err_clean(1);
Radek Krejci010e54b2016-03-15 09:40:34 +01007310 resolved++;
7311 progress = 1;
7312 } else if (rc == -1) {
7313 ly_vlog_hide(0);
Michal Vasko76e73402016-08-24 16:00:13 +02007314 /* print only this last error */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007315 resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fails);
Radek Krejci010e54b2016-03-15 09:40:34 +01007316 return -1;
Radek Krejci2467a492016-10-24 15:16:59 +02007317 } /* else forward reference */
Radek Krejci010e54b2016-03-15 09:40:34 +01007318 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007319 first = 0;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007320 } while (progress && resolved < when_stmt);
Radek Krejci010e54b2016-03-15 09:40:34 +01007321
Radek Krejci0b7704f2016-03-18 12:16:14 +01007322 /* do we have some unresolved when-stmt? */
Radek Krejcid940d732016-03-24 16:02:28 +01007323 if (when_stmt > resolved) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007324 ly_vlog_hide(0);
Radek Krejci2467a492016-10-24 15:16:59 +02007325 ly_err_repeat();
Radek Krejci0b7704f2016-03-18 12:16:14 +01007326 return -1;
7327 }
7328
7329 for (i = 0; del_items && i < unres->count; i++) {
7330 /* we had some when-stmt resulted to false, so now we have to sanitize the unres list */
7331 if (unres->type[i] != UNRES_DELETE) {
7332 continue;
7333 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007334 if (!unres->node[i]) {
7335 unres->type[i] = UNRES_RESOLVED;
7336 del_items--;
7337 continue;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007338 }
7339
7340 /* really remove the complete subtree */
7341 lyd_free(unres->node[i]);
7342 unres->type[i] = UNRES_RESOLVED;
7343 del_items--;
7344 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007345 ly_vlog_hide(0);
Radek Krejci010e54b2016-03-15 09:40:34 +01007346
7347 /* rest */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007348 for (i = 0; i < unres->count; ++i) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007349 if (unres->type[i] == UNRES_RESOLVED) {
7350 continue;
7351 }
Radek Krejci082c84f2016-10-17 16:33:06 +02007352 assert(!(options & LYD_OPT_TRUSTED) || ((unres->type[i] != UNRES_MUST) && (unres->type[i] != UNRES_MUST_INOUT)));
Radek Krejci010e54b2016-03-15 09:40:34 +01007353
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007354 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fails);
7355 if (rc) {
7356 /* since when was already resolved, a forward reference is an error */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007357 return -1;
7358 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007359
7360 unres->type[i] = UNRES_RESOLVED;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007361 }
7362
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02007363 LOGVRB("All data nodes and constraints resolved.");
Radek Krejci010e54b2016-03-15 09:40:34 +01007364 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007365 return EXIT_SUCCESS;
7366}