blob: 71e6e8c863b45a6b9df244f57ccdd32be064a64c [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 Vaskof9b35d92016-10-21 15:19:30 +020033static int resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type);
34
Michal Vaskod24dd012016-09-30 12:20:22 +020035int
36parse_range_dec64(const char **str_num, uint8_t dig, int64_t *num)
Michal Vasko4d1f0482016-09-19 14:35:06 +020037{
38 const char *ptr;
39 int minus = 0;
40 int64_t ret = 0;
Radek Krejcibf47a822016-11-04 10:06:08 +010041 int8_t str_exp, str_dig = -1, trailing_zeros = 0;
Michal Vasko4d1f0482016-09-19 14:35:06 +020042
43 ptr = *str_num;
44
45 if (ptr[0] == '-') {
46 minus = 1;
47 ++ptr;
Radek Krejci51673202016-11-01 17:00:32 +010048 } else if (ptr[0] == '+') {
49 ++ptr;
Michal Vasko4d1f0482016-09-19 14:35:06 +020050 }
51
Michal Vaskod24dd012016-09-30 12:20:22 +020052 if (!isdigit(ptr[0])) {
53 /* there must be at least one */
54 return 1;
55 }
56
Michal Vasko4d1f0482016-09-19 14:35:06 +020057 for (str_exp = 0; isdigit(ptr[0]) || ((ptr[0] == '.') && (str_dig < 0)); ++ptr) {
58 if (str_exp > 18) {
Michal Vaskod24dd012016-09-30 12:20:22 +020059 return 1;
Michal Vasko4d1f0482016-09-19 14:35:06 +020060 }
61
62 if (ptr[0] == '.') {
63 if (ptr[1] == '.') {
64 /* it's the next interval */
65 break;
66 }
67 ++str_dig;
68 } else {
Radek Krejcibf47a822016-11-04 10:06:08 +010069 ret = ret * 10 + (ptr[0] - '0');
Michal Vasko4d1f0482016-09-19 14:35:06 +020070 if (str_dig > -1) {
71 ++str_dig;
Radek Krejcibf47a822016-11-04 10:06:08 +010072 if (ptr[0] == '0') {
73 /* possibly trailing zero */
74 trailing_zeros++;
75 } else {
76 trailing_zeros = 0;
77 }
Michal Vasko4d1f0482016-09-19 14:35:06 +020078 }
79 ++str_exp;
80 }
81 }
Michal Vaskod24dd012016-09-30 12:20:22 +020082 if (str_dig == 0) {
83 /* no digits after '.' */
84 return 1;
85 } else if (str_dig == -1) {
86 /* there are 0 numbers after the floating point */
Michal Vasko4d1f0482016-09-19 14:35:06 +020087 str_dig = 0;
88 }
Radek Krejcibf47a822016-11-04 10:06:08 +010089 /* remove trailing zeros */
90 if (trailing_zeros) {
91 str_dig = str_dig - trailing_zeros;
92 ret = ret / dec_pow(trailing_zeros);
93 }
Michal Vasko4d1f0482016-09-19 14:35:06 +020094
95 /* it's parsed, now adjust the number based on fraction-digits, if needed */
96 if (str_dig < dig) {
97 if ((str_exp - 1) + (dig - str_dig) > 18) {
Michal Vaskod24dd012016-09-30 12:20:22 +020098 return 1;
Michal Vasko4d1f0482016-09-19 14:35:06 +020099 }
100 ret *= dec_pow(dig - str_dig);
101 }
102 if (str_dig > dig) {
Michal Vaskod24dd012016-09-30 12:20:22 +0200103 return 1;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200104 }
105
106 if (minus) {
107 ret *= -1;
108 }
109 *str_num = ptr;
Michal Vaskod24dd012016-09-30 12:20:22 +0200110 *num = ret;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200111
Michal Vaskod24dd012016-09-30 12:20:22 +0200112 return 0;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200113}
114
115/**
Radek Krejci6dc53a22015-08-17 13:27:59 +0200116 * @brief Parse an identifier.
117 *
118 * ;; An identifier MUST NOT start with (('X'|'x') ('M'|'m') ('L'|'l'))
119 * identifier = (ALPHA / "_")
120 * *(ALPHA / DIGIT / "_" / "-" / ".")
121 *
Michal Vaskobb211122015-08-19 14:03:11 +0200122 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200123 *
124 * @return Number of characters successfully parsed.
125 */
Michal Vasko249e6b52015-08-19 11:08:52 +0200126int
Radek Krejci6dc53a22015-08-17 13:27:59 +0200127parse_identifier(const char *id)
128{
129 int parsed = 0;
130
Michal Vasko1ab90bc2016-03-15 10:40:22 +0100131 assert(id);
132
Radek Krejci6dc53a22015-08-17 13:27:59 +0200133 if (!isalpha(id[0]) && (id[0] != '_')) {
134 return -parsed;
135 }
136
137 ++parsed;
138 ++id;
139
140 while (isalnum(id[0]) || (id[0] == '_') || (id[0] == '-') || (id[0] == '.')) {
141 ++parsed;
142 ++id;
143 }
144
145 return parsed;
146}
147
148/**
149 * @brief Parse a node-identifier.
150 *
Michal Vasko723e50c2015-10-20 15:20:29 +0200151 * node-identifier = [module-name ":"] identifier
Radek Krejci6dc53a22015-08-17 13:27:59 +0200152 *
Michal Vaskobb211122015-08-19 14:03:11 +0200153 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200154 * @param[out] mod_name Points to the module name, NULL if there is not any.
155 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200156 * @param[out] name Points to the node name.
157 * @param[out] nam_len Length of the node name.
158 *
159 * @return Number of characters successfully parsed,
160 * positive on success, negative on failure.
161 */
162static int
Michal Vasko723e50c2015-10-20 15:20:29 +0200163parse_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 +0200164{
165 int parsed = 0, ret;
166
167 assert(id);
Michal Vasko723e50c2015-10-20 15:20:29 +0200168 if (mod_name) {
169 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200170 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200171 if (mod_name_len) {
172 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200173 }
174 if (name) {
175 *name = NULL;
176 }
177 if (nam_len) {
178 *nam_len = 0;
179 }
180
181 if ((ret = parse_identifier(id)) < 1) {
182 return ret;
183 }
184
Michal Vasko723e50c2015-10-20 15:20:29 +0200185 if (mod_name) {
186 *mod_name = id;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200187 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200188 if (mod_name_len) {
189 *mod_name_len = ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200190 }
191
192 parsed += ret;
193 id += ret;
194
195 /* there is prefix */
196 if (id[0] == ':') {
197 ++parsed;
198 ++id;
199
200 /* there isn't */
201 } else {
Michal Vasko723e50c2015-10-20 15:20:29 +0200202 if (name && mod_name) {
203 *name = *mod_name;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200204 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200205 if (mod_name) {
206 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200207 }
208
Michal Vasko723e50c2015-10-20 15:20:29 +0200209 if (nam_len && mod_name_len) {
210 *nam_len = *mod_name_len;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200211 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200212 if (mod_name_len) {
213 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200214 }
215
216 return parsed;
217 }
218
219 /* identifier (node name) */
220 if ((ret = parse_identifier(id)) < 1) {
221 return -parsed+ret;
222 }
223
224 if (name) {
225 *name = id;
226 }
227 if (nam_len) {
228 *nam_len = ret;
229 }
230
231 return parsed+ret;
232}
233
234/**
235 * @brief Parse a path-predicate (leafref).
236 *
237 * path-predicate = "[" *WSP path-equality-expr *WSP "]"
238 * path-equality-expr = node-identifier *WSP "=" *WSP path-key-expr
239 *
Michal Vaskobb211122015-08-19 14:03:11 +0200240 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200241 * @param[out] prefix Points to the prefix, NULL if there is not any.
242 * @param[out] pref_len Length of the prefix, 0 if there is not any.
243 * @param[out] name Points to the node name.
244 * @param[out] nam_len Length of the node name.
245 * @param[out] path_key_expr Points to the path-key-expr.
246 * @param[out] pke_len Length of the path-key-expr.
247 * @param[out] has_predicate Flag to mark whether there is another predicate following.
248 *
249 * @return Number of characters successfully parsed,
250 * positive on success, negative on failure.
251 */
252static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200253parse_path_predicate(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
254 const char **path_key_expr, int *pke_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200255{
256 const char *ptr;
257 int parsed = 0, ret;
258
259 assert(id);
260 if (prefix) {
261 *prefix = NULL;
262 }
263 if (pref_len) {
264 *pref_len = 0;
265 }
266 if (name) {
267 *name = NULL;
268 }
269 if (nam_len) {
270 *nam_len = 0;
271 }
272 if (path_key_expr) {
273 *path_key_expr = NULL;
274 }
275 if (pke_len) {
276 *pke_len = 0;
277 }
278 if (has_predicate) {
279 *has_predicate = 0;
280 }
281
282 if (id[0] != '[') {
283 return -parsed;
284 }
285
286 ++parsed;
287 ++id;
288
289 while (isspace(id[0])) {
290 ++parsed;
291 ++id;
292 }
293
294 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
295 return -parsed+ret;
296 }
297
298 parsed += ret;
299 id += ret;
300
301 while (isspace(id[0])) {
302 ++parsed;
303 ++id;
304 }
305
306 if (id[0] != '=') {
307 return -parsed;
308 }
309
310 ++parsed;
311 ++id;
312
313 while (isspace(id[0])) {
314 ++parsed;
315 ++id;
316 }
317
318 if ((ptr = strchr(id, ']')) == NULL) {
319 return -parsed;
320 }
321
322 --ptr;
323 while (isspace(ptr[0])) {
324 --ptr;
325 }
326 ++ptr;
327
328 ret = ptr-id;
329 if (path_key_expr) {
330 *path_key_expr = id;
331 }
332 if (pke_len) {
333 *pke_len = ret;
334 }
335
336 parsed += ret;
337 id += ret;
338
339 while (isspace(id[0])) {
340 ++parsed;
341 ++id;
342 }
343
344 assert(id[0] == ']');
345
346 if (id[1] == '[') {
347 *has_predicate = 1;
348 }
349
350 return parsed+1;
351}
352
353/**
354 * @brief Parse a path-key-expr (leafref). First call parses "current()", all
355 * the ".." and the first node-identifier, other calls parse a single
356 * node-identifier each.
357 *
358 * path-key-expr = current-function-invocation *WSP "/" *WSP
359 * rel-path-keyexpr
360 * rel-path-keyexpr = 1*(".." *WSP "/" *WSP)
361 * *(node-identifier *WSP "/" *WSP)
362 * node-identifier
363 *
Michal Vaskobb211122015-08-19 14:03:11 +0200364 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200365 * @param[out] prefix Points to the prefix, NULL if there is not any.
366 * @param[out] pref_len Length of the prefix, 0 if there is not any.
367 * @param[out] name Points to the node name.
368 * @param[out] nam_len Length of the node name.
369 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
370 * must not be changed between consecutive calls.
371 * @return Number of characters successfully parsed,
372 * positive on success, negative on failure.
373 */
374static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200375parse_path_key_expr(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
376 int *parent_times)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200377{
378 int parsed = 0, ret, par_times = 0;
379
380 assert(id);
381 assert(parent_times);
382 if (prefix) {
383 *prefix = NULL;
384 }
385 if (pref_len) {
386 *pref_len = 0;
387 }
388 if (name) {
389 *name = NULL;
390 }
391 if (nam_len) {
392 *nam_len = 0;
393 }
394
395 if (!*parent_times) {
396 /* current-function-invocation *WSP "/" *WSP rel-path-keyexpr */
397 if (strncmp(id, "current()", 9)) {
398 return -parsed;
399 }
400
401 parsed += 9;
402 id += 9;
403
404 while (isspace(id[0])) {
405 ++parsed;
406 ++id;
407 }
408
409 if (id[0] != '/') {
410 return -parsed;
411 }
412
413 ++parsed;
414 ++id;
415
416 while (isspace(id[0])) {
417 ++parsed;
418 ++id;
419 }
420
421 /* rel-path-keyexpr */
422 if (strncmp(id, "..", 2)) {
423 return -parsed;
424 }
425 ++par_times;
426
427 parsed += 2;
428 id += 2;
429
430 while (isspace(id[0])) {
431 ++parsed;
432 ++id;
433 }
434 }
435
436 /* 1*(".." *WSP "/" *WSP) *(node-identifier *WSP "/" *WSP) node-identifier
437 *
438 * first parent reference with whitespaces already parsed
439 */
440 if (id[0] != '/') {
441 return -parsed;
442 }
443
444 ++parsed;
445 ++id;
446
447 while (isspace(id[0])) {
448 ++parsed;
449 ++id;
450 }
451
452 while (!strncmp(id, "..", 2) && !*parent_times) {
453 ++par_times;
454
455 parsed += 2;
456 id += 2;
457
458 while (isspace(id[0])) {
459 ++parsed;
460 ++id;
461 }
462
463 if (id[0] != '/') {
464 return -parsed;
465 }
466
467 ++parsed;
468 ++id;
469
470 while (isspace(id[0])) {
471 ++parsed;
472 ++id;
473 }
474 }
475
476 if (!*parent_times) {
477 *parent_times = par_times;
478 }
479
480 /* all parent references must be parsed at this point */
481 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
482 return -parsed+ret;
483 }
484
485 parsed += ret;
486 id += ret;
487
488 return parsed;
489}
490
491/**
492 * @brief Parse path-arg (leafref).
493 *
494 * path-arg = absolute-path / relative-path
495 * absolute-path = 1*("/" (node-identifier *path-predicate))
496 * relative-path = 1*(".." "/") descendant-path
497 *
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200498 * @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 +0200499 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200500 * @param[out] prefix Points to the prefix, NULL if there is not any.
501 * @param[out] pref_len Length of the prefix, 0 if there is not any.
502 * @param[out] name Points to the node name.
503 * @param[out] nam_len Length of the node name.
504 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
505 * must not be changed between consecutive calls. -1 if the
506 * path is relative.
507 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
508 *
509 * @return Number of characters successfully parsed,
510 * positive on success, negative on failure.
511 */
512static int
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200513parse_path_arg(struct lys_module *mod, const char *id, const char **prefix, int *pref_len,
514 const char **name, int *nam_len, int *parent_times, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200515{
516 int parsed = 0, ret, par_times = 0;
517
518 assert(id);
519 assert(parent_times);
520 if (prefix) {
521 *prefix = NULL;
522 }
523 if (pref_len) {
524 *pref_len = 0;
525 }
526 if (name) {
527 *name = NULL;
528 }
529 if (nam_len) {
530 *nam_len = 0;
531 }
532 if (has_predicate) {
533 *has_predicate = 0;
534 }
535
536 if (!*parent_times && !strncmp(id, "..", 2)) {
537 ++par_times;
538
539 parsed += 2;
540 id += 2;
541
542 while (!strncmp(id, "/..", 3)) {
543 ++par_times;
544
545 parsed += 3;
546 id += 3;
547 }
548 }
549
550 if (!*parent_times) {
551 if (par_times) {
552 *parent_times = par_times;
553 } else {
554 *parent_times = -1;
555 }
556 }
557
558 if (id[0] != '/') {
559 return -parsed;
560 }
561
562 /* skip '/' */
563 ++parsed;
564 ++id;
565
566 /* node-identifier ([prefix:]identifier) */
567 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
568 return -parsed-ret;
569 }
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200570 if (!(*prefix)) {
571 /* actually we always need prefix even it is not specified */
572 *prefix = lys_main_module(mod)->name;
573 *pref_len = strlen(*prefix);
574 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200575
576 parsed += ret;
577 id += ret;
578
579 /* there is no predicate */
580 if ((id[0] == '/') || !id[0]) {
581 return parsed;
582 } else if (id[0] != '[') {
583 return -parsed;
584 }
585
586 if (has_predicate) {
587 *has_predicate = 1;
588 }
589
590 return parsed;
591}
592
593/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200594 * @brief Parse instance-identifier in JSON data format. That means that prefixes
Michal Vaskob2f40be2016-09-08 16:03:48 +0200595 * (which are mandatory for every node-identifier) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200596 *
597 * instance-identifier = 1*("/" (node-identifier *predicate))
598 *
Michal Vaskobb211122015-08-19 14:03:11 +0200599 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200600 * @param[out] model Points to the model name.
601 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200602 * @param[out] name Points to the node name.
603 * @param[out] nam_len Length of the node name.
604 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
605 *
606 * @return Number of characters successfully parsed,
607 * positive on success, negative on failure.
608 */
609static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200610parse_instance_identifier(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
611 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200612{
613 int parsed = 0, ret;
614
Radek Krejci6dc53a22015-08-17 13:27:59 +0200615 if (has_predicate) {
616 *has_predicate = 0;
617 }
618
619 if (id[0] != '/') {
620 return -parsed;
621 }
622
623 ++parsed;
624 ++id;
625
Michal Vaskob2f40be2016-09-08 16:03:48 +0200626 if ((ret = parse_identifier(id)) < 1) {
627 return ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200628 }
629
Michal Vaskob2f40be2016-09-08 16:03:48 +0200630 *model = id;
631 *mod_len = ret;
632
Radek Krejci6dc53a22015-08-17 13:27:59 +0200633 parsed += ret;
634 id += ret;
635
Michal Vaskob2f40be2016-09-08 16:03:48 +0200636 if (id[0] != ':') {
637 return -parsed;
638 }
639
640 ++parsed;
641 ++id;
642
643 if ((ret = parse_identifier(id)) < 1) {
644 return ret;
645 }
646
647 *name = id;
648 *nam_len = ret;
649
650 parsed += ret;
651 id += ret;
652
Radek Krejci4967cb62016-09-14 16:40:28 +0200653 if (id[0] == '[' && has_predicate) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200654 *has_predicate = 1;
655 }
656
657 return parsed;
658}
659
660/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200661 * @brief Parse predicate (instance-identifier) in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200662 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200663 *
664 * predicate = "[" *WSP (predicate-expr / pos) *WSP "]"
665 * predicate-expr = (node-identifier / ".") *WSP "=" *WSP
666 * ((DQUOTE string DQUOTE) /
667 * (SQUOTE string SQUOTE))
668 * pos = non-negative-integer-value
669 *
Michal Vaskobb211122015-08-19 14:03:11 +0200670 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200671 * @param[out] model Points to the model name.
672 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200673 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
674 * @param[out] nam_len Length of the node name.
675 * @param[out] value Value the node-identifier must have (string from the grammar),
676 * NULL if there is not any.
677 * @param[out] val_len Length of the value, 0 if there is not any.
678 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
679 *
680 * @return Number of characters successfully parsed,
681 * positive on success, negative on failure.
682 */
683static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200684parse_predicate(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
685 const char **value, int *val_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200686{
687 const char *ptr;
688 int parsed = 0, ret;
689 char quote;
690
691 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200692 if (model) {
693 *model = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200694 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200695 if (mod_len) {
696 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200697 }
698 if (name) {
699 *name = NULL;
700 }
701 if (nam_len) {
702 *nam_len = 0;
703 }
704 if (value) {
705 *value = NULL;
706 }
707 if (val_len) {
708 *val_len = 0;
709 }
710 if (has_predicate) {
711 *has_predicate = 0;
712 }
713
714 if (id[0] != '[') {
715 return -parsed;
716 }
717
718 ++parsed;
719 ++id;
720
721 while (isspace(id[0])) {
722 ++parsed;
723 ++id;
724 }
725
726 /* pos */
727 if (isdigit(id[0])) {
728 if (name) {
729 *name = id;
730 }
731
732 if (id[0] == '0') {
Michal Vaskof2f28a12016-09-09 12:43:06 +0200733 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200734 }
735
736 while (isdigit(id[0])) {
737 ++parsed;
738 ++id;
739 }
740
741 if (nam_len) {
742 *nam_len = id-(*name);
743 }
744
Michal Vaskof2f28a12016-09-09 12:43:06 +0200745 /* "." or node-identifier */
Radek Krejci6dc53a22015-08-17 13:27:59 +0200746 } else {
Michal Vaskof2f28a12016-09-09 12:43:06 +0200747 if (id[0] == '.') {
748 if (name) {
749 *name = id;
750 }
751 if (nam_len) {
752 *nam_len = 1;
753 }
754
755 ++parsed;
756 ++id;
757
758 } else {
759 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
760 return -parsed+ret;
761 } else if (model && !*model) {
762 return -parsed;
763 }
764
765 parsed += ret;
766 id += ret;
767 }
768
769 while (isspace(id[0])) {
770 ++parsed;
771 ++id;
772 }
773
774 if (id[0] != '=') {
Michal Vasko1f2cc332015-08-19 11:18:32 +0200775 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200776 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200777
Radek Krejci6dc53a22015-08-17 13:27:59 +0200778 ++parsed;
779 ++id;
780
Michal Vaskof2f28a12016-09-09 12:43:06 +0200781 while (isspace(id[0])) {
782 ++parsed;
783 ++id;
784 }
785
786 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
787 if ((id[0] == '\"') || (id[0] == '\'')) {
788 quote = id[0];
789
790 ++parsed;
791 ++id;
792
793 if ((ptr = strchr(id, quote)) == NULL) {
794 return -parsed;
795 }
796 ret = ptr-id;
797
798 if (value) {
799 *value = id;
800 }
801 if (val_len) {
802 *val_len = ret;
803 }
804
805 parsed += ret+1;
806 id += ret+1;
807 } else {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200808 return -parsed;
809 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200810 }
811
812 while (isspace(id[0])) {
813 ++parsed;
814 ++id;
815 }
816
817 if (id[0] != ']') {
818 return -parsed;
819 }
820
821 ++parsed;
822 ++id;
823
824 if ((id[0] == '[') && has_predicate) {
825 *has_predicate = 1;
826 }
827
828 return parsed;
829}
830
831/**
832 * @brief Parse schema-nodeid.
833 *
834 * schema-nodeid = absolute-schema-nodeid /
835 * descendant-schema-nodeid
836 * absolute-schema-nodeid = 1*("/" node-identifier)
Michal Vasko48935352016-03-29 11:52:36 +0200837 * descendant-schema-nodeid = ["." "/"]
Radek Krejci6dc53a22015-08-17 13:27:59 +0200838 * node-identifier
839 * absolute-schema-nodeid
840 *
Michal Vaskobb211122015-08-19 14:03:11 +0200841 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200842 * @param[out] mod_name Points to the module name, NULL if there is not any.
843 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Michal Vasko48935352016-03-29 11:52:36 +0200844 * @param[out] name Points to the node name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200845 * @param[out] nam_len Length of the node name.
846 * @param[out] is_relative Flag to mark whether the nodeid is absolute or descendant. Must be -1
847 * on the first call, must not be changed between consecutive calls.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100848 * @param[out] has_predicate Flag to mark whether there is a predicate specified. It cannot be
849 * based on the grammar, in those cases use NULL.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200850 *
851 * @return Number of characters successfully parsed,
852 * positive on success, negative on failure.
853 */
Michal Vasko22448d32016-03-16 13:17:29 +0100854int
Michal Vasko723e50c2015-10-20 15:20:29 +0200855parse_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 +0100856 int *is_relative, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200857{
858 int parsed = 0, ret;
859
860 assert(id);
861 assert(is_relative);
Michal Vasko723e50c2015-10-20 15:20:29 +0200862 if (mod_name) {
863 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200864 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200865 if (mod_name_len) {
866 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200867 }
868 if (name) {
869 *name = NULL;
870 }
871 if (nam_len) {
872 *nam_len = 0;
873 }
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100874 if (has_predicate) {
875 *has_predicate = 0;
876 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200877
878 if (id[0] != '/') {
879 if (*is_relative != -1) {
880 return -parsed;
881 } else {
882 *is_relative = 1;
883 }
Michal Vasko48935352016-03-29 11:52:36 +0200884 if (!strncmp(id, "./", 2)) {
885 parsed += 2;
886 id += 2;
887 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200888 } else {
889 if (*is_relative == -1) {
890 *is_relative = 0;
891 }
892 ++parsed;
893 ++id;
894 }
895
Michal Vasko723e50c2015-10-20 15:20:29 +0200896 if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200897 return -parsed+ret;
898 }
899
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100900 parsed += ret;
901 id += ret;
902
903 if ((id[0] == '[') && has_predicate) {
904 *has_predicate = 1;
905 }
906
907 return parsed;
908}
909
910/**
911 * @brief Parse schema predicate (special format internally used).
912 *
913 * predicate = "[" *WSP predicate-expr *WSP "]"
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200914 * predicate-expr = "." / identifier / key-with-value
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100915 * key-with-value = identifier *WSP "=" *WSP
916 * ((DQUOTE string DQUOTE) /
917 * (SQUOTE string SQUOTE))
918 *
919 * @param[in] id Identifier to use.
920 * @param[out] name Points to the list key name.
921 * @param[out] nam_len Length of \p name.
Michal Vasko22448d32016-03-16 13:17:29 +0100922 * @param[out] value Points to the key value. If specified, key-with-value is expected.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100923 * @param[out] val_len Length of \p value.
924 * @param[out] has_predicate Flag to mark whether there is another predicate specified.
925 */
Michal Vasko22448d32016-03-16 13:17:29 +0100926int
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200927parse_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 +0100928 int *has_predicate)
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100929{
930 const char *ptr;
931 int parsed = 0, ret;
932 char quote;
933
934 assert(id);
935 if (name) {
936 *name = NULL;
937 }
938 if (nam_len) {
939 *nam_len = 0;
940 }
941 if (value) {
942 *value = NULL;
943 }
944 if (val_len) {
945 *val_len = 0;
946 }
947 if (has_predicate) {
948 *has_predicate = 0;
949 }
950
951 if (id[0] != '[') {
952 return -parsed;
953 }
954
955 ++parsed;
956 ++id;
957
958 while (isspace(id[0])) {
959 ++parsed;
960 ++id;
961 }
962
Michal Vasko22448d32016-03-16 13:17:29 +0100963 /* identifier */
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200964 if (id[0] == '.') {
965 ret = 1;
966 } else if ((ret = parse_identifier(id)) < 1) {
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100967 return -parsed + ret;
968 }
969 if (name) {
970 *name = id;
971 }
972 if (nam_len) {
973 *nam_len = ret;
974 }
975
976 parsed += ret;
977 id += ret;
978
979 while (isspace(id[0])) {
980 ++parsed;
981 ++id;
982 }
983
984 /* there is value as well */
985 if (id[0] == '=') {
986 ++parsed;
987 ++id;
988
989 while (isspace(id[0])) {
990 ++parsed;
991 ++id;
992 }
993
994 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
995 if ((id[0] == '\"') || (id[0] == '\'')) {
996 quote = id[0];
997
998 ++parsed;
999 ++id;
1000
1001 if ((ptr = strchr(id, quote)) == NULL) {
1002 return -parsed;
1003 }
1004 ret = ptr - id;
1005
1006 if (value) {
1007 *value = id;
1008 }
1009 if (val_len) {
1010 *val_len = ret;
1011 }
1012
1013 parsed += ret + 1;
1014 id += ret + 1;
1015 } else {
1016 return -parsed;
1017 }
1018
1019 while (isspace(id[0])) {
1020 ++parsed;
1021 ++id;
1022 }
Michal Vasko22448d32016-03-16 13:17:29 +01001023 } else if (value) {
1024 /* if value was expected, it's mandatory */
1025 return -parsed;
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001026 }
1027
1028 if (id[0] != ']') {
1029 return -parsed;
1030 }
1031
1032 ++parsed;
1033 ++id;
1034
1035 if ((id[0] == '[') && has_predicate) {
1036 *has_predicate = 1;
1037 }
1038
1039 return parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +02001040}
1041
1042/**
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001043 * @brief Resolve (find) a feature definition. Logs directly.
1044 *
1045 * @param[in] feat_name Feature name to resolve.
1046 * @param[in] len Length of \p feat_name.
1047 * @param[in] node Node with the if-feature expression.
Radek Krejci9ff0a922016-07-14 13:08:05 +02001048 * @param[out] feature Pointer to be set to point to the feature definition, if feature not found
1049 * (return code 1), the pointer is untouched.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001050 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02001051 * @return 0 on success, 1 on forward reference, -1 on error.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001052 */
1053static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001054resolve_feature(const char *feat_name, uint16_t len, const struct lys_node *node, struct lys_feature **feature)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001055{
1056 char *str;
1057 const char *mod_name, *name;
1058 int mod_name_len, nam_len, i, j;
1059 const struct lys_module *module;
1060
Radek Krejci9ff0a922016-07-14 13:08:05 +02001061 assert(feature);
1062
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001063 /* check prefix */
1064 if ((i = parse_node_identifier(feat_name, &mod_name, &mod_name_len, &name, &nam_len)) < 1) {
1065 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, feat_name[-i], &feat_name[-i]);
1066 return -1;
1067 }
1068
1069 module = lys_get_import_module(lys_node_module(node), NULL, 0, mod_name, mod_name_len);
1070 if (!module) {
1071 /* identity refers unknown data model */
1072 LOGVAL(LYE_INMOD_LEN, LY_VLOG_NONE, NULL, mod_name_len, mod_name);
1073 return -1;
1074 }
1075
Radek Krejci9ff0a922016-07-14 13:08:05 +02001076 if (module != node->module && module == lys_node_module(node)) {
1077 /* first, try to search directly in submodule where the feature was mentioned */
1078 for (j = 0; j < node->module->features_size; j++) {
1079 if (!strncmp(name, node->module->features[j].name, nam_len) && !node->module->features[j].name[nam_len]) {
1080 /* check status */
1081 if (lyp_check_status(node->flags, lys_node_module(node), node->name, node->module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001082 node->module->features[j].module, node->module->features[j].name, NULL)) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001083 return -1;
1084 }
1085 *feature = &node->module->features[j];
1086 return 0;
1087 }
1088 }
1089 }
1090
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001091 /* search in the identified module ... */
1092 for (j = 0; j < module->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001093 if (!strncmp(name, module->features[j].name, nam_len) && !module->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001094 /* check status */
1095 if (lyp_check_status(node->flags, lys_node_module(node), node->name, module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001096 module->features[j].module, module->features[j].name, NULL)) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001097 return -1;
1098 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001099 *feature = &module->features[j];
1100 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001101 }
1102 }
1103 /* ... and all its submodules */
1104 for (i = 0; i < module->inc_size; i++) {
1105 if (!module->inc[i].submodule) {
1106 /* not yet resolved */
1107 continue;
1108 }
1109 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001110 if (!strncmp(name, module->inc[i].submodule->features[j].name, nam_len)
1111 && !module->inc[i].submodule->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001112 /* check status */
1113 if (lyp_check_status(node->flags, lys_node_module(node), node->name,
1114 module->inc[i].submodule->features[j].flags,
1115 module->inc[i].submodule->features[j].module,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001116 module->inc[i].submodule->features[j].name, NULL)) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001117 return -1;
1118 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001119 *feature = &module->inc[i].submodule->features[j];
1120 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001121 }
1122 }
1123 }
1124
1125 /* not found */
1126 str = strndup(feat_name, len);
1127 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, "feature", str);
1128 free(str);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001129 return 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001130}
1131
Radek Krejci9ff0a922016-07-14 13:08:05 +02001132/*
1133 * @return
Radek Krejci69b8d922016-07-27 13:13:41 +02001134 * - 1 if enabled
1135 * - 0 if disabled
Radek Krejci9ff0a922016-07-14 13:08:05 +02001136 * - -1 if not usable by its if-feature expression
1137 */
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001138static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001139resolve_feature_value(const struct lys_feature *feat)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001140{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001141 int i;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001142
Radek Krejci9ff0a922016-07-14 13:08:05 +02001143 for (i = 0; i < feat->iffeature_size; i++) {
Radek Krejci69b8d922016-07-27 13:13:41 +02001144 if (!resolve_iffeature(&feat->iffeature[i])) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001145 return -1;
1146 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001147 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001148
Radek Krejci69b8d922016-07-27 13:13:41 +02001149 return feat->flags & LYS_FENABLED ? 1 : 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001150}
1151
1152static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001153resolve_iffeature_recursive(struct lys_iffeature *expr, int *index_e, int *index_f)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001154{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001155 uint8_t op;
1156 int rc, a, b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001157
Radek Krejci9ff0a922016-07-14 13:08:05 +02001158 op = iff_getop(expr->expr, *index_e);
1159 (*index_e)++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001160
Radek Krejci9ff0a922016-07-14 13:08:05 +02001161 switch (op) {
1162 case LYS_IFF_F:
1163 /* resolve feature */
1164 return resolve_feature_value(expr->features[(*index_f)++]);
1165 case LYS_IFF_NOT:
1166 rc = resolve_iffeature_recursive(expr, index_e, index_f);
1167 if (rc == -1) {
1168 /* one of the referenced feature is hidden by its if-feature,
1169 * so this if-feature expression is always false */
1170 return -1;
1171 } else {
1172 /* invert result */
1173 return rc ? 0 : 1;
1174 }
1175 case LYS_IFF_AND:
1176 case LYS_IFF_OR:
1177 a = resolve_iffeature_recursive(expr, index_e, index_f);
1178 b = resolve_iffeature_recursive(expr, index_e, index_f);
1179 if (a == -1 || b == -1) {
1180 /* one of the referenced feature is hidden by its if-feature,
1181 * so this if-feature expression is always false */
1182 return -1;
1183 } else if (op == LYS_IFF_AND) {
1184 return a && b;
1185 } else { /* LYS_IFF_OR */
1186 return a || b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001187 }
1188 }
1189
Radek Krejci9ff0a922016-07-14 13:08:05 +02001190 return -1;
1191}
1192
1193int
1194resolve_iffeature(struct lys_iffeature *expr)
1195{
1196 int rc = -1;
1197 int index_e = 0, index_f = 0;
1198
1199 if (expr->expr) {
1200 rc = resolve_iffeature_recursive(expr, &index_e, &index_f);
1201 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001202 return (rc == 1) ? 1 : 0;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001203}
1204
1205struct iff_stack {
1206 int size;
1207 int index; /* first empty item */
1208 uint8_t *stack;
1209};
1210
1211static int
1212iff_stack_push(struct iff_stack *stack, uint8_t value)
1213{
1214 if (stack->index == stack->size) {
1215 stack->size += 4;
1216 stack->stack = ly_realloc(stack->stack, stack->size * sizeof *stack->stack);
1217 if (!stack->stack) {
1218 LOGMEM;
1219 stack->size = 0;
1220 return EXIT_FAILURE;
1221 }
1222 }
1223
1224 stack->stack[stack->index++] = value;
1225 return EXIT_SUCCESS;
1226}
1227
1228static uint8_t
1229iff_stack_pop(struct iff_stack *stack)
1230{
1231 stack->index--;
1232 return stack->stack[stack->index];
1233}
1234
1235static void
1236iff_stack_clean(struct iff_stack *stack)
1237{
1238 stack->size = 0;
1239 free(stack->stack);
1240}
1241
1242static void
1243iff_setop(uint8_t *list, uint8_t op, int pos)
1244{
1245 uint8_t *item;
1246 uint8_t mask = 3;
1247
1248 assert(pos >= 0);
1249 assert(op <= 3); /* max 2 bits */
1250
1251 item = &list[pos / 4];
1252 mask = mask << 2 * (pos % 4);
1253 *item = (*item) & ~mask;
1254 *item = (*item) | (op << 2 * (pos % 4));
1255}
1256
1257uint8_t
1258iff_getop(uint8_t *list, int pos)
1259{
1260 uint8_t *item;
1261 uint8_t mask = 3, result;
1262
1263 assert(pos >= 0);
1264
1265 item = &list[pos / 4];
1266 result = (*item) & (mask << 2 * (pos % 4));
1267 return result >> 2 * (pos % 4);
1268}
1269
1270#define LYS_IFF_LP 0x04 /* ( */
1271#define LYS_IFF_RP 0x08 /* ) */
1272
Radek Krejcicbb473e2016-09-16 14:48:32 +02001273/* internal structure for passing data for UNRES_IFFEAT */
1274struct unres_iffeat_data {
1275 struct lys_node *node;
1276 const char *fname;
Radek Krejci9de2c042016-10-19 16:53:06 +02001277 int infeature;
Radek Krejcicbb473e2016-09-16 14:48:32 +02001278};
1279
Radek Krejci9ff0a922016-07-14 13:08:05 +02001280void
1281resolve_iffeature_getsizes(struct lys_iffeature *iffeat, unsigned int *expr_size, unsigned int *feat_size)
1282{
1283 unsigned int e = 0, f = 0, r = 0;
1284 uint8_t op;
1285
1286 assert(iffeat);
1287
1288 if (!iffeat->expr) {
1289 goto result;
1290 }
1291
1292 do {
1293 op = iff_getop(iffeat->expr, e++);
1294 switch (op) {
1295 case LYS_IFF_NOT:
1296 if (!r) {
1297 r += 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001298 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001299 break;
1300 case LYS_IFF_AND:
1301 case LYS_IFF_OR:
1302 if (!r) {
1303 r += 2;
1304 } else {
1305 r += 1;
1306 }
1307 break;
1308 case LYS_IFF_F:
1309 f++;
1310 if (r) {
1311 r--;
1312 }
1313 break;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001314 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001315 } while(r);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001316
Radek Krejci9ff0a922016-07-14 13:08:05 +02001317result:
1318 if (expr_size) {
1319 *expr_size = e;
1320 }
1321 if (feat_size) {
1322 *feat_size = f;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001323 }
1324}
1325
1326int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001327resolve_iffeature_compile(struct lys_iffeature *iffeat_expr, const char *value, struct lys_node *node,
Radek Krejci9de2c042016-10-19 16:53:06 +02001328 int infeature, struct unres_schema *unres)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001329{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001330 const char *c = value;
1331 int r, rc = EXIT_FAILURE;
Radek Krejci69b8d922016-07-27 13:13:41 +02001332 int i, j, last_not, checkversion = 0;
1333 unsigned int f_size = 0, expr_size = 0, f_exp = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001334 uint8_t op;
1335 struct iff_stack stack = {0, 0, NULL};
Radek Krejcicbb473e2016-09-16 14:48:32 +02001336 struct unres_iffeat_data *iff_data;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001337
Radek Krejci9ff0a922016-07-14 13:08:05 +02001338 assert(c);
1339
1340 if (isspace(c[0])) {
1341 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, c[0], c);
1342 return EXIT_FAILURE;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001343 }
1344
Radek Krejci9ff0a922016-07-14 13:08:05 +02001345 /* pre-parse the expression to get sizes for arrays, also do some syntax checks of the expression */
1346 for (i = j = last_not = 0; c[i]; i++) {
1347 if (c[i] == '(') {
Radek Krejci69b8d922016-07-27 13:13:41 +02001348 checkversion = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001349 j++;
1350 continue;
1351 } else if (c[i] == ')') {
1352 j--;
1353 continue;
1354 } else if (isspace(c[i])) {
1355 continue;
1356 }
1357
1358 if (!strncmp(&c[i], "not", r = 3) || !strncmp(&c[i], "and", r = 3) || !strncmp(&c[i], "or", r = 2)) {
1359 if (c[i + r] == '\0') {
Radek Krejcia98da3f2016-07-27 14:05:22 +02001360 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
Radek Krejci9ff0a922016-07-14 13:08:05 +02001361 return EXIT_FAILURE;
1362 } else if (!isspace(c[i + r])) {
1363 /* feature name starting with the not/and/or */
1364 last_not = 0;
1365 f_size++;
1366 } else if (c[i] == 'n') { /* not operation */
1367 if (last_not) {
1368 /* double not */
1369 expr_size = expr_size - 2;
1370 last_not = 0;
1371 } else {
1372 last_not = 1;
1373 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001374 } else { /* and, or */
1375 f_exp++;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001376 /* not a not operation */
1377 last_not = 0;
1378 }
1379 i += r;
1380 } else {
1381 f_size++;
1382 last_not = 0;
1383 }
1384 expr_size++;
1385
1386 while (!isspace(c[i])) {
1387 if (!c[i] || c[i] == ')') {
1388 i--;
1389 break;
1390 }
1391 i++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001392 }
1393 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001394 if (j || f_exp != f_size) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001395 /* not matching count of ( and ) */
1396 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1397 return EXIT_FAILURE;
1398 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001399
Radek Krejci69b8d922016-07-27 13:13:41 +02001400 if (checkversion || expr_size > 1) {
1401 /* check that we have 1.1 module */
1402 if (node->module->version != 2) {
1403 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1404 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "YANG 1.1 if-feature expression found in 1.0 module.");
1405 return EXIT_FAILURE;
1406 }
1407 }
1408
Radek Krejci9ff0a922016-07-14 13:08:05 +02001409 /* allocate the memory */
1410 iffeat_expr->expr = calloc((j = (expr_size / 4) + ((expr_size % 4) ? 1 : 0)), sizeof *iffeat_expr->expr);
Radek Krejcicbb473e2016-09-16 14:48:32 +02001411 iffeat_expr->features = calloc(f_size, sizeof *iffeat_expr->features);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001412 stack.size = expr_size;
1413 stack.stack = malloc(expr_size * sizeof *stack.stack);
1414 if (!stack.stack || !iffeat_expr->expr || !iffeat_expr->features) {
1415 LOGMEM;
1416 goto error;
1417 }
1418 f_size--; expr_size--; /* used as indexes from now */
1419
1420 for (i--; i >= 0; i--) {
1421 if (c[i] == ')') {
1422 /* push it on stack */
1423 iff_stack_push(&stack, LYS_IFF_RP);
1424 continue;
1425 } else if (c[i] == '(') {
1426 /* pop from the stack into result all operators until ) */
1427 while((op = iff_stack_pop(&stack)) != LYS_IFF_RP) {
1428 iff_setop(iffeat_expr->expr, op, expr_size--);
1429 }
1430 continue;
1431 } else if (isspace(c[i])) {
1432 continue;
1433 }
1434
1435 /* end operator or operand -> find beginning and get what is it */
1436 j = i + 1;
1437 while (i >= 0 && !isspace(c[i]) && c[i] != '(') {
1438 i--;
1439 }
1440 i++; /* get back by one step */
1441
1442 if (!strncmp(&c[i], "not ", 4)) {
1443 if (stack.index && stack.stack[stack.index - 1] == LYS_IFF_NOT) {
1444 /* double not */
1445 iff_stack_pop(&stack);
1446 } else {
1447 /* not has the highest priority, so do not pop from the stack
1448 * as in case of AND and OR */
1449 iff_stack_push(&stack, LYS_IFF_NOT);
1450 }
1451 } else if (!strncmp(&c[i], "and ", 4)) {
1452 /* as for OR - pop from the stack all operators with the same or higher
1453 * priority and store them to the result, then push the AND to the stack */
1454 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_AND) {
1455 op = iff_stack_pop(&stack);
1456 iff_setop(iffeat_expr->expr, op, expr_size--);
1457 }
1458 iff_stack_push(&stack, LYS_IFF_AND);
1459 } else if (!strncmp(&c[i], "or ", 3)) {
1460 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_OR) {
1461 op = iff_stack_pop(&stack);
1462 iff_setop(iffeat_expr->expr, op, expr_size--);
1463 }
1464 iff_stack_push(&stack, LYS_IFF_OR);
1465 } else {
1466 /* feature name, length is j - i */
1467
1468 /* add it to the result */
1469 iff_setop(iffeat_expr->expr, LYS_IFF_F, expr_size--);
1470
1471 /* now get the link to the feature definition. Since it can be
Radek Krejcicbb473e2016-09-16 14:48:32 +02001472 * forward referenced, we have to keep the feature name in auxiliary
1473 * structure passed into unres */
1474 iff_data = malloc(sizeof *iff_data);
1475 iff_data->node = node;
1476 iff_data->fname = lydict_insert(node->module->ctx, &c[i], j - i);
Radek Krejci9de2c042016-10-19 16:53:06 +02001477 iff_data->infeature = infeature;
Radek Krejcicbb473e2016-09-16 14:48:32 +02001478 r = unres_schema_add_node(node->module, unres, &iffeat_expr->features[f_size], UNRES_IFFEAT,
1479 (struct lys_node *)iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001480 f_size--;
1481
1482 if (r == -1) {
Pavol Vican4d084512016-09-29 16:38:12 +02001483 free(iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001484 goto error;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001485 }
1486 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001487 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001488 while (stack.index) {
1489 op = iff_stack_pop(&stack);
1490 iff_setop(iffeat_expr->expr, op, expr_size--);
1491 }
1492
1493 if (++expr_size || ++f_size) {
1494 /* not all expected operators and operands found */
1495 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1496 rc = EXIT_FAILURE;
1497 } else {
1498 rc = EXIT_SUCCESS;
1499 }
1500
1501error:
1502 /* cleanup */
1503 iff_stack_clean(&stack);
1504
1505 return rc;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001506}
1507
1508/**
Michal Vasko3edeaf72016-02-11 13:17:43 +01001509 * @brief Resolve (find) a data node based on a schema-nodeid.
1510 *
1511 * Used for resolving unique statements - so id is expected to be relative and local (without reference to a different
1512 * module).
1513 *
1514 */
1515struct lyd_node *
1516resolve_data_descendant_schema_nodeid(const char *nodeid, struct lyd_node *start)
1517{
1518 char *str, *token, *p;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001519 struct lyd_node *result = NULL, *iter;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001520 const struct lys_node *schema = NULL;
Radek Krejcicc217a62016-04-08 16:58:11 +02001521 int shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001522
1523 assert(nodeid && start);
1524
1525 if (nodeid[0] == '/') {
1526 return NULL;
1527 }
1528
1529 str = p = strdup(nodeid);
1530 if (!str) {
1531 LOGMEM;
1532 return NULL;
1533 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001534
Michal Vasko3edeaf72016-02-11 13:17:43 +01001535 while (p) {
1536 token = p;
1537 p = strchr(p, '/');
1538 if (p) {
1539 *p = '\0';
1540 p++;
1541 }
1542
Radek Krejci5da4eb62016-04-08 14:45:51 +02001543 if (p) {
1544 /* inner node */
Radek Krejcicc217a62016-04-08 16:58:11 +02001545 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema,
Radek Krejcif3c71de2016-04-11 12:45:46 +02001546 LYS_CONTAINER | LYS_CHOICE | LYS_CASE | LYS_LEAF, 0, 0, &schema)
Radek Krejci5da4eb62016-04-08 14:45:51 +02001547 || !schema) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001548 result = NULL;
1549 break;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001550 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001551
Radek Krejci5da4eb62016-04-08 14:45:51 +02001552 if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
1553 continue;
Michal Vaskodcf98e62016-05-05 17:53:53 +02001554 } else if (lys_parent(schema)->nodetype == LYS_CHOICE) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001555 /* shorthand case */
1556 if (!shorthand) {
1557 shorthand = 1;
Michal Vaskodcf98e62016-05-05 17:53:53 +02001558 schema = lys_parent(schema);
Radek Krejcicc217a62016-04-08 16:58:11 +02001559 continue;
1560 } else {
1561 shorthand = 0;
1562 if (schema->nodetype == LYS_LEAF) {
1563 /* should not be here, since we have leaf, which is not a shorthand nor final node */
1564 result = NULL;
1565 break;
1566 }
1567 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001568 }
1569 } else {
1570 /* final node */
Radek Krejcif3c71de2016-04-11 12:45:46 +02001571 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema, LYS_LEAF,
1572 shorthand ? 0 : 1, 0, &schema)
Radek Krejcicc217a62016-04-08 16:58:11 +02001573 || !schema) {
1574 result = NULL;
1575 break;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001576 }
1577 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001578 LY_TREE_FOR(result ? result->child : start, iter) {
1579 if (iter->schema == schema) {
1580 /* move in data tree according to returned schema */
1581 result = iter;
1582 break;
1583 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001584 }
Radek Krejcicc217a62016-04-08 16:58:11 +02001585 if (!iter) {
1586 /* instance not found */
1587 result = NULL;
1588 break;
1589 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001590 }
1591 free(str);
1592
1593 return result;
1594}
1595
Radek Krejcibdf92362016-04-08 14:43:34 +02001596/*
1597 * 0 - ok (done)
1598 * 1 - continue
1599 * 2 - break
1600 * -1 - error
1601 */
1602static int
Radek Krejcicc217a62016-04-08 16:58:11 +02001603schema_nodeid_siblingcheck(const struct lys_node *sibling, int8_t *shorthand, const char *id,
Radek Krejcibdf92362016-04-08 14:43:34 +02001604 const struct lys_module *module, const char *mod_name, int mod_name_len,
Radek Krejci0fa54e92016-09-14 14:01:05 +02001605 int implemented_mod, const struct lys_node **start)
Radek Krejcibdf92362016-04-08 14:43:34 +02001606{
1607 const struct lys_module *prefix_mod;
1608
1609 /* module check */
1610 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Radek Krejcidf46e222016-11-08 11:57:37 +01001611 if (prefix_mod && implemented_mod) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001612 prefix_mod = lys_get_implemented_module(prefix_mod);
1613 }
Radek Krejcibdf92362016-04-08 14:43:34 +02001614 if (!prefix_mod) {
1615 return -1;
1616 }
1617 if (prefix_mod != lys_node_module(sibling)) {
1618 return 1;
1619 }
1620
1621 /* check for shorthand cases - then 'start' does not change */
Michal Vaskodcf98e62016-05-05 17:53:53 +02001622 if (lys_parent(sibling) && (lys_parent(sibling)->nodetype == LYS_CHOICE) && (sibling->nodetype != LYS_CASE)) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001623 if (*shorthand != -1) {
1624 *shorthand = *shorthand ? 0 : 1;
1625 }
Radek Krejcibdf92362016-04-08 14:43:34 +02001626 }
1627
1628 /* the result node? */
1629 if (!id[0]) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001630 if (*shorthand == 1) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001631 return 1;
1632 }
1633 return 0;
1634 }
1635
Radek Krejci3a130162016-11-07 16:21:20 +01001636 if (!(*shorthand)) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001637 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02001638 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001639 return -1;
1640 }
1641 *start = sibling->child;
1642 }
1643
1644 return 2;
1645}
1646
Radek Krejcidf46e222016-11-08 11:57:37 +01001647/* start - relative, module - absolute, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1
1648 * implement: 0 - do not change the implemented status of the affected modules, 1 - change implemented status of the affected modules
1649 */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001650int
1651resolve_augment_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_module *module,
Radek Krejcidf46e222016-11-08 11:57:37 +01001652 int implement, const struct lys_node **ret)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001653{
Radek Krejcidf46e222016-11-08 11:57:37 +01001654 const char *name, *mod_name, *mod_name_prev, *id;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001655 const struct lys_node *sibling;
1656 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001657 int8_t shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001658 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcidf46e222016-11-08 11:57:37 +01001659 const struct lys_module *start_mod, *aux_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001660
1661 assert(nodeid && (start || module) && !(start && module) && ret);
1662
1663 id = nodeid;
1664
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001665 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 +01001666 return ((id - nodeid) - r) + 1;
1667 }
1668 id += r;
1669
1670 if ((is_relative && !start) || (!is_relative && !module)) {
1671 return -1;
1672 }
1673
1674 /* descendant-schema-nodeid */
1675 if (is_relative) {
Michal Vasko4c06fd82016-02-17 13:43:38 +01001676 module = start_mod = start->module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001677
1678 /* absolute-schema-nodeid */
1679 } else {
1680 start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Radek Krejcidf46e222016-11-08 11:57:37 +01001681 if (start_mod != lys_main_module(module) && start_mod && !start_mod->implemented) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001682 /* if the submodule augments the mainmodule (or in general a module augments
1683 * itself, we don't want to search for the implemented module but augments
1684 * the module anyway. But when augmenting another module, we need the implemented
1685 * revision of the module if any */
Radek Krejcidf46e222016-11-08 11:57:37 +01001686 aux_mod = lys_get_implemented_module(start_mod);
1687 if (!aux_mod->implemented && implement) {
1688 /* make the found module implemented */
1689 if (lys_set_implemented(aux_mod)) {
1690 return -1;
1691 }
1692 }
1693 start_mod = aux_mod;
1694 implement++;
Radek Krejci0fa54e92016-09-14 14:01:05 +02001695 }
Michal Vaskoe2905632016-02-11 15:42:24 +01001696 if (!start_mod) {
1697 return -1;
1698 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001699 start = start_mod->data;
1700 }
1701
1702 while (1) {
1703 sibling = NULL;
Radek Krejcidf46e222016-11-08 11:57:37 +01001704 mod_name_prev = mod_name;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001705 while ((sibling = lys_getnext(sibling, lys_parent(start), start_mod,
1706 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
1707 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001708 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001709 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len,
Radek Krejcidf46e222016-11-08 11:57:37 +01001710 implement, &start);
Radek Krejcibdf92362016-04-08 14:43:34 +02001711 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001712 *ret = sibling;
1713 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001714 } else if (r == 1) {
1715 continue;
1716 } else if (r == 2) {
1717 break;
1718 } else {
1719 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001720 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001721 }
1722 }
1723
1724 /* no match */
1725 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001726 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001727 return EXIT_SUCCESS;
1728 }
1729
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001730 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 +01001731 return ((id - nodeid) - r) + 1;
1732 }
1733 id += r;
Radek Krejcidf46e222016-11-08 11:57:37 +01001734
1735 if ((mod_name && mod_name_prev && strncmp(mod_name, mod_name_prev, mod_name_len + 1)) ||
1736 (mod_name != mod_name_prev && (!mod_name || !mod_name_prev))) {
1737 /* we are getting into another module (augment) */
1738 if (implement) {
1739 /* we have to check that also target modules are implemented, if not, we have to change it */
1740 aux_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
1741 if (!aux_mod) {
1742 return -1;
1743 }
1744 if (!aux_mod->implemented) {
1745 aux_mod = lys_get_implemented_module(aux_mod);
1746 if (!aux_mod->implemented) {
1747 /* make the found module implemented */
1748 if (lys_set_implemented(aux_mod)) {
1749 return -1;
1750 }
1751 }
1752 }
1753 } else {
1754 /* we are not implementing the module itself, so the augments outside the module are ignored */
1755 *ret = NULL;
1756 return EXIT_SUCCESS;
1757 }
1758 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001759 }
1760
1761 /* cannot get here */
1762 LOGINT;
1763 return -1;
1764}
1765
Radek Krejcif3c71de2016-04-11 12:45:46 +02001766/* unique, refine,
1767 * >0 - unexpected char on position (ret - 1),
1768 * 0 - ok (but ret can still be NULL),
1769 * -1 - error,
1770 * -2 - violated no_innerlist */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001771int
1772resolve_descendant_schema_nodeid(const char *nodeid, const struct lys_node *start, int ret_nodetype,
Radek Krejcif3c71de2016-04-11 12:45:46 +02001773 int check_shorthand, int no_innerlist, const struct lys_node **ret)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001774{
1775 const char *name, *mod_name, *id;
1776 const struct lys_node *sibling;
1777 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001778 int8_t shorthand = check_shorthand ? 0 : -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001779 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcibdf92362016-04-08 14:43:34 +02001780 const struct lys_module *module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001781
1782 assert(nodeid && start && ret);
1783 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1784
1785 id = nodeid;
1786 module = start->module;
1787
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001788 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 +01001789 return ((id - nodeid) - r) + 1;
1790 }
1791 id += r;
1792
1793 if (!is_relative) {
1794 return -1;
1795 }
1796
1797 while (1) {
1798 sibling = NULL;
1799 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
1800 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE))) {
1801 /* name match */
1802 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001803 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len, 0, &start);
Radek Krejcibdf92362016-04-08 14:43:34 +02001804 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001805 if (!(sibling->nodetype & ret_nodetype)) {
1806 /* wrong node type, too bad */
1807 continue;
1808 }
1809 *ret = sibling;
1810 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001811 } else if (r == 1) {
1812 continue;
1813 } else if (r == 2) {
1814 break;
1815 } else {
1816 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001817 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001818 }
1819 }
1820
1821 /* no match */
1822 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001823 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001824 return EXIT_SUCCESS;
Radek Krejcif3c71de2016-04-11 12:45:46 +02001825 } else if (no_innerlist && sibling->nodetype == LYS_LIST) {
1826 *ret = NULL;
1827 return -2;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001828 }
1829
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001830 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 +01001831 return ((id - nodeid) - r) + 1;
1832 }
1833 id += r;
1834 }
1835
1836 /* cannot get here */
1837 LOGINT;
1838 return -1;
1839}
1840
1841/* choice default */
1842int
1843resolve_choice_default_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node **ret)
1844{
1845 /* cannot actually be a path */
1846 if (strchr(nodeid, '/')) {
1847 return -1;
1848 }
1849
Radek Krejcif3c71de2016-04-11 12:45:46 +02001850 return resolve_descendant_schema_nodeid(nodeid, start, LYS_NO_RPC_NOTIF_NODE, 1, 0, ret);
Michal Vasko3edeaf72016-02-11 13:17:43 +01001851}
1852
1853/* uses, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1854static int
1855resolve_uses_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node_grp **ret)
1856{
1857 const struct lys_module *module;
1858 const char *mod_prefix, *name;
1859 int i, mod_prefix_len, nam_len;
1860
1861 /* parse the identifier, it must be parsed on one call */
1862 if (((i = parse_node_identifier(nodeid, &mod_prefix, &mod_prefix_len, &name, &nam_len)) < 1) || nodeid[i]) {
1863 return -i + 1;
1864 }
1865
1866 module = lys_get_import_module(start->module, mod_prefix, mod_prefix_len, NULL, 0);
1867 if (!module) {
1868 return -1;
1869 }
1870 if (module != start->module) {
1871 start = module->data;
1872 }
1873
1874 *ret = lys_find_grouping_up(name, (struct lys_node *)start);
1875
1876 return EXIT_SUCCESS;
1877}
1878
1879int
1880resolve_absolute_schema_nodeid(const char *nodeid, const struct lys_module *module, int ret_nodetype,
1881 const struct lys_node **ret)
1882{
1883 const char *name, *mod_name, *id;
1884 const struct lys_node *sibling, *start;
1885 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001886 int8_t shorthand = 0;
Radek Krejcibdf92362016-04-08 14:43:34 +02001887 const struct lys_module *abs_start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001888
1889 assert(nodeid && module && ret);
1890 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1891
1892 id = nodeid;
1893 start = module->data;
1894
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001895 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 +01001896 return ((id - nodeid) - r) + 1;
1897 }
1898 id += r;
1899
1900 if (is_relative) {
1901 return -1;
1902 }
1903
1904 abs_start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001905 if (!abs_start_mod) {
1906 return -1;
1907 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001908
1909 while (1) {
1910 sibling = NULL;
1911 while ((sibling = lys_getnext(sibling, lys_parent(start), abs_start_mod, LYS_GETNEXT_WITHCHOICE
1912 | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_WITHGROUPING))) {
1913 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001914 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001915 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len, 0, &start);
Radek Krejcibdf92362016-04-08 14:43:34 +02001916 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001917 if (!(sibling->nodetype & ret_nodetype)) {
1918 /* wrong node type, too bad */
1919 continue;
1920 }
1921 *ret = sibling;
1922 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001923 } else if (r == 1) {
1924 continue;
1925 } else if (r == 2) {
1926 break;
1927 } else {
1928 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001929 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001930 }
1931 }
1932
1933 /* no match */
1934 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001935 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001936 return EXIT_SUCCESS;
1937 }
1938
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001939 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 +01001940 return ((id - nodeid) - r) + 1;
1941 }
1942 id += r;
1943 }
1944
1945 /* cannot get here */
1946 LOGINT;
1947 return -1;
1948}
1949
Michal Vaskoe733d682016-03-14 09:08:27 +01001950static int
Michal Vasko3547c532016-03-14 09:40:50 +01001951resolve_json_schema_list_predicate(const char *predicate, const struct lys_node_list *list, int *parsed)
Michal Vaskoe733d682016-03-14 09:08:27 +01001952{
1953 const char *name;
1954 int nam_len, has_predicate, i;
1955
Michal Vasko7b54f7e2016-05-03 15:07:31 +02001956 if (((i = parse_schema_json_predicate(predicate, &name, &nam_len, NULL, NULL, &has_predicate)) < 1)
1957 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001958 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-i], &predicate[-i]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001959 return -1;
1960 }
1961
1962 predicate += i;
1963 *parsed += i;
1964
1965 for (i = 0; i < list->keys_size; ++i) {
1966 if (!strncmp(list->keys[i]->name, name, nam_len) && !list->keys[i]->name[nam_len]) {
1967 break;
1968 }
1969 }
1970
1971 if (i == list->keys_size) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001972 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskoe733d682016-03-14 09:08:27 +01001973 return -1;
1974 }
1975
1976 /* more predicates? */
1977 if (has_predicate) {
Michal Vasko3547c532016-03-14 09:40:50 +01001978 return resolve_json_schema_list_predicate(predicate, list, parsed);
Michal Vaskoe733d682016-03-14 09:08:27 +01001979 }
1980
1981 return 0;
1982}
1983
Michal Vasko8d26e5c2016-09-08 10:03:49 +02001984/* cannot return LYS_GROUPING, LYS_AUGMENT, LYS_USES, logs directly */
Michal Vaskoe733d682016-03-14 09:08:27 +01001985const struct lys_node *
Michal Vasko8d26e5c2016-09-08 10:03:49 +02001986resolve_json_nodeid(const char *nodeid, struct ly_ctx *ctx, const struct lys_node *start)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001987{
Michal Vasko10728b52016-04-07 14:26:29 +02001988 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001989 const char *name, *mod_name, *id;
Michal Vasko3547c532016-03-14 09:40:50 +01001990 const struct lys_node *sibling;
Radek Krejcibdf92362016-04-08 14:43:34 +02001991 int r, nam_len, mod_name_len, is_relative = -1, has_predicate, shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001992 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vaskoe733d682016-03-14 09:08:27 +01001993 const struct lys_module *prefix_mod, *module, *prev_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001994
Michal Vasko3547c532016-03-14 09:40:50 +01001995 assert(nodeid && (ctx || start));
1996 if (!ctx) {
1997 ctx = start->module->ctx;
1998 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001999
2000 id = nodeid;
2001
Michal Vaskoe733d682016-03-14 09:08:27 +01002002 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 +01002003 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002004 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002005 }
2006 id += r;
2007
2008 if (is_relative) {
Michal Vasko3547c532016-03-14 09:40:50 +01002009 assert(start);
2010 start = start->child;
2011 if (!start) {
2012 /* no descendants, fail for sure */
Michal Vasko10728b52016-04-07 14:26:29 +02002013 str = strndup(nodeid, (name + nam_len) - nodeid);
2014 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
2015 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002016 return NULL;
2017 }
2018 module = start->module;
2019 } else {
2020 if (!mod_name) {
Michal Vasko10728b52016-04-07 14:26:29 +02002021 str = strndup(nodeid, (name + nam_len) - nodeid);
2022 LOGVAL(LYE_PATH_MISSMOD, LY_VLOG_STR, nodeid);
2023 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002024 return NULL;
Michal Vasko971a3ca2016-04-01 13:09:29 +02002025 } else if (mod_name_len > LY_BUF_SIZE - 1) {
2026 LOGINT;
2027 return NULL;
Michal Vasko3547c532016-03-14 09:40:50 +01002028 }
2029
Michal Vasko971a3ca2016-04-01 13:09:29 +02002030 if (ly_buf_used && module_name[0]) {
2031 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2032 }
2033 ly_buf_used++;
2034
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002035 memmove(module_name, mod_name, mod_name_len);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002036 module_name[mod_name_len] = '\0';
2037 module = ly_ctx_get_module(ctx, module_name, NULL);
2038
2039 if (buf_backup) {
2040 /* return previous internal buffer content */
2041 strcpy(module_name, buf_backup);
2042 free(buf_backup);
2043 buf_backup = NULL;
2044 }
2045 ly_buf_used--;
2046
Michal Vasko3547c532016-03-14 09:40:50 +01002047 if (!module) {
Michal Vasko10728b52016-04-07 14:26:29 +02002048 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2049 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2050 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002051 return NULL;
2052 }
2053 start = module->data;
2054
2055 /* now it's as if there was no module name */
2056 mod_name = NULL;
2057 mod_name_len = 0;
Michal Vaskoe733d682016-03-14 09:08:27 +01002058 }
2059
Michal Vaskoe733d682016-03-14 09:08:27 +01002060 prev_mod = module;
2061
Michal Vasko3edeaf72016-02-11 13:17:43 +01002062 while (1) {
2063 sibling = NULL;
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002064 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
2065 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002066 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02002067 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002068 /* module check */
2069 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002070 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko8757e7c2016-03-15 10:41:30 +01002071 LOGINT;
2072 return NULL;
2073 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002074
2075 if (ly_buf_used && module_name[0]) {
2076 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2077 }
2078 ly_buf_used++;
2079
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002080 memmove(module_name, mod_name, mod_name_len);
Michal Vasko8757e7c2016-03-15 10:41:30 +01002081 module_name[mod_name_len] = '\0';
2082 /* will also find an augment module */
2083 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002084
2085 if (buf_backup) {
2086 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002087 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002088 free(buf_backup);
2089 buf_backup = NULL;
2090 }
2091 ly_buf_used--;
2092
Michal Vasko3edeaf72016-02-11 13:17:43 +01002093 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002094 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2095 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2096 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002097 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002098 }
2099 } else {
2100 prefix_mod = prev_mod;
2101 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01002102 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002103 continue;
2104 }
2105
Michal Vaskoe733d682016-03-14 09:08:27 +01002106 /* do we have some predicates on it? */
2107 if (has_predicate) {
2108 r = 0;
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002109 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
2110 if ((r = parse_schema_json_predicate(id, NULL, NULL, NULL, NULL, &has_predicate)) < 1) {
2111 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2112 return NULL;
2113 }
2114 } else if (sibling->nodetype == LYS_LIST) {
2115 if (resolve_json_schema_list_predicate(id, (const struct lys_node_list *)sibling, &r)) {
2116 return NULL;
2117 }
2118 } else {
Michal Vasko43c300e2016-03-22 12:54:27 +01002119 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vaskoe733d682016-03-14 09:08:27 +01002120 return NULL;
Michal Vaskoe733d682016-03-14 09:08:27 +01002121 }
2122 id += r;
2123 }
2124
Radek Krejcibdf92362016-04-08 14:43:34 +02002125 /* check for shorthand cases - then 'start' does not change */
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002126 if (lys_parent(sibling) && (lys_parent(sibling)->nodetype == LYS_CHOICE) && (sibling->nodetype != LYS_CASE)) {
Radek Krejcibdf92362016-04-08 14:43:34 +02002127 shorthand = ~shorthand;
2128 }
2129
Michal Vasko3edeaf72016-02-11 13:17:43 +01002130 /* the result node? */
2131 if (!id[0]) {
Radek Krejcibdf92362016-04-08 14:43:34 +02002132 if (shorthand) {
2133 /* wrong path for shorthand */
Michal Vasko025e0452016-05-17 16:14:20 +02002134 str = strndup(nodeid, (name + nam_len) - nodeid);
2135 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
Michal Vasko3c0f9f52016-05-17 16:38:10 +02002136 LOGVAL(LYE_SPEC, LY_VLOG_STR, str, "Schema shorthand case path must include the virtual case statement.");
Radek Krejci9a5fccc2016-05-18 15:44:58 +02002137 free(str);
Michal Vasko025e0452016-05-17 16:14:20 +02002138 return NULL;
Radek Krejcibdf92362016-04-08 14:43:34 +02002139 }
Michal Vaskoe733d682016-03-14 09:08:27 +01002140 return sibling;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002141 }
2142
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002143 if (!shorthand) {
Michal Vasko7dc71d02016-03-15 10:42:28 +01002144 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002145 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002146 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko7dc71d02016-03-15 10:42:28 +01002147 return NULL;
2148 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01002149 start = sibling->child;
2150 }
2151
2152 /* update prev mod */
2153 prev_mod = start->module;
2154 break;
2155 }
2156 }
2157
2158 /* no match */
2159 if (!sibling) {
Michal Vasko10728b52016-04-07 14:26:29 +02002160 str = strndup(nodeid, (name + nam_len) - nodeid);
2161 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
2162 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002163 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002164 }
2165
Michal Vaskoe733d682016-03-14 09:08:27 +01002166 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 +01002167 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002168 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002169 }
2170 id += r;
2171 }
2172
2173 /* cannot get here */
2174 LOGINT;
Michal Vaskoe733d682016-03-14 09:08:27 +01002175 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002176}
2177
Michal Vasko22448d32016-03-16 13:17:29 +01002178static int
2179resolve_partial_json_data_list_predicate(const char *predicate, const char *node_name, struct lyd_node *node, int *parsed)
2180{
2181 const char *name, *value;
2182 int nam_len, val_len, has_predicate = 1, r;
2183 uint16_t i;
Michal Vaskof29903d2016-04-18 13:13:10 +02002184 struct lyd_node_leaf_list *key;
Michal Vasko22448d32016-03-16 13:17:29 +01002185
Radek Krejci61a86c62016-03-24 11:06:44 +01002186 assert(node);
Michal Vasko22448d32016-03-16 13:17:29 +01002187 assert(node->schema->nodetype == LYS_LIST);
2188
Michal Vaskof29903d2016-04-18 13:13:10 +02002189 key = (struct lyd_node_leaf_list *)node->child;
2190 for (i = 0; i < ((struct lys_node_list *)node->schema)->keys_size; ++i) {
2191 if (!key) {
2192 /* invalid data */
2193 LOGINT;
2194 return -1;
2195 }
Michal Vasko22448d32016-03-16 13:17:29 +01002196
Michal Vasko22448d32016-03-16 13:17:29 +01002197 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002198 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, node_name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002199 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002200 }
2201
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002202 if (((r = parse_schema_json_predicate(predicate, &name, &nam_len, &value, &val_len, &has_predicate)) < 1)
2203 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002204 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
Michal Vaskof29903d2016-04-18 13:13:10 +02002205 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002206 }
2207
2208 predicate += r;
2209 *parsed += r;
2210
Michal Vaskof29903d2016-04-18 13:13:10 +02002211 if (strncmp(key->schema->name, name, nam_len) || key->schema->name[nam_len]) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002212 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002213 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002214 }
2215
2216 /* value does not match */
Michal Vaskof29903d2016-04-18 13:13:10 +02002217 if (strncmp(key->value_str, value, val_len) || key->value_str[val_len]) {
Michal Vasko22448d32016-03-16 13:17:29 +01002218 return 1;
2219 }
Michal Vaskof29903d2016-04-18 13:13:10 +02002220
2221 key = (struct lyd_node_leaf_list *)key->next;
Michal Vasko22448d32016-03-16 13:17:29 +01002222 }
2223
2224 if (has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002225 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko22448d32016-03-16 13:17:29 +01002226 return -1;
2227 }
2228
2229 return 0;
2230}
2231
Radek Krejci45826012016-08-24 15:07:57 +02002232/**
2233 * @brief get the closest parent of the node (or the node itself) identified by the nodeid (path)
2234 *
2235 * @param[in] nodeid Node data path to find
2236 * @param[in] llist_value If the \p nodeid identifies leaf-list, this is expected value of the leaf-list instance.
2237 * @param[in] options Bitmask of options flags, see @ref pathoptions.
2238 * @param[out] parsed Number of characters processed in \p id
2239 * @return The closes parent (or the node itself) from the path
2240 */
Michal Vasko22448d32016-03-16 13:17:29 +01002241struct lyd_node *
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002242resolve_partial_json_data_nodeid(const char *nodeid, const char *llist_value, struct lyd_node *start, int options,
2243 int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002244{
Michal Vasko10728b52016-04-07 14:26:29 +02002245 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002246 const char *id, *mod_name, *name, *pred_name;
2247 int r, ret, mod_name_len, nam_len, is_relative = -1;
2248 int has_predicate, last_parsed, val_len, pred_name_len, last_has_pred;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002249 struct lyd_node *sibling, *last_match = NULL;
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002250 struct lyd_node_leaf_list *llist;
Michal Vasko22448d32016-03-16 13:17:29 +01002251 const struct lys_module *prefix_mod, *prev_mod;
2252 struct ly_ctx *ctx;
2253
2254 assert(nodeid && start && parsed);
2255
2256 ctx = start->schema->module->ctx;
2257 id = nodeid;
2258
2259 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 +01002260 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002261 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002262 return NULL;
2263 }
2264 id += r;
2265 /* add it to parsed only after the data node was actually found */
2266 last_parsed = r;
2267
2268 if (is_relative) {
2269 prev_mod = start->schema->module;
Michal Vasko22448d32016-03-16 13:17:29 +01002270 start = start->child;
2271 } else {
2272 for (; start->parent; start = start->parent);
Michal Vasko22448d32016-03-16 13:17:29 +01002273 prev_mod = start->schema->module;
2274 }
2275
2276 while (1) {
2277 LY_TREE_FOR(start, sibling) {
Michal Vasko945b96b2016-10-18 11:49:12 +02002278 /* RPC/action data check, return simply invalid argument, because the data tree is invalid */
Michal Vasko2411b942016-03-23 13:50:03 +01002279 if (lys_parent(sibling->schema)) {
2280 if (options & LYD_PATH_OPT_OUTPUT) {
2281 if (lys_parent(sibling->schema)->nodetype == LYS_INPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002282 LOGERR(LY_EINVAL, "Provided data tree includes some RPC input nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002283 *parsed = -1;
2284 return NULL;
2285 }
2286 } else {
2287 if (lys_parent(sibling->schema)->nodetype == LYS_OUTPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002288 LOGERR(LY_EINVAL, "Provided data tree includes some RPC output nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002289 *parsed = -1;
2290 return NULL;
2291 }
2292 }
2293 }
2294
Michal Vasko22448d32016-03-16 13:17:29 +01002295 /* name match */
2296 if (!strncmp(name, sibling->schema->name, nam_len) && !sibling->schema->name[nam_len]) {
2297
2298 /* module check */
2299 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002300 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko22448d32016-03-16 13:17:29 +01002301 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002302 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002303 return NULL;
2304 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002305
2306 if (ly_buf_used && module_name[0]) {
2307 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2308 }
2309 ly_buf_used++;
2310
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002311 memmove(module_name, mod_name, mod_name_len);
Michal Vasko22448d32016-03-16 13:17:29 +01002312 module_name[mod_name_len] = '\0';
2313 /* will also find an augment module */
2314 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002315
2316 if (buf_backup) {
2317 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002318 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002319 free(buf_backup);
2320 buf_backup = NULL;
2321 }
2322 ly_buf_used--;
2323
Michal Vasko22448d32016-03-16 13:17:29 +01002324 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002325 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2326 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2327 free(str);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002328 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002329 return NULL;
2330 }
2331 } else {
2332 prefix_mod = prev_mod;
2333 }
2334 if (prefix_mod != lys_node_module(sibling->schema)) {
2335 continue;
2336 }
2337
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002338 /* leaf-list, did we find it with the correct value or not? */
Michal Vasko22448d32016-03-16 13:17:29 +01002339 if (sibling->schema->nodetype == LYS_LEAFLIST) {
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002340 last_has_pred = 0;
Michal Vaskof0a50972016-10-19 11:33:55 +02002341 if (has_predicate) {
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002342 if ((r = parse_schema_json_predicate(id, &pred_name, &pred_name_len, &llist_value, &val_len, &last_has_pred)) < 1) {
Michal Vaskof0a50972016-10-19 11:33:55 +02002343 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2344 *parsed = -1;
2345 return NULL;
2346 }
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002347 if ((pred_name[0] != '.') || (pred_name_len != 1)) {
2348 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[1], id + 1);
2349 *parsed = -1;
2350 return NULL;
2351 }
Michal Vaskof0a50972016-10-19 11:33:55 +02002352 } else {
2353 r = 0;
2354 if (llist_value) {
2355 val_len = strlen(llist_value);
2356 } else {
2357 val_len = 0;
2358 }
2359 }
2360
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002361 llist = (struct lyd_node_leaf_list *)sibling;
Michal Vaskof0a50972016-10-19 11:33:55 +02002362 if ((!val_len && llist->value_str && llist->value_str[0])
2363 || (val_len && (strncmp(llist_value, llist->value_str, val_len) || llist->value_str[val_len]))) {
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002364 continue;
2365 }
Michal Vaskof0a50972016-10-19 11:33:55 +02002366 id += r;
2367 last_parsed += r;
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002368 has_predicate = last_has_pred;
Michal Vaskof0a50972016-10-19 11:33:55 +02002369
Radek Krejci45826012016-08-24 15:07:57 +02002370 } else if (sibling->schema->nodetype == LYS_LIST) {
2371 /* list, we need predicates'n'stuff then */
Michal Vasko22448d32016-03-16 13:17:29 +01002372 r = 0;
2373 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002374 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002375 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002376 return NULL;
2377 }
2378 ret = resolve_partial_json_data_list_predicate(id, name, sibling, &r);
2379 if (ret == -1) {
Michal Vasko238bd2f2016-03-23 09:39:01 +01002380 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002381 return NULL;
2382 } else if (ret == 1) {
2383 /* this list instance does not match */
2384 continue;
2385 }
2386 id += r;
2387 last_parsed += r;
2388 }
2389
2390 *parsed += last_parsed;
2391
2392 /* the result node? */
2393 if (!id[0]) {
2394 return sibling;
2395 }
2396
2397 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002398 if (sibling->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002399 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002400 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002401 return NULL;
2402 }
Michal Vaskoc6c52cf2016-03-29 11:53:04 +02002403 last_match = sibling;
Michal Vasko22448d32016-03-16 13:17:29 +01002404 start = sibling->child;
2405 if (start) {
2406 prev_mod = start->schema->module;
2407 }
2408 break;
2409 }
2410 }
2411
2412 /* no match, return last match */
2413 if (!sibling) {
2414 return last_match;
2415 }
2416
2417 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 +01002418 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002419 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002420 return NULL;
2421 }
2422 id += r;
2423 last_parsed = r;
2424 }
2425
2426 /* cannot get here */
2427 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002428 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002429 return NULL;
2430}
2431
Michal Vasko3edeaf72016-02-11 13:17:43 +01002432/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02002433 * @brief Resolves length or range intervals. Does not log.
Michal Vaskoaeb51802016-04-11 10:58:47 +02002434 * Syntax is assumed to be correct, *ret MUST be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002435 *
Michal Vaskoaeb51802016-04-11 10:58:47 +02002436 * @param[in] str_restr Restriction as a string.
2437 * @param[in] type Type of the restriction.
2438 * @param[out] ret Final interval structure that starts with
2439 * the interval of the initial type, continues with intervals
2440 * of any superior types derived from the initial one, and
2441 * finishes with intervals from our \p type.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002442 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002443 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002444 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002445int
Michal Vaskoaeb51802016-04-11 10:58:47 +02002446resolve_len_ran_interval(const char *str_restr, struct lys_type *type, struct len_ran_intv **ret)
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002447{
2448 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002449 int kind;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002450 int64_t local_smin, local_smax, local_fmin, local_fmax;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002451 uint64_t local_umin, local_umax;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002452 uint8_t local_fdig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002453 const char *seg_ptr, *ptr;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002454 struct len_ran_intv *local_intv = NULL, *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002455
2456 switch (type->base) {
2457 case LY_TYPE_BINARY:
2458 kind = 0;
2459 local_umin = 0;
2460 local_umax = 18446744073709551615UL;
2461
2462 if (!str_restr && type->info.binary.length) {
2463 str_restr = type->info.binary.length->expr;
2464 }
2465 break;
2466 case LY_TYPE_DEC64:
2467 kind = 2;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002468 local_fmin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2469 local_fmax = __INT64_C(9223372036854775807);
2470 local_fdig = type->info.dec64.dig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002471
2472 if (!str_restr && type->info.dec64.range) {
2473 str_restr = type->info.dec64.range->expr;
2474 }
2475 break;
2476 case LY_TYPE_INT8:
2477 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002478 local_smin = __INT64_C(-128);
2479 local_smax = __INT64_C(127);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002480
2481 if (!str_restr && type->info.num.range) {
2482 str_restr = type->info.num.range->expr;
2483 }
2484 break;
2485 case LY_TYPE_INT16:
2486 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002487 local_smin = __INT64_C(-32768);
2488 local_smax = __INT64_C(32767);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002489
2490 if (!str_restr && type->info.num.range) {
2491 str_restr = type->info.num.range->expr;
2492 }
2493 break;
2494 case LY_TYPE_INT32:
2495 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002496 local_smin = __INT64_C(-2147483648);
2497 local_smax = __INT64_C(2147483647);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002498
2499 if (!str_restr && type->info.num.range) {
2500 str_restr = type->info.num.range->expr;
2501 }
2502 break;
2503 case LY_TYPE_INT64:
2504 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002505 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2506 local_smax = __INT64_C(9223372036854775807);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002507
2508 if (!str_restr && type->info.num.range) {
2509 str_restr = type->info.num.range->expr;
2510 }
2511 break;
2512 case LY_TYPE_UINT8:
2513 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002514 local_umin = __UINT64_C(0);
2515 local_umax = __UINT64_C(255);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002516
2517 if (!str_restr && type->info.num.range) {
2518 str_restr = type->info.num.range->expr;
2519 }
2520 break;
2521 case LY_TYPE_UINT16:
2522 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002523 local_umin = __UINT64_C(0);
2524 local_umax = __UINT64_C(65535);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002525
2526 if (!str_restr && type->info.num.range) {
2527 str_restr = type->info.num.range->expr;
2528 }
2529 break;
2530 case LY_TYPE_UINT32:
2531 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002532 local_umin = __UINT64_C(0);
2533 local_umax = __UINT64_C(4294967295);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002534
2535 if (!str_restr && type->info.num.range) {
2536 str_restr = type->info.num.range->expr;
2537 }
2538 break;
2539 case LY_TYPE_UINT64:
2540 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002541 local_umin = __UINT64_C(0);
2542 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002543
2544 if (!str_restr && type->info.num.range) {
2545 str_restr = type->info.num.range->expr;
2546 }
2547 break;
2548 case LY_TYPE_STRING:
2549 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002550 local_umin = __UINT64_C(0);
2551 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002552
2553 if (!str_restr && type->info.str.length) {
2554 str_restr = type->info.str.length->expr;
2555 }
2556 break;
2557 default:
2558 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002559 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002560 }
2561
2562 /* process superior types */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002563 if (type->der) {
2564 if (resolve_len_ran_interval(NULL, &type->der->type, &intv)) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002565 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002566 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02002567 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002568 assert(!intv || (intv->kind == kind));
2569 }
2570
2571 if (!str_restr) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002572 /* we do not have any restriction, return superior ones */
2573 *ret = intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002574 return EXIT_SUCCESS;
2575 }
2576
2577 /* adjust local min and max */
2578 if (intv) {
2579 tmp_intv = intv;
2580
2581 if (kind == 0) {
2582 local_umin = tmp_intv->value.uval.min;
2583 } else if (kind == 1) {
2584 local_smin = tmp_intv->value.sval.min;
2585 } else if (kind == 2) {
2586 local_fmin = tmp_intv->value.fval.min;
2587 }
2588
2589 while (tmp_intv->next) {
2590 tmp_intv = tmp_intv->next;
2591 }
2592
2593 if (kind == 0) {
2594 local_umax = tmp_intv->value.uval.max;
2595 } else if (kind == 1) {
2596 local_smax = tmp_intv->value.sval.max;
2597 } else if (kind == 2) {
2598 local_fmax = tmp_intv->value.fval.max;
2599 }
2600 }
2601
2602 /* finally parse our restriction */
2603 seg_ptr = str_restr;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002604 tmp_intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002605 while (1) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002606 if (!tmp_local_intv) {
2607 assert(!local_intv);
2608 local_intv = malloc(sizeof *local_intv);
2609 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002610 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002611 tmp_local_intv->next = malloc(sizeof *tmp_local_intv);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002612 tmp_local_intv = tmp_local_intv->next;
2613 }
Michal Vasko253035f2015-12-17 16:58:13 +01002614 if (!tmp_local_intv) {
2615 LOGMEM;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002616 goto error;
Michal Vasko253035f2015-12-17 16:58:13 +01002617 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002618
2619 tmp_local_intv->kind = kind;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002620 tmp_local_intv->type = type;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002621 tmp_local_intv->next = NULL;
2622
2623 /* min */
2624 ptr = seg_ptr;
2625 while (isspace(ptr[0])) {
2626 ++ptr;
2627 }
2628 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2629 if (kind == 0) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002630 tmp_local_intv->value.uval.min = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002631 } else if (kind == 1) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002632 tmp_local_intv->value.sval.min = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002633 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002634 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.min)) {
2635 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2636 goto error;
2637 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002638 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002639 } else if (!strncmp(ptr, "min", 3)) {
2640 if (kind == 0) {
2641 tmp_local_intv->value.uval.min = local_umin;
2642 } else if (kind == 1) {
2643 tmp_local_intv->value.sval.min = local_smin;
2644 } else if (kind == 2) {
2645 tmp_local_intv->value.fval.min = local_fmin;
2646 }
2647
2648 ptr += 3;
2649 } else if (!strncmp(ptr, "max", 3)) {
2650 if (kind == 0) {
2651 tmp_local_intv->value.uval.min = local_umax;
2652 } else if (kind == 1) {
2653 tmp_local_intv->value.sval.min = local_smax;
2654 } else if (kind == 2) {
2655 tmp_local_intv->value.fval.min = local_fmax;
2656 }
2657
2658 ptr += 3;
2659 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002660 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002661 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002662 }
2663
2664 while (isspace(ptr[0])) {
2665 ptr++;
2666 }
2667
2668 /* no interval or interval */
2669 if ((ptr[0] == '|') || !ptr[0]) {
2670 if (kind == 0) {
2671 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
2672 } else if (kind == 1) {
2673 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
2674 } else if (kind == 2) {
2675 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
2676 }
2677 } else if (!strncmp(ptr, "..", 2)) {
2678 /* skip ".." */
2679 ptr += 2;
2680 while (isspace(ptr[0])) {
2681 ++ptr;
2682 }
2683
2684 /* max */
2685 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2686 if (kind == 0) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002687 tmp_local_intv->value.uval.max = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002688 } else if (kind == 1) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002689 tmp_local_intv->value.sval.max = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002690 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002691 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.max)) {
2692 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2693 goto error;
2694 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002695 }
2696 } else if (!strncmp(ptr, "max", 3)) {
2697 if (kind == 0) {
2698 tmp_local_intv->value.uval.max = local_umax;
2699 } else if (kind == 1) {
2700 tmp_local_intv->value.sval.max = local_smax;
2701 } else if (kind == 2) {
2702 tmp_local_intv->value.fval.max = local_fmax;
2703 }
2704 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002705 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002706 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002707 }
2708 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002709 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002710 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002711 }
2712
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002713 /* check min and max in correct order*/
2714 if (kind == 0) {
2715 /* current segment */
2716 if (tmp_local_intv->value.uval.min > tmp_local_intv->value.uval.max) {
2717 goto error;
2718 }
2719 if (tmp_local_intv->value.uval.min < local_umin || tmp_local_intv->value.uval.max > local_umax) {
2720 goto error;
2721 }
2722 /* segments sholud be ascending order */
Pavol Vican69f62c92016-08-30 09:06:25 +02002723 if (tmp_intv && (tmp_intv->value.uval.max >= tmp_local_intv->value.uval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002724 goto error;
2725 }
2726 } else if (kind == 1) {
2727 if (tmp_local_intv->value.sval.min > tmp_local_intv->value.sval.max) {
2728 goto error;
2729 }
2730 if (tmp_local_intv->value.sval.min < local_smin || tmp_local_intv->value.sval.max > local_smax) {
2731 goto error;
2732 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002733 if (tmp_intv && (tmp_intv->value.sval.max >= tmp_local_intv->value.sval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002734 goto error;
2735 }
2736 } else if (kind == 2) {
2737 if (tmp_local_intv->value.fval.min > tmp_local_intv->value.fval.max) {
2738 goto error;
2739 }
2740 if (tmp_local_intv->value.fval.min < local_fmin || tmp_local_intv->value.fval.max > local_fmax) {
2741 goto error;
2742 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002743 if (tmp_intv && (tmp_intv->value.fval.max >= tmp_local_intv->value.fval.min)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002744 /* fraction-digits value is always the same (it cannot be changed in derived types) */
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002745 goto error;
2746 }
2747 }
2748
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002749 /* next segment (next OR) */
2750 seg_ptr = strchr(seg_ptr, '|');
2751 if (!seg_ptr) {
2752 break;
2753 }
2754 seg_ptr++;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002755 tmp_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002756 }
2757
2758 /* check local restrictions against superior ones */
2759 if (intv) {
2760 tmp_intv = intv;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002761 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002762
2763 while (tmp_local_intv && tmp_intv) {
2764 /* reuse local variables */
2765 if (kind == 0) {
2766 local_umin = tmp_local_intv->value.uval.min;
2767 local_umax = tmp_local_intv->value.uval.max;
2768
2769 /* it must be in this interval */
2770 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
2771 /* this interval is covered, next one */
2772 if (local_umax <= tmp_intv->value.uval.max) {
2773 tmp_local_intv = tmp_local_intv->next;
2774 continue;
2775 /* ascending order of restrictions -> fail */
2776 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002777 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002778 }
2779 }
2780 } else if (kind == 1) {
2781 local_smin = tmp_local_intv->value.sval.min;
2782 local_smax = tmp_local_intv->value.sval.max;
2783
2784 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
2785 if (local_smax <= tmp_intv->value.sval.max) {
2786 tmp_local_intv = tmp_local_intv->next;
2787 continue;
2788 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002789 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002790 }
2791 }
2792 } else if (kind == 2) {
2793 local_fmin = tmp_local_intv->value.fval.min;
2794 local_fmax = tmp_local_intv->value.fval.max;
2795
Michal Vasko4d1f0482016-09-19 14:35:06 +02002796 if ((dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.min, local_fdig) > -1)
Pavol Vican3c8ee2b2016-09-29 13:18:13 +02002797 && (dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002798 if (dec64cmp(local_fmax, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002799 tmp_local_intv = tmp_local_intv->next;
2800 continue;
2801 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002802 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002803 }
2804 }
2805 }
2806
2807 tmp_intv = tmp_intv->next;
2808 }
2809
2810 /* some interval left uncovered -> fail */
2811 if (tmp_local_intv) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002812 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002813 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002814 }
2815
Michal Vaskoaeb51802016-04-11 10:58:47 +02002816 /* append the local intervals to all the intervals of the superior types, return it all */
2817 if (intv) {
2818 for (tmp_intv = intv; tmp_intv->next; tmp_intv = tmp_intv->next);
2819 tmp_intv->next = local_intv;
2820 } else {
2821 intv = local_intv;
2822 }
2823 *ret = intv;
2824
2825 return EXIT_SUCCESS;
2826
2827error:
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002828 while (intv) {
2829 tmp_intv = intv->next;
2830 free(intv);
2831 intv = tmp_intv;
2832 }
Michal Vaskoaeb51802016-04-11 10:58:47 +02002833 while (local_intv) {
2834 tmp_local_intv = local_intv->next;
2835 free(local_intv);
2836 local_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002837 }
2838
Michal Vaskoaeb51802016-04-11 10:58:47 +02002839 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002840}
2841
Michal Vasko730dfdf2015-08-11 14:48:05 +02002842/**
Michal Vasko01c6fd22016-05-20 11:43:05 +02002843 * @brief Resolve a typedef, return only resolved typedefs if derived. If leafref, it must be
2844 * resolved for this function to return it. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002845 *
2846 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02002847 * @param[in] mod_name Typedef name module name.
2848 * @param[in] module Main module.
2849 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002850 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002851 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002852 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002853 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002854int
Michal Vasko1e62a092015-12-01 12:27:20 +01002855resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
2856 const struct lys_node *parent, struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002857{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002858 int i, j;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002859 struct lys_tpdf *tpdf, *match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002860 int tpdf_size;
2861
Michal Vasko1dca6882015-10-22 14:29:42 +02002862 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002863 /* no prefix, try built-in types */
2864 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
2865 if (!strcmp(ly_types[i].def->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002866 if (ret) {
2867 *ret = ly_types[i].def;
2868 }
2869 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002870 }
2871 }
2872 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02002873 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002874 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02002875 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002876 }
2877 }
2878
Michal Vasko1dca6882015-10-22 14:29:42 +02002879 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002880 /* search in local typedefs */
2881 while (parent) {
2882 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02002883 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02002884 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
2885 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002886 break;
2887
Radek Krejci76512572015-08-04 09:47:08 +02002888 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02002889 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
2890 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002891 break;
2892
Radek Krejci76512572015-08-04 09:47:08 +02002893 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02002894 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
2895 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002896 break;
2897
Radek Krejci76512572015-08-04 09:47:08 +02002898 case LYS_RPC:
Michal Vasko44fb6382016-06-29 11:12:27 +02002899 case LYS_ACTION:
2900 tpdf_size = ((struct lys_node_rpc_action *)parent)->tpdf_size;
2901 tpdf = ((struct lys_node_rpc_action *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002902 break;
2903
Radek Krejci76512572015-08-04 09:47:08 +02002904 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02002905 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
2906 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002907 break;
2908
Radek Krejci76512572015-08-04 09:47:08 +02002909 case LYS_INPUT:
2910 case LYS_OUTPUT:
Michal Vasko44fb6382016-06-29 11:12:27 +02002911 tpdf_size = ((struct lys_node_inout *)parent)->tpdf_size;
2912 tpdf = ((struct lys_node_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002913 break;
2914
2915 default:
Michal Vaskodcf98e62016-05-05 17:53:53 +02002916 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002917 continue;
2918 }
2919
2920 for (i = 0; i < tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002921 if (!strcmp(tpdf[i].name, name) && tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002922 match = &tpdf[i];
2923 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002924 }
2925 }
2926
Michal Vaskodcf98e62016-05-05 17:53:53 +02002927 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002928 }
Radek Krejcic071c542016-01-27 14:57:51 +01002929 } else {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002930 /* get module where to search */
Michal Vaskob6729c62015-10-21 12:09:47 +02002931 module = lys_get_import_module(module, NULL, 0, mod_name, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02002932 if (!module) {
2933 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002934 }
2935 }
2936
2937 /* search in top level typedefs */
2938 for (i = 0; i < module->tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002939 if (!strcmp(module->tpdf[i].name, name) && module->tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002940 match = &module->tpdf[i];
2941 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002942 }
2943 }
2944
2945 /* search in submodules */
Radek Krejcic071c542016-01-27 14:57:51 +01002946 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002947 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002948 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 +02002949 match = &module->inc[i].submodule->tpdf[j];
2950 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002951 }
2952 }
2953 }
2954
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002955 return EXIT_FAILURE;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002956
2957check_leafref:
2958 if (ret) {
2959 *ret = match;
2960 }
2961 if (match->type.base == LY_TYPE_LEAFREF) {
2962 while (!match->type.info.lref.path) {
2963 match = match->type.der;
2964 assert(match);
2965 }
Michal Vasko01c6fd22016-05-20 11:43:05 +02002966 }
2967 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002968}
2969
Michal Vasko1dca6882015-10-22 14:29:42 +02002970/**
2971 * @brief Check the default \p value of the \p type. Logs directly.
2972 *
2973 * @param[in] type Type definition to use.
2974 * @param[in] value Default value to check.
Michal Vasko56826402016-03-02 11:11:37 +01002975 * @param[in] module Type module.
Michal Vasko1dca6882015-10-22 14:29:42 +02002976 *
2977 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
2978 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002979static int
Radek Krejci51673202016-11-01 17:00:32 +01002980check_default(struct lys_type *type, const char **value, struct lys_module *module)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002981{
Radek Krejcibad2f172016-08-02 11:04:15 +02002982 struct lys_tpdf *base_tpdf = NULL;
Michal Vasko1dca6882015-10-22 14:29:42 +02002983 struct lyd_node_leaf_list node;
Radek Krejci51673202016-11-01 17:00:32 +01002984 const char *dflt = NULL;
Radek Krejci37b756f2016-01-18 10:15:03 +01002985 int ret = EXIT_SUCCESS;
Michal Vasko1dca6882015-10-22 14:29:42 +02002986
Radek Krejci51673202016-11-01 17:00:32 +01002987 assert(value);
2988
Radek Krejcic13db382016-08-16 10:52:42 +02002989 if (type->base <= LY_TYPE_DER) {
Michal Vasko478c4652016-07-21 12:55:01 +02002990 /* the type was not resolved yet, nothing to do for now */
2991 return EXIT_FAILURE;
2992 }
2993
Radek Krejci51673202016-11-01 17:00:32 +01002994 dflt = *value;
2995 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02002996 /* we do not have a new default value, so is there any to check even, in some base type? */
2997 for (base_tpdf = type->der; base_tpdf->type.der; base_tpdf = base_tpdf->type.der) {
2998 if (base_tpdf->dflt) {
Radek Krejci51673202016-11-01 17:00:32 +01002999 dflt = base_tpdf->dflt;
Michal Vasko478c4652016-07-21 12:55:01 +02003000 break;
3001 }
3002 }
3003
Radek Krejci51673202016-11-01 17:00:32 +01003004 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003005 /* no default value, nothing to check, all is well */
3006 return EXIT_SUCCESS;
3007 }
3008
3009 /* 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)? */
3010 switch (type->base) {
Michal Vasko478c4652016-07-21 12:55:01 +02003011 case LY_TYPE_IDENT:
3012 case LY_TYPE_INST:
3013 case LY_TYPE_LEAFREF:
3014 case LY_TYPE_BOOL:
3015 case LY_TYPE_EMPTY:
3016 /* these have no restrictions, so we would do the exact same work as the unres in the base typedef */
3017 return EXIT_SUCCESS;
Radek Krejcibad2f172016-08-02 11:04:15 +02003018 case LY_TYPE_BITS:
3019 /* the default value must match the restricted list of values, if the type was restricted */
3020 if (type->info.bits.count) {
3021 break;
3022 }
3023 return EXIT_SUCCESS;
3024 case LY_TYPE_ENUM:
3025 /* the default value must match the restricted list of values, if the type was restricted */
3026 if (type->info.enums.count) {
3027 break;
3028 }
3029 return EXIT_SUCCESS;
Michal Vasko478c4652016-07-21 12:55:01 +02003030 case LY_TYPE_DEC64:
3031 if (type->info.dec64.range) {
3032 break;
3033 }
3034 return EXIT_SUCCESS;
3035 case LY_TYPE_BINARY:
3036 if (type->info.binary.length) {
3037 break;
3038 }
3039 return EXIT_SUCCESS;
3040 case LY_TYPE_INT8:
3041 case LY_TYPE_INT16:
3042 case LY_TYPE_INT32:
3043 case LY_TYPE_INT64:
3044 case LY_TYPE_UINT8:
3045 case LY_TYPE_UINT16:
3046 case LY_TYPE_UINT32:
3047 case LY_TYPE_UINT64:
3048 if (type->info.num.range) {
3049 break;
3050 }
3051 return EXIT_SUCCESS;
3052 case LY_TYPE_STRING:
3053 if (type->info.str.length || type->info.str.patterns) {
3054 break;
3055 }
3056 return EXIT_SUCCESS;
3057 case LY_TYPE_UNION:
3058 /* way too much trouble learning whether we need to check the default again, so just do it */
3059 break;
3060 default:
3061 LOGINT;
3062 return -1;
3063 }
Radek Krejci55a161c2016-09-05 17:13:25 +02003064 } else if (type->base == LY_TYPE_EMPTY) {
3065 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "default", type->parent->name);
3066 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"empty\" data type cannot have a default value.");
3067 return -1;
Michal Vasko478c4652016-07-21 12:55:01 +02003068 }
3069
Michal Vasko1dca6882015-10-22 14:29:42 +02003070 /* dummy leaf */
Radek Krejci4fe36bd2016-03-17 16:47:16 +01003071 memset(&node, 0, sizeof node);
Radek Krejci51673202016-11-01 17:00:32 +01003072 node.value_str = dflt;
Michal Vasko1dca6882015-10-22 14:29:42 +02003073 node.value_type = type->base;
Radek Krejci37b756f2016-01-18 10:15:03 +01003074 node.schema = calloc(1, sizeof (struct lys_node_leaf));
Michal Vasko253035f2015-12-17 16:58:13 +01003075 if (!node.schema) {
3076 LOGMEM;
3077 return -1;
3078 }
Radek Krejcibad2f172016-08-02 11:04:15 +02003079 node.schema->name = strdup("fake-default");
Michal Vasko253035f2015-12-17 16:58:13 +01003080 if (!node.schema->name) {
3081 LOGMEM;
Michal Vaskof49eda02016-07-21 12:17:01 +02003082 free(node.schema);
Michal Vasko253035f2015-12-17 16:58:13 +01003083 return -1;
3084 }
Michal Vasko56826402016-03-02 11:11:37 +01003085 node.schema->module = module;
Radek Krejci37b756f2016-01-18 10:15:03 +01003086 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
Michal Vasko1dca6882015-10-22 14:29:42 +02003087
Radek Krejci37b756f2016-01-18 10:15:03 +01003088 if (type->base == LY_TYPE_LEAFREF) {
Michal Vasko1dca6882015-10-22 14:29:42 +02003089 if (!type->info.lref.target) {
3090 ret = EXIT_FAILURE;
3091 goto finish;
3092 }
Radek Krejci51673202016-11-01 17:00:32 +01003093 ret = check_default(&type->info.lref.target->type, &dflt, module);
3094 if (!ret) {
3095 /* adopt possibly changed default value to its canonical form */
3096 if (*value) {
3097 *value = dflt;
3098 }
3099 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003100 } else {
Radek Krejci1899d6a2016-11-03 13:48:07 +01003101 if (!lyp_parse_value(&((struct lys_node_leaf *)node.schema)->type, &node.value_str, NULL, NULL, &node, 1, 1)) {
Radek Krejci5dca5932016-11-04 14:30:47 +01003102 /* possible forward reference */
3103 ret = 1;
Radek Krejcibad2f172016-08-02 11:04:15 +02003104 if (base_tpdf) {
Radek Krejci9ad23f42016-10-31 15:46:52 +01003105 /* default value is defined in some base typedef */
Radek Krejcibad2f172016-08-02 11:04:15 +02003106 if ((type->base == LY_TYPE_BITS && type->der->type.der) ||
3107 (type->base == LY_TYPE_ENUM && type->der->type.der)) {
3108 /* we have refined bits/enums */
3109 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
3110 "Invalid value \"%s\" of the default statement inherited to \"%s\" from \"%s\" base type.",
Radek Krejci51673202016-11-01 17:00:32 +01003111 dflt, type->parent->name, base_tpdf->name);
Radek Krejcibad2f172016-08-02 11:04:15 +02003112 }
3113 }
Radek Krejci51673202016-11-01 17:00:32 +01003114 } else {
3115 /* success - adopt canonical form from the node into the default value */
3116 if (dflt != node.value_str) {
3117 /* this can happen only if we have non-inherited default value,
3118 * inherited default values are already in canonical form */
3119 assert(dflt == *value);
3120 *value = node.value_str;
3121 }
Michal Vasko3767fb22016-07-21 12:10:57 +02003122 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003123 }
3124
3125finish:
3126 if (node.value_type == LY_TYPE_BITS) {
3127 free(node.value.bit);
3128 }
3129 free((char *)node.schema->name);
3130 free(node.schema);
3131
3132 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003133}
3134
Michal Vasko730dfdf2015-08-11 14:48:05 +02003135/**
3136 * @brief Check a key for mandatory attributes. Logs directly.
3137 *
3138 * @param[in] key The key to check.
3139 * @param[in] flags What flags to check.
3140 * @param[in] list The list of all the keys.
3141 * @param[in] index Index of the key in the key list.
3142 * @param[in] name The name of the keys.
3143 * @param[in] len The name length.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003144 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003145 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003146 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003147static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003148check_key(struct lys_node_list *list, int index, const char *name, int len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003149{
Radek Krejciadb57612016-02-16 13:34:34 +01003150 struct lys_node_leaf *key = list->keys[index];
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003151 char *dup = NULL;
3152 int j;
3153
3154 /* existence */
3155 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02003156 if (name[len] != '\0') {
3157 dup = strdup(name);
Michal Vasko253035f2015-12-17 16:58:13 +01003158 if (!dup) {
3159 LOGMEM;
3160 return -1;
3161 }
Michal Vaskof02e3742015-08-05 16:27:02 +02003162 dup[len] = '\0';
3163 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003164 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003165 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, list, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003166 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003167 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003168 }
3169
3170 /* uniqueness */
3171 for (j = index - 1; j >= 0; j--) {
Radek Krejciadb57612016-02-16 13:34:34 +01003172 if (key == list->keys[j]) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003173 LOGVAL(LYE_KEY_DUP, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003174 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003175 }
3176 }
3177
3178 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02003179 if (key->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003180 LOGVAL(LYE_KEY_NLEAF, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003181 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003182 }
3183
3184 /* type of the leaf is not built-in empty */
Radek Krejcic3738db2016-09-15 15:51:21 +02003185 if (key->type.base == LY_TYPE_EMPTY && key->module->version < 2) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003186 LOGVAL(LYE_KEY_TYPE, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003187 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003188 }
3189
3190 /* config attribute is the same as of the list */
Radek Krejci5c08a992016-11-02 13:30:04 +01003191 if ((key->flags & LYS_CONFIG_MASK) && (list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003192 LOGVAL(LYE_KEY_CONFIG, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003193 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003194 }
3195
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003196 /* key is not placed from augment */
3197 if (key->parent->nodetype == LYS_AUGMENT) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003198 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, key, key->name);
3199 LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key inserted from augment.");
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003200 return -1;
3201 }
3202
Radek Krejci3f21ada2016-08-01 13:34:31 +02003203 /* key is not when/if-feature -conditional */
3204 j = 0;
3205 if (key->when || (key->iffeature_size && (j = 1))) {
3206 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, key, j ? "if-feature" : "when", "leaf");
3207 LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key definition cannot depend on a \"%s\" condition.",
3208 j ? "if-feature" : "when");
Radek Krejci581ce772015-11-10 17:22:40 +01003209 return -1;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003210 }
3211
Michal Vasko0b85aa82016-03-07 14:37:43 +01003212 return EXIT_SUCCESS;
Michal Vasko184521f2015-09-24 13:14:26 +02003213}
Michal Vasko730dfdf2015-08-11 14:48:05 +02003214
3215/**
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003216 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003217 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003218 * @param[in] parent The parent node of the unique structure.
Michal Vasko0b85aa82016-03-07 14:37:43 +01003219 * @param[in] uniq_str_path One path from the unique string.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003220 *
3221 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
3222 */
3223int
Radek Krejcid09d1a52016-08-11 14:05:45 +02003224resolve_unique(struct lys_node *parent, const char *uniq_str_path, uint8_t *trg_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003225{
Radek Krejci581ce772015-11-10 17:22:40 +01003226 int rc;
Michal Vasko1e62a092015-12-01 12:27:20 +01003227 const struct lys_node *leaf = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003228
Radek Krejcif3c71de2016-04-11 12:45:46 +02003229 rc = resolve_descendant_schema_nodeid(uniq_str_path, parent->child, LYS_LEAF, 1, 1, &leaf);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003230 if (rc || !leaf) {
Michal Vasko0b85aa82016-03-07 14:37:43 +01003231 if (rc) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003232 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003233 if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003234 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, parent, uniq_str_path[rc - 1], &uniq_str_path[rc - 1]);
Radek Krejcif3c71de2016-04-11 12:45:46 +02003235 } else if (rc == -2) {
Michal Vaskoc66c6d82016-04-12 11:37:31 +02003236 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Unique argument references list.");
Radek Krejci581ce772015-11-10 17:22:40 +01003237 }
Michal Vasko0b85aa82016-03-07 14:37:43 +01003238 rc = -1;
Michal Vasko0b85aa82016-03-07 14:37:43 +01003239 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01003240 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3241 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target leaf not found.");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003242 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003243 }
Radek Krejci581ce772015-11-10 17:22:40 +01003244 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003245 }
Michal Vasko9bb061b2016-02-12 11:00:19 +01003246 if (leaf->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003247 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3248 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target is not a leaf.");
Radek Krejcid09d1a52016-08-11 14:05:45 +02003249 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003250 }
3251
Radek Krejcicf509982015-12-15 09:22:44 +01003252 /* check status */
Radek Krejci48464ed2016-03-17 15:44:09 +01003253 if (lyp_check_status(parent->flags, parent->module, parent->name, leaf->flags, leaf->module, leaf->name, leaf)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003254 return -1;
3255 }
3256
Radek Krejcid09d1a52016-08-11 14:05:45 +02003257 /* check that all unique's targets are of the same config type */
3258 if (*trg_type) {
3259 if (((*trg_type == 1) && (leaf->flags & LYS_CONFIG_R)) || ((*trg_type == 2) && (leaf->flags & LYS_CONFIG_W))) {
3260 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3261 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent,
3262 "Leaf \"%s\" referenced in unique statement is config %s, but previous referenced leaf is config %s.",
3263 uniq_str_path, *trg_type == 1 ? "false" : "true", *trg_type == 1 ? "true" : "false");
3264 return -1;
3265 }
3266 } else {
3267 /* first unique */
3268 if (leaf->flags & LYS_CONFIG_W) {
3269 *trg_type = 1;
3270 } else {
3271 *trg_type = 2;
3272 }
3273 }
3274
Radek Krejcica7efb72016-01-18 13:06:01 +01003275 /* set leaf's unique flag */
3276 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
3277
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003278 return EXIT_SUCCESS;
3279
3280error:
3281
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003282 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003283}
3284
Radek Krejci0c0086a2016-03-24 15:20:28 +01003285void
Michal Vasko23b61ec2015-08-19 11:19:50 +02003286unres_data_del(struct unres_data *unres, uint32_t i)
3287{
3288 /* there are items after the one deleted */
3289 if (i+1 < unres->count) {
3290 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02003291 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003292
3293 /* deleting the last item */
3294 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02003295 free(unres->node);
3296 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003297 }
3298
3299 /* if there are no items after and it is not the last one, just move the counter */
3300 --unres->count;
3301}
3302
Michal Vasko0491ab32015-08-19 14:28:29 +02003303/**
3304 * @brief Resolve (find) a data node from a specific module. Does not log.
3305 *
3306 * @param[in] mod Module to search in.
3307 * @param[in] name Name of the data node.
3308 * @param[in] nam_len Length of the name.
3309 * @param[in] start Data node to start the search from.
3310 * @param[in,out] parents Resolved nodes. If there are some parents,
3311 * they are replaced (!!) with the resolvents.
3312 *
Michal Vasko2471e7f2016-04-11 11:00:15 +02003313 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko0491ab32015-08-19 14:28:29 +02003314 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003315static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003316resolve_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 +02003317{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003318 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02003319 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003320 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003321
Michal Vasko23b61ec2015-08-19 11:19:50 +02003322 if (!parents->count) {
3323 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003324 parents->node = malloc(sizeof *parents->node);
Michal Vasko253035f2015-12-17 16:58:13 +01003325 if (!parents->node) {
3326 LOGMEM;
Michal Vasko2471e7f2016-04-11 11:00:15 +02003327 return -1;
Michal Vasko253035f2015-12-17 16:58:13 +01003328 }
Michal Vaskocf024702015-10-08 15:01:42 +02003329 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003330 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003331 for (i = 0; i < parents->count;) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02003332 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003333 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003334 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003335 continue;
3336 }
3337 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02003338 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003339 if (node->schema->module == mod && !strncmp(node->schema->name, name, nam_len)
3340 && node->schema->name[nam_len] == '\0') {
3341 /* matching target */
3342 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02003343 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02003344 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003345 flag = 1;
3346 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02003347 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003348 ++parents->count;
Michal Vasko253035f2015-12-17 16:58:13 +01003349 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
3350 if (!parents->node) {
3351 return EXIT_FAILURE;
3352 }
Michal Vaskocf024702015-10-08 15:01:42 +02003353 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003354 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003355 }
3356 }
3357 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003358
3359 if (!flag) {
3360 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003361 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02003362 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003363 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02003364 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003365 }
3366
Michal Vasko0491ab32015-08-19 14:28:29 +02003367 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02003368}
3369
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003370/**
3371 * @brief Resolve (find) a data node. Does not log.
3372 *
Radek Krejci581ce772015-11-10 17:22:40 +01003373 * @param[in] mod_name Module name of the data node.
3374 * @param[in] mod_name_len Length of the module name.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003375 * @param[in] name Name of the data node.
3376 * @param[in] nam_len Length of the name.
3377 * @param[in] start Data node to start the search from.
3378 * @param[in,out] parents Resolved nodes. If there are some parents,
3379 * they are replaced (!!) with the resolvents.
3380 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003381 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003382 */
Radek Krejcic5090c32015-08-12 09:46:19 +02003383static int
Radek Krejci581ce772015-11-10 17:22:40 +01003384resolve_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 +02003385 struct unres_data *parents)
Radek Krejcic5090c32015-08-12 09:46:19 +02003386{
Michal Vasko1e62a092015-12-01 12:27:20 +01003387 const struct lys_module *mod;
Michal Vasko31fc3672015-10-21 12:08:13 +02003388 char *str;
Radek Krejcic5090c32015-08-12 09:46:19 +02003389
Michal Vasko23b61ec2015-08-19 11:19:50 +02003390 assert(start);
3391
Michal Vasko31fc3672015-10-21 12:08:13 +02003392 if (mod_name) {
3393 /* we have mod_name, find appropriate module */
3394 str = strndup(mod_name, mod_name_len);
Michal Vasko253035f2015-12-17 16:58:13 +01003395 if (!str) {
3396 LOGMEM;
3397 return -1;
3398 }
Michal Vasko31fc3672015-10-21 12:08:13 +02003399 mod = ly_ctx_get_module(start->schema->module->ctx, str, NULL);
3400 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02003401 if (!mod) {
3402 /* invalid prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003403 return -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02003404 }
3405 } else {
3406 /* no prefix, module is the same as of current node */
3407 mod = start->schema->module;
3408 }
3409
3410 return resolve_data(mod, name, name_len, start, parents);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003411}
3412
Michal Vasko730dfdf2015-08-11 14:48:05 +02003413/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003414 * @brief Resolve a path predicate (leafref) in JSON data context. Logs directly
Radek Krejci48464ed2016-03-17 15:44:09 +01003415 * only specific errors, general no-resolvent error is left to the caller.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003416 *
Michal Vaskobb211122015-08-19 14:03:11 +02003417 * @param[in] pred Predicate to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003418 * @param[in] node Node from which the predicate is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02003419 * @param[in,out] node_match Nodes satisfying the restriction
3420 * without the predicate. Nodes not
3421 * satisfying the predicate are removed.
Michal Vasko0491ab32015-08-19 14:28:29 +02003422 * @param[out] parsed Number of characters parsed, negative on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003423 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003424 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003425 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003426static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003427resolve_path_predicate_data(const char *pred, struct lyd_node *node, struct unres_data *node_match,
Radek Krejci010e54b2016-03-15 09:40:34 +01003428 int *parsed)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003429{
Michal Vasko730dfdf2015-08-11 14:48:05 +02003430 /* ... /node[source = destination] ... */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003431 struct unres_data source_match, dest_match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003432 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vasko0491ab32015-08-19 14:28:29 +02003433 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed_loc = 0, pke_parsed = 0;
3434 int has_predicate, dest_parent_times, i, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003435 uint32_t j;
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003436 struct lyd_node_leaf_list *leaf_dst, *leaf_src;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003437
3438 source_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003439 source_match.node = malloc(sizeof *source_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003440 if (!source_match.node) {
3441 LOGMEM;
3442 return -1;
3443 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003444 dest_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003445 dest_match.node = malloc(sizeof *dest_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003446 if (!dest_match.node) {
3447 LOGMEM;
3448 return -1;
3449 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003450
3451 do {
3452 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
3453 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003454 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, pred[-i], &pred[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003455 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003456 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003457 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003458 parsed_loc += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003459 pred += i;
3460
Michal Vasko23b61ec2015-08-19 11:19:50 +02003461 for (j = 0; j < node_match->count;) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003462 /* source */
Michal Vaskocf024702015-10-08 15:01:42 +02003463 source_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02003464
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003465 /* must be leaf (key of a list) */
Radek Krejci581ce772015-11-10 17:22:40 +01003466 if ((rc = resolve_data_node(sour_pref, sour_pref_len, source, sour_len, node_match->node[j],
Michal Vaskocf024702015-10-08 15:01:42 +02003467 &source_match)) || (source_match.count != 1) || (source_match.node[0]->schema->nodetype != LYS_LEAF)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003468 i = 0;
3469 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003470 }
3471
3472 /* destination */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003473 dest_match.node[0] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003474 dest_parent_times = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003475 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3476 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003477 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003478 rc = -1;
3479 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003480 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003481 pke_parsed = i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003482 for (i = 0; i < dest_parent_times; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02003483 dest_match.node[0] = dest_match.node[0]->parent;
3484 if (!dest_match.node[0]) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003485 i = 0;
Michal Vasko0491ab32015-08-19 14:28:29 +02003486 rc = EXIT_FAILURE;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003487 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003488 }
3489 }
3490 while (1) {
Radek Krejci581ce772015-11-10 17:22:40 +01003491 if ((rc = resolve_data_node(dest_pref, dest_pref_len, dest, dest_len, dest_match.node[0],
Michal Vasko0491ab32015-08-19 14:28:29 +02003492 &dest_match)) || (dest_match.count != 1)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003493 i = 0;
3494 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003495 }
3496
3497 if (pke_len == pke_parsed) {
3498 break;
3499 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003500 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 +02003501 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003502 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003503 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003504 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003505 }
3506 pke_parsed += i;
3507 }
3508
3509 /* check match between source and destination nodes */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003510 leaf_dst = (struct lyd_node_leaf_list *)dest_match.node[0];
3511 while (leaf_dst->value_type == LY_TYPE_LEAFREF) {
3512 leaf_dst = (struct lyd_node_leaf_list *)leaf_dst->value.leafref;
3513 }
3514 leaf_src = (struct lyd_node_leaf_list *)source_match.node[0];
3515 while (leaf_src->value_type == LY_TYPE_LEAFREF) {
3516 leaf_src = (struct lyd_node_leaf_list *)leaf_src->value.leafref;
3517 }
3518 if (leaf_src->value_type != leaf_dst->value_type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003519 goto remove_leafref;
3520 }
3521
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003522 if (!ly_strequal(leaf_src->value_str, leaf_dst->value_str, 1)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003523 goto remove_leafref;
3524 }
3525
3526 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003527 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003528 continue;
3529
3530remove_leafref:
3531 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003532 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003533 }
3534 } while (has_predicate);
3535
Michal Vaskocf024702015-10-08 15:01:42 +02003536 free(source_match.node);
3537 free(dest_match.node);
Michal Vasko0491ab32015-08-19 14:28:29 +02003538 if (parsed) {
3539 *parsed = parsed_loc;
3540 }
3541 return EXIT_SUCCESS;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003542
3543error:
3544
3545 if (source_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003546 free(source_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003547 }
3548 if (dest_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003549 free(dest_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003550 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003551 if (parsed) {
3552 *parsed = -parsed_loc+i;
3553 }
3554 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003555}
3556
Michal Vasko730dfdf2015-08-11 14:48:05 +02003557/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003558 * @brief Resolve a path (leafref) in JSON data context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003559 *
Michal Vaskocf024702015-10-08 15:01:42 +02003560 * @param[in] node Leafref data node.
Michal Vasko23b61ec2015-08-19 11:19:50 +02003561 * @param[in] path Path of the leafref.
Radek Krejci48464ed2016-03-17 15:44:09 +01003562 * @param[out] ret Matching nodes. Expects an empty, but allocated structure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003563 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003564 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003565 */
Michal Vasko184521f2015-09-24 13:14:26 +02003566static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003567resolve_path_arg_data(struct lyd_node *node, const char *path, struct unres_data *ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003568{
Radek Krejci71b795b2015-08-10 16:20:39 +02003569 struct lyd_node *data = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003570 const char *prefix, *name;
Michal Vasko0491ab32015-08-19 14:28:29 +02003571 int pref_len, nam_len, has_predicate, parent_times, i, parsed, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003572 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003573
Michal Vaskocf024702015-10-08 15:01:42 +02003574 assert(node && path && ret && !ret->count);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003575
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003576 parent_times = 0;
Michal Vaskod9173342015-08-17 14:35:36 +02003577 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003578
3579 /* searching for nodeset */
3580 do {
Radek Krejcif7ed4c32016-10-27 16:20:03 +02003581 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 +01003582 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path[-i], &path[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003583 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003584 goto error;
3585 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003586 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003587 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003588
Michal Vasko23b61ec2015-08-19 11:19:50 +02003589 if (!ret->count) {
Michal Vaskobfd98e62016-09-02 09:50:05 +02003590 if (parent_times > 0) {
3591 data = node;
3592 for (i = 1; i < parent_times; ++i) {
3593 data = data->parent;
Michal Vasko253035f2015-12-17 16:58:13 +01003594 }
Michal Vaskobfd98e62016-09-02 09:50:05 +02003595 } else if (!parent_times) {
3596 data = node->child;
3597 } else {
3598 /* absolute path */
3599 for (data = node; data->parent; data = data->parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003600 }
3601
Michal Vaskobfd98e62016-09-02 09:50:05 +02003602 /* we may still be parsing it and the pointer is not correct yet */
3603 if (data->prev) {
3604 while (data->prev->next) {
3605 data = data->prev;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003606 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003607 }
3608 }
3609
3610 /* node identifier */
Radek Krejci581ce772015-11-10 17:22:40 +01003611 if ((rc = resolve_data_node(prefix, pref_len, name, nam_len, data, ret))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003612 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003613 LOGVAL(LYE_INELEM_LEN, LY_VLOG_LYD, node, nam_len, name);
Michal Vasko184521f2015-09-24 13:14:26 +02003614 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003615 goto error;
3616 }
3617
3618 if (has_predicate) {
3619 /* we have predicate, so the current results must be lists */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003620 for (j = 0; j < ret->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02003621 if (ret->node[j]->schema->nodetype == LYS_LIST &&
3622 ((struct lys_node_list *)ret->node[0]->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003623 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003624 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003625 continue;
3626 }
3627
3628 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003629 unres_data_del(ret, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003630 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003631 if ((rc = resolve_path_predicate_data(path, node, ret, &i))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003632 if (rc == -1) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003633 LOGVAL(LYE_NORESOLV, LY_VLOG_LYD, node, "leafref", path);
Michal Vasko184521f2015-09-24 13:14:26 +02003634 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003635 goto error;
3636 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003637 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003638 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003639
Michal Vasko23b61ec2015-08-19 11:19:50 +02003640 if (!ret->count) {
Michal Vasko0491ab32015-08-19 14:28:29 +02003641 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003642 goto error;
3643 }
3644 }
3645 } while (path[0] != '\0');
3646
Michal Vaskof02e3742015-08-05 16:27:02 +02003647 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003648
3649error:
3650
Michal Vaskocf024702015-10-08 15:01:42 +02003651 free(ret->node);
3652 ret->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003653 ret->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003654
Michal Vasko0491ab32015-08-19 14:28:29 +02003655 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003656}
3657
Michal Vaskoe27516a2016-10-10 17:55:31 +00003658static int
3659resolve_path_arg_schema_valid_dep_flag(const struct lys_node *op_node, const struct lys_node *first_node, int abs_path)
3660{
3661 int dep1, dep2;
3662 const struct lys_node *node;
3663
3664 if (lys_parent(op_node)) {
3665 /* inner operation (notif/action) */
3666 if (abs_path) {
3667 return 1;
3668 } else {
3669 /* compare depth of both nodes */
3670 for (dep1 = 0, node = op_node; lys_parent(node); node = lys_parent(node));
3671 for (dep2 = 0, node = first_node; lys_parent(node); node = lys_parent(node));
3672 if ((dep2 > dep1) || ((dep2 == dep1) && (op_node != first_node))) {
3673 return 1;
3674 }
3675 }
3676 } else {
3677 /* top-level operation (notif/rpc) */
3678 if (op_node != first_node) {
3679 return 1;
3680 }
3681 }
3682
3683 return 0;
3684}
3685
Michal Vasko730dfdf2015-08-11 14:48:05 +02003686/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003687 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003688 *
Michal Vaskobb211122015-08-19 14:03:11 +02003689 * @param[in] path Path to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003690 * @param[in] context_node Predicate context node (where the predicate is placed).
3691 * @param[in] parent Path context node (where the path begins/is placed).
Michal Vaskoe27516a2016-10-10 17:55:31 +00003692 * @param[in] op_node Optional node if the leafref is in an operation (action/rpc/notif).
Michal Vasko730dfdf2015-08-11 14:48:05 +02003693 *
Michal Vasko184521f2015-09-24 13:14:26 +02003694 * @return 0 on forward reference, otherwise the number
3695 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003696 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003697 */
Michal Vasko1f76a282015-08-04 16:16:53 +02003698static int
Radek Krejciadb57612016-02-16 13:34:34 +01003699resolve_path_predicate_schema(const char *path, const struct lys_node *context_node,
Michal Vaskoe27516a2016-10-10 17:55:31 +00003700 struct lys_node *parent, const struct lys_node *op_node)
Michal Vasko1f76a282015-08-04 16:16:53 +02003701{
Michal Vasko1e62a092015-12-01 12:27:20 +01003702 const struct lys_node *src_node, *dst_node;
Michal Vasko1f76a282015-08-04 16:16:53 +02003703 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vaskof9b35d92016-10-21 15:19:30 +02003704 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, pke_parsed, parsed = 0;
3705 int has_predicate, dest_parent_times, i, rc, first_iter;
Michal Vasko1f76a282015-08-04 16:16:53 +02003706
3707 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02003708 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02003709 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003710 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003711 return -parsed+i;
3712 }
3713 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003714 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02003715
Michal Vasko58090902015-08-13 14:04:15 +02003716 /* source (must be leaf) */
Michal Vasko36cbaa42015-12-14 13:15:48 +01003717 if (!sour_pref) {
Radek Krejciadb57612016-02-16 13:34:34 +01003718 sour_pref = context_node->module->name;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003719 }
Radek Krejciadb57612016-02-16 13:34:34 +01003720 rc = lys_get_sibling(context_node->child, sour_pref, sour_pref_len, source, sour_len,
Michal Vasko59ad4582016-09-16 13:15:41 +02003721 LYS_LEAF | LYS_LEAFLIST | LYS_AUGMENT, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003722 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003723 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02003724 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003725 }
3726
3727 /* destination */
Michal Vaskof9b35d92016-10-21 15:19:30 +02003728 dest_parent_times = 0;
3729 pke_parsed = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003730 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3731 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003732 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 +02003733 return -parsed;
3734 }
3735 pke_parsed += i;
3736
Radek Krejciadb57612016-02-16 13:34:34 +01003737 for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
Michal Vaskofbaead72016-10-07 10:54:48 +02003738 /* path is supposed to be evaluated in data tree, so we have to skip
3739 * all schema nodes that cannot be instantiated in data tree */
3740 for (dst_node = lys_parent(dst_node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003741 dst_node && !(dst_node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Michal Vaskofbaead72016-10-07 10:54:48 +02003742 dst_node = lys_parent(dst_node));
3743
Michal Vasko1f76a282015-08-04 16:16:53 +02003744 if (!dst_node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003745 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003746 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003747 }
3748 }
Michal Vaskoe27516a2016-10-10 17:55:31 +00003749 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003750 while (1) {
Michal Vasko36cbaa42015-12-14 13:15:48 +01003751 if (!dest_pref) {
3752 dest_pref = dst_node->module->name;
3753 }
3754 rc = lys_get_sibling(dst_node->child, dest_pref, dest_pref_len, dest, dest_len,
Michal Vasko165dc4a2015-10-23 09:44:27 +02003755 LYS_CONTAINER | LYS_LIST | LYS_LEAF | LYS_AUGMENT, &dst_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003756 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003757 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003758 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003759 }
3760
Michal Vaskoe27516a2016-10-10 17:55:31 +00003761 if (first_iter) {
3762 if (resolve_path_arg_schema_valid_dep_flag(op_node, dst_node, 0)) {
3763 parent->flags |= LYS_VALID_DEP;
3764 }
3765 first_iter = 0;
3766 }
3767
Michal Vasko1f76a282015-08-04 16:16:53 +02003768 if (pke_len == pke_parsed) {
3769 break;
3770 }
3771
3772 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
3773 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003774 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent,
Radek Krejciadb57612016-02-16 13:34:34 +01003775 (path_key_expr+pke_parsed)[-i], (path_key_expr+pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003776 return -parsed;
3777 }
3778 pke_parsed += i;
3779 }
3780
3781 /* check source - dest match */
Michal Vasko59ad4582016-09-16 13:15:41 +02003782 if (dst_node->nodetype != src_node->nodetype) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003783 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko59ad4582016-09-16 13:15:41 +02003784 LOGVAL(LYE_SPEC, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "Destination node is not a %s, but a %s.",
3785 strnodetype(src_node->nodetype), strnodetype(dst_node->nodetype));
Michal Vasko184521f2015-09-24 13:14:26 +02003786 return -parsed;
3787 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003788 } while (has_predicate);
3789
3790 return parsed;
3791}
3792
Michal Vasko730dfdf2015-08-11 14:48:05 +02003793/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003794 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003795 *
Michal Vaskobb211122015-08-19 14:03:11 +02003796 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003797 * @param[in] parent_node Parent of the leafref.
Radek Krejci2f12f852016-01-08 12:59:57 +01003798 * @param[in] parent_tpdf Flag if the parent node is actually typedef, in that case the path
3799 * has to contain absolute path
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003800 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003801 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003802 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003803 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003804static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003805resolve_path_arg_schema(const char *path, struct lys_node *parent, int parent_tpdf,
Michal Vasko36cbaa42015-12-14 13:15:48 +01003806 const struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02003807{
Michal Vaskoe27516a2016-10-10 17:55:31 +00003808 const struct lys_node *node, *op_node = NULL;
Radek Krejci27fe55e2016-09-13 17:13:35 +02003809 const struct lys_module *mod, *mod2;
Michal Vasko1f76a282015-08-04 16:16:53 +02003810 const char *id, *prefix, *name;
3811 int pref_len, nam_len, parent_times, has_predicate;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003812 int i, first_iter, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02003813
Michal Vasko184521f2015-09-24 13:14:26 +02003814 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003815 parent_times = 0;
3816 id = path;
3817
Michal Vaskoe27516a2016-10-10 17:55:31 +00003818 /* find operation schema we are in, if applicable */
Michal Vaskoe9914d12016-10-07 14:32:37 +02003819 if (!parent_tpdf) {
Michal Vaskoe27516a2016-10-10 17:55:31 +00003820 for (op_node = lys_parent(parent);
3821 op_node && !(op_node->nodetype & (LYS_ACTION | LYS_NOTIF | LYS_RPC));
3822 op_node = lys_parent(op_node));
Michal Vaskoe9914d12016-10-07 14:32:37 +02003823 }
3824
Radek Krejci27fe55e2016-09-13 17:13:35 +02003825 mod2 = lys_node_module(parent);
Michal Vasko1f76a282015-08-04 16:16:53 +02003826 do {
Radek Krejcif7ed4c32016-10-27 16:20:03 +02003827 if ((i = parse_path_arg(parent->module, id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003828 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 +02003829 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003830 }
3831 id += i;
3832
Michal Vasko184521f2015-09-24 13:14:26 +02003833 if (first_iter) {
Michal Vasko1f76a282015-08-04 16:16:53 +02003834 if (parent_times == -1) {
Radek Krejcic071c542016-01-27 14:57:51 +01003835 /* resolve prefix of the module */
Radek Krejciadb57612016-02-16 13:34:34 +01003836 mod = lys_get_import_module(parent->module, NULL, 0, prefix, pref_len);
Radek Krejci0fa54e92016-09-14 14:01:05 +02003837 mod = lys_get_implemented_module(mod);
Radek Krejcic071c542016-01-27 14:57:51 +01003838 /* get start node */
3839 node = mod ? mod->data : NULL;
Michal Vasko58090902015-08-13 14:04:15 +02003840 if (!node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003841 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3842 "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003843 return EXIT_FAILURE;
Michal Vasko58090902015-08-13 14:04:15 +02003844 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003845 } else if (parent_times > 0) {
Radek Krejci2f12f852016-01-08 12:59:57 +01003846 if (parent_tpdf) {
3847 /* the path is not allowed to contain relative path since we are in top level typedef */
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003848 LOGVAL(LYE_NORESOLV, 0, NULL, "leafref", path);
Radek Krejci2f12f852016-01-08 12:59:57 +01003849 return -1;
3850 }
3851
Michal Vasko94458082016-10-07 14:34:36 +02003852 /* we are looking for a sibling of a node, node it's parent (that is why parent_times - 1) */
3853 for (i = 0, node = parent; i < parent_times - 1; i++) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02003854 /* path is supposed to be evaluated in data tree, so we have to skip
3855 * all schema nodes that cannot be instantiated in data tree */
3856 for (node = lys_parent(node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003857 node && !(node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Radek Krejci3a5501d2016-07-18 22:03:34 +02003858 node = lys_parent(node));
3859
Michal Vasko1f76a282015-08-04 16:16:53 +02003860 if (!node) {
Michal Vaskoe9914d12016-10-07 14:32:37 +02003861 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003862 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003863 }
3864 }
Michal Vaskoe01eca52015-08-13 14:42:02 +02003865 } else {
3866 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003867 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003868 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003869 } else {
Michal Vasko7dc71d02016-03-15 10:42:28 +01003870 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02003871 if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko2f5aceb2016-03-22 10:24:14 +01003872 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 +01003873 return -1;
3874 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003875 node = node->child;
Radek Krejci43ccc4c2016-10-18 20:40:06 +02003876 if (!node) {
3877 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3878 "leafref", path);
3879 return EXIT_FAILURE;
3880 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003881 }
3882
Michal Vasko4f0dad02016-02-15 14:08:23 +01003883 if (!prefix) {
Radek Krejciadb57612016-02-16 13:34:34 +01003884 prefix = lys_node_module(parent)->name;
Michal Vasko4f0dad02016-02-15 14:08:23 +01003885 }
3886
Michal Vasko36cbaa42015-12-14 13:15:48 +01003887 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 +02003888 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003889 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko7a55bea2016-05-02 14:51:20 +02003890 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003891 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003892
Michal Vaskoe27516a2016-10-10 17:55:31 +00003893 if (first_iter) {
3894 /* set external dependency flag, we can decide based on the first found node */
3895 if (!parent_tpdf && op_node && parent_times &&
3896 resolve_path_arg_schema_valid_dep_flag(op_node, node, (parent_times == -1 ? 1 : 0))) {
3897 parent->flags |= LYS_VALID_DEP;
3898 }
3899 first_iter = 0;
3900 }
3901
Michal Vasko1f76a282015-08-04 16:16:53 +02003902 if (has_predicate) {
3903 /* we have predicate, so the current result must be list */
3904 if (node->nodetype != LYS_LIST) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003905 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003906 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003907 }
3908
Michal Vaskoe27516a2016-10-10 17:55:31 +00003909 i = resolve_path_predicate_schema(id, node, parent, op_node);
Radek Krejci27fe55e2016-09-13 17:13:35 +02003910 if (i <= 0) {
3911 if (i == 0) {
3912 return EXIT_FAILURE;
3913 } else { /* i < 0 */
3914 return -1;
3915 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003916 }
3917 id += i;
Michal Vaskof9b35d92016-10-21 15:19:30 +02003918 has_predicate = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003919 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02003920 mod = lys_node_module(node);
3921 if (!mod->implemented && mod != mod2) {
3922 /* set the module implemented */
3923 if (lys_set_implemented(mod)) {
3924 return -1;
3925 }
3926 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003927 } while (id[0]);
3928
Michal Vaskoca917682016-07-25 11:00:37 +02003929 /* the target must be leaf or leaf-list (in YANG 1.1 only) */
Radek Krejci2a5a9602016-11-04 10:21:13 +01003930 if ((node->nodetype != LYS_LEAF) && (node->nodetype != LYS_LEAFLIST)) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003931 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Radek Krejcid47daf62016-08-22 16:23:38 +02003932 LOGVAL(LYE_SPEC, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
Radek Krejci2a5a9602016-11-04 10:21:13 +01003933 "Leafref target \"%s\" is not a leaf nor a leaf-list.", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003934 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02003935 }
3936
Radek Krejcicf509982015-12-15 09:22:44 +01003937 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01003938 if (lyp_check_status(parent->flags, parent->module, parent->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01003939 node->flags, node->module, node->name, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003940 return -1;
3941 }
3942
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003943 if (ret) {
3944 *ret = node;
3945 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02003946
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003947 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02003948}
3949
Michal Vasko730dfdf2015-08-11 14:48:05 +02003950/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003951 * @brief Resolve instance-identifier predicate in JSON data format.
3952 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003953 *
Michal Vaskobb211122015-08-19 14:03:11 +02003954 * @param[in] pred Predicate to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003955 * @param[in,out] node_match Nodes matching the restriction without
3956 * the predicate. Nodes not satisfying
3957 * the predicate are removed.
3958 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003959 * @return Number of characters successfully parsed,
3960 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003961 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003962static int
Michal Vaskof39142b2015-10-21 11:40:05 +02003963resolve_predicate(const char *pred, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003964{
Michal Vasko730dfdf2015-08-11 14:48:05 +02003965 /* ... /node[target = value] ... */
Michal Vaskob2f40be2016-09-08 16:03:48 +02003966 struct lyd_node *target;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003967 const char *model, *name, *value;
Michal Vaskob2f40be2016-09-08 16:03:48 +02003968 int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed, pred_iter, k;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003969 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003970
Michal Vasko1f2cc332015-08-19 11:18:32 +02003971 assert(pred && node_match->count);
3972
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003973 idx = -1;
3974 parsed = 0;
3975
Michal Vaskob2f40be2016-09-08 16:03:48 +02003976 pred_iter = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003977 do {
Michal Vaskof39142b2015-10-21 11:40:05 +02003978 if ((i = parse_predicate(pred, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003979 return -parsed+i;
3980 }
3981 parsed += i;
3982 pred += i;
3983
3984 if (isdigit(name[0])) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02003985 /* pos */
3986 assert(!value);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003987 idx = atoi(name);
Michal Vaskob2f40be2016-09-08 16:03:48 +02003988 } else if (name[0] != '.') {
3989 /* list keys */
3990 if (pred_iter < 0) {
3991 pred_iter = 1;
3992 } else {
3993 ++pred_iter;
3994 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003995 }
3996
Michal Vaskof2f28a12016-09-09 12:43:06 +02003997 for (cur_idx = 1, j = 0; j < node_match->count; ++cur_idx) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003998 /* target */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003999 if (name[0] == '.') {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004000 /* leaf-list value */
Michal Vaskocf024702015-10-08 15:01:42 +02004001 if (node_match->node[j]->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004002 goto remove_instid;
4003 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004004
4005 target = node_match->node[j];
4006 /* check the value */
4007 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
4008 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
4009 goto remove_instid;
4010 }
4011
4012 } else if (!value) {
4013 /* keyless list position */
4014 if ((node_match->node[j]->schema->nodetype != LYS_LIST)
4015 || ((struct lys_node_list *)node_match->node[j]->schema)->keys) {
4016 goto remove_instid;
4017 }
4018
4019 if (idx != cur_idx) {
4020 goto remove_instid;
4021 }
4022
4023 } else {
4024 /* list key value */
Michal Vaskocf024702015-10-08 15:01:42 +02004025 if (node_match->node[j]->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004026 goto remove_instid;
4027 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004028
4029 /* key module must match the list module */
4030 if (strncmp(node_match->node[j]->schema->module->name, model, mod_len)
4031 || node_match->node[j]->schema->module->name[mod_len]) {
4032 goto remove_instid;
4033 }
4034 /* find the key leaf */
Michal Vasko045182c2016-09-09 12:44:07 +02004035 for (k = 1, target = node_match->node[j]->child; target && (k < pred_iter); k++, target = target->next);
Michal Vaskob2f40be2016-09-08 16:03:48 +02004036 if (!target) {
4037 goto remove_instid;
4038 }
4039 if ((struct lys_node_leaf *)target->schema !=
4040 ((struct lys_node_list *)node_match->node[j]->schema)->keys[pred_iter - 1]) {
4041 goto remove_instid;
4042 }
4043
4044 /* check the value */
4045 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
4046 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
4047 goto remove_instid;
4048 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004049 }
4050
Michal Vaskob2f40be2016-09-08 16:03:48 +02004051 /* instid is ok, continue check with the next one */
Michal Vasko1f2cc332015-08-19 11:18:32 +02004052 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004053 continue;
4054
4055remove_instid:
Michal Vaskob2f40be2016-09-08 16:03:48 +02004056 /* does not fulfill conditions, remove instid record */
Michal Vasko1f2cc332015-08-19 11:18:32 +02004057 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004058 }
4059 } while (has_predicate);
4060
Michal Vaskob2f40be2016-09-08 16:03:48 +02004061 /* check that all list keys were specified */
4062 if ((pred_iter > 0) && node_match->count) {
Michal Vasko045182c2016-09-09 12:44:07 +02004063 j = 0;
4064 while (j < node_match->count) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004065 assert(node_match->node[j]->schema->nodetype == LYS_LIST);
4066 if (pred_iter < ((struct lys_node_list *)node_match->node[j]->schema)->keys_size) {
4067 /* not enough predicates, just remove the list instance */
4068 unres_data_del(node_match, j);
Michal Vasko045182c2016-09-09 12:44:07 +02004069 } else {
4070 ++j;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004071 }
4072 }
4073
4074 if (!node_match->count) {
4075 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier is missing some list keys.");
4076 }
4077 }
4078
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004079 return parsed;
4080}
4081
Michal Vasko730dfdf2015-08-11 14:48:05 +02004082/**
Michal Vaskof39142b2015-10-21 11:40:05 +02004083 * @brief Resolve instance-identifier in JSON data format. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004084 *
Radek Krejciadb57612016-02-16 13:34:34 +01004085 * @param[in] data Data node where the path is used
Michal Vasko730dfdf2015-08-11 14:48:05 +02004086 * @param[in] path Instance-identifier node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004087 *
Radek Krejcic5090c32015-08-12 09:46:19 +02004088 * @return Matching node or NULL if no such a node exists. If error occurs, NULL is returned and ly_errno is set.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004089 */
Radek Krejci1899d6a2016-11-03 13:48:07 +01004090struct lyd_node *
Radek Krejci48464ed2016-03-17 15:44:09 +01004091resolve_instid(struct lyd_node *data, const char *path)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004092{
Radek Krejcic5090c32015-08-12 09:46:19 +02004093 int i = 0, j;
4094 struct lyd_node *result = NULL;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004095 const struct lys_module *mod;
Radek Krejcic5090c32015-08-12 09:46:19 +02004096 struct ly_ctx *ctx = data->schema->module->ctx;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004097 const char *model, *name;
Radek Krejcic5090c32015-08-12 09:46:19 +02004098 char *str;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004099 int mod_len, name_len, has_predicate;
4100 struct unres_data node_match;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004101
4102 memset(&node_match, 0, sizeof node_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004103
Radek Krejcic5090c32015-08-12 09:46:19 +02004104 /* we need root to resolve absolute path */
4105 for (; data->parent; data = data->parent);
Michal Vaskodb9323c2015-10-16 10:32:44 +02004106 /* we're still parsing it and the pointer is not correct yet */
Michal Vasko0491ab32015-08-19 14:28:29 +02004107 if (data->prev) {
4108 for (; data->prev->next; data = data->prev);
4109 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004110
Radek Krejcic5090c32015-08-12 09:46:19 +02004111 /* search for the instance node */
4112 while (path[i]) {
Michal Vaskof39142b2015-10-21 11:40:05 +02004113 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
Radek Krejcic5090c32015-08-12 09:46:19 +02004114 if (j <= 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004115 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004116 goto error;
4117 }
Radek Krejcic5090c32015-08-12 09:46:19 +02004118 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02004119
Michal Vaskob2f40be2016-09-08 16:03:48 +02004120 str = strndup(model, mod_len);
4121 if (!str) {
4122 LOGMEM;
4123 goto error;
Radek Krejcic5090c32015-08-12 09:46:19 +02004124 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004125 mod = ly_ctx_get_module(ctx, str, NULL);
4126 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02004127
Michal Vasko1f2cc332015-08-19 11:18:32 +02004128 if (resolve_data(mod, name, name_len, data, &node_match)) {
Radek Krejcic5090c32015-08-12 09:46:19 +02004129 /* no instance exists */
4130 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004131 }
4132
4133 if (has_predicate) {
4134 /* we have predicate, so the current results must be list or leaf-list */
Michal Vaskof39142b2015-10-21 11:40:05 +02004135 j = resolve_predicate(&path[i], &node_match);
Radek Krejcic5090c32015-08-12 09:46:19 +02004136 if (j < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004137 LOGVAL(LYE_INPRED, LY_VLOG_LYD, data, &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004138 goto error;
4139 }
Michal Vasko1f2cc332015-08-19 11:18:32 +02004140 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02004141
Michal Vasko1f2cc332015-08-19 11:18:32 +02004142 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02004143 /* no instance exists */
4144 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004145 }
4146 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004147 }
4148
Michal Vasko1f2cc332015-08-19 11:18:32 +02004149 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02004150 /* no instance exists */
4151 return NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02004152 } else if (node_match.count > 1) {
Radek Krejcic5090c32015-08-12 09:46:19 +02004153 /* instance identifier must resolve to a single node */
Radek Krejci48464ed2016-03-17 15:44:09 +01004154 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
Michal Vaskod6adbaa2016-04-11 11:01:09 +02004155 goto error;
Radek Krejcic5090c32015-08-12 09:46:19 +02004156 } else {
4157 /* we have required result, remember it and cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02004158 result = node_match.node[0];
4159 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02004160 return result;
4161 }
4162
4163error:
Radek Krejcic5090c32015-08-12 09:46:19 +02004164 /* cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02004165 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02004166 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004167}
4168
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004169int
4170lys_check_xpath(struct lys_node *node, int check_place)
Michal Vasko9e635ac2016-10-17 11:44:09 +02004171{
4172 struct lys_node *parent, *elem;
4173 struct lyxp_set set;
4174 uint32_t i;
4175 int rc;
4176
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004177 if (check_place) {
4178 parent = node;
4179 while (parent) {
4180 if (parent->nodetype == LYS_GROUPING) {
4181 /* unresolved grouping, skip for now (will be checked later) */
Michal Vasko9e635ac2016-10-17 11:44:09 +02004182 return EXIT_SUCCESS;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004183 }
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004184 if (parent->nodetype == LYS_AUGMENT) {
4185 if (!((struct lys_node_augment *)parent)->target) {
Radek Krejcidf46e222016-11-08 11:57:37 +01004186 /* unresolved augment */
4187 if (parent->module->implemented) {
4188 /* skip for now (will be checked later) */
4189 return EXIT_FAILURE;
4190 } else {
4191 /* not implemented augment, skip resolving */
4192 return EXIT_SUCCESS;
4193 }
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004194 } else {
4195 parent = ((struct lys_node_augment *)parent)->target;
4196 continue;
4197 }
4198 }
4199 parent = parent->parent;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004200 }
Michal Vasko9e635ac2016-10-17 11:44:09 +02004201 }
4202
4203 rc = lyxp_node_atomize(node, &set);
4204 if (rc) {
4205 return rc;
4206 }
4207
4208 for (parent = node; parent && !(parent->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); parent = lys_parent(parent));
4209
4210 for (i = 0; i < set.used; ++i) {
4211 /* skip roots'n'stuff */
4212 if (set.val.snodes[i].type == LYXP_NODE_ELEM) {
4213 /* XPath expression cannot reference "lower" status than the node that has the definition */
4214 if (lyp_check_status(node->flags, lys_node_module(node), node->name, set.val.snodes[i].snode->flags,
4215 lys_node_module(set.val.snodes[i].snode), set.val.snodes[i].snode->name, node)) {
4216 return -1;
4217 }
4218
4219 if (parent) {
4220 for (elem = set.val.snodes[i].snode; elem && (elem != parent); elem = lys_parent(elem));
4221 if (!elem) {
4222 /* not in node's RPC or notification subtree, set the flag */
4223 node->flags |= LYS_VALID_DEP;
4224 break;
4225 }
4226 }
4227 }
4228 }
4229
4230 free(set.val.snodes);
4231 return EXIT_SUCCESS;
4232}
4233
Radek Krejcif71f48f2016-10-25 16:37:24 +02004234static int
4235check_leafref_config(struct lys_node_leaf *leaf, struct lys_type *type)
4236{
4237 int i;
4238
4239 if (type->base == LY_TYPE_LEAFREF) {
4240 if ((leaf->flags & LYS_CONFIG_W) && type->info.lref.target && (type->info.lref.target->flags & LYS_CONFIG_R)) {
4241 LOGVAL(LYE_SPEC, LY_VLOG_LYS, leaf, "The %s is config but refers to a non-config %s.",
4242 strnodetype(leaf->nodetype), strnodetype(type->info.lref.target->nodetype));
4243 return -1;
4244 }
4245 /* we can skip the test in case the leafref is not yet resolved. In that case the test is done in the time
4246 * of leafref resolving (lys_leaf_add_leafref_target()) */
4247 } else if (type->base == LY_TYPE_UNION) {
4248 for (i = 0; i < type->info.uni.count; i++) {
4249 if (check_leafref_config(leaf, &type->info.uni.types[i])) {
4250 return -1;
4251 }
4252 }
4253 }
4254 return 0;
4255}
4256
Michal Vasko9e635ac2016-10-17 11:44:09 +02004257/**
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004258 * @brief Passes config flag down to children, skips nodes without config flags.
4259 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004260 *
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004261 * @param[in] node Siblings and their children to have flags changed.
Michal Vaskoe022a562016-09-27 14:24:15 +02004262 * @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 +02004263 * @param[in] flags Flags to assign to all the nodes.
Michal Vaskoa86508c2016-08-26 14:30:19 +02004264 *
4265 * @return 0 on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004266 */
Michal Vaskoa86508c2016-08-26 14:30:19 +02004267static int
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004268inherit_config_flag(struct lys_node *node, int flags, int clear)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004269{
Radek Krejcif71f48f2016-10-25 16:37:24 +02004270 struct lys_node_leaf *leaf;
4271
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004272 assert(!(flags ^ (flags & LYS_CONFIG_MASK)));
Radek Krejci1d82ef62015-08-07 14:44:40 +02004273 LY_TREE_FOR(node, node) {
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004274 if (lys_check_xpath(node, 0)) {
Michal Vasko9e635ac2016-10-17 11:44:09 +02004275 return -1;
4276 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004277 if (clear) {
4278 node->flags &= ~LYS_CONFIG_MASK;
Michal Vaskoc2a8d362016-09-29 08:50:13 +02004279 node->flags &= ~LYS_CONFIG_SET;
Michal Vaskoe022a562016-09-27 14:24:15 +02004280 } else {
4281 if (node->flags & LYS_CONFIG_SET) {
4282 /* skip nodes with an explicit config value */
4283 if ((flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
4284 LOGVAL(LYE_INARG, LY_VLOG_LYS, node, "true", "config");
4285 LOGVAL(LYE_SPEC, LY_VLOG_LYS, node, "State nodes cannot have configuration nodes as children.");
4286 return -1;
4287 }
4288 continue;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004289 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004290
4291 if (!(node->nodetype & (LYS_USES | LYS_GROUPING))) {
4292 node->flags = (node->flags & ~LYS_CONFIG_MASK) | flags;
4293 /* check that configuration lists have keys */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004294 if ((node->nodetype == LYS_LIST) && (node->flags & LYS_CONFIG_W)
4295 && !((struct lys_node_list *)node)->keys_size) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004296 LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_LYS, node, "key", "list");
4297 return -1;
4298 }
4299 }
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004300 }
Radek Krejcibf2abff2016-08-23 15:51:52 +02004301 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004302 if (inherit_config_flag(node->child, flags, clear)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004303 return -1;
4304 }
Radek Krejcif71f48f2016-10-25 16:37:24 +02004305 } else if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
4306 leaf = (struct lys_node_leaf *)node;
4307 if (check_leafref_config(leaf, &leaf->type)) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02004308 return -1;
4309 }
4310 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004311 }
Michal Vaskoa86508c2016-08-26 14:30:19 +02004312
4313 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004314}
4315
Michal Vasko730dfdf2015-08-11 14:48:05 +02004316/**
Michal Vasko7178e692016-02-12 15:58:05 +01004317 * @brief Resolve augment target. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004318 *
Michal Vaskobb211122015-08-19 14:03:11 +02004319 * @param[in] aug Augment to use.
Michal Vasko3edeaf72016-02-11 13:17:43 +01004320 * @param[in] siblings Nodes where to start the search in. If set, uses augment, if not, standalone augment.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004321 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004322 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004323 */
Michal Vasko7178e692016-02-12 15:58:05 +01004324static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004325resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004326{
Michal Vaskoe022a562016-09-27 14:24:15 +02004327 int rc, clear_config;
Michal Vasko1d87a922015-08-21 12:57:16 +02004328 struct lys_node *sub;
Pavol Vican47319932016-08-29 09:14:47 +02004329 const struct lys_node *aug_target, *parent;
Radek Krejci27fe55e2016-09-13 17:13:35 +02004330 struct lys_module *mod;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004331
Michal Vasko15b36692016-08-26 15:29:54 +02004332 assert(aug && !aug->target);
Radek Krejcidf46e222016-11-08 11:57:37 +01004333 mod = lys_main_module(aug->module);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004334
Michal Vasko15b36692016-08-26 15:29:54 +02004335 /* resolve target node */
Radek Krejcidf46e222016-11-08 11:57:37 +01004336 rc = resolve_augment_schema_nodeid(aug->target_name, siblings, (siblings ? NULL : aug->module), mod->implemented, &aug_target);
Michal Vasko15b36692016-08-26 15:29:54 +02004337 if (rc == -1) {
4338 return -1;
4339 }
4340 if (rc > 0) {
4341 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, aug, aug->target_name[rc - 1], &aug->target_name[rc - 1]);
4342 return -1;
4343 }
Radek Krejcidf46e222016-11-08 11:57:37 +01004344 if (!aug_target && mod->implemented) {
Michal Vasko15b36692016-08-26 15:29:54 +02004345 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
4346 return EXIT_FAILURE;
4347 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02004348 /* check that we want to connect augment into its target */
Radek Krejci27fe55e2016-09-13 17:13:35 +02004349 if (!mod->implemented) {
4350 /* it must be augment only to the same module,
4351 * otherwise we do not apply augment in not-implemented
4352 * module. If the module is set to be implemented in future,
4353 * the augment is being resolved and checked again */
Radek Krejcidf46e222016-11-08 11:57:37 +01004354 if (!aug_target) {
4355 /* target was not even resolved */
4356 return EXIT_SUCCESS;
4357 }
4358 /* target was resolved, but it may refer another module */
4359 for (sub = (struct lys_node *)aug_target; sub; sub = lys_parent(sub)) {
Radek Krejci27fe55e2016-09-13 17:13:35 +02004360 if (lys_node_module(sub) != mod) {
4361 /* this is not an implemented module and the augment
4362 * target some other module, so avoid its connecting
4363 * to the target */
4364 return EXIT_SUCCESS;
4365 }
4366 }
4367 }
4368
Michal Vasko15b36692016-08-26 15:29:54 +02004369 if (!aug->child) {
4370 /* nothing to do */
4371 LOGWRN("Augment \"%s\" without children.", aug->target_name);
Radek Krejci27fe55e2016-09-13 17:13:35 +02004372 goto success;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004373 }
4374
Michal Vaskod58d5962016-03-02 14:29:41 +01004375 /* check for mandatory nodes - if the target node is in another module
4376 * the added nodes cannot be mandatory
4377 */
Michal Vasko15b36692016-08-26 15:29:54 +02004378 if (!aug->parent && (lys_node_module((struct lys_node *)aug) != lys_node_module(aug_target))
Radek Krejcidf24cbe2016-11-08 11:55:51 +01004379 && (rc = lyp_check_mandatory_augment(aug, aug_target))) {
Radek Krejcie00d2312016-08-12 15:27:49 +02004380 return rc;
Michal Vaskod58d5962016-03-02 14:29:41 +01004381 }
4382
Michal Vasko07e89ef2016-03-03 13:28:57 +01004383 /* check augment target type and then augment nodes type */
Michal Vasko15b36692016-08-26 15:29:54 +02004384 if (aug_target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF)) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004385 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004386 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES | LYS_CHOICE))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004387 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4388 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko15b36692016-08-26 15:29:54 +02004389 strnodetype(aug_target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004390 return -1;
4391 }
4392 }
Michal Vasko15b36692016-08-26 15:29:54 +02004393 } else if (aug_target->nodetype == LYS_CHOICE) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004394 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004395 if (!(sub->nodetype & (LYS_CASE | LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004396 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4397 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko15b36692016-08-26 15:29:54 +02004398 strnodetype(aug_target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004399 return -1;
4400 }
4401 }
4402 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01004403 LOGVAL(LYE_INARG, LY_VLOG_LYS, aug, aug->target_name, "target-node");
Michal Vasko15b36692016-08-26 15:29:54 +02004404 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Invalid augment target node type \"%s\".", strnodetype(aug_target->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004405 return -1;
4406 }
4407
Radek Krejcic071c542016-01-27 14:57:51 +01004408 /* check identifier uniqueness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02004409 LY_TREE_FOR(aug->child, sub) {
Michal Vasko15b36692016-08-26 15:29:54 +02004410 if (lys_check_id(sub, (struct lys_node *)aug_target, NULL)) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02004411 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02004412 }
4413 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004414
Michal Vasko15b36692016-08-26 15:29:54 +02004415 /* finally reconnect augmenting data into the target - add them to the target child list,
4416 * by setting aug->target we know the augment is fully resolved now */
4417 aug->target = (struct lys_node *)aug_target;
4418 if (aug->target->child) {
4419 sub = aug->target->child->prev; /* remember current target's last node */
4420 sub->next = aug->child; /* connect augmenting data after target's last node */
4421 aug->target->child->prev = aug->child->prev; /* new target's last node is last augmenting node */
4422 aug->child->prev = sub; /* finish connecting of both child lists */
4423 } else {
4424 aug->target->child = aug->child;
4425 }
4426
Michal Vasko9e635ac2016-10-17 11:44:09 +02004427 /* inherit config information from actual parent */
4428 for(parent = aug_target; parent && !(parent->nodetype & (LYS_NOTIF | LYS_INPUT | LYS_OUTPUT | LYS_RPC)); parent = lys_parent(parent));
4429 clear_config = (parent) ? 1 : 0;
4430 LY_TREE_FOR(aug->child, sub) {
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004431 if (inherit_config_flag(sub, aug_target->flags & LYS_CONFIG_MASK, clear_config)) {
Michal Vasko9e635ac2016-10-17 11:44:09 +02004432 return -1;
4433 }
4434 }
4435
Radek Krejci27fe55e2016-09-13 17:13:35 +02004436success:
4437 if (mod->implemented) {
4438 /* make target modules also implemented */
4439 for (sub = aug->target; sub; sub = lys_parent(sub)) {
4440 if (lys_set_implemented(sub->module)) {
4441 return -1;
4442 }
4443 }
4444 }
4445
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004446 return EXIT_SUCCESS;
4447}
4448
Michal Vasko730dfdf2015-08-11 14:48:05 +02004449/**
Pavol Vican855ca622016-09-05 13:07:54 +02004450 * @brief Resolve (find) choice default case. Does not log.
4451 *
4452 * @param[in] choic Choice to use.
4453 * @param[in] dflt Name of the default case.
4454 *
4455 * @return Pointer to the default node or NULL.
4456 */
4457static struct lys_node *
4458resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
4459{
4460 struct lys_node *child, *ret;
4461
4462 LY_TREE_FOR(choic->child, child) {
4463 if (child->nodetype == LYS_USES) {
4464 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
4465 if (ret) {
4466 return ret;
4467 }
4468 }
4469
4470 if (ly_strequal(child->name, dflt, 1) && (child->nodetype & (LYS_ANYDATA | LYS_CASE
Radek Krejci2f792db2016-09-12 10:52:33 +02004471 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE))) {
Pavol Vican855ca622016-09-05 13:07:54 +02004472 return child;
4473 }
4474 }
4475
4476 return NULL;
4477}
4478
4479/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02004480 * @brief Resolve uses, apply augments, refines. Logs directly.
4481 *
Michal Vaskobb211122015-08-19 14:03:11 +02004482 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004483 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004484 *
Michal Vaskodef0db12015-10-07 13:22:48 +02004485 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004486 */
Michal Vasko184521f2015-09-24 13:14:26 +02004487static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004488resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004489{
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004490 struct ly_ctx *ctx = uses->module->ctx; /* shortcut */
Pavol Vican855ca622016-09-05 13:07:54 +02004491 struct lys_node *node = NULL, *next, *iter, **refine_nodes = NULL;
Pavol Vican55abd332016-07-12 15:54:49 +02004492 struct lys_node *node_aux, *parent, *tmp;
Radek Krejci200bf712016-08-16 17:11:04 +02004493 struct lys_node_leaflist *llist;
4494 struct lys_node_leaf *leaf;
Radek Krejci76512572015-08-04 09:47:08 +02004495 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004496 struct lys_restr *must, **old_must;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004497 struct lys_iffeature *iff, **old_iff;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004498 int i, j, k, rc;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004499 uint8_t size, *old_size;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004500 unsigned int usize, usize1, usize2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004501
Michal Vasko71e1aa82015-08-12 12:17:51 +02004502 assert(uses->grp);
Michal Vaskoe7708512016-03-11 10:26:55 +01004503 /* HACK just check that the grouping is resolved */
Michal Vaskodef0db12015-10-07 13:22:48 +02004504 assert(!uses->grp->nacm);
Michal Vasko71e1aa82015-08-12 12:17:51 +02004505
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004506 if (!uses->grp->child) {
4507 /* grouping without children, warning was already displayed */
4508 return EXIT_SUCCESS;
4509 }
4510
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004511 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01004512 LY_TREE_FOR(uses->grp->child, node_aux) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004513 node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, uses->nacm, unres, 0);
Michal Vasko1e62a092015-12-01 12:27:20 +01004514 if (!node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004515 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, uses->grp->name, "uses");
4516 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Copying data from grouping failed.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004517 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004518 }
Pavol Vican55abd332016-07-12 15:54:49 +02004519 /* test the name of siblings */
4520 LY_TREE_FOR((uses->parent) ? uses->parent->child : lys_main_module(uses->module)->data, tmp) {
Pavol Vican2510ddc2016-07-18 16:23:44 +02004521 if (!(tmp->nodetype & (LYS_USES | LYS_GROUPING | LYS_CASE)) && ly_strequal(tmp->name, node_aux->name, 1)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004522 goto fail;
Pavol Vican55abd332016-07-12 15:54:49 +02004523 }
4524 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004525 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004526
Michal Vaskodef0db12015-10-07 13:22:48 +02004527 /* we managed to copy the grouping, the rest must be possible to resolve */
4528
Pavol Vican855ca622016-09-05 13:07:54 +02004529 if (uses->refine_size) {
4530 refine_nodes = malloc(uses->refine_size * sizeof *refine_nodes);
4531 if (!refine_nodes) {
4532 LOGMEM;
4533 goto fail;
4534 }
4535 }
4536
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004537 /* apply refines */
4538 for (i = 0; i < uses->refine_size; i++) {
4539 rfn = &uses->refine[i];
Michal Vasko3edeaf72016-02-11 13:17:43 +01004540 rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child, LYS_NO_RPC_NOTIF_NODE,
Radek Krejcif3c71de2016-04-11 12:45:46 +02004541 1, 0, (const struct lys_node **)&node);
Michal Vasko9bb061b2016-02-12 11:00:19 +01004542 if (rc || !node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004543 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004544 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004545 }
4546
Radek Krejci1d82ef62015-08-07 14:44:40 +02004547 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004548 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
4549 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Refine substatements not applicable to the target-node.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004550 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004551 }
Pavol Vican855ca622016-09-05 13:07:54 +02004552 refine_nodes[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004553
4554 /* description on any nodetype */
4555 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004556 lydict_remove(ctx, node->dsc);
4557 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004558 }
4559
4560 /* reference on any nodetype */
4561 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004562 lydict_remove(ctx, node->ref);
4563 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004564 }
4565
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004566 /* config on any nodetype,
4567 * in case of notification or rpc/action, the config is not applicable (there is no config status) */
4568 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004569 node->flags &= ~LYS_CONFIG_MASK;
4570 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004571 }
4572
4573 /* default value ... */
Radek Krejci200bf712016-08-16 17:11:04 +02004574 if (rfn->dflt_size) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004575 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004576 /* leaf */
Radek Krejci200bf712016-08-16 17:11:04 +02004577 leaf = (struct lys_node_leaf *)node;
4578
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004579 /* replace default value */
Radek Krejci200bf712016-08-16 17:11:04 +02004580 lydict_remove(ctx, leaf->dflt);
4581 leaf->dflt = lydict_insert(ctx, rfn->dflt[0], 0);
4582
4583 /* check the default value */
Radek Krejci51673202016-11-01 17:00:32 +01004584 if (unres_schema_add_node(leaf->module, unres, &leaf->type, UNRES_TYPE_DFLT,
4585 (struct lys_node *)(&leaf->dflt)) == -1) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004586 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004587 }
Radek Krejci200bf712016-08-16 17:11:04 +02004588 } else if (node->nodetype == LYS_LEAFLIST) {
4589 /* leaf-list */
4590 llist = (struct lys_node_leaflist *)node;
4591
4592 /* remove complete set of defaults in target */
4593 for (i = 0; i < llist->dflt_size; i++) {
4594 lydict_remove(ctx, llist->dflt[i]);
4595 }
4596 free(llist->dflt);
4597
4598 /* copy the default set from refine */
4599 llist->dflt_size = rfn->dflt_size;
4600 llist->dflt = malloc(llist->dflt_size * sizeof *llist->dflt);
4601 for (i = 0; i < llist->dflt_size; i++) {
4602 llist->dflt[i] = lydict_insert(ctx, rfn->dflt[i], 0);
4603 }
4604
4605 /* check default value */
4606 for (i = 0; i < llist->dflt_size; i++) {
Radek Krejci51673202016-11-01 17:00:32 +01004607 if (unres_schema_add_node(llist->module, unres, &llist->type, UNRES_TYPE_DFLT,
4608 (struct lys_node *)(&llist->dflt[i])) == -1) {
Pavol Vican855ca622016-09-05 13:07:54 +02004609 goto fail;
Radek Krejci200bf712016-08-16 17:11:04 +02004610 }
4611 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004612 }
4613 }
4614
4615 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02004616 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004617 if (node->nodetype & (LYS_LEAF | LYS_ANYDATA | LYS_CHOICE)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004618 /* remove current value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004619 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004620
4621 /* set new value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004622 node->flags |= (rfn->flags & LYS_MAND_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004623 }
Pavol Vican855ca622016-09-05 13:07:54 +02004624 if (rfn->flags & LYS_MAND_TRUE) {
4625 /* check if node has default value */
4626 if ((node->nodetype & LYS_LEAF) && ((struct lys_node_leaf *)node)->dflt) {
4627 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"mandatory\" statement is forbidden on leaf with \"default\".");
4628 goto fail;
4629 }
4630 if ((node->nodetype & LYS_CHOICE) && ((struct lys_node_choice *)node)->dflt) {
4631 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"mandatory\" statement is forbidden on choices with \"default\".");
4632 goto fail;
4633 }
4634 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004635 }
4636
4637 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004638 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
4639 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
4640 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004641 }
4642
4643 /* min/max-elements on list or leaf-list */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004644 if (node->nodetype == LYS_LIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004645 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004646 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004647 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004648 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004649 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004650 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02004651 } else if (node->nodetype == LYS_LEAFLIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004652 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004653 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004654 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004655 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004656 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004657 }
4658 }
4659
4660 /* must in leaf, leaf-list, list, container or anyxml */
4661 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004662 switch (node->nodetype) {
4663 case LYS_LEAF:
4664 old_size = &((struct lys_node_leaf *)node)->must_size;
4665 old_must = &((struct lys_node_leaf *)node)->must;
4666 break;
4667 case LYS_LEAFLIST:
4668 old_size = &((struct lys_node_leaflist *)node)->must_size;
4669 old_must = &((struct lys_node_leaflist *)node)->must;
4670 break;
4671 case LYS_LIST:
4672 old_size = &((struct lys_node_list *)node)->must_size;
4673 old_must = &((struct lys_node_list *)node)->must;
4674 break;
4675 case LYS_CONTAINER:
4676 old_size = &((struct lys_node_container *)node)->must_size;
4677 old_must = &((struct lys_node_container *)node)->must;
4678 break;
4679 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02004680 case LYS_ANYDATA:
4681 old_size = &((struct lys_node_anydata *)node)->must_size;
4682 old_must = &((struct lys_node_anydata *)node)->must;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004683 break;
4684 default:
4685 LOGINT;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004686 goto fail;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004687 }
4688
4689 size = *old_size + rfn->must_size;
4690 must = realloc(*old_must, size * sizeof *rfn->must);
4691 if (!must) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004692 LOGMEM;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004693 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004694 }
Pavol Vican855ca622016-09-05 13:07:54 +02004695 for (k = 0, j = *old_size; k < rfn->must_size; k++, j++) {
4696 must[j].expr = lydict_insert(ctx, rfn->must[k].expr, 0);
4697 must[j].dsc = lydict_insert(ctx, rfn->must[k].dsc, 0);
4698 must[j].ref = lydict_insert(ctx, rfn->must[k].ref, 0);
4699 must[j].eapptag = lydict_insert(ctx, rfn->must[k].eapptag, 0);
4700 must[j].emsg = lydict_insert(ctx, rfn->must[k].emsg, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004701 }
4702
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004703 *old_must = must;
4704 *old_size = size;
Michal Vasko508a50d2016-09-07 14:50:33 +02004705
4706 /* check XPath dependencies again */
4707 if (unres_schema_add_node(node->module, unres, node, UNRES_XPATH, NULL) == -1) {
4708 goto fail;
4709 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004710 }
Radek Krejci363bd4a2016-07-29 14:30:20 +02004711
4712 /* if-feature in leaf, leaf-list, list, container or anyxml */
4713 if (rfn->iffeature_size) {
4714 old_size = &node->iffeature_size;
4715 old_iff = &node->iffeature;
4716
4717 size = *old_size + rfn->iffeature_size;
4718 iff = realloc(*old_iff, size * sizeof *rfn->iffeature);
4719 if (!iff) {
4720 LOGMEM;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004721 goto fail;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004722 }
Pavol Vican855ca622016-09-05 13:07:54 +02004723 for (k = 0, j = *old_size; k < rfn->iffeature_size; k++, j++) {
4724 resolve_iffeature_getsizes(&rfn->iffeature[k], &usize1, &usize2);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004725 if (usize1) {
4726 /* there is something to duplicate */
4727 /* duplicate compiled expression */
4728 usize = (usize1 / 4) + (usize1 % 4) ? 1 : 0;
4729 iff[j].expr = malloc(usize * sizeof *iff[j].expr);
Pavol Vican855ca622016-09-05 13:07:54 +02004730 memcpy(iff[j].expr, rfn->iffeature[k].expr, usize * sizeof *iff[j].expr);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004731
4732 /* duplicate list of feature pointers */
Pavol Vican855ca622016-09-05 13:07:54 +02004733 iff[j].features = malloc(usize2 * sizeof *iff[k].features);
4734 memcpy(iff[j].features, rfn->iffeature[k].features, usize2 * sizeof *iff[j].features);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004735 }
4736 }
4737
4738 *old_iff = iff;
4739 *old_size = size;
4740 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004741 }
4742
4743 /* apply augments */
4744 for (i = 0; i < uses->augment_size; i++) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004745 rc = resolve_augment(&uses->augment[i], uses->child);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004746 if (rc) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004747 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004748 }
4749 }
4750
Pavol Vican855ca622016-09-05 13:07:54 +02004751 /* check refines */
4752 for (i = 0; i < uses->refine_size; i++) {
4753 node = refine_nodes[i];
4754 rfn = &uses->refine[i];
4755
4756 /* config on any nodetype */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004757 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Pavol Vican855ca622016-09-05 13:07:54 +02004758 for (parent = lys_parent(node); parent && parent->nodetype == LYS_USES; parent = lys_parent(parent));
Radek Krejci5c08a992016-11-02 13:30:04 +01004759 if (parent && parent->nodetype != LYS_GROUPING && (parent->flags & LYS_CONFIG_MASK) &&
Pavol Vican855ca622016-09-05 13:07:54 +02004760 ((parent->flags & LYS_CONFIG_MASK) != (rfn->flags & LYS_CONFIG_MASK)) &&
4761 (rfn->flags & LYS_CONFIG_W)) {
4762 /* setting config true under config false is prohibited */
4763 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
4764 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4765 "changing config from 'false' to 'true' is prohibited while "
4766 "the target's parent is still config 'false'.");
4767 goto fail;
4768 }
4769
4770 /* inherit config change to the target children */
4771 LY_TREE_DFS_BEGIN(node->child, next, iter) {
4772 if (rfn->flags & LYS_CONFIG_W) {
4773 if (iter->flags & LYS_CONFIG_SET) {
4774 /* config is set explicitely, go to next sibling */
4775 next = NULL;
4776 goto nextsibling;
4777 }
4778 } else { /* LYS_CONFIG_R */
4779 if ((iter->flags & LYS_CONFIG_SET) && (iter->flags & LYS_CONFIG_W)) {
4780 /* error - we would have config data under status data */
4781 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
4782 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4783 "changing config from 'true' to 'false' is prohibited while the target "
4784 "has still a children with explicit config 'true'.");
4785 goto fail;
4786 }
4787 }
4788 /* change config */
4789 iter->flags &= ~LYS_CONFIG_MASK;
4790 iter->flags |= (rfn->flags & LYS_CONFIG_MASK);
4791
4792 /* select next iter - modified LY_TREE_DFS_END */
4793 if (iter->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
4794 next = NULL;
4795 } else {
4796 next = iter->child;
4797 }
4798nextsibling:
4799 if (!next) {
4800 /* try siblings */
4801 next = iter->next;
4802 }
4803 while (!next) {
4804 /* parent is already processed, go to its sibling */
4805 iter = lys_parent(iter);
4806
4807 /* no siblings, go back through parents */
4808 if (iter == node) {
4809 /* we are done, no next element to process */
4810 break;
4811 }
4812 next = iter->next;
4813 }
4814 }
4815 }
4816
4817 /* default value */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004818 if (rfn->dflt_size) {
4819 if (node->nodetype == LYS_CHOICE) {
4820 /* choice */
4821 ((struct lys_node_choice *)node)->dflt = resolve_choice_dflt((struct lys_node_choice *)node,
4822 rfn->dflt[0]);
4823 if (!((struct lys_node_choice *)node)->dflt) {
4824 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->dflt[0], "default");
4825 goto fail;
4826 }
4827 if (lyp_check_mandatory_choice(node)) {
4828 goto fail;
4829 }
Pavol Vican855ca622016-09-05 13:07:54 +02004830 }
4831 }
4832
4833 /* min/max-elements on list or leaf-list */
4834 if (node->nodetype == LYS_LIST) {
4835 if (((struct lys_node_list *)node)->min > ((struct lys_node_list *)node)->max) {
4836 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
4837 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "\"min-elements\" is bigger than \"max-elements\".");
4838 goto fail;
4839 }
4840 } else if (node->nodetype == LYS_LEAFLIST) {
4841 if (((struct lys_node_leaflist *)node)->min > ((struct lys_node_leaflist *)node)->max) {
4842 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
4843 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "\"min-elements\" is bigger than \"max-elements\".");
4844 goto fail;
4845 }
4846 }
4847
4848 /* additional checks */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004849 /* default value with mandatory/min-elements */
Pavol Vican855ca622016-09-05 13:07:54 +02004850 if (node->nodetype == LYS_LEAFLIST) {
4851 llist = (struct lys_node_leaflist *)node;
4852 if (llist->dflt_size && llist->min) {
4853 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, rfn->dflt_size ? "default" : "min-elements", "refine");
4854 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
4855 "The \"min-elements\" statement with non-zero value is forbidden on leaf-lists with the \"default\" statement.");
4856 goto fail;
4857 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004858 } else if (node->nodetype == LYS_LEAF) {
4859 leaf = (struct lys_node_leaf *)node;
4860 if (leaf->dflt && (leaf->flags & LYS_MAND_TRUE)) {
4861 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, rfn->dflt_size ? "default" : "mandatory", "refine");
4862 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
4863 "The \"mandatory\" statement is forbidden on leafs with the \"default\" statement.");
4864 goto fail;
4865 }
Pavol Vican855ca622016-09-05 13:07:54 +02004866 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004867
Pavol Vican855ca622016-09-05 13:07:54 +02004868 /* check for mandatory node in default case, first find the closest parent choice to the changed node */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004869 if ((rfn->flags & LYS_MAND_TRUE) || rfn->mod.list.min) {
Pavol Vican855ca622016-09-05 13:07:54 +02004870 for (parent = node->parent;
4871 parent && !(parent->nodetype & (LYS_CHOICE | LYS_GROUPING | LYS_ACTION | LYS_USES));
4872 parent = parent->parent) {
4873 if (parent->nodetype == LYS_CONTAINER && ((struct lys_node_container *)parent)->presence) {
4874 /* stop also on presence containers */
4875 break;
4876 }
4877 }
4878 /* and if it is a choice with the default case, check it for presence of a mandatory node in it */
4879 if (parent && parent->nodetype == LYS_CHOICE && ((struct lys_node_choice *)parent)->dflt) {
4880 if (lyp_check_mandatory_choice(parent)) {
4881 goto fail;
4882 }
4883 }
4884 }
4885 }
4886 free(refine_nodes);
4887
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004888 return EXIT_SUCCESS;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004889
4890fail:
4891 LY_TREE_FOR_SAFE(uses->child, next, iter) {
4892 lys_node_free(iter, NULL, 0);
4893 }
Pavol Vican855ca622016-09-05 13:07:54 +02004894 free(refine_nodes);
Michal Vaskoa86508c2016-08-26 14:30:19 +02004895 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004896}
4897
Radek Krejci018f1f52016-08-03 16:01:20 +02004898static int
4899identity_backlink_update(struct lys_ident *der, struct lys_ident *base)
4900{
4901 int i;
4902
4903 assert(der && base);
4904
Radek Krejci018f1f52016-08-03 16:01:20 +02004905 if (!base->der) {
Radek Krejci85a54be2016-10-20 12:39:56 +02004906 /* create a set for backlinks if it does not exist */
4907 base->der = ly_set_new();
Radek Krejci018f1f52016-08-03 16:01:20 +02004908 }
Radek Krejci85a54be2016-10-20 12:39:56 +02004909 /* store backlink */
4910 ly_set_add(base->der, der, LY_SET_OPT_USEASLIST);
Radek Krejci018f1f52016-08-03 16:01:20 +02004911
Radek Krejci85a54be2016-10-20 12:39:56 +02004912 /* do it recursively */
Radek Krejci018f1f52016-08-03 16:01:20 +02004913 for (i = 0; i < base->base_size; i++) {
4914 if (identity_backlink_update(der, base->base[i])) {
4915 return EXIT_FAILURE;
4916 }
4917 }
4918
4919 return EXIT_SUCCESS;
4920}
4921
Michal Vasko730dfdf2015-08-11 14:48:05 +02004922/**
4923 * @brief Resolve base identity recursively. Does not log.
4924 *
4925 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004926 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004927 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004928 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004929 *
Radek Krejci219fa612016-08-15 10:36:51 +02004930 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on crucial error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004931 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004932static int
Michal Vasko1e62a092015-12-01 12:27:20 +01004933resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Radek Krejci018f1f52016-08-03 16:01:20 +02004934 struct unres_schema *unres, struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004935{
Michal Vaskof02e3742015-08-05 16:27:02 +02004936 uint32_t i, j;
Radek Krejci018f1f52016-08-03 16:01:20 +02004937 struct lys_ident *base = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004938
Radek Krejcicf509982015-12-15 09:22:44 +01004939 assert(ret);
4940
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004941 /* search module */
4942 for (i = 0; i < module->ident_size; i++) {
4943 if (!strcmp(basename, module->ident[i].name)) {
4944
4945 if (!ident) {
4946 /* just search for type, so do not modify anything, just return
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004947 * the base identity pointer */
Radek Krejcicf509982015-12-15 09:22:44 +01004948 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004949 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004950 }
4951
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004952 base = &module->ident[i];
4953 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004954 }
4955 }
4956
4957 /* search submodules */
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004958 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
4959 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
4960 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004961
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004962 if (!ident) {
4963 *ret = &module->inc[j].submodule->ident[i];
4964 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004965 }
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004966
4967 base = &module->inc[j].submodule->ident[i];
4968 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004969 }
4970 }
4971 }
4972
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004973matchfound:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004974 /* we found it somewhere */
Radek Krejcibabbff82016-02-19 13:31:37 +01004975 if (base) {
Radek Krejci018f1f52016-08-03 16:01:20 +02004976 /* is it already completely resolved? */
4977 for (i = 0; i < unres->count; i++) {
Radek Krejciba7b1cc2016-08-08 13:44:43 +02004978 if ((unres->item[i] == base) && (unres->type[i] == UNRES_IDENT)) {
Radek Krejci018f1f52016-08-03 16:01:20 +02004979 /* identity found, but not yet resolved, so do not return it in *res and try it again later */
4980
4981 /* simple check for circular reference,
4982 * the complete check is done as a side effect of using only completely
4983 * resolved identities (previous check of unres content) */
4984 if (ly_strequal((const char *)unres->str_snode[i], ident->name, 1)) {
4985 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, basename, "base");
4986 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Circular reference of \"%s\" identity.", basename);
Radek Krejci219fa612016-08-15 10:36:51 +02004987 return -1;
Radek Krejci018f1f52016-08-03 16:01:20 +02004988 }
4989
Radek Krejci06f64ed2016-08-15 11:07:44 +02004990 return EXIT_FAILURE;
Radek Krejcibabbff82016-02-19 13:31:37 +01004991 }
4992 }
Radek Krejci018f1f52016-08-03 16:01:20 +02004993
Radek Krejcibabbff82016-02-19 13:31:37 +01004994 /* checks done, store the result */
Radek Krejci018f1f52016-08-03 16:01:20 +02004995 *ret = base;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02004996 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004997 }
4998
Radek Krejci219fa612016-08-15 10:36:51 +02004999 /* base not found (maybe a forward reference) */
5000 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005001}
5002
Michal Vasko730dfdf2015-08-11 14:48:05 +02005003/**
5004 * @brief Resolve base identity. Logs directly.
5005 *
5006 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02005007 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005008 * @param[in] basename Base name of the identity.
Radek Krejcibabbff82016-02-19 13:31:37 +01005009 * @param[in] parent Either "type" or "identity".
Radek Krejcicf509982015-12-15 09:22:44 +01005010 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005011 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005012 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005013 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005014static int
Michal Vaskof2d43962016-09-02 11:10:16 +02005015resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char *parent,
Radek Krejci018f1f52016-08-03 16:01:20 +02005016 struct lys_type *type, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005017{
5018 const char *name;
Radek Krejci219fa612016-08-15 10:36:51 +02005019 int mod_name_len = 0, rc;
Radek Krejcicf509982015-12-15 09:22:44 +01005020 struct lys_ident *target, **ret;
Radek Krejci4372b4e2016-04-14 17:42:16 +02005021 uint16_t flags;
Radek Krejcicf509982015-12-15 09:22:44 +01005022 struct lys_module *mod;
5023
5024 assert((ident && !type) || (!ident && type));
5025
5026 if (!type) {
5027 /* have ident to resolve */
5028 ret = &target;
5029 flags = ident->flags;
5030 mod = ident->module;
5031 } else {
5032 /* have type to fill */
Michal Vaskof2d43962016-09-02 11:10:16 +02005033 ++type->info.ident.count;
5034 type->info.ident.ref = ly_realloc(type->info.ident.ref, type->info.ident.count * sizeof *type->info.ident.ref);
5035 if (!type->info.ident.ref) {
5036 LOGMEM;
5037 return -1;
5038 }
5039
5040 ret = &type->info.ident.ref[type->info.ident.count - 1];
Radek Krejcicf509982015-12-15 09:22:44 +01005041 flags = type->parent->flags;
5042 mod = type->parent->module;
5043 }
Michal Vaskof2006002016-04-21 16:28:15 +02005044 *ret = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005045
5046 /* search for the base identity */
5047 name = strchr(basename, ':');
5048 if (name) {
5049 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02005050 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005051 name++;
5052
Michal Vasko2d851a92015-10-20 16:16:36 +02005053 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005054 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02005055 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005056 }
5057 } else {
5058 name = basename;
5059 }
5060
Radek Krejcic071c542016-01-27 14:57:51 +01005061 /* get module where to search */
5062 module = lys_get_import_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len);
5063 if (!module) {
5064 /* identity refers unknown data model */
Radek Krejci02a04992016-03-17 16:06:37 +01005065 LOGVAL(LYE_INMOD, LY_VLOG_NONE, NULL, basename);
Radek Krejcic071c542016-01-27 14:57:51 +01005066 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005067 }
5068
Radek Krejcic071c542016-01-27 14:57:51 +01005069 /* search in the identified module ... */
Radek Krejci219fa612016-08-15 10:36:51 +02005070 rc = resolve_base_ident_sub(module, ident, name, unres, ret);
5071 if (!rc) {
5072 assert(*ret);
5073
5074 /* check status */
5075 if (lyp_check_status(flags, mod, ident ? ident->name : "of type",
5076 (*ret)->flags, (*ret)->module, (*ret)->name, NULL)) {
5077 rc = -1;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02005078 } else {
5079 if (ident) {
5080 ident->base[ident->base_size++] = *ret;
5081
5082 /* maintain backlinks to the derived identities */
5083 rc = identity_backlink_update(ident, *ret) ? -1 : EXIT_SUCCESS;
5084 }
Radek Krejci219fa612016-08-15 10:36:51 +02005085 }
5086 } else if (rc == EXIT_FAILURE) {
5087 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, parent, basename);
Pavol Vican053a2882016-09-05 14:40:33 +02005088 if (type) {
5089 --type->info.ident.count;
5090 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005091 }
5092
Radek Krejci219fa612016-08-15 10:36:51 +02005093 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005094}
5095
Michal Vasko730dfdf2015-08-11 14:48:05 +02005096/**
Michal Vaskof39142b2015-10-21 11:40:05 +02005097 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005098 *
Michal Vaskof2d43962016-09-02 11:10:16 +02005099 * @param[in] type Identityref type.
Michal Vaskofb0873c2015-08-21 09:00:07 +02005100 * @param[in] ident_name Identityref name.
Radek Krejciadb57612016-02-16 13:34:34 +01005101 * @param[in] node Node where the identityref is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02005102 *
5103 * @return Pointer to the identity resolvent, NULL on error.
5104 */
Radek Krejcia52656e2015-08-05 13:41:50 +02005105struct lys_ident *
Michal Vaskof2d43962016-09-02 11:10:16 +02005106resolve_identref(struct lys_type *type, const char *ident_name, struct lyd_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005107{
Michal Vaskoc633ca02015-08-21 14:03:51 +02005108 const char *mod_name, *name;
Radek Krejci85a54be2016-10-20 12:39:56 +02005109 int mod_name_len, rc, i;
5110 unsigned int u;
Michal Vaskof2d43962016-09-02 11:10:16 +02005111 struct lys_ident *der, *cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005112
Michal Vaskof2d43962016-09-02 11:10:16 +02005113 if (!type || (!type->info.ident.count && !type->der) || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005114 return NULL;
5115 }
5116
Michal Vaskoc633ca02015-08-21 14:03:51 +02005117 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, NULL);
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005118 if (rc < 1) {
Radek Krejci1899d6a2016-11-03 13:48:07 +01005119 if (node) {
5120 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
Radek Krejci5dca5932016-11-04 14:30:47 +01005121 } else {
5122 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid identityref value \"%s\".", ident_name);
5123 ly_vecode = LYVE_INCHAR;
Radek Krejci1899d6a2016-11-03 13:48:07 +01005124 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02005125 return NULL;
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005126 } else if (rc < (signed)strlen(ident_name)) {
Radek Krejci1899d6a2016-11-03 13:48:07 +01005127 if (node) {
5128 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[rc], &ident_name[rc]);
Radek Krejci5dca5932016-11-04 14:30:47 +01005129 } else {
5130 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid identityref value \"%s\".", ident_name);
5131 ly_vecode = LYVE_INCHAR;
Radek Krejci1899d6a2016-11-03 13:48:07 +01005132 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02005133 return NULL;
5134 }
5135
Michal Vaskof2d43962016-09-02 11:10:16 +02005136 /* go through all the bases in all the derived types */
5137 while (type->der) {
5138 for (i = 0; i < type->info.ident.count; ++i) {
5139 cur = type->info.ident.ref[i];
5140 if (!strcmp(cur->name, name) && (!mod_name
5141 || (!strncmp(cur->module->name, mod_name, mod_name_len) && !cur->module->name[mod_name_len]))) {
5142 goto match;
5143 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02005144
Radek Krejci85a54be2016-10-20 12:39:56 +02005145 if (cur->der) {
5146 /* there are also some derived identities */
5147 for (u = 0; u < cur->der->number; u++) {
5148 der = (struct lys_ident *)cur->der->set.g[u]; /* shortcut */
5149 if (!strcmp(der->name, name) &&
5150 (!mod_name || (!strncmp(der->module->name, mod_name, mod_name_len) && !der->module->name[mod_name_len]))) {
5151 /* we have match */
5152 cur = der;
5153 goto match;
5154 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005155 }
5156 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005157 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005158 type = &type->der->type;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005159 }
5160
Radek Krejci1899d6a2016-11-03 13:48:07 +01005161 if (node) {
5162 LOGVAL(LYE_INRESOLV, LY_VLOG_LYD, node, "identityref", ident_name);
Radek Krejci5dca5932016-11-04 14:30:47 +01005163 } else {
5164 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid identityref value \"%s\".", ident_name);
5165 ly_vecode = LYVE_INRESOLV;
Radek Krejci1899d6a2016-11-03 13:48:07 +01005166 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005167 return NULL;
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005168
5169match:
Michal Vaskof2d43962016-09-02 11:10:16 +02005170 for (i = 0; i < cur->iffeature_size; i++) {
5171 if (!resolve_iffeature(&cur->iffeature[i])) {
Radek Krejci1899d6a2016-11-03 13:48:07 +01005172 if (node) {
5173 LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, cur->name, node->schema->name);
5174 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, "Identity \"%s\" is disabled by its if-feature condition.",
5175 cur->name);
Radek Krejci5dca5932016-11-04 14:30:47 +01005176 } else {
5177 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Identity \"%s\" is disabled by its if-feature condition.",
5178 cur->name);
5179 ly_vecode = LYVE_INVAL;
Radek Krejci1899d6a2016-11-03 13:48:07 +01005180 }
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005181 return NULL;
5182 }
5183 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005184 return cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005185}
5186
Michal Vasko730dfdf2015-08-11 14:48:05 +02005187/**
Michal Vaskobb211122015-08-19 14:03:11 +02005188 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005189 *
Michal Vaskobb211122015-08-19 14:03:11 +02005190 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005191 * @param[in] unres Specific unres item.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005192 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005193 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005194 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005195static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005196resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005197{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005198 int rc;
Radek Krejci010e54b2016-03-15 09:40:34 +01005199 struct lys_node *par_grp;
Michal Vaskoe91afce2015-08-12 12:21:00 +02005200
Radek Krejci010e54b2016-03-15 09:40:34 +01005201 /* HACK: when a grouping has uses inside, all such uses have to be resolved before the grouping itself
5202 * is used in some uses. When we see such a uses, the grouping's nacm member (not used in grouping)
5203 * is used to store number of so far unresolved uses. The grouping cannot be used unless the nacm
5204 * value is decreased back to 0. To remember that the uses already increased grouping's nacm, the
5205 * LYS_USESGRP flag is used. */
Michal Vaskodcf98e62016-05-05 17:53:53 +02005206 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 +02005207
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005208 if (!uses->grp) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01005209 rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
5210 if (rc == -1) {
Michal Vasko92981a62016-10-14 10:25:16 +02005211 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005212 return -1;
5213 } else if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005214 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005215 return -1;
5216 } else if (!uses->grp) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005217 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005218 /* hack - in contrast to lys_node, lys_node_grp has bigger nacm field
5219 * (and smaller flags - it uses only a limited set of flags)
5220 */
5221 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci010e54b2016-03-15 09:40:34 +01005222 uses->flags |= LYS_USESGRP;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005223 }
Michal Vasko92981a62016-10-14 10:25:16 +02005224 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005225 return EXIT_FAILURE;
Michal Vasko12e30842015-08-04 11:54:00 +02005226 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005227 }
5228
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005229 if (uses->grp->nacm) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005230 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005231 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci010e54b2016-03-15 09:40:34 +01005232 uses->flags |= LYS_USESGRP;
Radek Krejcie00d2312016-08-12 15:27:49 +02005233 } else {
5234 /* instantiate grouping only when it is completely resolved */
5235 uses->grp = NULL;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005236 }
Michal Vasko92981a62016-10-14 10:25:16 +02005237 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005238 return EXIT_FAILURE;
5239 }
5240
Radek Krejci48464ed2016-03-17 15:44:09 +01005241 rc = resolve_uses(uses, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005242 if (!rc) {
5243 /* decrease unres count only if not first try */
Radek Krejci010e54b2016-03-15 09:40:34 +01005244 if (par_grp && (uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005245 if (!((struct lys_node_grp *)par_grp)->nacm) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005246 LOGINT;
5247 return -1;
5248 }
Radek Krejci4372b4e2016-04-14 17:42:16 +02005249 ((struct lys_node_grp *)par_grp)->nacm--;
Radek Krejci010e54b2016-03-15 09:40:34 +01005250 uses->flags &= ~LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005251 }
Radek Krejcicf509982015-12-15 09:22:44 +01005252
5253 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005254 if (lyp_check_status(uses->flags, uses->module, "of uses",
Radek Krejciadb57612016-02-16 13:34:34 +01005255 uses->grp->flags, uses->grp->module, uses->grp->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005256 (struct lys_node *)uses)) {
Radek Krejcicf509982015-12-15 09:22:44 +01005257 return -1;
5258 }
5259
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005260 return EXIT_SUCCESS;
5261 }
5262
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005263 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005264}
5265
Michal Vasko730dfdf2015-08-11 14:48:05 +02005266/**
Michal Vasko9957e592015-08-17 15:04:09 +02005267 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005268 *
Michal Vaskobb211122015-08-19 14:03:11 +02005269 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005270 * @param[in] keys_str Keys node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005271 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005272 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005273 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005274static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005275resolve_list_keys(struct lys_node_list *list, const char *keys_str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005276{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005277 int i, len, rc;
Michal Vasko4f0dad02016-02-15 14:08:23 +01005278 const char *value;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005279
5280 for (i = 0; i < list->keys_size; ++i) {
Radek Krejci5c08a992016-11-02 13:30:04 +01005281 if (!list->child) {
5282 /* no child, possible forward reference */
5283 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
5284 return EXIT_FAILURE;
5285 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005286 /* get the key name */
5287 if ((value = strpbrk(keys_str, " \t\n"))) {
5288 len = value - keys_str;
5289 while (isspace(value[0])) {
5290 value++;
5291 }
5292 } else {
5293 len = strlen(keys_str);
5294 }
5295
Radek Krejcic4283442016-04-22 09:19:27 +02005296 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 +02005297 if (rc) {
Michal Vasko7a55bea2016-05-02 14:51:20 +02005298 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
5299 return EXIT_FAILURE;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005300 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005301
Radek Krejci48464ed2016-03-17 15:44:09 +01005302 if (check_key(list, i, keys_str, len)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005303 /* check_key logs */
5304 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005305 }
5306
Radek Krejcicf509982015-12-15 09:22:44 +01005307 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005308 if (lyp_check_status(list->flags, list->module, list->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005309 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
5310 (struct lys_node *)list->keys[i])) {
Radek Krejcicf509982015-12-15 09:22:44 +01005311 return -1;
5312 }
5313
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005314 /* prepare for next iteration */
5315 while (value && isspace(value[0])) {
5316 value++;
5317 }
5318 keys_str = value;
5319 }
5320
Michal Vaskof02e3742015-08-05 16:27:02 +02005321 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005322}
5323
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005324/**
Michal Vaskobf19d252015-10-08 15:39:17 +02005325 * @brief Resolve (check) all must conditions of \p node.
5326 * Logs directly.
5327 *
5328 * @param[in] node Data node with optional must statements.
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005329 * @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 +02005330 *
5331 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
5332 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005333static int
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005334resolve_must(struct lyd_node *node, int inout_parent)
Michal Vaskof02e3742015-08-05 16:27:02 +02005335{
Michal Vaskobf19d252015-10-08 15:39:17 +02005336 uint8_t i, must_size;
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005337 struct lys_node *schema;
Michal Vaskobf19d252015-10-08 15:39:17 +02005338 struct lys_restr *must;
5339 struct lyxp_set set;
5340
5341 assert(node);
5342 memset(&set, 0, sizeof set);
5343
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005344 if (inout_parent) {
5345 for (schema = lys_parent(node->schema);
5346 schema && (schema->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES));
5347 schema = lys_parent(schema));
5348 if (!schema || !(schema->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5349 LOGINT;
5350 return -1;
5351 }
5352 must_size = ((struct lys_node_inout *)schema)->must_size;
5353 must = ((struct lys_node_inout *)schema)->must;
5354
5355 /* context node is the RPC/action */
5356 node = node->parent;
5357 if (!(node->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
5358 LOGINT;
5359 return -1;
5360 }
5361 } else {
5362 switch (node->schema->nodetype) {
5363 case LYS_CONTAINER:
5364 must_size = ((struct lys_node_container *)node->schema)->must_size;
5365 must = ((struct lys_node_container *)node->schema)->must;
5366 break;
5367 case LYS_LEAF:
5368 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
5369 must = ((struct lys_node_leaf *)node->schema)->must;
5370 break;
5371 case LYS_LEAFLIST:
5372 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
5373 must = ((struct lys_node_leaflist *)node->schema)->must;
5374 break;
5375 case LYS_LIST:
5376 must_size = ((struct lys_node_list *)node->schema)->must_size;
5377 must = ((struct lys_node_list *)node->schema)->must;
5378 break;
5379 case LYS_ANYXML:
5380 case LYS_ANYDATA:
5381 must_size = ((struct lys_node_anydata *)node->schema)->must_size;
5382 must = ((struct lys_node_anydata *)node->schema)->must;
5383 break;
5384 case LYS_NOTIF:
5385 must_size = ((struct lys_node_notif *)node->schema)->must_size;
5386 must = ((struct lys_node_notif *)node->schema)->must;
5387 break;
5388 default:
5389 must_size = 0;
5390 break;
5391 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005392 }
5393
5394 for (i = 0; i < must_size; ++i) {
Michal Vaskoa59495d2016-08-22 09:18:58 +02005395 if (lyxp_eval(must[i].expr, node, LYXP_NODE_ELEM, &set, LYXP_MUST)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02005396 return -1;
5397 }
5398
Michal Vasko944a5642016-03-21 11:48:58 +01005399 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, LYXP_MUST);
Michal Vaskobf19d252015-10-08 15:39:17 +02005400
Michal Vasko8146d4c2016-05-09 15:50:29 +02005401 if (!set.val.bool) {
Michal Vasko6ac68282016-04-11 10:56:47 +02005402 LOGVAL(LYE_NOMUST, LY_VLOG_LYD, node, must[i].expr);
5403 if (must[i].emsg) {
5404 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, must[i].emsg);
5405 }
5406 if (must[i].eapptag) {
5407 strncpy(((struct ly_err *)&ly_errno)->apptag, must[i].eapptag, LY_APPTAG_LEN - 1);
5408 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005409 return 1;
5410 }
5411 }
5412
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005413 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02005414}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005415
Michal Vaskobf19d252015-10-08 15:39:17 +02005416/**
Michal Vasko508a50d2016-09-07 14:50:33 +02005417 * @brief Resolve (find) when condition schema context node. Does not log.
5418 *
5419 * @param[in] schema Schema node with the when condition.
5420 * @param[out] ctx_snode When schema context node.
5421 * @param[out] ctx_snode_type Schema context node type.
5422 */
5423void
5424resolve_when_ctx_snode(const struct lys_node *schema, struct lys_node **ctx_snode, enum lyxp_node_type *ctx_snode_type)
5425{
5426 const struct lys_node *sparent;
5427
5428 /* find a not schema-only node */
5429 *ctx_snode_type = LYXP_NODE_ELEM;
5430 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
5431 if (schema->nodetype == LYS_AUGMENT) {
5432 sparent = ((struct lys_node_augment *)schema)->target;
5433 } else {
5434 sparent = schema->parent;
5435 }
5436 if (!sparent) {
5437 /* context node is the document root (fake root in our case) */
5438 if (schema->flags & LYS_CONFIG_W) {
5439 *ctx_snode_type = LYXP_NODE_ROOT_CONFIG;
5440 } else {
Michal Vaskob94a5e42016-09-08 14:01:56 +02005441 *ctx_snode_type = LYXP_NODE_ROOT;
Michal Vasko508a50d2016-09-07 14:50:33 +02005442 }
Michal Vasko2d2aec12016-09-08 11:42:50 +02005443 /* we need the first top-level sibling, but no uses or groupings */
Michal Vaskob94a5e42016-09-08 14:01:56 +02005444 schema = lys_getnext(NULL, NULL, lys_node_module(schema), 0);
Michal Vasko508a50d2016-09-07 14:50:33 +02005445 break;
5446 }
5447 schema = sparent;
5448 }
5449
5450 *ctx_snode = (struct lys_node *)schema;
5451}
5452
5453/**
Michal Vaskocf024702015-10-08 15:01:42 +02005454 * @brief Resolve (find) when condition context node. Does not log.
5455 *
5456 * @param[in] node Data node, whose conditional definition is being decided.
Michal Vasko508a50d2016-09-07 14:50:33 +02005457 * @param[in] schema Schema node with the when condition.
Michal Vaskoa59495d2016-08-22 09:18:58 +02005458 * @param[out] ctx_node Context node.
5459 * @param[out] ctx_node_type Context node type.
Michal Vaskocf024702015-10-08 15:01:42 +02005460 *
Michal Vaskoa59495d2016-08-22 09:18:58 +02005461 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vaskocf024702015-10-08 15:01:42 +02005462 */
Michal Vaskoa59495d2016-08-22 09:18:58 +02005463static int
5464resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema, struct lyd_node **ctx_node,
5465 enum lyxp_node_type *ctx_node_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005466{
Michal Vaskocf024702015-10-08 15:01:42 +02005467 struct lyd_node *parent;
5468 struct lys_node *sparent;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005469 enum lyxp_node_type node_type;
Michal Vaskocf024702015-10-08 15:01:42 +02005470 uint16_t i, data_depth, schema_depth;
5471
Michal Vasko508a50d2016-09-07 14:50:33 +02005472 resolve_when_ctx_snode(schema, &schema, &node_type);
Michal Vaskocf024702015-10-08 15:01:42 +02005473
Michal Vaskofe989752016-09-08 08:47:26 +02005474 if (node_type == LYXP_NODE_ELEM) {
5475 /* standard element context node */
5476 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
5477 for (sparent = schema, schema_depth = 0;
5478 sparent;
5479 sparent = (sparent->nodetype == LYS_AUGMENT ? ((struct lys_node_augment *)sparent)->target : sparent->parent)) {
5480 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_NOTIF | LYS_RPC)) {
5481 ++schema_depth;
5482 }
Michal Vaskocf024702015-10-08 15:01:42 +02005483 }
Michal Vaskofe989752016-09-08 08:47:26 +02005484 if (data_depth < schema_depth) {
5485 return -1;
5486 }
Michal Vaskocf024702015-10-08 15:01:42 +02005487
Michal Vasko956e8542016-08-26 09:43:35 +02005488 /* find the corresponding data node */
5489 for (i = 0; i < data_depth - schema_depth; ++i) {
5490 node = node->parent;
5491 }
Michal Vaskoa59495d2016-08-22 09:18:58 +02005492 if (node->schema != schema) {
5493 return -1;
5494 }
Michal Vaskofe989752016-09-08 08:47:26 +02005495 } else {
5496 /* root context node */
5497 while (node->parent) {
5498 node = node->parent;
5499 }
5500 while (node->prev->next) {
5501 node = node->prev;
5502 }
Michal Vaskocf024702015-10-08 15:01:42 +02005503 }
5504
Michal Vaskoa59495d2016-08-22 09:18:58 +02005505 *ctx_node = node;
5506 *ctx_node_type = node_type;
5507 return EXIT_SUCCESS;
Michal Vaskocf024702015-10-08 15:01:42 +02005508}
5509
Michal Vasko76c3bd32016-08-24 16:02:52 +02005510/**
5511 * @brief Temporarily unlink nodes as per YANG 1.1 RFC section 7.21.5 for when XPath evaluation.
5512 * The context nodes is adjusted if needed.
5513 *
5514 * @param[in] snode Schema node, whose children instances need to be unlinked.
5515 * @param[in,out] node Data siblings where to look for the children of \p snode. If it is unlinked,
5516 * it is moved to point to another sibling still in the original tree.
5517 * @param[in,out] ctx_node When context node, adjusted if needed.
5518 * @param[in] ctx_node_type Context node type, just for information to detect invalid situations.
5519 * @param[out] unlinked_nodes Unlinked siblings. Can be safely appended to \p node afterwards.
5520 * Ordering may change, but there will be no semantic change.
5521 *
5522 * @return EXIT_SUCCESS on success, -1 on error.
5523 */
5524static int
5525resolve_when_unlink_nodes(struct lys_node *snode, struct lyd_node **node, struct lyd_node **ctx_node,
5526 enum lyxp_node_type ctx_node_type, struct lyd_node **unlinked_nodes)
5527{
5528 struct lyd_node *next, *elem;
5529
5530 switch (snode->nodetype) {
5531 case LYS_AUGMENT:
5532 case LYS_USES:
5533 case LYS_CHOICE:
5534 case LYS_CASE:
5535 LY_TREE_FOR(snode->child, snode) {
5536 if (resolve_when_unlink_nodes(snode, node, ctx_node, ctx_node_type, unlinked_nodes)) {
5537 return -1;
5538 }
5539 }
5540 break;
5541 case LYS_CONTAINER:
5542 case LYS_LIST:
5543 case LYS_LEAF:
5544 case LYS_LEAFLIST:
5545 case LYS_ANYXML:
5546 case LYS_ANYDATA:
5547 LY_TREE_FOR_SAFE(lyd_first_sibling(*node), next, elem) {
5548 if (elem->schema == snode) {
5549
5550 if (elem == *ctx_node) {
5551 /* We are going to unlink our context node! This normally cannot happen,
5552 * but we use normal top-level data nodes for faking a document root node,
5553 * so if this is the context node, we just use the next top-level node.
5554 * Additionally, it can even happen that there are no top-level data nodes left,
5555 * all were unlinked, so in this case we pass NULL as the context node/data tree,
5556 * lyxp_eval() can handle this special situation.
5557 */
5558 if (ctx_node_type == LYXP_NODE_ELEM) {
5559 LOGINT;
5560 return -1;
5561 }
5562
5563 if (elem->prev == elem) {
5564 /* unlinking last top-level element, use an empty data tree */
5565 *ctx_node = NULL;
5566 } else {
5567 /* in this case just use the previous/last top-level data node */
5568 *ctx_node = elem->prev;
5569 }
5570 } else if (elem == *node) {
5571 /* We are going to unlink the currently processed node. This does not matter that
5572 * much, but we would lose access to the original data tree, so just move our
5573 * pointer somewhere still inside it.
5574 */
5575 if ((*node)->prev != *node) {
5576 *node = (*node)->prev;
5577 } else {
5578 /* the processed node with sibings were all unlinked, oh well */
5579 *node = NULL;
5580 }
5581 }
5582
5583 /* temporarily unlink the node */
5584 lyd_unlink(elem);
5585 if (*unlinked_nodes) {
5586 if (lyd_insert_after(*unlinked_nodes, elem)) {
5587 LOGINT;
5588 return -1;
5589 }
5590 } else {
5591 *unlinked_nodes = elem;
5592 }
5593
5594 if (snode->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_ANYDATA)) {
5595 /* there can be only one instance */
5596 break;
5597 }
5598 }
5599 }
5600 break;
5601 default:
5602 LOGINT;
5603 return -1;
5604 }
5605
5606 return EXIT_SUCCESS;
5607}
5608
5609/**
5610 * @brief Relink the unlinked nodes back.
5611 *
5612 * @param[in] node Data node to link the nodes back to. It can actually be the adjusted context node,
5613 * we simply need a sibling from the original data tree.
5614 * @param[in] unlinked_nodes Unlinked nodes to relink to \p node.
5615 * @param[in] ctx_node_type Context node type to distinguish between \p node being the parent
5616 * or the sibling of \p unlinked_nodes.
5617 *
5618 * @return EXIT_SUCCESS on success, -1 on error.
5619 */
5620static int
5621resolve_when_relink_nodes(struct lyd_node *node, struct lyd_node *unlinked_nodes, enum lyxp_node_type ctx_node_type)
5622{
5623 struct lyd_node *elem;
5624
5625 LY_TREE_FOR_SAFE(unlinked_nodes, unlinked_nodes, elem) {
5626 if (ctx_node_type == LYXP_NODE_ELEM) {
5627 if (lyd_insert(node, elem)) {
5628 return -1;
5629 }
5630 } else {
5631 if (lyd_insert_after(node, elem)) {
5632 return -1;
5633 }
5634 }
5635 }
5636
5637 return EXIT_SUCCESS;
5638}
5639
Radek Krejci03b71f72016-03-16 11:10:09 +01005640int
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005641resolve_applies_must(const struct lyd_node *node)
Radek Krejci01696bf2016-03-18 13:19:36 +01005642{
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005643 int ret = 0;
5644 uint8_t must_size;
5645 struct lys_node *schema, *iter;
Radek Krejci46165822016-08-26 14:06:27 +02005646
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005647 assert(node);
5648
5649 schema = node->schema;
5650
5651 /* their own must */
Radek Krejci46165822016-08-26 14:06:27 +02005652 switch (schema->nodetype) {
Radek Krejci01696bf2016-03-18 13:19:36 +01005653 case LYS_CONTAINER:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005654 must_size = ((struct lys_node_container *)schema)->must_size;
5655 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005656 case LYS_LEAF:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005657 must_size = ((struct lys_node_leaf *)schema)->must_size;
5658 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005659 case LYS_LEAFLIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005660 must_size = ((struct lys_node_leaflist *)schema)->must_size;
5661 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005662 case LYS_LIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005663 must_size = ((struct lys_node_list *)schema)->must_size;
5664 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005665 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02005666 case LYS_ANYDATA:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005667 must_size = ((struct lys_node_anydata *)schema)->must_size;
5668 break;
5669 case LYS_NOTIF:
5670 must_size = ((struct lys_node_notif *)schema)->must_size;
5671 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005672 default:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005673 must_size = 0;
5674 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005675 }
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005676
5677 if (must_size) {
5678 ++ret;
5679 }
5680
5681 /* schema may be a direct data child of input/output with must (but it must be first, it needs to be evaluated only once) */
5682 if (!node->prev->next) {
5683 for (iter = lys_parent(schema); iter && (iter->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES)); iter = lys_parent(iter));
5684 if (iter && (iter->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5685 ret += 0x2;
5686 }
5687 }
5688
5689 return ret;
Radek Krejci01696bf2016-03-18 13:19:36 +01005690}
5691
5692int
Radek Krejci46165822016-08-26 14:06:27 +02005693resolve_applies_when(const struct lys_node *schema, int mode, const struct lys_node *stop)
Radek Krejci03b71f72016-03-16 11:10:09 +01005694{
Radek Krejci46165822016-08-26 14:06:27 +02005695 const struct lys_node *parent;
Radek Krejci03b71f72016-03-16 11:10:09 +01005696
Radek Krejci46165822016-08-26 14:06:27 +02005697 assert(schema);
Radek Krejci03b71f72016-03-16 11:10:09 +01005698
Radek Krejci46165822016-08-26 14:06:27 +02005699 if (!(schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)schema)->when)) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005700 return 1;
5701 }
5702
Radek Krejci46165822016-08-26 14:06:27 +02005703 parent = schema;
Radek Krejci03b71f72016-03-16 11:10:09 +01005704 goto check_augment;
5705
Radek Krejci46165822016-08-26 14:06:27 +02005706 while (parent) {
5707 /* stop conditions */
5708 if (!mode) {
5709 /* stop on node that can be instantiated in data tree */
5710 if (!(parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
5711 break;
5712 }
5713 } else {
5714 /* stop on the specified node */
5715 if (parent == stop) {
5716 break;
5717 }
5718 }
5719
5720 if (((const struct lys_node_uses *)parent)->when) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005721 return 1;
5722 }
5723check_augment:
5724
5725 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) &&
Radek Krejci46165822016-08-26 14:06:27 +02005726 (((const struct lys_node_augment *)parent->parent)->when))) {
Michal Vaskoe3655562016-08-24 15:56:17 +02005727 return 1;
Radek Krejci03b71f72016-03-16 11:10:09 +01005728 }
5729 parent = lys_parent(parent);
5730 }
5731
5732 return 0;
5733}
5734
Michal Vaskocf024702015-10-08 15:01:42 +02005735/**
5736 * @brief Resolve (check) all when conditions relevant for \p node.
5737 * Logs directly.
5738 *
5739 * @param[in] node Data node, whose conditional reference, if such, is being decided.
Michal Vaskocf024702015-10-08 15:01:42 +02005740 *
Radek Krejci03b71f72016-03-16 11:10:09 +01005741 * @return
5742 * -1 - error, ly_errno is set
5743 * 0 - true "when" statement
Radek Krejci46165822016-08-26 14:06:27 +02005744 * 0, ly_vecode = LYVE_NOWHEN - false "when" statement
Radek Krejci03b71f72016-03-16 11:10:09 +01005745 * 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 +02005746 */
Radek Krejci46165822016-08-26 14:06:27 +02005747int
5748resolve_when(struct lyd_node *node, int *result)
Michal Vaskocf024702015-10-08 15:01:42 +02005749{
Michal Vasko76c3bd32016-08-24 16:02:52 +02005750 struct lyd_node *ctx_node = NULL, *unlinked_nodes, *tmp_node;
Michal Vasko90fc2a32016-08-24 15:58:58 +02005751 struct lys_node *sparent;
Michal Vaskocf024702015-10-08 15:01:42 +02005752 struct lyxp_set set;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005753 enum lyxp_node_type ctx_node_type;
Radek Krejci51093642016-03-29 10:14:59 +02005754 int rc = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02005755
5756 assert(node);
5757 memset(&set, 0, sizeof set);
5758
5759 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)node->schema)->when)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005760 /* make the node dummy for the evaluation */
5761 node->validity |= LYD_VAL_INUSE;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005762 rc = lyxp_eval(((struct lys_node_container *)node->schema)->when->cond, node, LYXP_NODE_ELEM, &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005763 node->validity &= ~LYD_VAL_INUSE;
Radek Krejci03b71f72016-03-16 11:10:09 +01005764 if (rc) {
5765 if (rc == 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005766 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005767 }
Radek Krejci51093642016-03-29 10:14:59 +02005768 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005769 }
5770
Radek Krejci03b71f72016-03-16 11:10:09 +01005771 /* set boolean result of the condition */
Michal Vasko944a5642016-03-21 11:48:58 +01005772 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02005773 if (!set.val.bool) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005774 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci0b7704f2016-03-18 12:16:14 +01005775 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02005776 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005777 }
Radek Krejci51093642016-03-29 10:14:59 +02005778
5779 /* free xpath set content */
5780 lyxp_set_cast(&set, LYXP_SET_EMPTY, node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005781 }
5782
Michal Vasko90fc2a32016-08-24 15:58:58 +02005783 sparent = node->schema;
Michal Vaskocf024702015-10-08 15:01:42 +02005784 goto check_augment;
5785
5786 /* check when in every schema node that affects node */
Michal Vasko90fc2a32016-08-24 15:58:58 +02005787 while (sparent && (sparent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
5788 if (((struct lys_node_uses *)sparent)->when) {
Michal Vaskocf024702015-10-08 15:01:42 +02005789 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005790 rc = resolve_when_ctx_node(node, sparent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02005791 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02005792 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02005793 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005794 }
5795 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02005796
5797 unlinked_nodes = NULL;
5798 /* we do not want our node pointer to change */
5799 tmp_node = node;
5800 rc = resolve_when_unlink_nodes(sparent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
5801 if (rc) {
5802 goto cleanup;
5803 }
5804
5805 rc = lyxp_eval(((struct lys_node_uses *)sparent)->when->cond, ctx_node, ctx_node_type, &set, LYXP_WHEN);
5806
5807 if (unlinked_nodes && ctx_node) {
5808 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
5809 rc = -1;
5810 goto cleanup;
5811 }
5812 }
5813
Radek Krejci03b71f72016-03-16 11:10:09 +01005814 if (rc) {
5815 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005816 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005817 }
Radek Krejci51093642016-03-29 10:14:59 +02005818 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005819 }
5820
Michal Vasko944a5642016-03-21 11:48:58 +01005821 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02005822 if (!set.val.bool) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005823 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Radek Krejci0b7704f2016-03-18 12:16:14 +01005824 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02005825 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005826 }
Radek Krejci51093642016-03-29 10:14:59 +02005827
5828 /* free xpath set content */
5829 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005830 }
5831
5832check_augment:
Michal Vasko90fc2a32016-08-24 15:58:58 +02005833 if ((sparent->parent && (sparent->parent->nodetype == LYS_AUGMENT) && (((struct lys_node_augment *)sparent->parent)->when))) {
Michal Vaskocf024702015-10-08 15:01:42 +02005834 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005835 rc = resolve_when_ctx_node(node, sparent->parent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02005836 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02005837 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02005838 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005839 }
5840 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02005841
5842 unlinked_nodes = NULL;
5843 tmp_node = node;
5844 rc = resolve_when_unlink_nodes(sparent->parent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
5845 if (rc) {
5846 goto cleanup;
5847 }
5848
5849 rc = lyxp_eval(((struct lys_node_augment *)sparent->parent)->when->cond, ctx_node, ctx_node_type, &set, LYXP_WHEN);
5850
5851 /* reconnect nodes, if ctx_node is NULL then all the nodes were unlinked, but linked together,
5852 * so the tree did not actually change and there is nothing for us to do
5853 */
5854 if (unlinked_nodes && ctx_node) {
5855 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
5856 rc = -1;
5857 goto cleanup;
5858 }
5859 }
5860
Radek Krejci03b71f72016-03-16 11:10:09 +01005861 if (rc) {
5862 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005863 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005864 }
Radek Krejci51093642016-03-29 10:14:59 +02005865 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005866 }
5867
Michal Vasko944a5642016-03-21 11:48:58 +01005868 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, LYXP_WHEN);
Michal Vaskocf024702015-10-08 15:01:42 +02005869
Michal Vasko8146d4c2016-05-09 15:50:29 +02005870 if (!set.val.bool) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005871 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Radek Krejci0b7704f2016-03-18 12:16:14 +01005872 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02005873 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005874 }
Radek Krejci51093642016-03-29 10:14:59 +02005875
5876 /* free xpath set content */
5877 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005878 }
5879
Michal Vasko90fc2a32016-08-24 15:58:58 +02005880 sparent = lys_parent(sparent);
Michal Vaskocf024702015-10-08 15:01:42 +02005881 }
5882
Radek Krejci0b7704f2016-03-18 12:16:14 +01005883 node->when_status |= LYD_WHEN_TRUE;
Radek Krejci03b71f72016-03-16 11:10:09 +01005884
Radek Krejci51093642016-03-29 10:14:59 +02005885cleanup:
Radek Krejci51093642016-03-29 10:14:59 +02005886 /* free xpath set content */
5887 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node ? ctx_node : node, 0);
5888
Radek Krejci46165822016-08-26 14:06:27 +02005889 if (result) {
5890 if (node->when_status & LYD_WHEN_TRUE) {
5891 *result = 1;
5892 } else {
5893 *result = 0;
5894 }
5895 }
5896
Radek Krejci51093642016-03-29 10:14:59 +02005897 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005898}
5899
Radek Krejcicbb473e2016-09-16 14:48:32 +02005900static int
5901check_leafref_features(struct lys_type *type)
5902{
5903 struct lys_node *iter;
5904 struct ly_set *src_parents, *trg_parents, *features;
5905 unsigned int i, j, size, x;
5906 int ret = EXIT_SUCCESS;
5907
5908 assert(type->parent);
5909
5910 src_parents = ly_set_new();
5911 trg_parents = ly_set_new();
5912 features = ly_set_new();
5913
5914 /* get parents chain of source (leafref) */
5915 for (iter = (struct lys_node *)type->parent; iter; iter = iter->parent) {
5916 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
5917 continue;
5918 }
5919 ly_set_add(src_parents, iter, LY_SET_OPT_USEASLIST);
5920 }
5921 /* get parents chain of target */
5922 for (iter = (struct lys_node *)type->info.lref.target; iter; iter = iter->parent) {
5923 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
5924 continue;
5925 }
5926 ly_set_add(trg_parents, iter, LY_SET_OPT_USEASLIST);
5927 }
5928
5929 /* compare the features used in if-feature statements in the rest of both
5930 * chains of parents. The set of features used for target must be a subset
5931 * of features used for the leafref. This is not a perfect, we should compare
5932 * the truth tables but it could require too much resources, so we simplify that */
5933 for (i = 0; i < src_parents->number; i++) {
5934 iter = src_parents->set.s[i]; /* shortcut */
5935 if (!iter->iffeature_size) {
5936 continue;
5937 }
5938 for (j = 0; j < iter->iffeature_size; j++) {
5939 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
5940 for (; size; size--) {
5941 if (!iter->iffeature[j].features[size - 1]) {
5942 /* not yet resolved feature, postpone this check */
5943 ret = EXIT_FAILURE;
5944 goto cleanup;
5945 }
5946 ly_set_add(features, iter->iffeature[j].features[size - 1], 0);
5947 }
5948 }
5949 }
5950 x = features->number;
5951 for (i = 0; i < trg_parents->number; i++) {
5952 iter = trg_parents->set.s[i]; /* shortcut */
5953 if (!iter->iffeature_size) {
5954 continue;
5955 }
5956 for (j = 0; j < iter->iffeature_size; j++) {
5957 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
5958 for (; size; size--) {
5959 if (!iter->iffeature[j].features[size - 1]) {
5960 /* not yet resolved feature, postpone this check */
5961 ret = EXIT_FAILURE;
5962 goto cleanup;
5963 }
5964 if ((unsigned int)ly_set_add(features, iter->iffeature[j].features[size - 1], 0) >= x) {
5965 /* the feature is not present in features set of target's parents chain */
5966 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, type->parent, "leafref", type->info.lref.path);
5967 LOGVAL(LYE_SPEC, LY_VLOG_LYS, type->parent,
5968 "Leafref is not conditional based on \"%s\" feature as its target.",
5969 iter->iffeature[j].features[size - 1]->name);
5970 ret = -1;
5971 goto cleanup;
5972 }
5973 }
5974 }
5975 }
5976
5977cleanup:
5978 ly_set_free(features);
5979 ly_set_free(src_parents);
5980 ly_set_free(trg_parents);
5981
5982 return ret;
5983}
5984
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005985/**
Michal Vaskobb211122015-08-19 14:03:11 +02005986 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005987 *
5988 * @param[in] mod Main module.
5989 * @param[in] item Item to resolve. Type determined by \p type.
5990 * @param[in] type Type of the unresolved item.
5991 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02005992 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005993 *
5994 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
5995 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005996static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02005997resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Radek Krejci48464ed2016-03-17 15:44:09 +01005998 struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005999{
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006000 /* has_str - whether the str_snode is a string in a dictionary that needs to be freed */
Radek Krejcic79c6b12016-07-26 15:11:49 +02006001 int rc = -1, has_str = 0, tpdf_flag = 0, i, k;
6002 unsigned int j;
Radek Krejcic13db382016-08-16 10:52:42 +02006003 struct lys_node *node, *par_grp;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006004 const char *expr;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006005
Radek Krejcic79c6b12016-07-26 15:11:49 +02006006 struct ly_set *refs, *procs;
6007 struct lys_feature *ref, *feat;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006008 struct lys_ident *ident;
6009 struct lys_type *stype;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006010 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01006011 struct lyxml_elem *yin;
Pavol Vicana0e4e672016-02-24 12:20:04 +01006012 struct yang_type *yang;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006013 struct unres_list_uniq *unique_info;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006014 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006015
6016 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006017 case UNRES_IDENT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006018 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006019 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006020 ident = item;
6021
Radek Krejci018f1f52016-08-03 16:01:20 +02006022 rc = resolve_base_ident(mod, ident, expr, "identity", NULL, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006023 break;
6024 case UNRES_TYPE_IDENTREF:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006025 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006026 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006027 stype = item;
6028
Radek Krejci018f1f52016-08-03 16:01:20 +02006029 rc = resolve_base_ident(mod, NULL, expr, "type", stype, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006030 break;
6031 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02006032 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006033 stype = item;
6034
Radek Krejci2f12f852016-01-08 12:59:57 +01006035 /* HACK - when there is no parent, we are in top level typedef and in that
6036 * case, the path has to contain absolute path, so we let the resolve_path_arg_schema()
6037 * know it via tpdf_flag */
6038 if (!node) {
Radek Krejci4f78b532016-02-17 13:43:00 +01006039 tpdf_flag = 1;
Radek Krejci2f12f852016-01-08 12:59:57 +01006040 node = (struct lys_node *)stype->parent;
6041 }
6042
Radek Krejci27fe55e2016-09-13 17:13:35 +02006043 if (!lys_node_module(node)->implemented) {
6044 /* not implemented module, don't bother with resolving the leafref
6045 * if the module is set to be implemented, tha path will be resolved then */
6046 rc = 0;
6047 break;
6048 }
Radek Krejci48464ed2016-03-17 15:44:09 +01006049 rc = resolve_path_arg_schema(stype->info.lref.path, node, tpdf_flag,
Michal Vasko1e62a092015-12-01 12:27:20 +01006050 (const struct lys_node **)&stype->info.lref.target);
Michal Vasko01c6fd22016-05-20 11:43:05 +02006051 if (!tpdf_flag && !rc) {
6052 assert(stype->info.lref.target);
Radek Krejcicbb473e2016-09-16 14:48:32 +02006053 /* check if leafref and its target are under a common if-features */
6054 rc = check_leafref_features(stype);
6055 if (rc) {
6056 break;
6057 }
6058
Radek Krejci46c4cd72016-01-21 15:13:52 +01006059 /* store the backlink from leafref target */
Michal Vasko01c6fd22016-05-20 11:43:05 +02006060 if (lys_leaf_add_leafref_target(stype->info.lref.target, (struct lys_node *)stype->parent)) {
6061 rc = -1;
Radek Krejci46c4cd72016-01-21 15:13:52 +01006062 }
Radek Krejci46c4cd72016-01-21 15:13:52 +01006063 }
6064
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006065 break;
Radek Krejci3a5501d2016-07-18 22:03:34 +02006066 case UNRES_TYPE_DER_TPDF:
6067 tpdf_flag = 1;
6068 /* no break */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006069 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01006070 /* parent */
6071 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006072 stype = item;
6073
Michal Vasko88c29542015-11-27 14:57:53 +01006074 /* HACK type->der is temporarily unparsed type statement */
6075 yin = (struct lyxml_elem *)stype->der;
6076 stype->der = NULL;
6077
Pavol Vicana0e4e672016-02-24 12:20:04 +01006078 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6079 yang = (struct yang_type *)yin;
Radek Krejci3a5501d2016-07-18 22:03:34 +02006080 rc = yang_check_type(mod, node, yang, tpdf_flag, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006081
6082 if (rc) {
Pavol Vican8bd72e42016-08-29 09:53:05 +02006083 /* may try again later */
6084 stype->der = (struct lys_tpdf *)yang;
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006085 } else {
6086 /* we need to always be able to free this, it's safe only in this case */
Pavol Vican5f0316a2016-04-05 21:21:11 +02006087 lydict_remove(mod->ctx, yang->name);
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006088 free(yang);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006089 }
6090
Michal Vasko88c29542015-11-27 14:57:53 +01006091 } else {
Radek Krejci3a5501d2016-07-18 22:03:34 +02006092 rc = fill_yin_type(mod, node, yin, stype, tpdf_flag, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006093 if (!rc) {
6094 /* we need to always be able to free this, it's safe only in this case */
6095 lyxml_free(mod->ctx, yin);
6096 } else {
6097 /* may try again later, put all back how it was */
6098 stype->der = (struct lys_tpdf *)yin;
6099 }
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006100 }
Radek Krejcic13db382016-08-16 10:52:42 +02006101 if (rc == EXIT_SUCCESS) {
Radek Krejci2c2fce82016-08-01 13:52:26 +02006102 /* it does not make sense to have leaf-list of empty type */
6103 if (!tpdf_flag && node->nodetype == LYS_LEAFLIST && stype->base == LY_TYPE_EMPTY) {
6104 LOGWRN("The leaf-list \"%s\" is of \"empty\" type, which does not make sense.", node->name);
6105 }
Radek Krejci9b6aad22016-09-20 15:55:51 +02006106 } else if (rc == EXIT_FAILURE && stype->base != LY_TYPE_ERR) {
Radek Krejcic13db382016-08-16 10:52:42 +02006107 /* forward reference - in case the type is in grouping, we have to make the grouping unusable
6108 * by uses statement until the type is resolved. We do that the same way as uses statements inside
6109 * grouping - the grouping's nacm member (not used un grouping) is used to increase the number of
6110 * 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 +02006111 * 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 +02006112 * of the type's base member. */
6113 for (par_grp = node; par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
6114 if (par_grp) {
6115 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci9b6aad22016-09-20 15:55:51 +02006116 stype->base = LY_TYPE_ERR;
Radek Krejcic13db382016-08-16 10:52:42 +02006117 }
Radek Krejci2c2fce82016-08-01 13:52:26 +02006118 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006119 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006120 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006121 iff_data = str_snode;
6122 rc = resolve_feature(iff_data->fname, strlen(iff_data->fname), iff_data->node, item);
Radek Krejci9ff0a922016-07-14 13:08:05 +02006123 if (!rc) {
6124 /* success */
Radek Krejci9de2c042016-10-19 16:53:06 +02006125 if (iff_data->infeature) {
6126 /* store backlink into the target feature to allow reverse changes in case of changing feature status */
6127 feat = *((struct lys_feature **)item);
6128 if (!feat->depfeatures) {
6129 feat->depfeatures = ly_set_new();
6130 }
Radek Krejci85a54be2016-10-20 12:39:56 +02006131 ly_set_add(feat->depfeatures, iff_data->node, LY_SET_OPT_USEASLIST);
Radek Krejci9de2c042016-10-19 16:53:06 +02006132 }
6133 /* cleanup temporary data */
Radek Krejcicbb473e2016-09-16 14:48:32 +02006134 lydict_remove(mod->ctx, iff_data->fname);
6135 free(iff_data);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006136 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006137 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006138 case UNRES_FEATURE:
6139 feat = (struct lys_feature *)item;
6140
6141 if (feat->iffeature_size) {
6142 refs = ly_set_new();
6143 procs = ly_set_new();
6144 ly_set_add(procs, feat, 0);
6145
6146 while (procs->number) {
6147 ref = procs->set.g[procs->number - 1];
6148 ly_set_rm_index(procs, procs->number - 1);
6149
6150 for (i = 0; i < ref->iffeature_size; i++) {
6151 resolve_iffeature_getsizes(&ref->iffeature[i], NULL, &j);
6152 for (; j > 0 ; j--) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006153 if (ref->iffeature[i].features[j - 1]) {
Radek Krejcic79c6b12016-07-26 15:11:49 +02006154 if (ref->iffeature[i].features[j - 1] == feat) {
6155 LOGVAL(LYE_CIRC_FEATURES, LY_VLOG_NONE, NULL, feat->name);
6156 goto featurecheckdone;
6157 }
6158
6159 if (ref->iffeature[i].features[j - 1]->iffeature_size) {
6160 k = refs->number;
6161 if (ly_set_add(refs, ref->iffeature[i].features[j - 1], 0) == k) {
6162 /* not yet seen feature, add it for processing */
6163 ly_set_add(procs, ref->iffeature[i].features[j - 1], 0);
6164 }
6165 }
6166 } else {
6167 /* forward reference */
6168 rc = EXIT_FAILURE;
6169 goto featurecheckdone;
6170 }
6171 }
6172
6173 }
6174 }
6175 rc = EXIT_SUCCESS;
6176
6177featurecheckdone:
6178 ly_set_free(refs);
6179 ly_set_free(procs);
6180 }
6181
6182 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006183 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006184 rc = resolve_unres_schema_uses(item, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006185 break;
6186 case UNRES_TYPE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006187 stype = item;
6188
Radek Krejci51673202016-11-01 17:00:32 +01006189 rc = check_default(stype, (const char **)str_snode, mod);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006190 break;
6191 case UNRES_CHOICE_DFLT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006192 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006193 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006194 choic = item;
6195
Radek Krejcie00d2312016-08-12 15:27:49 +02006196 if (!choic->dflt) {
6197 choic->dflt = resolve_choice_dflt(choic, expr);
6198 }
Michal Vasko7955b362015-09-04 14:18:15 +02006199 if (choic->dflt) {
Radek Krejcie00d2312016-08-12 15:27:49 +02006200 rc = lyp_check_mandatory_choice((struct lys_node *)choic);
Michal Vasko7955b362015-09-04 14:18:15 +02006201 } else {
6202 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006203 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006204 break;
6205 case UNRES_LIST_KEYS:
Radek Krejci5c08a992016-11-02 13:30:04 +01006206 rc = resolve_list_keys(item, ((struct lys_node_list *)item)->keys_str);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006207 break;
6208 case UNRES_LIST_UNIQ:
Radek Krejcid09d1a52016-08-11 14:05:45 +02006209 unique_info = (struct unres_list_uniq *)item;
6210 rc = resolve_unique(unique_info->list, unique_info->expr, unique_info->trg_type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006211 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006212 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006213 rc = resolve_augment(item, NULL);
Michal Vasko7178e692016-02-12 15:58:05 +01006214 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006215 case UNRES_XPATH:
6216 node = (struct lys_node *)item;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02006217 rc = lys_check_xpath(node, 1);
Michal Vasko508a50d2016-09-07 14:50:33 +02006218 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006219 default:
6220 LOGINT;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006221 break;
6222 }
6223
Radek Krejci54081ce2016-08-12 15:21:47 +02006224 if (has_str && !rc) {
6225 /* the string is no more needed in case of success.
6226 * In case of forward reference, we will try to resolve the string later */
Radek Krejci4f78b532016-02-17 13:43:00 +01006227 lydict_remove(mod->ctx, str_snode);
6228 }
6229
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006230 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006231}
6232
Michal Vaskof02e3742015-08-05 16:27:02 +02006233/* logs directly */
6234static void
Radek Krejci48464ed2016-03-17 15:44:09 +01006235print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006236{
Michal Vaskocb34dc62016-05-20 14:38:37 +02006237 struct lyxml_elem *xml;
6238 struct lyxml_attr *attr;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006239 struct unres_iffeat_data *iff_data;
Radek Krejci76e15e12016-06-22 11:02:24 +02006240 const char *type_name = NULL;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006241
Michal Vaskof02e3742015-08-05 16:27:02 +02006242 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02006243 case UNRES_IDENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006244 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identity", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006245 break;
6246 case UNRES_TYPE_IDENTREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006247 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identityref", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006248 break;
6249 case UNRES_TYPE_LEAFREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006250 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "leafref",
6251 ((struct lys_type *)item)->info.lref.path);
Michal Vaskof02e3742015-08-05 16:27:02 +02006252 break;
Radek Krejci3a5501d2016-07-18 22:03:34 +02006253 case UNRES_TYPE_DER_TPDF:
Michal Vaskof02e3742015-08-05 16:27:02 +02006254 case UNRES_TYPE_DER:
Michal Vaskocb34dc62016-05-20 14:38:37 +02006255 xml = (struct lyxml_elem *)((struct lys_type *)item)->der;
6256 if (xml->flags & LY_YANG_STRUCTURE_FLAG) {
6257 type_name = ((struct yang_type *)xml)->name;
6258 } else {
6259 LY_TREE_FOR(xml->attr, attr) {
6260 if ((attr->type == LYXML_ATTR_STD) && !strcmp(attr->name, "name")) {
6261 type_name = attr->value;
6262 break;
6263 }
6264 }
6265 assert(attr);
6266 }
6267 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "derived type", type_name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006268 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006269 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006270 iff_data = str_node;
6271 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "if-feature", iff_data->fname);
Michal Vaskof02e3742015-08-05 16:27:02 +02006272 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006273 case UNRES_FEATURE:
6274 LOGVRB("There are unresolved if-features for \"%s\" feature circular dependency check, it will be attempted later",
6275 ((struct lys_feature *)item)->name);
6276 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006277 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006278 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "uses", ((struct lys_node_uses *)item)->name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006279 break;
6280 case UNRES_TYPE_DFLT:
Radek Krejci2e2de832016-10-13 16:12:26 +02006281 if (str_node) {
6282 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "type default", (char *)str_node);
6283 } /* else no default value in the type itself, but we are checking some restrictions against
6284 * possible default value of some base type. The failure is caused by not resolved base type,
6285 * so it was already reported */
Michal Vaskof02e3742015-08-05 16:27:02 +02006286 break;
6287 case UNRES_CHOICE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006288 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "choice default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006289 break;
6290 case UNRES_LIST_KEYS:
Radek Krejci48464ed2016-03-17 15:44:09 +01006291 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list keys", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006292 break;
6293 case UNRES_LIST_UNIQ:
Radek Krejci48464ed2016-03-17 15:44:09 +01006294 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list unique", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006295 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006296 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006297 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "augment target",
6298 ((struct lys_node_augment *)item)->target_name);
Michal Vasko7178e692016-02-12 15:58:05 +01006299 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006300 case UNRES_XPATH:
6301 LOGVRB("Resolving %s \"%s\" with the context node \"%s\" failed, it will be attempted later.", "XPath",
6302 (char *)str_node, ((struct lys_node *)item)->name);
6303 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006304 default:
6305 LOGINT;
Michal Vaskof02e3742015-08-05 16:27:02 +02006306 break;
6307 }
6308}
6309
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006310/**
Michal Vaskobb211122015-08-19 14:03:11 +02006311 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006312 *
6313 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006314 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006315 *
Michal Vasko92b8a382015-08-19 14:03:49 +02006316 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006317 */
Michal Vaskof02e3742015-08-05 16:27:02 +02006318int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006319resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02006320{
Radek Krejci010e54b2016-03-15 09:40:34 +01006321 uint32_t i, resolved = 0, unres_count, res_count;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006322 int rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006323
6324 assert(unres);
6325
Michal Vaskoe8734262016-09-29 14:12:06 +02006326 LOGVRB("Resolving \"%s\" unresolved schema nodes and their constraints...", mod->name);
Radek Krejci010e54b2016-03-15 09:40:34 +01006327 ly_vlog_hide(1);
Michal Vasko51054ca2015-08-12 12:20:00 +02006328
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006329 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02006330 do {
Michal Vasko88c29542015-11-27 14:57:53 +01006331 unres_count = 0;
6332 res_count = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02006333
6334 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006335 /* UNRES_TYPE_LEAFREF must be resolved (for storing leafref target pointers);
Radek Krejcic79c6b12016-07-26 15:11:49 +02006336 * if-features are resolved here to make sure that we will have all if-features for
6337 * later check of feature circular dependency */
Radek Krejci018f1f52016-08-03 16:01:20 +02006338 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006339 continue;
6340 }
Radek Krejci018f1f52016-08-03 16:01:20 +02006341 /* processes UNRES_USES, UNRES_IFFEAT, UNRES_TYPE_DER, UNRES_TYPE_DER_TPDF, UNRES_TYPE_LEAFREF,
Radek Krejcie00d2312016-08-12 15:27:49 +02006342 * UNRES_CHOICE_DFLT and UNRES_IDENT */
Michal Vasko51054ca2015-08-12 12:20:00 +02006343
Michal Vasko88c29542015-11-27 14:57:53 +01006344 ++unres_count;
Radek Krejci48464ed2016-03-17 15:44:09 +01006345 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006346 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006347 unres->type[i] = UNRES_RESOLVED;
6348 ++resolved;
Michal Vasko88c29542015-11-27 14:57:53 +01006349 ++res_count;
Michal Vasko89e15322015-08-17 15:46:55 +02006350 } else if (rc == -1) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006351 ly_vlog_hide(0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02006352 /* print the error */
6353 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006354 return -1;
Radek Krejcic2a180f2016-06-22 13:28:16 +02006355 } else {
6356 /* forward reference, erase ly_errno */
Radek Krejci00a0e712016-10-26 10:24:46 +02006357 ly_err_clean(1);
Michal Vasko51054ca2015-08-12 12:20:00 +02006358 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006359 }
Michal Vasko88c29542015-11-27 14:57:53 +01006360 } while (res_count && (res_count < unres_count));
Michal Vasko51054ca2015-08-12 12:20:00 +02006361
Michal Vasko88c29542015-11-27 14:57:53 +01006362 if (res_count < unres_count) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006363 /* just print the errors */
6364 ly_vlog_hide(0);
6365
6366 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006367 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006368 continue;
6369 }
6370 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
6371 }
Michal Vasko92b8a382015-08-19 14:03:49 +02006372 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006373 }
6374
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006375 /* the rest */
6376 for (i = 0; i < unres->count; ++i) {
6377 if (unres->type[i] == UNRES_RESOLVED) {
6378 continue;
6379 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02006380
Radek Krejci48464ed2016-03-17 15:44:09 +01006381 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01006382 if (rc == 0) {
Pavol Vican88e16c92016-09-07 15:41:50 +02006383 if (unres->type[i] == UNRES_LIST_UNIQ) {
6384 /* free the allocated structure */
6385 free(unres->item[i]);
6386 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006387 unres->type[i] = UNRES_RESOLVED;
6388 ++resolved;
6389 } else if (rc == -1) {
6390 ly_vlog_hide(0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02006391 /* print the error */
6392 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
6393 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006394 }
6395 }
6396
Radek Krejci010e54b2016-03-15 09:40:34 +01006397 ly_vlog_hide(0);
6398
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006399 if (resolved < unres->count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006400 /* try to resolve the unresolved nodes again, it will not resolve anything, but it will print
6401 * all the validation errors
6402 */
6403 for (i = 0; i < unres->count; ++i) {
6404 if (unres->type[i] == UNRES_RESOLVED) {
6405 continue;
6406 }
Radek Krejci48464ed2016-03-17 15:44:09 +01006407 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01006408 }
Michal Vasko92b8a382015-08-19 14:03:49 +02006409 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006410 }
6411
Michal Vaskoe8734262016-09-29 14:12:06 +02006412 LOGVRB("All \"%s\" schema nodes and constraints resolved.", mod->name);
Radek Krejcic071c542016-01-27 14:57:51 +01006413 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006414 return EXIT_SUCCESS;
6415}
6416
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006417/**
Michal Vaskobb211122015-08-19 14:03:11 +02006418 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006419 *
6420 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006421 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006422 * @param[in] item Item to resolve. Type determined by \p type.
6423 * @param[in] type Type of the unresolved item.
6424 * @param[in] str String argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006425 *
Michal Vasko3767fb22016-07-21 12:10:57 +02006426 * @return EXIT_SUCCESS on success, EXIT_FAILURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006427 */
6428int
Radek Krejci48464ed2016-03-17 15:44:09 +01006429unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
6430 const char *str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006431{
Radek Krejci54081ce2016-08-12 15:21:47 +02006432 int rc;
6433 const char *dictstr;
6434
6435 dictstr = lydict_insert(mod->ctx, str, 0);
6436 rc = unres_schema_add_node(mod, unres, item, type, (struct lys_node *)dictstr);
6437
6438 if (rc == -1) {
6439 lydict_remove(mod->ctx, dictstr);
6440 }
6441 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006442}
6443
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006444/**
Michal Vaskobb211122015-08-19 14:03:11 +02006445 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006446 *
6447 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006448 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006449 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01006450 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006451 * @param[in] snode Schema node argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006452 *
Michal Vasko3767fb22016-07-21 12:10:57 +02006453 * @return EXIT_SUCCESS on success, EXIT_FIALURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006454 */
6455int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006456unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Radek Krejci48464ed2016-03-17 15:44:09 +01006457 struct lys_node *snode)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006458{
Michal Vaskoef486d72016-09-27 12:10:44 +02006459 int rc, log_hidden;
Michal Vasko88c29542015-11-27 14:57:53 +01006460 struct lyxml_elem *yin;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006461
Michal Vasko9bf425b2015-10-22 11:42:03 +02006462 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
6463 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006464
Michal Vaskoef486d72016-09-27 12:10:44 +02006465 if (*ly_vlog_hide_location()) {
6466 log_hidden = 1;
6467 } else {
6468 log_hidden = 0;
6469 ly_vlog_hide(1);
6470 }
Radek Krejci48464ed2016-03-17 15:44:09 +01006471 rc = resolve_unres_schema_item(mod, item, type, snode, unres);
Michal Vaskoef486d72016-09-27 12:10:44 +02006472 if (!log_hidden) {
6473 ly_vlog_hide(0);
6474 }
6475
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006476 if (rc != EXIT_FAILURE) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006477 if (rc == -1 && ly_errno == LY_EVALID) {
Radek Krejci2467a492016-10-24 15:16:59 +02006478 ly_err_repeat();
Radek Krejci010e54b2016-03-15 09:40:34 +01006479 }
Radek Krejcid09d1a52016-08-11 14:05:45 +02006480 if (type == UNRES_LIST_UNIQ) {
6481 /* free the allocated structure */
6482 free(item);
Pavol Vican88e16c92016-09-07 15:41:50 +02006483 } else if (rc == -1 && type == UNRES_IFFEAT) {
6484 /* free the allocated resources */
6485 free(*((char **)item));
6486 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006487 return rc;
Radek Krejcif347abc2016-06-22 10:18:47 +02006488 } else {
6489 /* erase info about validation errors */
Radek Krejci00a0e712016-10-26 10:24:46 +02006490 ly_err_clean(1);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006491 }
6492
Radek Krejci48464ed2016-03-17 15:44:09 +01006493 print_unres_schema_item_fail(item, type, snode);
Michal Vaskof02e3742015-08-05 16:27:02 +02006494
Michal Vasko88c29542015-11-27 14:57:53 +01006495 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
Radek Krejci3a5501d2016-07-18 22:03:34 +02006496 if (type == UNRES_TYPE_DER || type == UNRES_TYPE_DER_TPDF) {
Michal Vasko88c29542015-11-27 14:57:53 +01006497 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
Pavol Vicana0e4e672016-02-24 12:20:04 +01006498 if (!(yin->flags & LY_YANG_STRUCTURE_FLAG)) {
6499 lyxml_unlink_elem(mod->ctx, yin, 1);
6500 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
6501 }
Michal Vasko88c29542015-11-27 14:57:53 +01006502 }
6503
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006504 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01006505 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
6506 if (!unres->item) {
6507 LOGMEM;
6508 return -1;
6509 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006510 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01006511 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
6512 if (!unres->type) {
6513 LOGMEM;
6514 return -1;
6515 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006516 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01006517 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
6518 if (!unres->str_snode) {
6519 LOGMEM;
6520 return -1;
6521 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006522 unres->str_snode[unres->count-1] = snode;
Radek Krejcic071c542016-01-27 14:57:51 +01006523 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
6524 if (!unres->module) {
6525 LOGMEM;
6526 return -1;
6527 }
6528 unres->module[unres->count-1] = mod;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006529
Michal Vasko3767fb22016-07-21 12:10:57 +02006530 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006531}
6532
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006533/**
Michal Vaskobb211122015-08-19 14:03:11 +02006534 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006535 *
6536 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006537 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006538 * @param[in] item Old item to be resolved.
6539 * @param[in] type Type of the old unresolved item.
6540 * @param[in] new_item New item to use in the duplicate.
6541 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02006542 * @return EXIT_SUCCESS on success, EXIT_FAILURE if item is not in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006543 */
Michal Vaskodad19402015-08-06 09:51:53 +02006544int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006545unres_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 +02006546{
6547 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006548 struct unres_list_uniq aux_uniq;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006549 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006550
Michal Vaskocf024702015-10-08 15:01:42 +02006551 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006552
Radek Krejcid09d1a52016-08-11 14:05:45 +02006553 /* hack for UNRES_LIST_UNIQ, which stores multiple items behind its item */
6554 if (type == UNRES_LIST_UNIQ) {
6555 aux_uniq.list = item;
6556 aux_uniq.expr = ((struct unres_list_uniq *)new_item)->expr;
6557 item = &aux_uniq;
6558 }
Michal Vasko878e38d2016-09-05 12:17:53 +02006559 i = unres_schema_find(unres, -1, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006560
6561 if (i == -1) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006562 if (type == UNRES_LIST_UNIQ) {
6563 free(new_item);
6564 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02006565 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006566 }
6567
Radek Krejcic79c6b12016-07-26 15:11:49 +02006568 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT) ||
Radek Krejcib69f3232016-09-16 17:41:07 +02006569 (type == UNRES_FEATURE) || (type == UNRES_LIST_UNIQ)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01006570 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006571 LOGINT;
6572 return -1;
6573 }
Radek Krejcicbb473e2016-09-16 14:48:32 +02006574 } else if (type == UNRES_IFFEAT) {
6575 /* duplicate unres_iffeature_data */
6576 iff_data = malloc(sizeof *iff_data);
6577 iff_data->fname = lydict_insert(mod->ctx, ((struct unres_iffeat_data *)unres->str_snode[i])->fname, 0);
6578 iff_data->node = ((struct unres_iffeat_data *)unres->str_snode[i])->node;
6579 if (unres_schema_add_node(mod, unres, new_item, type, (struct lys_node *)iff_data) == -1) {
6580 LOGINT;
6581 return -1;
6582 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006583 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01006584 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006585 LOGINT;
6586 return -1;
6587 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006588 }
Michal Vaskodad19402015-08-06 09:51:53 +02006589
6590 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006591}
6592
Michal Vaskof02e3742015-08-05 16:27:02 +02006593/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006594int
Michal Vasko878e38d2016-09-05 12:17:53 +02006595unres_schema_find(struct unres_schema *unres, int start_on_backwards, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006596{
Michal Vasko878e38d2016-09-05 12:17:53 +02006597 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006598 struct unres_list_uniq *aux_uniq1, *aux_uniq2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006599
Michal Vasko878e38d2016-09-05 12:17:53 +02006600 if (start_on_backwards > 0) {
6601 i = start_on_backwards;
6602 } else {
6603 i = unres->count - 1;
6604 }
6605 for (; i > -1; i--) {
6606 if (unres->type[i] != type) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006607 continue;
6608 }
6609 if (type != UNRES_LIST_UNIQ) {
Michal Vasko878e38d2016-09-05 12:17:53 +02006610 if (unres->item[i] == item) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006611 break;
6612 }
6613 } else {
6614 aux_uniq1 = (struct unres_list_uniq *)unres->item[i - 1];
6615 aux_uniq2 = (struct unres_list_uniq *)item;
6616 if ((aux_uniq1->list == aux_uniq2->list) && ly_strequal(aux_uniq1->expr, aux_uniq2->expr, 0)) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006617 break;
6618 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006619 }
6620 }
6621
Michal Vasko878e38d2016-09-05 12:17:53 +02006622 return i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006623}
Michal Vasko8bcdf292015-08-19 14:04:43 +02006624
Michal Vaskoede9c472016-06-07 09:38:15 +02006625static void
6626unres_schema_free_item(struct ly_ctx *ctx, struct unres_schema *unres, uint32_t i)
6627{
6628 struct lyxml_elem *yin;
6629 struct yang_type *yang;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006630 struct unres_iffeat_data *iff_data;
Michal Vaskoede9c472016-06-07 09:38:15 +02006631
6632 switch (unres->type[i]) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02006633 case UNRES_TYPE_DER_TPDF:
Michal Vaskoede9c472016-06-07 09:38:15 +02006634 case UNRES_TYPE_DER:
6635 yin = (struct lyxml_elem *)((struct lys_type *)unres->item[i])->der;
6636 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6637 yang =(struct yang_type *)yin;
6638 yang->type->base = yang->base;
6639 lydict_remove(ctx, yang->name);
6640 free(yang);
6641 } else {
6642 lyxml_free(ctx, yin);
6643 }
6644 break;
Pavol Vican88e16c92016-09-07 15:41:50 +02006645 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006646 iff_data = (struct unres_iffeat_data *)unres->str_snode[i];
6647 lydict_remove(ctx, iff_data->fname);
6648 free(unres->str_snode[i]);
Pavol Vican88e16c92016-09-07 15:41:50 +02006649 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02006650 case UNRES_IDENT:
6651 case UNRES_TYPE_IDENTREF:
Michal Vaskoede9c472016-06-07 09:38:15 +02006652 case UNRES_CHOICE_DFLT:
6653 case UNRES_LIST_KEYS:
Michal Vaskoede9c472016-06-07 09:38:15 +02006654 lydict_remove(ctx, (const char *)unres->str_snode[i]);
6655 break;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006656 case UNRES_LIST_UNIQ:
6657 free(unres->item[i]);
6658 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02006659 default:
6660 break;
6661 }
6662 unres->type[i] = UNRES_RESOLVED;
6663}
6664
Michal Vasko88c29542015-11-27 14:57:53 +01006665void
Radek Krejcic071c542016-01-27 14:57:51 +01006666unres_schema_free(struct lys_module *module, struct unres_schema **unres)
Michal Vasko88c29542015-11-27 14:57:53 +01006667{
6668 uint32_t i;
Radek Krejcic071c542016-01-27 14:57:51 +01006669 unsigned int unresolved = 0;
Michal Vasko88c29542015-11-27 14:57:53 +01006670
Radek Krejcic071c542016-01-27 14:57:51 +01006671 if (!unres || !(*unres)) {
6672 return;
Michal Vasko88c29542015-11-27 14:57:53 +01006673 }
6674
Radek Krejcic071c542016-01-27 14:57:51 +01006675 assert(module || (*unres)->count == 0);
6676
6677 for (i = 0; i < (*unres)->count; ++i) {
6678 if ((*unres)->module[i] != module) {
6679 if ((*unres)->type[i] != UNRES_RESOLVED) {
6680 unresolved++;
6681 }
6682 continue;
6683 }
Michal Vaskoede9c472016-06-07 09:38:15 +02006684
6685 /* free heap memory for the specific item */
6686 unres_schema_free_item(module->ctx, *unres, i);
Radek Krejcic071c542016-01-27 14:57:51 +01006687 }
6688
Michal Vaskoede9c472016-06-07 09:38:15 +02006689 /* free it all */
Radek Krejcic071c542016-01-27 14:57:51 +01006690 if (!module || (!unresolved && !module->type)) {
6691 free((*unres)->item);
6692 free((*unres)->type);
6693 free((*unres)->str_snode);
6694 free((*unres)->module);
Radek Krejcic071c542016-01-27 14:57:51 +01006695 free((*unres));
6696 (*unres) = NULL;
6697 }
Michal Vasko88c29542015-11-27 14:57:53 +01006698}
6699
Radek Krejci1899d6a2016-11-03 13:48:07 +01006700int
Radek Krejci9b6aad22016-09-20 15:55:51 +02006701resolve_leafref(struct lyd_node_leaf_list *leaf, struct lys_type *type)
Radek Krejci7de36cf2016-09-12 16:18:50 +02006702{
Radek Krejci7de36cf2016-09-12 16:18:50 +02006703 struct unres_data matches;
6704 uint32_t i;
6705
Radek Krejci9b6aad22016-09-20 15:55:51 +02006706 assert(type->base == LY_TYPE_LEAFREF);
6707
6708 /* init */
Radek Krejci7de36cf2016-09-12 16:18:50 +02006709 memset(&matches, 0, sizeof matches);
Radek Krejci7de36cf2016-09-12 16:18:50 +02006710
6711 /* EXIT_FAILURE return keeps leaf->value.lefref NULL, handled later */
Radek Krejci9b6aad22016-09-20 15:55:51 +02006712 if (resolve_path_arg_data((struct lyd_node *)leaf, type->info.lref.path, &matches) == -1) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02006713 return -1;
6714 }
6715
6716 /* check that value matches */
6717 for (i = 0; i < matches.count; ++i) {
Radek Krejci1899d6a2016-11-03 13:48:07 +01006718 /* not that the value is already in canonical form since the parsers does the conversion,
6719 * so we can simply compare just the values */
Radek Krejci7de36cf2016-09-12 16:18:50 +02006720 if (ly_strequal(leaf->value_str, ((struct lyd_node_leaf_list *)matches.node[i])->value_str, 1)) {
Radek Krejci1899d6a2016-11-03 13:48:07 +01006721 /* we have the match */
Radek Krejci7de36cf2016-09-12 16:18:50 +02006722 leaf->value.leafref = matches.node[i];
6723 break;
6724 }
6725 }
6726
6727 free(matches.node);
6728
6729 if (!leaf->value.leafref) {
6730 /* reference not found */
6731 if (type->info.lref.req > -1) {
6732 LOGVAL(LYE_NOLEAFREF, LY_VLOG_LYD, leaf, type->info.lref.path, leaf->value_str);
6733 return EXIT_FAILURE;
6734 } else {
6735 LOGVRB("There is no leafref with the value \"%s\", but it is not required.", leaf->value_str);
6736 }
6737 }
6738
6739 return EXIT_SUCCESS;
6740}
6741
Radek Krejci9ad23f42016-10-31 15:46:52 +01006742API const struct lys_type *
Radek Krejci1899d6a2016-11-03 13:48:07 +01006743lyd_leaf_type(struct lyd_node_leaf_list *leaf, int resolve)
Radek Krejci9b6aad22016-09-20 15:55:51 +02006744{
Radek Krejci9b6aad22016-09-20 15:55:51 +02006745 if (!leaf || !(leaf->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Radek Krejci9ad23f42016-10-31 15:46:52 +01006746 return NULL;
Radek Krejci9b6aad22016-09-20 15:55:51 +02006747 }
Radek Krejci1899d6a2016-11-03 13:48:07 +01006748 if (((struct lys_node_leaf *)leaf->schema)->type.base == LY_TYPE_BITS) {
6749 free(leaf->value.bit);
Radek Krejci9b6aad22016-09-20 15:55:51 +02006750 }
Radek Krejci1899d6a2016-11-03 13:48:07 +01006751 memset(&leaf->value, 0, sizeof leaf->value);
Radek Krejci9b6aad22016-09-20 15:55:51 +02006752
Radek Krejci1899d6a2016-11-03 13:48:07 +01006753 /* resolve */
6754 return lyp_parse_value(&((struct lys_node_leaf *)leaf->schema)->type, (const char **)&leaf->value_str, NULL,
6755 (struct lyd_node *)leaf, resolve ? leaf : NULL, 1, 0);
Radek Krejci9b6aad22016-09-20 15:55:51 +02006756}
6757
6758static int
6759resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type)
6760{
6761 struct lys_type *datatype = NULL;
Radek Krejci9b6aad22016-09-20 15:55:51 +02006762
6763 assert(type->base == LY_TYPE_UNION);
6764
6765 memset(&leaf->value, 0, sizeof leaf->value);
Radek Krejci1899d6a2016-11-03 13:48:07 +01006766 datatype = lyp_parse_value(type, &leaf->value_str, NULL, (struct lyd_node *)leaf, leaf, 1, 0);
Radek Krejci9b6aad22016-09-20 15:55:51 +02006767 if (!datatype) {
6768 /* failure */
6769 LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, (leaf->value_str ? leaf->value_str : ""), leaf->schema->name);
6770 return EXIT_FAILURE;
6771 }
6772
6773 return EXIT_SUCCESS;
6774}
6775
Michal Vasko8bcdf292015-08-19 14:04:43 +02006776/**
6777 * @brief Resolve a single unres data item. Logs directly.
6778 *
Michal Vaskocf024702015-10-08 15:01:42 +02006779 * @param[in] node Data node to resolve.
Michal Vaskocf024702015-10-08 15:01:42 +02006780 * @param[in] type Type of the unresolved item.
Michal Vasko8bcdf292015-08-19 14:04:43 +02006781 *
6782 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
6783 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02006784int
Radek Krejci48464ed2016-03-17 15:44:09 +01006785resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02006786{
Michal Vasko0491ab32015-08-19 14:28:29 +02006787 int rc;
Michal Vasko83a6c462015-10-08 16:43:53 +02006788 struct lyd_node_leaf_list *leaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006789 struct lys_node_leaf *sleaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006790
Michal Vasko83a6c462015-10-08 16:43:53 +02006791 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02006792 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006793
Michal Vaskocf024702015-10-08 15:01:42 +02006794 switch (type) {
6795 case UNRES_LEAFREF:
6796 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Radek Krejci9b6aad22016-09-20 15:55:51 +02006797 return resolve_leafref(leaf, &sleaf->type);
Michal Vasko8bcdf292015-08-19 14:04:43 +02006798
Michal Vaskocf024702015-10-08 15:01:42 +02006799 case UNRES_INSTID:
Radek Krejci7de36cf2016-09-12 16:18:50 +02006800 assert(sleaf->type.base == LY_TYPE_INST);
Radek Krejci00a0e712016-10-26 10:24:46 +02006801 ly_err_clean(1);
Radek Krejci48464ed2016-03-17 15:44:09 +01006802 leaf->value.instance = resolve_instid(node, leaf->value_str);
Radek Krejci40f17b92016-02-03 14:30:43 +01006803 if (!leaf->value.instance) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02006804 if (ly_errno) {
6805 return -1;
6806 } else if (sleaf->type.info.inst.req > -1) {
Michal Vasko6ac68282016-04-11 10:56:47 +02006807 LOGVAL(LYE_NOREQINS, LY_VLOG_LYD, leaf, leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02006808 return EXIT_FAILURE;
6809 } else {
Michal Vasko9925e282016-09-02 12:45:14 +02006810 LOGVRB("There is no instance identifier \"%s\", but it is not required.", leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02006811 }
6812 }
Michal Vaskocf024702015-10-08 15:01:42 +02006813 break;
6814
Radek Krejci7de36cf2016-09-12 16:18:50 +02006815 case UNRES_UNION:
6816 assert(sleaf->type.base == LY_TYPE_UNION);
Radek Krejci9b6aad22016-09-20 15:55:51 +02006817 return resolve_union(leaf, &sleaf->type);
Radek Krejci7de36cf2016-09-12 16:18:50 +02006818
Michal Vaskocf024702015-10-08 15:01:42 +02006819 case UNRES_WHEN:
Radek Krejci46165822016-08-26 14:06:27 +02006820 if ((rc = resolve_when(node, NULL))) {
Michal Vaskocf024702015-10-08 15:01:42 +02006821 return rc;
6822 }
6823 break;
6824
Michal Vaskobf19d252015-10-08 15:39:17 +02006825 case UNRES_MUST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006826 if ((rc = resolve_must(node, 0))) {
6827 return rc;
6828 }
6829 break;
6830
6831 case UNRES_MUST_INOUT:
6832 if ((rc = resolve_must(node, 1))) {
Michal Vaskobf19d252015-10-08 15:39:17 +02006833 return rc;
6834 }
6835 break;
6836
Michal Vaskocf024702015-10-08 15:01:42 +02006837 default:
Michal Vasko8bcdf292015-08-19 14:04:43 +02006838 LOGINT;
6839 return -1;
6840 }
6841
6842 return EXIT_SUCCESS;
6843}
6844
6845/**
Radek Krejci0b7704f2016-03-18 12:16:14 +01006846 * @brief add data unres item
Michal Vasko8bcdf292015-08-19 14:04:43 +02006847 *
6848 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02006849 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02006850 *
Radek Krejci0b7704f2016-03-18 12:16:14 +01006851 * @return 0 on success, -1 on error.
Michal Vasko8bcdf292015-08-19 14:04:43 +02006852 */
6853int
Radek Krejci0b7704f2016-03-18 12:16:14 +01006854unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02006855{
Radek Krejci03b71f72016-03-16 11:10:09 +01006856 assert(unres && node);
Michal Vaskoc4280842016-04-19 16:10:42 +02006857 assert((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)
Radek Krejcibacc7442016-10-27 13:39:56 +02006858 || (type == UNRES_MUST_INOUT) || (type == UNRES_UNION));
Michal Vasko8bcdf292015-08-19 14:04:43 +02006859
Radek Krejci03b71f72016-03-16 11:10:09 +01006860 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01006861 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
6862 if (!unres->node) {
6863 LOGMEM;
6864 return -1;
6865 }
Michal Vaskocf024702015-10-08 15:01:42 +02006866 unres->node[unres->count - 1] = node;
Michal Vasko253035f2015-12-17 16:58:13 +01006867 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
6868 if (!unres->type) {
6869 LOGMEM;
6870 return -1;
6871 }
Michal Vaskocf024702015-10-08 15:01:42 +02006872 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006873
Radek Krejci0b7704f2016-03-18 12:16:14 +01006874 if (type == UNRES_WHEN) {
6875 /* remove previous result */
6876 node->when_status = LYD_WHEN;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006877 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006878
6879 return EXIT_SUCCESS;
6880}
6881
6882/**
6883 * @brief Resolve every unres data item in the structure. Logs directly.
6884 *
Radek Krejci082c84f2016-10-17 16:33:06 +02006885 * If options includes LYD_OPT_TRUSTED, the data are considered trusted (when, must conditions are not expected,
6886 * unresolved leafrefs/instids are accepted).
6887 *
6888 * If options includes LYD_OPT_NOAUTODEL, the false resulting when condition on non-default nodes, the error is raised.
6889 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006890 * @param[in] unres Unres data structure to use.
Radek Krejci082c84f2016-10-17 16:33:06 +02006891 * @param[in,out] root Root node of the data tree, can be changed due to autodeletion.
6892 * @param[in] options Data options as described above.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006893 *
6894 * @return EXIT_SUCCESS on success, -1 on error.
6895 */
6896int
Radek Krejci082c84f2016-10-17 16:33:06 +02006897resolve_unres_data(struct unres_data *unres, struct lyd_node **root, int options)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006898{
Radek Krejci0c0086a2016-03-24 15:20:28 +01006899 uint32_t i, j, first = 1, resolved = 0, del_items = 0, when_stmt = 0;
Radek Krejci010e54b2016-03-15 09:40:34 +01006900 int rc, progress;
Radek Krejci0b7704f2016-03-18 12:16:14 +01006901 struct lyd_node *parent;
Radek Krejci7de36cf2016-09-12 16:18:50 +02006902 struct lyd_node_leaf_list *leaf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006903
Radek Krejci082c84f2016-10-17 16:33:06 +02006904 assert(root);
Radek Krejci03b71f72016-03-16 11:10:09 +01006905 assert(unres);
Radek Krejci03b71f72016-03-16 11:10:09 +01006906
6907 if (!unres->count) {
6908 return EXIT_SUCCESS;
6909 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006910
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02006911 LOGVRB("Resolving unresolved data nodes and their constraints...");
Radek Krejci010e54b2016-03-15 09:40:34 +01006912 ly_vlog_hide(1);
6913
Radek Krejci0b7704f2016-03-18 12:16:14 +01006914 /* when-stmt first */
Radek Krejci010e54b2016-03-15 09:40:34 +01006915 do {
Radek Krejci00a0e712016-10-26 10:24:46 +02006916 ly_err_clean(1);
Radek Krejci010e54b2016-03-15 09:40:34 +01006917 progress = 0;
Michal Vasko6df94132016-09-22 11:08:09 +02006918 for (i = 0; i < unres->count; i++) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006919 if (unres->type[i] != UNRES_WHEN) {
6920 continue;
6921 }
Radek Krejci082c84f2016-10-17 16:33:06 +02006922 assert(!(options & LYD_OPT_TRUSTED));
Radek Krejci0c0086a2016-03-24 15:20:28 +01006923 if (first) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006924 /* count when-stmt nodes in unres list */
6925 when_stmt++;
6926 }
6927
6928 /* resolve when condition only when all parent when conditions are already resolved */
6929 for (parent = unres->node[i]->parent;
6930 parent && LYD_WHEN_DONE(parent->when_status);
6931 parent = parent->parent) {
6932 if (!parent->parent && (parent->when_status & LYD_WHEN_FALSE)) {
6933 /* the parent node was already unlinked, do not resolve this node,
6934 * it will be removed anyway, so just mark it as resolved
6935 */
6936 unres->node[i]->when_status |= LYD_WHEN_FALSE;
6937 unres->type[i] = UNRES_RESOLVED;
6938 resolved++;
6939 break;
6940 }
6941 }
6942 if (parent) {
6943 continue;
6944 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006945
Radek Krejci48464ed2016-03-17 15:44:09 +01006946 rc = resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01006947 if (!rc) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006948 if (unres->node[i]->when_status & LYD_WHEN_FALSE) {
Radek Krejci082c84f2016-10-17 16:33:06 +02006949 if ((options & LYD_OPT_NOAUTODEL) && !unres->node[i]->dflt) {
Radek Krejci03b71f72016-03-16 11:10:09 +01006950 /* false when condition */
6951 ly_vlog_hide(0);
Radek Krejci2467a492016-10-24 15:16:59 +02006952 ly_err_repeat();
Radek Krejci03b71f72016-03-16 11:10:09 +01006953 return -1;
Radek Krejci0b7704f2016-03-18 12:16:14 +01006954 } /* follows else */
6955
Radek Krejci0c0086a2016-03-24 15:20:28 +01006956 /* only unlink now, the subtree can contain another nodes stored in the unres list */
6957 /* if it has parent non-presence containers that would be empty, we should actually
6958 * remove the container
6959 */
Radek Krejci2537fd32016-09-07 16:22:41 +02006960 for (parent = unres->node[i];
6961 parent->parent && parent->parent->schema->nodetype == LYS_CONTAINER;
6962 parent = parent->parent) {
6963 if (((struct lys_node_container *)parent->parent->schema)->presence) {
6964 /* presence container */
6965 break;
Radek Krejci0c0086a2016-03-24 15:20:28 +01006966 }
Radek Krejci2537fd32016-09-07 16:22:41 +02006967 if (parent->next || parent->prev != parent) {
6968 /* non empty (the child we are in and we are going to remove is not the only child) */
6969 break;
6970 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01006971 }
Radek Krejci2537fd32016-09-07 16:22:41 +02006972 unres->node[i] = parent;
Radek Krejci0c0086a2016-03-24 15:20:28 +01006973
Radek Krejci0b7704f2016-03-18 12:16:14 +01006974 /* auto-delete */
6975 LOGVRB("auto-delete node \"%s\" due to when condition (%s)", ly_errpath(),
6976 ((struct lys_node_leaf *)unres->node[i]->schema)->when->cond);
Radek Krejci0c0086a2016-03-24 15:20:28 +01006977 if (*root && *root == unres->node[i]) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006978 *root = (*root)->next;
Radek Krejci03b71f72016-03-16 11:10:09 +01006979 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01006980
Radek Krejci0b7704f2016-03-18 12:16:14 +01006981 lyd_unlink(unres->node[i]);
6982 unres->type[i] = UNRES_DELETE;
6983 del_items++;
Radek Krejci51fd8162016-03-24 15:49:51 +01006984
6985 /* update the rest of unres items */
6986 for (j = 0; j < unres->count; j++) {
Radek Krejci3db819b2016-03-24 16:29:48 +01006987 if (unres->type[j] == UNRES_RESOLVED || unres->type[j] == UNRES_DELETE) {
Radek Krejci51fd8162016-03-24 15:49:51 +01006988 continue;
6989 }
6990
6991 /* test if the node is in subtree to be deleted */
6992 for (parent = unres->node[j]; parent; parent = parent->parent) {
6993 if (parent == unres->node[i]) {
6994 /* yes, it is */
6995 unres->type[j] = UNRES_RESOLVED;
6996 resolved++;
6997 break;
6998 }
6999 }
7000 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007001 } else {
7002 unres->type[i] = UNRES_RESOLVED;
Radek Krejci03b71f72016-03-16 11:10:09 +01007003 }
Radek Krejci00a0e712016-10-26 10:24:46 +02007004 ly_err_clean(1);
Radek Krejci010e54b2016-03-15 09:40:34 +01007005 resolved++;
7006 progress = 1;
7007 } else if (rc == -1) {
7008 ly_vlog_hide(0);
Michal Vasko76e73402016-08-24 16:00:13 +02007009 /* print only this last error */
7010 resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01007011 return -1;
Radek Krejci2467a492016-10-24 15:16:59 +02007012 } /* else forward reference */
Radek Krejci010e54b2016-03-15 09:40:34 +01007013 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007014 first = 0;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007015 } while (progress && resolved < when_stmt);
Radek Krejci010e54b2016-03-15 09:40:34 +01007016
Radek Krejci0b7704f2016-03-18 12:16:14 +01007017 /* do we have some unresolved when-stmt? */
Radek Krejcid940d732016-03-24 16:02:28 +01007018 if (when_stmt > resolved) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007019 ly_vlog_hide(0);
Radek Krejci2467a492016-10-24 15:16:59 +02007020 ly_err_repeat();
Radek Krejci0b7704f2016-03-18 12:16:14 +01007021 return -1;
7022 }
7023
7024 for (i = 0; del_items && i < unres->count; i++) {
7025 /* we had some when-stmt resulted to false, so now we have to sanitize the unres list */
7026 if (unres->type[i] != UNRES_DELETE) {
7027 continue;
7028 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007029 if (!unres->node[i]) {
7030 unres->type[i] = UNRES_RESOLVED;
7031 del_items--;
7032 continue;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007033 }
7034
7035 /* really remove the complete subtree */
7036 lyd_free(unres->node[i]);
7037 unres->type[i] = UNRES_RESOLVED;
7038 del_items--;
7039 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007040
7041 /* rest */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007042 for (i = 0; i < unres->count; ++i) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007043 if (unres->type[i] == UNRES_RESOLVED) {
7044 continue;
7045 }
Radek Krejci082c84f2016-10-17 16:33:06 +02007046 assert(!(options & LYD_OPT_TRUSTED) || ((unres->type[i] != UNRES_MUST) && (unres->type[i] != UNRES_MUST_INOUT)));
Radek Krejci010e54b2016-03-15 09:40:34 +01007047
Radek Krejci48464ed2016-03-17 15:44:09 +01007048 rc = resolve_unres_data_item(unres->node[i], unres->type[i]);
Michal Vasko6df94132016-09-22 11:08:09 +02007049 if (rc == -1) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007050 ly_vlog_hide(0);
Michal Vasko96b846c2016-05-18 13:28:58 +02007051 /* print only this last error */
7052 resolve_unres_data_item(unres->node[i], unres->type[i]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007053 return -1;
Radek Krejci082c84f2016-10-17 16:33:06 +02007054 } else if ((rc == 0) || ((options & LYD_OPT_TRUSTED) && ((unres->type[i] == UNRES_LEAFREF) || (unres->type[i] == UNRES_INSTID)))) {
Michal Vasko6df94132016-09-22 11:08:09 +02007055 unres->type[i] = UNRES_RESOLVED;
7056 resolved++;
Radek Krejci082c84f2016-10-17 16:33:06 +02007057 if (options & LYD_OPT_TRUSTED) {
Michal Vasko6df94132016-09-22 11:08:09 +02007058 /* accept it in this case */
7059 if (unres->type[i] == UNRES_LEAFREF) {
7060 LOGVRB("Leafref \"%s\" with value \"%s\" failed to be resolved.",
7061 ((struct lys_node_leaf *)unres->node[i]->schema)->type.info.lref.path,
7062 ((struct lyd_node_leaf_list *)unres->node[i])->value_str);
7063 } else {
7064 LOGVRB("Instance identifier \"%s\" failed to be resolved.",
7065 ((struct lyd_node_leaf_list *)unres->node[i])->value_str);
7066 }
7067 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007068 }
7069 }
7070
Radek Krejci010e54b2016-03-15 09:40:34 +01007071 ly_vlog_hide(0);
7072 if (resolved < unres->count) {
7073 /* try to resolve the unresolved data again, it will not resolve anything, but it will print
7074 * all the validation errors
7075 */
7076 for (i = 0; i < unres->count; ++i) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02007077 if (unres->type[i] == UNRES_UNION) {
7078 /* does not make sense to print specific errors for all
7079 * the data types, just print that the value is invalid */
7080 leaf = (struct lyd_node_leaf_list *)unres->node[i];
7081 LOGVAL(LYE_INVAL, LY_VLOG_LYD, unres->node[i], (leaf->value_str ? leaf->value_str : ""),
7082 leaf->schema->name);
7083 } else if (unres->type[i] != UNRES_RESOLVED) {
7084 resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01007085 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007086 }
7087 return -1;
7088 }
7089
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02007090 LOGVRB("All data nodes and constraints resolved.");
Radek Krejci010e54b2016-03-15 09:40:34 +01007091 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007092 return EXIT_SUCCESS;
7093}