blob: 084ee1c409c404f0e3e171c6cdb11d018922fe9a [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 Vasko7b54f7e2016-05-03 15:07:31 +0200913 * predicate-expr = "." / identifier / 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;
965 } else if ((ret = parse_identifier(id)) < 1) {
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100966 return -parsed + ret;
967 }
968 if (name) {
969 *name = id;
970 }
971 if (nam_len) {
972 *nam_len = ret;
973 }
974
975 parsed += ret;
976 id += ret;
977
978 while (isspace(id[0])) {
979 ++parsed;
980 ++id;
981 }
982
983 /* there is value as well */
984 if (id[0] == '=') {
985 ++parsed;
986 ++id;
987
988 while (isspace(id[0])) {
989 ++parsed;
990 ++id;
991 }
992
993 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
994 if ((id[0] == '\"') || (id[0] == '\'')) {
995 quote = id[0];
996
997 ++parsed;
998 ++id;
999
1000 if ((ptr = strchr(id, quote)) == NULL) {
1001 return -parsed;
1002 }
1003 ret = ptr - id;
1004
1005 if (value) {
1006 *value = id;
1007 }
1008 if (val_len) {
1009 *val_len = ret;
1010 }
1011
1012 parsed += ret + 1;
1013 id += ret + 1;
1014 } else {
1015 return -parsed;
1016 }
1017
1018 while (isspace(id[0])) {
1019 ++parsed;
1020 ++id;
1021 }
Michal Vasko22448d32016-03-16 13:17:29 +01001022 } else if (value) {
1023 /* if value was expected, it's mandatory */
1024 return -parsed;
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001025 }
1026
1027 if (id[0] != ']') {
1028 return -parsed;
1029 }
1030
1031 ++parsed;
1032 ++id;
1033
1034 if ((id[0] == '[') && has_predicate) {
1035 *has_predicate = 1;
1036 }
1037
1038 return parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +02001039}
1040
1041/**
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001042 * @brief Resolve (find) a feature definition. Logs directly.
1043 *
1044 * @param[in] feat_name Feature name to resolve.
1045 * @param[in] len Length of \p feat_name.
1046 * @param[in] node Node with the if-feature expression.
Radek Krejci9ff0a922016-07-14 13:08:05 +02001047 * @param[out] feature Pointer to be set to point to the feature definition, if feature not found
1048 * (return code 1), the pointer is untouched.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001049 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02001050 * @return 0 on success, 1 on forward reference, -1 on error.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001051 */
1052static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001053resolve_feature(const char *feat_name, uint16_t len, const struct lys_node *node, struct lys_feature **feature)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001054{
1055 char *str;
1056 const char *mod_name, *name;
1057 int mod_name_len, nam_len, i, j;
1058 const struct lys_module *module;
1059
Radek Krejci9ff0a922016-07-14 13:08:05 +02001060 assert(feature);
1061
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001062 /* check prefix */
1063 if ((i = parse_node_identifier(feat_name, &mod_name, &mod_name_len, &name, &nam_len)) < 1) {
1064 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, feat_name[-i], &feat_name[-i]);
1065 return -1;
1066 }
1067
1068 module = lys_get_import_module(lys_node_module(node), NULL, 0, mod_name, mod_name_len);
1069 if (!module) {
1070 /* identity refers unknown data model */
1071 LOGVAL(LYE_INMOD_LEN, LY_VLOG_NONE, NULL, mod_name_len, mod_name);
1072 return -1;
1073 }
1074
Radek Krejci9ff0a922016-07-14 13:08:05 +02001075 if (module != node->module && module == lys_node_module(node)) {
1076 /* first, try to search directly in submodule where the feature was mentioned */
1077 for (j = 0; j < node->module->features_size; j++) {
1078 if (!strncmp(name, node->module->features[j].name, nam_len) && !node->module->features[j].name[nam_len]) {
1079 /* check status */
1080 if (lyp_check_status(node->flags, lys_node_module(node), node->name, node->module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001081 node->module->features[j].module, node->module->features[j].name, NULL)) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001082 return -1;
1083 }
1084 *feature = &node->module->features[j];
1085 return 0;
1086 }
1087 }
1088 }
1089
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001090 /* search in the identified module ... */
1091 for (j = 0; j < module->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001092 if (!strncmp(name, module->features[j].name, nam_len) && !module->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001093 /* check status */
1094 if (lyp_check_status(node->flags, lys_node_module(node), node->name, module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001095 module->features[j].module, module->features[j].name, NULL)) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001096 return -1;
1097 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001098 *feature = &module->features[j];
1099 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001100 }
1101 }
1102 /* ... and all its submodules */
1103 for (i = 0; i < module->inc_size; i++) {
1104 if (!module->inc[i].submodule) {
1105 /* not yet resolved */
1106 continue;
1107 }
1108 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001109 if (!strncmp(name, module->inc[i].submodule->features[j].name, nam_len)
1110 && !module->inc[i].submodule->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001111 /* check status */
1112 if (lyp_check_status(node->flags, lys_node_module(node), node->name,
1113 module->inc[i].submodule->features[j].flags,
1114 module->inc[i].submodule->features[j].module,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001115 module->inc[i].submodule->features[j].name, NULL)) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001116 return -1;
1117 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001118 *feature = &module->inc[i].submodule->features[j];
1119 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001120 }
1121 }
1122 }
1123
1124 /* not found */
1125 str = strndup(feat_name, len);
1126 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, "feature", str);
1127 free(str);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001128 return 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001129}
1130
Radek Krejci9ff0a922016-07-14 13:08:05 +02001131/*
1132 * @return
Radek Krejci69b8d922016-07-27 13:13:41 +02001133 * - 1 if enabled
1134 * - 0 if disabled
Radek Krejci9ff0a922016-07-14 13:08:05 +02001135 * - -1 if not usable by its if-feature expression
1136 */
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001137static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001138resolve_feature_value(const struct lys_feature *feat)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001139{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001140 int i;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001141
Radek Krejci9ff0a922016-07-14 13:08:05 +02001142 for (i = 0; i < feat->iffeature_size; i++) {
Radek Krejci69b8d922016-07-27 13:13:41 +02001143 if (!resolve_iffeature(&feat->iffeature[i])) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001144 return -1;
1145 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001146 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001147
Radek Krejci69b8d922016-07-27 13:13:41 +02001148 return feat->flags & LYS_FENABLED ? 1 : 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001149}
1150
1151static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001152resolve_iffeature_recursive(struct lys_iffeature *expr, int *index_e, int *index_f)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001153{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001154 uint8_t op;
1155 int rc, a, b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001156
Radek Krejci9ff0a922016-07-14 13:08:05 +02001157 op = iff_getop(expr->expr, *index_e);
1158 (*index_e)++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001159
Radek Krejci9ff0a922016-07-14 13:08:05 +02001160 switch (op) {
1161 case LYS_IFF_F:
1162 /* resolve feature */
1163 return resolve_feature_value(expr->features[(*index_f)++]);
1164 case LYS_IFF_NOT:
1165 rc = resolve_iffeature_recursive(expr, index_e, index_f);
1166 if (rc == -1) {
1167 /* one of the referenced feature is hidden by its if-feature,
1168 * so this if-feature expression is always false */
1169 return -1;
1170 } else {
1171 /* invert result */
1172 return rc ? 0 : 1;
1173 }
1174 case LYS_IFF_AND:
1175 case LYS_IFF_OR:
1176 a = resolve_iffeature_recursive(expr, index_e, index_f);
1177 b = resolve_iffeature_recursive(expr, index_e, index_f);
1178 if (a == -1 || b == -1) {
1179 /* one of the referenced feature is hidden by its if-feature,
1180 * so this if-feature expression is always false */
1181 return -1;
1182 } else if (op == LYS_IFF_AND) {
1183 return a && b;
1184 } else { /* LYS_IFF_OR */
1185 return a || b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001186 }
1187 }
1188
Radek Krejci9ff0a922016-07-14 13:08:05 +02001189 return -1;
1190}
1191
1192int
1193resolve_iffeature(struct lys_iffeature *expr)
1194{
1195 int rc = -1;
1196 int index_e = 0, index_f = 0;
1197
1198 if (expr->expr) {
1199 rc = resolve_iffeature_recursive(expr, &index_e, &index_f);
1200 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001201 return (rc == 1) ? 1 : 0;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001202}
1203
1204struct iff_stack {
1205 int size;
1206 int index; /* first empty item */
1207 uint8_t *stack;
1208};
1209
1210static int
1211iff_stack_push(struct iff_stack *stack, uint8_t value)
1212{
1213 if (stack->index == stack->size) {
1214 stack->size += 4;
1215 stack->stack = ly_realloc(stack->stack, stack->size * sizeof *stack->stack);
1216 if (!stack->stack) {
1217 LOGMEM;
1218 stack->size = 0;
1219 return EXIT_FAILURE;
1220 }
1221 }
1222
1223 stack->stack[stack->index++] = value;
1224 return EXIT_SUCCESS;
1225}
1226
1227static uint8_t
1228iff_stack_pop(struct iff_stack *stack)
1229{
1230 stack->index--;
1231 return stack->stack[stack->index];
1232}
1233
1234static void
1235iff_stack_clean(struct iff_stack *stack)
1236{
1237 stack->size = 0;
1238 free(stack->stack);
1239}
1240
1241static void
1242iff_setop(uint8_t *list, uint8_t op, int pos)
1243{
1244 uint8_t *item;
1245 uint8_t mask = 3;
1246
1247 assert(pos >= 0);
1248 assert(op <= 3); /* max 2 bits */
1249
1250 item = &list[pos / 4];
1251 mask = mask << 2 * (pos % 4);
1252 *item = (*item) & ~mask;
1253 *item = (*item) | (op << 2 * (pos % 4));
1254}
1255
1256uint8_t
1257iff_getop(uint8_t *list, int pos)
1258{
1259 uint8_t *item;
1260 uint8_t mask = 3, result;
1261
1262 assert(pos >= 0);
1263
1264 item = &list[pos / 4];
1265 result = (*item) & (mask << 2 * (pos % 4));
1266 return result >> 2 * (pos % 4);
1267}
1268
1269#define LYS_IFF_LP 0x04 /* ( */
1270#define LYS_IFF_RP 0x08 /* ) */
1271
Radek Krejcicbb473e2016-09-16 14:48:32 +02001272/* internal structure for passing data for UNRES_IFFEAT */
1273struct unres_iffeat_data {
1274 struct lys_node *node;
1275 const char *fname;
Radek Krejci9de2c042016-10-19 16:53:06 +02001276 int infeature;
Radek Krejcicbb473e2016-09-16 14:48:32 +02001277};
1278
Radek Krejci9ff0a922016-07-14 13:08:05 +02001279void
1280resolve_iffeature_getsizes(struct lys_iffeature *iffeat, unsigned int *expr_size, unsigned int *feat_size)
1281{
1282 unsigned int e = 0, f = 0, r = 0;
1283 uint8_t op;
1284
1285 assert(iffeat);
1286
1287 if (!iffeat->expr) {
1288 goto result;
1289 }
1290
1291 do {
1292 op = iff_getop(iffeat->expr, e++);
1293 switch (op) {
1294 case LYS_IFF_NOT:
1295 if (!r) {
1296 r += 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001297 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001298 break;
1299 case LYS_IFF_AND:
1300 case LYS_IFF_OR:
1301 if (!r) {
1302 r += 2;
1303 } else {
1304 r += 1;
1305 }
1306 break;
1307 case LYS_IFF_F:
1308 f++;
1309 if (r) {
1310 r--;
1311 }
1312 break;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001313 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001314 } while(r);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001315
Radek Krejci9ff0a922016-07-14 13:08:05 +02001316result:
1317 if (expr_size) {
1318 *expr_size = e;
1319 }
1320 if (feat_size) {
1321 *feat_size = f;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001322 }
1323}
1324
1325int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001326resolve_iffeature_compile(struct lys_iffeature *iffeat_expr, const char *value, struct lys_node *node,
Radek Krejci9de2c042016-10-19 16:53:06 +02001327 int infeature, struct unres_schema *unres)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001328{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001329 const char *c = value;
1330 int r, rc = EXIT_FAILURE;
Radek Krejci69b8d922016-07-27 13:13:41 +02001331 int i, j, last_not, checkversion = 0;
1332 unsigned int f_size = 0, expr_size = 0, f_exp = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001333 uint8_t op;
1334 struct iff_stack stack = {0, 0, NULL};
Radek Krejcicbb473e2016-09-16 14:48:32 +02001335 struct unres_iffeat_data *iff_data;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001336
Radek Krejci9ff0a922016-07-14 13:08:05 +02001337 assert(c);
1338
1339 if (isspace(c[0])) {
1340 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, c[0], c);
1341 return EXIT_FAILURE;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001342 }
1343
Radek Krejci9ff0a922016-07-14 13:08:05 +02001344 /* pre-parse the expression to get sizes for arrays, also do some syntax checks of the expression */
1345 for (i = j = last_not = 0; c[i]; i++) {
1346 if (c[i] == '(') {
Radek Krejci69b8d922016-07-27 13:13:41 +02001347 checkversion = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001348 j++;
1349 continue;
1350 } else if (c[i] == ')') {
1351 j--;
1352 continue;
1353 } else if (isspace(c[i])) {
1354 continue;
1355 }
1356
1357 if (!strncmp(&c[i], "not", r = 3) || !strncmp(&c[i], "and", r = 3) || !strncmp(&c[i], "or", r = 2)) {
1358 if (c[i + r] == '\0') {
Radek Krejcia98da3f2016-07-27 14:05:22 +02001359 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
Radek Krejci9ff0a922016-07-14 13:08:05 +02001360 return EXIT_FAILURE;
1361 } else if (!isspace(c[i + r])) {
1362 /* feature name starting with the not/and/or */
1363 last_not = 0;
1364 f_size++;
1365 } else if (c[i] == 'n') { /* not operation */
1366 if (last_not) {
1367 /* double not */
1368 expr_size = expr_size - 2;
1369 last_not = 0;
1370 } else {
1371 last_not = 1;
1372 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001373 } else { /* and, or */
1374 f_exp++;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001375 /* not a not operation */
1376 last_not = 0;
1377 }
1378 i += r;
1379 } else {
1380 f_size++;
1381 last_not = 0;
1382 }
1383 expr_size++;
1384
1385 while (!isspace(c[i])) {
1386 if (!c[i] || c[i] == ')') {
1387 i--;
1388 break;
1389 }
1390 i++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001391 }
1392 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001393 if (j || f_exp != f_size) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001394 /* not matching count of ( and ) */
1395 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1396 return EXIT_FAILURE;
1397 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001398
Radek Krejci69b8d922016-07-27 13:13:41 +02001399 if (checkversion || expr_size > 1) {
1400 /* check that we have 1.1 module */
1401 if (node->module->version != 2) {
1402 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1403 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "YANG 1.1 if-feature expression found in 1.0 module.");
1404 return EXIT_FAILURE;
1405 }
1406 }
1407
Radek Krejci9ff0a922016-07-14 13:08:05 +02001408 /* allocate the memory */
1409 iffeat_expr->expr = calloc((j = (expr_size / 4) + ((expr_size % 4) ? 1 : 0)), sizeof *iffeat_expr->expr);
Radek Krejcicbb473e2016-09-16 14:48:32 +02001410 iffeat_expr->features = calloc(f_size, sizeof *iffeat_expr->features);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001411 stack.size = expr_size;
1412 stack.stack = malloc(expr_size * sizeof *stack.stack);
1413 if (!stack.stack || !iffeat_expr->expr || !iffeat_expr->features) {
1414 LOGMEM;
1415 goto error;
1416 }
1417 f_size--; expr_size--; /* used as indexes from now */
1418
1419 for (i--; i >= 0; i--) {
1420 if (c[i] == ')') {
1421 /* push it on stack */
1422 iff_stack_push(&stack, LYS_IFF_RP);
1423 continue;
1424 } else if (c[i] == '(') {
1425 /* pop from the stack into result all operators until ) */
1426 while((op = iff_stack_pop(&stack)) != LYS_IFF_RP) {
1427 iff_setop(iffeat_expr->expr, op, expr_size--);
1428 }
1429 continue;
1430 } else if (isspace(c[i])) {
1431 continue;
1432 }
1433
1434 /* end operator or operand -> find beginning and get what is it */
1435 j = i + 1;
1436 while (i >= 0 && !isspace(c[i]) && c[i] != '(') {
1437 i--;
1438 }
1439 i++; /* get back by one step */
1440
1441 if (!strncmp(&c[i], "not ", 4)) {
1442 if (stack.index && stack.stack[stack.index - 1] == LYS_IFF_NOT) {
1443 /* double not */
1444 iff_stack_pop(&stack);
1445 } else {
1446 /* not has the highest priority, so do not pop from the stack
1447 * as in case of AND and OR */
1448 iff_stack_push(&stack, LYS_IFF_NOT);
1449 }
1450 } else if (!strncmp(&c[i], "and ", 4)) {
1451 /* as for OR - pop from the stack all operators with the same or higher
1452 * priority and store them to the result, then push the AND to the stack */
1453 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_AND) {
1454 op = iff_stack_pop(&stack);
1455 iff_setop(iffeat_expr->expr, op, expr_size--);
1456 }
1457 iff_stack_push(&stack, LYS_IFF_AND);
1458 } else if (!strncmp(&c[i], "or ", 3)) {
1459 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_OR) {
1460 op = iff_stack_pop(&stack);
1461 iff_setop(iffeat_expr->expr, op, expr_size--);
1462 }
1463 iff_stack_push(&stack, LYS_IFF_OR);
1464 } else {
1465 /* feature name, length is j - i */
1466
1467 /* add it to the result */
1468 iff_setop(iffeat_expr->expr, LYS_IFF_F, expr_size--);
1469
1470 /* now get the link to the feature definition. Since it can be
Radek Krejcicbb473e2016-09-16 14:48:32 +02001471 * forward referenced, we have to keep the feature name in auxiliary
1472 * structure passed into unres */
1473 iff_data = malloc(sizeof *iff_data);
1474 iff_data->node = node;
1475 iff_data->fname = lydict_insert(node->module->ctx, &c[i], j - i);
Radek Krejci9de2c042016-10-19 16:53:06 +02001476 iff_data->infeature = infeature;
Radek Krejcicbb473e2016-09-16 14:48:32 +02001477 r = unres_schema_add_node(node->module, unres, &iffeat_expr->features[f_size], UNRES_IFFEAT,
1478 (struct lys_node *)iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001479 f_size--;
1480
1481 if (r == -1) {
Pavol Vican4d084512016-09-29 16:38:12 +02001482 free(iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001483 goto error;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001484 }
1485 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001486 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001487 while (stack.index) {
1488 op = iff_stack_pop(&stack);
1489 iff_setop(iffeat_expr->expr, op, expr_size--);
1490 }
1491
1492 if (++expr_size || ++f_size) {
1493 /* not all expected operators and operands found */
1494 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1495 rc = EXIT_FAILURE;
1496 } else {
1497 rc = EXIT_SUCCESS;
1498 }
1499
1500error:
1501 /* cleanup */
1502 iff_stack_clean(&stack);
1503
1504 return rc;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001505}
1506
1507/**
Michal Vasko3edeaf72016-02-11 13:17:43 +01001508 * @brief Resolve (find) a data node based on a schema-nodeid.
1509 *
1510 * Used for resolving unique statements - so id is expected to be relative and local (without reference to a different
1511 * module).
1512 *
1513 */
1514struct lyd_node *
1515resolve_data_descendant_schema_nodeid(const char *nodeid, struct lyd_node *start)
1516{
1517 char *str, *token, *p;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001518 struct lyd_node *result = NULL, *iter;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001519 const struct lys_node *schema = NULL;
Radek Krejcicc217a62016-04-08 16:58:11 +02001520 int shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001521
1522 assert(nodeid && start);
1523
1524 if (nodeid[0] == '/') {
1525 return NULL;
1526 }
1527
1528 str = p = strdup(nodeid);
1529 if (!str) {
1530 LOGMEM;
1531 return NULL;
1532 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001533
Michal Vasko3edeaf72016-02-11 13:17:43 +01001534 while (p) {
1535 token = p;
1536 p = strchr(p, '/');
1537 if (p) {
1538 *p = '\0';
1539 p++;
1540 }
1541
Radek Krejci5da4eb62016-04-08 14:45:51 +02001542 if (p) {
1543 /* inner node */
Radek Krejcicc217a62016-04-08 16:58:11 +02001544 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema,
Radek Krejcif3c71de2016-04-11 12:45:46 +02001545 LYS_CONTAINER | LYS_CHOICE | LYS_CASE | LYS_LEAF, 0, 0, &schema)
Radek Krejci5da4eb62016-04-08 14:45:51 +02001546 || !schema) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001547 result = NULL;
1548 break;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001549 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001550
Radek Krejci5da4eb62016-04-08 14:45:51 +02001551 if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
1552 continue;
Michal Vaskodcf98e62016-05-05 17:53:53 +02001553 } else if (lys_parent(schema)->nodetype == LYS_CHOICE) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001554 /* shorthand case */
1555 if (!shorthand) {
1556 shorthand = 1;
Michal Vaskodcf98e62016-05-05 17:53:53 +02001557 schema = lys_parent(schema);
Radek Krejcicc217a62016-04-08 16:58:11 +02001558 continue;
1559 } else {
1560 shorthand = 0;
1561 if (schema->nodetype == LYS_LEAF) {
1562 /* should not be here, since we have leaf, which is not a shorthand nor final node */
1563 result = NULL;
1564 break;
1565 }
1566 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001567 }
1568 } else {
1569 /* final node */
Radek Krejcif3c71de2016-04-11 12:45:46 +02001570 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema, LYS_LEAF,
1571 shorthand ? 0 : 1, 0, &schema)
Radek Krejcicc217a62016-04-08 16:58:11 +02001572 || !schema) {
1573 result = NULL;
1574 break;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001575 }
1576 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001577 LY_TREE_FOR(result ? result->child : start, iter) {
1578 if (iter->schema == schema) {
1579 /* move in data tree according to returned schema */
1580 result = iter;
1581 break;
1582 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001583 }
Radek Krejcicc217a62016-04-08 16:58:11 +02001584 if (!iter) {
1585 /* instance not found */
1586 result = NULL;
1587 break;
1588 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001589 }
1590 free(str);
1591
1592 return result;
1593}
1594
Radek Krejcibdf92362016-04-08 14:43:34 +02001595/*
1596 * 0 - ok (done)
1597 * 1 - continue
1598 * 2 - break
1599 * -1 - error
1600 */
1601static int
Radek Krejcicc217a62016-04-08 16:58:11 +02001602schema_nodeid_siblingcheck(const struct lys_node *sibling, int8_t *shorthand, const char *id,
Radek Krejcibdf92362016-04-08 14:43:34 +02001603 const struct lys_module *module, const char *mod_name, int mod_name_len,
Radek Krejci0fa54e92016-09-14 14:01:05 +02001604 int implemented_mod, const struct lys_node **start)
Radek Krejcibdf92362016-04-08 14:43:34 +02001605{
1606 const struct lys_module *prefix_mod;
1607
1608 /* module check */
1609 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Radek Krejcidf46e222016-11-08 11:57:37 +01001610 if (prefix_mod && implemented_mod) {
Radek Krejci2eee5c02016-12-06 19:18:05 +01001611 prefix_mod = lys_implemented_module(prefix_mod);
Radek Krejci0fa54e92016-09-14 14:01:05 +02001612 }
Radek Krejcibdf92362016-04-08 14:43:34 +02001613 if (!prefix_mod) {
1614 return -1;
1615 }
1616 if (prefix_mod != lys_node_module(sibling)) {
1617 return 1;
1618 }
1619
1620 /* check for shorthand cases - then 'start' does not change */
Michal Vaskodcf98e62016-05-05 17:53:53 +02001621 if (lys_parent(sibling) && (lys_parent(sibling)->nodetype == LYS_CHOICE) && (sibling->nodetype != LYS_CASE)) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001622 if (*shorthand != -1) {
1623 *shorthand = *shorthand ? 0 : 1;
1624 }
Radek Krejcibdf92362016-04-08 14:43:34 +02001625 }
1626
1627 /* the result node? */
1628 if (!id[0]) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001629 if (*shorthand == 1) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001630 return 1;
1631 }
1632 return 0;
1633 }
1634
Radek Krejci3a130162016-11-07 16:21:20 +01001635 if (!(*shorthand)) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001636 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02001637 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001638 return -1;
1639 }
1640 *start = sibling->child;
1641 }
1642
1643 return 2;
1644}
1645
Radek Krejcidf46e222016-11-08 11:57:37 +01001646/* start - relative, module - absolute, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1
1647 * implement: 0 - do not change the implemented status of the affected modules, 1 - change implemented status of the affected modules
1648 */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001649int
1650resolve_augment_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_module *module,
Radek Krejcidf46e222016-11-08 11:57:37 +01001651 int implement, const struct lys_node **ret)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001652{
Radek Krejcidf46e222016-11-08 11:57:37 +01001653 const char *name, *mod_name, *mod_name_prev, *id;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001654 const struct lys_node *sibling;
1655 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001656 int8_t shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001657 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcidf46e222016-11-08 11:57:37 +01001658 const struct lys_module *start_mod, *aux_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001659
1660 assert(nodeid && (start || module) && !(start && module) && ret);
1661
1662 id = nodeid;
1663
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001664 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 +01001665 return ((id - nodeid) - r) + 1;
1666 }
1667 id += r;
1668
1669 if ((is_relative && !start) || (!is_relative && !module)) {
1670 return -1;
1671 }
1672
1673 /* descendant-schema-nodeid */
1674 if (is_relative) {
Michal Vasko4c06fd82016-02-17 13:43:38 +01001675 module = start_mod = start->module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001676
1677 /* absolute-schema-nodeid */
1678 } else {
1679 start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Radek Krejcidf46e222016-11-08 11:57:37 +01001680 if (start_mod != lys_main_module(module) && start_mod && !start_mod->implemented) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001681 /* if the submodule augments the mainmodule (or in general a module augments
1682 * itself, we don't want to search for the implemented module but augments
1683 * the module anyway. But when augmenting another module, we need the implemented
1684 * revision of the module if any */
Radek Krejci2eee5c02016-12-06 19:18:05 +01001685 aux_mod = lys_implemented_module(start_mod);
Radek Krejcidf46e222016-11-08 11:57:37 +01001686 if (!aux_mod->implemented && implement) {
1687 /* make the found module implemented */
1688 if (lys_set_implemented(aux_mod)) {
1689 return -1;
1690 }
1691 }
1692 start_mod = aux_mod;
1693 implement++;
Radek Krejci0fa54e92016-09-14 14:01:05 +02001694 }
Michal Vaskoe2905632016-02-11 15:42:24 +01001695 if (!start_mod) {
1696 return -1;
1697 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001698 start = start_mod->data;
1699 }
1700
1701 while (1) {
1702 sibling = NULL;
Radek Krejcidf46e222016-11-08 11:57:37 +01001703 mod_name_prev = mod_name;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001704 while ((sibling = lys_getnext(sibling, lys_parent(start), start_mod,
1705 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
1706 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001707 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001708 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len,
Radek Krejcidf46e222016-11-08 11:57:37 +01001709 implement, &start);
Radek Krejcibdf92362016-04-08 14:43:34 +02001710 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001711 *ret = sibling;
1712 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001713 } else if (r == 1) {
1714 continue;
1715 } else if (r == 2) {
1716 break;
1717 } else {
1718 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001719 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001720 }
1721 }
1722
1723 /* no match */
1724 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001725 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001726 return EXIT_SUCCESS;
1727 }
1728
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001729 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 +01001730 return ((id - nodeid) - r) + 1;
1731 }
1732 id += r;
Radek Krejcidf46e222016-11-08 11:57:37 +01001733
1734 if ((mod_name && mod_name_prev && strncmp(mod_name, mod_name_prev, mod_name_len + 1)) ||
1735 (mod_name != mod_name_prev && (!mod_name || !mod_name_prev))) {
1736 /* we are getting into another module (augment) */
1737 if (implement) {
1738 /* we have to check that also target modules are implemented, if not, we have to change it */
1739 aux_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
1740 if (!aux_mod) {
1741 return -1;
1742 }
1743 if (!aux_mod->implemented) {
Radek Krejci2eee5c02016-12-06 19:18:05 +01001744 aux_mod = lys_implemented_module(aux_mod);
Radek Krejcidf46e222016-11-08 11:57:37 +01001745 if (!aux_mod->implemented) {
1746 /* make the found module implemented */
1747 if (lys_set_implemented(aux_mod)) {
1748 return -1;
1749 }
1750 }
1751 }
1752 } else {
1753 /* we are not implementing the module itself, so the augments outside the module are ignored */
1754 *ret = NULL;
1755 return EXIT_SUCCESS;
1756 }
1757 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001758 }
1759
1760 /* cannot get here */
1761 LOGINT;
1762 return -1;
1763}
1764
Radek Krejcif3c71de2016-04-11 12:45:46 +02001765/* unique, refine,
1766 * >0 - unexpected char on position (ret - 1),
1767 * 0 - ok (but ret can still be NULL),
1768 * -1 - error,
1769 * -2 - violated no_innerlist */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001770int
1771resolve_descendant_schema_nodeid(const char *nodeid, const struct lys_node *start, int ret_nodetype,
Radek Krejcif3c71de2016-04-11 12:45:46 +02001772 int check_shorthand, int no_innerlist, const struct lys_node **ret)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001773{
1774 const char *name, *mod_name, *id;
1775 const struct lys_node *sibling;
1776 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001777 int8_t shorthand = check_shorthand ? 0 : -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001778 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcibdf92362016-04-08 14:43:34 +02001779 const struct lys_module *module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001780
1781 assert(nodeid && start && ret);
1782 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1783
1784 id = nodeid;
1785 module = start->module;
1786
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001787 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 +01001788 return ((id - nodeid) - r) + 1;
1789 }
1790 id += r;
1791
1792 if (!is_relative) {
1793 return -1;
1794 }
1795
1796 while (1) {
1797 sibling = NULL;
1798 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
1799 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE))) {
1800 /* name match */
1801 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001802 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len, 0, &start);
Radek Krejcibdf92362016-04-08 14:43:34 +02001803 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001804 if (!(sibling->nodetype & ret_nodetype)) {
1805 /* wrong node type, too bad */
1806 continue;
1807 }
1808 *ret = sibling;
1809 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001810 } else if (r == 1) {
1811 continue;
1812 } else if (r == 2) {
1813 break;
1814 } else {
1815 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001816 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001817 }
1818 }
1819
1820 /* no match */
1821 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001822 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001823 return EXIT_SUCCESS;
Radek Krejcif3c71de2016-04-11 12:45:46 +02001824 } else if (no_innerlist && sibling->nodetype == LYS_LIST) {
1825 *ret = NULL;
1826 return -2;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001827 }
1828
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001829 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 +01001830 return ((id - nodeid) - r) + 1;
1831 }
1832 id += r;
1833 }
1834
1835 /* cannot get here */
1836 LOGINT;
1837 return -1;
1838}
1839
1840/* choice default */
1841int
1842resolve_choice_default_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node **ret)
1843{
1844 /* cannot actually be a path */
1845 if (strchr(nodeid, '/')) {
1846 return -1;
1847 }
1848
Radek Krejcif3c71de2016-04-11 12:45:46 +02001849 return resolve_descendant_schema_nodeid(nodeid, start, LYS_NO_RPC_NOTIF_NODE, 1, 0, ret);
Michal Vasko3edeaf72016-02-11 13:17:43 +01001850}
1851
1852/* uses, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1853static int
1854resolve_uses_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node_grp **ret)
1855{
1856 const struct lys_module *module;
1857 const char *mod_prefix, *name;
1858 int i, mod_prefix_len, nam_len;
1859
1860 /* parse the identifier, it must be parsed on one call */
1861 if (((i = parse_node_identifier(nodeid, &mod_prefix, &mod_prefix_len, &name, &nam_len)) < 1) || nodeid[i]) {
1862 return -i + 1;
1863 }
1864
1865 module = lys_get_import_module(start->module, mod_prefix, mod_prefix_len, NULL, 0);
1866 if (!module) {
1867 return -1;
1868 }
1869 if (module != start->module) {
1870 start = module->data;
1871 }
1872
1873 *ret = lys_find_grouping_up(name, (struct lys_node *)start);
1874
1875 return EXIT_SUCCESS;
1876}
1877
1878int
1879resolve_absolute_schema_nodeid(const char *nodeid, const struct lys_module *module, int ret_nodetype,
1880 const struct lys_node **ret)
1881{
1882 const char *name, *mod_name, *id;
1883 const struct lys_node *sibling, *start;
1884 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001885 int8_t shorthand = 0;
Radek Krejcibdf92362016-04-08 14:43:34 +02001886 const struct lys_module *abs_start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001887
1888 assert(nodeid && module && ret);
1889 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1890
1891 id = nodeid;
1892 start = module->data;
1893
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001894 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 +01001895 return ((id - nodeid) - r) + 1;
1896 }
1897 id += r;
1898
1899 if (is_relative) {
1900 return -1;
1901 }
1902
1903 abs_start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001904 if (!abs_start_mod) {
1905 return -1;
1906 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001907
1908 while (1) {
1909 sibling = NULL;
1910 while ((sibling = lys_getnext(sibling, lys_parent(start), abs_start_mod, LYS_GETNEXT_WITHCHOICE
1911 | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_WITHGROUPING))) {
1912 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001913 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001914 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len, 0, &start);
Radek Krejcibdf92362016-04-08 14:43:34 +02001915 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001916 if (!(sibling->nodetype & ret_nodetype)) {
1917 /* wrong node type, too bad */
1918 continue;
1919 }
1920 *ret = sibling;
1921 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001922 } else if (r == 1) {
1923 continue;
1924 } else if (r == 2) {
1925 break;
1926 } else {
1927 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001928 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001929 }
1930 }
1931
1932 /* no match */
1933 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001934 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001935 return EXIT_SUCCESS;
1936 }
1937
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001938 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 +01001939 return ((id - nodeid) - r) + 1;
1940 }
1941 id += r;
1942 }
1943
1944 /* cannot get here */
1945 LOGINT;
1946 return -1;
1947}
1948
Michal Vaskoe733d682016-03-14 09:08:27 +01001949static int
Michal Vasko3547c532016-03-14 09:40:50 +01001950resolve_json_schema_list_predicate(const char *predicate, const struct lys_node_list *list, int *parsed)
Michal Vaskoe733d682016-03-14 09:08:27 +01001951{
1952 const char *name;
1953 int nam_len, has_predicate, i;
1954
Michal Vasko7b54f7e2016-05-03 15:07:31 +02001955 if (((i = parse_schema_json_predicate(predicate, &name, &nam_len, NULL, NULL, &has_predicate)) < 1)
1956 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001957 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-i], &predicate[-i]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001958 return -1;
1959 }
1960
1961 predicate += i;
1962 *parsed += i;
1963
1964 for (i = 0; i < list->keys_size; ++i) {
1965 if (!strncmp(list->keys[i]->name, name, nam_len) && !list->keys[i]->name[nam_len]) {
1966 break;
1967 }
1968 }
1969
1970 if (i == list->keys_size) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001971 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskoe733d682016-03-14 09:08:27 +01001972 return -1;
1973 }
1974
1975 /* more predicates? */
1976 if (has_predicate) {
Michal Vasko3547c532016-03-14 09:40:50 +01001977 return resolve_json_schema_list_predicate(predicate, list, parsed);
Michal Vaskoe733d682016-03-14 09:08:27 +01001978 }
1979
1980 return 0;
1981}
1982
Michal Vasko8d26e5c2016-09-08 10:03:49 +02001983/* cannot return LYS_GROUPING, LYS_AUGMENT, LYS_USES, logs directly */
Michal Vaskoe733d682016-03-14 09:08:27 +01001984const struct lys_node *
Michal Vasko8d26e5c2016-09-08 10:03:49 +02001985resolve_json_nodeid(const char *nodeid, struct ly_ctx *ctx, const struct lys_node *start)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001986{
Michal Vasko10728b52016-04-07 14:26:29 +02001987 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001988 const char *name, *mod_name, *id;
Michal Vasko3547c532016-03-14 09:40:50 +01001989 const struct lys_node *sibling;
Radek Krejcibdf92362016-04-08 14:43:34 +02001990 int r, nam_len, mod_name_len, is_relative = -1, has_predicate, shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001991 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vaskoe733d682016-03-14 09:08:27 +01001992 const struct lys_module *prefix_mod, *module, *prev_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001993
Michal Vasko3547c532016-03-14 09:40:50 +01001994 assert(nodeid && (ctx || start));
1995 if (!ctx) {
1996 ctx = start->module->ctx;
1997 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001998
1999 id = nodeid;
2000
Michal Vaskoe733d682016-03-14 09:08:27 +01002001 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 +01002002 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002003 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002004 }
2005 id += r;
2006
2007 if (is_relative) {
Michal Vasko3547c532016-03-14 09:40:50 +01002008 assert(start);
2009 start = start->child;
2010 if (!start) {
2011 /* no descendants, fail for sure */
Michal Vasko10728b52016-04-07 14:26:29 +02002012 str = strndup(nodeid, (name + nam_len) - nodeid);
2013 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
2014 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002015 return NULL;
2016 }
2017 module = start->module;
2018 } else {
2019 if (!mod_name) {
Michal Vasko10728b52016-04-07 14:26:29 +02002020 str = strndup(nodeid, (name + nam_len) - nodeid);
2021 LOGVAL(LYE_PATH_MISSMOD, LY_VLOG_STR, nodeid);
2022 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002023 return NULL;
Michal Vasko971a3ca2016-04-01 13:09:29 +02002024 } else if (mod_name_len > LY_BUF_SIZE - 1) {
2025 LOGINT;
2026 return NULL;
Michal Vasko3547c532016-03-14 09:40:50 +01002027 }
2028
Michal Vasko971a3ca2016-04-01 13:09:29 +02002029 if (ly_buf_used && module_name[0]) {
2030 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2031 }
2032 ly_buf_used++;
2033
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002034 memmove(module_name, mod_name, mod_name_len);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002035 module_name[mod_name_len] = '\0';
2036 module = ly_ctx_get_module(ctx, module_name, NULL);
2037
2038 if (buf_backup) {
2039 /* return previous internal buffer content */
2040 strcpy(module_name, buf_backup);
2041 free(buf_backup);
2042 buf_backup = NULL;
2043 }
2044 ly_buf_used--;
2045
Michal Vasko3547c532016-03-14 09:40:50 +01002046 if (!module) {
Michal Vasko10728b52016-04-07 14:26:29 +02002047 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2048 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2049 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002050 return NULL;
2051 }
2052 start = module->data;
2053
2054 /* now it's as if there was no module name */
2055 mod_name = NULL;
2056 mod_name_len = 0;
Michal Vaskoe733d682016-03-14 09:08:27 +01002057 }
2058
Michal Vaskoe733d682016-03-14 09:08:27 +01002059 prev_mod = module;
2060
Michal Vasko3edeaf72016-02-11 13:17:43 +01002061 while (1) {
2062 sibling = NULL;
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002063 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
2064 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002065 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02002066 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002067 /* module check */
2068 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002069 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko8757e7c2016-03-15 10:41:30 +01002070 LOGINT;
2071 return NULL;
2072 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002073
2074 if (ly_buf_used && module_name[0]) {
2075 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2076 }
2077 ly_buf_used++;
2078
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002079 memmove(module_name, mod_name, mod_name_len);
Michal Vasko8757e7c2016-03-15 10:41:30 +01002080 module_name[mod_name_len] = '\0';
2081 /* will also find an augment module */
2082 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002083
2084 if (buf_backup) {
2085 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002086 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002087 free(buf_backup);
2088 buf_backup = NULL;
2089 }
2090 ly_buf_used--;
2091
Michal Vasko3edeaf72016-02-11 13:17:43 +01002092 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002093 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2094 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2095 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002096 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002097 }
2098 } else {
2099 prefix_mod = prev_mod;
2100 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01002101 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002102 continue;
2103 }
2104
Michal Vaskoe733d682016-03-14 09:08:27 +01002105 /* do we have some predicates on it? */
2106 if (has_predicate) {
2107 r = 0;
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002108 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
2109 if ((r = parse_schema_json_predicate(id, NULL, NULL, NULL, NULL, &has_predicate)) < 1) {
2110 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2111 return NULL;
2112 }
2113 } else if (sibling->nodetype == LYS_LIST) {
2114 if (resolve_json_schema_list_predicate(id, (const struct lys_node_list *)sibling, &r)) {
2115 return NULL;
2116 }
2117 } else {
Michal Vasko43c300e2016-03-22 12:54:27 +01002118 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vaskoe733d682016-03-14 09:08:27 +01002119 return NULL;
Michal Vaskoe733d682016-03-14 09:08:27 +01002120 }
2121 id += r;
2122 }
2123
Radek Krejcibdf92362016-04-08 14:43:34 +02002124 /* check for shorthand cases - then 'start' does not change */
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002125 if (lys_parent(sibling) && (lys_parent(sibling)->nodetype == LYS_CHOICE) && (sibling->nodetype != LYS_CASE)) {
Radek Krejcibdf92362016-04-08 14:43:34 +02002126 shorthand = ~shorthand;
2127 }
2128
Michal Vasko3edeaf72016-02-11 13:17:43 +01002129 /* the result node? */
2130 if (!id[0]) {
Radek Krejcibdf92362016-04-08 14:43:34 +02002131 if (shorthand) {
2132 /* wrong path for shorthand */
Michal Vasko025e0452016-05-17 16:14:20 +02002133 str = strndup(nodeid, (name + nam_len) - nodeid);
2134 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
Michal Vasko3c0f9f52016-05-17 16:38:10 +02002135 LOGVAL(LYE_SPEC, LY_VLOG_STR, str, "Schema shorthand case path must include the virtual case statement.");
Radek Krejci9a5fccc2016-05-18 15:44:58 +02002136 free(str);
Michal Vasko025e0452016-05-17 16:14:20 +02002137 return NULL;
Radek Krejcibdf92362016-04-08 14:43:34 +02002138 }
Michal Vaskoe733d682016-03-14 09:08:27 +01002139 return sibling;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002140 }
2141
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002142 if (!shorthand) {
Michal Vasko7dc71d02016-03-15 10:42:28 +01002143 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002144 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002145 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko7dc71d02016-03-15 10:42:28 +01002146 return NULL;
2147 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01002148 start = sibling->child;
2149 }
2150
2151 /* update prev mod */
2152 prev_mod = start->module;
2153 break;
2154 }
2155 }
2156
2157 /* no match */
2158 if (!sibling) {
Michal Vasko10728b52016-04-07 14:26:29 +02002159 str = strndup(nodeid, (name + nam_len) - nodeid);
2160 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
2161 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002162 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002163 }
2164
Michal Vaskoe733d682016-03-14 09:08:27 +01002165 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 +01002166 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002167 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002168 }
2169 id += r;
2170 }
2171
2172 /* cannot get here */
2173 LOGINT;
Michal Vaskoe733d682016-03-14 09:08:27 +01002174 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002175}
2176
Michal Vasko22448d32016-03-16 13:17:29 +01002177static int
2178resolve_partial_json_data_list_predicate(const char *predicate, const char *node_name, struct lyd_node *node, int *parsed)
2179{
Michal Vasko9ba34de2016-12-07 12:21:19 +01002180 const char *name, *value, *key_val;
Michal Vasko22448d32016-03-16 13:17:29 +01002181 int nam_len, val_len, has_predicate = 1, r;
2182 uint16_t i;
Michal Vaskof29903d2016-04-18 13:13:10 +02002183 struct lyd_node_leaf_list *key;
Michal Vasko22448d32016-03-16 13:17:29 +01002184
Radek Krejci61a86c62016-03-24 11:06:44 +01002185 assert(node);
Michal Vasko22448d32016-03-16 13:17:29 +01002186 assert(node->schema->nodetype == LYS_LIST);
2187
Michal Vaskof29903d2016-04-18 13:13:10 +02002188 key = (struct lyd_node_leaf_list *)node->child;
2189 for (i = 0; i < ((struct lys_node_list *)node->schema)->keys_size; ++i) {
2190 if (!key) {
2191 /* invalid data */
2192 LOGINT;
2193 return -1;
2194 }
Michal Vasko22448d32016-03-16 13:17:29 +01002195
Michal Vasko22448d32016-03-16 13:17:29 +01002196 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002197 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, node_name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002198 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002199 }
2200
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002201 if (((r = parse_schema_json_predicate(predicate, &name, &nam_len, &value, &val_len, &has_predicate)) < 1)
2202 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002203 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
Michal Vaskof29903d2016-04-18 13:13:10 +02002204 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002205 }
2206
2207 predicate += r;
2208 *parsed += r;
2209
Michal Vaskof29903d2016-04-18 13:13:10 +02002210 if (strncmp(key->schema->name, name, nam_len) || key->schema->name[nam_len]) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002211 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002212 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002213 }
2214
Michal Vasko9ba34de2016-12-07 12:21:19 +01002215 /* make value canonical */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01002216 if ((key->value_type & LY_TYPE_IDENT)
Michal Vasko6a938d62016-12-21 09:21:30 +01002217 && !strncmp(key->value_str, lyd_node_module(node)->name, strlen(lyd_node_module(node)->name))
2218 && (key->value_str[strlen(lyd_node_module(node)->name)] == ':')) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002219 key_val = key->value_str + strlen(lyd_node_module(node)->name) + 1;
2220 } else {
2221 key_val = key->value_str;
2222 }
2223
Michal Vasko22448d32016-03-16 13:17:29 +01002224 /* value does not match */
Michal Vasko9ba34de2016-12-07 12:21:19 +01002225 if (strncmp(key_val, value, val_len) || key_val[val_len]) {
Michal Vasko22448d32016-03-16 13:17:29 +01002226 return 1;
2227 }
Michal Vaskof29903d2016-04-18 13:13:10 +02002228
2229 key = (struct lyd_node_leaf_list *)key->next;
Michal Vasko22448d32016-03-16 13:17:29 +01002230 }
2231
2232 if (has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002233 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko22448d32016-03-16 13:17:29 +01002234 return -1;
2235 }
2236
2237 return 0;
2238}
2239
Radek Krejci45826012016-08-24 15:07:57 +02002240/**
2241 * @brief get the closest parent of the node (or the node itself) identified by the nodeid (path)
2242 *
2243 * @param[in] nodeid Node data path to find
2244 * @param[in] llist_value If the \p nodeid identifies leaf-list, this is expected value of the leaf-list instance.
2245 * @param[in] options Bitmask of options flags, see @ref pathoptions.
2246 * @param[out] parsed Number of characters processed in \p id
2247 * @return The closes parent (or the node itself) from the path
2248 */
Michal Vasko22448d32016-03-16 13:17:29 +01002249struct lyd_node *
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002250resolve_partial_json_data_nodeid(const char *nodeid, const char *llist_value, struct lyd_node *start, int options,
2251 int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002252{
Michal Vasko10728b52016-04-07 14:26:29 +02002253 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko9ba34de2016-12-07 12:21:19 +01002254 const char *id, *mod_name, *name, *pred_name, *data_val;
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002255 int r, ret, mod_name_len, nam_len, is_relative = -1;
Michal Vasko9ba34de2016-12-07 12:21:19 +01002256 int has_predicate, last_parsed, llval_len, pred_name_len, last_has_pred;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002257 struct lyd_node *sibling, *last_match = NULL;
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002258 struct lyd_node_leaf_list *llist;
Michal Vasko22448d32016-03-16 13:17:29 +01002259 const struct lys_module *prefix_mod, *prev_mod;
2260 struct ly_ctx *ctx;
2261
2262 assert(nodeid && start && parsed);
2263
2264 ctx = start->schema->module->ctx;
2265 id = nodeid;
2266
2267 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 +01002268 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002269 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002270 return NULL;
2271 }
2272 id += r;
2273 /* add it to parsed only after the data node was actually found */
2274 last_parsed = r;
2275
2276 if (is_relative) {
Michal Vasko1adc7242016-11-16 11:05:28 +01002277 prev_mod = lyd_node_module(start);
Michal Vasko22448d32016-03-16 13:17:29 +01002278 start = start->child;
2279 } else {
2280 for (; start->parent; start = start->parent);
Michal Vasko1adc7242016-11-16 11:05:28 +01002281 prev_mod = lyd_node_module(start);
Michal Vasko22448d32016-03-16 13:17:29 +01002282 }
2283
2284 while (1) {
2285 LY_TREE_FOR(start, sibling) {
Michal Vasko945b96b2016-10-18 11:49:12 +02002286 /* RPC/action data check, return simply invalid argument, because the data tree is invalid */
Michal Vasko2411b942016-03-23 13:50:03 +01002287 if (lys_parent(sibling->schema)) {
2288 if (options & LYD_PATH_OPT_OUTPUT) {
2289 if (lys_parent(sibling->schema)->nodetype == LYS_INPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002290 LOGERR(LY_EINVAL, "Provided data tree includes some RPC input nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002291 *parsed = -1;
2292 return NULL;
2293 }
2294 } else {
2295 if (lys_parent(sibling->schema)->nodetype == LYS_OUTPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002296 LOGERR(LY_EINVAL, "Provided data tree includes some RPC output nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002297 *parsed = -1;
2298 return NULL;
2299 }
2300 }
2301 }
2302
Michal Vasko22448d32016-03-16 13:17:29 +01002303 /* name match */
2304 if (!strncmp(name, sibling->schema->name, nam_len) && !sibling->schema->name[nam_len]) {
2305
2306 /* module check */
2307 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002308 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko22448d32016-03-16 13:17:29 +01002309 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002310 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002311 return NULL;
2312 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002313
2314 if (ly_buf_used && module_name[0]) {
2315 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2316 }
2317 ly_buf_used++;
2318
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002319 memmove(module_name, mod_name, mod_name_len);
Michal Vasko22448d32016-03-16 13:17:29 +01002320 module_name[mod_name_len] = '\0';
2321 /* will also find an augment module */
2322 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002323
2324 if (buf_backup) {
2325 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002326 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002327 free(buf_backup);
2328 buf_backup = NULL;
2329 }
2330 ly_buf_used--;
2331
Michal Vasko22448d32016-03-16 13:17:29 +01002332 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002333 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2334 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2335 free(str);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002336 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002337 return NULL;
2338 }
2339 } else {
2340 prefix_mod = prev_mod;
2341 }
Michal Vasko1adc7242016-11-16 11:05:28 +01002342 if (prefix_mod != lyd_node_module(sibling)) {
Michal Vasko22448d32016-03-16 13:17:29 +01002343 continue;
2344 }
2345
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002346 /* leaf-list, did we find it with the correct value or not? */
Michal Vasko22448d32016-03-16 13:17:29 +01002347 if (sibling->schema->nodetype == LYS_LEAFLIST) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002348 llist = (struct lyd_node_leaf_list *)sibling;
2349
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002350 last_has_pred = 0;
Michal Vaskof0a50972016-10-19 11:33:55 +02002351 if (has_predicate) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002352 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 +02002353 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2354 *parsed = -1;
2355 return NULL;
2356 }
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002357 if ((pred_name[0] != '.') || (pred_name_len != 1)) {
2358 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[1], id + 1);
2359 *parsed = -1;
2360 return NULL;
2361 }
Michal Vaskof0a50972016-10-19 11:33:55 +02002362 } else {
2363 r = 0;
2364 if (llist_value) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002365 llval_len = strlen(llist_value);
Michal Vaskof0a50972016-10-19 11:33:55 +02002366 }
2367 }
2368
Michal Vasko9ba34de2016-12-07 12:21:19 +01002369 /* make value canonical */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01002370 if ((llist->value_type & LY_TYPE_IDENT)
Michal Vasko6a938d62016-12-21 09:21:30 +01002371 && !strncmp(llist->value_str, lyd_node_module(sibling)->name, strlen(lyd_node_module(sibling)->name))
2372 && (llist->value_str[strlen(lyd_node_module(sibling)->name)] == ':')) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002373 data_val = llist->value_str + strlen(lyd_node_module(sibling)->name) + 1;
2374 } else {
2375 data_val = llist->value_str;
2376 }
2377
2378 if ((!llist_value && data_val && data_val[0])
2379 || (llist_value && (strncmp(llist_value, data_val, llval_len) || data_val[llval_len]))) {
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002380 continue;
2381 }
Michal Vasko9ba34de2016-12-07 12:21:19 +01002382
Michal Vaskof0a50972016-10-19 11:33:55 +02002383 id += r;
2384 last_parsed += r;
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002385 has_predicate = last_has_pred;
Michal Vaskof0a50972016-10-19 11:33:55 +02002386
Radek Krejci45826012016-08-24 15:07:57 +02002387 } else if (sibling->schema->nodetype == LYS_LIST) {
2388 /* list, we need predicates'n'stuff then */
Michal Vasko22448d32016-03-16 13:17:29 +01002389 r = 0;
2390 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002391 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002392 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002393 return NULL;
2394 }
2395 ret = resolve_partial_json_data_list_predicate(id, name, sibling, &r);
2396 if (ret == -1) {
Michal Vasko238bd2f2016-03-23 09:39:01 +01002397 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002398 return NULL;
2399 } else if (ret == 1) {
2400 /* this list instance does not match */
2401 continue;
2402 }
2403 id += r;
2404 last_parsed += r;
2405 }
2406
2407 *parsed += last_parsed;
2408
2409 /* the result node? */
2410 if (!id[0]) {
2411 return sibling;
2412 }
2413
2414 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002415 if (sibling->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002416 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002417 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002418 return NULL;
2419 }
Michal Vaskoc6c52cf2016-03-29 11:53:04 +02002420 last_match = sibling;
Michal Vaskofc11b682016-11-18 09:52:41 +01002421 prev_mod = lyd_node_module(sibling);
Michal Vasko22448d32016-03-16 13:17:29 +01002422 start = sibling->child;
Michal Vasko22448d32016-03-16 13:17:29 +01002423 break;
2424 }
2425 }
2426
2427 /* no match, return last match */
2428 if (!sibling) {
2429 return last_match;
2430 }
2431
2432 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 +01002433 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002434 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002435 return NULL;
2436 }
2437 id += r;
2438 last_parsed = r;
2439 }
2440
2441 /* cannot get here */
2442 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002443 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002444 return NULL;
2445}
2446
Michal Vasko3edeaf72016-02-11 13:17:43 +01002447/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02002448 * @brief Resolves length or range intervals. Does not log.
Michal Vaskoaeb51802016-04-11 10:58:47 +02002449 * Syntax is assumed to be correct, *ret MUST be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002450 *
Michal Vaskoaeb51802016-04-11 10:58:47 +02002451 * @param[in] str_restr Restriction as a string.
2452 * @param[in] type Type of the restriction.
2453 * @param[out] ret Final interval structure that starts with
2454 * the interval of the initial type, continues with intervals
2455 * of any superior types derived from the initial one, and
2456 * finishes with intervals from our \p type.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002457 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002458 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002459 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002460int
Michal Vaskoaeb51802016-04-11 10:58:47 +02002461resolve_len_ran_interval(const char *str_restr, struct lys_type *type, struct len_ran_intv **ret)
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002462{
2463 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002464 int kind;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002465 int64_t local_smin, local_smax, local_fmin, local_fmax;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002466 uint64_t local_umin, local_umax;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002467 uint8_t local_fdig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002468 const char *seg_ptr, *ptr;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002469 struct len_ran_intv *local_intv = NULL, *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002470
2471 switch (type->base) {
2472 case LY_TYPE_BINARY:
2473 kind = 0;
2474 local_umin = 0;
2475 local_umax = 18446744073709551615UL;
2476
2477 if (!str_restr && type->info.binary.length) {
2478 str_restr = type->info.binary.length->expr;
2479 }
2480 break;
2481 case LY_TYPE_DEC64:
2482 kind = 2;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002483 local_fmin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2484 local_fmax = __INT64_C(9223372036854775807);
2485 local_fdig = type->info.dec64.dig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002486
2487 if (!str_restr && type->info.dec64.range) {
2488 str_restr = type->info.dec64.range->expr;
2489 }
2490 break;
2491 case LY_TYPE_INT8:
2492 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002493 local_smin = __INT64_C(-128);
2494 local_smax = __INT64_C(127);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002495
2496 if (!str_restr && type->info.num.range) {
2497 str_restr = type->info.num.range->expr;
2498 }
2499 break;
2500 case LY_TYPE_INT16:
2501 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002502 local_smin = __INT64_C(-32768);
2503 local_smax = __INT64_C(32767);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002504
2505 if (!str_restr && type->info.num.range) {
2506 str_restr = type->info.num.range->expr;
2507 }
2508 break;
2509 case LY_TYPE_INT32:
2510 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002511 local_smin = __INT64_C(-2147483648);
2512 local_smax = __INT64_C(2147483647);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002513
2514 if (!str_restr && type->info.num.range) {
2515 str_restr = type->info.num.range->expr;
2516 }
2517 break;
2518 case LY_TYPE_INT64:
2519 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002520 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2521 local_smax = __INT64_C(9223372036854775807);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002522
2523 if (!str_restr && type->info.num.range) {
2524 str_restr = type->info.num.range->expr;
2525 }
2526 break;
2527 case LY_TYPE_UINT8:
2528 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002529 local_umin = __UINT64_C(0);
2530 local_umax = __UINT64_C(255);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002531
2532 if (!str_restr && type->info.num.range) {
2533 str_restr = type->info.num.range->expr;
2534 }
2535 break;
2536 case LY_TYPE_UINT16:
2537 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002538 local_umin = __UINT64_C(0);
2539 local_umax = __UINT64_C(65535);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002540
2541 if (!str_restr && type->info.num.range) {
2542 str_restr = type->info.num.range->expr;
2543 }
2544 break;
2545 case LY_TYPE_UINT32:
2546 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002547 local_umin = __UINT64_C(0);
2548 local_umax = __UINT64_C(4294967295);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002549
2550 if (!str_restr && type->info.num.range) {
2551 str_restr = type->info.num.range->expr;
2552 }
2553 break;
2554 case LY_TYPE_UINT64:
2555 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002556 local_umin = __UINT64_C(0);
2557 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002558
2559 if (!str_restr && type->info.num.range) {
2560 str_restr = type->info.num.range->expr;
2561 }
2562 break;
2563 case LY_TYPE_STRING:
2564 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002565 local_umin = __UINT64_C(0);
2566 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002567
2568 if (!str_restr && type->info.str.length) {
2569 str_restr = type->info.str.length->expr;
2570 }
2571 break;
2572 default:
2573 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002574 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002575 }
2576
2577 /* process superior types */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002578 if (type->der) {
2579 if (resolve_len_ran_interval(NULL, &type->der->type, &intv)) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002580 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002581 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02002582 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002583 assert(!intv || (intv->kind == kind));
2584 }
2585
2586 if (!str_restr) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002587 /* we do not have any restriction, return superior ones */
2588 *ret = intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002589 return EXIT_SUCCESS;
2590 }
2591
2592 /* adjust local min and max */
2593 if (intv) {
2594 tmp_intv = intv;
2595
2596 if (kind == 0) {
2597 local_umin = tmp_intv->value.uval.min;
2598 } else if (kind == 1) {
2599 local_smin = tmp_intv->value.sval.min;
2600 } else if (kind == 2) {
2601 local_fmin = tmp_intv->value.fval.min;
2602 }
2603
2604 while (tmp_intv->next) {
2605 tmp_intv = tmp_intv->next;
2606 }
2607
2608 if (kind == 0) {
2609 local_umax = tmp_intv->value.uval.max;
2610 } else if (kind == 1) {
2611 local_smax = tmp_intv->value.sval.max;
2612 } else if (kind == 2) {
2613 local_fmax = tmp_intv->value.fval.max;
2614 }
2615 }
2616
2617 /* finally parse our restriction */
2618 seg_ptr = str_restr;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002619 tmp_intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002620 while (1) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002621 if (!tmp_local_intv) {
2622 assert(!local_intv);
2623 local_intv = malloc(sizeof *local_intv);
2624 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002625 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002626 tmp_local_intv->next = malloc(sizeof *tmp_local_intv);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002627 tmp_local_intv = tmp_local_intv->next;
2628 }
Michal Vasko253035f2015-12-17 16:58:13 +01002629 if (!tmp_local_intv) {
2630 LOGMEM;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002631 goto error;
Michal Vasko253035f2015-12-17 16:58:13 +01002632 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002633
2634 tmp_local_intv->kind = kind;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002635 tmp_local_intv->type = type;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002636 tmp_local_intv->next = NULL;
2637
2638 /* min */
2639 ptr = seg_ptr;
2640 while (isspace(ptr[0])) {
2641 ++ptr;
2642 }
2643 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2644 if (kind == 0) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002645 tmp_local_intv->value.uval.min = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002646 } else if (kind == 1) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002647 tmp_local_intv->value.sval.min = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002648 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002649 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.min)) {
2650 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2651 goto error;
2652 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002653 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002654 } else if (!strncmp(ptr, "min", 3)) {
2655 if (kind == 0) {
2656 tmp_local_intv->value.uval.min = local_umin;
2657 } else if (kind == 1) {
2658 tmp_local_intv->value.sval.min = local_smin;
2659 } else if (kind == 2) {
2660 tmp_local_intv->value.fval.min = local_fmin;
2661 }
2662
2663 ptr += 3;
2664 } else if (!strncmp(ptr, "max", 3)) {
2665 if (kind == 0) {
2666 tmp_local_intv->value.uval.min = local_umax;
2667 } else if (kind == 1) {
2668 tmp_local_intv->value.sval.min = local_smax;
2669 } else if (kind == 2) {
2670 tmp_local_intv->value.fval.min = local_fmax;
2671 }
2672
2673 ptr += 3;
2674 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002675 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002676 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002677 }
2678
2679 while (isspace(ptr[0])) {
2680 ptr++;
2681 }
2682
2683 /* no interval or interval */
2684 if ((ptr[0] == '|') || !ptr[0]) {
2685 if (kind == 0) {
2686 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
2687 } else if (kind == 1) {
2688 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
2689 } else if (kind == 2) {
2690 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
2691 }
2692 } else if (!strncmp(ptr, "..", 2)) {
2693 /* skip ".." */
2694 ptr += 2;
2695 while (isspace(ptr[0])) {
2696 ++ptr;
2697 }
2698
2699 /* max */
2700 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2701 if (kind == 0) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002702 tmp_local_intv->value.uval.max = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002703 } else if (kind == 1) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002704 tmp_local_intv->value.sval.max = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002705 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002706 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.max)) {
2707 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2708 goto error;
2709 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002710 }
2711 } else if (!strncmp(ptr, "max", 3)) {
2712 if (kind == 0) {
2713 tmp_local_intv->value.uval.max = local_umax;
2714 } else if (kind == 1) {
2715 tmp_local_intv->value.sval.max = local_smax;
2716 } else if (kind == 2) {
2717 tmp_local_intv->value.fval.max = local_fmax;
2718 }
2719 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002720 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002721 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002722 }
2723 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002724 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002725 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002726 }
2727
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002728 /* check min and max in correct order*/
2729 if (kind == 0) {
2730 /* current segment */
2731 if (tmp_local_intv->value.uval.min > tmp_local_intv->value.uval.max) {
2732 goto error;
2733 }
2734 if (tmp_local_intv->value.uval.min < local_umin || tmp_local_intv->value.uval.max > local_umax) {
2735 goto error;
2736 }
2737 /* segments sholud be ascending order */
Pavol Vican69f62c92016-08-30 09:06:25 +02002738 if (tmp_intv && (tmp_intv->value.uval.max >= tmp_local_intv->value.uval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002739 goto error;
2740 }
2741 } else if (kind == 1) {
2742 if (tmp_local_intv->value.sval.min > tmp_local_intv->value.sval.max) {
2743 goto error;
2744 }
2745 if (tmp_local_intv->value.sval.min < local_smin || tmp_local_intv->value.sval.max > local_smax) {
2746 goto error;
2747 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002748 if (tmp_intv && (tmp_intv->value.sval.max >= tmp_local_intv->value.sval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002749 goto error;
2750 }
2751 } else if (kind == 2) {
2752 if (tmp_local_intv->value.fval.min > tmp_local_intv->value.fval.max) {
2753 goto error;
2754 }
2755 if (tmp_local_intv->value.fval.min < local_fmin || tmp_local_intv->value.fval.max > local_fmax) {
2756 goto error;
2757 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002758 if (tmp_intv && (tmp_intv->value.fval.max >= tmp_local_intv->value.fval.min)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002759 /* fraction-digits value is always the same (it cannot be changed in derived types) */
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002760 goto error;
2761 }
2762 }
2763
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002764 /* next segment (next OR) */
2765 seg_ptr = strchr(seg_ptr, '|');
2766 if (!seg_ptr) {
2767 break;
2768 }
2769 seg_ptr++;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002770 tmp_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002771 }
2772
2773 /* check local restrictions against superior ones */
2774 if (intv) {
2775 tmp_intv = intv;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002776 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002777
2778 while (tmp_local_intv && tmp_intv) {
2779 /* reuse local variables */
2780 if (kind == 0) {
2781 local_umin = tmp_local_intv->value.uval.min;
2782 local_umax = tmp_local_intv->value.uval.max;
2783
2784 /* it must be in this interval */
2785 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
2786 /* this interval is covered, next one */
2787 if (local_umax <= tmp_intv->value.uval.max) {
2788 tmp_local_intv = tmp_local_intv->next;
2789 continue;
2790 /* ascending order of restrictions -> fail */
2791 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002792 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002793 }
2794 }
2795 } else if (kind == 1) {
2796 local_smin = tmp_local_intv->value.sval.min;
2797 local_smax = tmp_local_intv->value.sval.max;
2798
2799 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
2800 if (local_smax <= tmp_intv->value.sval.max) {
2801 tmp_local_intv = tmp_local_intv->next;
2802 continue;
2803 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002804 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002805 }
2806 }
2807 } else if (kind == 2) {
2808 local_fmin = tmp_local_intv->value.fval.min;
2809 local_fmax = tmp_local_intv->value.fval.max;
2810
Michal Vasko4d1f0482016-09-19 14:35:06 +02002811 if ((dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.min, local_fdig) > -1)
Pavol Vican3c8ee2b2016-09-29 13:18:13 +02002812 && (dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002813 if (dec64cmp(local_fmax, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002814 tmp_local_intv = tmp_local_intv->next;
2815 continue;
2816 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002817 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002818 }
2819 }
2820 }
2821
2822 tmp_intv = tmp_intv->next;
2823 }
2824
2825 /* some interval left uncovered -> fail */
2826 if (tmp_local_intv) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002827 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002828 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002829 }
2830
Michal Vaskoaeb51802016-04-11 10:58:47 +02002831 /* append the local intervals to all the intervals of the superior types, return it all */
2832 if (intv) {
2833 for (tmp_intv = intv; tmp_intv->next; tmp_intv = tmp_intv->next);
2834 tmp_intv->next = local_intv;
2835 } else {
2836 intv = local_intv;
2837 }
2838 *ret = intv;
2839
2840 return EXIT_SUCCESS;
2841
2842error:
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002843 while (intv) {
2844 tmp_intv = intv->next;
2845 free(intv);
2846 intv = tmp_intv;
2847 }
Michal Vaskoaeb51802016-04-11 10:58:47 +02002848 while (local_intv) {
2849 tmp_local_intv = local_intv->next;
2850 free(local_intv);
2851 local_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002852 }
2853
Michal Vaskoaeb51802016-04-11 10:58:47 +02002854 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002855}
2856
Michal Vasko730dfdf2015-08-11 14:48:05 +02002857/**
Michal Vasko01c6fd22016-05-20 11:43:05 +02002858 * @brief Resolve a typedef, return only resolved typedefs if derived. If leafref, it must be
2859 * resolved for this function to return it. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002860 *
2861 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02002862 * @param[in] mod_name Typedef name module name.
2863 * @param[in] module Main module.
2864 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002865 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002866 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002867 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002868 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002869int
Michal Vasko1e62a092015-12-01 12:27:20 +01002870resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
2871 const struct lys_node *parent, struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002872{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002873 int i, j;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002874 struct lys_tpdf *tpdf, *match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002875 int tpdf_size;
2876
Michal Vasko1dca6882015-10-22 14:29:42 +02002877 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002878 /* no prefix, try built-in types */
2879 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
2880 if (!strcmp(ly_types[i].def->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002881 if (ret) {
2882 *ret = ly_types[i].def;
2883 }
2884 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002885 }
2886 }
2887 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02002888 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002889 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02002890 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002891 }
2892 }
2893
Michal Vasko1dca6882015-10-22 14:29:42 +02002894 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002895 /* search in local typedefs */
2896 while (parent) {
2897 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02002898 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02002899 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
2900 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002901 break;
2902
Radek Krejci76512572015-08-04 09:47:08 +02002903 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02002904 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
2905 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002906 break;
2907
Radek Krejci76512572015-08-04 09:47:08 +02002908 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02002909 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
2910 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002911 break;
2912
Radek Krejci76512572015-08-04 09:47:08 +02002913 case LYS_RPC:
Michal Vasko44fb6382016-06-29 11:12:27 +02002914 case LYS_ACTION:
2915 tpdf_size = ((struct lys_node_rpc_action *)parent)->tpdf_size;
2916 tpdf = ((struct lys_node_rpc_action *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002917 break;
2918
Radek Krejci76512572015-08-04 09:47:08 +02002919 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02002920 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
2921 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002922 break;
2923
Radek Krejci76512572015-08-04 09:47:08 +02002924 case LYS_INPUT:
2925 case LYS_OUTPUT:
Michal Vasko44fb6382016-06-29 11:12:27 +02002926 tpdf_size = ((struct lys_node_inout *)parent)->tpdf_size;
2927 tpdf = ((struct lys_node_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002928 break;
2929
2930 default:
Michal Vaskodcf98e62016-05-05 17:53:53 +02002931 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002932 continue;
2933 }
2934
2935 for (i = 0; i < tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002936 if (!strcmp(tpdf[i].name, name) && tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002937 match = &tpdf[i];
2938 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002939 }
2940 }
2941
Michal Vaskodcf98e62016-05-05 17:53:53 +02002942 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002943 }
Radek Krejcic071c542016-01-27 14:57:51 +01002944 } else {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002945 /* get module where to search */
Michal Vaskob6729c62015-10-21 12:09:47 +02002946 module = lys_get_import_module(module, NULL, 0, mod_name, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02002947 if (!module) {
2948 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002949 }
2950 }
2951
2952 /* search in top level typedefs */
2953 for (i = 0; i < module->tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002954 if (!strcmp(module->tpdf[i].name, name) && module->tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002955 match = &module->tpdf[i];
2956 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002957 }
2958 }
2959
2960 /* search in submodules */
Radek Krejcic071c542016-01-27 14:57:51 +01002961 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002962 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002963 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 +02002964 match = &module->inc[i].submodule->tpdf[j];
2965 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002966 }
2967 }
2968 }
2969
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002970 return EXIT_FAILURE;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002971
2972check_leafref:
2973 if (ret) {
2974 *ret = match;
2975 }
2976 if (match->type.base == LY_TYPE_LEAFREF) {
2977 while (!match->type.info.lref.path) {
2978 match = match->type.der;
2979 assert(match);
2980 }
Michal Vasko01c6fd22016-05-20 11:43:05 +02002981 }
2982 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002983}
2984
Michal Vasko1dca6882015-10-22 14:29:42 +02002985/**
2986 * @brief Check the default \p value of the \p type. Logs directly.
2987 *
2988 * @param[in] type Type definition to use.
2989 * @param[in] value Default value to check.
Michal Vasko56826402016-03-02 11:11:37 +01002990 * @param[in] module Type module.
Michal Vasko1dca6882015-10-22 14:29:42 +02002991 *
2992 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
2993 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002994static int
Radek Krejci51673202016-11-01 17:00:32 +01002995check_default(struct lys_type *type, const char **value, struct lys_module *module)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002996{
Radek Krejcibad2f172016-08-02 11:04:15 +02002997 struct lys_tpdf *base_tpdf = NULL;
Michal Vasko1dca6882015-10-22 14:29:42 +02002998 struct lyd_node_leaf_list node;
Radek Krejci51673202016-11-01 17:00:32 +01002999 const char *dflt = NULL;
Radek Krejci37b756f2016-01-18 10:15:03 +01003000 int ret = EXIT_SUCCESS;
Michal Vasko1dca6882015-10-22 14:29:42 +02003001
Radek Krejci51673202016-11-01 17:00:32 +01003002 assert(value);
3003
Radek Krejcic13db382016-08-16 10:52:42 +02003004 if (type->base <= LY_TYPE_DER) {
Michal Vasko478c4652016-07-21 12:55:01 +02003005 /* the type was not resolved yet, nothing to do for now */
3006 return EXIT_FAILURE;
3007 }
3008
Radek Krejci51673202016-11-01 17:00:32 +01003009 dflt = *value;
3010 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003011 /* we do not have a new default value, so is there any to check even, in some base type? */
3012 for (base_tpdf = type->der; base_tpdf->type.der; base_tpdf = base_tpdf->type.der) {
3013 if (base_tpdf->dflt) {
Radek Krejci51673202016-11-01 17:00:32 +01003014 dflt = base_tpdf->dflt;
Michal Vasko478c4652016-07-21 12:55:01 +02003015 break;
3016 }
3017 }
3018
Radek Krejci51673202016-11-01 17:00:32 +01003019 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003020 /* no default value, nothing to check, all is well */
3021 return EXIT_SUCCESS;
3022 }
3023
3024 /* 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)? */
3025 switch (type->base) {
Michal Vasko478c4652016-07-21 12:55:01 +02003026 case LY_TYPE_IDENT:
3027 case LY_TYPE_INST:
3028 case LY_TYPE_LEAFREF:
3029 case LY_TYPE_BOOL:
3030 case LY_TYPE_EMPTY:
3031 /* these have no restrictions, so we would do the exact same work as the unres in the base typedef */
3032 return EXIT_SUCCESS;
Radek Krejcibad2f172016-08-02 11:04:15 +02003033 case LY_TYPE_BITS:
3034 /* the default value must match the restricted list of values, if the type was restricted */
3035 if (type->info.bits.count) {
3036 break;
3037 }
3038 return EXIT_SUCCESS;
3039 case LY_TYPE_ENUM:
3040 /* the default value must match the restricted list of values, if the type was restricted */
3041 if (type->info.enums.count) {
3042 break;
3043 }
3044 return EXIT_SUCCESS;
Michal Vasko478c4652016-07-21 12:55:01 +02003045 case LY_TYPE_DEC64:
3046 if (type->info.dec64.range) {
3047 break;
3048 }
3049 return EXIT_SUCCESS;
3050 case LY_TYPE_BINARY:
3051 if (type->info.binary.length) {
3052 break;
3053 }
3054 return EXIT_SUCCESS;
3055 case LY_TYPE_INT8:
3056 case LY_TYPE_INT16:
3057 case LY_TYPE_INT32:
3058 case LY_TYPE_INT64:
3059 case LY_TYPE_UINT8:
3060 case LY_TYPE_UINT16:
3061 case LY_TYPE_UINT32:
3062 case LY_TYPE_UINT64:
3063 if (type->info.num.range) {
3064 break;
3065 }
3066 return EXIT_SUCCESS;
3067 case LY_TYPE_STRING:
3068 if (type->info.str.length || type->info.str.patterns) {
3069 break;
3070 }
3071 return EXIT_SUCCESS;
3072 case LY_TYPE_UNION:
3073 /* way too much trouble learning whether we need to check the default again, so just do it */
3074 break;
3075 default:
3076 LOGINT;
3077 return -1;
3078 }
Radek Krejci55a161c2016-09-05 17:13:25 +02003079 } else if (type->base == LY_TYPE_EMPTY) {
3080 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "default", type->parent->name);
3081 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"empty\" data type cannot have a default value.");
3082 return -1;
Michal Vasko478c4652016-07-21 12:55:01 +02003083 }
3084
Michal Vasko1dca6882015-10-22 14:29:42 +02003085 /* dummy leaf */
Radek Krejci4fe36bd2016-03-17 16:47:16 +01003086 memset(&node, 0, sizeof node);
Radek Krejci51673202016-11-01 17:00:32 +01003087 node.value_str = dflt;
Michal Vasko1dca6882015-10-22 14:29:42 +02003088 node.value_type = type->base;
Radek Krejci37b756f2016-01-18 10:15:03 +01003089 node.schema = calloc(1, sizeof (struct lys_node_leaf));
Michal Vasko253035f2015-12-17 16:58:13 +01003090 if (!node.schema) {
3091 LOGMEM;
3092 return -1;
3093 }
Radek Krejcibad2f172016-08-02 11:04:15 +02003094 node.schema->name = strdup("fake-default");
Michal Vasko253035f2015-12-17 16:58:13 +01003095 if (!node.schema->name) {
3096 LOGMEM;
Michal Vaskof49eda02016-07-21 12:17:01 +02003097 free(node.schema);
Michal Vasko253035f2015-12-17 16:58:13 +01003098 return -1;
3099 }
Michal Vasko56826402016-03-02 11:11:37 +01003100 node.schema->module = module;
Radek Krejci37b756f2016-01-18 10:15:03 +01003101 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
Michal Vasko1dca6882015-10-22 14:29:42 +02003102
Radek Krejci37b756f2016-01-18 10:15:03 +01003103 if (type->base == LY_TYPE_LEAFREF) {
Michal Vasko1dca6882015-10-22 14:29:42 +02003104 if (!type->info.lref.target) {
3105 ret = EXIT_FAILURE;
3106 goto finish;
3107 }
Radek Krejci51673202016-11-01 17:00:32 +01003108 ret = check_default(&type->info.lref.target->type, &dflt, module);
3109 if (!ret) {
3110 /* adopt possibly changed default value to its canonical form */
3111 if (*value) {
3112 *value = dflt;
3113 }
3114 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003115 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01003116 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 +01003117 /* possible forward reference */
3118 ret = 1;
Radek Krejcibad2f172016-08-02 11:04:15 +02003119 if (base_tpdf) {
Radek Krejci9ad23f42016-10-31 15:46:52 +01003120 /* default value is defined in some base typedef */
Radek Krejcibad2f172016-08-02 11:04:15 +02003121 if ((type->base == LY_TYPE_BITS && type->der->type.der) ||
3122 (type->base == LY_TYPE_ENUM && type->der->type.der)) {
3123 /* we have refined bits/enums */
3124 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
3125 "Invalid value \"%s\" of the default statement inherited to \"%s\" from \"%s\" base type.",
Radek Krejci51673202016-11-01 17:00:32 +01003126 dflt, type->parent->name, base_tpdf->name);
Radek Krejcibad2f172016-08-02 11:04:15 +02003127 }
3128 }
Radek Krejci51673202016-11-01 17:00:32 +01003129 } else {
3130 /* success - adopt canonical form from the node into the default value */
3131 if (dflt != node.value_str) {
3132 /* this can happen only if we have non-inherited default value,
3133 * inherited default values are already in canonical form */
3134 assert(dflt == *value);
3135 *value = node.value_str;
3136 }
Michal Vasko3767fb22016-07-21 12:10:57 +02003137 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003138 }
3139
3140finish:
3141 if (node.value_type == LY_TYPE_BITS) {
3142 free(node.value.bit);
3143 }
3144 free((char *)node.schema->name);
3145 free(node.schema);
3146
3147 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003148}
3149
Michal Vasko730dfdf2015-08-11 14:48:05 +02003150/**
3151 * @brief Check a key for mandatory attributes. Logs directly.
3152 *
3153 * @param[in] key The key to check.
3154 * @param[in] flags What flags to check.
3155 * @param[in] list The list of all the keys.
3156 * @param[in] index Index of the key in the key list.
3157 * @param[in] name The name of the keys.
3158 * @param[in] len The name length.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003159 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003160 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003161 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003162static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003163check_key(struct lys_node_list *list, int index, const char *name, int len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003164{
Radek Krejciadb57612016-02-16 13:34:34 +01003165 struct lys_node_leaf *key = list->keys[index];
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003166 char *dup = NULL;
3167 int j;
3168
3169 /* existence */
3170 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02003171 if (name[len] != '\0') {
3172 dup = strdup(name);
Michal Vasko253035f2015-12-17 16:58:13 +01003173 if (!dup) {
3174 LOGMEM;
3175 return -1;
3176 }
Michal Vaskof02e3742015-08-05 16:27:02 +02003177 dup[len] = '\0';
3178 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003179 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003180 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, list, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003181 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003182 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003183 }
3184
3185 /* uniqueness */
3186 for (j = index - 1; j >= 0; j--) {
Radek Krejciadb57612016-02-16 13:34:34 +01003187 if (key == list->keys[j]) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003188 LOGVAL(LYE_KEY_DUP, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003189 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003190 }
3191 }
3192
3193 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02003194 if (key->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003195 LOGVAL(LYE_KEY_NLEAF, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003196 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003197 }
3198
3199 /* type of the leaf is not built-in empty */
Radek Krejcic3738db2016-09-15 15:51:21 +02003200 if (key->type.base == LY_TYPE_EMPTY && key->module->version < 2) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003201 LOGVAL(LYE_KEY_TYPE, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003202 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003203 }
3204
3205 /* config attribute is the same as of the list */
Radek Krejci5c08a992016-11-02 13:30:04 +01003206 if ((key->flags & LYS_CONFIG_MASK) && (list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003207 LOGVAL(LYE_KEY_CONFIG, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003208 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003209 }
3210
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003211 /* key is not placed from augment */
3212 if (key->parent->nodetype == LYS_AUGMENT) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003213 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, key, key->name);
3214 LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key inserted from augment.");
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003215 return -1;
3216 }
3217
Radek Krejci3f21ada2016-08-01 13:34:31 +02003218 /* key is not when/if-feature -conditional */
3219 j = 0;
3220 if (key->when || (key->iffeature_size && (j = 1))) {
3221 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, key, j ? "if-feature" : "when", "leaf");
3222 LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key definition cannot depend on a \"%s\" condition.",
3223 j ? "if-feature" : "when");
Radek Krejci581ce772015-11-10 17:22:40 +01003224 return -1;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003225 }
3226
Michal Vasko0b85aa82016-03-07 14:37:43 +01003227 return EXIT_SUCCESS;
Michal Vasko184521f2015-09-24 13:14:26 +02003228}
Michal Vasko730dfdf2015-08-11 14:48:05 +02003229
3230/**
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003231 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003232 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003233 * @param[in] parent The parent node of the unique structure.
Michal Vasko0b85aa82016-03-07 14:37:43 +01003234 * @param[in] uniq_str_path One path from the unique string.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003235 *
3236 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
3237 */
3238int
Radek Krejcid09d1a52016-08-11 14:05:45 +02003239resolve_unique(struct lys_node *parent, const char *uniq_str_path, uint8_t *trg_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003240{
Radek Krejci581ce772015-11-10 17:22:40 +01003241 int rc;
Michal Vasko1e62a092015-12-01 12:27:20 +01003242 const struct lys_node *leaf = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003243
Radek Krejcif3c71de2016-04-11 12:45:46 +02003244 rc = resolve_descendant_schema_nodeid(uniq_str_path, parent->child, LYS_LEAF, 1, 1, &leaf);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003245 if (rc || !leaf) {
Michal Vasko0b85aa82016-03-07 14:37:43 +01003246 if (rc) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003247 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003248 if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003249 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, parent, uniq_str_path[rc - 1], &uniq_str_path[rc - 1]);
Radek Krejcif3c71de2016-04-11 12:45:46 +02003250 } else if (rc == -2) {
Michal Vaskoc66c6d82016-04-12 11:37:31 +02003251 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Unique argument references list.");
Radek Krejci581ce772015-11-10 17:22:40 +01003252 }
Michal Vasko0b85aa82016-03-07 14:37:43 +01003253 rc = -1;
Michal Vasko0b85aa82016-03-07 14:37:43 +01003254 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01003255 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3256 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target leaf not found.");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003257 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003258 }
Radek Krejci581ce772015-11-10 17:22:40 +01003259 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003260 }
Michal Vasko9bb061b2016-02-12 11:00:19 +01003261 if (leaf->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003262 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3263 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target is not a leaf.");
Radek Krejcid09d1a52016-08-11 14:05:45 +02003264 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003265 }
3266
Radek Krejcicf509982015-12-15 09:22:44 +01003267 /* check status */
Radek Krejci48464ed2016-03-17 15:44:09 +01003268 if (lyp_check_status(parent->flags, parent->module, parent->name, leaf->flags, leaf->module, leaf->name, leaf)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003269 return -1;
3270 }
3271
Radek Krejcid09d1a52016-08-11 14:05:45 +02003272 /* check that all unique's targets are of the same config type */
3273 if (*trg_type) {
3274 if (((*trg_type == 1) && (leaf->flags & LYS_CONFIG_R)) || ((*trg_type == 2) && (leaf->flags & LYS_CONFIG_W))) {
3275 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3276 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent,
3277 "Leaf \"%s\" referenced in unique statement is config %s, but previous referenced leaf is config %s.",
3278 uniq_str_path, *trg_type == 1 ? "false" : "true", *trg_type == 1 ? "true" : "false");
3279 return -1;
3280 }
3281 } else {
3282 /* first unique */
3283 if (leaf->flags & LYS_CONFIG_W) {
3284 *trg_type = 1;
3285 } else {
3286 *trg_type = 2;
3287 }
3288 }
3289
Radek Krejcica7efb72016-01-18 13:06:01 +01003290 /* set leaf's unique flag */
3291 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
3292
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003293 return EXIT_SUCCESS;
3294
3295error:
3296
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003297 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003298}
3299
Radek Krejci0c0086a2016-03-24 15:20:28 +01003300void
Michal Vasko23b61ec2015-08-19 11:19:50 +02003301unres_data_del(struct unres_data *unres, uint32_t i)
3302{
3303 /* there are items after the one deleted */
3304 if (i+1 < unres->count) {
3305 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02003306 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003307
3308 /* deleting the last item */
3309 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02003310 free(unres->node);
3311 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003312 }
3313
3314 /* if there are no items after and it is not the last one, just move the counter */
3315 --unres->count;
3316}
3317
Michal Vasko0491ab32015-08-19 14:28:29 +02003318/**
3319 * @brief Resolve (find) a data node from a specific module. Does not log.
3320 *
3321 * @param[in] mod Module to search in.
3322 * @param[in] name Name of the data node.
3323 * @param[in] nam_len Length of the name.
3324 * @param[in] start Data node to start the search from.
3325 * @param[in,out] parents Resolved nodes. If there are some parents,
3326 * they are replaced (!!) with the resolvents.
3327 *
Michal Vasko2471e7f2016-04-11 11:00:15 +02003328 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko0491ab32015-08-19 14:28:29 +02003329 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003330static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003331resolve_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 +02003332{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003333 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02003334 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003335 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003336
Michal Vasko23b61ec2015-08-19 11:19:50 +02003337 if (!parents->count) {
3338 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003339 parents->node = malloc(sizeof *parents->node);
Michal Vasko253035f2015-12-17 16:58:13 +01003340 if (!parents->node) {
3341 LOGMEM;
Michal Vasko2471e7f2016-04-11 11:00:15 +02003342 return -1;
Michal Vasko253035f2015-12-17 16:58:13 +01003343 }
Michal Vaskocf024702015-10-08 15:01:42 +02003344 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003345 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003346 for (i = 0; i < parents->count;) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02003347 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003348 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003349 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003350 continue;
3351 }
3352 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02003353 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003354 if (node->schema->module == mod && !strncmp(node->schema->name, name, nam_len)
3355 && node->schema->name[nam_len] == '\0') {
3356 /* matching target */
3357 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02003358 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02003359 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003360 flag = 1;
3361 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02003362 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003363 ++parents->count;
Michal Vasko253035f2015-12-17 16:58:13 +01003364 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
3365 if (!parents->node) {
3366 return EXIT_FAILURE;
3367 }
Michal Vaskocf024702015-10-08 15:01:42 +02003368 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003369 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003370 }
3371 }
3372 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003373
3374 if (!flag) {
3375 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003376 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02003377 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003378 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02003379 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003380 }
3381
Michal Vasko0491ab32015-08-19 14:28:29 +02003382 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02003383}
3384
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003385/**
3386 * @brief Resolve (find) a data node. Does not log.
3387 *
Radek Krejci581ce772015-11-10 17:22:40 +01003388 * @param[in] mod_name Module name of the data node.
3389 * @param[in] mod_name_len Length of the module name.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003390 * @param[in] name Name of the data node.
3391 * @param[in] nam_len Length of the name.
3392 * @param[in] start Data node to start the search from.
3393 * @param[in,out] parents Resolved nodes. If there are some parents,
3394 * they are replaced (!!) with the resolvents.
3395 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003396 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003397 */
Radek Krejcic5090c32015-08-12 09:46:19 +02003398static int
Radek Krejci581ce772015-11-10 17:22:40 +01003399resolve_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 +02003400 struct unres_data *parents)
Radek Krejcic5090c32015-08-12 09:46:19 +02003401{
Michal Vasko1e62a092015-12-01 12:27:20 +01003402 const struct lys_module *mod;
Michal Vasko31fc3672015-10-21 12:08:13 +02003403 char *str;
Radek Krejcic5090c32015-08-12 09:46:19 +02003404
Michal Vasko23b61ec2015-08-19 11:19:50 +02003405 assert(start);
3406
Michal Vasko31fc3672015-10-21 12:08:13 +02003407 if (mod_name) {
3408 /* we have mod_name, find appropriate module */
3409 str = strndup(mod_name, mod_name_len);
Michal Vasko253035f2015-12-17 16:58:13 +01003410 if (!str) {
3411 LOGMEM;
3412 return -1;
3413 }
Michal Vasko31fc3672015-10-21 12:08:13 +02003414 mod = ly_ctx_get_module(start->schema->module->ctx, str, NULL);
3415 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02003416 if (!mod) {
3417 /* invalid prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003418 return -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02003419 }
3420 } else {
3421 /* no prefix, module is the same as of current node */
3422 mod = start->schema->module;
3423 }
3424
3425 return resolve_data(mod, name, name_len, start, parents);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003426}
3427
Michal Vasko730dfdf2015-08-11 14:48:05 +02003428/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003429 * @brief Resolve a path predicate (leafref) in JSON data context. Logs directly
Radek Krejci48464ed2016-03-17 15:44:09 +01003430 * only specific errors, general no-resolvent error is left to the caller.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003431 *
Michal Vaskobb211122015-08-19 14:03:11 +02003432 * @param[in] pred Predicate to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003433 * @param[in] node Node from which the predicate is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02003434 * @param[in,out] node_match Nodes satisfying the restriction
3435 * without the predicate. Nodes not
3436 * satisfying the predicate are removed.
Michal Vasko0491ab32015-08-19 14:28:29 +02003437 * @param[out] parsed Number of characters parsed, negative on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003438 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003439 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003440 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003441static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003442resolve_path_predicate_data(const char *pred, struct lyd_node *node, struct unres_data *node_match,
Radek Krejci010e54b2016-03-15 09:40:34 +01003443 int *parsed)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003444{
Michal Vasko730dfdf2015-08-11 14:48:05 +02003445 /* ... /node[source = destination] ... */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003446 struct unres_data source_match, dest_match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003447 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vasko0491ab32015-08-19 14:28:29 +02003448 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed_loc = 0, pke_parsed = 0;
3449 int has_predicate, dest_parent_times, i, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003450 uint32_t j;
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003451 struct lyd_node_leaf_list *leaf_dst, *leaf_src;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003452
3453 source_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003454 source_match.node = malloc(sizeof *source_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003455 if (!source_match.node) {
3456 LOGMEM;
3457 return -1;
3458 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003459 dest_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003460 dest_match.node = malloc(sizeof *dest_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003461 if (!dest_match.node) {
3462 LOGMEM;
3463 return -1;
3464 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003465
3466 do {
3467 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
3468 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003469 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, pred[-i], &pred[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003470 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003471 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003472 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003473 parsed_loc += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003474 pred += i;
3475
Michal Vasko23b61ec2015-08-19 11:19:50 +02003476 for (j = 0; j < node_match->count;) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003477 /* source */
Michal Vaskocf024702015-10-08 15:01:42 +02003478 source_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02003479
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003480 /* must be leaf (key of a list) */
Radek Krejci581ce772015-11-10 17:22:40 +01003481 if ((rc = resolve_data_node(sour_pref, sour_pref_len, source, sour_len, node_match->node[j],
Michal Vaskocf024702015-10-08 15:01:42 +02003482 &source_match)) || (source_match.count != 1) || (source_match.node[0]->schema->nodetype != LYS_LEAF)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003483 i = 0;
3484 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003485 }
3486
3487 /* destination */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003488 dest_match.node[0] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003489 dest_parent_times = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003490 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3491 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003492 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003493 rc = -1;
3494 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003495 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003496 pke_parsed = i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003497 for (i = 0; i < dest_parent_times; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02003498 dest_match.node[0] = dest_match.node[0]->parent;
3499 if (!dest_match.node[0]) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003500 i = 0;
Michal Vasko0491ab32015-08-19 14:28:29 +02003501 rc = EXIT_FAILURE;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003502 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003503 }
3504 }
3505 while (1) {
Radek Krejci581ce772015-11-10 17:22:40 +01003506 if ((rc = resolve_data_node(dest_pref, dest_pref_len, dest, dest_len, dest_match.node[0],
Michal Vasko0491ab32015-08-19 14:28:29 +02003507 &dest_match)) || (dest_match.count != 1)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003508 i = 0;
3509 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003510 }
3511
3512 if (pke_len == pke_parsed) {
3513 break;
3514 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003515 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 +02003516 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003517 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003518 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003519 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003520 }
3521 pke_parsed += i;
3522 }
3523
3524 /* check match between source and destination nodes */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003525 leaf_dst = (struct lyd_node_leaf_list *)dest_match.node[0];
3526 while (leaf_dst->value_type == LY_TYPE_LEAFREF) {
3527 leaf_dst = (struct lyd_node_leaf_list *)leaf_dst->value.leafref;
3528 }
3529 leaf_src = (struct lyd_node_leaf_list *)source_match.node[0];
3530 while (leaf_src->value_type == LY_TYPE_LEAFREF) {
3531 leaf_src = (struct lyd_node_leaf_list *)leaf_src->value.leafref;
3532 }
3533 if (leaf_src->value_type != leaf_dst->value_type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003534 goto remove_leafref;
3535 }
3536
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003537 if (!ly_strequal(leaf_src->value_str, leaf_dst->value_str, 1)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003538 goto remove_leafref;
3539 }
3540
3541 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003542 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003543 continue;
3544
3545remove_leafref:
3546 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003547 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003548 }
3549 } while (has_predicate);
3550
Michal Vaskocf024702015-10-08 15:01:42 +02003551 free(source_match.node);
3552 free(dest_match.node);
Michal Vasko0491ab32015-08-19 14:28:29 +02003553 if (parsed) {
3554 *parsed = parsed_loc;
3555 }
3556 return EXIT_SUCCESS;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003557
3558error:
3559
3560 if (source_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003561 free(source_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003562 }
3563 if (dest_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003564 free(dest_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003565 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003566 if (parsed) {
3567 *parsed = -parsed_loc+i;
3568 }
3569 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003570}
3571
Michal Vasko730dfdf2015-08-11 14:48:05 +02003572/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003573 * @brief Resolve a path (leafref) in JSON data context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003574 *
Michal Vaskocf024702015-10-08 15:01:42 +02003575 * @param[in] node Leafref data node.
Michal Vasko23b61ec2015-08-19 11:19:50 +02003576 * @param[in] path Path of the leafref.
Radek Krejci48464ed2016-03-17 15:44:09 +01003577 * @param[out] ret Matching nodes. Expects an empty, but allocated structure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003578 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003579 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003580 */
Michal Vasko184521f2015-09-24 13:14:26 +02003581static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003582resolve_path_arg_data(struct lyd_node *node, const char *path, struct unres_data *ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003583{
Radek Krejci71b795b2015-08-10 16:20:39 +02003584 struct lyd_node *data = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003585 const char *prefix, *name;
Michal Vasko0491ab32015-08-19 14:28:29 +02003586 int pref_len, nam_len, has_predicate, parent_times, i, parsed, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003587 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003588
Michal Vaskocf024702015-10-08 15:01:42 +02003589 assert(node && path && ret && !ret->count);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003590
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003591 parent_times = 0;
Michal Vaskod9173342015-08-17 14:35:36 +02003592 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003593
3594 /* searching for nodeset */
3595 do {
Radek Krejcif7ed4c32016-10-27 16:20:03 +02003596 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 +01003597 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path[-i], &path[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003598 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003599 goto error;
3600 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003601 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003602 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003603
Michal Vasko23b61ec2015-08-19 11:19:50 +02003604 if (!ret->count) {
Michal Vaskobfd98e62016-09-02 09:50:05 +02003605 if (parent_times > 0) {
3606 data = node;
3607 for (i = 1; i < parent_times; ++i) {
3608 data = data->parent;
Michal Vasko253035f2015-12-17 16:58:13 +01003609 }
Michal Vaskobfd98e62016-09-02 09:50:05 +02003610 } else if (!parent_times) {
3611 data = node->child;
3612 } else {
3613 /* absolute path */
3614 for (data = node; data->parent; data = data->parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003615 }
3616
Michal Vaskobfd98e62016-09-02 09:50:05 +02003617 /* we may still be parsing it and the pointer is not correct yet */
3618 if (data->prev) {
3619 while (data->prev->next) {
3620 data = data->prev;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003621 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003622 }
3623 }
3624
3625 /* node identifier */
Radek Krejci581ce772015-11-10 17:22:40 +01003626 if ((rc = resolve_data_node(prefix, pref_len, name, nam_len, data, ret))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003627 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003628 LOGVAL(LYE_INELEM_LEN, LY_VLOG_LYD, node, nam_len, name);
Michal Vasko184521f2015-09-24 13:14:26 +02003629 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003630 goto error;
3631 }
3632
3633 if (has_predicate) {
3634 /* we have predicate, so the current results must be lists */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003635 for (j = 0; j < ret->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02003636 if (ret->node[j]->schema->nodetype == LYS_LIST &&
3637 ((struct lys_node_list *)ret->node[0]->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003638 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003639 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003640 continue;
3641 }
3642
3643 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003644 unres_data_del(ret, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003645 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003646 if ((rc = resolve_path_predicate_data(path, node, ret, &i))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003647 if (rc == -1) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003648 LOGVAL(LYE_NORESOLV, LY_VLOG_LYD, node, "leafref", path);
Michal Vasko184521f2015-09-24 13:14:26 +02003649 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003650 goto error;
3651 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003652 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003653 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003654
Michal Vasko23b61ec2015-08-19 11:19:50 +02003655 if (!ret->count) {
Michal Vasko0491ab32015-08-19 14:28:29 +02003656 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003657 goto error;
3658 }
3659 }
3660 } while (path[0] != '\0');
3661
Michal Vaskof02e3742015-08-05 16:27:02 +02003662 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003663
3664error:
3665
Michal Vaskocf024702015-10-08 15:01:42 +02003666 free(ret->node);
3667 ret->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003668 ret->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003669
Michal Vasko0491ab32015-08-19 14:28:29 +02003670 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003671}
3672
Michal Vaskoe27516a2016-10-10 17:55:31 +00003673static int
3674resolve_path_arg_schema_valid_dep_flag(const struct lys_node *op_node, const struct lys_node *first_node, int abs_path)
3675{
3676 int dep1, dep2;
3677 const struct lys_node *node;
3678
3679 if (lys_parent(op_node)) {
3680 /* inner operation (notif/action) */
3681 if (abs_path) {
3682 return 1;
3683 } else {
3684 /* compare depth of both nodes */
3685 for (dep1 = 0, node = op_node; lys_parent(node); node = lys_parent(node));
3686 for (dep2 = 0, node = first_node; lys_parent(node); node = lys_parent(node));
3687 if ((dep2 > dep1) || ((dep2 == dep1) && (op_node != first_node))) {
3688 return 1;
3689 }
3690 }
3691 } else {
3692 /* top-level operation (notif/rpc) */
3693 if (op_node != first_node) {
3694 return 1;
3695 }
3696 }
3697
3698 return 0;
3699}
3700
Michal Vasko730dfdf2015-08-11 14:48:05 +02003701/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003702 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003703 *
Michal Vaskobb211122015-08-19 14:03:11 +02003704 * @param[in] path Path to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003705 * @param[in] context_node Predicate context node (where the predicate is placed).
3706 * @param[in] parent Path context node (where the path begins/is placed).
Michal Vaskoe27516a2016-10-10 17:55:31 +00003707 * @param[in] op_node Optional node if the leafref is in an operation (action/rpc/notif).
Michal Vasko730dfdf2015-08-11 14:48:05 +02003708 *
Michal Vasko184521f2015-09-24 13:14:26 +02003709 * @return 0 on forward reference, otherwise the number
3710 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003711 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003712 */
Michal Vasko1f76a282015-08-04 16:16:53 +02003713static int
Radek Krejciadb57612016-02-16 13:34:34 +01003714resolve_path_predicate_schema(const char *path, const struct lys_node *context_node,
Michal Vaskoe27516a2016-10-10 17:55:31 +00003715 struct lys_node *parent, const struct lys_node *op_node)
Michal Vasko1f76a282015-08-04 16:16:53 +02003716{
Michal Vasko1e62a092015-12-01 12:27:20 +01003717 const struct lys_node *src_node, *dst_node;
Michal Vasko1f76a282015-08-04 16:16:53 +02003718 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vaskof9b35d92016-10-21 15:19:30 +02003719 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, pke_parsed, parsed = 0;
3720 int has_predicate, dest_parent_times, i, rc, first_iter;
Michal Vasko1f76a282015-08-04 16:16:53 +02003721
3722 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02003723 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02003724 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003725 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003726 return -parsed+i;
3727 }
3728 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003729 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02003730
Michal Vasko58090902015-08-13 14:04:15 +02003731 /* source (must be leaf) */
Michal Vasko36cbaa42015-12-14 13:15:48 +01003732 if (!sour_pref) {
Radek Krejciadb57612016-02-16 13:34:34 +01003733 sour_pref = context_node->module->name;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003734 }
Radek Krejciadb57612016-02-16 13:34:34 +01003735 rc = lys_get_sibling(context_node->child, sour_pref, sour_pref_len, source, sour_len,
Michal Vasko59ad4582016-09-16 13:15:41 +02003736 LYS_LEAF | LYS_LEAFLIST | LYS_AUGMENT, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003737 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003738 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02003739 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003740 }
3741
3742 /* destination */
Michal Vaskof9b35d92016-10-21 15:19:30 +02003743 dest_parent_times = 0;
3744 pke_parsed = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003745 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3746 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003747 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 +02003748 return -parsed;
3749 }
3750 pke_parsed += i;
3751
Radek Krejciadb57612016-02-16 13:34:34 +01003752 for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
Michal Vaskofbaead72016-10-07 10:54:48 +02003753 /* path is supposed to be evaluated in data tree, so we have to skip
3754 * all schema nodes that cannot be instantiated in data tree */
3755 for (dst_node = lys_parent(dst_node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003756 dst_node && !(dst_node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Michal Vaskofbaead72016-10-07 10:54:48 +02003757 dst_node = lys_parent(dst_node));
3758
Michal Vasko1f76a282015-08-04 16:16:53 +02003759 if (!dst_node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003760 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003761 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003762 }
3763 }
Michal Vaskoe27516a2016-10-10 17:55:31 +00003764 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003765 while (1) {
Michal Vasko36cbaa42015-12-14 13:15:48 +01003766 if (!dest_pref) {
3767 dest_pref = dst_node->module->name;
3768 }
3769 rc = lys_get_sibling(dst_node->child, dest_pref, dest_pref_len, dest, dest_len,
Michal Vasko165dc4a2015-10-23 09:44:27 +02003770 LYS_CONTAINER | LYS_LIST | LYS_LEAF | LYS_AUGMENT, &dst_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003771 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003772 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003773 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003774 }
3775
Michal Vaskoe27516a2016-10-10 17:55:31 +00003776 if (first_iter) {
3777 if (resolve_path_arg_schema_valid_dep_flag(op_node, dst_node, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01003778 parent->flags |= LYS_LEAFREF_DEP;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003779 }
3780 first_iter = 0;
3781 }
3782
Michal Vasko1f76a282015-08-04 16:16:53 +02003783 if (pke_len == pke_parsed) {
3784 break;
3785 }
3786
3787 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &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,
Radek Krejciadb57612016-02-16 13:34:34 +01003790 (path_key_expr+pke_parsed)[-i], (path_key_expr+pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003791 return -parsed;
3792 }
3793 pke_parsed += i;
3794 }
3795
3796 /* check source - dest match */
Michal Vasko59ad4582016-09-16 13:15:41 +02003797 if (dst_node->nodetype != src_node->nodetype) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003798 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko59ad4582016-09-16 13:15:41 +02003799 LOGVAL(LYE_SPEC, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "Destination node is not a %s, but a %s.",
3800 strnodetype(src_node->nodetype), strnodetype(dst_node->nodetype));
Michal Vasko184521f2015-09-24 13:14:26 +02003801 return -parsed;
3802 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003803 } while (has_predicate);
3804
3805 return parsed;
3806}
3807
Michal Vasko730dfdf2015-08-11 14:48:05 +02003808/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003809 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003810 *
Michal Vaskobb211122015-08-19 14:03:11 +02003811 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003812 * @param[in] parent_node Parent of the leafref.
Radek Krejci2f12f852016-01-08 12:59:57 +01003813 * @param[in] parent_tpdf Flag if the parent node is actually typedef, in that case the path
3814 * has to contain absolute path
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003815 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003816 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003817 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003818 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003819static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003820resolve_path_arg_schema(const char *path, struct lys_node *parent, int parent_tpdf,
Michal Vasko36cbaa42015-12-14 13:15:48 +01003821 const struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02003822{
Michal Vaskoe27516a2016-10-10 17:55:31 +00003823 const struct lys_node *node, *op_node = NULL;
Radek Krejci990af1f2016-11-09 13:53:36 +01003824 const struct lys_module *mod;
3825 struct lys_module *mod_start;
Michal Vasko1f76a282015-08-04 16:16:53 +02003826 const char *id, *prefix, *name;
3827 int pref_len, nam_len, parent_times, has_predicate;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003828 int i, first_iter, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02003829
Michal Vasko184521f2015-09-24 13:14:26 +02003830 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003831 parent_times = 0;
3832 id = path;
3833
Michal Vaskoe27516a2016-10-10 17:55:31 +00003834 /* find operation schema we are in, if applicable */
Michal Vaskoe9914d12016-10-07 14:32:37 +02003835 if (!parent_tpdf) {
Michal Vaskoe27516a2016-10-10 17:55:31 +00003836 for (op_node = lys_parent(parent);
3837 op_node && !(op_node->nodetype & (LYS_ACTION | LYS_NOTIF | LYS_RPC));
3838 op_node = lys_parent(op_node));
Michal Vaskoe9914d12016-10-07 14:32:37 +02003839 }
3840
Radek Krejci990af1f2016-11-09 13:53:36 +01003841 mod_start = lys_node_module(parent);
Michal Vasko1f76a282015-08-04 16:16:53 +02003842 do {
Radek Krejci990af1f2016-11-09 13:53:36 +01003843 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 +01003844 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 +02003845 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003846 }
3847 id += i;
3848
Michal Vasko184521f2015-09-24 13:14:26 +02003849 if (first_iter) {
Michal Vasko1f76a282015-08-04 16:16:53 +02003850 if (parent_times == -1) {
Radek Krejcic071c542016-01-27 14:57:51 +01003851 /* resolve prefix of the module */
Radek Krejci990af1f2016-11-09 13:53:36 +01003852 mod = prefix ? lys_get_import_module(mod_start, NULL, 0, prefix, pref_len) : mod_start;
3853 if (!mod) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003854 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3855 "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003856 return EXIT_FAILURE;
Michal Vasko58090902015-08-13 14:04:15 +02003857 }
Radek Krejci990af1f2016-11-09 13:53:36 +01003858 if (!mod->implemented) {
Radek Krejci2eee5c02016-12-06 19:18:05 +01003859 mod = lys_implemented_module(mod);
Radek Krejci990af1f2016-11-09 13:53:36 +01003860 if (!mod->implemented) {
3861 /* make the found module implemented */
3862 if (lys_set_implemented(mod)) {
3863 return EXIT_FAILURE;
3864 }
3865 }
3866 }
3867 /* get start node */
3868 if (!mod->data) {
3869 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3870 "leafref", path);
3871 return EXIT_FAILURE;
3872 }
3873 node = mod->data;
3874
Michal Vasko1f76a282015-08-04 16:16:53 +02003875 } else if (parent_times > 0) {
Radek Krejci2f12f852016-01-08 12:59:57 +01003876 if (parent_tpdf) {
3877 /* the path is not allowed to contain relative path since we are in top level typedef */
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003878 LOGVAL(LYE_NORESOLV, 0, NULL, "leafref", path);
Radek Krejci2f12f852016-01-08 12:59:57 +01003879 return -1;
3880 }
3881
Michal Vasko94458082016-10-07 14:34:36 +02003882 /* we are looking for a sibling of a node, node it's parent (that is why parent_times - 1) */
3883 for (i = 0, node = parent; i < parent_times - 1; i++) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02003884 /* path is supposed to be evaluated in data tree, so we have to skip
3885 * all schema nodes that cannot be instantiated in data tree */
3886 for (node = lys_parent(node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003887 node && !(node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Radek Krejci3a5501d2016-07-18 22:03:34 +02003888 node = lys_parent(node));
3889
Michal Vasko1f76a282015-08-04 16:16:53 +02003890 if (!node) {
Michal Vaskoe9914d12016-10-07 14:32:37 +02003891 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003892 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003893 }
3894 }
Radek Krejci990af1f2016-11-09 13:53:36 +01003895
3896 /* now we have to check that if we are going into a node from a different module,
3897 * the module is implemented (so its augments are applied) */
3898 mod = prefix ? lys_get_import_module(mod_start, NULL, 0, prefix, pref_len) : mod_start;
3899 if (!mod) {
3900 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
3901 return EXIT_FAILURE;
3902 }
3903 if (!mod->implemented) {
Radek Krejci2eee5c02016-12-06 19:18:05 +01003904 mod = lys_implemented_module(mod);
Radek Krejci990af1f2016-11-09 13:53:36 +01003905 if (!mod->implemented) {
3906 /* make the found module implemented */
3907 if (lys_set_implemented(mod)) {
3908 return EXIT_FAILURE;
3909 }
3910 }
3911 }
Michal Vaskoe01eca52015-08-13 14:42:02 +02003912 } else {
3913 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003914 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003915 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003916 } else {
Radek Krejci990af1f2016-11-09 13:53:36 +01003917 /* we have to first check that the module we are going into is implemented */
3918 mod = prefix ? lys_get_import_module(mod_start, NULL, 0, prefix, pref_len) : mod_start;
3919 if (!mod) {
3920 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
3921 return EXIT_FAILURE;
3922 }
3923 if (!mod->implemented) {
Radek Krejci2eee5c02016-12-06 19:18:05 +01003924 mod = lys_implemented_module(mod);
Radek Krejci990af1f2016-11-09 13:53:36 +01003925 if (!mod->implemented) {
3926 /* make the found module implemented */
3927 if (lys_set_implemented(mod)) {
3928 return EXIT_FAILURE;
3929 }
3930 }
3931 }
3932
Michal Vasko7dc71d02016-03-15 10:42:28 +01003933 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02003934 if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko2f5aceb2016-03-22 10:24:14 +01003935 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 +01003936 return -1;
3937 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003938 node = node->child;
Radek Krejci43ccc4c2016-10-18 20:40:06 +02003939 if (!node) {
3940 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3941 "leafref", path);
3942 return EXIT_FAILURE;
3943 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003944 }
3945
Michal Vasko4f0dad02016-02-15 14:08:23 +01003946 if (!prefix) {
Radek Krejci990af1f2016-11-09 13:53:36 +01003947 prefix = mod_start->name;
Michal Vasko4f0dad02016-02-15 14:08:23 +01003948 }
3949
Michal Vasko36cbaa42015-12-14 13:15:48 +01003950 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 +02003951 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003952 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko7a55bea2016-05-02 14:51:20 +02003953 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003954 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003955
Michal Vaskoe27516a2016-10-10 17:55:31 +00003956 if (first_iter) {
3957 /* set external dependency flag, we can decide based on the first found node */
3958 if (!parent_tpdf && op_node && parent_times &&
3959 resolve_path_arg_schema_valid_dep_flag(op_node, node, (parent_times == -1 ? 1 : 0))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01003960 parent->flags |= LYS_LEAFREF_DEP;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003961 }
3962 first_iter = 0;
3963 }
3964
Michal Vasko1f76a282015-08-04 16:16:53 +02003965 if (has_predicate) {
3966 /* we have predicate, so the current result must be list */
3967 if (node->nodetype != LYS_LIST) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003968 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003969 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003970 }
3971
Michal Vaskoe27516a2016-10-10 17:55:31 +00003972 i = resolve_path_predicate_schema(id, node, parent, op_node);
Radek Krejci27fe55e2016-09-13 17:13:35 +02003973 if (i <= 0) {
3974 if (i == 0) {
3975 return EXIT_FAILURE;
3976 } else { /* i < 0 */
3977 return -1;
3978 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003979 }
3980 id += i;
Michal Vaskof9b35d92016-10-21 15:19:30 +02003981 has_predicate = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003982 }
3983 } while (id[0]);
3984
Michal Vaskoca917682016-07-25 11:00:37 +02003985 /* the target must be leaf or leaf-list (in YANG 1.1 only) */
Radek Krejci2a5a9602016-11-04 10:21:13 +01003986 if ((node->nodetype != LYS_LEAF) && (node->nodetype != LYS_LEAFLIST)) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003987 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Radek Krejcid47daf62016-08-22 16:23:38 +02003988 LOGVAL(LYE_SPEC, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
Radek Krejci2a5a9602016-11-04 10:21:13 +01003989 "Leafref target \"%s\" is not a leaf nor a leaf-list.", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003990 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02003991 }
3992
Radek Krejcicf509982015-12-15 09:22:44 +01003993 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01003994 if (lyp_check_status(parent->flags, parent->module, parent->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01003995 node->flags, node->module, node->name, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003996 return -1;
3997 }
3998
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003999 if (ret) {
4000 *ret = node;
4001 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02004002
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004003 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02004004}
4005
Michal Vasko730dfdf2015-08-11 14:48:05 +02004006/**
Michal Vaskof39142b2015-10-21 11:40:05 +02004007 * @brief Resolve instance-identifier predicate in JSON data format.
4008 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004009 *
Michal Vaskobb211122015-08-19 14:03:11 +02004010 * @param[in] pred Predicate to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004011 * @param[in,out] node_match Nodes matching the restriction without
4012 * the predicate. Nodes not satisfying
4013 * the predicate are removed.
4014 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004015 * @return Number of characters successfully parsed,
4016 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004017 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004018static int
Michal Vaskof39142b2015-10-21 11:40:05 +02004019resolve_predicate(const char *pred, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004020{
Michal Vasko730dfdf2015-08-11 14:48:05 +02004021 /* ... /node[target = value] ... */
Michal Vaskob2f40be2016-09-08 16:03:48 +02004022 struct lyd_node *target;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004023 const char *model, *name, *value;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004024 int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed, pred_iter, k;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004025 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004026
Michal Vasko1f2cc332015-08-19 11:18:32 +02004027 assert(pred && node_match->count);
4028
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004029 idx = -1;
4030 parsed = 0;
4031
Michal Vaskob2f40be2016-09-08 16:03:48 +02004032 pred_iter = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004033 do {
Michal Vaskof39142b2015-10-21 11:40:05 +02004034 if ((i = parse_predicate(pred, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004035 return -parsed+i;
4036 }
4037 parsed += i;
4038 pred += i;
4039
4040 if (isdigit(name[0])) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004041 /* pos */
4042 assert(!value);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004043 idx = atoi(name);
Michal Vaskob2f40be2016-09-08 16:03:48 +02004044 } else if (name[0] != '.') {
4045 /* list keys */
4046 if (pred_iter < 0) {
4047 pred_iter = 1;
4048 } else {
4049 ++pred_iter;
4050 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004051 }
4052
Michal Vaskof2f28a12016-09-09 12:43:06 +02004053 for (cur_idx = 1, j = 0; j < node_match->count; ++cur_idx) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004054 /* target */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004055 if (name[0] == '.') {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004056 /* leaf-list value */
Michal Vaskocf024702015-10-08 15:01:42 +02004057 if (node_match->node[j]->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004058 goto remove_instid;
4059 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004060
4061 target = node_match->node[j];
4062 /* check the value */
4063 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
4064 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
4065 goto remove_instid;
4066 }
4067
4068 } else if (!value) {
4069 /* keyless list position */
4070 if ((node_match->node[j]->schema->nodetype != LYS_LIST)
4071 || ((struct lys_node_list *)node_match->node[j]->schema)->keys) {
4072 goto remove_instid;
4073 }
4074
4075 if (idx != cur_idx) {
4076 goto remove_instid;
4077 }
4078
4079 } else {
4080 /* list key value */
Michal Vaskocf024702015-10-08 15:01:42 +02004081 if (node_match->node[j]->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004082 goto remove_instid;
4083 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004084
4085 /* key module must match the list module */
4086 if (strncmp(node_match->node[j]->schema->module->name, model, mod_len)
4087 || node_match->node[j]->schema->module->name[mod_len]) {
4088 goto remove_instid;
4089 }
4090 /* find the key leaf */
Michal Vasko045182c2016-09-09 12:44:07 +02004091 for (k = 1, target = node_match->node[j]->child; target && (k < pred_iter); k++, target = target->next);
Michal Vaskob2f40be2016-09-08 16:03:48 +02004092 if (!target) {
4093 goto remove_instid;
4094 }
4095 if ((struct lys_node_leaf *)target->schema !=
4096 ((struct lys_node_list *)node_match->node[j]->schema)->keys[pred_iter - 1]) {
4097 goto remove_instid;
4098 }
4099
4100 /* check the value */
4101 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
4102 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
4103 goto remove_instid;
4104 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004105 }
4106
Michal Vaskob2f40be2016-09-08 16:03:48 +02004107 /* instid is ok, continue check with the next one */
Michal Vasko1f2cc332015-08-19 11:18:32 +02004108 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004109 continue;
4110
4111remove_instid:
Michal Vaskob2f40be2016-09-08 16:03:48 +02004112 /* does not fulfill conditions, remove instid record */
Michal Vasko1f2cc332015-08-19 11:18:32 +02004113 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004114 }
4115 } while (has_predicate);
4116
Michal Vaskob2f40be2016-09-08 16:03:48 +02004117 /* check that all list keys were specified */
4118 if ((pred_iter > 0) && node_match->count) {
Michal Vasko045182c2016-09-09 12:44:07 +02004119 j = 0;
4120 while (j < node_match->count) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004121 assert(node_match->node[j]->schema->nodetype == LYS_LIST);
4122 if (pred_iter < ((struct lys_node_list *)node_match->node[j]->schema)->keys_size) {
4123 /* not enough predicates, just remove the list instance */
4124 unres_data_del(node_match, j);
Michal Vasko045182c2016-09-09 12:44:07 +02004125 } else {
4126 ++j;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004127 }
4128 }
4129
4130 if (!node_match->count) {
4131 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier is missing some list keys.");
4132 }
4133 }
4134
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004135 return parsed;
4136}
4137
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004138int
4139lys_check_xpath(struct lys_node *node, int check_place)
Michal Vasko9e635ac2016-10-17 11:44:09 +02004140{
4141 struct lys_node *parent, *elem;
4142 struct lyxp_set set;
4143 uint32_t i;
4144 int rc;
4145
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004146 if (check_place) {
4147 parent = node;
4148 while (parent) {
4149 if (parent->nodetype == LYS_GROUPING) {
4150 /* unresolved grouping, skip for now (will be checked later) */
Michal Vasko9e635ac2016-10-17 11:44:09 +02004151 return EXIT_SUCCESS;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004152 }
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004153 if (parent->nodetype == LYS_AUGMENT) {
4154 if (!((struct lys_node_augment *)parent)->target) {
Radek Krejcidf46e222016-11-08 11:57:37 +01004155 /* unresolved augment */
4156 if (parent->module->implemented) {
4157 /* skip for now (will be checked later) */
4158 return EXIT_FAILURE;
4159 } else {
4160 /* not implemented augment, skip resolving */
4161 return EXIT_SUCCESS;
4162 }
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004163 } else {
4164 parent = ((struct lys_node_augment *)parent)->target;
4165 continue;
4166 }
4167 }
4168 parent = parent->parent;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004169 }
Michal Vasko9e635ac2016-10-17 11:44:09 +02004170 }
4171
4172 rc = lyxp_node_atomize(node, &set);
4173 if (rc) {
4174 return rc;
4175 }
4176
4177 for (parent = node; parent && !(parent->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); parent = lys_parent(parent));
4178
4179 for (i = 0; i < set.used; ++i) {
4180 /* skip roots'n'stuff */
4181 if (set.val.snodes[i].type == LYXP_NODE_ELEM) {
4182 /* XPath expression cannot reference "lower" status than the node that has the definition */
4183 if (lyp_check_status(node->flags, lys_node_module(node), node->name, set.val.snodes[i].snode->flags,
4184 lys_node_module(set.val.snodes[i].snode), set.val.snodes[i].snode->name, node)) {
4185 return -1;
4186 }
4187
4188 if (parent) {
4189 for (elem = set.val.snodes[i].snode; elem && (elem != parent); elem = lys_parent(elem));
4190 if (!elem) {
4191 /* not in node's RPC or notification subtree, set the flag */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01004192 node->flags |= LYS_XPATH_DEP;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004193 break;
4194 }
4195 }
4196 }
4197 }
4198
4199 free(set.val.snodes);
4200 return EXIT_SUCCESS;
4201}
4202
Radek Krejcif71f48f2016-10-25 16:37:24 +02004203static int
4204check_leafref_config(struct lys_node_leaf *leaf, struct lys_type *type)
4205{
4206 int i;
4207
4208 if (type->base == LY_TYPE_LEAFREF) {
4209 if ((leaf->flags & LYS_CONFIG_W) && type->info.lref.target && (type->info.lref.target->flags & LYS_CONFIG_R)) {
4210 LOGVAL(LYE_SPEC, LY_VLOG_LYS, leaf, "The %s is config but refers to a non-config %s.",
4211 strnodetype(leaf->nodetype), strnodetype(type->info.lref.target->nodetype));
4212 return -1;
4213 }
4214 /* we can skip the test in case the leafref is not yet resolved. In that case the test is done in the time
4215 * of leafref resolving (lys_leaf_add_leafref_target()) */
4216 } else if (type->base == LY_TYPE_UNION) {
4217 for (i = 0; i < type->info.uni.count; i++) {
4218 if (check_leafref_config(leaf, &type->info.uni.types[i])) {
4219 return -1;
4220 }
4221 }
4222 }
4223 return 0;
4224}
4225
Michal Vasko9e635ac2016-10-17 11:44:09 +02004226/**
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004227 * @brief Passes config flag down to children, skips nodes without config flags.
4228 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004229 *
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004230 * @param[in] node Siblings and their children to have flags changed.
Michal Vaskoe022a562016-09-27 14:24:15 +02004231 * @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 +02004232 * @param[in] flags Flags to assign to all the nodes.
Radek Krejcib3142312016-11-09 11:04:12 +01004233 * @param[in,out] unres List of unresolved items.
Michal Vaskoa86508c2016-08-26 14:30:19 +02004234 *
4235 * @return 0 on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004236 */
Michal Vaskoa86508c2016-08-26 14:30:19 +02004237static int
Radek Krejcib3142312016-11-09 11:04:12 +01004238inherit_config_flag(struct lys_node *node, int flags, int clear, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004239{
Radek Krejcif71f48f2016-10-25 16:37:24 +02004240 struct lys_node_leaf *leaf;
4241
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004242 assert(!(flags ^ (flags & LYS_CONFIG_MASK)));
Radek Krejci1d82ef62015-08-07 14:44:40 +02004243 LY_TREE_FOR(node, node) {
Radek Krejcib3142312016-11-09 11:04:12 +01004244 if (lys_has_xpath(node) && unres_schema_add_node(node->module, unres, node, UNRES_XPATH, NULL) == -1) {
Michal Vasko9e635ac2016-10-17 11:44:09 +02004245 return -1;
4246 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004247 if (clear) {
4248 node->flags &= ~LYS_CONFIG_MASK;
Michal Vaskoc2a8d362016-09-29 08:50:13 +02004249 node->flags &= ~LYS_CONFIG_SET;
Michal Vaskoe022a562016-09-27 14:24:15 +02004250 } else {
4251 if (node->flags & LYS_CONFIG_SET) {
4252 /* skip nodes with an explicit config value */
4253 if ((flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
4254 LOGVAL(LYE_INARG, LY_VLOG_LYS, node, "true", "config");
4255 LOGVAL(LYE_SPEC, LY_VLOG_LYS, node, "State nodes cannot have configuration nodes as children.");
4256 return -1;
4257 }
4258 continue;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004259 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004260
4261 if (!(node->nodetype & (LYS_USES | LYS_GROUPING))) {
4262 node->flags = (node->flags & ~LYS_CONFIG_MASK) | flags;
4263 /* check that configuration lists have keys */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004264 if ((node->nodetype == LYS_LIST) && (node->flags & LYS_CONFIG_W)
4265 && !((struct lys_node_list *)node)->keys_size) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004266 LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_LYS, node, "key", "list");
4267 return -1;
4268 }
4269 }
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004270 }
Radek Krejcibf2abff2016-08-23 15:51:52 +02004271 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Radek Krejcib3142312016-11-09 11:04:12 +01004272 if (inherit_config_flag(node->child, flags, clear, unres)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004273 return -1;
4274 }
Radek Krejcif71f48f2016-10-25 16:37:24 +02004275 } else if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
4276 leaf = (struct lys_node_leaf *)node;
4277 if (check_leafref_config(leaf, &leaf->type)) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02004278 return -1;
4279 }
4280 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004281 }
Michal Vaskoa86508c2016-08-26 14:30:19 +02004282
4283 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004284}
4285
Michal Vasko730dfdf2015-08-11 14:48:05 +02004286/**
Michal Vasko7178e692016-02-12 15:58:05 +01004287 * @brief Resolve augment target. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004288 *
Michal Vaskobb211122015-08-19 14:03:11 +02004289 * @param[in] aug Augment to use.
Michal Vasko3edeaf72016-02-11 13:17:43 +01004290 * @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 +01004291 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004292 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004293 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004294 */
Michal Vasko7178e692016-02-12 15:58:05 +01004295static int
Radek Krejcib3142312016-11-09 11:04:12 +01004296resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004297{
Michal Vaskoe022a562016-09-27 14:24:15 +02004298 int rc, clear_config;
Michal Vasko1d87a922015-08-21 12:57:16 +02004299 struct lys_node *sub;
Pavol Vican47319932016-08-29 09:14:47 +02004300 const struct lys_node *aug_target, *parent;
Radek Krejci27fe55e2016-09-13 17:13:35 +02004301 struct lys_module *mod;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004302
Michal Vasko15b36692016-08-26 15:29:54 +02004303 assert(aug && !aug->target);
Radek Krejcidf46e222016-11-08 11:57:37 +01004304 mod = lys_main_module(aug->module);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004305
Michal Vasko15b36692016-08-26 15:29:54 +02004306 /* resolve target node */
Radek Krejcidf46e222016-11-08 11:57:37 +01004307 rc = resolve_augment_schema_nodeid(aug->target_name, siblings, (siblings ? NULL : aug->module), mod->implemented, &aug_target);
Michal Vasko15b36692016-08-26 15:29:54 +02004308 if (rc == -1) {
4309 return -1;
Radek Krejci5fb4c382016-11-28 09:21:42 +01004310 } else if (rc > 0) {
Michal Vasko15b36692016-08-26 15:29:54 +02004311 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, aug, aug->target_name[rc - 1], &aug->target_name[rc - 1]);
4312 return -1;
Radek Krejci5fb4c382016-11-28 09:21:42 +01004313 } else if (rc == 0 && aug->target) {
4314 /* augment was resolved as a side effect of setting module implemented when
4315 * resolving augment schema nodeid, so we are done here */
4316 return 0;
Michal Vasko15b36692016-08-26 15:29:54 +02004317 }
Radek Krejcidf46e222016-11-08 11:57:37 +01004318 if (!aug_target && mod->implemented) {
Michal Vasko15b36692016-08-26 15:29:54 +02004319 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
4320 return EXIT_FAILURE;
4321 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02004322 /* check that we want to connect augment into its target */
Radek Krejci27fe55e2016-09-13 17:13:35 +02004323 if (!mod->implemented) {
4324 /* it must be augment only to the same module,
4325 * otherwise we do not apply augment in not-implemented
4326 * module. If the module is set to be implemented in future,
4327 * the augment is being resolved and checked again */
Radek Krejcidf46e222016-11-08 11:57:37 +01004328 if (!aug_target) {
4329 /* target was not even resolved */
4330 return EXIT_SUCCESS;
4331 }
4332 /* target was resolved, but it may refer another module */
4333 for (sub = (struct lys_node *)aug_target; sub; sub = lys_parent(sub)) {
Radek Krejci27fe55e2016-09-13 17:13:35 +02004334 if (lys_node_module(sub) != mod) {
4335 /* this is not an implemented module and the augment
4336 * target some other module, so avoid its connecting
4337 * to the target */
4338 return EXIT_SUCCESS;
4339 }
4340 }
4341 }
4342
Michal Vasko15b36692016-08-26 15:29:54 +02004343 if (!aug->child) {
4344 /* nothing to do */
4345 LOGWRN("Augment \"%s\" without children.", aug->target_name);
Radek Krejci27fe55e2016-09-13 17:13:35 +02004346 goto success;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004347 }
4348
Michal Vaskod58d5962016-03-02 14:29:41 +01004349 /* check for mandatory nodes - if the target node is in another module
4350 * the added nodes cannot be mandatory
4351 */
Michal Vasko15b36692016-08-26 15:29:54 +02004352 if (!aug->parent && (lys_node_module((struct lys_node *)aug) != lys_node_module(aug_target))
Radek Krejcidf24cbe2016-11-08 11:55:51 +01004353 && (rc = lyp_check_mandatory_augment(aug, aug_target))) {
Radek Krejcie00d2312016-08-12 15:27:49 +02004354 return rc;
Michal Vaskod58d5962016-03-02 14:29:41 +01004355 }
4356
Michal Vasko07e89ef2016-03-03 13:28:57 +01004357 /* check augment target type and then augment nodes type */
Michal Vasko15b36692016-08-26 15:29:54 +02004358 if (aug_target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF)) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004359 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004360 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES | LYS_CHOICE))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004361 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4362 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko15b36692016-08-26 15:29:54 +02004363 strnodetype(aug_target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004364 return -1;
4365 }
4366 }
Michal Vasko15b36692016-08-26 15:29:54 +02004367 } else if (aug_target->nodetype == LYS_CHOICE) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004368 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004369 if (!(sub->nodetype & (LYS_CASE | LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004370 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4371 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko15b36692016-08-26 15:29:54 +02004372 strnodetype(aug_target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004373 return -1;
4374 }
4375 }
4376 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01004377 LOGVAL(LYE_INARG, LY_VLOG_LYS, aug, aug->target_name, "target-node");
Michal Vasko15b36692016-08-26 15:29:54 +02004378 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Invalid augment target node type \"%s\".", strnodetype(aug_target->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004379 return -1;
4380 }
4381
Radek Krejcic071c542016-01-27 14:57:51 +01004382 /* check identifier uniqueness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02004383 LY_TREE_FOR(aug->child, sub) {
Michal Vasko15b36692016-08-26 15:29:54 +02004384 if (lys_check_id(sub, (struct lys_node *)aug_target, NULL)) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02004385 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02004386 }
4387 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004388
Michal Vasko15b36692016-08-26 15:29:54 +02004389 /* finally reconnect augmenting data into the target - add them to the target child list,
4390 * by setting aug->target we know the augment is fully resolved now */
4391 aug->target = (struct lys_node *)aug_target;
4392 if (aug->target->child) {
4393 sub = aug->target->child->prev; /* remember current target's last node */
4394 sub->next = aug->child; /* connect augmenting data after target's last node */
4395 aug->target->child->prev = aug->child->prev; /* new target's last node is last augmenting node */
4396 aug->child->prev = sub; /* finish connecting of both child lists */
4397 } else {
4398 aug->target->child = aug->child;
4399 }
4400
Michal Vasko9e635ac2016-10-17 11:44:09 +02004401 /* inherit config information from actual parent */
4402 for(parent = aug_target; parent && !(parent->nodetype & (LYS_NOTIF | LYS_INPUT | LYS_OUTPUT | LYS_RPC)); parent = lys_parent(parent));
4403 clear_config = (parent) ? 1 : 0;
4404 LY_TREE_FOR(aug->child, sub) {
Radek Krejcib3142312016-11-09 11:04:12 +01004405 if (inherit_config_flag(sub, aug_target->flags & LYS_CONFIG_MASK, clear_config, unres)) {
Michal Vasko9e635ac2016-10-17 11:44:09 +02004406 return -1;
4407 }
4408 }
4409
Radek Krejci27fe55e2016-09-13 17:13:35 +02004410success:
4411 if (mod->implemented) {
4412 /* make target modules also implemented */
4413 for (sub = aug->target; sub; sub = lys_parent(sub)) {
4414 if (lys_set_implemented(sub->module)) {
4415 return -1;
4416 }
4417 }
4418 }
4419
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004420 return EXIT_SUCCESS;
4421}
4422
Michal Vasko730dfdf2015-08-11 14:48:05 +02004423/**
Pavol Vican855ca622016-09-05 13:07:54 +02004424 * @brief Resolve (find) choice default case. Does not log.
4425 *
4426 * @param[in] choic Choice to use.
4427 * @param[in] dflt Name of the default case.
4428 *
4429 * @return Pointer to the default node or NULL.
4430 */
4431static struct lys_node *
4432resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
4433{
4434 struct lys_node *child, *ret;
4435
4436 LY_TREE_FOR(choic->child, child) {
4437 if (child->nodetype == LYS_USES) {
4438 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
4439 if (ret) {
4440 return ret;
4441 }
4442 }
4443
4444 if (ly_strequal(child->name, dflt, 1) && (child->nodetype & (LYS_ANYDATA | LYS_CASE
Radek Krejci2f792db2016-09-12 10:52:33 +02004445 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE))) {
Pavol Vican855ca622016-09-05 13:07:54 +02004446 return child;
4447 }
4448 }
4449
4450 return NULL;
4451}
4452
4453/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02004454 * @brief Resolve uses, apply augments, refines. Logs directly.
4455 *
Michal Vaskobb211122015-08-19 14:03:11 +02004456 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004457 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004458 *
Michal Vaskodef0db12015-10-07 13:22:48 +02004459 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004460 */
Michal Vasko184521f2015-09-24 13:14:26 +02004461static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004462resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004463{
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004464 struct ly_ctx *ctx = uses->module->ctx; /* shortcut */
Pavol Vican855ca622016-09-05 13:07:54 +02004465 struct lys_node *node = NULL, *next, *iter, **refine_nodes = NULL;
Pavol Vican55abd332016-07-12 15:54:49 +02004466 struct lys_node *node_aux, *parent, *tmp;
Radek Krejci200bf712016-08-16 17:11:04 +02004467 struct lys_node_leaflist *llist;
4468 struct lys_node_leaf *leaf;
Radek Krejci76512572015-08-04 09:47:08 +02004469 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004470 struct lys_restr *must, **old_must;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004471 struct lys_iffeature *iff, **old_iff;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004472 int i, j, k, rc;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004473 uint8_t size, *old_size;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004474 unsigned int usize, usize1, usize2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004475
Michal Vasko71e1aa82015-08-12 12:17:51 +02004476 assert(uses->grp);
Michal Vaskoe7708512016-03-11 10:26:55 +01004477 /* HACK just check that the grouping is resolved */
Michal Vaskodef0db12015-10-07 13:22:48 +02004478 assert(!uses->grp->nacm);
Michal Vasko71e1aa82015-08-12 12:17:51 +02004479
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004480 if (!uses->grp->child) {
4481 /* grouping without children, warning was already displayed */
4482 return EXIT_SUCCESS;
4483 }
4484
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004485 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01004486 LY_TREE_FOR(uses->grp->child, node_aux) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004487 node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, uses->nacm, unres, 0);
Michal Vasko1e62a092015-12-01 12:27:20 +01004488 if (!node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004489 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, uses->grp->name, "uses");
4490 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Copying data from grouping failed.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004491 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004492 }
Pavol Vican55abd332016-07-12 15:54:49 +02004493 /* test the name of siblings */
4494 LY_TREE_FOR((uses->parent) ? uses->parent->child : lys_main_module(uses->module)->data, tmp) {
Pavol Vican2510ddc2016-07-18 16:23:44 +02004495 if (!(tmp->nodetype & (LYS_USES | LYS_GROUPING | LYS_CASE)) && ly_strequal(tmp->name, node_aux->name, 1)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004496 goto fail;
Pavol Vican55abd332016-07-12 15:54:49 +02004497 }
4498 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004499 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004500
Michal Vaskodef0db12015-10-07 13:22:48 +02004501 /* we managed to copy the grouping, the rest must be possible to resolve */
4502
Pavol Vican855ca622016-09-05 13:07:54 +02004503 if (uses->refine_size) {
4504 refine_nodes = malloc(uses->refine_size * sizeof *refine_nodes);
4505 if (!refine_nodes) {
4506 LOGMEM;
4507 goto fail;
4508 }
4509 }
4510
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004511 /* apply refines */
4512 for (i = 0; i < uses->refine_size; i++) {
4513 rfn = &uses->refine[i];
Michal Vasko3edeaf72016-02-11 13:17:43 +01004514 rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child, LYS_NO_RPC_NOTIF_NODE,
Radek Krejcif3c71de2016-04-11 12:45:46 +02004515 1, 0, (const struct lys_node **)&node);
Michal Vasko9bb061b2016-02-12 11:00:19 +01004516 if (rc || !node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004517 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004518 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004519 }
4520
Radek Krejci1d82ef62015-08-07 14:44:40 +02004521 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004522 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
4523 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Refine substatements not applicable to the target-node.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004524 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004525 }
Pavol Vican855ca622016-09-05 13:07:54 +02004526 refine_nodes[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004527
4528 /* description on any nodetype */
4529 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004530 lydict_remove(ctx, node->dsc);
4531 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004532 }
4533
4534 /* reference on any nodetype */
4535 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004536 lydict_remove(ctx, node->ref);
4537 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004538 }
4539
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004540 /* config on any nodetype,
4541 * in case of notification or rpc/action, the config is not applicable (there is no config status) */
4542 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004543 node->flags &= ~LYS_CONFIG_MASK;
4544 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004545 }
4546
4547 /* default value ... */
Radek Krejci200bf712016-08-16 17:11:04 +02004548 if (rfn->dflt_size) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004549 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004550 /* leaf */
Radek Krejci200bf712016-08-16 17:11:04 +02004551 leaf = (struct lys_node_leaf *)node;
4552
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004553 /* replace default value */
Radek Krejci200bf712016-08-16 17:11:04 +02004554 lydict_remove(ctx, leaf->dflt);
4555 leaf->dflt = lydict_insert(ctx, rfn->dflt[0], 0);
4556
4557 /* check the default value */
Radek Krejci51673202016-11-01 17:00:32 +01004558 if (unres_schema_add_node(leaf->module, unres, &leaf->type, UNRES_TYPE_DFLT,
4559 (struct lys_node *)(&leaf->dflt)) == -1) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004560 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004561 }
Radek Krejci200bf712016-08-16 17:11:04 +02004562 } else if (node->nodetype == LYS_LEAFLIST) {
4563 /* leaf-list */
4564 llist = (struct lys_node_leaflist *)node;
4565
4566 /* remove complete set of defaults in target */
4567 for (i = 0; i < llist->dflt_size; i++) {
4568 lydict_remove(ctx, llist->dflt[i]);
4569 }
4570 free(llist->dflt);
4571
4572 /* copy the default set from refine */
4573 llist->dflt_size = rfn->dflt_size;
4574 llist->dflt = malloc(llist->dflt_size * sizeof *llist->dflt);
4575 for (i = 0; i < llist->dflt_size; i++) {
4576 llist->dflt[i] = lydict_insert(ctx, rfn->dflt[i], 0);
4577 }
4578
4579 /* check default value */
4580 for (i = 0; i < llist->dflt_size; i++) {
Radek Krejci51673202016-11-01 17:00:32 +01004581 if (unres_schema_add_node(llist->module, unres, &llist->type, UNRES_TYPE_DFLT,
4582 (struct lys_node *)(&llist->dflt[i])) == -1) {
Pavol Vican855ca622016-09-05 13:07:54 +02004583 goto fail;
Radek Krejci200bf712016-08-16 17:11:04 +02004584 }
4585 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004586 }
4587 }
4588
4589 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02004590 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004591 if (node->nodetype & (LYS_LEAF | LYS_ANYDATA | LYS_CHOICE)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004592 /* remove current value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004593 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004594
4595 /* set new value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004596 node->flags |= (rfn->flags & LYS_MAND_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004597 }
Pavol Vican855ca622016-09-05 13:07:54 +02004598 if (rfn->flags & LYS_MAND_TRUE) {
4599 /* check if node has default value */
4600 if ((node->nodetype & LYS_LEAF) && ((struct lys_node_leaf *)node)->dflt) {
4601 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"mandatory\" statement is forbidden on leaf with \"default\".");
4602 goto fail;
4603 }
4604 if ((node->nodetype & LYS_CHOICE) && ((struct lys_node_choice *)node)->dflt) {
4605 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"mandatory\" statement is forbidden on choices with \"default\".");
4606 goto fail;
4607 }
4608 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004609 }
4610
4611 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004612 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
4613 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
4614 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004615 }
4616
4617 /* min/max-elements on list or leaf-list */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004618 if (node->nodetype == LYS_LIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004619 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004620 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004621 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004622 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004623 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004624 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02004625 } else if (node->nodetype == LYS_LEAFLIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004626 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004627 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004628 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004629 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004630 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004631 }
4632 }
4633
4634 /* must in leaf, leaf-list, list, container or anyxml */
4635 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004636 switch (node->nodetype) {
4637 case LYS_LEAF:
4638 old_size = &((struct lys_node_leaf *)node)->must_size;
4639 old_must = &((struct lys_node_leaf *)node)->must;
4640 break;
4641 case LYS_LEAFLIST:
4642 old_size = &((struct lys_node_leaflist *)node)->must_size;
4643 old_must = &((struct lys_node_leaflist *)node)->must;
4644 break;
4645 case LYS_LIST:
4646 old_size = &((struct lys_node_list *)node)->must_size;
4647 old_must = &((struct lys_node_list *)node)->must;
4648 break;
4649 case LYS_CONTAINER:
4650 old_size = &((struct lys_node_container *)node)->must_size;
4651 old_must = &((struct lys_node_container *)node)->must;
4652 break;
4653 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02004654 case LYS_ANYDATA:
4655 old_size = &((struct lys_node_anydata *)node)->must_size;
4656 old_must = &((struct lys_node_anydata *)node)->must;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004657 break;
4658 default:
4659 LOGINT;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004660 goto fail;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004661 }
4662
4663 size = *old_size + rfn->must_size;
4664 must = realloc(*old_must, size * sizeof *rfn->must);
4665 if (!must) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004666 LOGMEM;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004667 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004668 }
Pavol Vican855ca622016-09-05 13:07:54 +02004669 for (k = 0, j = *old_size; k < rfn->must_size; k++, j++) {
4670 must[j].expr = lydict_insert(ctx, rfn->must[k].expr, 0);
4671 must[j].dsc = lydict_insert(ctx, rfn->must[k].dsc, 0);
4672 must[j].ref = lydict_insert(ctx, rfn->must[k].ref, 0);
4673 must[j].eapptag = lydict_insert(ctx, rfn->must[k].eapptag, 0);
4674 must[j].emsg = lydict_insert(ctx, rfn->must[k].emsg, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004675 }
4676
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004677 *old_must = must;
4678 *old_size = size;
Michal Vasko508a50d2016-09-07 14:50:33 +02004679
4680 /* check XPath dependencies again */
4681 if (unres_schema_add_node(node->module, unres, node, UNRES_XPATH, NULL) == -1) {
4682 goto fail;
4683 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004684 }
Radek Krejci363bd4a2016-07-29 14:30:20 +02004685
4686 /* if-feature in leaf, leaf-list, list, container or anyxml */
4687 if (rfn->iffeature_size) {
4688 old_size = &node->iffeature_size;
4689 old_iff = &node->iffeature;
4690
4691 size = *old_size + rfn->iffeature_size;
4692 iff = realloc(*old_iff, size * sizeof *rfn->iffeature);
4693 if (!iff) {
4694 LOGMEM;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004695 goto fail;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004696 }
Pavol Vican855ca622016-09-05 13:07:54 +02004697 for (k = 0, j = *old_size; k < rfn->iffeature_size; k++, j++) {
4698 resolve_iffeature_getsizes(&rfn->iffeature[k], &usize1, &usize2);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004699 if (usize1) {
4700 /* there is something to duplicate */
4701 /* duplicate compiled expression */
4702 usize = (usize1 / 4) + (usize1 % 4) ? 1 : 0;
4703 iff[j].expr = malloc(usize * sizeof *iff[j].expr);
Pavol Vican855ca622016-09-05 13:07:54 +02004704 memcpy(iff[j].expr, rfn->iffeature[k].expr, usize * sizeof *iff[j].expr);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004705
4706 /* duplicate list of feature pointers */
Pavol Vican855ca622016-09-05 13:07:54 +02004707 iff[j].features = malloc(usize2 * sizeof *iff[k].features);
4708 memcpy(iff[j].features, rfn->iffeature[k].features, usize2 * sizeof *iff[j].features);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004709 }
4710 }
4711
4712 *old_iff = iff;
4713 *old_size = size;
4714 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004715 }
4716
4717 /* apply augments */
4718 for (i = 0; i < uses->augment_size; i++) {
Radek Krejcib3142312016-11-09 11:04:12 +01004719 rc = resolve_augment(&uses->augment[i], uses->child, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004720 if (rc) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004721 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004722 }
4723 }
4724
Pavol Vican855ca622016-09-05 13:07:54 +02004725 /* check refines */
4726 for (i = 0; i < uses->refine_size; i++) {
4727 node = refine_nodes[i];
4728 rfn = &uses->refine[i];
4729
4730 /* config on any nodetype */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004731 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Pavol Vican855ca622016-09-05 13:07:54 +02004732 for (parent = lys_parent(node); parent && parent->nodetype == LYS_USES; parent = lys_parent(parent));
Radek Krejci5c08a992016-11-02 13:30:04 +01004733 if (parent && parent->nodetype != LYS_GROUPING && (parent->flags & LYS_CONFIG_MASK) &&
Pavol Vican855ca622016-09-05 13:07:54 +02004734 ((parent->flags & LYS_CONFIG_MASK) != (rfn->flags & LYS_CONFIG_MASK)) &&
4735 (rfn->flags & LYS_CONFIG_W)) {
4736 /* setting config true under config false is prohibited */
4737 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
4738 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4739 "changing config from 'false' to 'true' is prohibited while "
4740 "the target's parent is still config 'false'.");
4741 goto fail;
4742 }
4743
4744 /* inherit config change to the target children */
4745 LY_TREE_DFS_BEGIN(node->child, next, iter) {
4746 if (rfn->flags & LYS_CONFIG_W) {
4747 if (iter->flags & LYS_CONFIG_SET) {
4748 /* config is set explicitely, go to next sibling */
4749 next = NULL;
4750 goto nextsibling;
4751 }
4752 } else { /* LYS_CONFIG_R */
4753 if ((iter->flags & LYS_CONFIG_SET) && (iter->flags & LYS_CONFIG_W)) {
4754 /* error - we would have config data under status data */
4755 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
4756 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4757 "changing config from 'true' to 'false' is prohibited while the target "
4758 "has still a children with explicit config 'true'.");
4759 goto fail;
4760 }
4761 }
4762 /* change config */
4763 iter->flags &= ~LYS_CONFIG_MASK;
4764 iter->flags |= (rfn->flags & LYS_CONFIG_MASK);
4765
4766 /* select next iter - modified LY_TREE_DFS_END */
4767 if (iter->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
4768 next = NULL;
4769 } else {
4770 next = iter->child;
4771 }
4772nextsibling:
4773 if (!next) {
4774 /* try siblings */
4775 next = iter->next;
4776 }
4777 while (!next) {
4778 /* parent is already processed, go to its sibling */
4779 iter = lys_parent(iter);
4780
4781 /* no siblings, go back through parents */
4782 if (iter == node) {
4783 /* we are done, no next element to process */
4784 break;
4785 }
4786 next = iter->next;
4787 }
4788 }
4789 }
4790
4791 /* default value */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004792 if (rfn->dflt_size) {
4793 if (node->nodetype == LYS_CHOICE) {
4794 /* choice */
4795 ((struct lys_node_choice *)node)->dflt = resolve_choice_dflt((struct lys_node_choice *)node,
4796 rfn->dflt[0]);
4797 if (!((struct lys_node_choice *)node)->dflt) {
4798 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->dflt[0], "default");
4799 goto fail;
4800 }
4801 if (lyp_check_mandatory_choice(node)) {
4802 goto fail;
4803 }
Pavol Vican855ca622016-09-05 13:07:54 +02004804 }
4805 }
4806
4807 /* min/max-elements on list or leaf-list */
4808 if (node->nodetype == LYS_LIST) {
4809 if (((struct lys_node_list *)node)->min > ((struct lys_node_list *)node)->max) {
4810 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
4811 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "\"min-elements\" is bigger than \"max-elements\".");
4812 goto fail;
4813 }
4814 } else if (node->nodetype == LYS_LEAFLIST) {
4815 if (((struct lys_node_leaflist *)node)->min > ((struct lys_node_leaflist *)node)->max) {
4816 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
4817 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "\"min-elements\" is bigger than \"max-elements\".");
4818 goto fail;
4819 }
4820 }
4821
4822 /* additional checks */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004823 /* default value with mandatory/min-elements */
Pavol Vican855ca622016-09-05 13:07:54 +02004824 if (node->nodetype == LYS_LEAFLIST) {
4825 llist = (struct lys_node_leaflist *)node;
4826 if (llist->dflt_size && llist->min) {
4827 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, rfn->dflt_size ? "default" : "min-elements", "refine");
4828 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
4829 "The \"min-elements\" statement with non-zero value is forbidden on leaf-lists with the \"default\" statement.");
4830 goto fail;
4831 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004832 } else if (node->nodetype == LYS_LEAF) {
4833 leaf = (struct lys_node_leaf *)node;
4834 if (leaf->dflt && (leaf->flags & LYS_MAND_TRUE)) {
4835 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, rfn->dflt_size ? "default" : "mandatory", "refine");
4836 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
4837 "The \"mandatory\" statement is forbidden on leafs with the \"default\" statement.");
4838 goto fail;
4839 }
Pavol Vican855ca622016-09-05 13:07:54 +02004840 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004841
Pavol Vican855ca622016-09-05 13:07:54 +02004842 /* check for mandatory node in default case, first find the closest parent choice to the changed node */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004843 if ((rfn->flags & LYS_MAND_TRUE) || rfn->mod.list.min) {
Pavol Vican855ca622016-09-05 13:07:54 +02004844 for (parent = node->parent;
4845 parent && !(parent->nodetype & (LYS_CHOICE | LYS_GROUPING | LYS_ACTION | LYS_USES));
4846 parent = parent->parent) {
4847 if (parent->nodetype == LYS_CONTAINER && ((struct lys_node_container *)parent)->presence) {
4848 /* stop also on presence containers */
4849 break;
4850 }
4851 }
4852 /* and if it is a choice with the default case, check it for presence of a mandatory node in it */
4853 if (parent && parent->nodetype == LYS_CHOICE && ((struct lys_node_choice *)parent)->dflt) {
4854 if (lyp_check_mandatory_choice(parent)) {
4855 goto fail;
4856 }
4857 }
4858 }
4859 }
4860 free(refine_nodes);
4861
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004862 return EXIT_SUCCESS;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004863
4864fail:
4865 LY_TREE_FOR_SAFE(uses->child, next, iter) {
4866 lys_node_free(iter, NULL, 0);
4867 }
Pavol Vican855ca622016-09-05 13:07:54 +02004868 free(refine_nodes);
Michal Vaskoa86508c2016-08-26 14:30:19 +02004869 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004870}
4871
Radek Krejci018f1f52016-08-03 16:01:20 +02004872static int
4873identity_backlink_update(struct lys_ident *der, struct lys_ident *base)
4874{
4875 int i;
4876
4877 assert(der && base);
4878
Radek Krejci018f1f52016-08-03 16:01:20 +02004879 if (!base->der) {
Radek Krejci85a54be2016-10-20 12:39:56 +02004880 /* create a set for backlinks if it does not exist */
4881 base->der = ly_set_new();
Radek Krejci018f1f52016-08-03 16:01:20 +02004882 }
Radek Krejci85a54be2016-10-20 12:39:56 +02004883 /* store backlink */
4884 ly_set_add(base->der, der, LY_SET_OPT_USEASLIST);
Radek Krejci018f1f52016-08-03 16:01:20 +02004885
Radek Krejci85a54be2016-10-20 12:39:56 +02004886 /* do it recursively */
Radek Krejci018f1f52016-08-03 16:01:20 +02004887 for (i = 0; i < base->base_size; i++) {
4888 if (identity_backlink_update(der, base->base[i])) {
4889 return EXIT_FAILURE;
4890 }
4891 }
4892
4893 return EXIT_SUCCESS;
4894}
4895
Michal Vasko730dfdf2015-08-11 14:48:05 +02004896/**
4897 * @brief Resolve base identity recursively. Does not log.
4898 *
4899 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004900 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004901 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004902 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004903 *
Radek Krejci219fa612016-08-15 10:36:51 +02004904 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on crucial error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004905 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004906static int
Michal Vasko1e62a092015-12-01 12:27:20 +01004907resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Radek Krejci018f1f52016-08-03 16:01:20 +02004908 struct unres_schema *unres, struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004909{
Michal Vaskof02e3742015-08-05 16:27:02 +02004910 uint32_t i, j;
Radek Krejci018f1f52016-08-03 16:01:20 +02004911 struct lys_ident *base = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004912
Radek Krejcicf509982015-12-15 09:22:44 +01004913 assert(ret);
4914
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004915 /* search module */
4916 for (i = 0; i < module->ident_size; i++) {
4917 if (!strcmp(basename, module->ident[i].name)) {
4918
4919 if (!ident) {
4920 /* just search for type, so do not modify anything, just return
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004921 * the base identity pointer */
Radek Krejcicf509982015-12-15 09:22:44 +01004922 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004923 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004924 }
4925
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004926 base = &module->ident[i];
4927 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004928 }
4929 }
4930
4931 /* search submodules */
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004932 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
4933 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
4934 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004935
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004936 if (!ident) {
4937 *ret = &module->inc[j].submodule->ident[i];
4938 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004939 }
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004940
4941 base = &module->inc[j].submodule->ident[i];
4942 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004943 }
4944 }
4945 }
4946
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004947matchfound:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004948 /* we found it somewhere */
Radek Krejcibabbff82016-02-19 13:31:37 +01004949 if (base) {
Radek Krejci018f1f52016-08-03 16:01:20 +02004950 /* is it already completely resolved? */
4951 for (i = 0; i < unres->count; i++) {
Radek Krejciba7b1cc2016-08-08 13:44:43 +02004952 if ((unres->item[i] == base) && (unres->type[i] == UNRES_IDENT)) {
Radek Krejci018f1f52016-08-03 16:01:20 +02004953 /* identity found, but not yet resolved, so do not return it in *res and try it again later */
4954
4955 /* simple check for circular reference,
4956 * the complete check is done as a side effect of using only completely
4957 * resolved identities (previous check of unres content) */
4958 if (ly_strequal((const char *)unres->str_snode[i], ident->name, 1)) {
4959 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, basename, "base");
4960 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Circular reference of \"%s\" identity.", basename);
Radek Krejci219fa612016-08-15 10:36:51 +02004961 return -1;
Radek Krejci018f1f52016-08-03 16:01:20 +02004962 }
4963
Radek Krejci06f64ed2016-08-15 11:07:44 +02004964 return EXIT_FAILURE;
Radek Krejcibabbff82016-02-19 13:31:37 +01004965 }
4966 }
Radek Krejci018f1f52016-08-03 16:01:20 +02004967
Radek Krejcibabbff82016-02-19 13:31:37 +01004968 /* checks done, store the result */
Radek Krejci018f1f52016-08-03 16:01:20 +02004969 *ret = base;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02004970 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004971 }
4972
Radek Krejci219fa612016-08-15 10:36:51 +02004973 /* base not found (maybe a forward reference) */
4974 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004975}
4976
Michal Vasko730dfdf2015-08-11 14:48:05 +02004977/**
4978 * @brief Resolve base identity. Logs directly.
4979 *
4980 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004981 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004982 * @param[in] basename Base name of the identity.
Radek Krejcibabbff82016-02-19 13:31:37 +01004983 * @param[in] parent Either "type" or "identity".
Radek Krejcicf509982015-12-15 09:22:44 +01004984 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004985 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004986 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004987 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004988static int
Michal Vaskof2d43962016-09-02 11:10:16 +02004989resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char *parent,
Radek Krejci018f1f52016-08-03 16:01:20 +02004990 struct lys_type *type, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004991{
4992 const char *name;
Radek Krejci219fa612016-08-15 10:36:51 +02004993 int mod_name_len = 0, rc;
Radek Krejcicf509982015-12-15 09:22:44 +01004994 struct lys_ident *target, **ret;
Radek Krejci4372b4e2016-04-14 17:42:16 +02004995 uint16_t flags;
Radek Krejcicf509982015-12-15 09:22:44 +01004996 struct lys_module *mod;
4997
4998 assert((ident && !type) || (!ident && type));
4999
5000 if (!type) {
5001 /* have ident to resolve */
5002 ret = &target;
5003 flags = ident->flags;
5004 mod = ident->module;
5005 } else {
5006 /* have type to fill */
Michal Vaskof2d43962016-09-02 11:10:16 +02005007 ++type->info.ident.count;
5008 type->info.ident.ref = ly_realloc(type->info.ident.ref, type->info.ident.count * sizeof *type->info.ident.ref);
5009 if (!type->info.ident.ref) {
5010 LOGMEM;
5011 return -1;
5012 }
5013
5014 ret = &type->info.ident.ref[type->info.ident.count - 1];
Radek Krejcicf509982015-12-15 09:22:44 +01005015 flags = type->parent->flags;
5016 mod = type->parent->module;
5017 }
Michal Vaskof2006002016-04-21 16:28:15 +02005018 *ret = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005019
5020 /* search for the base identity */
5021 name = strchr(basename, ':');
5022 if (name) {
5023 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02005024 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005025 name++;
5026
Michal Vasko2d851a92015-10-20 16:16:36 +02005027 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005028 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02005029 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005030 }
5031 } else {
5032 name = basename;
5033 }
5034
Radek Krejcic071c542016-01-27 14:57:51 +01005035 /* get module where to search */
5036 module = lys_get_import_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len);
5037 if (!module) {
5038 /* identity refers unknown data model */
Radek Krejci02a04992016-03-17 16:06:37 +01005039 LOGVAL(LYE_INMOD, LY_VLOG_NONE, NULL, basename);
Radek Krejcic071c542016-01-27 14:57:51 +01005040 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005041 }
5042
Radek Krejcic071c542016-01-27 14:57:51 +01005043 /* search in the identified module ... */
Radek Krejci219fa612016-08-15 10:36:51 +02005044 rc = resolve_base_ident_sub(module, ident, name, unres, ret);
5045 if (!rc) {
5046 assert(*ret);
5047
5048 /* check status */
5049 if (lyp_check_status(flags, mod, ident ? ident->name : "of type",
5050 (*ret)->flags, (*ret)->module, (*ret)->name, NULL)) {
5051 rc = -1;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02005052 } else {
5053 if (ident) {
5054 ident->base[ident->base_size++] = *ret;
5055
5056 /* maintain backlinks to the derived identities */
5057 rc = identity_backlink_update(ident, *ret) ? -1 : EXIT_SUCCESS;
5058 }
Radek Krejci219fa612016-08-15 10:36:51 +02005059 }
5060 } else if (rc == EXIT_FAILURE) {
5061 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, parent, basename);
Pavol Vican053a2882016-09-05 14:40:33 +02005062 if (type) {
5063 --type->info.ident.count;
5064 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005065 }
5066
Radek Krejci219fa612016-08-15 10:36:51 +02005067 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005068}
5069
Michal Vasko730dfdf2015-08-11 14:48:05 +02005070/**
Michal Vaskof39142b2015-10-21 11:40:05 +02005071 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005072 *
Michal Vaskof2d43962016-09-02 11:10:16 +02005073 * @param[in] type Identityref type.
Michal Vaskofb0873c2015-08-21 09:00:07 +02005074 * @param[in] ident_name Identityref name.
Radek Krejciadb57612016-02-16 13:34:34 +01005075 * @param[in] node Node where the identityref is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02005076 *
5077 * @return Pointer to the identity resolvent, NULL on error.
5078 */
Radek Krejcia52656e2015-08-05 13:41:50 +02005079struct lys_ident *
Michal Vaskof2d43962016-09-02 11:10:16 +02005080resolve_identref(struct lys_type *type, const char *ident_name, struct lyd_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005081{
Radek Krejci639491e2016-12-05 13:30:42 +01005082 const char *mod_name, *name, *mod_name_iter;
Radek Krejci85a54be2016-10-20 12:39:56 +02005083 int mod_name_len, rc, i;
5084 unsigned int u;
Michal Vaskof2d43962016-09-02 11:10:16 +02005085 struct lys_ident *der, *cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005086
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005087 assert(type && ident_name && node);
5088
Michal Vaskof2d43962016-09-02 11:10:16 +02005089 if (!type || (!type->info.ident.count && !type->der) || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005090 return NULL;
5091 }
5092
Michal Vaskoc633ca02015-08-21 14:03:51 +02005093 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, NULL);
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005094 if (rc < 1) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005095 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005096 return NULL;
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005097 } else if (rc < (signed)strlen(ident_name)) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005098 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[rc], &ident_name[rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005099 return NULL;
5100 }
Radek Krejcif32c5f62016-12-05 09:27:38 +01005101 if (!mod_name) {
5102 /* no prefix, identity must be defined in the same module as node */
Radek Krejci639491e2016-12-05 13:30:42 +01005103 mod_name = lys_main_module(node->schema->module)->name;
Radek Krejcif32c5f62016-12-05 09:27:38 +01005104 mod_name_len = strlen(mod_name);
5105 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02005106
Michal Vaskof2d43962016-09-02 11:10:16 +02005107 /* go through all the bases in all the derived types */
5108 while (type->der) {
5109 for (i = 0; i < type->info.ident.count; ++i) {
5110 cur = type->info.ident.ref[i];
Radek Krejci639491e2016-12-05 13:30:42 +01005111 mod_name_iter = lys_main_module(cur->module)->name;
Radek Krejcif32c5f62016-12-05 09:27:38 +01005112 if (!strcmp(cur->name, name) &&
Radek Krejci639491e2016-12-05 13:30:42 +01005113 !strncmp(mod_name_iter, mod_name, mod_name_len) && !mod_name_iter[mod_name_len]) {
Michal Vaskof2d43962016-09-02 11:10:16 +02005114 goto match;
5115 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02005116
Radek Krejci85a54be2016-10-20 12:39:56 +02005117 if (cur->der) {
5118 /* there are also some derived identities */
5119 for (u = 0; u < cur->der->number; u++) {
5120 der = (struct lys_ident *)cur->der->set.g[u]; /* shortcut */
Radek Krejci639491e2016-12-05 13:30:42 +01005121 mod_name_iter = lys_main_module(der->module)->name;
Radek Krejci85a54be2016-10-20 12:39:56 +02005122 if (!strcmp(der->name, name) &&
Radek Krejci639491e2016-12-05 13:30:42 +01005123 !strncmp(mod_name_iter, mod_name, mod_name_len) && !mod_name_iter[mod_name_len]) {
Radek Krejci85a54be2016-10-20 12:39:56 +02005124 /* we have match */
5125 cur = der;
5126 goto match;
5127 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005128 }
5129 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005130 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005131 type = &type->der->type;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005132 }
5133
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005134 LOGVAL(LYE_INRESOLV, LY_VLOG_LYD, node, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005135 return NULL;
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005136
5137match:
Michal Vaskof2d43962016-09-02 11:10:16 +02005138 for (i = 0; i < cur->iffeature_size; i++) {
5139 if (!resolve_iffeature(&cur->iffeature[i])) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005140 LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, cur->name, node->schema->name);
5141 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 +02005142 return NULL;
5143 }
5144 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005145 return cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005146}
5147
Michal Vasko730dfdf2015-08-11 14:48:05 +02005148/**
Michal Vaskobb211122015-08-19 14:03:11 +02005149 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005150 *
Michal Vaskobb211122015-08-19 14:03:11 +02005151 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005152 * @param[in] unres Specific unres item.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005153 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005154 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005155 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005156static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005157resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005158{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005159 int rc;
Radek Krejci010e54b2016-03-15 09:40:34 +01005160 struct lys_node *par_grp;
Michal Vaskoe91afce2015-08-12 12:21:00 +02005161
Radek Krejci010e54b2016-03-15 09:40:34 +01005162 /* HACK: when a grouping has uses inside, all such uses have to be resolved before the grouping itself
5163 * is used in some uses. When we see such a uses, the grouping's nacm member (not used in grouping)
5164 * is used to store number of so far unresolved uses. The grouping cannot be used unless the nacm
5165 * value is decreased back to 0. To remember that the uses already increased grouping's nacm, the
5166 * LYS_USESGRP flag is used. */
Michal Vaskodcf98e62016-05-05 17:53:53 +02005167 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 +02005168
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005169 if (!uses->grp) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01005170 rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
5171 if (rc == -1) {
Michal Vasko92981a62016-10-14 10:25:16 +02005172 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005173 return -1;
5174 } else if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005175 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005176 return -1;
5177 } else if (!uses->grp) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005178 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005179 /* hack - in contrast to lys_node, lys_node_grp has bigger nacm field
5180 * (and smaller flags - it uses only a limited set of flags)
5181 */
5182 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci010e54b2016-03-15 09:40:34 +01005183 uses->flags |= LYS_USESGRP;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005184 }
Michal Vasko92981a62016-10-14 10:25:16 +02005185 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005186 return EXIT_FAILURE;
Michal Vasko12e30842015-08-04 11:54:00 +02005187 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005188 }
5189
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005190 if (uses->grp->nacm) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005191 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005192 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci010e54b2016-03-15 09:40:34 +01005193 uses->flags |= LYS_USESGRP;
Radek Krejcie00d2312016-08-12 15:27:49 +02005194 } else {
5195 /* instantiate grouping only when it is completely resolved */
5196 uses->grp = NULL;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005197 }
Michal Vasko92981a62016-10-14 10:25:16 +02005198 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005199 return EXIT_FAILURE;
5200 }
5201
Radek Krejci48464ed2016-03-17 15:44:09 +01005202 rc = resolve_uses(uses, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005203 if (!rc) {
5204 /* decrease unres count only if not first try */
Radek Krejci010e54b2016-03-15 09:40:34 +01005205 if (par_grp && (uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005206 if (!((struct lys_node_grp *)par_grp)->nacm) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005207 LOGINT;
5208 return -1;
5209 }
Radek Krejci4372b4e2016-04-14 17:42:16 +02005210 ((struct lys_node_grp *)par_grp)->nacm--;
Radek Krejci010e54b2016-03-15 09:40:34 +01005211 uses->flags &= ~LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005212 }
Radek Krejcicf509982015-12-15 09:22:44 +01005213
5214 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005215 if (lyp_check_status(uses->flags, uses->module, "of uses",
Radek Krejciadb57612016-02-16 13:34:34 +01005216 uses->grp->flags, uses->grp->module, uses->grp->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005217 (struct lys_node *)uses)) {
Radek Krejcicf509982015-12-15 09:22:44 +01005218 return -1;
5219 }
5220
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005221 return EXIT_SUCCESS;
5222 }
5223
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005224 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005225}
5226
Michal Vasko730dfdf2015-08-11 14:48:05 +02005227/**
Michal Vasko9957e592015-08-17 15:04:09 +02005228 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005229 *
Michal Vaskobb211122015-08-19 14:03:11 +02005230 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005231 * @param[in] keys_str Keys node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005232 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005233 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005234 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005235static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005236resolve_list_keys(struct lys_node_list *list, const char *keys_str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005237{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005238 int i, len, rc;
Michal Vasko4f0dad02016-02-15 14:08:23 +01005239 const char *value;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005240
5241 for (i = 0; i < list->keys_size; ++i) {
Radek Krejci5c08a992016-11-02 13:30:04 +01005242 if (!list->child) {
5243 /* no child, possible forward reference */
5244 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
5245 return EXIT_FAILURE;
5246 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005247 /* get the key name */
5248 if ((value = strpbrk(keys_str, " \t\n"))) {
5249 len = value - keys_str;
5250 while (isspace(value[0])) {
5251 value++;
5252 }
5253 } else {
5254 len = strlen(keys_str);
5255 }
5256
Radek Krejcic4283442016-04-22 09:19:27 +02005257 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 +02005258 if (rc) {
Michal Vasko7a55bea2016-05-02 14:51:20 +02005259 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
5260 return EXIT_FAILURE;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005261 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005262
Radek Krejci48464ed2016-03-17 15:44:09 +01005263 if (check_key(list, i, keys_str, len)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005264 /* check_key logs */
5265 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005266 }
5267
Radek Krejcicf509982015-12-15 09:22:44 +01005268 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005269 if (lyp_check_status(list->flags, list->module, list->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005270 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
5271 (struct lys_node *)list->keys[i])) {
Radek Krejcicf509982015-12-15 09:22:44 +01005272 return -1;
5273 }
5274
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005275 /* prepare for next iteration */
5276 while (value && isspace(value[0])) {
5277 value++;
5278 }
5279 keys_str = value;
5280 }
5281
Michal Vaskof02e3742015-08-05 16:27:02 +02005282 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005283}
5284
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005285/**
Michal Vaskobf19d252015-10-08 15:39:17 +02005286 * @brief Resolve (check) all must conditions of \p node.
5287 * Logs directly.
5288 *
5289 * @param[in] node Data node with optional must statements.
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005290 * @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 +02005291 *
5292 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
5293 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005294static int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005295resolve_must(struct lyd_node *node, int inout_parent, int ignore_fail)
Michal Vaskof02e3742015-08-05 16:27:02 +02005296{
Michal Vaskobf19d252015-10-08 15:39:17 +02005297 uint8_t i, must_size;
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005298 struct lys_node *schema;
Michal Vaskobf19d252015-10-08 15:39:17 +02005299 struct lys_restr *must;
5300 struct lyxp_set set;
5301
5302 assert(node);
5303 memset(&set, 0, sizeof set);
5304
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005305 if (inout_parent) {
5306 for (schema = lys_parent(node->schema);
5307 schema && (schema->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES));
5308 schema = lys_parent(schema));
5309 if (!schema || !(schema->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5310 LOGINT;
5311 return -1;
5312 }
5313 must_size = ((struct lys_node_inout *)schema)->must_size;
5314 must = ((struct lys_node_inout *)schema)->must;
5315
5316 /* context node is the RPC/action */
5317 node = node->parent;
5318 if (!(node->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
5319 LOGINT;
5320 return -1;
5321 }
5322 } else {
5323 switch (node->schema->nodetype) {
5324 case LYS_CONTAINER:
5325 must_size = ((struct lys_node_container *)node->schema)->must_size;
5326 must = ((struct lys_node_container *)node->schema)->must;
5327 break;
5328 case LYS_LEAF:
5329 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
5330 must = ((struct lys_node_leaf *)node->schema)->must;
5331 break;
5332 case LYS_LEAFLIST:
5333 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
5334 must = ((struct lys_node_leaflist *)node->schema)->must;
5335 break;
5336 case LYS_LIST:
5337 must_size = ((struct lys_node_list *)node->schema)->must_size;
5338 must = ((struct lys_node_list *)node->schema)->must;
5339 break;
5340 case LYS_ANYXML:
5341 case LYS_ANYDATA:
5342 must_size = ((struct lys_node_anydata *)node->schema)->must_size;
5343 must = ((struct lys_node_anydata *)node->schema)->must;
5344 break;
5345 case LYS_NOTIF:
5346 must_size = ((struct lys_node_notif *)node->schema)->must_size;
5347 must = ((struct lys_node_notif *)node->schema)->must;
5348 break;
5349 default:
5350 must_size = 0;
5351 break;
5352 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005353 }
5354
5355 for (i = 0; i < must_size; ++i) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005356 if (lyxp_eval(must[i].expr, node, LYXP_NODE_ELEM, lyd_node_module(node), &set, LYXP_MUST)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02005357 return -1;
5358 }
5359
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005360 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_MUST);
Michal Vaskobf19d252015-10-08 15:39:17 +02005361
Michal Vasko8146d4c2016-05-09 15:50:29 +02005362 if (!set.val.bool) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005363 if (ignore_fail) {
5364 LOGVRB("Must condition \"%s\" not satisfied, but it is not required.", must[i].expr);
5365 } else {
5366 LOGVAL(LYE_NOMUST, LY_VLOG_LYD, node, must[i].expr);
5367 if (must[i].emsg) {
5368 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, must[i].emsg);
5369 }
5370 if (must[i].eapptag) {
5371 strncpy(((struct ly_err *)&ly_errno)->apptag, must[i].eapptag, LY_APPTAG_LEN - 1);
5372 }
5373 return 1;
Michal Vasko6ac68282016-04-11 10:56:47 +02005374 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005375 }
5376 }
5377
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005378 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02005379}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005380
Michal Vaskobf19d252015-10-08 15:39:17 +02005381/**
Michal Vasko508a50d2016-09-07 14:50:33 +02005382 * @brief Resolve (find) when condition schema context node. Does not log.
5383 *
5384 * @param[in] schema Schema node with the when condition.
5385 * @param[out] ctx_snode When schema context node.
5386 * @param[out] ctx_snode_type Schema context node type.
5387 */
5388void
5389resolve_when_ctx_snode(const struct lys_node *schema, struct lys_node **ctx_snode, enum lyxp_node_type *ctx_snode_type)
5390{
5391 const struct lys_node *sparent;
5392
5393 /* find a not schema-only node */
5394 *ctx_snode_type = LYXP_NODE_ELEM;
5395 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
5396 if (schema->nodetype == LYS_AUGMENT) {
5397 sparent = ((struct lys_node_augment *)schema)->target;
5398 } else {
5399 sparent = schema->parent;
5400 }
5401 if (!sparent) {
5402 /* context node is the document root (fake root in our case) */
5403 if (schema->flags & LYS_CONFIG_W) {
5404 *ctx_snode_type = LYXP_NODE_ROOT_CONFIG;
5405 } else {
Michal Vaskob94a5e42016-09-08 14:01:56 +02005406 *ctx_snode_type = LYXP_NODE_ROOT;
Michal Vasko508a50d2016-09-07 14:50:33 +02005407 }
Michal Vasko2d2aec12016-09-08 11:42:50 +02005408 /* we need the first top-level sibling, but no uses or groupings */
Michal Vaskob94a5e42016-09-08 14:01:56 +02005409 schema = lys_getnext(NULL, NULL, lys_node_module(schema), 0);
Michal Vasko508a50d2016-09-07 14:50:33 +02005410 break;
5411 }
5412 schema = sparent;
5413 }
5414
5415 *ctx_snode = (struct lys_node *)schema;
5416}
5417
5418/**
Michal Vaskocf024702015-10-08 15:01:42 +02005419 * @brief Resolve (find) when condition context node. Does not log.
5420 *
5421 * @param[in] node Data node, whose conditional definition is being decided.
Michal Vasko508a50d2016-09-07 14:50:33 +02005422 * @param[in] schema Schema node with the when condition.
Michal Vaskoa59495d2016-08-22 09:18:58 +02005423 * @param[out] ctx_node Context node.
5424 * @param[out] ctx_node_type Context node type.
Michal Vaskocf024702015-10-08 15:01:42 +02005425 *
Michal Vaskoa59495d2016-08-22 09:18:58 +02005426 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vaskocf024702015-10-08 15:01:42 +02005427 */
Michal Vaskoa59495d2016-08-22 09:18:58 +02005428static int
5429resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema, struct lyd_node **ctx_node,
5430 enum lyxp_node_type *ctx_node_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005431{
Michal Vaskocf024702015-10-08 15:01:42 +02005432 struct lyd_node *parent;
5433 struct lys_node *sparent;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005434 enum lyxp_node_type node_type;
Michal Vaskocf024702015-10-08 15:01:42 +02005435 uint16_t i, data_depth, schema_depth;
5436
Michal Vasko508a50d2016-09-07 14:50:33 +02005437 resolve_when_ctx_snode(schema, &schema, &node_type);
Michal Vaskocf024702015-10-08 15:01:42 +02005438
Michal Vaskofe989752016-09-08 08:47:26 +02005439 if (node_type == LYXP_NODE_ELEM) {
5440 /* standard element context node */
5441 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
5442 for (sparent = schema, schema_depth = 0;
5443 sparent;
5444 sparent = (sparent->nodetype == LYS_AUGMENT ? ((struct lys_node_augment *)sparent)->target : sparent->parent)) {
5445 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_NOTIF | LYS_RPC)) {
5446 ++schema_depth;
5447 }
Michal Vaskocf024702015-10-08 15:01:42 +02005448 }
Michal Vaskofe989752016-09-08 08:47:26 +02005449 if (data_depth < schema_depth) {
5450 return -1;
5451 }
Michal Vaskocf024702015-10-08 15:01:42 +02005452
Michal Vasko956e8542016-08-26 09:43:35 +02005453 /* find the corresponding data node */
5454 for (i = 0; i < data_depth - schema_depth; ++i) {
5455 node = node->parent;
5456 }
Michal Vaskoa59495d2016-08-22 09:18:58 +02005457 if (node->schema != schema) {
5458 return -1;
5459 }
Michal Vaskofe989752016-09-08 08:47:26 +02005460 } else {
5461 /* root context node */
5462 while (node->parent) {
5463 node = node->parent;
5464 }
5465 while (node->prev->next) {
5466 node = node->prev;
5467 }
Michal Vaskocf024702015-10-08 15:01:42 +02005468 }
5469
Michal Vaskoa59495d2016-08-22 09:18:58 +02005470 *ctx_node = node;
5471 *ctx_node_type = node_type;
5472 return EXIT_SUCCESS;
Michal Vaskocf024702015-10-08 15:01:42 +02005473}
5474
Michal Vasko76c3bd32016-08-24 16:02:52 +02005475/**
5476 * @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 +01005477 * The context node is adjusted if needed.
Michal Vasko76c3bd32016-08-24 16:02:52 +02005478 *
5479 * @param[in] snode Schema node, whose children instances need to be unlinked.
5480 * @param[in,out] node Data siblings where to look for the children of \p snode. If it is unlinked,
5481 * it is moved to point to another sibling still in the original tree.
5482 * @param[in,out] ctx_node When context node, adjusted if needed.
5483 * @param[in] ctx_node_type Context node type, just for information to detect invalid situations.
5484 * @param[out] unlinked_nodes Unlinked siblings. Can be safely appended to \p node afterwards.
5485 * Ordering may change, but there will be no semantic change.
5486 *
5487 * @return EXIT_SUCCESS on success, -1 on error.
5488 */
5489static int
5490resolve_when_unlink_nodes(struct lys_node *snode, struct lyd_node **node, struct lyd_node **ctx_node,
5491 enum lyxp_node_type ctx_node_type, struct lyd_node **unlinked_nodes)
5492{
5493 struct lyd_node *next, *elem;
5494
5495 switch (snode->nodetype) {
5496 case LYS_AUGMENT:
5497 case LYS_USES:
5498 case LYS_CHOICE:
5499 case LYS_CASE:
5500 LY_TREE_FOR(snode->child, snode) {
5501 if (resolve_when_unlink_nodes(snode, node, ctx_node, ctx_node_type, unlinked_nodes)) {
5502 return -1;
5503 }
5504 }
5505 break;
5506 case LYS_CONTAINER:
5507 case LYS_LIST:
5508 case LYS_LEAF:
5509 case LYS_LEAFLIST:
5510 case LYS_ANYXML:
5511 case LYS_ANYDATA:
5512 LY_TREE_FOR_SAFE(lyd_first_sibling(*node), next, elem) {
5513 if (elem->schema == snode) {
5514
5515 if (elem == *ctx_node) {
5516 /* We are going to unlink our context node! This normally cannot happen,
5517 * but we use normal top-level data nodes for faking a document root node,
5518 * so if this is the context node, we just use the next top-level node.
5519 * Additionally, it can even happen that there are no top-level data nodes left,
5520 * all were unlinked, so in this case we pass NULL as the context node/data tree,
5521 * lyxp_eval() can handle this special situation.
5522 */
5523 if (ctx_node_type == LYXP_NODE_ELEM) {
5524 LOGINT;
5525 return -1;
5526 }
5527
5528 if (elem->prev == elem) {
5529 /* unlinking last top-level element, use an empty data tree */
5530 *ctx_node = NULL;
5531 } else {
5532 /* in this case just use the previous/last top-level data node */
5533 *ctx_node = elem->prev;
5534 }
5535 } else if (elem == *node) {
5536 /* We are going to unlink the currently processed node. This does not matter that
5537 * much, but we would lose access to the original data tree, so just move our
5538 * pointer somewhere still inside it.
5539 */
5540 if ((*node)->prev != *node) {
5541 *node = (*node)->prev;
5542 } else {
5543 /* the processed node with sibings were all unlinked, oh well */
5544 *node = NULL;
5545 }
5546 }
5547
5548 /* temporarily unlink the node */
5549 lyd_unlink(elem);
5550 if (*unlinked_nodes) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005551 if (lyd_insert_after((*unlinked_nodes)->prev, elem)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005552 LOGINT;
5553 return -1;
5554 }
5555 } else {
5556 *unlinked_nodes = elem;
5557 }
5558
5559 if (snode->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_ANYDATA)) {
5560 /* there can be only one instance */
5561 break;
5562 }
5563 }
5564 }
5565 break;
5566 default:
5567 LOGINT;
5568 return -1;
5569 }
5570
5571 return EXIT_SUCCESS;
5572}
5573
5574/**
5575 * @brief Relink the unlinked nodes back.
5576 *
5577 * @param[in] node Data node to link the nodes back to. It can actually be the adjusted context node,
5578 * we simply need a sibling from the original data tree.
5579 * @param[in] unlinked_nodes Unlinked nodes to relink to \p node.
5580 * @param[in] ctx_node_type Context node type to distinguish between \p node being the parent
5581 * or the sibling of \p unlinked_nodes.
5582 *
5583 * @return EXIT_SUCCESS on success, -1 on error.
5584 */
5585static int
5586resolve_when_relink_nodes(struct lyd_node *node, struct lyd_node *unlinked_nodes, enum lyxp_node_type ctx_node_type)
5587{
5588 struct lyd_node *elem;
5589
5590 LY_TREE_FOR_SAFE(unlinked_nodes, unlinked_nodes, elem) {
Michal Vaskode1feeb2016-12-20 14:48:42 +01005591 lyd_unlink(elem);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005592 if (ctx_node_type == LYXP_NODE_ELEM) {
5593 if (lyd_insert(node, elem)) {
5594 return -1;
5595 }
5596 } else {
5597 if (lyd_insert_after(node, elem)) {
5598 return -1;
5599 }
5600 }
5601 }
5602
5603 return EXIT_SUCCESS;
5604}
5605
Radek Krejci03b71f72016-03-16 11:10:09 +01005606int
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005607resolve_applies_must(const struct lyd_node *node)
Radek Krejci01696bf2016-03-18 13:19:36 +01005608{
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005609 int ret = 0;
5610 uint8_t must_size;
5611 struct lys_node *schema, *iter;
Radek Krejci46165822016-08-26 14:06:27 +02005612
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005613 assert(node);
5614
5615 schema = node->schema;
5616
5617 /* their own must */
Radek Krejci46165822016-08-26 14:06:27 +02005618 switch (schema->nodetype) {
Radek Krejci01696bf2016-03-18 13:19:36 +01005619 case LYS_CONTAINER:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005620 must_size = ((struct lys_node_container *)schema)->must_size;
5621 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005622 case LYS_LEAF:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005623 must_size = ((struct lys_node_leaf *)schema)->must_size;
5624 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005625 case LYS_LEAFLIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005626 must_size = ((struct lys_node_leaflist *)schema)->must_size;
5627 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005628 case LYS_LIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005629 must_size = ((struct lys_node_list *)schema)->must_size;
5630 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005631 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02005632 case LYS_ANYDATA:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005633 must_size = ((struct lys_node_anydata *)schema)->must_size;
5634 break;
5635 case LYS_NOTIF:
5636 must_size = ((struct lys_node_notif *)schema)->must_size;
5637 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005638 default:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005639 must_size = 0;
5640 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005641 }
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005642
5643 if (must_size) {
5644 ++ret;
5645 }
5646
5647 /* schema may be a direct data child of input/output with must (but it must be first, it needs to be evaluated only once) */
5648 if (!node->prev->next) {
5649 for (iter = lys_parent(schema); iter && (iter->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES)); iter = lys_parent(iter));
5650 if (iter && (iter->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5651 ret += 0x2;
5652 }
5653 }
5654
5655 return ret;
Radek Krejci01696bf2016-03-18 13:19:36 +01005656}
5657
5658int
Radek Krejci46165822016-08-26 14:06:27 +02005659resolve_applies_when(const struct lys_node *schema, int mode, const struct lys_node *stop)
Radek Krejci03b71f72016-03-16 11:10:09 +01005660{
Radek Krejci46165822016-08-26 14:06:27 +02005661 const struct lys_node *parent;
Radek Krejci03b71f72016-03-16 11:10:09 +01005662
Radek Krejci46165822016-08-26 14:06:27 +02005663 assert(schema);
Radek Krejci03b71f72016-03-16 11:10:09 +01005664
Radek Krejci46165822016-08-26 14:06:27 +02005665 if (!(schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)schema)->when)) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005666 return 1;
5667 }
5668
Radek Krejci46165822016-08-26 14:06:27 +02005669 parent = schema;
Radek Krejci03b71f72016-03-16 11:10:09 +01005670 goto check_augment;
5671
Radek Krejci46165822016-08-26 14:06:27 +02005672 while (parent) {
5673 /* stop conditions */
5674 if (!mode) {
5675 /* stop on node that can be instantiated in data tree */
5676 if (!(parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
5677 break;
5678 }
5679 } else {
5680 /* stop on the specified node */
5681 if (parent == stop) {
5682 break;
5683 }
5684 }
5685
5686 if (((const struct lys_node_uses *)parent)->when) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005687 return 1;
5688 }
5689check_augment:
5690
5691 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) &&
Radek Krejci46165822016-08-26 14:06:27 +02005692 (((const struct lys_node_augment *)parent->parent)->when))) {
Michal Vaskoe3655562016-08-24 15:56:17 +02005693 return 1;
Radek Krejci03b71f72016-03-16 11:10:09 +01005694 }
5695 parent = lys_parent(parent);
5696 }
5697
5698 return 0;
5699}
5700
Michal Vaskocf024702015-10-08 15:01:42 +02005701/**
5702 * @brief Resolve (check) all when conditions relevant for \p node.
5703 * Logs directly.
5704 *
5705 * @param[in] node Data node, whose conditional reference, if such, is being decided.
Michal Vaskocf024702015-10-08 15:01:42 +02005706 *
Radek Krejci03b71f72016-03-16 11:10:09 +01005707 * @return
5708 * -1 - error, ly_errno is set
5709 * 0 - true "when" statement
Radek Krejci46165822016-08-26 14:06:27 +02005710 * 0, ly_vecode = LYVE_NOWHEN - false "when" statement
Radek Krejci03b71f72016-03-16 11:10:09 +01005711 * 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 +02005712 */
Radek Krejci46165822016-08-26 14:06:27 +02005713int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005714resolve_when(struct lyd_node *node, int *result, int ignore_fail)
Michal Vaskocf024702015-10-08 15:01:42 +02005715{
Michal Vasko76c3bd32016-08-24 16:02:52 +02005716 struct lyd_node *ctx_node = NULL, *unlinked_nodes, *tmp_node;
Michal Vasko90fc2a32016-08-24 15:58:58 +02005717 struct lys_node *sparent;
Michal Vaskocf024702015-10-08 15:01:42 +02005718 struct lyxp_set set;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005719 enum lyxp_node_type ctx_node_type;
Radek Krejci51093642016-03-29 10:14:59 +02005720 int rc = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02005721
5722 assert(node);
5723 memset(&set, 0, sizeof set);
5724
5725 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)node->schema)->when)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005726 /* make the node dummy for the evaluation */
5727 node->validity |= LYD_VAL_INUSE;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005728 rc = lyxp_eval(((struct lys_node_container *)node->schema)->when->cond, node, LYXP_NODE_ELEM, lyd_node_module(node),
5729 &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005730 node->validity &= ~LYD_VAL_INUSE;
Radek Krejci03b71f72016-03-16 11:10:09 +01005731 if (rc) {
5732 if (rc == 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005733 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005734 }
Radek Krejci51093642016-03-29 10:14:59 +02005735 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005736 }
5737
Radek Krejci03b71f72016-03-16 11:10:09 +01005738 /* set boolean result of the condition */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005739 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02005740 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01005741 node->when_status |= LYD_WHEN_FALSE;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005742 if (ignore_fail) {
5743 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
5744 ((struct lys_node_container *)node->schema)->when->cond);
5745 } else {
5746 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
5747 goto cleanup;
5748 }
Michal Vaskocf024702015-10-08 15:01:42 +02005749 }
Radek Krejci51093642016-03-29 10:14:59 +02005750
5751 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005752 lyxp_set_cast(&set, LYXP_SET_EMPTY, node, lyd_node_module(node), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005753 }
5754
Michal Vasko90fc2a32016-08-24 15:58:58 +02005755 sparent = node->schema;
Michal Vaskocf024702015-10-08 15:01:42 +02005756 goto check_augment;
5757
5758 /* check when in every schema node that affects node */
Michal Vasko90fc2a32016-08-24 15:58:58 +02005759 while (sparent && (sparent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
5760 if (((struct lys_node_uses *)sparent)->when) {
Michal Vaskocf024702015-10-08 15:01:42 +02005761 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005762 rc = resolve_when_ctx_node(node, sparent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02005763 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02005764 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02005765 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005766 }
5767 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02005768
5769 unlinked_nodes = NULL;
5770 /* we do not want our node pointer to change */
5771 tmp_node = node;
5772 rc = resolve_when_unlink_nodes(sparent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
5773 if (rc) {
5774 goto cleanup;
5775 }
5776
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005777 rc = lyxp_eval(((struct lys_node_uses *)sparent)->when->cond, ctx_node, ctx_node_type, lys_node_module(sparent),
5778 &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005779
5780 if (unlinked_nodes && ctx_node) {
5781 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
5782 rc = -1;
5783 goto cleanup;
5784 }
5785 }
5786
Radek Krejci03b71f72016-03-16 11:10:09 +01005787 if (rc) {
5788 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005789 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005790 }
Radek Krejci51093642016-03-29 10:14:59 +02005791 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005792 }
5793
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005794 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02005795 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01005796 node->when_status |= LYD_WHEN_FALSE;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005797 if (ignore_fail) {
5798 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
5799 ((struct lys_node_uses *)sparent)->when->cond);
5800 } else {
5801 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
5802 goto cleanup;
5803 }
Michal Vaskocf024702015-10-08 15:01:42 +02005804 }
Radek Krejci51093642016-03-29 10:14:59 +02005805
5806 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005807 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005808 }
5809
5810check_augment:
Michal Vasko90fc2a32016-08-24 15:58:58 +02005811 if ((sparent->parent && (sparent->parent->nodetype == LYS_AUGMENT) && (((struct lys_node_augment *)sparent->parent)->when))) {
Michal Vaskocf024702015-10-08 15:01:42 +02005812 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005813 rc = resolve_when_ctx_node(node, sparent->parent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02005814 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02005815 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02005816 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005817 }
5818 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02005819
5820 unlinked_nodes = NULL;
5821 tmp_node = node;
5822 rc = resolve_when_unlink_nodes(sparent->parent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
5823 if (rc) {
5824 goto cleanup;
5825 }
5826
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005827 rc = lyxp_eval(((struct lys_node_augment *)sparent->parent)->when->cond, ctx_node, ctx_node_type,
5828 lys_node_module(sparent->parent), &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005829
5830 /* reconnect nodes, if ctx_node is NULL then all the nodes were unlinked, but linked together,
5831 * so the tree did not actually change and there is nothing for us to do
5832 */
5833 if (unlinked_nodes && ctx_node) {
5834 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
5835 rc = -1;
5836 goto cleanup;
5837 }
5838 }
5839
Radek Krejci03b71f72016-03-16 11:10:09 +01005840 if (rc) {
5841 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005842 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005843 }
Radek Krejci51093642016-03-29 10:14:59 +02005844 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005845 }
5846
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005847 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent->parent), LYXP_WHEN);
Michal Vaskocf024702015-10-08 15:01:42 +02005848
Michal Vasko8146d4c2016-05-09 15:50:29 +02005849 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01005850 node->when_status |= LYD_WHEN_FALSE;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005851 if (ignore_fail) {
5852 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
5853 ((struct lys_node_augment *)sparent->parent)->when->cond);
5854 } else {
5855 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
5856 goto cleanup;
5857 }
Michal Vaskocf024702015-10-08 15:01:42 +02005858 }
Radek Krejci51093642016-03-29 10:14:59 +02005859
5860 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005861 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent->parent), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005862 }
5863
Michal Vasko90fc2a32016-08-24 15:58:58 +02005864 sparent = lys_parent(sparent);
Michal Vaskocf024702015-10-08 15:01:42 +02005865 }
5866
Radek Krejci0b7704f2016-03-18 12:16:14 +01005867 node->when_status |= LYD_WHEN_TRUE;
Radek Krejci03b71f72016-03-16 11:10:09 +01005868
Radek Krejci51093642016-03-29 10:14:59 +02005869cleanup:
Radek Krejci51093642016-03-29 10:14:59 +02005870 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005871 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node ? ctx_node : node, NULL, 0);
Radek Krejci51093642016-03-29 10:14:59 +02005872
Radek Krejci46165822016-08-26 14:06:27 +02005873 if (result) {
5874 if (node->when_status & LYD_WHEN_TRUE) {
5875 *result = 1;
5876 } else {
5877 *result = 0;
5878 }
5879 }
5880
Radek Krejci51093642016-03-29 10:14:59 +02005881 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005882}
5883
Radek Krejcicbb473e2016-09-16 14:48:32 +02005884static int
5885check_leafref_features(struct lys_type *type)
5886{
5887 struct lys_node *iter;
5888 struct ly_set *src_parents, *trg_parents, *features;
5889 unsigned int i, j, size, x;
5890 int ret = EXIT_SUCCESS;
5891
5892 assert(type->parent);
5893
5894 src_parents = ly_set_new();
5895 trg_parents = ly_set_new();
5896 features = ly_set_new();
5897
5898 /* get parents chain of source (leafref) */
5899 for (iter = (struct lys_node *)type->parent; iter; iter = iter->parent) {
5900 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
5901 continue;
5902 }
5903 ly_set_add(src_parents, iter, LY_SET_OPT_USEASLIST);
5904 }
5905 /* get parents chain of target */
5906 for (iter = (struct lys_node *)type->info.lref.target; iter; iter = iter->parent) {
5907 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
5908 continue;
5909 }
5910 ly_set_add(trg_parents, iter, LY_SET_OPT_USEASLIST);
5911 }
5912
5913 /* compare the features used in if-feature statements in the rest of both
5914 * chains of parents. The set of features used for target must be a subset
5915 * of features used for the leafref. This is not a perfect, we should compare
5916 * the truth tables but it could require too much resources, so we simplify that */
5917 for (i = 0; i < src_parents->number; i++) {
5918 iter = src_parents->set.s[i]; /* shortcut */
5919 if (!iter->iffeature_size) {
5920 continue;
5921 }
5922 for (j = 0; j < iter->iffeature_size; j++) {
5923 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
5924 for (; size; size--) {
5925 if (!iter->iffeature[j].features[size - 1]) {
5926 /* not yet resolved feature, postpone this check */
5927 ret = EXIT_FAILURE;
5928 goto cleanup;
5929 }
5930 ly_set_add(features, iter->iffeature[j].features[size - 1], 0);
5931 }
5932 }
5933 }
5934 x = features->number;
5935 for (i = 0; i < trg_parents->number; i++) {
5936 iter = trg_parents->set.s[i]; /* shortcut */
5937 if (!iter->iffeature_size) {
5938 continue;
5939 }
5940 for (j = 0; j < iter->iffeature_size; j++) {
5941 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
5942 for (; size; size--) {
5943 if (!iter->iffeature[j].features[size - 1]) {
5944 /* not yet resolved feature, postpone this check */
5945 ret = EXIT_FAILURE;
5946 goto cleanup;
5947 }
5948 if ((unsigned int)ly_set_add(features, iter->iffeature[j].features[size - 1], 0) >= x) {
5949 /* the feature is not present in features set of target's parents chain */
5950 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, type->parent, "leafref", type->info.lref.path);
5951 LOGVAL(LYE_SPEC, LY_VLOG_LYS, type->parent,
5952 "Leafref is not conditional based on \"%s\" feature as its target.",
5953 iter->iffeature[j].features[size - 1]->name);
5954 ret = -1;
5955 goto cleanup;
5956 }
5957 }
5958 }
5959 }
5960
5961cleanup:
5962 ly_set_free(features);
5963 ly_set_free(src_parents);
5964 ly_set_free(trg_parents);
5965
5966 return ret;
5967}
5968
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005969/**
Michal Vaskobb211122015-08-19 14:03:11 +02005970 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005971 *
5972 * @param[in] mod Main module.
5973 * @param[in] item Item to resolve. Type determined by \p type.
5974 * @param[in] type Type of the unresolved item.
5975 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02005976 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005977 *
5978 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
5979 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005980static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02005981resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Radek Krejci48464ed2016-03-17 15:44:09 +01005982 struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005983{
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005984 /* has_str - whether the str_snode is a string in a dictionary that needs to be freed */
Radek Krejcic79c6b12016-07-26 15:11:49 +02005985 int rc = -1, has_str = 0, tpdf_flag = 0, i, k;
5986 unsigned int j;
Radek Krejcic13db382016-08-16 10:52:42 +02005987 struct lys_node *node, *par_grp;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005988 const char *expr;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005989
Radek Krejcic79c6b12016-07-26 15:11:49 +02005990 struct ly_set *refs, *procs;
5991 struct lys_feature *ref, *feat;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005992 struct lys_ident *ident;
5993 struct lys_type *stype;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005994 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01005995 struct lyxml_elem *yin;
Pavol Vicana0e4e672016-02-24 12:20:04 +01005996 struct yang_type *yang;
Radek Krejcid09d1a52016-08-11 14:05:45 +02005997 struct unres_list_uniq *unique_info;
Radek Krejcicbb473e2016-09-16 14:48:32 +02005998 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005999
6000 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006001 case UNRES_IDENT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006002 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006003 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006004 ident = item;
6005
Radek Krejci018f1f52016-08-03 16:01:20 +02006006 rc = resolve_base_ident(mod, ident, expr, "identity", NULL, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006007 break;
6008 case UNRES_TYPE_IDENTREF:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006009 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006010 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006011 stype = item;
6012
Radek Krejci018f1f52016-08-03 16:01:20 +02006013 rc = resolve_base_ident(mod, NULL, expr, "type", stype, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006014 break;
6015 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02006016 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006017 stype = item;
6018
Radek Krejci2f12f852016-01-08 12:59:57 +01006019 /* HACK - when there is no parent, we are in top level typedef and in that
6020 * case, the path has to contain absolute path, so we let the resolve_path_arg_schema()
6021 * know it via tpdf_flag */
6022 if (!node) {
Radek Krejci4f78b532016-02-17 13:43:00 +01006023 tpdf_flag = 1;
Radek Krejci2f12f852016-01-08 12:59:57 +01006024 node = (struct lys_node *)stype->parent;
6025 }
6026
Radek Krejci27fe55e2016-09-13 17:13:35 +02006027 if (!lys_node_module(node)->implemented) {
6028 /* not implemented module, don't bother with resolving the leafref
Radek Krejci990af1f2016-11-09 13:53:36 +01006029 * if the module is set to be implemented, the path will be resolved then */
Radek Krejci27fe55e2016-09-13 17:13:35 +02006030 rc = 0;
6031 break;
6032 }
Radek Krejci48464ed2016-03-17 15:44:09 +01006033 rc = resolve_path_arg_schema(stype->info.lref.path, node, tpdf_flag,
Michal Vasko1e62a092015-12-01 12:27:20 +01006034 (const struct lys_node **)&stype->info.lref.target);
Michal Vasko01c6fd22016-05-20 11:43:05 +02006035 if (!tpdf_flag && !rc) {
6036 assert(stype->info.lref.target);
Radek Krejcicbb473e2016-09-16 14:48:32 +02006037 /* check if leafref and its target are under a common if-features */
6038 rc = check_leafref_features(stype);
6039 if (rc) {
6040 break;
6041 }
6042
Radek Krejci46c4cd72016-01-21 15:13:52 +01006043 /* store the backlink from leafref target */
Michal Vasko01c6fd22016-05-20 11:43:05 +02006044 if (lys_leaf_add_leafref_target(stype->info.lref.target, (struct lys_node *)stype->parent)) {
6045 rc = -1;
Radek Krejci46c4cd72016-01-21 15:13:52 +01006046 }
Radek Krejci46c4cd72016-01-21 15:13:52 +01006047 }
6048
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006049 break;
Radek Krejci3a5501d2016-07-18 22:03:34 +02006050 case UNRES_TYPE_DER_TPDF:
6051 tpdf_flag = 1;
6052 /* no break */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006053 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01006054 /* parent */
6055 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006056 stype = item;
6057
Michal Vasko88c29542015-11-27 14:57:53 +01006058 /* HACK type->der is temporarily unparsed type statement */
6059 yin = (struct lyxml_elem *)stype->der;
6060 stype->der = NULL;
6061
Pavol Vicana0e4e672016-02-24 12:20:04 +01006062 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6063 yang = (struct yang_type *)yin;
Radek Krejci3a5501d2016-07-18 22:03:34 +02006064 rc = yang_check_type(mod, node, yang, tpdf_flag, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006065
6066 if (rc) {
Pavol Vican8bd72e42016-08-29 09:53:05 +02006067 /* may try again later */
6068 stype->der = (struct lys_tpdf *)yang;
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006069 } else {
6070 /* we need to always be able to free this, it's safe only in this case */
Pavol Vican5f0316a2016-04-05 21:21:11 +02006071 lydict_remove(mod->ctx, yang->name);
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006072 free(yang);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006073 }
6074
Michal Vasko88c29542015-11-27 14:57:53 +01006075 } else {
Radek Krejci3a5501d2016-07-18 22:03:34 +02006076 rc = fill_yin_type(mod, node, yin, stype, tpdf_flag, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006077 if (!rc) {
6078 /* we need to always be able to free this, it's safe only in this case */
6079 lyxml_free(mod->ctx, yin);
6080 } else {
6081 /* may try again later, put all back how it was */
6082 stype->der = (struct lys_tpdf *)yin;
6083 }
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006084 }
Radek Krejcic13db382016-08-16 10:52:42 +02006085 if (rc == EXIT_SUCCESS) {
Radek Krejci2c2fce82016-08-01 13:52:26 +02006086 /* it does not make sense to have leaf-list of empty type */
6087 if (!tpdf_flag && node->nodetype == LYS_LEAFLIST && stype->base == LY_TYPE_EMPTY) {
6088 LOGWRN("The leaf-list \"%s\" is of \"empty\" type, which does not make sense.", node->name);
6089 }
Radek Krejci9b6aad22016-09-20 15:55:51 +02006090 } else if (rc == EXIT_FAILURE && stype->base != LY_TYPE_ERR) {
Radek Krejcic13db382016-08-16 10:52:42 +02006091 /* forward reference - in case the type is in grouping, we have to make the grouping unusable
6092 * by uses statement until the type is resolved. We do that the same way as uses statements inside
6093 * grouping - the grouping's nacm member (not used un grouping) is used to increase the number of
6094 * 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 +02006095 * 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 +02006096 * of the type's base member. */
6097 for (par_grp = node; par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
6098 if (par_grp) {
6099 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci9b6aad22016-09-20 15:55:51 +02006100 stype->base = LY_TYPE_ERR;
Radek Krejcic13db382016-08-16 10:52:42 +02006101 }
Radek Krejci2c2fce82016-08-01 13:52:26 +02006102 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006103 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006104 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006105 iff_data = str_snode;
6106 rc = resolve_feature(iff_data->fname, strlen(iff_data->fname), iff_data->node, item);
Radek Krejci9ff0a922016-07-14 13:08:05 +02006107 if (!rc) {
6108 /* success */
Radek Krejci9de2c042016-10-19 16:53:06 +02006109 if (iff_data->infeature) {
6110 /* store backlink into the target feature to allow reverse changes in case of changing feature status */
6111 feat = *((struct lys_feature **)item);
6112 if (!feat->depfeatures) {
6113 feat->depfeatures = ly_set_new();
6114 }
Radek Krejci85a54be2016-10-20 12:39:56 +02006115 ly_set_add(feat->depfeatures, iff_data->node, LY_SET_OPT_USEASLIST);
Radek Krejci9de2c042016-10-19 16:53:06 +02006116 }
6117 /* cleanup temporary data */
Radek Krejcicbb473e2016-09-16 14:48:32 +02006118 lydict_remove(mod->ctx, iff_data->fname);
6119 free(iff_data);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006120 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006121 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006122 case UNRES_FEATURE:
6123 feat = (struct lys_feature *)item;
6124
6125 if (feat->iffeature_size) {
6126 refs = ly_set_new();
6127 procs = ly_set_new();
6128 ly_set_add(procs, feat, 0);
6129
6130 while (procs->number) {
6131 ref = procs->set.g[procs->number - 1];
6132 ly_set_rm_index(procs, procs->number - 1);
6133
6134 for (i = 0; i < ref->iffeature_size; i++) {
6135 resolve_iffeature_getsizes(&ref->iffeature[i], NULL, &j);
6136 for (; j > 0 ; j--) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006137 if (ref->iffeature[i].features[j - 1]) {
Radek Krejcic79c6b12016-07-26 15:11:49 +02006138 if (ref->iffeature[i].features[j - 1] == feat) {
6139 LOGVAL(LYE_CIRC_FEATURES, LY_VLOG_NONE, NULL, feat->name);
6140 goto featurecheckdone;
6141 }
6142
6143 if (ref->iffeature[i].features[j - 1]->iffeature_size) {
6144 k = refs->number;
6145 if (ly_set_add(refs, ref->iffeature[i].features[j - 1], 0) == k) {
6146 /* not yet seen feature, add it for processing */
6147 ly_set_add(procs, ref->iffeature[i].features[j - 1], 0);
6148 }
6149 }
6150 } else {
6151 /* forward reference */
6152 rc = EXIT_FAILURE;
6153 goto featurecheckdone;
6154 }
6155 }
6156
6157 }
6158 }
6159 rc = EXIT_SUCCESS;
6160
6161featurecheckdone:
6162 ly_set_free(refs);
6163 ly_set_free(procs);
6164 }
6165
6166 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006167 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006168 rc = resolve_unres_schema_uses(item, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006169 break;
6170 case UNRES_TYPE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006171 stype = item;
6172
Radek Krejci51673202016-11-01 17:00:32 +01006173 rc = check_default(stype, (const char **)str_snode, mod);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006174 break;
6175 case UNRES_CHOICE_DFLT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006176 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006177 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006178 choic = item;
6179
Radek Krejcie00d2312016-08-12 15:27:49 +02006180 if (!choic->dflt) {
6181 choic->dflt = resolve_choice_dflt(choic, expr);
6182 }
Michal Vasko7955b362015-09-04 14:18:15 +02006183 if (choic->dflt) {
Radek Krejcie00d2312016-08-12 15:27:49 +02006184 rc = lyp_check_mandatory_choice((struct lys_node *)choic);
Michal Vasko7955b362015-09-04 14:18:15 +02006185 } else {
6186 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006187 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006188 break;
6189 case UNRES_LIST_KEYS:
Radek Krejci5c08a992016-11-02 13:30:04 +01006190 rc = resolve_list_keys(item, ((struct lys_node_list *)item)->keys_str);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006191 break;
6192 case UNRES_LIST_UNIQ:
Radek Krejcid09d1a52016-08-11 14:05:45 +02006193 unique_info = (struct unres_list_uniq *)item;
6194 rc = resolve_unique(unique_info->list, unique_info->expr, unique_info->trg_type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006195 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006196 case UNRES_AUGMENT:
Radek Krejcib3142312016-11-09 11:04:12 +01006197 rc = resolve_augment(item, NULL, unres);
Michal Vasko7178e692016-02-12 15:58:05 +01006198 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006199 case UNRES_XPATH:
6200 node = (struct lys_node *)item;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02006201 rc = lys_check_xpath(node, 1);
Michal Vasko508a50d2016-09-07 14:50:33 +02006202 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006203 default:
6204 LOGINT;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006205 break;
6206 }
6207
Radek Krejci54081ce2016-08-12 15:21:47 +02006208 if (has_str && !rc) {
6209 /* the string is no more needed in case of success.
6210 * In case of forward reference, we will try to resolve the string later */
Radek Krejci4f78b532016-02-17 13:43:00 +01006211 lydict_remove(mod->ctx, str_snode);
6212 }
6213
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006214 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006215}
6216
Michal Vaskof02e3742015-08-05 16:27:02 +02006217/* logs directly */
6218static void
Radek Krejci48464ed2016-03-17 15:44:09 +01006219print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006220{
Michal Vaskocb34dc62016-05-20 14:38:37 +02006221 struct lyxml_elem *xml;
6222 struct lyxml_attr *attr;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006223 struct unres_iffeat_data *iff_data;
Radek Krejci76e15e12016-06-22 11:02:24 +02006224 const char *type_name = NULL;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006225
Michal Vaskof02e3742015-08-05 16:27:02 +02006226 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02006227 case UNRES_IDENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006228 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identity", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006229 break;
6230 case UNRES_TYPE_IDENTREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006231 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identityref", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006232 break;
6233 case UNRES_TYPE_LEAFREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006234 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "leafref",
6235 ((struct lys_type *)item)->info.lref.path);
Michal Vaskof02e3742015-08-05 16:27:02 +02006236 break;
Radek Krejci3a5501d2016-07-18 22:03:34 +02006237 case UNRES_TYPE_DER_TPDF:
Michal Vaskof02e3742015-08-05 16:27:02 +02006238 case UNRES_TYPE_DER:
Michal Vaskocb34dc62016-05-20 14:38:37 +02006239 xml = (struct lyxml_elem *)((struct lys_type *)item)->der;
6240 if (xml->flags & LY_YANG_STRUCTURE_FLAG) {
6241 type_name = ((struct yang_type *)xml)->name;
6242 } else {
6243 LY_TREE_FOR(xml->attr, attr) {
6244 if ((attr->type == LYXML_ATTR_STD) && !strcmp(attr->name, "name")) {
6245 type_name = attr->value;
6246 break;
6247 }
6248 }
6249 assert(attr);
6250 }
6251 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "derived type", type_name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006252 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006253 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006254 iff_data = str_node;
6255 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "if-feature", iff_data->fname);
Michal Vaskof02e3742015-08-05 16:27:02 +02006256 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006257 case UNRES_FEATURE:
6258 LOGVRB("There are unresolved if-features for \"%s\" feature circular dependency check, it will be attempted later",
6259 ((struct lys_feature *)item)->name);
6260 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006261 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006262 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "uses", ((struct lys_node_uses *)item)->name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006263 break;
6264 case UNRES_TYPE_DFLT:
Radek Krejci2e2de832016-10-13 16:12:26 +02006265 if (str_node) {
6266 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "type default", (char *)str_node);
6267 } /* else no default value in the type itself, but we are checking some restrictions against
6268 * possible default value of some base type. The failure is caused by not resolved base type,
6269 * so it was already reported */
Michal Vaskof02e3742015-08-05 16:27:02 +02006270 break;
6271 case UNRES_CHOICE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006272 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "choice default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006273 break;
6274 case UNRES_LIST_KEYS:
Radek Krejci48464ed2016-03-17 15:44:09 +01006275 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list keys", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006276 break;
6277 case UNRES_LIST_UNIQ:
Radek Krejci48464ed2016-03-17 15:44:09 +01006278 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list unique", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006279 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006280 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006281 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "augment target",
6282 ((struct lys_node_augment *)item)->target_name);
Michal Vasko7178e692016-02-12 15:58:05 +01006283 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006284 case UNRES_XPATH:
Michal Vasko0d198372016-11-16 11:40:03 +01006285 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "XPath expressions of",
6286 ((struct lys_node *)item)->name);
Michal Vasko508a50d2016-09-07 14:50:33 +02006287 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006288 default:
6289 LOGINT;
Michal Vaskof02e3742015-08-05 16:27:02 +02006290 break;
6291 }
6292}
6293
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006294/**
Michal Vaskobb211122015-08-19 14:03:11 +02006295 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006296 *
6297 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006298 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006299 *
Michal Vasko92b8a382015-08-19 14:03:49 +02006300 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006301 */
Michal Vaskof02e3742015-08-05 16:27:02 +02006302int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006303resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02006304{
Radek Krejci010e54b2016-03-15 09:40:34 +01006305 uint32_t i, resolved = 0, unres_count, res_count;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006306 int rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006307
6308 assert(unres);
6309
Michal Vaskoe8734262016-09-29 14:12:06 +02006310 LOGVRB("Resolving \"%s\" unresolved schema nodes and their constraints...", mod->name);
Radek Krejci010e54b2016-03-15 09:40:34 +01006311 ly_vlog_hide(1);
Michal Vasko51054ca2015-08-12 12:20:00 +02006312
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006313 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02006314 do {
Michal Vasko88c29542015-11-27 14:57:53 +01006315 unres_count = 0;
6316 res_count = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02006317
6318 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006319 /* UNRES_TYPE_LEAFREF must be resolved (for storing leafref target pointers);
Radek Krejcic79c6b12016-07-26 15:11:49 +02006320 * if-features are resolved here to make sure that we will have all if-features for
6321 * later check of feature circular dependency */
Radek Krejci018f1f52016-08-03 16:01:20 +02006322 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006323 continue;
6324 }
Radek Krejci018f1f52016-08-03 16:01:20 +02006325 /* processes UNRES_USES, UNRES_IFFEAT, UNRES_TYPE_DER, UNRES_TYPE_DER_TPDF, UNRES_TYPE_LEAFREF,
Radek Krejci818b0c52016-11-09 15:10:51 +01006326 * UNRES_AUGMENT, UNRES_CHOICE_DFLT and UNRES_IDENT */
Michal Vasko51054ca2015-08-12 12:20:00 +02006327
Michal Vasko88c29542015-11-27 14:57:53 +01006328 ++unres_count;
Radek Krejci48464ed2016-03-17 15:44:09 +01006329 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006330 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006331 unres->type[i] = UNRES_RESOLVED;
6332 ++resolved;
Michal Vasko88c29542015-11-27 14:57:53 +01006333 ++res_count;
Michal Vasko89e15322015-08-17 15:46:55 +02006334 } else if (rc == -1) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006335 ly_vlog_hide(0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02006336 /* print the error */
6337 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006338 return -1;
Radek Krejcic2a180f2016-06-22 13:28:16 +02006339 } else {
6340 /* forward reference, erase ly_errno */
Radek Krejci00a0e712016-10-26 10:24:46 +02006341 ly_err_clean(1);
Michal Vasko51054ca2015-08-12 12:20:00 +02006342 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006343 }
Michal Vasko88c29542015-11-27 14:57:53 +01006344 } while (res_count && (res_count < unres_count));
Michal Vasko51054ca2015-08-12 12:20:00 +02006345
Michal Vasko88c29542015-11-27 14:57:53 +01006346 if (res_count < unres_count) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006347 /* just print the errors */
6348 ly_vlog_hide(0);
6349
6350 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006351 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006352 continue;
6353 }
6354 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
6355 }
Michal Vasko92b8a382015-08-19 14:03:49 +02006356 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006357 }
6358
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006359 /* the rest */
6360 for (i = 0; i < unres->count; ++i) {
6361 if (unres->type[i] == UNRES_RESOLVED) {
6362 continue;
6363 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02006364
Radek Krejci48464ed2016-03-17 15:44:09 +01006365 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01006366 if (rc == 0) {
Pavol Vican88e16c92016-09-07 15:41:50 +02006367 if (unres->type[i] == UNRES_LIST_UNIQ) {
6368 /* free the allocated structure */
6369 free(unres->item[i]);
6370 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006371 unres->type[i] = UNRES_RESOLVED;
6372 ++resolved;
6373 } else if (rc == -1) {
6374 ly_vlog_hide(0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02006375 /* print the error */
6376 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
6377 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006378 }
6379 }
6380
Radek Krejci010e54b2016-03-15 09:40:34 +01006381 ly_vlog_hide(0);
6382
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006383 if (resolved < unres->count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006384 /* try to resolve the unresolved nodes again, it will not resolve anything, but it will print
6385 * all the validation errors
6386 */
6387 for (i = 0; i < unres->count; ++i) {
6388 if (unres->type[i] == UNRES_RESOLVED) {
6389 continue;
6390 }
Radek Krejcib3142312016-11-09 11:04:12 +01006391 if (unres->type[i] == UNRES_XPATH) {
6392 /* unresolvable XPaths are actually supposed to be warnings - they may be
6393 * unresolved due to the not implemented target module so it shouldn't avoid
6394 * parsing the module, but we still want to announce some issue here */
6395 ly_vlog_hide(0xff);
6396 }
Radek Krejci48464ed2016-03-17 15:44:09 +01006397 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejcib3142312016-11-09 11:04:12 +01006398 if (unres->type[i] == UNRES_XPATH && *ly_vlog_hide_location() == 0xff) {
6399 unres->type[i] = UNRES_RESOLVED;
6400 resolved++;
6401 ly_vlog_hide(0);
6402 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006403 }
Radek Krejcib3142312016-11-09 11:04:12 +01006404 if (resolved < unres->count) {
6405 return -1;
6406 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006407 }
6408
Michal Vaskoe8734262016-09-29 14:12:06 +02006409 LOGVRB("All \"%s\" schema nodes and constraints resolved.", mod->name);
Radek Krejcic071c542016-01-27 14:57:51 +01006410 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006411 return EXIT_SUCCESS;
6412}
6413
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006414/**
Michal Vaskobb211122015-08-19 14:03:11 +02006415 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006416 *
6417 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006418 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006419 * @param[in] item Item to resolve. Type determined by \p type.
6420 * @param[in] type Type of the unresolved item.
6421 * @param[in] str String argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006422 *
Michal Vasko3767fb22016-07-21 12:10:57 +02006423 * @return EXIT_SUCCESS on success, EXIT_FAILURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006424 */
6425int
Radek Krejci48464ed2016-03-17 15:44:09 +01006426unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
6427 const char *str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006428{
Radek Krejci54081ce2016-08-12 15:21:47 +02006429 int rc;
6430 const char *dictstr;
6431
6432 dictstr = lydict_insert(mod->ctx, str, 0);
6433 rc = unres_schema_add_node(mod, unres, item, type, (struct lys_node *)dictstr);
6434
6435 if (rc == -1) {
6436 lydict_remove(mod->ctx, dictstr);
6437 }
6438 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006439}
6440
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006441/**
Michal Vaskobb211122015-08-19 14:03:11 +02006442 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006443 *
6444 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006445 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006446 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01006447 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006448 * @param[in] snode Schema node argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006449 *
Michal Vasko3767fb22016-07-21 12:10:57 +02006450 * @return EXIT_SUCCESS on success, EXIT_FIALURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006451 */
6452int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006453unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Radek Krejci48464ed2016-03-17 15:44:09 +01006454 struct lys_node *snode)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006455{
Michal Vaskoef486d72016-09-27 12:10:44 +02006456 int rc, log_hidden;
Radek Krejci850a5de2016-11-08 14:06:40 +01006457 uint32_t u;
Michal Vasko88c29542015-11-27 14:57:53 +01006458 struct lyxml_elem *yin;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006459
Michal Vasko9bf425b2015-10-22 11:42:03 +02006460 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
6461 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006462
Radek Krejci850a5de2016-11-08 14:06:40 +01006463 /* check for duplicities in unres */
6464 for (u = 0; u < unres->count; u++) {
6465 if (unres->type[u] == type && unres->item[u] == item &&
6466 unres->str_snode[u] == snode && unres->module[u] == mod) {
6467 /* duplication, will be resolved later */
6468 return EXIT_FAILURE;
6469 }
6470 }
6471
Michal Vaskoef486d72016-09-27 12:10:44 +02006472 if (*ly_vlog_hide_location()) {
6473 log_hidden = 1;
6474 } else {
6475 log_hidden = 0;
6476 ly_vlog_hide(1);
6477 }
Radek Krejci48464ed2016-03-17 15:44:09 +01006478 rc = resolve_unres_schema_item(mod, item, type, snode, unres);
Michal Vaskoef486d72016-09-27 12:10:44 +02006479 if (!log_hidden) {
6480 ly_vlog_hide(0);
6481 }
6482
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006483 if (rc != EXIT_FAILURE) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006484 if (rc == -1 && ly_errno == LY_EVALID) {
Radek Krejci2467a492016-10-24 15:16:59 +02006485 ly_err_repeat();
Radek Krejci010e54b2016-03-15 09:40:34 +01006486 }
Radek Krejcid09d1a52016-08-11 14:05:45 +02006487 if (type == UNRES_LIST_UNIQ) {
6488 /* free the allocated structure */
6489 free(item);
Pavol Vican88e16c92016-09-07 15:41:50 +02006490 } else if (rc == -1 && type == UNRES_IFFEAT) {
6491 /* free the allocated resources */
6492 free(*((char **)item));
6493 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006494 return rc;
Radek Krejcif347abc2016-06-22 10:18:47 +02006495 } else {
6496 /* erase info about validation errors */
Radek Krejci00a0e712016-10-26 10:24:46 +02006497 ly_err_clean(1);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006498 }
6499
Radek Krejci48464ed2016-03-17 15:44:09 +01006500 print_unres_schema_item_fail(item, type, snode);
Michal Vaskof02e3742015-08-05 16:27:02 +02006501
Michal Vasko88c29542015-11-27 14:57:53 +01006502 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
Radek Krejci3a5501d2016-07-18 22:03:34 +02006503 if (type == UNRES_TYPE_DER || type == UNRES_TYPE_DER_TPDF) {
Michal Vasko88c29542015-11-27 14:57:53 +01006504 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
Pavol Vicana0e4e672016-02-24 12:20:04 +01006505 if (!(yin->flags & LY_YANG_STRUCTURE_FLAG)) {
6506 lyxml_unlink_elem(mod->ctx, yin, 1);
6507 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
6508 }
Michal Vasko88c29542015-11-27 14:57:53 +01006509 }
6510
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006511 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01006512 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
6513 if (!unres->item) {
6514 LOGMEM;
6515 return -1;
6516 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006517 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01006518 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
6519 if (!unres->type) {
6520 LOGMEM;
6521 return -1;
6522 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006523 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01006524 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
6525 if (!unres->str_snode) {
6526 LOGMEM;
6527 return -1;
6528 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006529 unres->str_snode[unres->count-1] = snode;
Radek Krejcic071c542016-01-27 14:57:51 +01006530 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
6531 if (!unres->module) {
6532 LOGMEM;
6533 return -1;
6534 }
6535 unres->module[unres->count-1] = mod;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006536
Michal Vasko3767fb22016-07-21 12:10:57 +02006537 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006538}
6539
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006540/**
Michal Vaskobb211122015-08-19 14:03:11 +02006541 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006542 *
6543 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006544 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006545 * @param[in] item Old item to be resolved.
6546 * @param[in] type Type of the old unresolved item.
6547 * @param[in] new_item New item to use in the duplicate.
6548 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02006549 * @return EXIT_SUCCESS on success, EXIT_FAILURE if item is not in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006550 */
Michal Vaskodad19402015-08-06 09:51:53 +02006551int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006552unres_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 +02006553{
6554 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006555 struct unres_list_uniq aux_uniq;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006556 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006557
Michal Vaskocf024702015-10-08 15:01:42 +02006558 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006559
Radek Krejcid09d1a52016-08-11 14:05:45 +02006560 /* hack for UNRES_LIST_UNIQ, which stores multiple items behind its item */
6561 if (type == UNRES_LIST_UNIQ) {
6562 aux_uniq.list = item;
6563 aux_uniq.expr = ((struct unres_list_uniq *)new_item)->expr;
6564 item = &aux_uniq;
6565 }
Michal Vasko878e38d2016-09-05 12:17:53 +02006566 i = unres_schema_find(unres, -1, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006567
6568 if (i == -1) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006569 if (type == UNRES_LIST_UNIQ) {
6570 free(new_item);
6571 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02006572 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006573 }
6574
Radek Krejcic79c6b12016-07-26 15:11:49 +02006575 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT) ||
Radek Krejcib69f3232016-09-16 17:41:07 +02006576 (type == UNRES_FEATURE) || (type == UNRES_LIST_UNIQ)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01006577 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006578 LOGINT;
6579 return -1;
6580 }
Radek Krejcicbb473e2016-09-16 14:48:32 +02006581 } else if (type == UNRES_IFFEAT) {
6582 /* duplicate unres_iffeature_data */
6583 iff_data = malloc(sizeof *iff_data);
6584 iff_data->fname = lydict_insert(mod->ctx, ((struct unres_iffeat_data *)unres->str_snode[i])->fname, 0);
6585 iff_data->node = ((struct unres_iffeat_data *)unres->str_snode[i])->node;
6586 if (unres_schema_add_node(mod, unres, new_item, type, (struct lys_node *)iff_data) == -1) {
6587 LOGINT;
6588 return -1;
6589 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006590 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01006591 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006592 LOGINT;
6593 return -1;
6594 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006595 }
Michal Vaskodad19402015-08-06 09:51:53 +02006596
6597 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006598}
6599
Michal Vaskof02e3742015-08-05 16:27:02 +02006600/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006601int
Michal Vasko878e38d2016-09-05 12:17:53 +02006602unres_schema_find(struct unres_schema *unres, int start_on_backwards, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006603{
Michal Vasko878e38d2016-09-05 12:17:53 +02006604 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006605 struct unres_list_uniq *aux_uniq1, *aux_uniq2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006606
Michal Vasko878e38d2016-09-05 12:17:53 +02006607 if (start_on_backwards > 0) {
6608 i = start_on_backwards;
6609 } else {
6610 i = unres->count - 1;
6611 }
6612 for (; i > -1; i--) {
6613 if (unres->type[i] != type) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006614 continue;
6615 }
6616 if (type != UNRES_LIST_UNIQ) {
Michal Vasko878e38d2016-09-05 12:17:53 +02006617 if (unres->item[i] == item) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006618 break;
6619 }
6620 } else {
6621 aux_uniq1 = (struct unres_list_uniq *)unres->item[i - 1];
6622 aux_uniq2 = (struct unres_list_uniq *)item;
6623 if ((aux_uniq1->list == aux_uniq2->list) && ly_strequal(aux_uniq1->expr, aux_uniq2->expr, 0)) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006624 break;
6625 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006626 }
6627 }
6628
Michal Vasko878e38d2016-09-05 12:17:53 +02006629 return i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006630}
Michal Vasko8bcdf292015-08-19 14:04:43 +02006631
Michal Vaskoede9c472016-06-07 09:38:15 +02006632static void
6633unres_schema_free_item(struct ly_ctx *ctx, struct unres_schema *unres, uint32_t i)
6634{
6635 struct lyxml_elem *yin;
6636 struct yang_type *yang;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006637 struct unres_iffeat_data *iff_data;
Michal Vaskoede9c472016-06-07 09:38:15 +02006638
6639 switch (unres->type[i]) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02006640 case UNRES_TYPE_DER_TPDF:
Michal Vaskoede9c472016-06-07 09:38:15 +02006641 case UNRES_TYPE_DER:
6642 yin = (struct lyxml_elem *)((struct lys_type *)unres->item[i])->der;
6643 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6644 yang =(struct yang_type *)yin;
Pavol Vicancf2af4d2016-12-21 14:13:06 +01006645 ((struct lys_type *)unres->item[i])->base = yang->base;
Michal Vaskoede9c472016-06-07 09:38:15 +02006646 lydict_remove(ctx, yang->name);
6647 free(yang);
Pavol Vicancf2af4d2016-12-21 14:13:06 +01006648 if (((struct lys_type *)unres->item[i])->base == LY_TYPE_UNION) {
6649 yang_free_type_union(ctx, (struct lys_type *)unres->item[i]);
6650 }
Michal Vaskoede9c472016-06-07 09:38:15 +02006651 } else {
6652 lyxml_free(ctx, yin);
6653 }
6654 break;
Pavol Vican88e16c92016-09-07 15:41:50 +02006655 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006656 iff_data = (struct unres_iffeat_data *)unres->str_snode[i];
6657 lydict_remove(ctx, iff_data->fname);
6658 free(unres->str_snode[i]);
Pavol Vican88e16c92016-09-07 15:41:50 +02006659 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02006660 case UNRES_IDENT:
6661 case UNRES_TYPE_IDENTREF:
Michal Vaskoede9c472016-06-07 09:38:15 +02006662 case UNRES_CHOICE_DFLT:
6663 case UNRES_LIST_KEYS:
Michal Vaskoede9c472016-06-07 09:38:15 +02006664 lydict_remove(ctx, (const char *)unres->str_snode[i]);
6665 break;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006666 case UNRES_LIST_UNIQ:
6667 free(unres->item[i]);
6668 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02006669 default:
6670 break;
6671 }
6672 unres->type[i] = UNRES_RESOLVED;
6673}
6674
Michal Vasko88c29542015-11-27 14:57:53 +01006675void
Radek Krejcic071c542016-01-27 14:57:51 +01006676unres_schema_free(struct lys_module *module, struct unres_schema **unres)
Michal Vasko88c29542015-11-27 14:57:53 +01006677{
6678 uint32_t i;
Radek Krejcic071c542016-01-27 14:57:51 +01006679 unsigned int unresolved = 0;
Michal Vasko88c29542015-11-27 14:57:53 +01006680
Radek Krejcic071c542016-01-27 14:57:51 +01006681 if (!unres || !(*unres)) {
6682 return;
Michal Vasko88c29542015-11-27 14:57:53 +01006683 }
6684
Radek Krejcic071c542016-01-27 14:57:51 +01006685 assert(module || (*unres)->count == 0);
6686
6687 for (i = 0; i < (*unres)->count; ++i) {
6688 if ((*unres)->module[i] != module) {
6689 if ((*unres)->type[i] != UNRES_RESOLVED) {
6690 unresolved++;
6691 }
6692 continue;
6693 }
Michal Vaskoede9c472016-06-07 09:38:15 +02006694
6695 /* free heap memory for the specific item */
6696 unres_schema_free_item(module->ctx, *unres, i);
Radek Krejcic071c542016-01-27 14:57:51 +01006697 }
6698
Michal Vaskoede9c472016-06-07 09:38:15 +02006699 /* free it all */
Radek Krejcic071c542016-01-27 14:57:51 +01006700 if (!module || (!unresolved && !module->type)) {
6701 free((*unres)->item);
6702 free((*unres)->type);
6703 free((*unres)->str_snode);
6704 free((*unres)->module);
Radek Krejcic071c542016-01-27 14:57:51 +01006705 free((*unres));
6706 (*unres) = NULL;
6707 }
Michal Vasko88c29542015-11-27 14:57:53 +01006708}
6709
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006710/**
6711 * @brief Resolve instance-identifier in JSON data format. Logs directly.
6712 *
6713 * @param[in] data Data node where the path is used
6714 * @param[in] path Instance-identifier node value.
6715 * @param[in,out] ret Resolved instance or NULL.
6716 *
6717 * @return 0 on success (even if unresolved and \p ret is NULL), -1 on error.
6718 */
6719static int
6720resolve_instid(struct lyd_node *data, const char *path, int req_inst, struct lyd_node **ret)
6721{
6722 int i = 0, j;
6723 const struct lys_module *mod;
6724 struct ly_ctx *ctx = data->schema->module->ctx;
6725 const char *model, *name;
6726 char *str;
6727 int mod_len, name_len, has_predicate;
6728 struct unres_data node_match;
6729
6730 memset(&node_match, 0, sizeof node_match);
6731 *ret = NULL;
6732
6733 /* we need root to resolve absolute path */
6734 for (; data->parent; data = data->parent);
6735 /* we're still parsing it and the pointer is not correct yet */
6736 if (data->prev) {
6737 for (; data->prev->next; data = data->prev);
6738 }
6739
6740 /* search for the instance node */
6741 while (path[i]) {
6742 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
6743 if (j <= 0) {
6744 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
6745 goto error;
6746 }
6747 i += j;
6748
6749 str = strndup(model, mod_len);
6750 if (!str) {
6751 LOGMEM;
6752 goto error;
6753 }
6754 mod = ly_ctx_get_module(ctx, str, NULL);
6755 free(str);
6756
6757 if (resolve_data(mod, name, name_len, data, &node_match)) {
6758 /* no instance exists */
6759 break;
6760 }
6761
6762 if (has_predicate) {
6763 /* we have predicate, so the current results must be list or leaf-list */
6764 j = resolve_predicate(&path[i], &node_match);
6765 if (j < 1) {
6766 LOGVAL(LYE_INPRED, LY_VLOG_LYD, data, &path[i-j]);
6767 goto error;
6768 }
6769 i += j;
6770
6771 if (!node_match.count) {
6772 /* no instance exists */
6773 break;
6774 }
6775 }
6776 }
6777
6778 if (!node_match.count) {
6779 /* no instance exists */
6780 if (req_inst > -1) {
6781 LOGVAL(LYE_NOREQINS, LY_VLOG_NONE, NULL, path);
6782 return EXIT_FAILURE;
6783 }
6784 LOGVRB("There is no instance of \"%s\", but it is not required.", path);
6785 return EXIT_SUCCESS;
6786 } else if (node_match.count > 1) {
6787 /* instance identifier must resolve to a single node */
6788 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
6789 goto error;
6790 } else {
6791 /* we have required result, remember it and cleanup */
6792 *ret = node_match.node[0];
6793 free(node_match.node);
6794 return EXIT_SUCCESS;
6795 }
6796
6797error:
6798 /* cleanup */
6799 free(node_match.node);
6800 return -1;
6801}
6802
6803static int
6804resolve_leafref(struct lyd_node_leaf_list *leaf, const char *path, int req_inst, struct lyd_node **ret)
Radek Krejci7de36cf2016-09-12 16:18:50 +02006805{
Radek Krejci7de36cf2016-09-12 16:18:50 +02006806 struct unres_data matches;
6807 uint32_t i;
6808
Radek Krejci9b6aad22016-09-20 15:55:51 +02006809 /* init */
Radek Krejci7de36cf2016-09-12 16:18:50 +02006810 memset(&matches, 0, sizeof matches);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006811 *ret = NULL;
Radek Krejci7de36cf2016-09-12 16:18:50 +02006812
6813 /* EXIT_FAILURE return keeps leaf->value.lefref NULL, handled later */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006814 if (resolve_path_arg_data((struct lyd_node *)leaf, path, &matches) == -1) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02006815 return -1;
6816 }
6817
6818 /* check that value matches */
6819 for (i = 0; i < matches.count; ++i) {
Radek Krejci1899d6a2016-11-03 13:48:07 +01006820 /* not that the value is already in canonical form since the parsers does the conversion,
6821 * so we can simply compare just the values */
Radek Krejci7de36cf2016-09-12 16:18:50 +02006822 if (ly_strequal(leaf->value_str, ((struct lyd_node_leaf_list *)matches.node[i])->value_str, 1)) {
Radek Krejci1899d6a2016-11-03 13:48:07 +01006823 /* we have the match */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006824 *ret = matches.node[i];
Radek Krejci7de36cf2016-09-12 16:18:50 +02006825 break;
6826 }
6827 }
6828
6829 free(matches.node);
6830
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006831 if (!*ret) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02006832 /* reference not found */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006833 if (req_inst > -1) {
6834 LOGVAL(LYE_NOLEAFREF, LY_VLOG_LYD, leaf, path, leaf->value_str);
Radek Krejci7de36cf2016-09-12 16:18:50 +02006835 return EXIT_FAILURE;
6836 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006837 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 +02006838 }
6839 }
6840
6841 return EXIT_SUCCESS;
6842}
6843
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006844/* ignore fail because we are parsing edit-config, get, or get-config - but only if the union includes leafref or instid */
Radek Krejci9b6aad22016-09-20 15:55:51 +02006845static int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006846resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type, int ignore_fail)
Radek Krejci9b6aad22016-09-20 15:55:51 +02006847{
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006848 struct lys_type *t;
6849 struct lyd_node *ret;
6850 int found, hidden, success = 0;
6851 const char *json_val = NULL;
Radek Krejci9b6aad22016-09-20 15:55:51 +02006852
6853 assert(type->base == LY_TYPE_UNION);
6854
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006855 if ((leaf->value_type == LY_TYPE_UNION) || (leaf->value_type == (LY_TYPE_INST | LY_TYPE_INST_UNRES))) {
6856 /* either NULL or instid previously converted to JSON */
6857 json_val = leaf->value.string;
6858 }
Radek Krejci9b6aad22016-09-20 15:55:51 +02006859 memset(&leaf->value, 0, sizeof leaf->value);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006860
6861 /* turn logging off, we are going to try to validate the value with all the types in order */
6862 hidden = *ly_vlog_hide_location();
6863 ly_vlog_hide(1);
6864
6865 t = NULL;
6866 found = 0;
6867 while ((t = lyp_get_next_union_type(type, t, &found))) {
6868 found = 0;
6869
6870 switch (t->base) {
6871 case LY_TYPE_LEAFREF:
6872 if (!resolve_leafref(leaf, t->info.lref.path, (ignore_fail ? -1 : t->info.lref.req), &ret)) {
6873 if (ret) {
6874 /* valid resolved */
6875 leaf->value.leafref = ret;
6876 leaf->value_type = LY_TYPE_LEAFREF;
6877 } else {
6878 /* valid unresolved */
6879 if (!lyp_parse_value(t, &leaf->value_str, NULL, leaf, 1, 0)) {
6880 return -1;
6881 }
6882 }
6883
6884 success = 1;
6885 }
6886 break;
6887 case LY_TYPE_INST:
6888 if (!resolve_instid((struct lyd_node *)leaf, (json_val ? json_val : leaf->value_str),
6889 (ignore_fail ? -1 : t->info.inst.req), &ret)) {
6890 if (ret) {
6891 /* valid resolved */
6892 leaf->value.instance = ret;
6893 leaf->value_type = LY_TYPE_INST;
6894
6895 if (json_val) {
6896 lydict_remove(leaf->schema->module->ctx, leaf->value_str);
6897 leaf->value_str = json_val;
6898 json_val = NULL;
6899 }
6900 } else {
6901 /* valid unresolved */
6902 if (json_val) {
6903 /* put the JSON val back */
6904 leaf->value.string = json_val;
6905 json_val = NULL;
6906 } else {
6907 leaf->value.instance = NULL;
6908 }
6909 leaf->value_type = LY_TYPE_INST | LY_TYPE_INST_UNRES;
6910 }
6911
6912 success = 1;
6913 }
6914 break;
6915 default:
6916 if (lyp_parse_value(t, &leaf->value_str, NULL, leaf, 1, 0)) {
6917 success = 1;
6918 }
6919 break;
6920 }
6921
6922 if (success) {
6923 break;
6924 }
6925
6926 /* erase information about errors - they are false or irrelevant
6927 * and will be replaced by a single error messages */
6928 ly_err_clean(1);
6929
6930 /* erase possible present and invalid value data */
6931 if (t->base == LY_TYPE_BITS) {
6932 free(leaf->value.bit);
6933 }
6934 memset(&leaf->value, 0, sizeof leaf->value);
6935 }
6936
6937 /* turn logging back on */
6938 if (!hidden) {
6939 ly_vlog_hide(0);
6940 }
6941
6942 if (json_val) {
6943 if (!success) {
6944 /* put the value back for now */
6945 assert(leaf->value_type == LY_TYPE_UNION);
6946 leaf->value.string = json_val;
6947 } else {
6948 /* value was ultimately useless, but we could not have known */
6949 lydict_remove(leaf->schema->module->ctx, json_val);
6950 }
6951 }
6952
6953 if (!success && (!ignore_fail || !type->info.uni.has_ptr_type)) {
6954 /* not found and it is required */
6955 LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, leaf->value_str ? leaf->value_str : "", leaf->schema->name);
Radek Krejci9b6aad22016-09-20 15:55:51 +02006956 return EXIT_FAILURE;
6957 }
6958
6959 return EXIT_SUCCESS;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006960
Radek Krejci9b6aad22016-09-20 15:55:51 +02006961}
6962
Michal Vasko8bcdf292015-08-19 14:04:43 +02006963/**
6964 * @brief Resolve a single unres data item. Logs directly.
6965 *
Michal Vaskocf024702015-10-08 15:01:42 +02006966 * @param[in] node Data node to resolve.
Michal Vaskocf024702015-10-08 15:01:42 +02006967 * @param[in] type Type of the unresolved item.
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006968 * @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 +02006969 *
6970 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
6971 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02006972int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006973resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type, int ignore_fail)
Michal Vasko8bcdf292015-08-19 14:04:43 +02006974{
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006975 int rc, req_inst;
Michal Vasko83a6c462015-10-08 16:43:53 +02006976 struct lyd_node_leaf_list *leaf;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006977 struct lyd_node *ret;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006978 struct lys_node_leaf *sleaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006979
Michal Vasko83a6c462015-10-08 16:43:53 +02006980 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02006981 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006982
Michal Vaskocf024702015-10-08 15:01:42 +02006983 switch (type) {
6984 case UNRES_LEAFREF:
6985 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006986 assert(leaf->validity & LYD_VAL_LEAFREF);
6987 req_inst = (ignore_fail ? -1 : sleaf->type.info.lref.req);
6988 rc = resolve_leafref(leaf, sleaf->type.info.lref.path, req_inst, &ret);
6989 if (!rc) {
6990 if (ret) {
6991 /* valid resolved */
6992 leaf->value.leafref = ret;
6993 leaf->value_type = LY_TYPE_LEAFREF;
6994 } else {
6995 /* valid unresolved */
6996 if (!(leaf->value_type & LY_TYPE_LEAFREF_UNRES)) {
6997 if (!lyp_parse_value(&sleaf->type, &leaf->value_str, NULL, leaf, 1, 0)) {
6998 return -1;
6999 }
7000 }
7001 }
7002 leaf->validity &= ~LYD_VAL_LEAFREF;
7003 } else {
7004 return rc;
7005 }
7006 break;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007007
Michal Vaskocf024702015-10-08 15:01:42 +02007008 case UNRES_INSTID:
Radek Krejci7de36cf2016-09-12 16:18:50 +02007009 assert(sleaf->type.base == LY_TYPE_INST);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007010 req_inst = (ignore_fail ? -1 : sleaf->type.info.inst.req);
7011 rc = resolve_instid(node, leaf->value_str, req_inst, &ret);
7012 if (!rc) {
7013 if (ret) {
7014 /* valid resolved */
7015 leaf->value.instance = ret;
7016 leaf->value_type = LY_TYPE_INST;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007017 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007018 /* valid unresolved */
7019 leaf->value.instance = NULL;
7020 leaf->value_type = LY_TYPE_INST | LY_TYPE_INST_UNRES;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007021 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007022 } else {
7023 return rc;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007024 }
Michal Vaskocf024702015-10-08 15:01:42 +02007025 break;
7026
Radek Krejci7de36cf2016-09-12 16:18:50 +02007027 case UNRES_UNION:
7028 assert(sleaf->type.base == LY_TYPE_UNION);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007029 return resolve_union(leaf, &sleaf->type, ignore_fail);
Radek Krejci7de36cf2016-09-12 16:18:50 +02007030
Michal Vaskocf024702015-10-08 15:01:42 +02007031 case UNRES_WHEN:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007032 if ((rc = resolve_when(node, NULL, ignore_fail))) {
Michal Vaskocf024702015-10-08 15:01:42 +02007033 return rc;
7034 }
7035 break;
7036
Michal Vaskobf19d252015-10-08 15:39:17 +02007037 case UNRES_MUST:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007038 if ((rc = resolve_must(node, 0, ignore_fail))) {
Michal Vaskoc8c810c2016-09-15 14:02:00 +02007039 return rc;
7040 }
7041 break;
7042
7043 case UNRES_MUST_INOUT:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007044 if ((rc = resolve_must(node, 1, ignore_fail))) {
Michal Vaskobf19d252015-10-08 15:39:17 +02007045 return rc;
7046 }
7047 break;
7048
Michal Vaskocf024702015-10-08 15:01:42 +02007049 default:
Michal Vasko8bcdf292015-08-19 14:04:43 +02007050 LOGINT;
7051 return -1;
7052 }
7053
7054 return EXIT_SUCCESS;
7055}
7056
7057/**
Radek Krejci0b7704f2016-03-18 12:16:14 +01007058 * @brief add data unres item
Michal Vasko8bcdf292015-08-19 14:04:43 +02007059 *
7060 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02007061 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007062 *
Radek Krejci0b7704f2016-03-18 12:16:14 +01007063 * @return 0 on success, -1 on error.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007064 */
7065int
Radek Krejci0b7704f2016-03-18 12:16:14 +01007066unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02007067{
Radek Krejci03b71f72016-03-16 11:10:09 +01007068 assert(unres && node);
Michal Vaskoc4280842016-04-19 16:10:42 +02007069 assert((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)
Radek Krejcibacc7442016-10-27 13:39:56 +02007070 || (type == UNRES_MUST_INOUT) || (type == UNRES_UNION));
Michal Vasko8bcdf292015-08-19 14:04:43 +02007071
Radek Krejci03b71f72016-03-16 11:10:09 +01007072 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01007073 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
7074 if (!unres->node) {
7075 LOGMEM;
7076 return -1;
7077 }
Michal Vaskocf024702015-10-08 15:01:42 +02007078 unres->node[unres->count - 1] = node;
Michal Vasko253035f2015-12-17 16:58:13 +01007079 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
7080 if (!unres->type) {
7081 LOGMEM;
7082 return -1;
7083 }
Michal Vaskocf024702015-10-08 15:01:42 +02007084 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007085
Radek Krejci0b7704f2016-03-18 12:16:14 +01007086 if (type == UNRES_WHEN) {
7087 /* remove previous result */
7088 node->when_status = LYD_WHEN;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007089 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007090
7091 return EXIT_SUCCESS;
7092}
7093
7094/**
7095 * @brief Resolve every unres data item in the structure. Logs directly.
7096 *
Radek Krejci082c84f2016-10-17 16:33:06 +02007097 * If options includes LYD_OPT_TRUSTED, the data are considered trusted (when, must conditions are not expected,
7098 * unresolved leafrefs/instids are accepted).
7099 *
7100 * If options includes LYD_OPT_NOAUTODEL, the false resulting when condition on non-default nodes, the error is raised.
7101 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007102 * @param[in] unres Unres data structure to use.
Radek Krejci082c84f2016-10-17 16:33:06 +02007103 * @param[in,out] root Root node of the data tree, can be changed due to autodeletion.
7104 * @param[in] options Data options as described above.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007105 *
7106 * @return EXIT_SUCCESS on success, -1 on error.
7107 */
7108int
Radek Krejci082c84f2016-10-17 16:33:06 +02007109resolve_unres_data(struct unres_data *unres, struct lyd_node **root, int options)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007110{
Radek Krejci0c0086a2016-03-24 15:20:28 +01007111 uint32_t i, j, first = 1, resolved = 0, del_items = 0, when_stmt = 0;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007112 int rc, progress, ignore_fails;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007113 struct lyd_node *parent;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007114 //struct lyd_node_leaf_list *leaf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007115
Radek Krejci082c84f2016-10-17 16:33:06 +02007116 assert(root);
Radek Krejci03b71f72016-03-16 11:10:09 +01007117 assert(unres);
Radek Krejci03b71f72016-03-16 11:10:09 +01007118
7119 if (!unres->count) {
7120 return EXIT_SUCCESS;
7121 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007122
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007123 if (options & (LYD_OPT_TRUSTED | LYD_OPT_GET | LYD_OPT_GETCONFIG | LYD_OPT_EDIT)) {
7124 ignore_fails = 1;
7125 } else {
7126 ignore_fails = 0;
7127 }
7128
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02007129 LOGVRB("Resolving unresolved data nodes and their constraints...");
Radek Krejci010e54b2016-03-15 09:40:34 +01007130 ly_vlog_hide(1);
7131
Radek Krejci0b7704f2016-03-18 12:16:14 +01007132 /* when-stmt first */
Radek Krejci010e54b2016-03-15 09:40:34 +01007133 do {
Radek Krejci00a0e712016-10-26 10:24:46 +02007134 ly_err_clean(1);
Radek Krejci010e54b2016-03-15 09:40:34 +01007135 progress = 0;
Michal Vasko6df94132016-09-22 11:08:09 +02007136 for (i = 0; i < unres->count; i++) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007137 if (unres->type[i] != UNRES_WHEN) {
7138 continue;
7139 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007140 if (first) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007141 /* count when-stmt nodes in unres list */
7142 when_stmt++;
7143 }
7144
7145 /* resolve when condition only when all parent when conditions are already resolved */
7146 for (parent = unres->node[i]->parent;
7147 parent && LYD_WHEN_DONE(parent->when_status);
7148 parent = parent->parent) {
7149 if (!parent->parent && (parent->when_status & LYD_WHEN_FALSE)) {
7150 /* the parent node was already unlinked, do not resolve this node,
7151 * it will be removed anyway, so just mark it as resolved
7152 */
7153 unres->node[i]->when_status |= LYD_WHEN_FALSE;
7154 unres->type[i] = UNRES_RESOLVED;
7155 resolved++;
7156 break;
7157 }
7158 }
7159 if (parent) {
7160 continue;
7161 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007162
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007163 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fails);
Radek Krejci010e54b2016-03-15 09:40:34 +01007164 if (!rc) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007165 if (unres->node[i]->when_status & LYD_WHEN_FALSE) {
Radek Krejci082c84f2016-10-17 16:33:06 +02007166 if ((options & LYD_OPT_NOAUTODEL) && !unres->node[i]->dflt) {
Radek Krejci03b71f72016-03-16 11:10:09 +01007167 /* false when condition */
7168 ly_vlog_hide(0);
Radek Krejci2467a492016-10-24 15:16:59 +02007169 ly_err_repeat();
Radek Krejci03b71f72016-03-16 11:10:09 +01007170 return -1;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007171 } /* follows else */
7172
Radek Krejci0c0086a2016-03-24 15:20:28 +01007173 /* only unlink now, the subtree can contain another nodes stored in the unres list */
7174 /* if it has parent non-presence containers that would be empty, we should actually
7175 * remove the container
7176 */
Radek Krejci2537fd32016-09-07 16:22:41 +02007177 for (parent = unres->node[i];
7178 parent->parent && parent->parent->schema->nodetype == LYS_CONTAINER;
7179 parent = parent->parent) {
7180 if (((struct lys_node_container *)parent->parent->schema)->presence) {
7181 /* presence container */
7182 break;
Radek Krejci0c0086a2016-03-24 15:20:28 +01007183 }
Radek Krejci2537fd32016-09-07 16:22:41 +02007184 if (parent->next || parent->prev != parent) {
7185 /* non empty (the child we are in and we are going to remove is not the only child) */
7186 break;
7187 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007188 }
Radek Krejci2537fd32016-09-07 16:22:41 +02007189 unres->node[i] = parent;
Radek Krejci0c0086a2016-03-24 15:20:28 +01007190
Radek Krejci0b7704f2016-03-18 12:16:14 +01007191 /* auto-delete */
7192 LOGVRB("auto-delete node \"%s\" due to when condition (%s)", ly_errpath(),
7193 ((struct lys_node_leaf *)unres->node[i]->schema)->when->cond);
Radek Krejci0c0086a2016-03-24 15:20:28 +01007194 if (*root && *root == unres->node[i]) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007195 *root = (*root)->next;
Radek Krejci03b71f72016-03-16 11:10:09 +01007196 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007197
Radek Krejci0b7704f2016-03-18 12:16:14 +01007198 lyd_unlink(unres->node[i]);
7199 unres->type[i] = UNRES_DELETE;
7200 del_items++;
Radek Krejci51fd8162016-03-24 15:49:51 +01007201
7202 /* update the rest of unres items */
7203 for (j = 0; j < unres->count; j++) {
Radek Krejci3db819b2016-03-24 16:29:48 +01007204 if (unres->type[j] == UNRES_RESOLVED || unres->type[j] == UNRES_DELETE) {
Radek Krejci51fd8162016-03-24 15:49:51 +01007205 continue;
7206 }
7207
7208 /* test if the node is in subtree to be deleted */
7209 for (parent = unres->node[j]; parent; parent = parent->parent) {
7210 if (parent == unres->node[i]) {
7211 /* yes, it is */
7212 unres->type[j] = UNRES_RESOLVED;
7213 resolved++;
7214 break;
7215 }
7216 }
7217 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007218 } else {
7219 unres->type[i] = UNRES_RESOLVED;
Radek Krejci03b71f72016-03-16 11:10:09 +01007220 }
Radek Krejci00a0e712016-10-26 10:24:46 +02007221 ly_err_clean(1);
Radek Krejci010e54b2016-03-15 09:40:34 +01007222 resolved++;
7223 progress = 1;
7224 } else if (rc == -1) {
7225 ly_vlog_hide(0);
Michal Vasko76e73402016-08-24 16:00:13 +02007226 /* print only this last error */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007227 resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fails);
Radek Krejci010e54b2016-03-15 09:40:34 +01007228 return -1;
Radek Krejci2467a492016-10-24 15:16:59 +02007229 } /* else forward reference */
Radek Krejci010e54b2016-03-15 09:40:34 +01007230 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007231 first = 0;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007232 } while (progress && resolved < when_stmt);
Radek Krejci010e54b2016-03-15 09:40:34 +01007233
Radek Krejci0b7704f2016-03-18 12:16:14 +01007234 /* do we have some unresolved when-stmt? */
Radek Krejcid940d732016-03-24 16:02:28 +01007235 if (when_stmt > resolved) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007236 ly_vlog_hide(0);
Radek Krejci2467a492016-10-24 15:16:59 +02007237 ly_err_repeat();
Radek Krejci0b7704f2016-03-18 12:16:14 +01007238 return -1;
7239 }
7240
7241 for (i = 0; del_items && i < unres->count; i++) {
7242 /* we had some when-stmt resulted to false, so now we have to sanitize the unres list */
7243 if (unres->type[i] != UNRES_DELETE) {
7244 continue;
7245 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007246 if (!unres->node[i]) {
7247 unres->type[i] = UNRES_RESOLVED;
7248 del_items--;
7249 continue;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007250 }
7251
7252 /* really remove the complete subtree */
7253 lyd_free(unres->node[i]);
7254 unres->type[i] = UNRES_RESOLVED;
7255 del_items--;
7256 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007257 ly_vlog_hide(0);
Radek Krejci010e54b2016-03-15 09:40:34 +01007258
7259 /* rest */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007260 for (i = 0; i < unres->count; ++i) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007261 if (unres->type[i] == UNRES_RESOLVED) {
7262 continue;
7263 }
Radek Krejci082c84f2016-10-17 16:33:06 +02007264 assert(!(options & LYD_OPT_TRUSTED) || ((unres->type[i] != UNRES_MUST) && (unres->type[i] != UNRES_MUST_INOUT)));
Radek Krejci010e54b2016-03-15 09:40:34 +01007265
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007266 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fails);
7267 if (rc) {
7268 /* since when was already resolved, a forward reference is an error */
7269 //ly_vlog_hide(0);
Michal Vasko96b846c2016-05-18 13:28:58 +02007270 /* print only this last error */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007271 //resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fails);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007272 return -1;
7273 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007274
7275 unres->type[i] = UNRES_RESOLVED;
7276 //resolved++;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007277 }
7278
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007279 //ly_vlog_hide(0);
7280 //if (resolved < unres->count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007281 /* try to resolve the unresolved data again, it will not resolve anything, but it will print
7282 * all the validation errors
7283 */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007284 //for (i = 0; i < unres->count; ++i) {
7285 //if (unres->type[i] == UNRES_UNION) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02007286 /* does not make sense to print specific errors for all
7287 * the data types, just print that the value is invalid */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007288 /*leaf = (struct lyd_node_leaf_list *)unres->node[i];
Radek Krejci7de36cf2016-09-12 16:18:50 +02007289 LOGVAL(LYE_INVAL, LY_VLOG_LYD, unres->node[i], (leaf->value_str ? leaf->value_str : ""),
7290 leaf->schema->name);
7291 } else if (unres->type[i] != UNRES_RESOLVED) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007292 resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fails);
Radek Krejci010e54b2016-03-15 09:40:34 +01007293 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007294 }
7295 return -1;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007296 }*/
Radek Krejci010e54b2016-03-15 09:40:34 +01007297
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02007298 LOGVRB("All data nodes and constraints resolved.");
Radek Krejci010e54b2016-03-15 09:40:34 +01007299 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007300 return EXIT_SUCCESS;
7301}