blob: 5e37cd557b0bd64dd88fba16b18d3eca7117d2be [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) {
Michal Vasko6ca5ca72016-11-28 09:21:51 +010091 str_dig -= trailing_zeros;
92 str_exp -= trailing_zeros;
Radek Krejcibf47a822016-11-04 10:06:08 +010093 ret = ret / dec_pow(trailing_zeros);
94 }
Michal Vasko4d1f0482016-09-19 14:35:06 +020095
96 /* it's parsed, now adjust the number based on fraction-digits, if needed */
97 if (str_dig < dig) {
98 if ((str_exp - 1) + (dig - str_dig) > 18) {
Michal Vaskod24dd012016-09-30 12:20:22 +020099 return 1;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200100 }
101 ret *= dec_pow(dig - str_dig);
102 }
103 if (str_dig > dig) {
Michal Vaskod24dd012016-09-30 12:20:22 +0200104 return 1;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200105 }
106
107 if (minus) {
108 ret *= -1;
109 }
110 *str_num = ptr;
Michal Vaskod24dd012016-09-30 12:20:22 +0200111 *num = ret;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200112
Michal Vaskod24dd012016-09-30 12:20:22 +0200113 return 0;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200114}
115
116/**
Radek Krejci6dc53a22015-08-17 13:27:59 +0200117 * @brief Parse an identifier.
118 *
119 * ;; An identifier MUST NOT start with (('X'|'x') ('M'|'m') ('L'|'l'))
120 * identifier = (ALPHA / "_")
121 * *(ALPHA / DIGIT / "_" / "-" / ".")
122 *
Michal Vaskobb211122015-08-19 14:03:11 +0200123 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200124 *
125 * @return Number of characters successfully parsed.
126 */
Michal Vasko249e6b52015-08-19 11:08:52 +0200127int
Radek Krejci6dc53a22015-08-17 13:27:59 +0200128parse_identifier(const char *id)
129{
130 int parsed = 0;
131
Michal Vasko1ab90bc2016-03-15 10:40:22 +0100132 assert(id);
133
Radek Krejci6dc53a22015-08-17 13:27:59 +0200134 if (!isalpha(id[0]) && (id[0] != '_')) {
135 return -parsed;
136 }
137
138 ++parsed;
139 ++id;
140
141 while (isalnum(id[0]) || (id[0] == '_') || (id[0] == '-') || (id[0] == '.')) {
142 ++parsed;
143 ++id;
144 }
145
146 return parsed;
147}
148
149/**
150 * @brief Parse a node-identifier.
151 *
Michal Vasko723e50c2015-10-20 15:20:29 +0200152 * node-identifier = [module-name ":"] identifier
Radek Krejci6dc53a22015-08-17 13:27:59 +0200153 *
Michal Vaskobb211122015-08-19 14:03:11 +0200154 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200155 * @param[out] mod_name Points to the module name, NULL if there is not any.
156 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200157 * @param[out] name Points to the node name.
158 * @param[out] nam_len Length of the node name.
159 *
160 * @return Number of characters successfully parsed,
161 * positive on success, negative on failure.
162 */
163static int
Michal Vasko723e50c2015-10-20 15:20:29 +0200164parse_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 +0200165{
166 int parsed = 0, ret;
167
168 assert(id);
Michal Vasko723e50c2015-10-20 15:20:29 +0200169 if (mod_name) {
170 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200171 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200172 if (mod_name_len) {
173 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200174 }
175 if (name) {
176 *name = NULL;
177 }
178 if (nam_len) {
179 *nam_len = 0;
180 }
181
182 if ((ret = parse_identifier(id)) < 1) {
183 return ret;
184 }
185
Michal Vasko723e50c2015-10-20 15:20:29 +0200186 if (mod_name) {
187 *mod_name = id;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200188 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200189 if (mod_name_len) {
190 *mod_name_len = ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200191 }
192
193 parsed += ret;
194 id += ret;
195
196 /* there is prefix */
197 if (id[0] == ':') {
198 ++parsed;
199 ++id;
200
201 /* there isn't */
202 } else {
Michal Vasko723e50c2015-10-20 15:20:29 +0200203 if (name && mod_name) {
204 *name = *mod_name;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200205 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200206 if (mod_name) {
207 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200208 }
209
Michal Vasko723e50c2015-10-20 15:20:29 +0200210 if (nam_len && mod_name_len) {
211 *nam_len = *mod_name_len;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200212 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200213 if (mod_name_len) {
214 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200215 }
216
217 return parsed;
218 }
219
220 /* identifier (node name) */
221 if ((ret = parse_identifier(id)) < 1) {
222 return -parsed+ret;
223 }
224
225 if (name) {
226 *name = id;
227 }
228 if (nam_len) {
229 *nam_len = ret;
230 }
231
232 return parsed+ret;
233}
234
235/**
236 * @brief Parse a path-predicate (leafref).
237 *
238 * path-predicate = "[" *WSP path-equality-expr *WSP "]"
239 * path-equality-expr = node-identifier *WSP "=" *WSP path-key-expr
240 *
Michal Vaskobb211122015-08-19 14:03:11 +0200241 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200242 * @param[out] prefix Points to the prefix, NULL if there is not any.
243 * @param[out] pref_len Length of the prefix, 0 if there is not any.
244 * @param[out] name Points to the node name.
245 * @param[out] nam_len Length of the node name.
246 * @param[out] path_key_expr Points to the path-key-expr.
247 * @param[out] pke_len Length of the path-key-expr.
248 * @param[out] has_predicate Flag to mark whether there is another predicate following.
249 *
250 * @return Number of characters successfully parsed,
251 * positive on success, negative on failure.
252 */
253static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200254parse_path_predicate(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
255 const char **path_key_expr, int *pke_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200256{
257 const char *ptr;
258 int parsed = 0, ret;
259
260 assert(id);
261 if (prefix) {
262 *prefix = NULL;
263 }
264 if (pref_len) {
265 *pref_len = 0;
266 }
267 if (name) {
268 *name = NULL;
269 }
270 if (nam_len) {
271 *nam_len = 0;
272 }
273 if (path_key_expr) {
274 *path_key_expr = NULL;
275 }
276 if (pke_len) {
277 *pke_len = 0;
278 }
279 if (has_predicate) {
280 *has_predicate = 0;
281 }
282
283 if (id[0] != '[') {
284 return -parsed;
285 }
286
287 ++parsed;
288 ++id;
289
290 while (isspace(id[0])) {
291 ++parsed;
292 ++id;
293 }
294
295 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
296 return -parsed+ret;
297 }
298
299 parsed += ret;
300 id += ret;
301
302 while (isspace(id[0])) {
303 ++parsed;
304 ++id;
305 }
306
307 if (id[0] != '=') {
308 return -parsed;
309 }
310
311 ++parsed;
312 ++id;
313
314 while (isspace(id[0])) {
315 ++parsed;
316 ++id;
317 }
318
319 if ((ptr = strchr(id, ']')) == NULL) {
320 return -parsed;
321 }
322
323 --ptr;
324 while (isspace(ptr[0])) {
325 --ptr;
326 }
327 ++ptr;
328
329 ret = ptr-id;
330 if (path_key_expr) {
331 *path_key_expr = id;
332 }
333 if (pke_len) {
334 *pke_len = ret;
335 }
336
337 parsed += ret;
338 id += ret;
339
340 while (isspace(id[0])) {
341 ++parsed;
342 ++id;
343 }
344
345 assert(id[0] == ']');
346
347 if (id[1] == '[') {
348 *has_predicate = 1;
349 }
350
351 return parsed+1;
352}
353
354/**
355 * @brief Parse a path-key-expr (leafref). First call parses "current()", all
356 * the ".." and the first node-identifier, other calls parse a single
357 * node-identifier each.
358 *
359 * path-key-expr = current-function-invocation *WSP "/" *WSP
360 * rel-path-keyexpr
361 * rel-path-keyexpr = 1*(".." *WSP "/" *WSP)
362 * *(node-identifier *WSP "/" *WSP)
363 * node-identifier
364 *
Michal Vaskobb211122015-08-19 14:03:11 +0200365 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200366 * @param[out] prefix Points to the prefix, NULL if there is not any.
367 * @param[out] pref_len Length of the prefix, 0 if there is not any.
368 * @param[out] name Points to the node name.
369 * @param[out] nam_len Length of the node name.
370 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
371 * must not be changed between consecutive calls.
372 * @return Number of characters successfully parsed,
373 * positive on success, negative on failure.
374 */
375static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200376parse_path_key_expr(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
377 int *parent_times)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200378{
379 int parsed = 0, ret, par_times = 0;
380
381 assert(id);
382 assert(parent_times);
383 if (prefix) {
384 *prefix = NULL;
385 }
386 if (pref_len) {
387 *pref_len = 0;
388 }
389 if (name) {
390 *name = NULL;
391 }
392 if (nam_len) {
393 *nam_len = 0;
394 }
395
396 if (!*parent_times) {
397 /* current-function-invocation *WSP "/" *WSP rel-path-keyexpr */
398 if (strncmp(id, "current()", 9)) {
399 return -parsed;
400 }
401
402 parsed += 9;
403 id += 9;
404
405 while (isspace(id[0])) {
406 ++parsed;
407 ++id;
408 }
409
410 if (id[0] != '/') {
411 return -parsed;
412 }
413
414 ++parsed;
415 ++id;
416
417 while (isspace(id[0])) {
418 ++parsed;
419 ++id;
420 }
421
422 /* rel-path-keyexpr */
423 if (strncmp(id, "..", 2)) {
424 return -parsed;
425 }
426 ++par_times;
427
428 parsed += 2;
429 id += 2;
430
431 while (isspace(id[0])) {
432 ++parsed;
433 ++id;
434 }
435 }
436
437 /* 1*(".." *WSP "/" *WSP) *(node-identifier *WSP "/" *WSP) node-identifier
438 *
439 * first parent reference with whitespaces already parsed
440 */
441 if (id[0] != '/') {
442 return -parsed;
443 }
444
445 ++parsed;
446 ++id;
447
448 while (isspace(id[0])) {
449 ++parsed;
450 ++id;
451 }
452
453 while (!strncmp(id, "..", 2) && !*parent_times) {
454 ++par_times;
455
456 parsed += 2;
457 id += 2;
458
459 while (isspace(id[0])) {
460 ++parsed;
461 ++id;
462 }
463
464 if (id[0] != '/') {
465 return -parsed;
466 }
467
468 ++parsed;
469 ++id;
470
471 while (isspace(id[0])) {
472 ++parsed;
473 ++id;
474 }
475 }
476
477 if (!*parent_times) {
478 *parent_times = par_times;
479 }
480
481 /* all parent references must be parsed at this point */
482 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
483 return -parsed+ret;
484 }
485
486 parsed += ret;
487 id += ret;
488
489 return parsed;
490}
491
492/**
493 * @brief Parse path-arg (leafref).
494 *
495 * path-arg = absolute-path / relative-path
496 * absolute-path = 1*("/" (node-identifier *path-predicate))
497 * relative-path = 1*(".." "/") descendant-path
498 *
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200499 * @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 +0200500 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200501 * @param[out] prefix Points to the prefix, NULL if there is not any.
502 * @param[out] pref_len Length of the prefix, 0 if there is not any.
503 * @param[out] name Points to the node name.
504 * @param[out] nam_len Length of the node name.
505 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
506 * must not be changed between consecutive calls. -1 if the
507 * path is relative.
508 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
509 *
510 * @return Number of characters successfully parsed,
511 * positive on success, negative on failure.
512 */
513static int
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200514parse_path_arg(struct lys_module *mod, const char *id, const char **prefix, int *pref_len,
515 const char **name, int *nam_len, int *parent_times, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200516{
517 int parsed = 0, ret, par_times = 0;
518
519 assert(id);
520 assert(parent_times);
521 if (prefix) {
522 *prefix = NULL;
523 }
524 if (pref_len) {
525 *pref_len = 0;
526 }
527 if (name) {
528 *name = NULL;
529 }
530 if (nam_len) {
531 *nam_len = 0;
532 }
533 if (has_predicate) {
534 *has_predicate = 0;
535 }
536
537 if (!*parent_times && !strncmp(id, "..", 2)) {
538 ++par_times;
539
540 parsed += 2;
541 id += 2;
542
543 while (!strncmp(id, "/..", 3)) {
544 ++par_times;
545
546 parsed += 3;
547 id += 3;
548 }
549 }
550
551 if (!*parent_times) {
552 if (par_times) {
553 *parent_times = par_times;
554 } else {
555 *parent_times = -1;
556 }
557 }
558
559 if (id[0] != '/') {
560 return -parsed;
561 }
562
563 /* skip '/' */
564 ++parsed;
565 ++id;
566
567 /* node-identifier ([prefix:]identifier) */
568 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
569 return -parsed-ret;
570 }
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200571 if (!(*prefix)) {
572 /* actually we always need prefix even it is not specified */
573 *prefix = lys_main_module(mod)->name;
574 *pref_len = strlen(*prefix);
575 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200576
577 parsed += ret;
578 id += ret;
579
580 /* there is no predicate */
581 if ((id[0] == '/') || !id[0]) {
582 return parsed;
583 } else if (id[0] != '[') {
584 return -parsed;
585 }
586
587 if (has_predicate) {
588 *has_predicate = 1;
589 }
590
591 return parsed;
592}
593
594/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200595 * @brief Parse instance-identifier in JSON data format. That means that prefixes
Michal Vaskob2f40be2016-09-08 16:03:48 +0200596 * (which are mandatory for every node-identifier) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200597 *
598 * instance-identifier = 1*("/" (node-identifier *predicate))
599 *
Michal Vaskobb211122015-08-19 14:03:11 +0200600 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200601 * @param[out] model Points to the model name.
602 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200603 * @param[out] name Points to the node name.
604 * @param[out] nam_len Length of the node name.
605 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
606 *
607 * @return Number of characters successfully parsed,
608 * positive on success, negative on failure.
609 */
610static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200611parse_instance_identifier(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
612 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200613{
614 int parsed = 0, ret;
615
Radek Krejci6dc53a22015-08-17 13:27:59 +0200616 if (has_predicate) {
617 *has_predicate = 0;
618 }
619
620 if (id[0] != '/') {
621 return -parsed;
622 }
623
624 ++parsed;
625 ++id;
626
Michal Vaskob2f40be2016-09-08 16:03:48 +0200627 if ((ret = parse_identifier(id)) < 1) {
628 return ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200629 }
630
Michal Vaskob2f40be2016-09-08 16:03:48 +0200631 *model = id;
632 *mod_len = ret;
633
Radek Krejci6dc53a22015-08-17 13:27:59 +0200634 parsed += ret;
635 id += ret;
636
Michal Vaskob2f40be2016-09-08 16:03:48 +0200637 if (id[0] != ':') {
638 return -parsed;
639 }
640
641 ++parsed;
642 ++id;
643
644 if ((ret = parse_identifier(id)) < 1) {
645 return ret;
646 }
647
648 *name = id;
649 *nam_len = ret;
650
651 parsed += ret;
652 id += ret;
653
Radek Krejci4967cb62016-09-14 16:40:28 +0200654 if (id[0] == '[' && has_predicate) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200655 *has_predicate = 1;
656 }
657
658 return parsed;
659}
660
661/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200662 * @brief Parse predicate (instance-identifier) in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200663 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200664 *
665 * predicate = "[" *WSP (predicate-expr / pos) *WSP "]"
666 * predicate-expr = (node-identifier / ".") *WSP "=" *WSP
667 * ((DQUOTE string DQUOTE) /
668 * (SQUOTE string SQUOTE))
669 * pos = non-negative-integer-value
670 *
Michal Vaskobb211122015-08-19 14:03:11 +0200671 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200672 * @param[out] model Points to the model name.
673 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200674 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
675 * @param[out] nam_len Length of the node name.
676 * @param[out] value Value the node-identifier must have (string from the grammar),
677 * NULL if there is not any.
678 * @param[out] val_len Length of the value, 0 if there is not any.
679 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
680 *
681 * @return Number of characters successfully parsed,
682 * positive on success, negative on failure.
683 */
684static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200685parse_predicate(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
686 const char **value, int *val_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200687{
688 const char *ptr;
689 int parsed = 0, ret;
690 char quote;
691
692 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200693 if (model) {
694 *model = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200695 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200696 if (mod_len) {
697 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200698 }
699 if (name) {
700 *name = NULL;
701 }
702 if (nam_len) {
703 *nam_len = 0;
704 }
705 if (value) {
706 *value = NULL;
707 }
708 if (val_len) {
709 *val_len = 0;
710 }
711 if (has_predicate) {
712 *has_predicate = 0;
713 }
714
715 if (id[0] != '[') {
716 return -parsed;
717 }
718
719 ++parsed;
720 ++id;
721
722 while (isspace(id[0])) {
723 ++parsed;
724 ++id;
725 }
726
727 /* pos */
728 if (isdigit(id[0])) {
729 if (name) {
730 *name = id;
731 }
732
733 if (id[0] == '0') {
Michal Vaskof2f28a12016-09-09 12:43:06 +0200734 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200735 }
736
737 while (isdigit(id[0])) {
738 ++parsed;
739 ++id;
740 }
741
742 if (nam_len) {
743 *nam_len = id-(*name);
744 }
745
Michal Vaskof2f28a12016-09-09 12:43:06 +0200746 /* "." or node-identifier */
Radek Krejci6dc53a22015-08-17 13:27:59 +0200747 } else {
Michal Vaskof2f28a12016-09-09 12:43:06 +0200748 if (id[0] == '.') {
749 if (name) {
750 *name = id;
751 }
752 if (nam_len) {
753 *nam_len = 1;
754 }
755
756 ++parsed;
757 ++id;
758
759 } else {
760 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
761 return -parsed+ret;
762 } else if (model && !*model) {
763 return -parsed;
764 }
765
766 parsed += ret;
767 id += ret;
768 }
769
770 while (isspace(id[0])) {
771 ++parsed;
772 ++id;
773 }
774
775 if (id[0] != '=') {
Michal Vasko1f2cc332015-08-19 11:18:32 +0200776 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200777 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200778
Radek Krejci6dc53a22015-08-17 13:27:59 +0200779 ++parsed;
780 ++id;
781
Michal Vaskof2f28a12016-09-09 12:43:06 +0200782 while (isspace(id[0])) {
783 ++parsed;
784 ++id;
785 }
786
787 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
788 if ((id[0] == '\"') || (id[0] == '\'')) {
789 quote = id[0];
790
791 ++parsed;
792 ++id;
793
794 if ((ptr = strchr(id, quote)) == NULL) {
795 return -parsed;
796 }
797 ret = ptr-id;
798
799 if (value) {
800 *value = id;
801 }
802 if (val_len) {
803 *val_len = ret;
804 }
805
806 parsed += ret+1;
807 id += ret+1;
808 } else {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200809 return -parsed;
810 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200811 }
812
813 while (isspace(id[0])) {
814 ++parsed;
815 ++id;
816 }
817
818 if (id[0] != ']') {
819 return -parsed;
820 }
821
822 ++parsed;
823 ++id;
824
825 if ((id[0] == '[') && has_predicate) {
826 *has_predicate = 1;
827 }
828
829 return parsed;
830}
831
832/**
833 * @brief Parse schema-nodeid.
834 *
835 * schema-nodeid = absolute-schema-nodeid /
836 * descendant-schema-nodeid
837 * absolute-schema-nodeid = 1*("/" node-identifier)
Michal Vasko48935352016-03-29 11:52:36 +0200838 * descendant-schema-nodeid = ["." "/"]
Radek Krejci6dc53a22015-08-17 13:27:59 +0200839 * node-identifier
840 * absolute-schema-nodeid
841 *
Michal Vaskobb211122015-08-19 14:03:11 +0200842 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200843 * @param[out] mod_name Points to the module name, NULL if there is not any.
844 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Michal Vasko48935352016-03-29 11:52:36 +0200845 * @param[out] name Points to the node name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200846 * @param[out] nam_len Length of the node name.
847 * @param[out] is_relative Flag to mark whether the nodeid is absolute or descendant. Must be -1
848 * on the first call, must not be changed between consecutive calls.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100849 * @param[out] has_predicate Flag to mark whether there is a predicate specified. It cannot be
850 * based on the grammar, in those cases use NULL.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200851 *
852 * @return Number of characters successfully parsed,
853 * positive on success, negative on failure.
854 */
Michal Vasko22448d32016-03-16 13:17:29 +0100855int
Michal Vasko723e50c2015-10-20 15:20:29 +0200856parse_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 +0100857 int *is_relative, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200858{
859 int parsed = 0, ret;
860
861 assert(id);
862 assert(is_relative);
Michal Vasko723e50c2015-10-20 15:20:29 +0200863 if (mod_name) {
864 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200865 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200866 if (mod_name_len) {
867 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200868 }
869 if (name) {
870 *name = NULL;
871 }
872 if (nam_len) {
873 *nam_len = 0;
874 }
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100875 if (has_predicate) {
876 *has_predicate = 0;
877 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200878
879 if (id[0] != '/') {
880 if (*is_relative != -1) {
881 return -parsed;
882 } else {
883 *is_relative = 1;
884 }
Michal Vasko48935352016-03-29 11:52:36 +0200885 if (!strncmp(id, "./", 2)) {
886 parsed += 2;
887 id += 2;
888 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200889 } else {
890 if (*is_relative == -1) {
891 *is_relative = 0;
892 }
893 ++parsed;
894 ++id;
895 }
896
Michal Vasko723e50c2015-10-20 15:20:29 +0200897 if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200898 return -parsed+ret;
899 }
900
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100901 parsed += ret;
902 id += ret;
903
904 if ((id[0] == '[') && has_predicate) {
905 *has_predicate = 1;
906 }
907
908 return parsed;
909}
910
911/**
912 * @brief Parse schema predicate (special format internally used).
913 *
914 * predicate = "[" *WSP predicate-expr *WSP "]"
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200915 * predicate-expr = "." / identifier / key-with-value
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100916 * key-with-value = identifier *WSP "=" *WSP
917 * ((DQUOTE string DQUOTE) /
918 * (SQUOTE string SQUOTE))
919 *
920 * @param[in] id Identifier to use.
921 * @param[out] name Points to the list key name.
922 * @param[out] nam_len Length of \p name.
Michal Vasko22448d32016-03-16 13:17:29 +0100923 * @param[out] value Points to the key value. If specified, key-with-value is expected.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100924 * @param[out] val_len Length of \p value.
925 * @param[out] has_predicate Flag to mark whether there is another predicate specified.
926 */
Michal Vasko22448d32016-03-16 13:17:29 +0100927int
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200928parse_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 +0100929 int *has_predicate)
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100930{
931 const char *ptr;
932 int parsed = 0, ret;
933 char quote;
934
935 assert(id);
936 if (name) {
937 *name = NULL;
938 }
939 if (nam_len) {
940 *nam_len = 0;
941 }
942 if (value) {
943 *value = NULL;
944 }
945 if (val_len) {
946 *val_len = 0;
947 }
948 if (has_predicate) {
949 *has_predicate = 0;
950 }
951
952 if (id[0] != '[') {
953 return -parsed;
954 }
955
956 ++parsed;
957 ++id;
958
959 while (isspace(id[0])) {
960 ++parsed;
961 ++id;
962 }
963
Michal Vasko22448d32016-03-16 13:17:29 +0100964 /* identifier */
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200965 if (id[0] == '.') {
966 ret = 1;
967 } else if ((ret = parse_identifier(id)) < 1) {
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100968 return -parsed + ret;
969 }
970 if (name) {
971 *name = id;
972 }
973 if (nam_len) {
974 *nam_len = ret;
975 }
976
977 parsed += ret;
978 id += ret;
979
980 while (isspace(id[0])) {
981 ++parsed;
982 ++id;
983 }
984
985 /* there is value as well */
986 if (id[0] == '=') {
987 ++parsed;
988 ++id;
989
990 while (isspace(id[0])) {
991 ++parsed;
992 ++id;
993 }
994
995 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
996 if ((id[0] == '\"') || (id[0] == '\'')) {
997 quote = id[0];
998
999 ++parsed;
1000 ++id;
1001
1002 if ((ptr = strchr(id, quote)) == NULL) {
1003 return -parsed;
1004 }
1005 ret = ptr - id;
1006
1007 if (value) {
1008 *value = id;
1009 }
1010 if (val_len) {
1011 *val_len = ret;
1012 }
1013
1014 parsed += ret + 1;
1015 id += ret + 1;
1016 } else {
1017 return -parsed;
1018 }
1019
1020 while (isspace(id[0])) {
1021 ++parsed;
1022 ++id;
1023 }
Michal Vasko22448d32016-03-16 13:17:29 +01001024 } else if (value) {
1025 /* if value was expected, it's mandatory */
1026 return -parsed;
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001027 }
1028
1029 if (id[0] != ']') {
1030 return -parsed;
1031 }
1032
1033 ++parsed;
1034 ++id;
1035
1036 if ((id[0] == '[') && has_predicate) {
1037 *has_predicate = 1;
1038 }
1039
1040 return parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +02001041}
1042
1043/**
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001044 * @brief Resolve (find) a feature definition. Logs directly.
1045 *
1046 * @param[in] feat_name Feature name to resolve.
1047 * @param[in] len Length of \p feat_name.
1048 * @param[in] node Node with the if-feature expression.
Radek Krejci9ff0a922016-07-14 13:08:05 +02001049 * @param[out] feature Pointer to be set to point to the feature definition, if feature not found
1050 * (return code 1), the pointer is untouched.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001051 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02001052 * @return 0 on success, 1 on forward reference, -1 on error.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001053 */
1054static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001055resolve_feature(const char *feat_name, uint16_t len, const struct lys_node *node, struct lys_feature **feature)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001056{
1057 char *str;
1058 const char *mod_name, *name;
1059 int mod_name_len, nam_len, i, j;
1060 const struct lys_module *module;
1061
Radek Krejci9ff0a922016-07-14 13:08:05 +02001062 assert(feature);
1063
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001064 /* check prefix */
1065 if ((i = parse_node_identifier(feat_name, &mod_name, &mod_name_len, &name, &nam_len)) < 1) {
1066 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, feat_name[-i], &feat_name[-i]);
1067 return -1;
1068 }
1069
1070 module = lys_get_import_module(lys_node_module(node), NULL, 0, mod_name, mod_name_len);
1071 if (!module) {
1072 /* identity refers unknown data model */
1073 LOGVAL(LYE_INMOD_LEN, LY_VLOG_NONE, NULL, mod_name_len, mod_name);
1074 return -1;
1075 }
1076
Radek Krejci9ff0a922016-07-14 13:08:05 +02001077 if (module != node->module && module == lys_node_module(node)) {
1078 /* first, try to search directly in submodule where the feature was mentioned */
1079 for (j = 0; j < node->module->features_size; j++) {
1080 if (!strncmp(name, node->module->features[j].name, nam_len) && !node->module->features[j].name[nam_len]) {
1081 /* check status */
1082 if (lyp_check_status(node->flags, lys_node_module(node), node->name, node->module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001083 node->module->features[j].module, node->module->features[j].name, NULL)) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001084 return -1;
1085 }
1086 *feature = &node->module->features[j];
1087 return 0;
1088 }
1089 }
1090 }
1091
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001092 /* search in the identified module ... */
1093 for (j = 0; j < module->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001094 if (!strncmp(name, module->features[j].name, nam_len) && !module->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001095 /* check status */
1096 if (lyp_check_status(node->flags, lys_node_module(node), node->name, module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001097 module->features[j].module, module->features[j].name, NULL)) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001098 return -1;
1099 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001100 *feature = &module->features[j];
1101 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001102 }
1103 }
1104 /* ... and all its submodules */
1105 for (i = 0; i < module->inc_size; i++) {
1106 if (!module->inc[i].submodule) {
1107 /* not yet resolved */
1108 continue;
1109 }
1110 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001111 if (!strncmp(name, module->inc[i].submodule->features[j].name, nam_len)
1112 && !module->inc[i].submodule->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001113 /* check status */
1114 if (lyp_check_status(node->flags, lys_node_module(node), node->name,
1115 module->inc[i].submodule->features[j].flags,
1116 module->inc[i].submodule->features[j].module,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001117 module->inc[i].submodule->features[j].name, NULL)) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001118 return -1;
1119 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001120 *feature = &module->inc[i].submodule->features[j];
1121 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001122 }
1123 }
1124 }
1125
1126 /* not found */
1127 str = strndup(feat_name, len);
1128 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, "feature", str);
1129 free(str);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001130 return 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001131}
1132
Radek Krejci9ff0a922016-07-14 13:08:05 +02001133/*
1134 * @return
Radek Krejci69b8d922016-07-27 13:13:41 +02001135 * - 1 if enabled
1136 * - 0 if disabled
Radek Krejci9ff0a922016-07-14 13:08:05 +02001137 * - -1 if not usable by its if-feature expression
1138 */
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001139static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001140resolve_feature_value(const struct lys_feature *feat)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001141{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001142 int i;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001143
Radek Krejci9ff0a922016-07-14 13:08:05 +02001144 for (i = 0; i < feat->iffeature_size; i++) {
Radek Krejci69b8d922016-07-27 13:13:41 +02001145 if (!resolve_iffeature(&feat->iffeature[i])) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001146 return -1;
1147 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001148 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001149
Radek Krejci69b8d922016-07-27 13:13:41 +02001150 return feat->flags & LYS_FENABLED ? 1 : 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001151}
1152
1153static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001154resolve_iffeature_recursive(struct lys_iffeature *expr, int *index_e, int *index_f)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001155{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001156 uint8_t op;
1157 int rc, a, b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001158
Radek Krejci9ff0a922016-07-14 13:08:05 +02001159 op = iff_getop(expr->expr, *index_e);
1160 (*index_e)++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001161
Radek Krejci9ff0a922016-07-14 13:08:05 +02001162 switch (op) {
1163 case LYS_IFF_F:
1164 /* resolve feature */
1165 return resolve_feature_value(expr->features[(*index_f)++]);
1166 case LYS_IFF_NOT:
1167 rc = resolve_iffeature_recursive(expr, index_e, index_f);
1168 if (rc == -1) {
1169 /* one of the referenced feature is hidden by its if-feature,
1170 * so this if-feature expression is always false */
1171 return -1;
1172 } else {
1173 /* invert result */
1174 return rc ? 0 : 1;
1175 }
1176 case LYS_IFF_AND:
1177 case LYS_IFF_OR:
1178 a = resolve_iffeature_recursive(expr, index_e, index_f);
1179 b = resolve_iffeature_recursive(expr, index_e, index_f);
1180 if (a == -1 || b == -1) {
1181 /* one of the referenced feature is hidden by its if-feature,
1182 * so this if-feature expression is always false */
1183 return -1;
1184 } else if (op == LYS_IFF_AND) {
1185 return a && b;
1186 } else { /* LYS_IFF_OR */
1187 return a || b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001188 }
1189 }
1190
Radek Krejci9ff0a922016-07-14 13:08:05 +02001191 return -1;
1192}
1193
1194int
1195resolve_iffeature(struct lys_iffeature *expr)
1196{
1197 int rc = -1;
1198 int index_e = 0, index_f = 0;
1199
1200 if (expr->expr) {
1201 rc = resolve_iffeature_recursive(expr, &index_e, &index_f);
1202 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001203 return (rc == 1) ? 1 : 0;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001204}
1205
1206struct iff_stack {
1207 int size;
1208 int index; /* first empty item */
1209 uint8_t *stack;
1210};
1211
1212static int
1213iff_stack_push(struct iff_stack *stack, uint8_t value)
1214{
1215 if (stack->index == stack->size) {
1216 stack->size += 4;
1217 stack->stack = ly_realloc(stack->stack, stack->size * sizeof *stack->stack);
1218 if (!stack->stack) {
1219 LOGMEM;
1220 stack->size = 0;
1221 return EXIT_FAILURE;
1222 }
1223 }
1224
1225 stack->stack[stack->index++] = value;
1226 return EXIT_SUCCESS;
1227}
1228
1229static uint8_t
1230iff_stack_pop(struct iff_stack *stack)
1231{
1232 stack->index--;
1233 return stack->stack[stack->index];
1234}
1235
1236static void
1237iff_stack_clean(struct iff_stack *stack)
1238{
1239 stack->size = 0;
1240 free(stack->stack);
1241}
1242
1243static void
1244iff_setop(uint8_t *list, uint8_t op, int pos)
1245{
1246 uint8_t *item;
1247 uint8_t mask = 3;
1248
1249 assert(pos >= 0);
1250 assert(op <= 3); /* max 2 bits */
1251
1252 item = &list[pos / 4];
1253 mask = mask << 2 * (pos % 4);
1254 *item = (*item) & ~mask;
1255 *item = (*item) | (op << 2 * (pos % 4));
1256}
1257
1258uint8_t
1259iff_getop(uint8_t *list, int pos)
1260{
1261 uint8_t *item;
1262 uint8_t mask = 3, result;
1263
1264 assert(pos >= 0);
1265
1266 item = &list[pos / 4];
1267 result = (*item) & (mask << 2 * (pos % 4));
1268 return result >> 2 * (pos % 4);
1269}
1270
1271#define LYS_IFF_LP 0x04 /* ( */
1272#define LYS_IFF_RP 0x08 /* ) */
1273
Radek Krejcicbb473e2016-09-16 14:48:32 +02001274/* internal structure for passing data for UNRES_IFFEAT */
1275struct unres_iffeat_data {
1276 struct lys_node *node;
1277 const char *fname;
Radek Krejci9de2c042016-10-19 16:53:06 +02001278 int infeature;
Radek Krejcicbb473e2016-09-16 14:48:32 +02001279};
1280
Radek Krejci9ff0a922016-07-14 13:08:05 +02001281void
1282resolve_iffeature_getsizes(struct lys_iffeature *iffeat, unsigned int *expr_size, unsigned int *feat_size)
1283{
1284 unsigned int e = 0, f = 0, r = 0;
1285 uint8_t op;
1286
1287 assert(iffeat);
1288
1289 if (!iffeat->expr) {
1290 goto result;
1291 }
1292
1293 do {
1294 op = iff_getop(iffeat->expr, e++);
1295 switch (op) {
1296 case LYS_IFF_NOT:
1297 if (!r) {
1298 r += 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001299 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001300 break;
1301 case LYS_IFF_AND:
1302 case LYS_IFF_OR:
1303 if (!r) {
1304 r += 2;
1305 } else {
1306 r += 1;
1307 }
1308 break;
1309 case LYS_IFF_F:
1310 f++;
1311 if (r) {
1312 r--;
1313 }
1314 break;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001315 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001316 } while(r);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001317
Radek Krejci9ff0a922016-07-14 13:08:05 +02001318result:
1319 if (expr_size) {
1320 *expr_size = e;
1321 }
1322 if (feat_size) {
1323 *feat_size = f;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001324 }
1325}
1326
1327int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001328resolve_iffeature_compile(struct lys_iffeature *iffeat_expr, const char *value, struct lys_node *node,
Radek Krejci9de2c042016-10-19 16:53:06 +02001329 int infeature, struct unres_schema *unres)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001330{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001331 const char *c = value;
1332 int r, rc = EXIT_FAILURE;
Radek Krejci69b8d922016-07-27 13:13:41 +02001333 int i, j, last_not, checkversion = 0;
1334 unsigned int f_size = 0, expr_size = 0, f_exp = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001335 uint8_t op;
1336 struct iff_stack stack = {0, 0, NULL};
Radek Krejcicbb473e2016-09-16 14:48:32 +02001337 struct unres_iffeat_data *iff_data;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001338
Radek Krejci9ff0a922016-07-14 13:08:05 +02001339 assert(c);
1340
1341 if (isspace(c[0])) {
1342 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, c[0], c);
1343 return EXIT_FAILURE;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001344 }
1345
Radek Krejci9ff0a922016-07-14 13:08:05 +02001346 /* pre-parse the expression to get sizes for arrays, also do some syntax checks of the expression */
1347 for (i = j = last_not = 0; c[i]; i++) {
1348 if (c[i] == '(') {
Radek Krejci69b8d922016-07-27 13:13:41 +02001349 checkversion = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001350 j++;
1351 continue;
1352 } else if (c[i] == ')') {
1353 j--;
1354 continue;
1355 } else if (isspace(c[i])) {
1356 continue;
1357 }
1358
1359 if (!strncmp(&c[i], "not", r = 3) || !strncmp(&c[i], "and", r = 3) || !strncmp(&c[i], "or", r = 2)) {
1360 if (c[i + r] == '\0') {
Radek Krejcia98da3f2016-07-27 14:05:22 +02001361 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
Radek Krejci9ff0a922016-07-14 13:08:05 +02001362 return EXIT_FAILURE;
1363 } else if (!isspace(c[i + r])) {
1364 /* feature name starting with the not/and/or */
1365 last_not = 0;
1366 f_size++;
1367 } else if (c[i] == 'n') { /* not operation */
1368 if (last_not) {
1369 /* double not */
1370 expr_size = expr_size - 2;
1371 last_not = 0;
1372 } else {
1373 last_not = 1;
1374 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001375 } else { /* and, or */
1376 f_exp++;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001377 /* not a not operation */
1378 last_not = 0;
1379 }
1380 i += r;
1381 } else {
1382 f_size++;
1383 last_not = 0;
1384 }
1385 expr_size++;
1386
1387 while (!isspace(c[i])) {
1388 if (!c[i] || c[i] == ')') {
1389 i--;
1390 break;
1391 }
1392 i++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001393 }
1394 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001395 if (j || f_exp != f_size) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001396 /* not matching count of ( and ) */
1397 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1398 return EXIT_FAILURE;
1399 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001400
Radek Krejci69b8d922016-07-27 13:13:41 +02001401 if (checkversion || expr_size > 1) {
1402 /* check that we have 1.1 module */
1403 if (node->module->version != 2) {
1404 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1405 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "YANG 1.1 if-feature expression found in 1.0 module.");
1406 return EXIT_FAILURE;
1407 }
1408 }
1409
Radek Krejci9ff0a922016-07-14 13:08:05 +02001410 /* allocate the memory */
1411 iffeat_expr->expr = calloc((j = (expr_size / 4) + ((expr_size % 4) ? 1 : 0)), sizeof *iffeat_expr->expr);
Radek Krejcicbb473e2016-09-16 14:48:32 +02001412 iffeat_expr->features = calloc(f_size, sizeof *iffeat_expr->features);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001413 stack.size = expr_size;
1414 stack.stack = malloc(expr_size * sizeof *stack.stack);
1415 if (!stack.stack || !iffeat_expr->expr || !iffeat_expr->features) {
1416 LOGMEM;
1417 goto error;
1418 }
1419 f_size--; expr_size--; /* used as indexes from now */
1420
1421 for (i--; i >= 0; i--) {
1422 if (c[i] == ')') {
1423 /* push it on stack */
1424 iff_stack_push(&stack, LYS_IFF_RP);
1425 continue;
1426 } else if (c[i] == '(') {
1427 /* pop from the stack into result all operators until ) */
1428 while((op = iff_stack_pop(&stack)) != LYS_IFF_RP) {
1429 iff_setop(iffeat_expr->expr, op, expr_size--);
1430 }
1431 continue;
1432 } else if (isspace(c[i])) {
1433 continue;
1434 }
1435
1436 /* end operator or operand -> find beginning and get what is it */
1437 j = i + 1;
1438 while (i >= 0 && !isspace(c[i]) && c[i] != '(') {
1439 i--;
1440 }
1441 i++; /* get back by one step */
1442
1443 if (!strncmp(&c[i], "not ", 4)) {
1444 if (stack.index && stack.stack[stack.index - 1] == LYS_IFF_NOT) {
1445 /* double not */
1446 iff_stack_pop(&stack);
1447 } else {
1448 /* not has the highest priority, so do not pop from the stack
1449 * as in case of AND and OR */
1450 iff_stack_push(&stack, LYS_IFF_NOT);
1451 }
1452 } else if (!strncmp(&c[i], "and ", 4)) {
1453 /* as for OR - pop from the stack all operators with the same or higher
1454 * priority and store them to the result, then push the AND to the stack */
1455 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_AND) {
1456 op = iff_stack_pop(&stack);
1457 iff_setop(iffeat_expr->expr, op, expr_size--);
1458 }
1459 iff_stack_push(&stack, LYS_IFF_AND);
1460 } else if (!strncmp(&c[i], "or ", 3)) {
1461 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_OR) {
1462 op = iff_stack_pop(&stack);
1463 iff_setop(iffeat_expr->expr, op, expr_size--);
1464 }
1465 iff_stack_push(&stack, LYS_IFF_OR);
1466 } else {
1467 /* feature name, length is j - i */
1468
1469 /* add it to the result */
1470 iff_setop(iffeat_expr->expr, LYS_IFF_F, expr_size--);
1471
1472 /* now get the link to the feature definition. Since it can be
Radek Krejcicbb473e2016-09-16 14:48:32 +02001473 * forward referenced, we have to keep the feature name in auxiliary
1474 * structure passed into unres */
1475 iff_data = malloc(sizeof *iff_data);
1476 iff_data->node = node;
1477 iff_data->fname = lydict_insert(node->module->ctx, &c[i], j - i);
Radek Krejci9de2c042016-10-19 16:53:06 +02001478 iff_data->infeature = infeature;
Radek Krejcicbb473e2016-09-16 14:48:32 +02001479 r = unres_schema_add_node(node->module, unres, &iffeat_expr->features[f_size], UNRES_IFFEAT,
1480 (struct lys_node *)iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001481 f_size--;
1482
1483 if (r == -1) {
Pavol Vican4d084512016-09-29 16:38:12 +02001484 free(iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001485 goto error;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001486 }
1487 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001488 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001489 while (stack.index) {
1490 op = iff_stack_pop(&stack);
1491 iff_setop(iffeat_expr->expr, op, expr_size--);
1492 }
1493
1494 if (++expr_size || ++f_size) {
1495 /* not all expected operators and operands found */
1496 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1497 rc = EXIT_FAILURE;
1498 } else {
1499 rc = EXIT_SUCCESS;
1500 }
1501
1502error:
1503 /* cleanup */
1504 iff_stack_clean(&stack);
1505
1506 return rc;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001507}
1508
1509/**
Michal Vasko3edeaf72016-02-11 13:17:43 +01001510 * @brief Resolve (find) a data node based on a schema-nodeid.
1511 *
1512 * Used for resolving unique statements - so id is expected to be relative and local (without reference to a different
1513 * module).
1514 *
1515 */
1516struct lyd_node *
1517resolve_data_descendant_schema_nodeid(const char *nodeid, struct lyd_node *start)
1518{
1519 char *str, *token, *p;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001520 struct lyd_node *result = NULL, *iter;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001521 const struct lys_node *schema = NULL;
Radek Krejcicc217a62016-04-08 16:58:11 +02001522 int shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001523
1524 assert(nodeid && start);
1525
1526 if (nodeid[0] == '/') {
1527 return NULL;
1528 }
1529
1530 str = p = strdup(nodeid);
1531 if (!str) {
1532 LOGMEM;
1533 return NULL;
1534 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001535
Michal Vasko3edeaf72016-02-11 13:17:43 +01001536 while (p) {
1537 token = p;
1538 p = strchr(p, '/');
1539 if (p) {
1540 *p = '\0';
1541 p++;
1542 }
1543
Radek Krejci5da4eb62016-04-08 14:45:51 +02001544 if (p) {
1545 /* inner node */
Radek Krejcicc217a62016-04-08 16:58:11 +02001546 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema,
Radek Krejcif3c71de2016-04-11 12:45:46 +02001547 LYS_CONTAINER | LYS_CHOICE | LYS_CASE | LYS_LEAF, 0, 0, &schema)
Radek Krejci5da4eb62016-04-08 14:45:51 +02001548 || !schema) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001549 result = NULL;
1550 break;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001551 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001552
Radek Krejci5da4eb62016-04-08 14:45:51 +02001553 if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
1554 continue;
Michal Vaskodcf98e62016-05-05 17:53:53 +02001555 } else if (lys_parent(schema)->nodetype == LYS_CHOICE) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001556 /* shorthand case */
1557 if (!shorthand) {
1558 shorthand = 1;
Michal Vaskodcf98e62016-05-05 17:53:53 +02001559 schema = lys_parent(schema);
Radek Krejcicc217a62016-04-08 16:58:11 +02001560 continue;
1561 } else {
1562 shorthand = 0;
1563 if (schema->nodetype == LYS_LEAF) {
1564 /* should not be here, since we have leaf, which is not a shorthand nor final node */
1565 result = NULL;
1566 break;
1567 }
1568 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001569 }
1570 } else {
1571 /* final node */
Radek Krejcif3c71de2016-04-11 12:45:46 +02001572 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema, LYS_LEAF,
1573 shorthand ? 0 : 1, 0, &schema)
Radek Krejcicc217a62016-04-08 16:58:11 +02001574 || !schema) {
1575 result = NULL;
1576 break;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001577 }
1578 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001579 LY_TREE_FOR(result ? result->child : start, iter) {
1580 if (iter->schema == schema) {
1581 /* move in data tree according to returned schema */
1582 result = iter;
1583 break;
1584 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001585 }
Radek Krejcicc217a62016-04-08 16:58:11 +02001586 if (!iter) {
1587 /* instance not found */
1588 result = NULL;
1589 break;
1590 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001591 }
1592 free(str);
1593
1594 return result;
1595}
1596
Radek Krejcibdf92362016-04-08 14:43:34 +02001597/*
1598 * 0 - ok (done)
1599 * 1 - continue
1600 * 2 - break
1601 * -1 - error
1602 */
1603static int
Radek Krejcicc217a62016-04-08 16:58:11 +02001604schema_nodeid_siblingcheck(const struct lys_node *sibling, int8_t *shorthand, const char *id,
Radek Krejcibdf92362016-04-08 14:43:34 +02001605 const struct lys_module *module, const char *mod_name, int mod_name_len,
Radek Krejci0fa54e92016-09-14 14:01:05 +02001606 int implemented_mod, const struct lys_node **start)
Radek Krejcibdf92362016-04-08 14:43:34 +02001607{
1608 const struct lys_module *prefix_mod;
1609
1610 /* module check */
1611 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Radek Krejcidf46e222016-11-08 11:57:37 +01001612 if (prefix_mod && implemented_mod) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001613 prefix_mod = lys_get_implemented_module(prefix_mod);
1614 }
Radek Krejcibdf92362016-04-08 14:43:34 +02001615 if (!prefix_mod) {
1616 return -1;
1617 }
1618 if (prefix_mod != lys_node_module(sibling)) {
1619 return 1;
1620 }
1621
1622 /* check for shorthand cases - then 'start' does not change */
Michal Vaskodcf98e62016-05-05 17:53:53 +02001623 if (lys_parent(sibling) && (lys_parent(sibling)->nodetype == LYS_CHOICE) && (sibling->nodetype != LYS_CASE)) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001624 if (*shorthand != -1) {
1625 *shorthand = *shorthand ? 0 : 1;
1626 }
Radek Krejcibdf92362016-04-08 14:43:34 +02001627 }
1628
1629 /* the result node? */
1630 if (!id[0]) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001631 if (*shorthand == 1) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001632 return 1;
1633 }
1634 return 0;
1635 }
1636
Radek Krejci3a130162016-11-07 16:21:20 +01001637 if (!(*shorthand)) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001638 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02001639 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001640 return -1;
1641 }
1642 *start = sibling->child;
1643 }
1644
1645 return 2;
1646}
1647
Radek Krejcidf46e222016-11-08 11:57:37 +01001648/* start - relative, module - absolute, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1
1649 * implement: 0 - do not change the implemented status of the affected modules, 1 - change implemented status of the affected modules
1650 */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001651int
1652resolve_augment_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_module *module,
Radek Krejcidf46e222016-11-08 11:57:37 +01001653 int implement, const struct lys_node **ret)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001654{
Radek Krejcidf46e222016-11-08 11:57:37 +01001655 const char *name, *mod_name, *mod_name_prev, *id;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001656 const struct lys_node *sibling;
1657 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001658 int8_t shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001659 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcidf46e222016-11-08 11:57:37 +01001660 const struct lys_module *start_mod, *aux_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001661
1662 assert(nodeid && (start || module) && !(start && module) && ret);
1663
1664 id = nodeid;
1665
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001666 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 +01001667 return ((id - nodeid) - r) + 1;
1668 }
1669 id += r;
1670
1671 if ((is_relative && !start) || (!is_relative && !module)) {
1672 return -1;
1673 }
1674
1675 /* descendant-schema-nodeid */
1676 if (is_relative) {
Michal Vasko4c06fd82016-02-17 13:43:38 +01001677 module = start_mod = start->module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001678
1679 /* absolute-schema-nodeid */
1680 } else {
1681 start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Radek Krejcidf46e222016-11-08 11:57:37 +01001682 if (start_mod != lys_main_module(module) && start_mod && !start_mod->implemented) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001683 /* if the submodule augments the mainmodule (or in general a module augments
1684 * itself, we don't want to search for the implemented module but augments
1685 * the module anyway. But when augmenting another module, we need the implemented
1686 * revision of the module if any */
Radek Krejcidf46e222016-11-08 11:57:37 +01001687 aux_mod = lys_get_implemented_module(start_mod);
1688 if (!aux_mod->implemented && implement) {
1689 /* make the found module implemented */
1690 if (lys_set_implemented(aux_mod)) {
1691 return -1;
1692 }
1693 }
1694 start_mod = aux_mod;
1695 implement++;
Radek Krejci0fa54e92016-09-14 14:01:05 +02001696 }
Michal Vaskoe2905632016-02-11 15:42:24 +01001697 if (!start_mod) {
1698 return -1;
1699 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001700 start = start_mod->data;
1701 }
1702
1703 while (1) {
1704 sibling = NULL;
Radek Krejcidf46e222016-11-08 11:57:37 +01001705 mod_name_prev = mod_name;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001706 while ((sibling = lys_getnext(sibling, lys_parent(start), start_mod,
1707 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
1708 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001709 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001710 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len,
Radek Krejcidf46e222016-11-08 11:57:37 +01001711 implement, &start);
Radek Krejcibdf92362016-04-08 14:43:34 +02001712 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001713 *ret = sibling;
1714 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001715 } else if (r == 1) {
1716 continue;
1717 } else if (r == 2) {
1718 break;
1719 } else {
1720 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001721 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001722 }
1723 }
1724
1725 /* no match */
1726 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001727 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001728 return EXIT_SUCCESS;
1729 }
1730
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001731 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 +01001732 return ((id - nodeid) - r) + 1;
1733 }
1734 id += r;
Radek Krejcidf46e222016-11-08 11:57:37 +01001735
1736 if ((mod_name && mod_name_prev && strncmp(mod_name, mod_name_prev, mod_name_len + 1)) ||
1737 (mod_name != mod_name_prev && (!mod_name || !mod_name_prev))) {
1738 /* we are getting into another module (augment) */
1739 if (implement) {
1740 /* we have to check that also target modules are implemented, if not, we have to change it */
1741 aux_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
1742 if (!aux_mod) {
1743 return -1;
1744 }
1745 if (!aux_mod->implemented) {
1746 aux_mod = lys_get_implemented_module(aux_mod);
1747 if (!aux_mod->implemented) {
1748 /* make the found module implemented */
1749 if (lys_set_implemented(aux_mod)) {
1750 return -1;
1751 }
1752 }
1753 }
1754 } else {
1755 /* we are not implementing the module itself, so the augments outside the module are ignored */
1756 *ret = NULL;
1757 return EXIT_SUCCESS;
1758 }
1759 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001760 }
1761
1762 /* cannot get here */
1763 LOGINT;
1764 return -1;
1765}
1766
Radek Krejcif3c71de2016-04-11 12:45:46 +02001767/* unique, refine,
1768 * >0 - unexpected char on position (ret - 1),
1769 * 0 - ok (but ret can still be NULL),
1770 * -1 - error,
1771 * -2 - violated no_innerlist */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001772int
1773resolve_descendant_schema_nodeid(const char *nodeid, const struct lys_node *start, int ret_nodetype,
Radek Krejcif3c71de2016-04-11 12:45:46 +02001774 int check_shorthand, int no_innerlist, const struct lys_node **ret)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001775{
1776 const char *name, *mod_name, *id;
1777 const struct lys_node *sibling;
1778 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001779 int8_t shorthand = check_shorthand ? 0 : -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001780 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcibdf92362016-04-08 14:43:34 +02001781 const struct lys_module *module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001782
1783 assert(nodeid && start && ret);
1784 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1785
1786 id = nodeid;
1787 module = start->module;
1788
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001789 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 +01001790 return ((id - nodeid) - r) + 1;
1791 }
1792 id += r;
1793
1794 if (!is_relative) {
1795 return -1;
1796 }
1797
1798 while (1) {
1799 sibling = NULL;
1800 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
1801 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE))) {
1802 /* name match */
1803 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001804 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len, 0, &start);
Radek Krejcibdf92362016-04-08 14:43:34 +02001805 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001806 if (!(sibling->nodetype & ret_nodetype)) {
1807 /* wrong node type, too bad */
1808 continue;
1809 }
1810 *ret = sibling;
1811 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001812 } else if (r == 1) {
1813 continue;
1814 } else if (r == 2) {
1815 break;
1816 } else {
1817 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001818 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001819 }
1820 }
1821
1822 /* no match */
1823 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001824 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001825 return EXIT_SUCCESS;
Radek Krejcif3c71de2016-04-11 12:45:46 +02001826 } else if (no_innerlist && sibling->nodetype == LYS_LIST) {
1827 *ret = NULL;
1828 return -2;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001829 }
1830
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001831 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 +01001832 return ((id - nodeid) - r) + 1;
1833 }
1834 id += r;
1835 }
1836
1837 /* cannot get here */
1838 LOGINT;
1839 return -1;
1840}
1841
1842/* choice default */
1843int
1844resolve_choice_default_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node **ret)
1845{
1846 /* cannot actually be a path */
1847 if (strchr(nodeid, '/')) {
1848 return -1;
1849 }
1850
Radek Krejcif3c71de2016-04-11 12:45:46 +02001851 return resolve_descendant_schema_nodeid(nodeid, start, LYS_NO_RPC_NOTIF_NODE, 1, 0, ret);
Michal Vasko3edeaf72016-02-11 13:17:43 +01001852}
1853
1854/* uses, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1855static int
1856resolve_uses_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node_grp **ret)
1857{
1858 const struct lys_module *module;
1859 const char *mod_prefix, *name;
1860 int i, mod_prefix_len, nam_len;
1861
1862 /* parse the identifier, it must be parsed on one call */
1863 if (((i = parse_node_identifier(nodeid, &mod_prefix, &mod_prefix_len, &name, &nam_len)) < 1) || nodeid[i]) {
1864 return -i + 1;
1865 }
1866
1867 module = lys_get_import_module(start->module, mod_prefix, mod_prefix_len, NULL, 0);
1868 if (!module) {
1869 return -1;
1870 }
1871 if (module != start->module) {
1872 start = module->data;
1873 }
1874
1875 *ret = lys_find_grouping_up(name, (struct lys_node *)start);
1876
1877 return EXIT_SUCCESS;
1878}
1879
1880int
1881resolve_absolute_schema_nodeid(const char *nodeid, const struct lys_module *module, int ret_nodetype,
1882 const struct lys_node **ret)
1883{
1884 const char *name, *mod_name, *id;
1885 const struct lys_node *sibling, *start;
1886 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001887 int8_t shorthand = 0;
Radek Krejcibdf92362016-04-08 14:43:34 +02001888 const struct lys_module *abs_start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001889
1890 assert(nodeid && module && ret);
1891 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1892
1893 id = nodeid;
1894 start = module->data;
1895
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001896 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 +01001897 return ((id - nodeid) - r) + 1;
1898 }
1899 id += r;
1900
1901 if (is_relative) {
1902 return -1;
1903 }
1904
1905 abs_start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001906 if (!abs_start_mod) {
1907 return -1;
1908 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001909
1910 while (1) {
1911 sibling = NULL;
1912 while ((sibling = lys_getnext(sibling, lys_parent(start), abs_start_mod, LYS_GETNEXT_WITHCHOICE
1913 | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_WITHGROUPING))) {
1914 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001915 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001916 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len, 0, &start);
Radek Krejcibdf92362016-04-08 14:43:34 +02001917 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001918 if (!(sibling->nodetype & ret_nodetype)) {
1919 /* wrong node type, too bad */
1920 continue;
1921 }
1922 *ret = sibling;
1923 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001924 } else if (r == 1) {
1925 continue;
1926 } else if (r == 2) {
1927 break;
1928 } else {
1929 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001930 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001931 }
1932 }
1933
1934 /* no match */
1935 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001936 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001937 return EXIT_SUCCESS;
1938 }
1939
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001940 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 +01001941 return ((id - nodeid) - r) + 1;
1942 }
1943 id += r;
1944 }
1945
1946 /* cannot get here */
1947 LOGINT;
1948 return -1;
1949}
1950
Michal Vaskoe733d682016-03-14 09:08:27 +01001951static int
Michal Vasko3547c532016-03-14 09:40:50 +01001952resolve_json_schema_list_predicate(const char *predicate, const struct lys_node_list *list, int *parsed)
Michal Vaskoe733d682016-03-14 09:08:27 +01001953{
1954 const char *name;
1955 int nam_len, has_predicate, i;
1956
Michal Vasko7b54f7e2016-05-03 15:07:31 +02001957 if (((i = parse_schema_json_predicate(predicate, &name, &nam_len, NULL, NULL, &has_predicate)) < 1)
1958 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001959 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-i], &predicate[-i]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001960 return -1;
1961 }
1962
1963 predicate += i;
1964 *parsed += i;
1965
1966 for (i = 0; i < list->keys_size; ++i) {
1967 if (!strncmp(list->keys[i]->name, name, nam_len) && !list->keys[i]->name[nam_len]) {
1968 break;
1969 }
1970 }
1971
1972 if (i == list->keys_size) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001973 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskoe733d682016-03-14 09:08:27 +01001974 return -1;
1975 }
1976
1977 /* more predicates? */
1978 if (has_predicate) {
Michal Vasko3547c532016-03-14 09:40:50 +01001979 return resolve_json_schema_list_predicate(predicate, list, parsed);
Michal Vaskoe733d682016-03-14 09:08:27 +01001980 }
1981
1982 return 0;
1983}
1984
Michal Vasko8d26e5c2016-09-08 10:03:49 +02001985/* cannot return LYS_GROUPING, LYS_AUGMENT, LYS_USES, logs directly */
Michal Vaskoe733d682016-03-14 09:08:27 +01001986const struct lys_node *
Michal Vasko8d26e5c2016-09-08 10:03:49 +02001987resolve_json_nodeid(const char *nodeid, struct ly_ctx *ctx, const struct lys_node *start)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001988{
Michal Vasko10728b52016-04-07 14:26:29 +02001989 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001990 const char *name, *mod_name, *id;
Michal Vasko3547c532016-03-14 09:40:50 +01001991 const struct lys_node *sibling;
Radek Krejcibdf92362016-04-08 14:43:34 +02001992 int r, nam_len, mod_name_len, is_relative = -1, has_predicate, shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001993 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vaskoe733d682016-03-14 09:08:27 +01001994 const struct lys_module *prefix_mod, *module, *prev_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001995
Michal Vasko3547c532016-03-14 09:40:50 +01001996 assert(nodeid && (ctx || start));
1997 if (!ctx) {
1998 ctx = start->module->ctx;
1999 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01002000
2001 id = nodeid;
2002
Michal Vaskoe733d682016-03-14 09:08:27 +01002003 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 +01002004 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002005 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002006 }
2007 id += r;
2008
2009 if (is_relative) {
Michal Vasko3547c532016-03-14 09:40:50 +01002010 assert(start);
2011 start = start->child;
2012 if (!start) {
2013 /* no descendants, fail for sure */
Michal Vasko10728b52016-04-07 14:26:29 +02002014 str = strndup(nodeid, (name + nam_len) - nodeid);
2015 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
2016 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002017 return NULL;
2018 }
2019 module = start->module;
2020 } else {
2021 if (!mod_name) {
Michal Vasko10728b52016-04-07 14:26:29 +02002022 str = strndup(nodeid, (name + nam_len) - nodeid);
2023 LOGVAL(LYE_PATH_MISSMOD, LY_VLOG_STR, nodeid);
2024 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002025 return NULL;
Michal Vasko971a3ca2016-04-01 13:09:29 +02002026 } else if (mod_name_len > LY_BUF_SIZE - 1) {
2027 LOGINT;
2028 return NULL;
Michal Vasko3547c532016-03-14 09:40:50 +01002029 }
2030
Michal Vasko971a3ca2016-04-01 13:09:29 +02002031 if (ly_buf_used && module_name[0]) {
2032 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2033 }
2034 ly_buf_used++;
2035
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002036 memmove(module_name, mod_name, mod_name_len);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002037 module_name[mod_name_len] = '\0';
2038 module = ly_ctx_get_module(ctx, module_name, NULL);
2039
2040 if (buf_backup) {
2041 /* return previous internal buffer content */
2042 strcpy(module_name, buf_backup);
2043 free(buf_backup);
2044 buf_backup = NULL;
2045 }
2046 ly_buf_used--;
2047
Michal Vasko3547c532016-03-14 09:40:50 +01002048 if (!module) {
Michal Vasko10728b52016-04-07 14:26:29 +02002049 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2050 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2051 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002052 return NULL;
2053 }
2054 start = module->data;
2055
2056 /* now it's as if there was no module name */
2057 mod_name = NULL;
2058 mod_name_len = 0;
Michal Vaskoe733d682016-03-14 09:08:27 +01002059 }
2060
Michal Vaskoe733d682016-03-14 09:08:27 +01002061 prev_mod = module;
2062
Michal Vasko3edeaf72016-02-11 13:17:43 +01002063 while (1) {
2064 sibling = NULL;
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002065 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
2066 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002067 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02002068 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002069 /* module check */
2070 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002071 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko8757e7c2016-03-15 10:41:30 +01002072 LOGINT;
2073 return NULL;
2074 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002075
2076 if (ly_buf_used && module_name[0]) {
2077 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2078 }
2079 ly_buf_used++;
2080
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002081 memmove(module_name, mod_name, mod_name_len);
Michal Vasko8757e7c2016-03-15 10:41:30 +01002082 module_name[mod_name_len] = '\0';
2083 /* will also find an augment module */
2084 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002085
2086 if (buf_backup) {
2087 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002088 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002089 free(buf_backup);
2090 buf_backup = NULL;
2091 }
2092 ly_buf_used--;
2093
Michal Vasko3edeaf72016-02-11 13:17:43 +01002094 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002095 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2096 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2097 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002098 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002099 }
2100 } else {
2101 prefix_mod = prev_mod;
2102 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01002103 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002104 continue;
2105 }
2106
Michal Vaskoe733d682016-03-14 09:08:27 +01002107 /* do we have some predicates on it? */
2108 if (has_predicate) {
2109 r = 0;
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002110 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
2111 if ((r = parse_schema_json_predicate(id, NULL, NULL, NULL, NULL, &has_predicate)) < 1) {
2112 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2113 return NULL;
2114 }
2115 } else if (sibling->nodetype == LYS_LIST) {
2116 if (resolve_json_schema_list_predicate(id, (const struct lys_node_list *)sibling, &r)) {
2117 return NULL;
2118 }
2119 } else {
Michal Vasko43c300e2016-03-22 12:54:27 +01002120 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vaskoe733d682016-03-14 09:08:27 +01002121 return NULL;
Michal Vaskoe733d682016-03-14 09:08:27 +01002122 }
2123 id += r;
2124 }
2125
Radek Krejcibdf92362016-04-08 14:43:34 +02002126 /* check for shorthand cases - then 'start' does not change */
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002127 if (lys_parent(sibling) && (lys_parent(sibling)->nodetype == LYS_CHOICE) && (sibling->nodetype != LYS_CASE)) {
Radek Krejcibdf92362016-04-08 14:43:34 +02002128 shorthand = ~shorthand;
2129 }
2130
Michal Vasko3edeaf72016-02-11 13:17:43 +01002131 /* the result node? */
2132 if (!id[0]) {
Radek Krejcibdf92362016-04-08 14:43:34 +02002133 if (shorthand) {
2134 /* wrong path for shorthand */
Michal Vasko025e0452016-05-17 16:14:20 +02002135 str = strndup(nodeid, (name + nam_len) - nodeid);
2136 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
Michal Vasko3c0f9f52016-05-17 16:38:10 +02002137 LOGVAL(LYE_SPEC, LY_VLOG_STR, str, "Schema shorthand case path must include the virtual case statement.");
Radek Krejci9a5fccc2016-05-18 15:44:58 +02002138 free(str);
Michal Vasko025e0452016-05-17 16:14:20 +02002139 return NULL;
Radek Krejcibdf92362016-04-08 14:43:34 +02002140 }
Michal Vaskoe733d682016-03-14 09:08:27 +01002141 return sibling;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002142 }
2143
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002144 if (!shorthand) {
Michal Vasko7dc71d02016-03-15 10:42:28 +01002145 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002146 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002147 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko7dc71d02016-03-15 10:42:28 +01002148 return NULL;
2149 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01002150 start = sibling->child;
2151 }
2152
2153 /* update prev mod */
2154 prev_mod = start->module;
2155 break;
2156 }
2157 }
2158
2159 /* no match */
2160 if (!sibling) {
Michal Vasko10728b52016-04-07 14:26:29 +02002161 str = strndup(nodeid, (name + nam_len) - nodeid);
2162 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
2163 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002164 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002165 }
2166
Michal Vaskoe733d682016-03-14 09:08:27 +01002167 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 +01002168 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002169 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002170 }
2171 id += r;
2172 }
2173
2174 /* cannot get here */
2175 LOGINT;
Michal Vaskoe733d682016-03-14 09:08:27 +01002176 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002177}
2178
Michal Vasko22448d32016-03-16 13:17:29 +01002179static int
2180resolve_partial_json_data_list_predicate(const char *predicate, const char *node_name, struct lyd_node *node, int *parsed)
2181{
2182 const char *name, *value;
2183 int nam_len, val_len, has_predicate = 1, r;
2184 uint16_t i;
Michal Vaskof29903d2016-04-18 13:13:10 +02002185 struct lyd_node_leaf_list *key;
Michal Vasko22448d32016-03-16 13:17:29 +01002186
Radek Krejci61a86c62016-03-24 11:06:44 +01002187 assert(node);
Michal Vasko22448d32016-03-16 13:17:29 +01002188 assert(node->schema->nodetype == LYS_LIST);
2189
Michal Vaskof29903d2016-04-18 13:13:10 +02002190 key = (struct lyd_node_leaf_list *)node->child;
2191 for (i = 0; i < ((struct lys_node_list *)node->schema)->keys_size; ++i) {
2192 if (!key) {
2193 /* invalid data */
2194 LOGINT;
2195 return -1;
2196 }
Michal Vasko22448d32016-03-16 13:17:29 +01002197
Michal Vasko22448d32016-03-16 13:17:29 +01002198 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002199 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, node_name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002200 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002201 }
2202
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002203 if (((r = parse_schema_json_predicate(predicate, &name, &nam_len, &value, &val_len, &has_predicate)) < 1)
2204 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002205 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
Michal Vaskof29903d2016-04-18 13:13:10 +02002206 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002207 }
2208
2209 predicate += r;
2210 *parsed += r;
2211
Michal Vaskof29903d2016-04-18 13:13:10 +02002212 if (strncmp(key->schema->name, name, nam_len) || key->schema->name[nam_len]) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002213 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002214 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002215 }
2216
2217 /* value does not match */
Michal Vaskof29903d2016-04-18 13:13:10 +02002218 if (strncmp(key->value_str, value, val_len) || key->value_str[val_len]) {
Michal Vasko22448d32016-03-16 13:17:29 +01002219 return 1;
2220 }
Michal Vaskof29903d2016-04-18 13:13:10 +02002221
2222 key = (struct lyd_node_leaf_list *)key->next;
Michal Vasko22448d32016-03-16 13:17:29 +01002223 }
2224
2225 if (has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002226 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko22448d32016-03-16 13:17:29 +01002227 return -1;
2228 }
2229
2230 return 0;
2231}
2232
Radek Krejci45826012016-08-24 15:07:57 +02002233/**
2234 * @brief get the closest parent of the node (or the node itself) identified by the nodeid (path)
2235 *
2236 * @param[in] nodeid Node data path to find
2237 * @param[in] llist_value If the \p nodeid identifies leaf-list, this is expected value of the leaf-list instance.
2238 * @param[in] options Bitmask of options flags, see @ref pathoptions.
2239 * @param[out] parsed Number of characters processed in \p id
2240 * @return The closes parent (or the node itself) from the path
2241 */
Michal Vasko22448d32016-03-16 13:17:29 +01002242struct lyd_node *
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002243resolve_partial_json_data_nodeid(const char *nodeid, const char *llist_value, struct lyd_node *start, int options,
2244 int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002245{
Michal Vasko10728b52016-04-07 14:26:29 +02002246 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002247 const char *id, *mod_name, *name, *pred_name;
2248 int r, ret, mod_name_len, nam_len, is_relative = -1;
2249 int has_predicate, last_parsed, val_len, pred_name_len, last_has_pred;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002250 struct lyd_node *sibling, *last_match = NULL;
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002251 struct lyd_node_leaf_list *llist;
Michal Vasko22448d32016-03-16 13:17:29 +01002252 const struct lys_module *prefix_mod, *prev_mod;
2253 struct ly_ctx *ctx;
2254
2255 assert(nodeid && start && parsed);
2256
2257 ctx = start->schema->module->ctx;
2258 id = nodeid;
2259
2260 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 +01002261 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002262 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002263 return NULL;
2264 }
2265 id += r;
2266 /* add it to parsed only after the data node was actually found */
2267 last_parsed = r;
2268
2269 if (is_relative) {
Michal Vasko1adc7242016-11-16 11:05:28 +01002270 prev_mod = lyd_node_module(start);
Michal Vasko22448d32016-03-16 13:17:29 +01002271 start = start->child;
2272 } else {
2273 for (; start->parent; start = start->parent);
Michal Vasko1adc7242016-11-16 11:05:28 +01002274 prev_mod = lyd_node_module(start);
Michal Vasko22448d32016-03-16 13:17:29 +01002275 }
2276
2277 while (1) {
2278 LY_TREE_FOR(start, sibling) {
Michal Vasko945b96b2016-10-18 11:49:12 +02002279 /* RPC/action data check, return simply invalid argument, because the data tree is invalid */
Michal Vasko2411b942016-03-23 13:50:03 +01002280 if (lys_parent(sibling->schema)) {
2281 if (options & LYD_PATH_OPT_OUTPUT) {
2282 if (lys_parent(sibling->schema)->nodetype == LYS_INPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002283 LOGERR(LY_EINVAL, "Provided data tree includes some RPC input nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002284 *parsed = -1;
2285 return NULL;
2286 }
2287 } else {
2288 if (lys_parent(sibling->schema)->nodetype == LYS_OUTPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002289 LOGERR(LY_EINVAL, "Provided data tree includes some RPC output nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002290 *parsed = -1;
2291 return NULL;
2292 }
2293 }
2294 }
2295
Michal Vasko22448d32016-03-16 13:17:29 +01002296 /* name match */
2297 if (!strncmp(name, sibling->schema->name, nam_len) && !sibling->schema->name[nam_len]) {
2298
2299 /* module check */
2300 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002301 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko22448d32016-03-16 13:17:29 +01002302 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002303 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002304 return NULL;
2305 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002306
2307 if (ly_buf_used && module_name[0]) {
2308 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2309 }
2310 ly_buf_used++;
2311
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002312 memmove(module_name, mod_name, mod_name_len);
Michal Vasko22448d32016-03-16 13:17:29 +01002313 module_name[mod_name_len] = '\0';
2314 /* will also find an augment module */
2315 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002316
2317 if (buf_backup) {
2318 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002319 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002320 free(buf_backup);
2321 buf_backup = NULL;
2322 }
2323 ly_buf_used--;
2324
Michal Vasko22448d32016-03-16 13:17:29 +01002325 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002326 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2327 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2328 free(str);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002329 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002330 return NULL;
2331 }
2332 } else {
2333 prefix_mod = prev_mod;
2334 }
Michal Vasko1adc7242016-11-16 11:05:28 +01002335 if (prefix_mod != lyd_node_module(sibling)) {
Michal Vasko22448d32016-03-16 13:17:29 +01002336 continue;
2337 }
2338
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002339 /* leaf-list, did we find it with the correct value or not? */
Michal Vasko22448d32016-03-16 13:17:29 +01002340 if (sibling->schema->nodetype == LYS_LEAFLIST) {
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002341 last_has_pred = 0;
Michal Vaskof0a50972016-10-19 11:33:55 +02002342 if (has_predicate) {
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002343 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 +02002344 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2345 *parsed = -1;
2346 return NULL;
2347 }
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002348 if ((pred_name[0] != '.') || (pred_name_len != 1)) {
2349 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[1], id + 1);
2350 *parsed = -1;
2351 return NULL;
2352 }
Michal Vaskof0a50972016-10-19 11:33:55 +02002353 } else {
2354 r = 0;
2355 if (llist_value) {
2356 val_len = strlen(llist_value);
2357 } else {
2358 val_len = 0;
2359 }
2360 }
2361
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002362 llist = (struct lyd_node_leaf_list *)sibling;
Michal Vaskof0a50972016-10-19 11:33:55 +02002363 if ((!val_len && llist->value_str && llist->value_str[0])
2364 || (val_len && (strncmp(llist_value, llist->value_str, val_len) || llist->value_str[val_len]))) {
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002365 continue;
2366 }
Michal Vaskof0a50972016-10-19 11:33:55 +02002367 id += r;
2368 last_parsed += r;
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002369 has_predicate = last_has_pred;
Michal Vaskof0a50972016-10-19 11:33:55 +02002370
Radek Krejci45826012016-08-24 15:07:57 +02002371 } else if (sibling->schema->nodetype == LYS_LIST) {
2372 /* list, we need predicates'n'stuff then */
Michal Vasko22448d32016-03-16 13:17:29 +01002373 r = 0;
2374 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002375 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002376 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002377 return NULL;
2378 }
2379 ret = resolve_partial_json_data_list_predicate(id, name, sibling, &r);
2380 if (ret == -1) {
Michal Vasko238bd2f2016-03-23 09:39:01 +01002381 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002382 return NULL;
2383 } else if (ret == 1) {
2384 /* this list instance does not match */
2385 continue;
2386 }
2387 id += r;
2388 last_parsed += r;
2389 }
2390
2391 *parsed += last_parsed;
2392
2393 /* the result node? */
2394 if (!id[0]) {
2395 return sibling;
2396 }
2397
2398 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002399 if (sibling->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002400 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002401 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002402 return NULL;
2403 }
Michal Vaskoc6c52cf2016-03-29 11:53:04 +02002404 last_match = sibling;
Michal Vaskofc11b682016-11-18 09:52:41 +01002405 prev_mod = lyd_node_module(sibling);
Michal Vasko22448d32016-03-16 13:17:29 +01002406 start = sibling->child;
Michal Vasko22448d32016-03-16 13:17:29 +01002407 break;
2408 }
2409 }
2410
2411 /* no match, return last match */
2412 if (!sibling) {
2413 return last_match;
2414 }
2415
2416 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 +01002417 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002418 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002419 return NULL;
2420 }
2421 id += r;
2422 last_parsed = r;
2423 }
2424
2425 /* cannot get here */
2426 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002427 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002428 return NULL;
2429}
2430
Michal Vasko3edeaf72016-02-11 13:17:43 +01002431/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02002432 * @brief Resolves length or range intervals. Does not log.
Michal Vaskoaeb51802016-04-11 10:58:47 +02002433 * Syntax is assumed to be correct, *ret MUST be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002434 *
Michal Vaskoaeb51802016-04-11 10:58:47 +02002435 * @param[in] str_restr Restriction as a string.
2436 * @param[in] type Type of the restriction.
2437 * @param[out] ret Final interval structure that starts with
2438 * the interval of the initial type, continues with intervals
2439 * of any superior types derived from the initial one, and
2440 * finishes with intervals from our \p type.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002441 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002442 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002443 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002444int
Michal Vaskoaeb51802016-04-11 10:58:47 +02002445resolve_len_ran_interval(const char *str_restr, struct lys_type *type, struct len_ran_intv **ret)
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002446{
2447 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002448 int kind;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002449 int64_t local_smin, local_smax, local_fmin, local_fmax;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002450 uint64_t local_umin, local_umax;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002451 uint8_t local_fdig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002452 const char *seg_ptr, *ptr;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002453 struct len_ran_intv *local_intv = NULL, *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002454
2455 switch (type->base) {
2456 case LY_TYPE_BINARY:
2457 kind = 0;
2458 local_umin = 0;
2459 local_umax = 18446744073709551615UL;
2460
2461 if (!str_restr && type->info.binary.length) {
2462 str_restr = type->info.binary.length->expr;
2463 }
2464 break;
2465 case LY_TYPE_DEC64:
2466 kind = 2;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002467 local_fmin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2468 local_fmax = __INT64_C(9223372036854775807);
2469 local_fdig = type->info.dec64.dig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002470
2471 if (!str_restr && type->info.dec64.range) {
2472 str_restr = type->info.dec64.range->expr;
2473 }
2474 break;
2475 case LY_TYPE_INT8:
2476 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002477 local_smin = __INT64_C(-128);
2478 local_smax = __INT64_C(127);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002479
2480 if (!str_restr && type->info.num.range) {
2481 str_restr = type->info.num.range->expr;
2482 }
2483 break;
2484 case LY_TYPE_INT16:
2485 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002486 local_smin = __INT64_C(-32768);
2487 local_smax = __INT64_C(32767);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002488
2489 if (!str_restr && type->info.num.range) {
2490 str_restr = type->info.num.range->expr;
2491 }
2492 break;
2493 case LY_TYPE_INT32:
2494 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002495 local_smin = __INT64_C(-2147483648);
2496 local_smax = __INT64_C(2147483647);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002497
2498 if (!str_restr && type->info.num.range) {
2499 str_restr = type->info.num.range->expr;
2500 }
2501 break;
2502 case LY_TYPE_INT64:
2503 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002504 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2505 local_smax = __INT64_C(9223372036854775807);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002506
2507 if (!str_restr && type->info.num.range) {
2508 str_restr = type->info.num.range->expr;
2509 }
2510 break;
2511 case LY_TYPE_UINT8:
2512 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002513 local_umin = __UINT64_C(0);
2514 local_umax = __UINT64_C(255);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002515
2516 if (!str_restr && type->info.num.range) {
2517 str_restr = type->info.num.range->expr;
2518 }
2519 break;
2520 case LY_TYPE_UINT16:
2521 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002522 local_umin = __UINT64_C(0);
2523 local_umax = __UINT64_C(65535);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002524
2525 if (!str_restr && type->info.num.range) {
2526 str_restr = type->info.num.range->expr;
2527 }
2528 break;
2529 case LY_TYPE_UINT32:
2530 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002531 local_umin = __UINT64_C(0);
2532 local_umax = __UINT64_C(4294967295);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002533
2534 if (!str_restr && type->info.num.range) {
2535 str_restr = type->info.num.range->expr;
2536 }
2537 break;
2538 case LY_TYPE_UINT64:
2539 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002540 local_umin = __UINT64_C(0);
2541 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002542
2543 if (!str_restr && type->info.num.range) {
2544 str_restr = type->info.num.range->expr;
2545 }
2546 break;
2547 case LY_TYPE_STRING:
2548 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002549 local_umin = __UINT64_C(0);
2550 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002551
2552 if (!str_restr && type->info.str.length) {
2553 str_restr = type->info.str.length->expr;
2554 }
2555 break;
2556 default:
2557 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002558 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002559 }
2560
2561 /* process superior types */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002562 if (type->der) {
2563 if (resolve_len_ran_interval(NULL, &type->der->type, &intv)) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002564 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002565 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02002566 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002567 assert(!intv || (intv->kind == kind));
2568 }
2569
2570 if (!str_restr) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002571 /* we do not have any restriction, return superior ones */
2572 *ret = intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002573 return EXIT_SUCCESS;
2574 }
2575
2576 /* adjust local min and max */
2577 if (intv) {
2578 tmp_intv = intv;
2579
2580 if (kind == 0) {
2581 local_umin = tmp_intv->value.uval.min;
2582 } else if (kind == 1) {
2583 local_smin = tmp_intv->value.sval.min;
2584 } else if (kind == 2) {
2585 local_fmin = tmp_intv->value.fval.min;
2586 }
2587
2588 while (tmp_intv->next) {
2589 tmp_intv = tmp_intv->next;
2590 }
2591
2592 if (kind == 0) {
2593 local_umax = tmp_intv->value.uval.max;
2594 } else if (kind == 1) {
2595 local_smax = tmp_intv->value.sval.max;
2596 } else if (kind == 2) {
2597 local_fmax = tmp_intv->value.fval.max;
2598 }
2599 }
2600
2601 /* finally parse our restriction */
2602 seg_ptr = str_restr;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002603 tmp_intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002604 while (1) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002605 if (!tmp_local_intv) {
2606 assert(!local_intv);
2607 local_intv = malloc(sizeof *local_intv);
2608 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002609 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002610 tmp_local_intv->next = malloc(sizeof *tmp_local_intv);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002611 tmp_local_intv = tmp_local_intv->next;
2612 }
Michal Vasko253035f2015-12-17 16:58:13 +01002613 if (!tmp_local_intv) {
2614 LOGMEM;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002615 goto error;
Michal Vasko253035f2015-12-17 16:58:13 +01002616 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002617
2618 tmp_local_intv->kind = kind;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002619 tmp_local_intv->type = type;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002620 tmp_local_intv->next = NULL;
2621
2622 /* min */
2623 ptr = seg_ptr;
2624 while (isspace(ptr[0])) {
2625 ++ptr;
2626 }
2627 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2628 if (kind == 0) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002629 tmp_local_intv->value.uval.min = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002630 } else if (kind == 1) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002631 tmp_local_intv->value.sval.min = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002632 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002633 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.min)) {
2634 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2635 goto error;
2636 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002637 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002638 } else if (!strncmp(ptr, "min", 3)) {
2639 if (kind == 0) {
2640 tmp_local_intv->value.uval.min = local_umin;
2641 } else if (kind == 1) {
2642 tmp_local_intv->value.sval.min = local_smin;
2643 } else if (kind == 2) {
2644 tmp_local_intv->value.fval.min = local_fmin;
2645 }
2646
2647 ptr += 3;
2648 } else if (!strncmp(ptr, "max", 3)) {
2649 if (kind == 0) {
2650 tmp_local_intv->value.uval.min = local_umax;
2651 } else if (kind == 1) {
2652 tmp_local_intv->value.sval.min = local_smax;
2653 } else if (kind == 2) {
2654 tmp_local_intv->value.fval.min = local_fmax;
2655 }
2656
2657 ptr += 3;
2658 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002659 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002660 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002661 }
2662
2663 while (isspace(ptr[0])) {
2664 ptr++;
2665 }
2666
2667 /* no interval or interval */
2668 if ((ptr[0] == '|') || !ptr[0]) {
2669 if (kind == 0) {
2670 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
2671 } else if (kind == 1) {
2672 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
2673 } else if (kind == 2) {
2674 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
2675 }
2676 } else if (!strncmp(ptr, "..", 2)) {
2677 /* skip ".." */
2678 ptr += 2;
2679 while (isspace(ptr[0])) {
2680 ++ptr;
2681 }
2682
2683 /* max */
2684 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2685 if (kind == 0) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002686 tmp_local_intv->value.uval.max = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002687 } else if (kind == 1) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002688 tmp_local_intv->value.sval.max = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002689 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002690 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.max)) {
2691 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2692 goto error;
2693 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002694 }
2695 } else if (!strncmp(ptr, "max", 3)) {
2696 if (kind == 0) {
2697 tmp_local_intv->value.uval.max = local_umax;
2698 } else if (kind == 1) {
2699 tmp_local_intv->value.sval.max = local_smax;
2700 } else if (kind == 2) {
2701 tmp_local_intv->value.fval.max = local_fmax;
2702 }
2703 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002704 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002705 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002706 }
2707 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002708 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002709 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002710 }
2711
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002712 /* check min and max in correct order*/
2713 if (kind == 0) {
2714 /* current segment */
2715 if (tmp_local_intv->value.uval.min > tmp_local_intv->value.uval.max) {
2716 goto error;
2717 }
2718 if (tmp_local_intv->value.uval.min < local_umin || tmp_local_intv->value.uval.max > local_umax) {
2719 goto error;
2720 }
2721 /* segments sholud be ascending order */
Pavol Vican69f62c92016-08-30 09:06:25 +02002722 if (tmp_intv && (tmp_intv->value.uval.max >= tmp_local_intv->value.uval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002723 goto error;
2724 }
2725 } else if (kind == 1) {
2726 if (tmp_local_intv->value.sval.min > tmp_local_intv->value.sval.max) {
2727 goto error;
2728 }
2729 if (tmp_local_intv->value.sval.min < local_smin || tmp_local_intv->value.sval.max > local_smax) {
2730 goto error;
2731 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002732 if (tmp_intv && (tmp_intv->value.sval.max >= tmp_local_intv->value.sval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002733 goto error;
2734 }
2735 } else if (kind == 2) {
2736 if (tmp_local_intv->value.fval.min > tmp_local_intv->value.fval.max) {
2737 goto error;
2738 }
2739 if (tmp_local_intv->value.fval.min < local_fmin || tmp_local_intv->value.fval.max > local_fmax) {
2740 goto error;
2741 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002742 if (tmp_intv && (tmp_intv->value.fval.max >= tmp_local_intv->value.fval.min)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002743 /* fraction-digits value is always the same (it cannot be changed in derived types) */
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002744 goto error;
2745 }
2746 }
2747
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002748 /* next segment (next OR) */
2749 seg_ptr = strchr(seg_ptr, '|');
2750 if (!seg_ptr) {
2751 break;
2752 }
2753 seg_ptr++;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002754 tmp_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002755 }
2756
2757 /* check local restrictions against superior ones */
2758 if (intv) {
2759 tmp_intv = intv;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002760 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002761
2762 while (tmp_local_intv && tmp_intv) {
2763 /* reuse local variables */
2764 if (kind == 0) {
2765 local_umin = tmp_local_intv->value.uval.min;
2766 local_umax = tmp_local_intv->value.uval.max;
2767
2768 /* it must be in this interval */
2769 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
2770 /* this interval is covered, next one */
2771 if (local_umax <= tmp_intv->value.uval.max) {
2772 tmp_local_intv = tmp_local_intv->next;
2773 continue;
2774 /* ascending order of restrictions -> fail */
2775 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002776 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002777 }
2778 }
2779 } else if (kind == 1) {
2780 local_smin = tmp_local_intv->value.sval.min;
2781 local_smax = tmp_local_intv->value.sval.max;
2782
2783 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
2784 if (local_smax <= tmp_intv->value.sval.max) {
2785 tmp_local_intv = tmp_local_intv->next;
2786 continue;
2787 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002788 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002789 }
2790 }
2791 } else if (kind == 2) {
2792 local_fmin = tmp_local_intv->value.fval.min;
2793 local_fmax = tmp_local_intv->value.fval.max;
2794
Michal Vasko4d1f0482016-09-19 14:35:06 +02002795 if ((dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.min, local_fdig) > -1)
Pavol Vican3c8ee2b2016-09-29 13:18:13 +02002796 && (dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002797 if (dec64cmp(local_fmax, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002798 tmp_local_intv = tmp_local_intv->next;
2799 continue;
2800 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002801 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002802 }
2803 }
2804 }
2805
2806 tmp_intv = tmp_intv->next;
2807 }
2808
2809 /* some interval left uncovered -> fail */
2810 if (tmp_local_intv) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002811 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002812 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002813 }
2814
Michal Vaskoaeb51802016-04-11 10:58:47 +02002815 /* append the local intervals to all the intervals of the superior types, return it all */
2816 if (intv) {
2817 for (tmp_intv = intv; tmp_intv->next; tmp_intv = tmp_intv->next);
2818 tmp_intv->next = local_intv;
2819 } else {
2820 intv = local_intv;
2821 }
2822 *ret = intv;
2823
2824 return EXIT_SUCCESS;
2825
2826error:
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002827 while (intv) {
2828 tmp_intv = intv->next;
2829 free(intv);
2830 intv = tmp_intv;
2831 }
Michal Vaskoaeb51802016-04-11 10:58:47 +02002832 while (local_intv) {
2833 tmp_local_intv = local_intv->next;
2834 free(local_intv);
2835 local_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002836 }
2837
Michal Vaskoaeb51802016-04-11 10:58:47 +02002838 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002839}
2840
Michal Vasko730dfdf2015-08-11 14:48:05 +02002841/**
Michal Vasko01c6fd22016-05-20 11:43:05 +02002842 * @brief Resolve a typedef, return only resolved typedefs if derived. If leafref, it must be
2843 * resolved for this function to return it. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002844 *
2845 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02002846 * @param[in] mod_name Typedef name module name.
2847 * @param[in] module Main module.
2848 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002849 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002850 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002851 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002852 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002853int
Michal Vasko1e62a092015-12-01 12:27:20 +01002854resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
2855 const struct lys_node *parent, struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002856{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002857 int i, j;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002858 struct lys_tpdf *tpdf, *match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002859 int tpdf_size;
2860
Michal Vasko1dca6882015-10-22 14:29:42 +02002861 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002862 /* no prefix, try built-in types */
2863 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
2864 if (!strcmp(ly_types[i].def->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002865 if (ret) {
2866 *ret = ly_types[i].def;
2867 }
2868 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002869 }
2870 }
2871 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02002872 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002873 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02002874 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002875 }
2876 }
2877
Michal Vasko1dca6882015-10-22 14:29:42 +02002878 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002879 /* search in local typedefs */
2880 while (parent) {
2881 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02002882 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02002883 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
2884 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002885 break;
2886
Radek Krejci76512572015-08-04 09:47:08 +02002887 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02002888 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
2889 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002890 break;
2891
Radek Krejci76512572015-08-04 09:47:08 +02002892 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02002893 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
2894 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002895 break;
2896
Radek Krejci76512572015-08-04 09:47:08 +02002897 case LYS_RPC:
Michal Vasko44fb6382016-06-29 11:12:27 +02002898 case LYS_ACTION:
2899 tpdf_size = ((struct lys_node_rpc_action *)parent)->tpdf_size;
2900 tpdf = ((struct lys_node_rpc_action *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002901 break;
2902
Radek Krejci76512572015-08-04 09:47:08 +02002903 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02002904 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
2905 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002906 break;
2907
Radek Krejci76512572015-08-04 09:47:08 +02002908 case LYS_INPUT:
2909 case LYS_OUTPUT:
Michal Vasko44fb6382016-06-29 11:12:27 +02002910 tpdf_size = ((struct lys_node_inout *)parent)->tpdf_size;
2911 tpdf = ((struct lys_node_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002912 break;
2913
2914 default:
Michal Vaskodcf98e62016-05-05 17:53:53 +02002915 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002916 continue;
2917 }
2918
2919 for (i = 0; i < tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002920 if (!strcmp(tpdf[i].name, name) && tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002921 match = &tpdf[i];
2922 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002923 }
2924 }
2925
Michal Vaskodcf98e62016-05-05 17:53:53 +02002926 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002927 }
Radek Krejcic071c542016-01-27 14:57:51 +01002928 } else {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002929 /* get module where to search */
Michal Vaskob6729c62015-10-21 12:09:47 +02002930 module = lys_get_import_module(module, NULL, 0, mod_name, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02002931 if (!module) {
2932 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002933 }
2934 }
2935
2936 /* search in top level typedefs */
2937 for (i = 0; i < module->tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002938 if (!strcmp(module->tpdf[i].name, name) && module->tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002939 match = &module->tpdf[i];
2940 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002941 }
2942 }
2943
2944 /* search in submodules */
Radek Krejcic071c542016-01-27 14:57:51 +01002945 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002946 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002947 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 +02002948 match = &module->inc[i].submodule->tpdf[j];
2949 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002950 }
2951 }
2952 }
2953
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002954 return EXIT_FAILURE;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002955
2956check_leafref:
2957 if (ret) {
2958 *ret = match;
2959 }
2960 if (match->type.base == LY_TYPE_LEAFREF) {
2961 while (!match->type.info.lref.path) {
2962 match = match->type.der;
2963 assert(match);
2964 }
Michal Vasko01c6fd22016-05-20 11:43:05 +02002965 }
2966 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002967}
2968
Michal Vasko1dca6882015-10-22 14:29:42 +02002969/**
2970 * @brief Check the default \p value of the \p type. Logs directly.
2971 *
2972 * @param[in] type Type definition to use.
2973 * @param[in] value Default value to check.
Michal Vasko56826402016-03-02 11:11:37 +01002974 * @param[in] module Type module.
Michal Vasko1dca6882015-10-22 14:29:42 +02002975 *
2976 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
2977 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002978static int
Radek Krejci51673202016-11-01 17:00:32 +01002979check_default(struct lys_type *type, const char **value, struct lys_module *module)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002980{
Radek Krejcibad2f172016-08-02 11:04:15 +02002981 struct lys_tpdf *base_tpdf = NULL;
Michal Vasko1dca6882015-10-22 14:29:42 +02002982 struct lyd_node_leaf_list node;
Radek Krejci51673202016-11-01 17:00:32 +01002983 const char *dflt = NULL;
Radek Krejci37b756f2016-01-18 10:15:03 +01002984 int ret = EXIT_SUCCESS;
Michal Vasko1dca6882015-10-22 14:29:42 +02002985
Radek Krejci51673202016-11-01 17:00:32 +01002986 assert(value);
2987
Radek Krejcic13db382016-08-16 10:52:42 +02002988 if (type->base <= LY_TYPE_DER) {
Michal Vasko478c4652016-07-21 12:55:01 +02002989 /* the type was not resolved yet, nothing to do for now */
2990 return EXIT_FAILURE;
2991 }
2992
Radek Krejci51673202016-11-01 17:00:32 +01002993 dflt = *value;
2994 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02002995 /* we do not have a new default value, so is there any to check even, in some base type? */
2996 for (base_tpdf = type->der; base_tpdf->type.der; base_tpdf = base_tpdf->type.der) {
2997 if (base_tpdf->dflt) {
Radek Krejci51673202016-11-01 17:00:32 +01002998 dflt = base_tpdf->dflt;
Michal Vasko478c4652016-07-21 12:55:01 +02002999 break;
3000 }
3001 }
3002
Radek Krejci51673202016-11-01 17:00:32 +01003003 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003004 /* no default value, nothing to check, all is well */
3005 return EXIT_SUCCESS;
3006 }
3007
3008 /* 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)? */
3009 switch (type->base) {
Michal Vasko478c4652016-07-21 12:55:01 +02003010 case LY_TYPE_IDENT:
3011 case LY_TYPE_INST:
3012 case LY_TYPE_LEAFREF:
3013 case LY_TYPE_BOOL:
3014 case LY_TYPE_EMPTY:
3015 /* these have no restrictions, so we would do the exact same work as the unres in the base typedef */
3016 return EXIT_SUCCESS;
Radek Krejcibad2f172016-08-02 11:04:15 +02003017 case LY_TYPE_BITS:
3018 /* the default value must match the restricted list of values, if the type was restricted */
3019 if (type->info.bits.count) {
3020 break;
3021 }
3022 return EXIT_SUCCESS;
3023 case LY_TYPE_ENUM:
3024 /* the default value must match the restricted list of values, if the type was restricted */
3025 if (type->info.enums.count) {
3026 break;
3027 }
3028 return EXIT_SUCCESS;
Michal Vasko478c4652016-07-21 12:55:01 +02003029 case LY_TYPE_DEC64:
3030 if (type->info.dec64.range) {
3031 break;
3032 }
3033 return EXIT_SUCCESS;
3034 case LY_TYPE_BINARY:
3035 if (type->info.binary.length) {
3036 break;
3037 }
3038 return EXIT_SUCCESS;
3039 case LY_TYPE_INT8:
3040 case LY_TYPE_INT16:
3041 case LY_TYPE_INT32:
3042 case LY_TYPE_INT64:
3043 case LY_TYPE_UINT8:
3044 case LY_TYPE_UINT16:
3045 case LY_TYPE_UINT32:
3046 case LY_TYPE_UINT64:
3047 if (type->info.num.range) {
3048 break;
3049 }
3050 return EXIT_SUCCESS;
3051 case LY_TYPE_STRING:
3052 if (type->info.str.length || type->info.str.patterns) {
3053 break;
3054 }
3055 return EXIT_SUCCESS;
3056 case LY_TYPE_UNION:
3057 /* way too much trouble learning whether we need to check the default again, so just do it */
3058 break;
3059 default:
3060 LOGINT;
3061 return -1;
3062 }
Radek Krejci55a161c2016-09-05 17:13:25 +02003063 } else if (type->base == LY_TYPE_EMPTY) {
3064 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "default", type->parent->name);
3065 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"empty\" data type cannot have a default value.");
3066 return -1;
Michal Vasko478c4652016-07-21 12:55:01 +02003067 }
3068
Michal Vasko1dca6882015-10-22 14:29:42 +02003069 /* dummy leaf */
Radek Krejci4fe36bd2016-03-17 16:47:16 +01003070 memset(&node, 0, sizeof node);
Radek Krejci51673202016-11-01 17:00:32 +01003071 node.value_str = dflt;
Michal Vasko1dca6882015-10-22 14:29:42 +02003072 node.value_type = type->base;
Radek Krejci37b756f2016-01-18 10:15:03 +01003073 node.schema = calloc(1, sizeof (struct lys_node_leaf));
Michal Vasko253035f2015-12-17 16:58:13 +01003074 if (!node.schema) {
3075 LOGMEM;
3076 return -1;
3077 }
Radek Krejcibad2f172016-08-02 11:04:15 +02003078 node.schema->name = strdup("fake-default");
Michal Vasko253035f2015-12-17 16:58:13 +01003079 if (!node.schema->name) {
3080 LOGMEM;
Michal Vaskof49eda02016-07-21 12:17:01 +02003081 free(node.schema);
Michal Vasko253035f2015-12-17 16:58:13 +01003082 return -1;
3083 }
Michal Vasko56826402016-03-02 11:11:37 +01003084 node.schema->module = module;
Radek Krejci37b756f2016-01-18 10:15:03 +01003085 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
Michal Vasko1dca6882015-10-22 14:29:42 +02003086
Radek Krejci37b756f2016-01-18 10:15:03 +01003087 if (type->base == LY_TYPE_LEAFREF) {
Michal Vasko1dca6882015-10-22 14:29:42 +02003088 if (!type->info.lref.target) {
3089 ret = EXIT_FAILURE;
3090 goto finish;
3091 }
Radek Krejci51673202016-11-01 17:00:32 +01003092 ret = check_default(&type->info.lref.target->type, &dflt, module);
3093 if (!ret) {
3094 /* adopt possibly changed default value to its canonical form */
3095 if (*value) {
3096 *value = dflt;
3097 }
3098 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003099 } else {
Radek Krejci1899d6a2016-11-03 13:48:07 +01003100 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 +01003101 /* possible forward reference */
3102 ret = 1;
Radek Krejcibad2f172016-08-02 11:04:15 +02003103 if (base_tpdf) {
Radek Krejci9ad23f42016-10-31 15:46:52 +01003104 /* default value is defined in some base typedef */
Radek Krejcibad2f172016-08-02 11:04:15 +02003105 if ((type->base == LY_TYPE_BITS && type->der->type.der) ||
3106 (type->base == LY_TYPE_ENUM && type->der->type.der)) {
3107 /* we have refined bits/enums */
3108 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
3109 "Invalid value \"%s\" of the default statement inherited to \"%s\" from \"%s\" base type.",
Radek Krejci51673202016-11-01 17:00:32 +01003110 dflt, type->parent->name, base_tpdf->name);
Radek Krejcibad2f172016-08-02 11:04:15 +02003111 }
3112 }
Radek Krejci51673202016-11-01 17:00:32 +01003113 } else {
3114 /* success - adopt canonical form from the node into the default value */
3115 if (dflt != node.value_str) {
3116 /* this can happen only if we have non-inherited default value,
3117 * inherited default values are already in canonical form */
3118 assert(dflt == *value);
3119 *value = node.value_str;
3120 }
Michal Vasko3767fb22016-07-21 12:10:57 +02003121 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003122 }
3123
3124finish:
3125 if (node.value_type == LY_TYPE_BITS) {
3126 free(node.value.bit);
3127 }
3128 free((char *)node.schema->name);
3129 free(node.schema);
3130
3131 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003132}
3133
Michal Vasko730dfdf2015-08-11 14:48:05 +02003134/**
3135 * @brief Check a key for mandatory attributes. Logs directly.
3136 *
3137 * @param[in] key The key to check.
3138 * @param[in] flags What flags to check.
3139 * @param[in] list The list of all the keys.
3140 * @param[in] index Index of the key in the key list.
3141 * @param[in] name The name of the keys.
3142 * @param[in] len The name length.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003143 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003144 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003145 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003146static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003147check_key(struct lys_node_list *list, int index, const char *name, int len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003148{
Radek Krejciadb57612016-02-16 13:34:34 +01003149 struct lys_node_leaf *key = list->keys[index];
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003150 char *dup = NULL;
3151 int j;
3152
3153 /* existence */
3154 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02003155 if (name[len] != '\0') {
3156 dup = strdup(name);
Michal Vasko253035f2015-12-17 16:58:13 +01003157 if (!dup) {
3158 LOGMEM;
3159 return -1;
3160 }
Michal Vaskof02e3742015-08-05 16:27:02 +02003161 dup[len] = '\0';
3162 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003163 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003164 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, list, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003165 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003166 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003167 }
3168
3169 /* uniqueness */
3170 for (j = index - 1; j >= 0; j--) {
Radek Krejciadb57612016-02-16 13:34:34 +01003171 if (key == list->keys[j]) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003172 LOGVAL(LYE_KEY_DUP, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003173 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003174 }
3175 }
3176
3177 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02003178 if (key->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003179 LOGVAL(LYE_KEY_NLEAF, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003180 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003181 }
3182
3183 /* type of the leaf is not built-in empty */
Radek Krejcic3738db2016-09-15 15:51:21 +02003184 if (key->type.base == LY_TYPE_EMPTY && key->module->version < 2) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003185 LOGVAL(LYE_KEY_TYPE, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003186 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003187 }
3188
3189 /* config attribute is the same as of the list */
Radek Krejci5c08a992016-11-02 13:30:04 +01003190 if ((key->flags & LYS_CONFIG_MASK) && (list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003191 LOGVAL(LYE_KEY_CONFIG, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003192 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003193 }
3194
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003195 /* key is not placed from augment */
3196 if (key->parent->nodetype == LYS_AUGMENT) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003197 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, key, key->name);
3198 LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key inserted from augment.");
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003199 return -1;
3200 }
3201
Radek Krejci3f21ada2016-08-01 13:34:31 +02003202 /* key is not when/if-feature -conditional */
3203 j = 0;
3204 if (key->when || (key->iffeature_size && (j = 1))) {
3205 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, key, j ? "if-feature" : "when", "leaf");
3206 LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key definition cannot depend on a \"%s\" condition.",
3207 j ? "if-feature" : "when");
Radek Krejci581ce772015-11-10 17:22:40 +01003208 return -1;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003209 }
3210
Michal Vasko0b85aa82016-03-07 14:37:43 +01003211 return EXIT_SUCCESS;
Michal Vasko184521f2015-09-24 13:14:26 +02003212}
Michal Vasko730dfdf2015-08-11 14:48:05 +02003213
3214/**
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003215 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003216 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003217 * @param[in] parent The parent node of the unique structure.
Michal Vasko0b85aa82016-03-07 14:37:43 +01003218 * @param[in] uniq_str_path One path from the unique string.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003219 *
3220 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
3221 */
3222int
Radek Krejcid09d1a52016-08-11 14:05:45 +02003223resolve_unique(struct lys_node *parent, const char *uniq_str_path, uint8_t *trg_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003224{
Radek Krejci581ce772015-11-10 17:22:40 +01003225 int rc;
Michal Vasko1e62a092015-12-01 12:27:20 +01003226 const struct lys_node *leaf = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003227
Radek Krejcif3c71de2016-04-11 12:45:46 +02003228 rc = resolve_descendant_schema_nodeid(uniq_str_path, parent->child, LYS_LEAF, 1, 1, &leaf);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003229 if (rc || !leaf) {
Michal Vasko0b85aa82016-03-07 14:37:43 +01003230 if (rc) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003231 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003232 if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003233 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, parent, uniq_str_path[rc - 1], &uniq_str_path[rc - 1]);
Radek Krejcif3c71de2016-04-11 12:45:46 +02003234 } else if (rc == -2) {
Michal Vaskoc66c6d82016-04-12 11:37:31 +02003235 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Unique argument references list.");
Radek Krejci581ce772015-11-10 17:22:40 +01003236 }
Michal Vasko0b85aa82016-03-07 14:37:43 +01003237 rc = -1;
Michal Vasko0b85aa82016-03-07 14:37:43 +01003238 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01003239 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3240 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target leaf not found.");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003241 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003242 }
Radek Krejci581ce772015-11-10 17:22:40 +01003243 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003244 }
Michal Vasko9bb061b2016-02-12 11:00:19 +01003245 if (leaf->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003246 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3247 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target is not a leaf.");
Radek Krejcid09d1a52016-08-11 14:05:45 +02003248 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003249 }
3250
Radek Krejcicf509982015-12-15 09:22:44 +01003251 /* check status */
Radek Krejci48464ed2016-03-17 15:44:09 +01003252 if (lyp_check_status(parent->flags, parent->module, parent->name, leaf->flags, leaf->module, leaf->name, leaf)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003253 return -1;
3254 }
3255
Radek Krejcid09d1a52016-08-11 14:05:45 +02003256 /* check that all unique's targets are of the same config type */
3257 if (*trg_type) {
3258 if (((*trg_type == 1) && (leaf->flags & LYS_CONFIG_R)) || ((*trg_type == 2) && (leaf->flags & LYS_CONFIG_W))) {
3259 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3260 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent,
3261 "Leaf \"%s\" referenced in unique statement is config %s, but previous referenced leaf is config %s.",
3262 uniq_str_path, *trg_type == 1 ? "false" : "true", *trg_type == 1 ? "true" : "false");
3263 return -1;
3264 }
3265 } else {
3266 /* first unique */
3267 if (leaf->flags & LYS_CONFIG_W) {
3268 *trg_type = 1;
3269 } else {
3270 *trg_type = 2;
3271 }
3272 }
3273
Radek Krejcica7efb72016-01-18 13:06:01 +01003274 /* set leaf's unique flag */
3275 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
3276
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003277 return EXIT_SUCCESS;
3278
3279error:
3280
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003281 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003282}
3283
Radek Krejci0c0086a2016-03-24 15:20:28 +01003284void
Michal Vasko23b61ec2015-08-19 11:19:50 +02003285unres_data_del(struct unres_data *unres, uint32_t i)
3286{
3287 /* there are items after the one deleted */
3288 if (i+1 < unres->count) {
3289 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02003290 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003291
3292 /* deleting the last item */
3293 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02003294 free(unres->node);
3295 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003296 }
3297
3298 /* if there are no items after and it is not the last one, just move the counter */
3299 --unres->count;
3300}
3301
Michal Vasko0491ab32015-08-19 14:28:29 +02003302/**
3303 * @brief Resolve (find) a data node from a specific module. Does not log.
3304 *
3305 * @param[in] mod Module to search in.
3306 * @param[in] name Name of the data node.
3307 * @param[in] nam_len Length of the name.
3308 * @param[in] start Data node to start the search from.
3309 * @param[in,out] parents Resolved nodes. If there are some parents,
3310 * they are replaced (!!) with the resolvents.
3311 *
Michal Vasko2471e7f2016-04-11 11:00:15 +02003312 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko0491ab32015-08-19 14:28:29 +02003313 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003314static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003315resolve_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 +02003316{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003317 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02003318 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003319 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003320
Michal Vasko23b61ec2015-08-19 11:19:50 +02003321 if (!parents->count) {
3322 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003323 parents->node = malloc(sizeof *parents->node);
Michal Vasko253035f2015-12-17 16:58:13 +01003324 if (!parents->node) {
3325 LOGMEM;
Michal Vasko2471e7f2016-04-11 11:00:15 +02003326 return -1;
Michal Vasko253035f2015-12-17 16:58:13 +01003327 }
Michal Vaskocf024702015-10-08 15:01:42 +02003328 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003329 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003330 for (i = 0; i < parents->count;) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02003331 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003332 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003333 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003334 continue;
3335 }
3336 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02003337 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003338 if (node->schema->module == mod && !strncmp(node->schema->name, name, nam_len)
3339 && node->schema->name[nam_len] == '\0') {
3340 /* matching target */
3341 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02003342 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02003343 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003344 flag = 1;
3345 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02003346 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003347 ++parents->count;
Michal Vasko253035f2015-12-17 16:58:13 +01003348 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
3349 if (!parents->node) {
3350 return EXIT_FAILURE;
3351 }
Michal Vaskocf024702015-10-08 15:01:42 +02003352 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003353 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003354 }
3355 }
3356 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003357
3358 if (!flag) {
3359 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003360 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02003361 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003362 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02003363 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003364 }
3365
Michal Vasko0491ab32015-08-19 14:28:29 +02003366 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02003367}
3368
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003369/**
3370 * @brief Resolve (find) a data node. Does not log.
3371 *
Radek Krejci581ce772015-11-10 17:22:40 +01003372 * @param[in] mod_name Module name of the data node.
3373 * @param[in] mod_name_len Length of the module name.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003374 * @param[in] name Name of the data node.
3375 * @param[in] nam_len Length of the name.
3376 * @param[in] start Data node to start the search from.
3377 * @param[in,out] parents Resolved nodes. If there are some parents,
3378 * they are replaced (!!) with the resolvents.
3379 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003380 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003381 */
Radek Krejcic5090c32015-08-12 09:46:19 +02003382static int
Radek Krejci581ce772015-11-10 17:22:40 +01003383resolve_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 +02003384 struct unres_data *parents)
Radek Krejcic5090c32015-08-12 09:46:19 +02003385{
Michal Vasko1e62a092015-12-01 12:27:20 +01003386 const struct lys_module *mod;
Michal Vasko31fc3672015-10-21 12:08:13 +02003387 char *str;
Radek Krejcic5090c32015-08-12 09:46:19 +02003388
Michal Vasko23b61ec2015-08-19 11:19:50 +02003389 assert(start);
3390
Michal Vasko31fc3672015-10-21 12:08:13 +02003391 if (mod_name) {
3392 /* we have mod_name, find appropriate module */
3393 str = strndup(mod_name, mod_name_len);
Michal Vasko253035f2015-12-17 16:58:13 +01003394 if (!str) {
3395 LOGMEM;
3396 return -1;
3397 }
Michal Vasko31fc3672015-10-21 12:08:13 +02003398 mod = ly_ctx_get_module(start->schema->module->ctx, str, NULL);
3399 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02003400 if (!mod) {
3401 /* invalid prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003402 return -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02003403 }
3404 } else {
3405 /* no prefix, module is the same as of current node */
3406 mod = start->schema->module;
3407 }
3408
3409 return resolve_data(mod, name, name_len, start, parents);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003410}
3411
Michal Vasko730dfdf2015-08-11 14:48:05 +02003412/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003413 * @brief Resolve a path predicate (leafref) in JSON data context. Logs directly
Radek Krejci48464ed2016-03-17 15:44:09 +01003414 * only specific errors, general no-resolvent error is left to the caller.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003415 *
Michal Vaskobb211122015-08-19 14:03:11 +02003416 * @param[in] pred Predicate to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003417 * @param[in] node Node from which the predicate is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02003418 * @param[in,out] node_match Nodes satisfying the restriction
3419 * without the predicate. Nodes not
3420 * satisfying the predicate are removed.
Michal Vasko0491ab32015-08-19 14:28:29 +02003421 * @param[out] parsed Number of characters parsed, negative on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003422 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003423 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003424 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003425static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003426resolve_path_predicate_data(const char *pred, struct lyd_node *node, struct unres_data *node_match,
Radek Krejci010e54b2016-03-15 09:40:34 +01003427 int *parsed)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003428{
Michal Vasko730dfdf2015-08-11 14:48:05 +02003429 /* ... /node[source = destination] ... */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003430 struct unres_data source_match, dest_match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003431 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vasko0491ab32015-08-19 14:28:29 +02003432 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed_loc = 0, pke_parsed = 0;
3433 int has_predicate, dest_parent_times, i, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003434 uint32_t j;
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003435 struct lyd_node_leaf_list *leaf_dst, *leaf_src;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003436
3437 source_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003438 source_match.node = malloc(sizeof *source_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003439 if (!source_match.node) {
3440 LOGMEM;
3441 return -1;
3442 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003443 dest_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003444 dest_match.node = malloc(sizeof *dest_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003445 if (!dest_match.node) {
3446 LOGMEM;
3447 return -1;
3448 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003449
3450 do {
3451 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
3452 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003453 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, pred[-i], &pred[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003454 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003455 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003456 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003457 parsed_loc += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003458 pred += i;
3459
Michal Vasko23b61ec2015-08-19 11:19:50 +02003460 for (j = 0; j < node_match->count;) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003461 /* source */
Michal Vaskocf024702015-10-08 15:01:42 +02003462 source_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02003463
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003464 /* must be leaf (key of a list) */
Radek Krejci581ce772015-11-10 17:22:40 +01003465 if ((rc = resolve_data_node(sour_pref, sour_pref_len, source, sour_len, node_match->node[j],
Michal Vaskocf024702015-10-08 15:01:42 +02003466 &source_match)) || (source_match.count != 1) || (source_match.node[0]->schema->nodetype != LYS_LEAF)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003467 i = 0;
3468 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003469 }
3470
3471 /* destination */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003472 dest_match.node[0] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003473 dest_parent_times = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003474 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3475 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003476 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003477 rc = -1;
3478 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003479 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003480 pke_parsed = i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003481 for (i = 0; i < dest_parent_times; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02003482 dest_match.node[0] = dest_match.node[0]->parent;
3483 if (!dest_match.node[0]) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003484 i = 0;
Michal Vasko0491ab32015-08-19 14:28:29 +02003485 rc = EXIT_FAILURE;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003486 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003487 }
3488 }
3489 while (1) {
Radek Krejci581ce772015-11-10 17:22:40 +01003490 if ((rc = resolve_data_node(dest_pref, dest_pref_len, dest, dest_len, dest_match.node[0],
Michal Vasko0491ab32015-08-19 14:28:29 +02003491 &dest_match)) || (dest_match.count != 1)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003492 i = 0;
3493 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003494 }
3495
3496 if (pke_len == pke_parsed) {
3497 break;
3498 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003499 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 +02003500 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003501 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003502 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003503 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003504 }
3505 pke_parsed += i;
3506 }
3507
3508 /* check match between source and destination nodes */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003509 leaf_dst = (struct lyd_node_leaf_list *)dest_match.node[0];
3510 while (leaf_dst->value_type == LY_TYPE_LEAFREF) {
3511 leaf_dst = (struct lyd_node_leaf_list *)leaf_dst->value.leafref;
3512 }
3513 leaf_src = (struct lyd_node_leaf_list *)source_match.node[0];
3514 while (leaf_src->value_type == LY_TYPE_LEAFREF) {
3515 leaf_src = (struct lyd_node_leaf_list *)leaf_src->value.leafref;
3516 }
3517 if (leaf_src->value_type != leaf_dst->value_type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003518 goto remove_leafref;
3519 }
3520
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003521 if (!ly_strequal(leaf_src->value_str, leaf_dst->value_str, 1)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003522 goto remove_leafref;
3523 }
3524
3525 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003526 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003527 continue;
3528
3529remove_leafref:
3530 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003531 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003532 }
3533 } while (has_predicate);
3534
Michal Vaskocf024702015-10-08 15:01:42 +02003535 free(source_match.node);
3536 free(dest_match.node);
Michal Vasko0491ab32015-08-19 14:28:29 +02003537 if (parsed) {
3538 *parsed = parsed_loc;
3539 }
3540 return EXIT_SUCCESS;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003541
3542error:
3543
3544 if (source_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003545 free(source_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003546 }
3547 if (dest_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003548 free(dest_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003549 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003550 if (parsed) {
3551 *parsed = -parsed_loc+i;
3552 }
3553 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003554}
3555
Michal Vasko730dfdf2015-08-11 14:48:05 +02003556/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003557 * @brief Resolve a path (leafref) in JSON data context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003558 *
Michal Vaskocf024702015-10-08 15:01:42 +02003559 * @param[in] node Leafref data node.
Michal Vasko23b61ec2015-08-19 11:19:50 +02003560 * @param[in] path Path of the leafref.
Radek Krejci48464ed2016-03-17 15:44:09 +01003561 * @param[out] ret Matching nodes. Expects an empty, but allocated structure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003562 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003563 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003564 */
Michal Vasko184521f2015-09-24 13:14:26 +02003565static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003566resolve_path_arg_data(struct lyd_node *node, const char *path, struct unres_data *ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003567{
Radek Krejci71b795b2015-08-10 16:20:39 +02003568 struct lyd_node *data = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003569 const char *prefix, *name;
Michal Vasko0491ab32015-08-19 14:28:29 +02003570 int pref_len, nam_len, has_predicate, parent_times, i, parsed, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003571 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003572
Michal Vaskocf024702015-10-08 15:01:42 +02003573 assert(node && path && ret && !ret->count);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003574
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003575 parent_times = 0;
Michal Vaskod9173342015-08-17 14:35:36 +02003576 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003577
3578 /* searching for nodeset */
3579 do {
Radek Krejcif7ed4c32016-10-27 16:20:03 +02003580 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 +01003581 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path[-i], &path[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003582 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003583 goto error;
3584 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003585 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003586 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003587
Michal Vasko23b61ec2015-08-19 11:19:50 +02003588 if (!ret->count) {
Michal Vaskobfd98e62016-09-02 09:50:05 +02003589 if (parent_times > 0) {
3590 data = node;
3591 for (i = 1; i < parent_times; ++i) {
3592 data = data->parent;
Michal Vasko253035f2015-12-17 16:58:13 +01003593 }
Michal Vaskobfd98e62016-09-02 09:50:05 +02003594 } else if (!parent_times) {
3595 data = node->child;
3596 } else {
3597 /* absolute path */
3598 for (data = node; data->parent; data = data->parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003599 }
3600
Michal Vaskobfd98e62016-09-02 09:50:05 +02003601 /* we may still be parsing it and the pointer is not correct yet */
3602 if (data->prev) {
3603 while (data->prev->next) {
3604 data = data->prev;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003605 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003606 }
3607 }
3608
3609 /* node identifier */
Radek Krejci581ce772015-11-10 17:22:40 +01003610 if ((rc = resolve_data_node(prefix, pref_len, name, nam_len, data, ret))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003611 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003612 LOGVAL(LYE_INELEM_LEN, LY_VLOG_LYD, node, nam_len, name);
Michal Vasko184521f2015-09-24 13:14:26 +02003613 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003614 goto error;
3615 }
3616
3617 if (has_predicate) {
3618 /* we have predicate, so the current results must be lists */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003619 for (j = 0; j < ret->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02003620 if (ret->node[j]->schema->nodetype == LYS_LIST &&
3621 ((struct lys_node_list *)ret->node[0]->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003622 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003623 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003624 continue;
3625 }
3626
3627 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003628 unres_data_del(ret, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003629 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003630 if ((rc = resolve_path_predicate_data(path, node, ret, &i))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003631 if (rc == -1) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003632 LOGVAL(LYE_NORESOLV, LY_VLOG_LYD, node, "leafref", path);
Michal Vasko184521f2015-09-24 13:14:26 +02003633 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003634 goto error;
3635 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003636 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003637 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003638
Michal Vasko23b61ec2015-08-19 11:19:50 +02003639 if (!ret->count) {
Michal Vasko0491ab32015-08-19 14:28:29 +02003640 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003641 goto error;
3642 }
3643 }
3644 } while (path[0] != '\0');
3645
Michal Vaskof02e3742015-08-05 16:27:02 +02003646 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003647
3648error:
3649
Michal Vaskocf024702015-10-08 15:01:42 +02003650 free(ret->node);
3651 ret->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003652 ret->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003653
Michal Vasko0491ab32015-08-19 14:28:29 +02003654 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003655}
3656
Michal Vaskoe27516a2016-10-10 17:55:31 +00003657static int
3658resolve_path_arg_schema_valid_dep_flag(const struct lys_node *op_node, const struct lys_node *first_node, int abs_path)
3659{
3660 int dep1, dep2;
3661 const struct lys_node *node;
3662
3663 if (lys_parent(op_node)) {
3664 /* inner operation (notif/action) */
3665 if (abs_path) {
3666 return 1;
3667 } else {
3668 /* compare depth of both nodes */
3669 for (dep1 = 0, node = op_node; lys_parent(node); node = lys_parent(node));
3670 for (dep2 = 0, node = first_node; lys_parent(node); node = lys_parent(node));
3671 if ((dep2 > dep1) || ((dep2 == dep1) && (op_node != first_node))) {
3672 return 1;
3673 }
3674 }
3675 } else {
3676 /* top-level operation (notif/rpc) */
3677 if (op_node != first_node) {
3678 return 1;
3679 }
3680 }
3681
3682 return 0;
3683}
3684
Michal Vasko730dfdf2015-08-11 14:48:05 +02003685/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003686 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003687 *
Michal Vaskobb211122015-08-19 14:03:11 +02003688 * @param[in] path Path to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003689 * @param[in] context_node Predicate context node (where the predicate is placed).
3690 * @param[in] parent Path context node (where the path begins/is placed).
Michal Vaskoe27516a2016-10-10 17:55:31 +00003691 * @param[in] op_node Optional node if the leafref is in an operation (action/rpc/notif).
Michal Vasko730dfdf2015-08-11 14:48:05 +02003692 *
Michal Vasko184521f2015-09-24 13:14:26 +02003693 * @return 0 on forward reference, otherwise the number
3694 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003695 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003696 */
Michal Vasko1f76a282015-08-04 16:16:53 +02003697static int
Radek Krejciadb57612016-02-16 13:34:34 +01003698resolve_path_predicate_schema(const char *path, const struct lys_node *context_node,
Michal Vaskoe27516a2016-10-10 17:55:31 +00003699 struct lys_node *parent, const struct lys_node *op_node)
Michal Vasko1f76a282015-08-04 16:16:53 +02003700{
Michal Vasko1e62a092015-12-01 12:27:20 +01003701 const struct lys_node *src_node, *dst_node;
Michal Vasko1f76a282015-08-04 16:16:53 +02003702 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vaskof9b35d92016-10-21 15:19:30 +02003703 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, pke_parsed, parsed = 0;
3704 int has_predicate, dest_parent_times, i, rc, first_iter;
Michal Vasko1f76a282015-08-04 16:16:53 +02003705
3706 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02003707 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02003708 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003709 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003710 return -parsed+i;
3711 }
3712 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003713 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02003714
Michal Vasko58090902015-08-13 14:04:15 +02003715 /* source (must be leaf) */
Michal Vasko36cbaa42015-12-14 13:15:48 +01003716 if (!sour_pref) {
Radek Krejciadb57612016-02-16 13:34:34 +01003717 sour_pref = context_node->module->name;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003718 }
Radek Krejciadb57612016-02-16 13:34:34 +01003719 rc = lys_get_sibling(context_node->child, sour_pref, sour_pref_len, source, sour_len,
Michal Vasko59ad4582016-09-16 13:15:41 +02003720 LYS_LEAF | LYS_LEAFLIST | LYS_AUGMENT, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003721 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003722 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02003723 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003724 }
3725
3726 /* destination */
Michal Vaskof9b35d92016-10-21 15:19:30 +02003727 dest_parent_times = 0;
3728 pke_parsed = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003729 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3730 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003731 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 +02003732 return -parsed;
3733 }
3734 pke_parsed += i;
3735
Radek Krejciadb57612016-02-16 13:34:34 +01003736 for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
Michal Vaskofbaead72016-10-07 10:54:48 +02003737 /* path is supposed to be evaluated in data tree, so we have to skip
3738 * all schema nodes that cannot be instantiated in data tree */
3739 for (dst_node = lys_parent(dst_node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003740 dst_node && !(dst_node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Michal Vaskofbaead72016-10-07 10:54:48 +02003741 dst_node = lys_parent(dst_node));
3742
Michal Vasko1f76a282015-08-04 16:16:53 +02003743 if (!dst_node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003744 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003745 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003746 }
3747 }
Michal Vaskoe27516a2016-10-10 17:55:31 +00003748 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003749 while (1) {
Michal Vasko36cbaa42015-12-14 13:15:48 +01003750 if (!dest_pref) {
3751 dest_pref = dst_node->module->name;
3752 }
3753 rc = lys_get_sibling(dst_node->child, dest_pref, dest_pref_len, dest, dest_len,
Michal Vasko165dc4a2015-10-23 09:44:27 +02003754 LYS_CONTAINER | LYS_LIST | LYS_LEAF | LYS_AUGMENT, &dst_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003755 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003756 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003757 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003758 }
3759
Michal Vaskoe27516a2016-10-10 17:55:31 +00003760 if (first_iter) {
3761 if (resolve_path_arg_schema_valid_dep_flag(op_node, dst_node, 0)) {
3762 parent->flags |= LYS_VALID_DEP;
3763 }
3764 first_iter = 0;
3765 }
3766
Michal Vasko1f76a282015-08-04 16:16:53 +02003767 if (pke_len == pke_parsed) {
3768 break;
3769 }
3770
3771 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
3772 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003773 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent,
Radek Krejciadb57612016-02-16 13:34:34 +01003774 (path_key_expr+pke_parsed)[-i], (path_key_expr+pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003775 return -parsed;
3776 }
3777 pke_parsed += i;
3778 }
3779
3780 /* check source - dest match */
Michal Vasko59ad4582016-09-16 13:15:41 +02003781 if (dst_node->nodetype != src_node->nodetype) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003782 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko59ad4582016-09-16 13:15:41 +02003783 LOGVAL(LYE_SPEC, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "Destination node is not a %s, but a %s.",
3784 strnodetype(src_node->nodetype), strnodetype(dst_node->nodetype));
Michal Vasko184521f2015-09-24 13:14:26 +02003785 return -parsed;
3786 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003787 } while (has_predicate);
3788
3789 return parsed;
3790}
3791
Michal Vasko730dfdf2015-08-11 14:48:05 +02003792/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003793 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003794 *
Michal Vaskobb211122015-08-19 14:03:11 +02003795 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003796 * @param[in] parent_node Parent of the leafref.
Radek Krejci2f12f852016-01-08 12:59:57 +01003797 * @param[in] parent_tpdf Flag if the parent node is actually typedef, in that case the path
3798 * has to contain absolute path
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003799 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003800 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003801 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003802 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003803static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003804resolve_path_arg_schema(const char *path, struct lys_node *parent, int parent_tpdf,
Michal Vasko36cbaa42015-12-14 13:15:48 +01003805 const struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02003806{
Michal Vaskoe27516a2016-10-10 17:55:31 +00003807 const struct lys_node *node, *op_node = NULL;
Radek Krejci990af1f2016-11-09 13:53:36 +01003808 const struct lys_module *mod;
3809 struct lys_module *mod_start;
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 Krejci990af1f2016-11-09 13:53:36 +01003825 mod_start = lys_node_module(parent);
Michal Vasko1f76a282015-08-04 16:16:53 +02003826 do {
Radek Krejci990af1f2016-11-09 13:53:36 +01003827 if ((i = parse_path_arg(mod_start, id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +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 Krejci990af1f2016-11-09 13:53:36 +01003836 mod = prefix ? lys_get_import_module(mod_start, NULL, 0, prefix, pref_len) : mod_start;
3837 if (!mod) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003838 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3839 "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003840 return EXIT_FAILURE;
Michal Vasko58090902015-08-13 14:04:15 +02003841 }
Radek Krejci990af1f2016-11-09 13:53:36 +01003842 if (!mod->implemented) {
3843 mod = lys_get_implemented_module(mod);
3844 if (!mod->implemented) {
3845 /* make the found module implemented */
3846 if (lys_set_implemented(mod)) {
3847 return EXIT_FAILURE;
3848 }
3849 }
3850 }
3851 /* get start node */
3852 if (!mod->data) {
3853 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3854 "leafref", path);
3855 return EXIT_FAILURE;
3856 }
3857 node = mod->data;
3858
Michal Vasko1f76a282015-08-04 16:16:53 +02003859 } else if (parent_times > 0) {
Radek Krejci2f12f852016-01-08 12:59:57 +01003860 if (parent_tpdf) {
3861 /* the path is not allowed to contain relative path since we are in top level typedef */
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003862 LOGVAL(LYE_NORESOLV, 0, NULL, "leafref", path);
Radek Krejci2f12f852016-01-08 12:59:57 +01003863 return -1;
3864 }
3865
Michal Vasko94458082016-10-07 14:34:36 +02003866 /* we are looking for a sibling of a node, node it's parent (that is why parent_times - 1) */
3867 for (i = 0, node = parent; i < parent_times - 1; i++) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02003868 /* path is supposed to be evaluated in data tree, so we have to skip
3869 * all schema nodes that cannot be instantiated in data tree */
3870 for (node = lys_parent(node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003871 node && !(node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Radek Krejci3a5501d2016-07-18 22:03:34 +02003872 node = lys_parent(node));
3873
Michal Vasko1f76a282015-08-04 16:16:53 +02003874 if (!node) {
Michal Vaskoe9914d12016-10-07 14:32:37 +02003875 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003876 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003877 }
3878 }
Radek Krejci990af1f2016-11-09 13:53:36 +01003879
3880 /* now we have to check that if we are going into a node from a different module,
3881 * the module is implemented (so its augments are applied) */
3882 mod = prefix ? lys_get_import_module(mod_start, NULL, 0, prefix, pref_len) : mod_start;
3883 if (!mod) {
3884 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
3885 return EXIT_FAILURE;
3886 }
3887 if (!mod->implemented) {
3888 mod = lys_get_implemented_module(mod);
3889 if (!mod->implemented) {
3890 /* make the found module implemented */
3891 if (lys_set_implemented(mod)) {
3892 return EXIT_FAILURE;
3893 }
3894 }
3895 }
Michal Vaskoe01eca52015-08-13 14:42:02 +02003896 } else {
3897 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003898 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003899 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003900 } else {
Radek Krejci990af1f2016-11-09 13:53:36 +01003901 /* we have to first check that the module we are going into is implemented */
3902 mod = prefix ? lys_get_import_module(mod_start, NULL, 0, prefix, pref_len) : mod_start;
3903 if (!mod) {
3904 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
3905 return EXIT_FAILURE;
3906 }
3907 if (!mod->implemented) {
3908 mod = lys_get_implemented_module(mod);
3909 if (!mod->implemented) {
3910 /* make the found module implemented */
3911 if (lys_set_implemented(mod)) {
3912 return EXIT_FAILURE;
3913 }
3914 }
3915 }
3916
Michal Vasko7dc71d02016-03-15 10:42:28 +01003917 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02003918 if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko2f5aceb2016-03-22 10:24:14 +01003919 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 +01003920 return -1;
3921 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003922 node = node->child;
Radek Krejci43ccc4c2016-10-18 20:40:06 +02003923 if (!node) {
3924 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3925 "leafref", path);
3926 return EXIT_FAILURE;
3927 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003928 }
3929
Michal Vasko4f0dad02016-02-15 14:08:23 +01003930 if (!prefix) {
Radek Krejci990af1f2016-11-09 13:53:36 +01003931 prefix = mod_start->name;
Michal Vasko4f0dad02016-02-15 14:08:23 +01003932 }
3933
Michal Vasko36cbaa42015-12-14 13:15:48 +01003934 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 +02003935 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003936 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko7a55bea2016-05-02 14:51:20 +02003937 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003938 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003939
Michal Vaskoe27516a2016-10-10 17:55:31 +00003940 if (first_iter) {
3941 /* set external dependency flag, we can decide based on the first found node */
3942 if (!parent_tpdf && op_node && parent_times &&
3943 resolve_path_arg_schema_valid_dep_flag(op_node, node, (parent_times == -1 ? 1 : 0))) {
3944 parent->flags |= LYS_VALID_DEP;
3945 }
3946 first_iter = 0;
3947 }
3948
Michal Vasko1f76a282015-08-04 16:16:53 +02003949 if (has_predicate) {
3950 /* we have predicate, so the current result must be list */
3951 if (node->nodetype != LYS_LIST) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003952 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003953 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003954 }
3955
Michal Vaskoe27516a2016-10-10 17:55:31 +00003956 i = resolve_path_predicate_schema(id, node, parent, op_node);
Radek Krejci27fe55e2016-09-13 17:13:35 +02003957 if (i <= 0) {
3958 if (i == 0) {
3959 return EXIT_FAILURE;
3960 } else { /* i < 0 */
3961 return -1;
3962 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003963 }
3964 id += i;
Michal Vaskof9b35d92016-10-21 15:19:30 +02003965 has_predicate = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003966 }
3967 } while (id[0]);
3968
Michal Vaskoca917682016-07-25 11:00:37 +02003969 /* the target must be leaf or leaf-list (in YANG 1.1 only) */
Radek Krejci2a5a9602016-11-04 10:21:13 +01003970 if ((node->nodetype != LYS_LEAF) && (node->nodetype != LYS_LEAFLIST)) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003971 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Radek Krejcid47daf62016-08-22 16:23:38 +02003972 LOGVAL(LYE_SPEC, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
Radek Krejci2a5a9602016-11-04 10:21:13 +01003973 "Leafref target \"%s\" is not a leaf nor a leaf-list.", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003974 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02003975 }
3976
Radek Krejcicf509982015-12-15 09:22:44 +01003977 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01003978 if (lyp_check_status(parent->flags, parent->module, parent->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01003979 node->flags, node->module, node->name, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003980 return -1;
3981 }
3982
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003983 if (ret) {
3984 *ret = node;
3985 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02003986
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003987 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02003988}
3989
Michal Vasko730dfdf2015-08-11 14:48:05 +02003990/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003991 * @brief Resolve instance-identifier predicate in JSON data format.
3992 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003993 *
Michal Vaskobb211122015-08-19 14:03:11 +02003994 * @param[in] pred Predicate to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003995 * @param[in,out] node_match Nodes matching the restriction without
3996 * the predicate. Nodes not satisfying
3997 * the predicate are removed.
3998 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003999 * @return Number of characters successfully parsed,
4000 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004001 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004002static int
Michal Vaskof39142b2015-10-21 11:40:05 +02004003resolve_predicate(const char *pred, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004004{
Michal Vasko730dfdf2015-08-11 14:48:05 +02004005 /* ... /node[target = value] ... */
Michal Vaskob2f40be2016-09-08 16:03:48 +02004006 struct lyd_node *target;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004007 const char *model, *name, *value;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004008 int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed, pred_iter, k;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004009 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004010
Michal Vasko1f2cc332015-08-19 11:18:32 +02004011 assert(pred && node_match->count);
4012
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004013 idx = -1;
4014 parsed = 0;
4015
Michal Vaskob2f40be2016-09-08 16:03:48 +02004016 pred_iter = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004017 do {
Michal Vaskof39142b2015-10-21 11:40:05 +02004018 if ((i = parse_predicate(pred, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004019 return -parsed+i;
4020 }
4021 parsed += i;
4022 pred += i;
4023
4024 if (isdigit(name[0])) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004025 /* pos */
4026 assert(!value);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004027 idx = atoi(name);
Michal Vaskob2f40be2016-09-08 16:03:48 +02004028 } else if (name[0] != '.') {
4029 /* list keys */
4030 if (pred_iter < 0) {
4031 pred_iter = 1;
4032 } else {
4033 ++pred_iter;
4034 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004035 }
4036
Michal Vaskof2f28a12016-09-09 12:43:06 +02004037 for (cur_idx = 1, j = 0; j < node_match->count; ++cur_idx) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004038 /* target */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004039 if (name[0] == '.') {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004040 /* leaf-list value */
Michal Vaskocf024702015-10-08 15:01:42 +02004041 if (node_match->node[j]->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004042 goto remove_instid;
4043 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004044
4045 target = node_match->node[j];
4046 /* check the value */
4047 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
4048 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
4049 goto remove_instid;
4050 }
4051
4052 } else if (!value) {
4053 /* keyless list position */
4054 if ((node_match->node[j]->schema->nodetype != LYS_LIST)
4055 || ((struct lys_node_list *)node_match->node[j]->schema)->keys) {
4056 goto remove_instid;
4057 }
4058
4059 if (idx != cur_idx) {
4060 goto remove_instid;
4061 }
4062
4063 } else {
4064 /* list key value */
Michal Vaskocf024702015-10-08 15:01:42 +02004065 if (node_match->node[j]->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004066 goto remove_instid;
4067 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004068
4069 /* key module must match the list module */
4070 if (strncmp(node_match->node[j]->schema->module->name, model, mod_len)
4071 || node_match->node[j]->schema->module->name[mod_len]) {
4072 goto remove_instid;
4073 }
4074 /* find the key leaf */
Michal Vasko045182c2016-09-09 12:44:07 +02004075 for (k = 1, target = node_match->node[j]->child; target && (k < pred_iter); k++, target = target->next);
Michal Vaskob2f40be2016-09-08 16:03:48 +02004076 if (!target) {
4077 goto remove_instid;
4078 }
4079 if ((struct lys_node_leaf *)target->schema !=
4080 ((struct lys_node_list *)node_match->node[j]->schema)->keys[pred_iter - 1]) {
4081 goto remove_instid;
4082 }
4083
4084 /* check the value */
4085 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
4086 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
4087 goto remove_instid;
4088 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004089 }
4090
Michal Vaskob2f40be2016-09-08 16:03:48 +02004091 /* instid is ok, continue check with the next one */
Michal Vasko1f2cc332015-08-19 11:18:32 +02004092 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004093 continue;
4094
4095remove_instid:
Michal Vaskob2f40be2016-09-08 16:03:48 +02004096 /* does not fulfill conditions, remove instid record */
Michal Vasko1f2cc332015-08-19 11:18:32 +02004097 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004098 }
4099 } while (has_predicate);
4100
Michal Vaskob2f40be2016-09-08 16:03:48 +02004101 /* check that all list keys were specified */
4102 if ((pred_iter > 0) && node_match->count) {
Michal Vasko045182c2016-09-09 12:44:07 +02004103 j = 0;
4104 while (j < node_match->count) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004105 assert(node_match->node[j]->schema->nodetype == LYS_LIST);
4106 if (pred_iter < ((struct lys_node_list *)node_match->node[j]->schema)->keys_size) {
4107 /* not enough predicates, just remove the list instance */
4108 unres_data_del(node_match, j);
Michal Vasko045182c2016-09-09 12:44:07 +02004109 } else {
4110 ++j;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004111 }
4112 }
4113
4114 if (!node_match->count) {
4115 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier is missing some list keys.");
4116 }
4117 }
4118
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004119 return parsed;
4120}
4121
Michal Vasko730dfdf2015-08-11 14:48:05 +02004122/**
Michal Vaskof39142b2015-10-21 11:40:05 +02004123 * @brief Resolve instance-identifier in JSON data format. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004124 *
Radek Krejciadb57612016-02-16 13:34:34 +01004125 * @param[in] data Data node where the path is used
Michal Vasko730dfdf2015-08-11 14:48:05 +02004126 * @param[in] path Instance-identifier node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004127 *
Radek Krejcic5090c32015-08-12 09:46:19 +02004128 * @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 +02004129 */
Radek Krejci1899d6a2016-11-03 13:48:07 +01004130struct lyd_node *
Radek Krejci48464ed2016-03-17 15:44:09 +01004131resolve_instid(struct lyd_node *data, const char *path)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004132{
Radek Krejcic5090c32015-08-12 09:46:19 +02004133 int i = 0, j;
4134 struct lyd_node *result = NULL;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004135 const struct lys_module *mod;
Radek Krejcic5090c32015-08-12 09:46:19 +02004136 struct ly_ctx *ctx = data->schema->module->ctx;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004137 const char *model, *name;
Radek Krejcic5090c32015-08-12 09:46:19 +02004138 char *str;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004139 int mod_len, name_len, has_predicate;
4140 struct unres_data node_match;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004141
4142 memset(&node_match, 0, sizeof node_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004143
Radek Krejcic5090c32015-08-12 09:46:19 +02004144 /* we need root to resolve absolute path */
4145 for (; data->parent; data = data->parent);
Michal Vaskodb9323c2015-10-16 10:32:44 +02004146 /* we're still parsing it and the pointer is not correct yet */
Michal Vasko0491ab32015-08-19 14:28:29 +02004147 if (data->prev) {
4148 for (; data->prev->next; data = data->prev);
4149 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004150
Radek Krejcic5090c32015-08-12 09:46:19 +02004151 /* search for the instance node */
4152 while (path[i]) {
Michal Vaskof39142b2015-10-21 11:40:05 +02004153 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
Radek Krejcic5090c32015-08-12 09:46:19 +02004154 if (j <= 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004155 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004156 goto error;
4157 }
Radek Krejcic5090c32015-08-12 09:46:19 +02004158 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02004159
Michal Vaskob2f40be2016-09-08 16:03:48 +02004160 str = strndup(model, mod_len);
4161 if (!str) {
4162 LOGMEM;
4163 goto error;
Radek Krejcic5090c32015-08-12 09:46:19 +02004164 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004165 mod = ly_ctx_get_module(ctx, str, NULL);
4166 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02004167
Michal Vasko1f2cc332015-08-19 11:18:32 +02004168 if (resolve_data(mod, name, name_len, data, &node_match)) {
Radek Krejcic5090c32015-08-12 09:46:19 +02004169 /* no instance exists */
4170 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004171 }
4172
4173 if (has_predicate) {
4174 /* we have predicate, so the current results must be list or leaf-list */
Michal Vaskof39142b2015-10-21 11:40:05 +02004175 j = resolve_predicate(&path[i], &node_match);
Radek Krejcic5090c32015-08-12 09:46:19 +02004176 if (j < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004177 LOGVAL(LYE_INPRED, LY_VLOG_LYD, data, &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004178 goto error;
4179 }
Michal Vasko1f2cc332015-08-19 11:18:32 +02004180 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02004181
Michal Vasko1f2cc332015-08-19 11:18:32 +02004182 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02004183 /* no instance exists */
4184 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004185 }
4186 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004187 }
4188
Michal Vasko1f2cc332015-08-19 11:18:32 +02004189 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02004190 /* no instance exists */
4191 return NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02004192 } else if (node_match.count > 1) {
Radek Krejcic5090c32015-08-12 09:46:19 +02004193 /* instance identifier must resolve to a single node */
Radek Krejci48464ed2016-03-17 15:44:09 +01004194 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
Michal Vaskod6adbaa2016-04-11 11:01:09 +02004195 goto error;
Radek Krejcic5090c32015-08-12 09:46:19 +02004196 } else {
4197 /* we have required result, remember it and cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02004198 result = node_match.node[0];
4199 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02004200 return result;
4201 }
4202
4203error:
Radek Krejcic5090c32015-08-12 09:46:19 +02004204 /* cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02004205 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02004206 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004207}
4208
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004209int
4210lys_check_xpath(struct lys_node *node, int check_place)
Michal Vasko9e635ac2016-10-17 11:44:09 +02004211{
4212 struct lys_node *parent, *elem;
4213 struct lyxp_set set;
4214 uint32_t i;
4215 int rc;
4216
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004217 if (check_place) {
4218 parent = node;
4219 while (parent) {
4220 if (parent->nodetype == LYS_GROUPING) {
4221 /* unresolved grouping, skip for now (will be checked later) */
Michal Vasko9e635ac2016-10-17 11:44:09 +02004222 return EXIT_SUCCESS;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004223 }
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004224 if (parent->nodetype == LYS_AUGMENT) {
4225 if (!((struct lys_node_augment *)parent)->target) {
Radek Krejcidf46e222016-11-08 11:57:37 +01004226 /* unresolved augment */
4227 if (parent->module->implemented) {
4228 /* skip for now (will be checked later) */
4229 return EXIT_FAILURE;
4230 } else {
4231 /* not implemented augment, skip resolving */
4232 return EXIT_SUCCESS;
4233 }
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004234 } else {
4235 parent = ((struct lys_node_augment *)parent)->target;
4236 continue;
4237 }
4238 }
4239 parent = parent->parent;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004240 }
Michal Vasko9e635ac2016-10-17 11:44:09 +02004241 }
4242
4243 rc = lyxp_node_atomize(node, &set);
4244 if (rc) {
4245 return rc;
4246 }
4247
4248 for (parent = node; parent && !(parent->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); parent = lys_parent(parent));
4249
4250 for (i = 0; i < set.used; ++i) {
4251 /* skip roots'n'stuff */
4252 if (set.val.snodes[i].type == LYXP_NODE_ELEM) {
4253 /* XPath expression cannot reference "lower" status than the node that has the definition */
4254 if (lyp_check_status(node->flags, lys_node_module(node), node->name, set.val.snodes[i].snode->flags,
4255 lys_node_module(set.val.snodes[i].snode), set.val.snodes[i].snode->name, node)) {
4256 return -1;
4257 }
4258
4259 if (parent) {
4260 for (elem = set.val.snodes[i].snode; elem && (elem != parent); elem = lys_parent(elem));
4261 if (!elem) {
4262 /* not in node's RPC or notification subtree, set the flag */
4263 node->flags |= LYS_VALID_DEP;
4264 break;
4265 }
4266 }
4267 }
4268 }
4269
4270 free(set.val.snodes);
4271 return EXIT_SUCCESS;
4272}
4273
Radek Krejcif71f48f2016-10-25 16:37:24 +02004274static int
4275check_leafref_config(struct lys_node_leaf *leaf, struct lys_type *type)
4276{
4277 int i;
4278
4279 if (type->base == LY_TYPE_LEAFREF) {
4280 if ((leaf->flags & LYS_CONFIG_W) && type->info.lref.target && (type->info.lref.target->flags & LYS_CONFIG_R)) {
4281 LOGVAL(LYE_SPEC, LY_VLOG_LYS, leaf, "The %s is config but refers to a non-config %s.",
4282 strnodetype(leaf->nodetype), strnodetype(type->info.lref.target->nodetype));
4283 return -1;
4284 }
4285 /* we can skip the test in case the leafref is not yet resolved. In that case the test is done in the time
4286 * of leafref resolving (lys_leaf_add_leafref_target()) */
4287 } else if (type->base == LY_TYPE_UNION) {
4288 for (i = 0; i < type->info.uni.count; i++) {
4289 if (check_leafref_config(leaf, &type->info.uni.types[i])) {
4290 return -1;
4291 }
4292 }
4293 }
4294 return 0;
4295}
4296
Michal Vasko9e635ac2016-10-17 11:44:09 +02004297/**
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004298 * @brief Passes config flag down to children, skips nodes without config flags.
4299 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004300 *
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004301 * @param[in] node Siblings and their children to have flags changed.
Michal Vaskoe022a562016-09-27 14:24:15 +02004302 * @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 +02004303 * @param[in] flags Flags to assign to all the nodes.
Radek Krejcib3142312016-11-09 11:04:12 +01004304 * @param[in,out] unres List of unresolved items.
Michal Vaskoa86508c2016-08-26 14:30:19 +02004305 *
4306 * @return 0 on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004307 */
Michal Vaskoa86508c2016-08-26 14:30:19 +02004308static int
Radek Krejcib3142312016-11-09 11:04:12 +01004309inherit_config_flag(struct lys_node *node, int flags, int clear, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004310{
Radek Krejcif71f48f2016-10-25 16:37:24 +02004311 struct lys_node_leaf *leaf;
4312
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004313 assert(!(flags ^ (flags & LYS_CONFIG_MASK)));
Radek Krejci1d82ef62015-08-07 14:44:40 +02004314 LY_TREE_FOR(node, node) {
Radek Krejcib3142312016-11-09 11:04:12 +01004315 if (lys_has_xpath(node) && unres_schema_add_node(node->module, unres, node, UNRES_XPATH, NULL) == -1) {
Michal Vasko9e635ac2016-10-17 11:44:09 +02004316 return -1;
4317 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004318 if (clear) {
4319 node->flags &= ~LYS_CONFIG_MASK;
Michal Vaskoc2a8d362016-09-29 08:50:13 +02004320 node->flags &= ~LYS_CONFIG_SET;
Michal Vaskoe022a562016-09-27 14:24:15 +02004321 } else {
4322 if (node->flags & LYS_CONFIG_SET) {
4323 /* skip nodes with an explicit config value */
4324 if ((flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
4325 LOGVAL(LYE_INARG, LY_VLOG_LYS, node, "true", "config");
4326 LOGVAL(LYE_SPEC, LY_VLOG_LYS, node, "State nodes cannot have configuration nodes as children.");
4327 return -1;
4328 }
4329 continue;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004330 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004331
4332 if (!(node->nodetype & (LYS_USES | LYS_GROUPING))) {
4333 node->flags = (node->flags & ~LYS_CONFIG_MASK) | flags;
4334 /* check that configuration lists have keys */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004335 if ((node->nodetype == LYS_LIST) && (node->flags & LYS_CONFIG_W)
4336 && !((struct lys_node_list *)node)->keys_size) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004337 LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_LYS, node, "key", "list");
4338 return -1;
4339 }
4340 }
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004341 }
Radek Krejcibf2abff2016-08-23 15:51:52 +02004342 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Radek Krejcib3142312016-11-09 11:04:12 +01004343 if (inherit_config_flag(node->child, flags, clear, unres)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004344 return -1;
4345 }
Radek Krejcif71f48f2016-10-25 16:37:24 +02004346 } else if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
4347 leaf = (struct lys_node_leaf *)node;
4348 if (check_leafref_config(leaf, &leaf->type)) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02004349 return -1;
4350 }
4351 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004352 }
Michal Vaskoa86508c2016-08-26 14:30:19 +02004353
4354 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004355}
4356
Michal Vasko730dfdf2015-08-11 14:48:05 +02004357/**
Michal Vasko7178e692016-02-12 15:58:05 +01004358 * @brief Resolve augment target. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004359 *
Michal Vaskobb211122015-08-19 14:03:11 +02004360 * @param[in] aug Augment to use.
Michal Vasko3edeaf72016-02-11 13:17:43 +01004361 * @param[in] siblings Nodes where to start the search in. If set, uses augment, if not, standalone augment.
Radek Krejcib3142312016-11-09 11:04:12 +01004362 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004363 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004364 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004365 */
Michal Vasko7178e692016-02-12 15:58:05 +01004366static int
Radek Krejcib3142312016-11-09 11:04:12 +01004367resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004368{
Michal Vaskoe022a562016-09-27 14:24:15 +02004369 int rc, clear_config;
Michal Vasko1d87a922015-08-21 12:57:16 +02004370 struct lys_node *sub;
Pavol Vican47319932016-08-29 09:14:47 +02004371 const struct lys_node *aug_target, *parent;
Radek Krejci27fe55e2016-09-13 17:13:35 +02004372 struct lys_module *mod;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004373
Michal Vasko15b36692016-08-26 15:29:54 +02004374 assert(aug && !aug->target);
Radek Krejcidf46e222016-11-08 11:57:37 +01004375 mod = lys_main_module(aug->module);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004376
Michal Vasko15b36692016-08-26 15:29:54 +02004377 /* resolve target node */
Radek Krejcidf46e222016-11-08 11:57:37 +01004378 rc = resolve_augment_schema_nodeid(aug->target_name, siblings, (siblings ? NULL : aug->module), mod->implemented, &aug_target);
Michal Vasko15b36692016-08-26 15:29:54 +02004379 if (rc == -1) {
4380 return -1;
Radek Krejci5fb4c382016-11-28 09:21:42 +01004381 } else if (rc > 0) {
Michal Vasko15b36692016-08-26 15:29:54 +02004382 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, aug, aug->target_name[rc - 1], &aug->target_name[rc - 1]);
4383 return -1;
Radek Krejci5fb4c382016-11-28 09:21:42 +01004384 } else if (rc == 0 && aug->target) {
4385 /* augment was resolved as a side effect of setting module implemented when
4386 * resolving augment schema nodeid, so we are done here */
4387 return 0;
Michal Vasko15b36692016-08-26 15:29:54 +02004388 }
Radek Krejcidf46e222016-11-08 11:57:37 +01004389 if (!aug_target && mod->implemented) {
Michal Vasko15b36692016-08-26 15:29:54 +02004390 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
4391 return EXIT_FAILURE;
4392 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02004393 /* check that we want to connect augment into its target */
Radek Krejci27fe55e2016-09-13 17:13:35 +02004394 if (!mod->implemented) {
4395 /* it must be augment only to the same module,
4396 * otherwise we do not apply augment in not-implemented
4397 * module. If the module is set to be implemented in future,
4398 * the augment is being resolved and checked again */
Radek Krejcidf46e222016-11-08 11:57:37 +01004399 if (!aug_target) {
4400 /* target was not even resolved */
4401 return EXIT_SUCCESS;
4402 }
4403 /* target was resolved, but it may refer another module */
4404 for (sub = (struct lys_node *)aug_target; sub; sub = lys_parent(sub)) {
Radek Krejci27fe55e2016-09-13 17:13:35 +02004405 if (lys_node_module(sub) != mod) {
4406 /* this is not an implemented module and the augment
4407 * target some other module, so avoid its connecting
4408 * to the target */
4409 return EXIT_SUCCESS;
4410 }
4411 }
4412 }
4413
Michal Vasko15b36692016-08-26 15:29:54 +02004414 if (!aug->child) {
4415 /* nothing to do */
4416 LOGWRN("Augment \"%s\" without children.", aug->target_name);
Radek Krejci27fe55e2016-09-13 17:13:35 +02004417 goto success;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004418 }
4419
Michal Vaskod58d5962016-03-02 14:29:41 +01004420 /* check for mandatory nodes - if the target node is in another module
4421 * the added nodes cannot be mandatory
4422 */
Michal Vasko15b36692016-08-26 15:29:54 +02004423 if (!aug->parent && (lys_node_module((struct lys_node *)aug) != lys_node_module(aug_target))
Radek Krejcidf24cbe2016-11-08 11:55:51 +01004424 && (rc = lyp_check_mandatory_augment(aug, aug_target))) {
Radek Krejcie00d2312016-08-12 15:27:49 +02004425 return rc;
Michal Vaskod58d5962016-03-02 14:29:41 +01004426 }
4427
Michal Vasko07e89ef2016-03-03 13:28:57 +01004428 /* check augment target type and then augment nodes type */
Michal Vasko15b36692016-08-26 15:29:54 +02004429 if (aug_target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF)) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004430 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004431 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES | LYS_CHOICE))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004432 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4433 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko15b36692016-08-26 15:29:54 +02004434 strnodetype(aug_target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004435 return -1;
4436 }
4437 }
Michal Vasko15b36692016-08-26 15:29:54 +02004438 } else if (aug_target->nodetype == LYS_CHOICE) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004439 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004440 if (!(sub->nodetype & (LYS_CASE | LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004441 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4442 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko15b36692016-08-26 15:29:54 +02004443 strnodetype(aug_target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004444 return -1;
4445 }
4446 }
4447 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01004448 LOGVAL(LYE_INARG, LY_VLOG_LYS, aug, aug->target_name, "target-node");
Michal Vasko15b36692016-08-26 15:29:54 +02004449 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Invalid augment target node type \"%s\".", strnodetype(aug_target->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004450 return -1;
4451 }
4452
Radek Krejcic071c542016-01-27 14:57:51 +01004453 /* check identifier uniqueness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02004454 LY_TREE_FOR(aug->child, sub) {
Michal Vasko15b36692016-08-26 15:29:54 +02004455 if (lys_check_id(sub, (struct lys_node *)aug_target, NULL)) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02004456 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02004457 }
4458 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004459
Michal Vasko15b36692016-08-26 15:29:54 +02004460 /* finally reconnect augmenting data into the target - add them to the target child list,
4461 * by setting aug->target we know the augment is fully resolved now */
4462 aug->target = (struct lys_node *)aug_target;
4463 if (aug->target->child) {
4464 sub = aug->target->child->prev; /* remember current target's last node */
4465 sub->next = aug->child; /* connect augmenting data after target's last node */
4466 aug->target->child->prev = aug->child->prev; /* new target's last node is last augmenting node */
4467 aug->child->prev = sub; /* finish connecting of both child lists */
4468 } else {
4469 aug->target->child = aug->child;
4470 }
4471
Michal Vasko9e635ac2016-10-17 11:44:09 +02004472 /* inherit config information from actual parent */
4473 for(parent = aug_target; parent && !(parent->nodetype & (LYS_NOTIF | LYS_INPUT | LYS_OUTPUT | LYS_RPC)); parent = lys_parent(parent));
4474 clear_config = (parent) ? 1 : 0;
4475 LY_TREE_FOR(aug->child, sub) {
Radek Krejcib3142312016-11-09 11:04:12 +01004476 if (inherit_config_flag(sub, aug_target->flags & LYS_CONFIG_MASK, clear_config, unres)) {
Michal Vasko9e635ac2016-10-17 11:44:09 +02004477 return -1;
4478 }
4479 }
4480
Radek Krejci27fe55e2016-09-13 17:13:35 +02004481success:
4482 if (mod->implemented) {
4483 /* make target modules also implemented */
4484 for (sub = aug->target; sub; sub = lys_parent(sub)) {
4485 if (lys_set_implemented(sub->module)) {
4486 return -1;
4487 }
4488 }
4489 }
4490
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004491 return EXIT_SUCCESS;
4492}
4493
Michal Vasko730dfdf2015-08-11 14:48:05 +02004494/**
Pavol Vican855ca622016-09-05 13:07:54 +02004495 * @brief Resolve (find) choice default case. Does not log.
4496 *
4497 * @param[in] choic Choice to use.
4498 * @param[in] dflt Name of the default case.
4499 *
4500 * @return Pointer to the default node or NULL.
4501 */
4502static struct lys_node *
4503resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
4504{
4505 struct lys_node *child, *ret;
4506
4507 LY_TREE_FOR(choic->child, child) {
4508 if (child->nodetype == LYS_USES) {
4509 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
4510 if (ret) {
4511 return ret;
4512 }
4513 }
4514
4515 if (ly_strequal(child->name, dflt, 1) && (child->nodetype & (LYS_ANYDATA | LYS_CASE
Radek Krejci2f792db2016-09-12 10:52:33 +02004516 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE))) {
Pavol Vican855ca622016-09-05 13:07:54 +02004517 return child;
4518 }
4519 }
4520
4521 return NULL;
4522}
4523
4524/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02004525 * @brief Resolve uses, apply augments, refines. Logs directly.
4526 *
Michal Vaskobb211122015-08-19 14:03:11 +02004527 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004528 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004529 *
Michal Vaskodef0db12015-10-07 13:22:48 +02004530 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004531 */
Michal Vasko184521f2015-09-24 13:14:26 +02004532static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004533resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004534{
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004535 struct ly_ctx *ctx = uses->module->ctx; /* shortcut */
Pavol Vican855ca622016-09-05 13:07:54 +02004536 struct lys_node *node = NULL, *next, *iter, **refine_nodes = NULL;
Pavol Vican55abd332016-07-12 15:54:49 +02004537 struct lys_node *node_aux, *parent, *tmp;
Radek Krejci200bf712016-08-16 17:11:04 +02004538 struct lys_node_leaflist *llist;
4539 struct lys_node_leaf *leaf;
Radek Krejci76512572015-08-04 09:47:08 +02004540 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004541 struct lys_restr *must, **old_must;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004542 struct lys_iffeature *iff, **old_iff;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004543 int i, j, k, rc;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004544 uint8_t size, *old_size;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004545 unsigned int usize, usize1, usize2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004546
Michal Vasko71e1aa82015-08-12 12:17:51 +02004547 assert(uses->grp);
Michal Vaskoe7708512016-03-11 10:26:55 +01004548 /* HACK just check that the grouping is resolved */
Michal Vaskodef0db12015-10-07 13:22:48 +02004549 assert(!uses->grp->nacm);
Michal Vasko71e1aa82015-08-12 12:17:51 +02004550
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004551 if (!uses->grp->child) {
4552 /* grouping without children, warning was already displayed */
4553 return EXIT_SUCCESS;
4554 }
4555
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004556 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01004557 LY_TREE_FOR(uses->grp->child, node_aux) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004558 node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, uses->nacm, unres, 0);
Michal Vasko1e62a092015-12-01 12:27:20 +01004559 if (!node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004560 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, uses->grp->name, "uses");
4561 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Copying data from grouping failed.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004562 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004563 }
Pavol Vican55abd332016-07-12 15:54:49 +02004564 /* test the name of siblings */
4565 LY_TREE_FOR((uses->parent) ? uses->parent->child : lys_main_module(uses->module)->data, tmp) {
Pavol Vican2510ddc2016-07-18 16:23:44 +02004566 if (!(tmp->nodetype & (LYS_USES | LYS_GROUPING | LYS_CASE)) && ly_strequal(tmp->name, node_aux->name, 1)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004567 goto fail;
Pavol Vican55abd332016-07-12 15:54:49 +02004568 }
4569 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004570 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004571
Michal Vaskodef0db12015-10-07 13:22:48 +02004572 /* we managed to copy the grouping, the rest must be possible to resolve */
4573
Pavol Vican855ca622016-09-05 13:07:54 +02004574 if (uses->refine_size) {
4575 refine_nodes = malloc(uses->refine_size * sizeof *refine_nodes);
4576 if (!refine_nodes) {
4577 LOGMEM;
4578 goto fail;
4579 }
4580 }
4581
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004582 /* apply refines */
4583 for (i = 0; i < uses->refine_size; i++) {
4584 rfn = &uses->refine[i];
Michal Vasko3edeaf72016-02-11 13:17:43 +01004585 rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child, LYS_NO_RPC_NOTIF_NODE,
Radek Krejcif3c71de2016-04-11 12:45:46 +02004586 1, 0, (const struct lys_node **)&node);
Michal Vasko9bb061b2016-02-12 11:00:19 +01004587 if (rc || !node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004588 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004589 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004590 }
4591
Radek Krejci1d82ef62015-08-07 14:44:40 +02004592 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004593 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
4594 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Refine substatements not applicable to the target-node.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004595 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004596 }
Pavol Vican855ca622016-09-05 13:07:54 +02004597 refine_nodes[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004598
4599 /* description on any nodetype */
4600 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004601 lydict_remove(ctx, node->dsc);
4602 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004603 }
4604
4605 /* reference on any nodetype */
4606 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004607 lydict_remove(ctx, node->ref);
4608 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004609 }
4610
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004611 /* config on any nodetype,
4612 * in case of notification or rpc/action, the config is not applicable (there is no config status) */
4613 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004614 node->flags &= ~LYS_CONFIG_MASK;
4615 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004616 }
4617
4618 /* default value ... */
Radek Krejci200bf712016-08-16 17:11:04 +02004619 if (rfn->dflt_size) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004620 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004621 /* leaf */
Radek Krejci200bf712016-08-16 17:11:04 +02004622 leaf = (struct lys_node_leaf *)node;
4623
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004624 /* replace default value */
Radek Krejci200bf712016-08-16 17:11:04 +02004625 lydict_remove(ctx, leaf->dflt);
4626 leaf->dflt = lydict_insert(ctx, rfn->dflt[0], 0);
4627
4628 /* check the default value */
Radek Krejci51673202016-11-01 17:00:32 +01004629 if (unres_schema_add_node(leaf->module, unres, &leaf->type, UNRES_TYPE_DFLT,
4630 (struct lys_node *)(&leaf->dflt)) == -1) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004631 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004632 }
Radek Krejci200bf712016-08-16 17:11:04 +02004633 } else if (node->nodetype == LYS_LEAFLIST) {
4634 /* leaf-list */
4635 llist = (struct lys_node_leaflist *)node;
4636
4637 /* remove complete set of defaults in target */
4638 for (i = 0; i < llist->dflt_size; i++) {
4639 lydict_remove(ctx, llist->dflt[i]);
4640 }
4641 free(llist->dflt);
4642
4643 /* copy the default set from refine */
4644 llist->dflt_size = rfn->dflt_size;
4645 llist->dflt = malloc(llist->dflt_size * sizeof *llist->dflt);
4646 for (i = 0; i < llist->dflt_size; i++) {
4647 llist->dflt[i] = lydict_insert(ctx, rfn->dflt[i], 0);
4648 }
4649
4650 /* check default value */
4651 for (i = 0; i < llist->dflt_size; i++) {
Radek Krejci51673202016-11-01 17:00:32 +01004652 if (unres_schema_add_node(llist->module, unres, &llist->type, UNRES_TYPE_DFLT,
4653 (struct lys_node *)(&llist->dflt[i])) == -1) {
Pavol Vican855ca622016-09-05 13:07:54 +02004654 goto fail;
Radek Krejci200bf712016-08-16 17:11:04 +02004655 }
4656 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004657 }
4658 }
4659
4660 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02004661 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004662 if (node->nodetype & (LYS_LEAF | LYS_ANYDATA | LYS_CHOICE)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004663 /* remove current value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004664 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004665
4666 /* set new value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004667 node->flags |= (rfn->flags & LYS_MAND_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004668 }
Pavol Vican855ca622016-09-05 13:07:54 +02004669 if (rfn->flags & LYS_MAND_TRUE) {
4670 /* check if node has default value */
4671 if ((node->nodetype & LYS_LEAF) && ((struct lys_node_leaf *)node)->dflt) {
4672 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"mandatory\" statement is forbidden on leaf with \"default\".");
4673 goto fail;
4674 }
4675 if ((node->nodetype & LYS_CHOICE) && ((struct lys_node_choice *)node)->dflt) {
4676 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"mandatory\" statement is forbidden on choices with \"default\".");
4677 goto fail;
4678 }
4679 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004680 }
4681
4682 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004683 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
4684 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
4685 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004686 }
4687
4688 /* min/max-elements on list or leaf-list */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004689 if (node->nodetype == LYS_LIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004690 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004691 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004692 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004693 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004694 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004695 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02004696 } else if (node->nodetype == LYS_LEAFLIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004697 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004698 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004699 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004700 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004701 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004702 }
4703 }
4704
4705 /* must in leaf, leaf-list, list, container or anyxml */
4706 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004707 switch (node->nodetype) {
4708 case LYS_LEAF:
4709 old_size = &((struct lys_node_leaf *)node)->must_size;
4710 old_must = &((struct lys_node_leaf *)node)->must;
4711 break;
4712 case LYS_LEAFLIST:
4713 old_size = &((struct lys_node_leaflist *)node)->must_size;
4714 old_must = &((struct lys_node_leaflist *)node)->must;
4715 break;
4716 case LYS_LIST:
4717 old_size = &((struct lys_node_list *)node)->must_size;
4718 old_must = &((struct lys_node_list *)node)->must;
4719 break;
4720 case LYS_CONTAINER:
4721 old_size = &((struct lys_node_container *)node)->must_size;
4722 old_must = &((struct lys_node_container *)node)->must;
4723 break;
4724 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02004725 case LYS_ANYDATA:
4726 old_size = &((struct lys_node_anydata *)node)->must_size;
4727 old_must = &((struct lys_node_anydata *)node)->must;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004728 break;
4729 default:
4730 LOGINT;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004731 goto fail;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004732 }
4733
4734 size = *old_size + rfn->must_size;
4735 must = realloc(*old_must, size * sizeof *rfn->must);
4736 if (!must) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004737 LOGMEM;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004738 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004739 }
Pavol Vican855ca622016-09-05 13:07:54 +02004740 for (k = 0, j = *old_size; k < rfn->must_size; k++, j++) {
4741 must[j].expr = lydict_insert(ctx, rfn->must[k].expr, 0);
4742 must[j].dsc = lydict_insert(ctx, rfn->must[k].dsc, 0);
4743 must[j].ref = lydict_insert(ctx, rfn->must[k].ref, 0);
4744 must[j].eapptag = lydict_insert(ctx, rfn->must[k].eapptag, 0);
4745 must[j].emsg = lydict_insert(ctx, rfn->must[k].emsg, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004746 }
4747
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004748 *old_must = must;
4749 *old_size = size;
Michal Vasko508a50d2016-09-07 14:50:33 +02004750
4751 /* check XPath dependencies again */
4752 if (unres_schema_add_node(node->module, unres, node, UNRES_XPATH, NULL) == -1) {
4753 goto fail;
4754 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004755 }
Radek Krejci363bd4a2016-07-29 14:30:20 +02004756
4757 /* if-feature in leaf, leaf-list, list, container or anyxml */
4758 if (rfn->iffeature_size) {
4759 old_size = &node->iffeature_size;
4760 old_iff = &node->iffeature;
4761
4762 size = *old_size + rfn->iffeature_size;
4763 iff = realloc(*old_iff, size * sizeof *rfn->iffeature);
4764 if (!iff) {
4765 LOGMEM;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004766 goto fail;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004767 }
Pavol Vican855ca622016-09-05 13:07:54 +02004768 for (k = 0, j = *old_size; k < rfn->iffeature_size; k++, j++) {
4769 resolve_iffeature_getsizes(&rfn->iffeature[k], &usize1, &usize2);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004770 if (usize1) {
4771 /* there is something to duplicate */
4772 /* duplicate compiled expression */
4773 usize = (usize1 / 4) + (usize1 % 4) ? 1 : 0;
4774 iff[j].expr = malloc(usize * sizeof *iff[j].expr);
Pavol Vican855ca622016-09-05 13:07:54 +02004775 memcpy(iff[j].expr, rfn->iffeature[k].expr, usize * sizeof *iff[j].expr);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004776
4777 /* duplicate list of feature pointers */
Pavol Vican855ca622016-09-05 13:07:54 +02004778 iff[j].features = malloc(usize2 * sizeof *iff[k].features);
4779 memcpy(iff[j].features, rfn->iffeature[k].features, usize2 * sizeof *iff[j].features);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004780 }
4781 }
4782
4783 *old_iff = iff;
4784 *old_size = size;
4785 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004786 }
4787
4788 /* apply augments */
4789 for (i = 0; i < uses->augment_size; i++) {
Radek Krejcib3142312016-11-09 11:04:12 +01004790 rc = resolve_augment(&uses->augment[i], uses->child, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004791 if (rc) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004792 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004793 }
4794 }
4795
Pavol Vican855ca622016-09-05 13:07:54 +02004796 /* check refines */
4797 for (i = 0; i < uses->refine_size; i++) {
4798 node = refine_nodes[i];
4799 rfn = &uses->refine[i];
4800
4801 /* config on any nodetype */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004802 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Pavol Vican855ca622016-09-05 13:07:54 +02004803 for (parent = lys_parent(node); parent && parent->nodetype == LYS_USES; parent = lys_parent(parent));
Radek Krejci5c08a992016-11-02 13:30:04 +01004804 if (parent && parent->nodetype != LYS_GROUPING && (parent->flags & LYS_CONFIG_MASK) &&
Pavol Vican855ca622016-09-05 13:07:54 +02004805 ((parent->flags & LYS_CONFIG_MASK) != (rfn->flags & LYS_CONFIG_MASK)) &&
4806 (rfn->flags & LYS_CONFIG_W)) {
4807 /* setting config true under config false is prohibited */
4808 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
4809 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4810 "changing config from 'false' to 'true' is prohibited while "
4811 "the target's parent is still config 'false'.");
4812 goto fail;
4813 }
4814
4815 /* inherit config change to the target children */
4816 LY_TREE_DFS_BEGIN(node->child, next, iter) {
4817 if (rfn->flags & LYS_CONFIG_W) {
4818 if (iter->flags & LYS_CONFIG_SET) {
4819 /* config is set explicitely, go to next sibling */
4820 next = NULL;
4821 goto nextsibling;
4822 }
4823 } else { /* LYS_CONFIG_R */
4824 if ((iter->flags & LYS_CONFIG_SET) && (iter->flags & LYS_CONFIG_W)) {
4825 /* error - we would have config data under status data */
4826 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
4827 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4828 "changing config from 'true' to 'false' is prohibited while the target "
4829 "has still a children with explicit config 'true'.");
4830 goto fail;
4831 }
4832 }
4833 /* change config */
4834 iter->flags &= ~LYS_CONFIG_MASK;
4835 iter->flags |= (rfn->flags & LYS_CONFIG_MASK);
4836
4837 /* select next iter - modified LY_TREE_DFS_END */
4838 if (iter->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
4839 next = NULL;
4840 } else {
4841 next = iter->child;
4842 }
4843nextsibling:
4844 if (!next) {
4845 /* try siblings */
4846 next = iter->next;
4847 }
4848 while (!next) {
4849 /* parent is already processed, go to its sibling */
4850 iter = lys_parent(iter);
4851
4852 /* no siblings, go back through parents */
4853 if (iter == node) {
4854 /* we are done, no next element to process */
4855 break;
4856 }
4857 next = iter->next;
4858 }
4859 }
4860 }
4861
4862 /* default value */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004863 if (rfn->dflt_size) {
4864 if (node->nodetype == LYS_CHOICE) {
4865 /* choice */
4866 ((struct lys_node_choice *)node)->dflt = resolve_choice_dflt((struct lys_node_choice *)node,
4867 rfn->dflt[0]);
4868 if (!((struct lys_node_choice *)node)->dflt) {
4869 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->dflt[0], "default");
4870 goto fail;
4871 }
4872 if (lyp_check_mandatory_choice(node)) {
4873 goto fail;
4874 }
Pavol Vican855ca622016-09-05 13:07:54 +02004875 }
4876 }
4877
4878 /* min/max-elements on list or leaf-list */
4879 if (node->nodetype == LYS_LIST) {
4880 if (((struct lys_node_list *)node)->min > ((struct lys_node_list *)node)->max) {
4881 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
4882 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "\"min-elements\" is bigger than \"max-elements\".");
4883 goto fail;
4884 }
4885 } else if (node->nodetype == LYS_LEAFLIST) {
4886 if (((struct lys_node_leaflist *)node)->min > ((struct lys_node_leaflist *)node)->max) {
4887 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
4888 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "\"min-elements\" is bigger than \"max-elements\".");
4889 goto fail;
4890 }
4891 }
4892
4893 /* additional checks */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004894 /* default value with mandatory/min-elements */
Pavol Vican855ca622016-09-05 13:07:54 +02004895 if (node->nodetype == LYS_LEAFLIST) {
4896 llist = (struct lys_node_leaflist *)node;
4897 if (llist->dflt_size && llist->min) {
4898 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, rfn->dflt_size ? "default" : "min-elements", "refine");
4899 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
4900 "The \"min-elements\" statement with non-zero value is forbidden on leaf-lists with the \"default\" statement.");
4901 goto fail;
4902 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004903 } else if (node->nodetype == LYS_LEAF) {
4904 leaf = (struct lys_node_leaf *)node;
4905 if (leaf->dflt && (leaf->flags & LYS_MAND_TRUE)) {
4906 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, rfn->dflt_size ? "default" : "mandatory", "refine");
4907 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
4908 "The \"mandatory\" statement is forbidden on leafs with the \"default\" statement.");
4909 goto fail;
4910 }
Pavol Vican855ca622016-09-05 13:07:54 +02004911 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004912
Pavol Vican855ca622016-09-05 13:07:54 +02004913 /* check for mandatory node in default case, first find the closest parent choice to the changed node */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004914 if ((rfn->flags & LYS_MAND_TRUE) || rfn->mod.list.min) {
Pavol Vican855ca622016-09-05 13:07:54 +02004915 for (parent = node->parent;
4916 parent && !(parent->nodetype & (LYS_CHOICE | LYS_GROUPING | LYS_ACTION | LYS_USES));
4917 parent = parent->parent) {
4918 if (parent->nodetype == LYS_CONTAINER && ((struct lys_node_container *)parent)->presence) {
4919 /* stop also on presence containers */
4920 break;
4921 }
4922 }
4923 /* and if it is a choice with the default case, check it for presence of a mandatory node in it */
4924 if (parent && parent->nodetype == LYS_CHOICE && ((struct lys_node_choice *)parent)->dflt) {
4925 if (lyp_check_mandatory_choice(parent)) {
4926 goto fail;
4927 }
4928 }
4929 }
4930 }
4931 free(refine_nodes);
4932
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004933 return EXIT_SUCCESS;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004934
4935fail:
4936 LY_TREE_FOR_SAFE(uses->child, next, iter) {
4937 lys_node_free(iter, NULL, 0);
4938 }
Pavol Vican855ca622016-09-05 13:07:54 +02004939 free(refine_nodes);
Michal Vaskoa86508c2016-08-26 14:30:19 +02004940 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004941}
4942
Radek Krejci018f1f52016-08-03 16:01:20 +02004943static int
4944identity_backlink_update(struct lys_ident *der, struct lys_ident *base)
4945{
4946 int i;
4947
4948 assert(der && base);
4949
Radek Krejci018f1f52016-08-03 16:01:20 +02004950 if (!base->der) {
Radek Krejci85a54be2016-10-20 12:39:56 +02004951 /* create a set for backlinks if it does not exist */
4952 base->der = ly_set_new();
Radek Krejci018f1f52016-08-03 16:01:20 +02004953 }
Radek Krejci85a54be2016-10-20 12:39:56 +02004954 /* store backlink */
4955 ly_set_add(base->der, der, LY_SET_OPT_USEASLIST);
Radek Krejci018f1f52016-08-03 16:01:20 +02004956
Radek Krejci85a54be2016-10-20 12:39:56 +02004957 /* do it recursively */
Radek Krejci018f1f52016-08-03 16:01:20 +02004958 for (i = 0; i < base->base_size; i++) {
4959 if (identity_backlink_update(der, base->base[i])) {
4960 return EXIT_FAILURE;
4961 }
4962 }
4963
4964 return EXIT_SUCCESS;
4965}
4966
Michal Vasko730dfdf2015-08-11 14:48:05 +02004967/**
4968 * @brief Resolve base identity recursively. Does not log.
4969 *
4970 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004971 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004972 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004973 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004974 *
Radek Krejci219fa612016-08-15 10:36:51 +02004975 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on crucial error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004976 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004977static int
Michal Vasko1e62a092015-12-01 12:27:20 +01004978resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Radek Krejci018f1f52016-08-03 16:01:20 +02004979 struct unres_schema *unres, struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004980{
Michal Vaskof02e3742015-08-05 16:27:02 +02004981 uint32_t i, j;
Radek Krejci018f1f52016-08-03 16:01:20 +02004982 struct lys_ident *base = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004983
Radek Krejcicf509982015-12-15 09:22:44 +01004984 assert(ret);
4985
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004986 /* search module */
4987 for (i = 0; i < module->ident_size; i++) {
4988 if (!strcmp(basename, module->ident[i].name)) {
4989
4990 if (!ident) {
4991 /* just search for type, so do not modify anything, just return
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004992 * the base identity pointer */
Radek Krejcicf509982015-12-15 09:22:44 +01004993 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004994 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004995 }
4996
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004997 base = &module->ident[i];
4998 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004999 }
5000 }
5001
5002 /* search submodules */
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005003 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
5004 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
5005 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005006
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005007 if (!ident) {
5008 *ret = &module->inc[j].submodule->ident[i];
5009 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005010 }
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005011
5012 base = &module->inc[j].submodule->ident[i];
5013 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005014 }
5015 }
5016 }
5017
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005018matchfound:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005019 /* we found it somewhere */
Radek Krejcibabbff82016-02-19 13:31:37 +01005020 if (base) {
Radek Krejci018f1f52016-08-03 16:01:20 +02005021 /* is it already completely resolved? */
5022 for (i = 0; i < unres->count; i++) {
Radek Krejciba7b1cc2016-08-08 13:44:43 +02005023 if ((unres->item[i] == base) && (unres->type[i] == UNRES_IDENT)) {
Radek Krejci018f1f52016-08-03 16:01:20 +02005024 /* identity found, but not yet resolved, so do not return it in *res and try it again later */
5025
5026 /* simple check for circular reference,
5027 * the complete check is done as a side effect of using only completely
5028 * resolved identities (previous check of unres content) */
5029 if (ly_strequal((const char *)unres->str_snode[i], ident->name, 1)) {
5030 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, basename, "base");
5031 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Circular reference of \"%s\" identity.", basename);
Radek Krejci219fa612016-08-15 10:36:51 +02005032 return -1;
Radek Krejci018f1f52016-08-03 16:01:20 +02005033 }
5034
Radek Krejci06f64ed2016-08-15 11:07:44 +02005035 return EXIT_FAILURE;
Radek Krejcibabbff82016-02-19 13:31:37 +01005036 }
5037 }
Radek Krejci018f1f52016-08-03 16:01:20 +02005038
Radek Krejcibabbff82016-02-19 13:31:37 +01005039 /* checks done, store the result */
Radek Krejci018f1f52016-08-03 16:01:20 +02005040 *ret = base;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02005041 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005042 }
5043
Radek Krejci219fa612016-08-15 10:36:51 +02005044 /* base not found (maybe a forward reference) */
5045 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005046}
5047
Michal Vasko730dfdf2015-08-11 14:48:05 +02005048/**
5049 * @brief Resolve base identity. Logs directly.
5050 *
5051 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02005052 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005053 * @param[in] basename Base name of the identity.
Radek Krejcibabbff82016-02-19 13:31:37 +01005054 * @param[in] parent Either "type" or "identity".
Radek Krejcicf509982015-12-15 09:22:44 +01005055 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005056 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005057 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005058 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005059static int
Michal Vaskof2d43962016-09-02 11:10:16 +02005060resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char *parent,
Radek Krejci018f1f52016-08-03 16:01:20 +02005061 struct lys_type *type, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005062{
5063 const char *name;
Radek Krejci219fa612016-08-15 10:36:51 +02005064 int mod_name_len = 0, rc;
Radek Krejcicf509982015-12-15 09:22:44 +01005065 struct lys_ident *target, **ret;
Radek Krejci4372b4e2016-04-14 17:42:16 +02005066 uint16_t flags;
Radek Krejcicf509982015-12-15 09:22:44 +01005067 struct lys_module *mod;
5068
5069 assert((ident && !type) || (!ident && type));
5070
5071 if (!type) {
5072 /* have ident to resolve */
5073 ret = &target;
5074 flags = ident->flags;
5075 mod = ident->module;
5076 } else {
5077 /* have type to fill */
Michal Vaskof2d43962016-09-02 11:10:16 +02005078 ++type->info.ident.count;
5079 type->info.ident.ref = ly_realloc(type->info.ident.ref, type->info.ident.count * sizeof *type->info.ident.ref);
5080 if (!type->info.ident.ref) {
5081 LOGMEM;
5082 return -1;
5083 }
5084
5085 ret = &type->info.ident.ref[type->info.ident.count - 1];
Radek Krejcicf509982015-12-15 09:22:44 +01005086 flags = type->parent->flags;
5087 mod = type->parent->module;
5088 }
Michal Vaskof2006002016-04-21 16:28:15 +02005089 *ret = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005090
5091 /* search for the base identity */
5092 name = strchr(basename, ':');
5093 if (name) {
5094 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02005095 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005096 name++;
5097
Michal Vasko2d851a92015-10-20 16:16:36 +02005098 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005099 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02005100 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005101 }
5102 } else {
5103 name = basename;
5104 }
5105
Radek Krejcic071c542016-01-27 14:57:51 +01005106 /* get module where to search */
5107 module = lys_get_import_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len);
5108 if (!module) {
5109 /* identity refers unknown data model */
Radek Krejci02a04992016-03-17 16:06:37 +01005110 LOGVAL(LYE_INMOD, LY_VLOG_NONE, NULL, basename);
Radek Krejcic071c542016-01-27 14:57:51 +01005111 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005112 }
5113
Radek Krejcic071c542016-01-27 14:57:51 +01005114 /* search in the identified module ... */
Radek Krejci219fa612016-08-15 10:36:51 +02005115 rc = resolve_base_ident_sub(module, ident, name, unres, ret);
5116 if (!rc) {
5117 assert(*ret);
5118
5119 /* check status */
5120 if (lyp_check_status(flags, mod, ident ? ident->name : "of type",
5121 (*ret)->flags, (*ret)->module, (*ret)->name, NULL)) {
5122 rc = -1;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02005123 } else {
5124 if (ident) {
5125 ident->base[ident->base_size++] = *ret;
5126
5127 /* maintain backlinks to the derived identities */
5128 rc = identity_backlink_update(ident, *ret) ? -1 : EXIT_SUCCESS;
5129 }
Radek Krejci219fa612016-08-15 10:36:51 +02005130 }
5131 } else if (rc == EXIT_FAILURE) {
5132 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, parent, basename);
Pavol Vican053a2882016-09-05 14:40:33 +02005133 if (type) {
5134 --type->info.ident.count;
5135 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005136 }
5137
Radek Krejci219fa612016-08-15 10:36:51 +02005138 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005139}
5140
Michal Vasko730dfdf2015-08-11 14:48:05 +02005141/**
Michal Vaskof39142b2015-10-21 11:40:05 +02005142 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005143 *
Michal Vaskof2d43962016-09-02 11:10:16 +02005144 * @param[in] type Identityref type.
Michal Vaskofb0873c2015-08-21 09:00:07 +02005145 * @param[in] ident_name Identityref name.
Radek Krejciadb57612016-02-16 13:34:34 +01005146 * @param[in] node Node where the identityref is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02005147 *
5148 * @return Pointer to the identity resolvent, NULL on error.
5149 */
Radek Krejcia52656e2015-08-05 13:41:50 +02005150struct lys_ident *
Michal Vaskof2d43962016-09-02 11:10:16 +02005151resolve_identref(struct lys_type *type, const char *ident_name, struct lyd_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005152{
Michal Vaskoc633ca02015-08-21 14:03:51 +02005153 const char *mod_name, *name;
Radek Krejci85a54be2016-10-20 12:39:56 +02005154 int mod_name_len, rc, i;
5155 unsigned int u;
Michal Vaskof2d43962016-09-02 11:10:16 +02005156 struct lys_ident *der, *cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005157
Michal Vaskof2d43962016-09-02 11:10:16 +02005158 if (!type || (!type->info.ident.count && !type->der) || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005159 return NULL;
5160 }
5161
Michal Vaskoc633ca02015-08-21 14:03:51 +02005162 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, NULL);
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005163 if (rc < 1) {
Radek Krejci1899d6a2016-11-03 13:48:07 +01005164 if (node) {
5165 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
Radek Krejci5dca5932016-11-04 14:30:47 +01005166 } else {
5167 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid identityref value \"%s\".", ident_name);
5168 ly_vecode = LYVE_INCHAR;
Radek Krejci1899d6a2016-11-03 13:48:07 +01005169 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02005170 return NULL;
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005171 } else if (rc < (signed)strlen(ident_name)) {
Radek Krejci1899d6a2016-11-03 13:48:07 +01005172 if (node) {
5173 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[rc], &ident_name[rc]);
Radek Krejci5dca5932016-11-04 14:30:47 +01005174 } else {
5175 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid identityref value \"%s\".", ident_name);
5176 ly_vecode = LYVE_INCHAR;
Radek Krejci1899d6a2016-11-03 13:48:07 +01005177 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02005178 return NULL;
5179 }
5180
Michal Vaskof2d43962016-09-02 11:10:16 +02005181 /* go through all the bases in all the derived types */
5182 while (type->der) {
5183 for (i = 0; i < type->info.ident.count; ++i) {
5184 cur = type->info.ident.ref[i];
5185 if (!strcmp(cur->name, name) && (!mod_name
5186 || (!strncmp(cur->module->name, mod_name, mod_name_len) && !cur->module->name[mod_name_len]))) {
5187 goto match;
5188 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02005189
Radek Krejci85a54be2016-10-20 12:39:56 +02005190 if (cur->der) {
5191 /* there are also some derived identities */
5192 for (u = 0; u < cur->der->number; u++) {
5193 der = (struct lys_ident *)cur->der->set.g[u]; /* shortcut */
5194 if (!strcmp(der->name, name) &&
5195 (!mod_name || (!strncmp(der->module->name, mod_name, mod_name_len) && !der->module->name[mod_name_len]))) {
5196 /* we have match */
5197 cur = der;
5198 goto match;
5199 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005200 }
5201 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005202 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005203 type = &type->der->type;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005204 }
5205
Radek Krejci1899d6a2016-11-03 13:48:07 +01005206 if (node) {
5207 LOGVAL(LYE_INRESOLV, LY_VLOG_LYD, node, "identityref", ident_name);
Radek Krejci5dca5932016-11-04 14:30:47 +01005208 } else {
5209 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid identityref value \"%s\".", ident_name);
5210 ly_vecode = LYVE_INRESOLV;
Radek Krejci1899d6a2016-11-03 13:48:07 +01005211 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005212 return NULL;
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005213
5214match:
Michal Vaskof2d43962016-09-02 11:10:16 +02005215 for (i = 0; i < cur->iffeature_size; i++) {
5216 if (!resolve_iffeature(&cur->iffeature[i])) {
Radek Krejci1899d6a2016-11-03 13:48:07 +01005217 if (node) {
5218 LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, cur->name, node->schema->name);
5219 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, "Identity \"%s\" is disabled by its if-feature condition.",
5220 cur->name);
Radek Krejci5dca5932016-11-04 14:30:47 +01005221 } else {
5222 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Identity \"%s\" is disabled by its if-feature condition.",
5223 cur->name);
5224 ly_vecode = LYVE_INVAL;
Radek Krejci1899d6a2016-11-03 13:48:07 +01005225 }
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005226 return NULL;
5227 }
5228 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005229 return cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005230}
5231
Michal Vasko730dfdf2015-08-11 14:48:05 +02005232/**
Michal Vaskobb211122015-08-19 14:03:11 +02005233 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005234 *
Michal Vaskobb211122015-08-19 14:03:11 +02005235 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005236 * @param[in] unres Specific unres item.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005237 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005238 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005239 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005240static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005241resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005242{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005243 int rc;
Radek Krejci010e54b2016-03-15 09:40:34 +01005244 struct lys_node *par_grp;
Michal Vaskoe91afce2015-08-12 12:21:00 +02005245
Radek Krejci010e54b2016-03-15 09:40:34 +01005246 /* HACK: when a grouping has uses inside, all such uses have to be resolved before the grouping itself
5247 * is used in some uses. When we see such a uses, the grouping's nacm member (not used in grouping)
5248 * is used to store number of so far unresolved uses. The grouping cannot be used unless the nacm
5249 * value is decreased back to 0. To remember that the uses already increased grouping's nacm, the
5250 * LYS_USESGRP flag is used. */
Michal Vaskodcf98e62016-05-05 17:53:53 +02005251 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 +02005252
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005253 if (!uses->grp) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01005254 rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
5255 if (rc == -1) {
Michal Vasko92981a62016-10-14 10:25:16 +02005256 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005257 return -1;
5258 } else if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005259 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005260 return -1;
5261 } else if (!uses->grp) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005262 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005263 /* hack - in contrast to lys_node, lys_node_grp has bigger nacm field
5264 * (and smaller flags - it uses only a limited set of flags)
5265 */
5266 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci010e54b2016-03-15 09:40:34 +01005267 uses->flags |= LYS_USESGRP;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005268 }
Michal Vasko92981a62016-10-14 10:25:16 +02005269 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005270 return EXIT_FAILURE;
Michal Vasko12e30842015-08-04 11:54:00 +02005271 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005272 }
5273
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005274 if (uses->grp->nacm) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005275 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005276 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci010e54b2016-03-15 09:40:34 +01005277 uses->flags |= LYS_USESGRP;
Radek Krejcie00d2312016-08-12 15:27:49 +02005278 } else {
5279 /* instantiate grouping only when it is completely resolved */
5280 uses->grp = NULL;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005281 }
Michal Vasko92981a62016-10-14 10:25:16 +02005282 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005283 return EXIT_FAILURE;
5284 }
5285
Radek Krejci48464ed2016-03-17 15:44:09 +01005286 rc = resolve_uses(uses, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005287 if (!rc) {
5288 /* decrease unres count only if not first try */
Radek Krejci010e54b2016-03-15 09:40:34 +01005289 if (par_grp && (uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005290 if (!((struct lys_node_grp *)par_grp)->nacm) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005291 LOGINT;
5292 return -1;
5293 }
Radek Krejci4372b4e2016-04-14 17:42:16 +02005294 ((struct lys_node_grp *)par_grp)->nacm--;
Radek Krejci010e54b2016-03-15 09:40:34 +01005295 uses->flags &= ~LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005296 }
Radek Krejcicf509982015-12-15 09:22:44 +01005297
5298 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005299 if (lyp_check_status(uses->flags, uses->module, "of uses",
Radek Krejciadb57612016-02-16 13:34:34 +01005300 uses->grp->flags, uses->grp->module, uses->grp->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005301 (struct lys_node *)uses)) {
Radek Krejcicf509982015-12-15 09:22:44 +01005302 return -1;
5303 }
5304
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005305 return EXIT_SUCCESS;
5306 }
5307
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005308 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005309}
5310
Michal Vasko730dfdf2015-08-11 14:48:05 +02005311/**
Michal Vasko9957e592015-08-17 15:04:09 +02005312 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005313 *
Michal Vaskobb211122015-08-19 14:03:11 +02005314 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005315 * @param[in] keys_str Keys node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005316 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005317 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005318 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005319static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005320resolve_list_keys(struct lys_node_list *list, const char *keys_str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005321{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005322 int i, len, rc;
Michal Vasko4f0dad02016-02-15 14:08:23 +01005323 const char *value;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005324
5325 for (i = 0; i < list->keys_size; ++i) {
Radek Krejci5c08a992016-11-02 13:30:04 +01005326 if (!list->child) {
5327 /* no child, possible forward reference */
5328 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
5329 return EXIT_FAILURE;
5330 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005331 /* get the key name */
5332 if ((value = strpbrk(keys_str, " \t\n"))) {
5333 len = value - keys_str;
5334 while (isspace(value[0])) {
5335 value++;
5336 }
5337 } else {
5338 len = strlen(keys_str);
5339 }
5340
Radek Krejcic4283442016-04-22 09:19:27 +02005341 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 +02005342 if (rc) {
Michal Vasko7a55bea2016-05-02 14:51:20 +02005343 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
5344 return EXIT_FAILURE;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005345 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005346
Radek Krejci48464ed2016-03-17 15:44:09 +01005347 if (check_key(list, i, keys_str, len)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005348 /* check_key logs */
5349 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005350 }
5351
Radek Krejcicf509982015-12-15 09:22:44 +01005352 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005353 if (lyp_check_status(list->flags, list->module, list->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005354 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
5355 (struct lys_node *)list->keys[i])) {
Radek Krejcicf509982015-12-15 09:22:44 +01005356 return -1;
5357 }
5358
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005359 /* prepare for next iteration */
5360 while (value && isspace(value[0])) {
5361 value++;
5362 }
5363 keys_str = value;
5364 }
5365
Michal Vaskof02e3742015-08-05 16:27:02 +02005366 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005367}
5368
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005369/**
Michal Vaskobf19d252015-10-08 15:39:17 +02005370 * @brief Resolve (check) all must conditions of \p node.
5371 * Logs directly.
5372 *
5373 * @param[in] node Data node with optional must statements.
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005374 * @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 +02005375 *
5376 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
5377 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005378static int
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005379resolve_must(struct lyd_node *node, int inout_parent)
Michal Vaskof02e3742015-08-05 16:27:02 +02005380{
Michal Vaskobf19d252015-10-08 15:39:17 +02005381 uint8_t i, must_size;
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005382 struct lys_node *schema;
Michal Vaskobf19d252015-10-08 15:39:17 +02005383 struct lys_restr *must;
5384 struct lyxp_set set;
5385
5386 assert(node);
5387 memset(&set, 0, sizeof set);
5388
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005389 if (inout_parent) {
5390 for (schema = lys_parent(node->schema);
5391 schema && (schema->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES));
5392 schema = lys_parent(schema));
5393 if (!schema || !(schema->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5394 LOGINT;
5395 return -1;
5396 }
5397 must_size = ((struct lys_node_inout *)schema)->must_size;
5398 must = ((struct lys_node_inout *)schema)->must;
5399
5400 /* context node is the RPC/action */
5401 node = node->parent;
5402 if (!(node->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
5403 LOGINT;
5404 return -1;
5405 }
5406 } else {
5407 switch (node->schema->nodetype) {
5408 case LYS_CONTAINER:
5409 must_size = ((struct lys_node_container *)node->schema)->must_size;
5410 must = ((struct lys_node_container *)node->schema)->must;
5411 break;
5412 case LYS_LEAF:
5413 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
5414 must = ((struct lys_node_leaf *)node->schema)->must;
5415 break;
5416 case LYS_LEAFLIST:
5417 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
5418 must = ((struct lys_node_leaflist *)node->schema)->must;
5419 break;
5420 case LYS_LIST:
5421 must_size = ((struct lys_node_list *)node->schema)->must_size;
5422 must = ((struct lys_node_list *)node->schema)->must;
5423 break;
5424 case LYS_ANYXML:
5425 case LYS_ANYDATA:
5426 must_size = ((struct lys_node_anydata *)node->schema)->must_size;
5427 must = ((struct lys_node_anydata *)node->schema)->must;
5428 break;
5429 case LYS_NOTIF:
5430 must_size = ((struct lys_node_notif *)node->schema)->must_size;
5431 must = ((struct lys_node_notif *)node->schema)->must;
5432 break;
5433 default:
5434 must_size = 0;
5435 break;
5436 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005437 }
5438
5439 for (i = 0; i < must_size; ++i) {
Michal Vaskoa59495d2016-08-22 09:18:58 +02005440 if (lyxp_eval(must[i].expr, node, LYXP_NODE_ELEM, &set, LYXP_MUST)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02005441 return -1;
5442 }
5443
Michal Vasko944a5642016-03-21 11:48:58 +01005444 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, LYXP_MUST);
Michal Vaskobf19d252015-10-08 15:39:17 +02005445
Michal Vasko8146d4c2016-05-09 15:50:29 +02005446 if (!set.val.bool) {
Michal Vasko6ac68282016-04-11 10:56:47 +02005447 LOGVAL(LYE_NOMUST, LY_VLOG_LYD, node, must[i].expr);
5448 if (must[i].emsg) {
5449 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, must[i].emsg);
5450 }
5451 if (must[i].eapptag) {
5452 strncpy(((struct ly_err *)&ly_errno)->apptag, must[i].eapptag, LY_APPTAG_LEN - 1);
5453 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005454 return 1;
5455 }
5456 }
5457
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005458 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02005459}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005460
Michal Vaskobf19d252015-10-08 15:39:17 +02005461/**
Michal Vasko508a50d2016-09-07 14:50:33 +02005462 * @brief Resolve (find) when condition schema context node. Does not log.
5463 *
5464 * @param[in] schema Schema node with the when condition.
5465 * @param[out] ctx_snode When schema context node.
5466 * @param[out] ctx_snode_type Schema context node type.
5467 */
5468void
5469resolve_when_ctx_snode(const struct lys_node *schema, struct lys_node **ctx_snode, enum lyxp_node_type *ctx_snode_type)
5470{
5471 const struct lys_node *sparent;
5472
5473 /* find a not schema-only node */
5474 *ctx_snode_type = LYXP_NODE_ELEM;
5475 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
5476 if (schema->nodetype == LYS_AUGMENT) {
5477 sparent = ((struct lys_node_augment *)schema)->target;
5478 } else {
5479 sparent = schema->parent;
5480 }
5481 if (!sparent) {
5482 /* context node is the document root (fake root in our case) */
5483 if (schema->flags & LYS_CONFIG_W) {
5484 *ctx_snode_type = LYXP_NODE_ROOT_CONFIG;
5485 } else {
Michal Vaskob94a5e42016-09-08 14:01:56 +02005486 *ctx_snode_type = LYXP_NODE_ROOT;
Michal Vasko508a50d2016-09-07 14:50:33 +02005487 }
Michal Vasko2d2aec12016-09-08 11:42:50 +02005488 /* we need the first top-level sibling, but no uses or groupings */
Michal Vaskob94a5e42016-09-08 14:01:56 +02005489 schema = lys_getnext(NULL, NULL, lys_node_module(schema), 0);
Michal Vasko508a50d2016-09-07 14:50:33 +02005490 break;
5491 }
5492 schema = sparent;
5493 }
5494
5495 *ctx_snode = (struct lys_node *)schema;
5496}
5497
5498/**
Michal Vaskocf024702015-10-08 15:01:42 +02005499 * @brief Resolve (find) when condition context node. Does not log.
5500 *
5501 * @param[in] node Data node, whose conditional definition is being decided.
Michal Vasko508a50d2016-09-07 14:50:33 +02005502 * @param[in] schema Schema node with the when condition.
Michal Vaskoa59495d2016-08-22 09:18:58 +02005503 * @param[out] ctx_node Context node.
5504 * @param[out] ctx_node_type Context node type.
Michal Vaskocf024702015-10-08 15:01:42 +02005505 *
Michal Vaskoa59495d2016-08-22 09:18:58 +02005506 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vaskocf024702015-10-08 15:01:42 +02005507 */
Michal Vaskoa59495d2016-08-22 09:18:58 +02005508static int
5509resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema, struct lyd_node **ctx_node,
5510 enum lyxp_node_type *ctx_node_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005511{
Michal Vaskocf024702015-10-08 15:01:42 +02005512 struct lyd_node *parent;
5513 struct lys_node *sparent;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005514 enum lyxp_node_type node_type;
Michal Vaskocf024702015-10-08 15:01:42 +02005515 uint16_t i, data_depth, schema_depth;
5516
Michal Vasko508a50d2016-09-07 14:50:33 +02005517 resolve_when_ctx_snode(schema, &schema, &node_type);
Michal Vaskocf024702015-10-08 15:01:42 +02005518
Michal Vaskofe989752016-09-08 08:47:26 +02005519 if (node_type == LYXP_NODE_ELEM) {
5520 /* standard element context node */
5521 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
5522 for (sparent = schema, schema_depth = 0;
5523 sparent;
5524 sparent = (sparent->nodetype == LYS_AUGMENT ? ((struct lys_node_augment *)sparent)->target : sparent->parent)) {
5525 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_NOTIF | LYS_RPC)) {
5526 ++schema_depth;
5527 }
Michal Vaskocf024702015-10-08 15:01:42 +02005528 }
Michal Vaskofe989752016-09-08 08:47:26 +02005529 if (data_depth < schema_depth) {
5530 return -1;
5531 }
Michal Vaskocf024702015-10-08 15:01:42 +02005532
Michal Vasko956e8542016-08-26 09:43:35 +02005533 /* find the corresponding data node */
5534 for (i = 0; i < data_depth - schema_depth; ++i) {
5535 node = node->parent;
5536 }
Michal Vaskoa59495d2016-08-22 09:18:58 +02005537 if (node->schema != schema) {
5538 return -1;
5539 }
Michal Vaskofe989752016-09-08 08:47:26 +02005540 } else {
5541 /* root context node */
5542 while (node->parent) {
5543 node = node->parent;
5544 }
5545 while (node->prev->next) {
5546 node = node->prev;
5547 }
Michal Vaskocf024702015-10-08 15:01:42 +02005548 }
5549
Michal Vaskoa59495d2016-08-22 09:18:58 +02005550 *ctx_node = node;
5551 *ctx_node_type = node_type;
5552 return EXIT_SUCCESS;
Michal Vaskocf024702015-10-08 15:01:42 +02005553}
5554
Michal Vasko76c3bd32016-08-24 16:02:52 +02005555/**
5556 * @brief Temporarily unlink nodes as per YANG 1.1 RFC section 7.21.5 for when XPath evaluation.
5557 * The context nodes is adjusted if needed.
5558 *
5559 * @param[in] snode Schema node, whose children instances need to be unlinked.
5560 * @param[in,out] node Data siblings where to look for the children of \p snode. If it is unlinked,
5561 * it is moved to point to another sibling still in the original tree.
5562 * @param[in,out] ctx_node When context node, adjusted if needed.
5563 * @param[in] ctx_node_type Context node type, just for information to detect invalid situations.
5564 * @param[out] unlinked_nodes Unlinked siblings. Can be safely appended to \p node afterwards.
5565 * Ordering may change, but there will be no semantic change.
5566 *
5567 * @return EXIT_SUCCESS on success, -1 on error.
5568 */
5569static int
5570resolve_when_unlink_nodes(struct lys_node *snode, struct lyd_node **node, struct lyd_node **ctx_node,
5571 enum lyxp_node_type ctx_node_type, struct lyd_node **unlinked_nodes)
5572{
5573 struct lyd_node *next, *elem;
5574
5575 switch (snode->nodetype) {
5576 case LYS_AUGMENT:
5577 case LYS_USES:
5578 case LYS_CHOICE:
5579 case LYS_CASE:
5580 LY_TREE_FOR(snode->child, snode) {
5581 if (resolve_when_unlink_nodes(snode, node, ctx_node, ctx_node_type, unlinked_nodes)) {
5582 return -1;
5583 }
5584 }
5585 break;
5586 case LYS_CONTAINER:
5587 case LYS_LIST:
5588 case LYS_LEAF:
5589 case LYS_LEAFLIST:
5590 case LYS_ANYXML:
5591 case LYS_ANYDATA:
5592 LY_TREE_FOR_SAFE(lyd_first_sibling(*node), next, elem) {
5593 if (elem->schema == snode) {
5594
5595 if (elem == *ctx_node) {
5596 /* We are going to unlink our context node! This normally cannot happen,
5597 * but we use normal top-level data nodes for faking a document root node,
5598 * so if this is the context node, we just use the next top-level node.
5599 * Additionally, it can even happen that there are no top-level data nodes left,
5600 * all were unlinked, so in this case we pass NULL as the context node/data tree,
5601 * lyxp_eval() can handle this special situation.
5602 */
5603 if (ctx_node_type == LYXP_NODE_ELEM) {
5604 LOGINT;
5605 return -1;
5606 }
5607
5608 if (elem->prev == elem) {
5609 /* unlinking last top-level element, use an empty data tree */
5610 *ctx_node = NULL;
5611 } else {
5612 /* in this case just use the previous/last top-level data node */
5613 *ctx_node = elem->prev;
5614 }
5615 } else if (elem == *node) {
5616 /* We are going to unlink the currently processed node. This does not matter that
5617 * much, but we would lose access to the original data tree, so just move our
5618 * pointer somewhere still inside it.
5619 */
5620 if ((*node)->prev != *node) {
5621 *node = (*node)->prev;
5622 } else {
5623 /* the processed node with sibings were all unlinked, oh well */
5624 *node = NULL;
5625 }
5626 }
5627
5628 /* temporarily unlink the node */
5629 lyd_unlink(elem);
5630 if (*unlinked_nodes) {
5631 if (lyd_insert_after(*unlinked_nodes, elem)) {
5632 LOGINT;
5633 return -1;
5634 }
5635 } else {
5636 *unlinked_nodes = elem;
5637 }
5638
5639 if (snode->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_ANYDATA)) {
5640 /* there can be only one instance */
5641 break;
5642 }
5643 }
5644 }
5645 break;
5646 default:
5647 LOGINT;
5648 return -1;
5649 }
5650
5651 return EXIT_SUCCESS;
5652}
5653
5654/**
5655 * @brief Relink the unlinked nodes back.
5656 *
5657 * @param[in] node Data node to link the nodes back to. It can actually be the adjusted context node,
5658 * we simply need a sibling from the original data tree.
5659 * @param[in] unlinked_nodes Unlinked nodes to relink to \p node.
5660 * @param[in] ctx_node_type Context node type to distinguish between \p node being the parent
5661 * or the sibling of \p unlinked_nodes.
5662 *
5663 * @return EXIT_SUCCESS on success, -1 on error.
5664 */
5665static int
5666resolve_when_relink_nodes(struct lyd_node *node, struct lyd_node *unlinked_nodes, enum lyxp_node_type ctx_node_type)
5667{
5668 struct lyd_node *elem;
5669
5670 LY_TREE_FOR_SAFE(unlinked_nodes, unlinked_nodes, elem) {
5671 if (ctx_node_type == LYXP_NODE_ELEM) {
5672 if (lyd_insert(node, elem)) {
5673 return -1;
5674 }
5675 } else {
5676 if (lyd_insert_after(node, elem)) {
5677 return -1;
5678 }
5679 }
5680 }
5681
5682 return EXIT_SUCCESS;
5683}
5684
Radek Krejci03b71f72016-03-16 11:10:09 +01005685int
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005686resolve_applies_must(const struct lyd_node *node)
Radek Krejci01696bf2016-03-18 13:19:36 +01005687{
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005688 int ret = 0;
5689 uint8_t must_size;
5690 struct lys_node *schema, *iter;
Radek Krejci46165822016-08-26 14:06:27 +02005691
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005692 assert(node);
5693
5694 schema = node->schema;
5695
5696 /* their own must */
Radek Krejci46165822016-08-26 14:06:27 +02005697 switch (schema->nodetype) {
Radek Krejci01696bf2016-03-18 13:19:36 +01005698 case LYS_CONTAINER:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005699 must_size = ((struct lys_node_container *)schema)->must_size;
5700 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005701 case LYS_LEAF:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005702 must_size = ((struct lys_node_leaf *)schema)->must_size;
5703 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005704 case LYS_LEAFLIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005705 must_size = ((struct lys_node_leaflist *)schema)->must_size;
5706 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005707 case LYS_LIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005708 must_size = ((struct lys_node_list *)schema)->must_size;
5709 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005710 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02005711 case LYS_ANYDATA:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005712 must_size = ((struct lys_node_anydata *)schema)->must_size;
5713 break;
5714 case LYS_NOTIF:
5715 must_size = ((struct lys_node_notif *)schema)->must_size;
5716 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005717 default:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005718 must_size = 0;
5719 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005720 }
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005721
5722 if (must_size) {
5723 ++ret;
5724 }
5725
5726 /* schema may be a direct data child of input/output with must (but it must be first, it needs to be evaluated only once) */
5727 if (!node->prev->next) {
5728 for (iter = lys_parent(schema); iter && (iter->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES)); iter = lys_parent(iter));
5729 if (iter && (iter->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5730 ret += 0x2;
5731 }
5732 }
5733
5734 return ret;
Radek Krejci01696bf2016-03-18 13:19:36 +01005735}
5736
5737int
Radek Krejci46165822016-08-26 14:06:27 +02005738resolve_applies_when(const struct lys_node *schema, int mode, const struct lys_node *stop)
Radek Krejci03b71f72016-03-16 11:10:09 +01005739{
Radek Krejci46165822016-08-26 14:06:27 +02005740 const struct lys_node *parent;
Radek Krejci03b71f72016-03-16 11:10:09 +01005741
Radek Krejci46165822016-08-26 14:06:27 +02005742 assert(schema);
Radek Krejci03b71f72016-03-16 11:10:09 +01005743
Radek Krejci46165822016-08-26 14:06:27 +02005744 if (!(schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)schema)->when)) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005745 return 1;
5746 }
5747
Radek Krejci46165822016-08-26 14:06:27 +02005748 parent = schema;
Radek Krejci03b71f72016-03-16 11:10:09 +01005749 goto check_augment;
5750
Radek Krejci46165822016-08-26 14:06:27 +02005751 while (parent) {
5752 /* stop conditions */
5753 if (!mode) {
5754 /* stop on node that can be instantiated in data tree */
5755 if (!(parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
5756 break;
5757 }
5758 } else {
5759 /* stop on the specified node */
5760 if (parent == stop) {
5761 break;
5762 }
5763 }
5764
5765 if (((const struct lys_node_uses *)parent)->when) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005766 return 1;
5767 }
5768check_augment:
5769
5770 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) &&
Radek Krejci46165822016-08-26 14:06:27 +02005771 (((const struct lys_node_augment *)parent->parent)->when))) {
Michal Vaskoe3655562016-08-24 15:56:17 +02005772 return 1;
Radek Krejci03b71f72016-03-16 11:10:09 +01005773 }
5774 parent = lys_parent(parent);
5775 }
5776
5777 return 0;
5778}
5779
Michal Vaskocf024702015-10-08 15:01:42 +02005780/**
5781 * @brief Resolve (check) all when conditions relevant for \p node.
5782 * Logs directly.
5783 *
5784 * @param[in] node Data node, whose conditional reference, if such, is being decided.
Michal Vaskocf024702015-10-08 15:01:42 +02005785 *
Radek Krejci03b71f72016-03-16 11:10:09 +01005786 * @return
5787 * -1 - error, ly_errno is set
5788 * 0 - true "when" statement
Radek Krejci46165822016-08-26 14:06:27 +02005789 * 0, ly_vecode = LYVE_NOWHEN - false "when" statement
Radek Krejci03b71f72016-03-16 11:10:09 +01005790 * 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 +02005791 */
Radek Krejci46165822016-08-26 14:06:27 +02005792int
5793resolve_when(struct lyd_node *node, int *result)
Michal Vaskocf024702015-10-08 15:01:42 +02005794{
Michal Vasko76c3bd32016-08-24 16:02:52 +02005795 struct lyd_node *ctx_node = NULL, *unlinked_nodes, *tmp_node;
Michal Vasko90fc2a32016-08-24 15:58:58 +02005796 struct lys_node *sparent;
Michal Vaskocf024702015-10-08 15:01:42 +02005797 struct lyxp_set set;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005798 enum lyxp_node_type ctx_node_type;
Radek Krejci51093642016-03-29 10:14:59 +02005799 int rc = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02005800
5801 assert(node);
5802 memset(&set, 0, sizeof set);
5803
5804 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)node->schema)->when)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005805 /* make the node dummy for the evaluation */
5806 node->validity |= LYD_VAL_INUSE;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005807 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 +02005808 node->validity &= ~LYD_VAL_INUSE;
Radek Krejci03b71f72016-03-16 11:10:09 +01005809 if (rc) {
5810 if (rc == 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005811 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005812 }
Radek Krejci51093642016-03-29 10:14:59 +02005813 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005814 }
5815
Radek Krejci03b71f72016-03-16 11:10:09 +01005816 /* set boolean result of the condition */
Michal Vasko944a5642016-03-21 11:48:58 +01005817 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02005818 if (!set.val.bool) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005819 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci0b7704f2016-03-18 12:16:14 +01005820 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02005821 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005822 }
Radek Krejci51093642016-03-29 10:14:59 +02005823
5824 /* free xpath set content */
5825 lyxp_set_cast(&set, LYXP_SET_EMPTY, node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005826 }
5827
Michal Vasko90fc2a32016-08-24 15:58:58 +02005828 sparent = node->schema;
Michal Vaskocf024702015-10-08 15:01:42 +02005829 goto check_augment;
5830
5831 /* check when in every schema node that affects node */
Michal Vasko90fc2a32016-08-24 15:58:58 +02005832 while (sparent && (sparent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
5833 if (((struct lys_node_uses *)sparent)->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, &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 /* we do not want our node pointer to change */
5844 tmp_node = node;
5845 rc = resolve_when_unlink_nodes(sparent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
5846 if (rc) {
5847 goto cleanup;
5848 }
5849
5850 rc = lyxp_eval(((struct lys_node_uses *)sparent)->when->cond, ctx_node, ctx_node_type, &set, LYXP_WHEN);
5851
5852 if (unlinked_nodes && ctx_node) {
5853 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
5854 rc = -1;
5855 goto cleanup;
5856 }
5857 }
5858
Radek Krejci03b71f72016-03-16 11:10:09 +01005859 if (rc) {
5860 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005861 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005862 }
Radek Krejci51093642016-03-29 10:14:59 +02005863 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005864 }
5865
Michal Vasko944a5642016-03-21 11:48:58 +01005866 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02005867 if (!set.val.bool) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005868 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Radek Krejci0b7704f2016-03-18 12:16:14 +01005869 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02005870 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005871 }
Radek Krejci51093642016-03-29 10:14:59 +02005872
5873 /* free xpath set content */
5874 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005875 }
5876
5877check_augment:
Michal Vasko90fc2a32016-08-24 15:58:58 +02005878 if ((sparent->parent && (sparent->parent->nodetype == LYS_AUGMENT) && (((struct lys_node_augment *)sparent->parent)->when))) {
Michal Vaskocf024702015-10-08 15:01:42 +02005879 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005880 rc = resolve_when_ctx_node(node, sparent->parent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02005881 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02005882 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02005883 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005884 }
5885 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02005886
5887 unlinked_nodes = NULL;
5888 tmp_node = node;
5889 rc = resolve_when_unlink_nodes(sparent->parent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
5890 if (rc) {
5891 goto cleanup;
5892 }
5893
5894 rc = lyxp_eval(((struct lys_node_augment *)sparent->parent)->when->cond, ctx_node, ctx_node_type, &set, LYXP_WHEN);
5895
5896 /* reconnect nodes, if ctx_node is NULL then all the nodes were unlinked, but linked together,
5897 * so the tree did not actually change and there is nothing for us to do
5898 */
5899 if (unlinked_nodes && ctx_node) {
5900 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
5901 rc = -1;
5902 goto cleanup;
5903 }
5904 }
5905
Radek Krejci03b71f72016-03-16 11:10:09 +01005906 if (rc) {
5907 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005908 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005909 }
Radek Krejci51093642016-03-29 10:14:59 +02005910 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005911 }
5912
Michal Vasko944a5642016-03-21 11:48:58 +01005913 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, LYXP_WHEN);
Michal Vaskocf024702015-10-08 15:01:42 +02005914
Michal Vasko8146d4c2016-05-09 15:50:29 +02005915 if (!set.val.bool) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005916 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Radek Krejci0b7704f2016-03-18 12:16:14 +01005917 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02005918 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005919 }
Radek Krejci51093642016-03-29 10:14:59 +02005920
5921 /* free xpath set content */
5922 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005923 }
5924
Michal Vasko90fc2a32016-08-24 15:58:58 +02005925 sparent = lys_parent(sparent);
Michal Vaskocf024702015-10-08 15:01:42 +02005926 }
5927
Radek Krejci0b7704f2016-03-18 12:16:14 +01005928 node->when_status |= LYD_WHEN_TRUE;
Radek Krejci03b71f72016-03-16 11:10:09 +01005929
Radek Krejci51093642016-03-29 10:14:59 +02005930cleanup:
Radek Krejci51093642016-03-29 10:14:59 +02005931 /* free xpath set content */
5932 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node ? ctx_node : node, 0);
5933
Radek Krejci46165822016-08-26 14:06:27 +02005934 if (result) {
5935 if (node->when_status & LYD_WHEN_TRUE) {
5936 *result = 1;
5937 } else {
5938 *result = 0;
5939 }
5940 }
5941
Radek Krejci51093642016-03-29 10:14:59 +02005942 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005943}
5944
Radek Krejcicbb473e2016-09-16 14:48:32 +02005945static int
5946check_leafref_features(struct lys_type *type)
5947{
5948 struct lys_node *iter;
5949 struct ly_set *src_parents, *trg_parents, *features;
5950 unsigned int i, j, size, x;
5951 int ret = EXIT_SUCCESS;
5952
5953 assert(type->parent);
5954
5955 src_parents = ly_set_new();
5956 trg_parents = ly_set_new();
5957 features = ly_set_new();
5958
5959 /* get parents chain of source (leafref) */
5960 for (iter = (struct lys_node *)type->parent; iter; iter = iter->parent) {
5961 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
5962 continue;
5963 }
5964 ly_set_add(src_parents, iter, LY_SET_OPT_USEASLIST);
5965 }
5966 /* get parents chain of target */
5967 for (iter = (struct lys_node *)type->info.lref.target; iter; iter = iter->parent) {
5968 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
5969 continue;
5970 }
5971 ly_set_add(trg_parents, iter, LY_SET_OPT_USEASLIST);
5972 }
5973
5974 /* compare the features used in if-feature statements in the rest of both
5975 * chains of parents. The set of features used for target must be a subset
5976 * of features used for the leafref. This is not a perfect, we should compare
5977 * the truth tables but it could require too much resources, so we simplify that */
5978 for (i = 0; i < src_parents->number; i++) {
5979 iter = src_parents->set.s[i]; /* shortcut */
5980 if (!iter->iffeature_size) {
5981 continue;
5982 }
5983 for (j = 0; j < iter->iffeature_size; j++) {
5984 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
5985 for (; size; size--) {
5986 if (!iter->iffeature[j].features[size - 1]) {
5987 /* not yet resolved feature, postpone this check */
5988 ret = EXIT_FAILURE;
5989 goto cleanup;
5990 }
5991 ly_set_add(features, iter->iffeature[j].features[size - 1], 0);
5992 }
5993 }
5994 }
5995 x = features->number;
5996 for (i = 0; i < trg_parents->number; i++) {
5997 iter = trg_parents->set.s[i]; /* shortcut */
5998 if (!iter->iffeature_size) {
5999 continue;
6000 }
6001 for (j = 0; j < iter->iffeature_size; j++) {
6002 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
6003 for (; size; size--) {
6004 if (!iter->iffeature[j].features[size - 1]) {
6005 /* not yet resolved feature, postpone this check */
6006 ret = EXIT_FAILURE;
6007 goto cleanup;
6008 }
6009 if ((unsigned int)ly_set_add(features, iter->iffeature[j].features[size - 1], 0) >= x) {
6010 /* the feature is not present in features set of target's parents chain */
6011 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, type->parent, "leafref", type->info.lref.path);
6012 LOGVAL(LYE_SPEC, LY_VLOG_LYS, type->parent,
6013 "Leafref is not conditional based on \"%s\" feature as its target.",
6014 iter->iffeature[j].features[size - 1]->name);
6015 ret = -1;
6016 goto cleanup;
6017 }
6018 }
6019 }
6020 }
6021
6022cleanup:
6023 ly_set_free(features);
6024 ly_set_free(src_parents);
6025 ly_set_free(trg_parents);
6026
6027 return ret;
6028}
6029
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006030/**
Michal Vaskobb211122015-08-19 14:03:11 +02006031 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006032 *
6033 * @param[in] mod Main module.
6034 * @param[in] item Item to resolve. Type determined by \p type.
6035 * @param[in] type Type of the unresolved item.
6036 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02006037 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006038 *
6039 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
6040 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006041static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006042resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Radek Krejci48464ed2016-03-17 15:44:09 +01006043 struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006044{
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006045 /* has_str - whether the str_snode is a string in a dictionary that needs to be freed */
Radek Krejcic79c6b12016-07-26 15:11:49 +02006046 int rc = -1, has_str = 0, tpdf_flag = 0, i, k;
6047 unsigned int j;
Radek Krejcic13db382016-08-16 10:52:42 +02006048 struct lys_node *node, *par_grp;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006049 const char *expr;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006050
Radek Krejcic79c6b12016-07-26 15:11:49 +02006051 struct ly_set *refs, *procs;
6052 struct lys_feature *ref, *feat;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006053 struct lys_ident *ident;
6054 struct lys_type *stype;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006055 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01006056 struct lyxml_elem *yin;
Pavol Vicana0e4e672016-02-24 12:20:04 +01006057 struct yang_type *yang;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006058 struct unres_list_uniq *unique_info;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006059 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006060
6061 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006062 case UNRES_IDENT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006063 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006064 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006065 ident = item;
6066
Radek Krejci018f1f52016-08-03 16:01:20 +02006067 rc = resolve_base_ident(mod, ident, expr, "identity", NULL, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006068 break;
6069 case UNRES_TYPE_IDENTREF:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006070 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006071 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006072 stype = item;
6073
Radek Krejci018f1f52016-08-03 16:01:20 +02006074 rc = resolve_base_ident(mod, NULL, expr, "type", stype, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006075 break;
6076 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02006077 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006078 stype = item;
6079
Radek Krejci2f12f852016-01-08 12:59:57 +01006080 /* HACK - when there is no parent, we are in top level typedef and in that
6081 * case, the path has to contain absolute path, so we let the resolve_path_arg_schema()
6082 * know it via tpdf_flag */
6083 if (!node) {
Radek Krejci4f78b532016-02-17 13:43:00 +01006084 tpdf_flag = 1;
Radek Krejci2f12f852016-01-08 12:59:57 +01006085 node = (struct lys_node *)stype->parent;
6086 }
6087
Radek Krejci27fe55e2016-09-13 17:13:35 +02006088 if (!lys_node_module(node)->implemented) {
6089 /* not implemented module, don't bother with resolving the leafref
Radek Krejci990af1f2016-11-09 13:53:36 +01006090 * if the module is set to be implemented, the path will be resolved then */
Radek Krejci27fe55e2016-09-13 17:13:35 +02006091 rc = 0;
6092 break;
6093 }
Radek Krejci48464ed2016-03-17 15:44:09 +01006094 rc = resolve_path_arg_schema(stype->info.lref.path, node, tpdf_flag,
Michal Vasko1e62a092015-12-01 12:27:20 +01006095 (const struct lys_node **)&stype->info.lref.target);
Michal Vasko01c6fd22016-05-20 11:43:05 +02006096 if (!tpdf_flag && !rc) {
6097 assert(stype->info.lref.target);
Radek Krejcicbb473e2016-09-16 14:48:32 +02006098 /* check if leafref and its target are under a common if-features */
6099 rc = check_leafref_features(stype);
6100 if (rc) {
6101 break;
6102 }
6103
Radek Krejci46c4cd72016-01-21 15:13:52 +01006104 /* store the backlink from leafref target */
Michal Vasko01c6fd22016-05-20 11:43:05 +02006105 if (lys_leaf_add_leafref_target(stype->info.lref.target, (struct lys_node *)stype->parent)) {
6106 rc = -1;
Radek Krejci46c4cd72016-01-21 15:13:52 +01006107 }
Radek Krejci46c4cd72016-01-21 15:13:52 +01006108 }
6109
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006110 break;
Radek Krejci3a5501d2016-07-18 22:03:34 +02006111 case UNRES_TYPE_DER_TPDF:
6112 tpdf_flag = 1;
6113 /* no break */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006114 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01006115 /* parent */
6116 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006117 stype = item;
6118
Michal Vasko88c29542015-11-27 14:57:53 +01006119 /* HACK type->der is temporarily unparsed type statement */
6120 yin = (struct lyxml_elem *)stype->der;
6121 stype->der = NULL;
6122
Pavol Vicana0e4e672016-02-24 12:20:04 +01006123 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6124 yang = (struct yang_type *)yin;
Radek Krejci3a5501d2016-07-18 22:03:34 +02006125 rc = yang_check_type(mod, node, yang, tpdf_flag, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006126
6127 if (rc) {
Pavol Vican8bd72e42016-08-29 09:53:05 +02006128 /* may try again later */
6129 stype->der = (struct lys_tpdf *)yang;
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006130 } else {
6131 /* we need to always be able to free this, it's safe only in this case */
Pavol Vican5f0316a2016-04-05 21:21:11 +02006132 lydict_remove(mod->ctx, yang->name);
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006133 free(yang);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006134 }
6135
Michal Vasko88c29542015-11-27 14:57:53 +01006136 } else {
Radek Krejci3a5501d2016-07-18 22:03:34 +02006137 rc = fill_yin_type(mod, node, yin, stype, tpdf_flag, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006138 if (!rc) {
6139 /* we need to always be able to free this, it's safe only in this case */
6140 lyxml_free(mod->ctx, yin);
6141 } else {
6142 /* may try again later, put all back how it was */
6143 stype->der = (struct lys_tpdf *)yin;
6144 }
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006145 }
Radek Krejcic13db382016-08-16 10:52:42 +02006146 if (rc == EXIT_SUCCESS) {
Radek Krejci2c2fce82016-08-01 13:52:26 +02006147 /* it does not make sense to have leaf-list of empty type */
6148 if (!tpdf_flag && node->nodetype == LYS_LEAFLIST && stype->base == LY_TYPE_EMPTY) {
6149 LOGWRN("The leaf-list \"%s\" is of \"empty\" type, which does not make sense.", node->name);
6150 }
Radek Krejci9b6aad22016-09-20 15:55:51 +02006151 } else if (rc == EXIT_FAILURE && stype->base != LY_TYPE_ERR) {
Radek Krejcic13db382016-08-16 10:52:42 +02006152 /* forward reference - in case the type is in grouping, we have to make the grouping unusable
6153 * by uses statement until the type is resolved. We do that the same way as uses statements inside
6154 * grouping - the grouping's nacm member (not used un grouping) is used to increase the number of
6155 * 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 +02006156 * 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 +02006157 * of the type's base member. */
6158 for (par_grp = node; par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
6159 if (par_grp) {
6160 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci9b6aad22016-09-20 15:55:51 +02006161 stype->base = LY_TYPE_ERR;
Radek Krejcic13db382016-08-16 10:52:42 +02006162 }
Radek Krejci2c2fce82016-08-01 13:52:26 +02006163 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006164 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006165 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006166 iff_data = str_snode;
6167 rc = resolve_feature(iff_data->fname, strlen(iff_data->fname), iff_data->node, item);
Radek Krejci9ff0a922016-07-14 13:08:05 +02006168 if (!rc) {
6169 /* success */
Radek Krejci9de2c042016-10-19 16:53:06 +02006170 if (iff_data->infeature) {
6171 /* store backlink into the target feature to allow reverse changes in case of changing feature status */
6172 feat = *((struct lys_feature **)item);
6173 if (!feat->depfeatures) {
6174 feat->depfeatures = ly_set_new();
6175 }
Radek Krejci85a54be2016-10-20 12:39:56 +02006176 ly_set_add(feat->depfeatures, iff_data->node, LY_SET_OPT_USEASLIST);
Radek Krejci9de2c042016-10-19 16:53:06 +02006177 }
6178 /* cleanup temporary data */
Radek Krejcicbb473e2016-09-16 14:48:32 +02006179 lydict_remove(mod->ctx, iff_data->fname);
6180 free(iff_data);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006181 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006182 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006183 case UNRES_FEATURE:
6184 feat = (struct lys_feature *)item;
6185
6186 if (feat->iffeature_size) {
6187 refs = ly_set_new();
6188 procs = ly_set_new();
6189 ly_set_add(procs, feat, 0);
6190
6191 while (procs->number) {
6192 ref = procs->set.g[procs->number - 1];
6193 ly_set_rm_index(procs, procs->number - 1);
6194
6195 for (i = 0; i < ref->iffeature_size; i++) {
6196 resolve_iffeature_getsizes(&ref->iffeature[i], NULL, &j);
6197 for (; j > 0 ; j--) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006198 if (ref->iffeature[i].features[j - 1]) {
Radek Krejcic79c6b12016-07-26 15:11:49 +02006199 if (ref->iffeature[i].features[j - 1] == feat) {
6200 LOGVAL(LYE_CIRC_FEATURES, LY_VLOG_NONE, NULL, feat->name);
6201 goto featurecheckdone;
6202 }
6203
6204 if (ref->iffeature[i].features[j - 1]->iffeature_size) {
6205 k = refs->number;
6206 if (ly_set_add(refs, ref->iffeature[i].features[j - 1], 0) == k) {
6207 /* not yet seen feature, add it for processing */
6208 ly_set_add(procs, ref->iffeature[i].features[j - 1], 0);
6209 }
6210 }
6211 } else {
6212 /* forward reference */
6213 rc = EXIT_FAILURE;
6214 goto featurecheckdone;
6215 }
6216 }
6217
6218 }
6219 }
6220 rc = EXIT_SUCCESS;
6221
6222featurecheckdone:
6223 ly_set_free(refs);
6224 ly_set_free(procs);
6225 }
6226
6227 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006228 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006229 rc = resolve_unres_schema_uses(item, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006230 break;
6231 case UNRES_TYPE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006232 stype = item;
6233
Radek Krejci51673202016-11-01 17:00:32 +01006234 rc = check_default(stype, (const char **)str_snode, mod);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006235 break;
6236 case UNRES_CHOICE_DFLT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006237 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006238 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006239 choic = item;
6240
Radek Krejcie00d2312016-08-12 15:27:49 +02006241 if (!choic->dflt) {
6242 choic->dflt = resolve_choice_dflt(choic, expr);
6243 }
Michal Vasko7955b362015-09-04 14:18:15 +02006244 if (choic->dflt) {
Radek Krejcie00d2312016-08-12 15:27:49 +02006245 rc = lyp_check_mandatory_choice((struct lys_node *)choic);
Michal Vasko7955b362015-09-04 14:18:15 +02006246 } else {
6247 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006248 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006249 break;
6250 case UNRES_LIST_KEYS:
Radek Krejci5c08a992016-11-02 13:30:04 +01006251 rc = resolve_list_keys(item, ((struct lys_node_list *)item)->keys_str);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006252 break;
6253 case UNRES_LIST_UNIQ:
Radek Krejcid09d1a52016-08-11 14:05:45 +02006254 unique_info = (struct unres_list_uniq *)item;
6255 rc = resolve_unique(unique_info->list, unique_info->expr, unique_info->trg_type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006256 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006257 case UNRES_AUGMENT:
Radek Krejcib3142312016-11-09 11:04:12 +01006258 rc = resolve_augment(item, NULL, unres);
Michal Vasko7178e692016-02-12 15:58:05 +01006259 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006260 case UNRES_XPATH:
6261 node = (struct lys_node *)item;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02006262 rc = lys_check_xpath(node, 1);
Michal Vasko508a50d2016-09-07 14:50:33 +02006263 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006264 default:
6265 LOGINT;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006266 break;
6267 }
6268
Radek Krejci54081ce2016-08-12 15:21:47 +02006269 if (has_str && !rc) {
6270 /* the string is no more needed in case of success.
6271 * In case of forward reference, we will try to resolve the string later */
Radek Krejci4f78b532016-02-17 13:43:00 +01006272 lydict_remove(mod->ctx, str_snode);
6273 }
6274
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006275 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006276}
6277
Michal Vaskof02e3742015-08-05 16:27:02 +02006278/* logs directly */
6279static void
Radek Krejci48464ed2016-03-17 15:44:09 +01006280print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006281{
Michal Vaskocb34dc62016-05-20 14:38:37 +02006282 struct lyxml_elem *xml;
6283 struct lyxml_attr *attr;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006284 struct unres_iffeat_data *iff_data;
Radek Krejci76e15e12016-06-22 11:02:24 +02006285 const char *type_name = NULL;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006286
Michal Vaskof02e3742015-08-05 16:27:02 +02006287 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02006288 case UNRES_IDENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006289 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identity", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006290 break;
6291 case UNRES_TYPE_IDENTREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006292 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identityref", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006293 break;
6294 case UNRES_TYPE_LEAFREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006295 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "leafref",
6296 ((struct lys_type *)item)->info.lref.path);
Michal Vaskof02e3742015-08-05 16:27:02 +02006297 break;
Radek Krejci3a5501d2016-07-18 22:03:34 +02006298 case UNRES_TYPE_DER_TPDF:
Michal Vaskof02e3742015-08-05 16:27:02 +02006299 case UNRES_TYPE_DER:
Michal Vaskocb34dc62016-05-20 14:38:37 +02006300 xml = (struct lyxml_elem *)((struct lys_type *)item)->der;
6301 if (xml->flags & LY_YANG_STRUCTURE_FLAG) {
6302 type_name = ((struct yang_type *)xml)->name;
6303 } else {
6304 LY_TREE_FOR(xml->attr, attr) {
6305 if ((attr->type == LYXML_ATTR_STD) && !strcmp(attr->name, "name")) {
6306 type_name = attr->value;
6307 break;
6308 }
6309 }
6310 assert(attr);
6311 }
6312 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "derived type", type_name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006313 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006314 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006315 iff_data = str_node;
6316 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "if-feature", iff_data->fname);
Michal Vaskof02e3742015-08-05 16:27:02 +02006317 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006318 case UNRES_FEATURE:
6319 LOGVRB("There are unresolved if-features for \"%s\" feature circular dependency check, it will be attempted later",
6320 ((struct lys_feature *)item)->name);
6321 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006322 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006323 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "uses", ((struct lys_node_uses *)item)->name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006324 break;
6325 case UNRES_TYPE_DFLT:
Radek Krejci2e2de832016-10-13 16:12:26 +02006326 if (str_node) {
6327 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "type default", (char *)str_node);
6328 } /* else no default value in the type itself, but we are checking some restrictions against
6329 * possible default value of some base type. The failure is caused by not resolved base type,
6330 * so it was already reported */
Michal Vaskof02e3742015-08-05 16:27:02 +02006331 break;
6332 case UNRES_CHOICE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006333 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "choice default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006334 break;
6335 case UNRES_LIST_KEYS:
Radek Krejci48464ed2016-03-17 15:44:09 +01006336 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list keys", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006337 break;
6338 case UNRES_LIST_UNIQ:
Radek Krejci48464ed2016-03-17 15:44:09 +01006339 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list unique", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006340 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006341 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006342 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "augment target",
6343 ((struct lys_node_augment *)item)->target_name);
Michal Vasko7178e692016-02-12 15:58:05 +01006344 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006345 case UNRES_XPATH:
Michal Vasko0d198372016-11-16 11:40:03 +01006346 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "XPath expressions of",
6347 ((struct lys_node *)item)->name);
Michal Vasko508a50d2016-09-07 14:50:33 +02006348 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006349 default:
6350 LOGINT;
Michal Vaskof02e3742015-08-05 16:27:02 +02006351 break;
6352 }
6353}
6354
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006355/**
Michal Vaskobb211122015-08-19 14:03:11 +02006356 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006357 *
6358 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006359 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006360 *
Michal Vasko92b8a382015-08-19 14:03:49 +02006361 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006362 */
Michal Vaskof02e3742015-08-05 16:27:02 +02006363int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006364resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02006365{
Radek Krejci010e54b2016-03-15 09:40:34 +01006366 uint32_t i, resolved = 0, unres_count, res_count;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006367 int rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006368
6369 assert(unres);
6370
Michal Vaskoe8734262016-09-29 14:12:06 +02006371 LOGVRB("Resolving \"%s\" unresolved schema nodes and their constraints...", mod->name);
Radek Krejci010e54b2016-03-15 09:40:34 +01006372 ly_vlog_hide(1);
Michal Vasko51054ca2015-08-12 12:20:00 +02006373
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006374 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02006375 do {
Michal Vasko88c29542015-11-27 14:57:53 +01006376 unres_count = 0;
6377 res_count = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02006378
6379 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006380 /* UNRES_TYPE_LEAFREF must be resolved (for storing leafref target pointers);
Radek Krejcic79c6b12016-07-26 15:11:49 +02006381 * if-features are resolved here to make sure that we will have all if-features for
6382 * later check of feature circular dependency */
Radek Krejci018f1f52016-08-03 16:01:20 +02006383 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006384 continue;
6385 }
Radek Krejci018f1f52016-08-03 16:01:20 +02006386 /* processes UNRES_USES, UNRES_IFFEAT, UNRES_TYPE_DER, UNRES_TYPE_DER_TPDF, UNRES_TYPE_LEAFREF,
Radek Krejci818b0c52016-11-09 15:10:51 +01006387 * UNRES_AUGMENT, UNRES_CHOICE_DFLT and UNRES_IDENT */
Michal Vasko51054ca2015-08-12 12:20:00 +02006388
Michal Vasko88c29542015-11-27 14:57:53 +01006389 ++unres_count;
Radek Krejci48464ed2016-03-17 15:44:09 +01006390 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006391 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006392 unres->type[i] = UNRES_RESOLVED;
6393 ++resolved;
Michal Vasko88c29542015-11-27 14:57:53 +01006394 ++res_count;
Michal Vasko89e15322015-08-17 15:46:55 +02006395 } else if (rc == -1) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006396 ly_vlog_hide(0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02006397 /* print the error */
6398 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006399 return -1;
Radek Krejcic2a180f2016-06-22 13:28:16 +02006400 } else {
6401 /* forward reference, erase ly_errno */
Radek Krejci00a0e712016-10-26 10:24:46 +02006402 ly_err_clean(1);
Michal Vasko51054ca2015-08-12 12:20:00 +02006403 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006404 }
Michal Vasko88c29542015-11-27 14:57:53 +01006405 } while (res_count && (res_count < unres_count));
Michal Vasko51054ca2015-08-12 12:20:00 +02006406
Michal Vasko88c29542015-11-27 14:57:53 +01006407 if (res_count < unres_count) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006408 /* just print the errors */
6409 ly_vlog_hide(0);
6410
6411 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006412 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006413 continue;
6414 }
6415 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
6416 }
Michal Vasko92b8a382015-08-19 14:03:49 +02006417 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006418 }
6419
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006420 /* the rest */
6421 for (i = 0; i < unres->count; ++i) {
6422 if (unres->type[i] == UNRES_RESOLVED) {
6423 continue;
6424 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02006425
Radek Krejci48464ed2016-03-17 15:44:09 +01006426 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01006427 if (rc == 0) {
Pavol Vican88e16c92016-09-07 15:41:50 +02006428 if (unres->type[i] == UNRES_LIST_UNIQ) {
6429 /* free the allocated structure */
6430 free(unres->item[i]);
6431 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006432 unres->type[i] = UNRES_RESOLVED;
6433 ++resolved;
6434 } else if (rc == -1) {
6435 ly_vlog_hide(0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02006436 /* print the error */
6437 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
6438 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006439 }
6440 }
6441
Radek Krejci010e54b2016-03-15 09:40:34 +01006442 ly_vlog_hide(0);
6443
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006444 if (resolved < unres->count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006445 /* try to resolve the unresolved nodes again, it will not resolve anything, but it will print
6446 * all the validation errors
6447 */
6448 for (i = 0; i < unres->count; ++i) {
6449 if (unres->type[i] == UNRES_RESOLVED) {
6450 continue;
6451 }
Radek Krejcib3142312016-11-09 11:04:12 +01006452 if (unres->type[i] == UNRES_XPATH) {
6453 /* unresolvable XPaths are actually supposed to be warnings - they may be
6454 * unresolved due to the not implemented target module so it shouldn't avoid
6455 * parsing the module, but we still want to announce some issue here */
6456 ly_vlog_hide(0xff);
6457 }
Radek Krejci48464ed2016-03-17 15:44:09 +01006458 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejcib3142312016-11-09 11:04:12 +01006459 if (unres->type[i] == UNRES_XPATH && *ly_vlog_hide_location() == 0xff) {
6460 unres->type[i] = UNRES_RESOLVED;
6461 resolved++;
6462 ly_vlog_hide(0);
6463 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006464 }
Radek Krejcib3142312016-11-09 11:04:12 +01006465 if (resolved < unres->count) {
6466 return -1;
6467 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006468 }
6469
Michal Vaskoe8734262016-09-29 14:12:06 +02006470 LOGVRB("All \"%s\" schema nodes and constraints resolved.", mod->name);
Radek Krejcic071c542016-01-27 14:57:51 +01006471 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006472 return EXIT_SUCCESS;
6473}
6474
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006475/**
Michal Vaskobb211122015-08-19 14:03:11 +02006476 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006477 *
6478 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006479 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006480 * @param[in] item Item to resolve. Type determined by \p type.
6481 * @param[in] type Type of the unresolved item.
6482 * @param[in] str String argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006483 *
Michal Vasko3767fb22016-07-21 12:10:57 +02006484 * @return EXIT_SUCCESS on success, EXIT_FAILURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006485 */
6486int
Radek Krejci48464ed2016-03-17 15:44:09 +01006487unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
6488 const char *str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006489{
Radek Krejci54081ce2016-08-12 15:21:47 +02006490 int rc;
6491 const char *dictstr;
6492
6493 dictstr = lydict_insert(mod->ctx, str, 0);
6494 rc = unres_schema_add_node(mod, unres, item, type, (struct lys_node *)dictstr);
6495
6496 if (rc == -1) {
6497 lydict_remove(mod->ctx, dictstr);
6498 }
6499 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006500}
6501
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006502/**
Michal Vaskobb211122015-08-19 14:03:11 +02006503 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006504 *
6505 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006506 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006507 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01006508 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006509 * @param[in] snode Schema node argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006510 *
Michal Vasko3767fb22016-07-21 12:10:57 +02006511 * @return EXIT_SUCCESS on success, EXIT_FIALURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006512 */
6513int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006514unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Radek Krejci48464ed2016-03-17 15:44:09 +01006515 struct lys_node *snode)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006516{
Michal Vaskoef486d72016-09-27 12:10:44 +02006517 int rc, log_hidden;
Radek Krejci850a5de2016-11-08 14:06:40 +01006518 uint32_t u;
Michal Vasko88c29542015-11-27 14:57:53 +01006519 struct lyxml_elem *yin;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006520
Michal Vasko9bf425b2015-10-22 11:42:03 +02006521 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
6522 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006523
Radek Krejci850a5de2016-11-08 14:06:40 +01006524 /* check for duplicities in unres */
6525 for (u = 0; u < unres->count; u++) {
6526 if (unres->type[u] == type && unres->item[u] == item &&
6527 unres->str_snode[u] == snode && unres->module[u] == mod) {
6528 /* duplication, will be resolved later */
6529 return EXIT_FAILURE;
6530 }
6531 }
6532
Michal Vaskoef486d72016-09-27 12:10:44 +02006533 if (*ly_vlog_hide_location()) {
6534 log_hidden = 1;
6535 } else {
6536 log_hidden = 0;
6537 ly_vlog_hide(1);
6538 }
Radek Krejci48464ed2016-03-17 15:44:09 +01006539 rc = resolve_unres_schema_item(mod, item, type, snode, unres);
Michal Vaskoef486d72016-09-27 12:10:44 +02006540 if (!log_hidden) {
6541 ly_vlog_hide(0);
6542 }
6543
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006544 if (rc != EXIT_FAILURE) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006545 if (rc == -1 && ly_errno == LY_EVALID) {
Radek Krejci2467a492016-10-24 15:16:59 +02006546 ly_err_repeat();
Radek Krejci010e54b2016-03-15 09:40:34 +01006547 }
Radek Krejcid09d1a52016-08-11 14:05:45 +02006548 if (type == UNRES_LIST_UNIQ) {
6549 /* free the allocated structure */
6550 free(item);
Pavol Vican88e16c92016-09-07 15:41:50 +02006551 } else if (rc == -1 && type == UNRES_IFFEAT) {
6552 /* free the allocated resources */
6553 free(*((char **)item));
6554 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006555 return rc;
Radek Krejcif347abc2016-06-22 10:18:47 +02006556 } else {
6557 /* erase info about validation errors */
Radek Krejci00a0e712016-10-26 10:24:46 +02006558 ly_err_clean(1);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006559 }
6560
Radek Krejci48464ed2016-03-17 15:44:09 +01006561 print_unres_schema_item_fail(item, type, snode);
Michal Vaskof02e3742015-08-05 16:27:02 +02006562
Michal Vasko88c29542015-11-27 14:57:53 +01006563 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
Radek Krejci3a5501d2016-07-18 22:03:34 +02006564 if (type == UNRES_TYPE_DER || type == UNRES_TYPE_DER_TPDF) {
Michal Vasko88c29542015-11-27 14:57:53 +01006565 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
Pavol Vicana0e4e672016-02-24 12:20:04 +01006566 if (!(yin->flags & LY_YANG_STRUCTURE_FLAG)) {
6567 lyxml_unlink_elem(mod->ctx, yin, 1);
6568 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
6569 }
Michal Vasko88c29542015-11-27 14:57:53 +01006570 }
6571
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006572 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01006573 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
6574 if (!unres->item) {
6575 LOGMEM;
6576 return -1;
6577 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006578 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01006579 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
6580 if (!unres->type) {
6581 LOGMEM;
6582 return -1;
6583 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006584 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01006585 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
6586 if (!unres->str_snode) {
6587 LOGMEM;
6588 return -1;
6589 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006590 unres->str_snode[unres->count-1] = snode;
Radek Krejcic071c542016-01-27 14:57:51 +01006591 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
6592 if (!unres->module) {
6593 LOGMEM;
6594 return -1;
6595 }
6596 unres->module[unres->count-1] = mod;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006597
Michal Vasko3767fb22016-07-21 12:10:57 +02006598 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006599}
6600
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006601/**
Michal Vaskobb211122015-08-19 14:03:11 +02006602 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006603 *
6604 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006605 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006606 * @param[in] item Old item to be resolved.
6607 * @param[in] type Type of the old unresolved item.
6608 * @param[in] new_item New item to use in the duplicate.
6609 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02006610 * @return EXIT_SUCCESS on success, EXIT_FAILURE if item is not in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006611 */
Michal Vaskodad19402015-08-06 09:51:53 +02006612int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006613unres_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 +02006614{
6615 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006616 struct unres_list_uniq aux_uniq;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006617 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006618
Michal Vaskocf024702015-10-08 15:01:42 +02006619 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006620
Radek Krejcid09d1a52016-08-11 14:05:45 +02006621 /* hack for UNRES_LIST_UNIQ, which stores multiple items behind its item */
6622 if (type == UNRES_LIST_UNIQ) {
6623 aux_uniq.list = item;
6624 aux_uniq.expr = ((struct unres_list_uniq *)new_item)->expr;
6625 item = &aux_uniq;
6626 }
Michal Vasko878e38d2016-09-05 12:17:53 +02006627 i = unres_schema_find(unres, -1, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006628
6629 if (i == -1) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006630 if (type == UNRES_LIST_UNIQ) {
6631 free(new_item);
6632 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02006633 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006634 }
6635
Radek Krejcic79c6b12016-07-26 15:11:49 +02006636 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT) ||
Radek Krejcib69f3232016-09-16 17:41:07 +02006637 (type == UNRES_FEATURE) || (type == UNRES_LIST_UNIQ)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01006638 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006639 LOGINT;
6640 return -1;
6641 }
Radek Krejcicbb473e2016-09-16 14:48:32 +02006642 } else if (type == UNRES_IFFEAT) {
6643 /* duplicate unres_iffeature_data */
6644 iff_data = malloc(sizeof *iff_data);
6645 iff_data->fname = lydict_insert(mod->ctx, ((struct unres_iffeat_data *)unres->str_snode[i])->fname, 0);
6646 iff_data->node = ((struct unres_iffeat_data *)unres->str_snode[i])->node;
6647 if (unres_schema_add_node(mod, unres, new_item, type, (struct lys_node *)iff_data) == -1) {
6648 LOGINT;
6649 return -1;
6650 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006651 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01006652 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006653 LOGINT;
6654 return -1;
6655 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006656 }
Michal Vaskodad19402015-08-06 09:51:53 +02006657
6658 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006659}
6660
Michal Vaskof02e3742015-08-05 16:27:02 +02006661/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006662int
Michal Vasko878e38d2016-09-05 12:17:53 +02006663unres_schema_find(struct unres_schema *unres, int start_on_backwards, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006664{
Michal Vasko878e38d2016-09-05 12:17:53 +02006665 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006666 struct unres_list_uniq *aux_uniq1, *aux_uniq2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006667
Michal Vasko878e38d2016-09-05 12:17:53 +02006668 if (start_on_backwards > 0) {
6669 i = start_on_backwards;
6670 } else {
6671 i = unres->count - 1;
6672 }
6673 for (; i > -1; i--) {
6674 if (unres->type[i] != type) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006675 continue;
6676 }
6677 if (type != UNRES_LIST_UNIQ) {
Michal Vasko878e38d2016-09-05 12:17:53 +02006678 if (unres->item[i] == item) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006679 break;
6680 }
6681 } else {
6682 aux_uniq1 = (struct unres_list_uniq *)unres->item[i - 1];
6683 aux_uniq2 = (struct unres_list_uniq *)item;
6684 if ((aux_uniq1->list == aux_uniq2->list) && ly_strequal(aux_uniq1->expr, aux_uniq2->expr, 0)) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006685 break;
6686 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006687 }
6688 }
6689
Michal Vasko878e38d2016-09-05 12:17:53 +02006690 return i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006691}
Michal Vasko8bcdf292015-08-19 14:04:43 +02006692
Michal Vaskoede9c472016-06-07 09:38:15 +02006693static void
6694unres_schema_free_item(struct ly_ctx *ctx, struct unres_schema *unres, uint32_t i)
6695{
6696 struct lyxml_elem *yin;
6697 struct yang_type *yang;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006698 struct unres_iffeat_data *iff_data;
Michal Vaskoede9c472016-06-07 09:38:15 +02006699
6700 switch (unres->type[i]) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02006701 case UNRES_TYPE_DER_TPDF:
Michal Vaskoede9c472016-06-07 09:38:15 +02006702 case UNRES_TYPE_DER:
6703 yin = (struct lyxml_elem *)((struct lys_type *)unres->item[i])->der;
6704 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6705 yang =(struct yang_type *)yin;
6706 yang->type->base = yang->base;
6707 lydict_remove(ctx, yang->name);
6708 free(yang);
6709 } else {
6710 lyxml_free(ctx, yin);
6711 }
6712 break;
Pavol Vican88e16c92016-09-07 15:41:50 +02006713 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006714 iff_data = (struct unres_iffeat_data *)unres->str_snode[i];
6715 lydict_remove(ctx, iff_data->fname);
6716 free(unres->str_snode[i]);
Pavol Vican88e16c92016-09-07 15:41:50 +02006717 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02006718 case UNRES_IDENT:
6719 case UNRES_TYPE_IDENTREF:
Michal Vaskoede9c472016-06-07 09:38:15 +02006720 case UNRES_CHOICE_DFLT:
6721 case UNRES_LIST_KEYS:
Michal Vaskoede9c472016-06-07 09:38:15 +02006722 lydict_remove(ctx, (const char *)unres->str_snode[i]);
6723 break;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006724 case UNRES_LIST_UNIQ:
6725 free(unres->item[i]);
6726 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02006727 default:
6728 break;
6729 }
6730 unres->type[i] = UNRES_RESOLVED;
6731}
6732
Michal Vasko88c29542015-11-27 14:57:53 +01006733void
Radek Krejcic071c542016-01-27 14:57:51 +01006734unres_schema_free(struct lys_module *module, struct unres_schema **unres)
Michal Vasko88c29542015-11-27 14:57:53 +01006735{
6736 uint32_t i;
Radek Krejcic071c542016-01-27 14:57:51 +01006737 unsigned int unresolved = 0;
Michal Vasko88c29542015-11-27 14:57:53 +01006738
Radek Krejcic071c542016-01-27 14:57:51 +01006739 if (!unres || !(*unres)) {
6740 return;
Michal Vasko88c29542015-11-27 14:57:53 +01006741 }
6742
Radek Krejcic071c542016-01-27 14:57:51 +01006743 assert(module || (*unres)->count == 0);
6744
6745 for (i = 0; i < (*unres)->count; ++i) {
6746 if ((*unres)->module[i] != module) {
6747 if ((*unres)->type[i] != UNRES_RESOLVED) {
6748 unresolved++;
6749 }
6750 continue;
6751 }
Michal Vaskoede9c472016-06-07 09:38:15 +02006752
6753 /* free heap memory for the specific item */
6754 unres_schema_free_item(module->ctx, *unres, i);
Radek Krejcic071c542016-01-27 14:57:51 +01006755 }
6756
Michal Vaskoede9c472016-06-07 09:38:15 +02006757 /* free it all */
Radek Krejcic071c542016-01-27 14:57:51 +01006758 if (!module || (!unresolved && !module->type)) {
6759 free((*unres)->item);
6760 free((*unres)->type);
6761 free((*unres)->str_snode);
6762 free((*unres)->module);
Radek Krejcic071c542016-01-27 14:57:51 +01006763 free((*unres));
6764 (*unres) = NULL;
6765 }
Michal Vasko88c29542015-11-27 14:57:53 +01006766}
6767
Radek Krejci1899d6a2016-11-03 13:48:07 +01006768int
Radek Krejci9b6aad22016-09-20 15:55:51 +02006769resolve_leafref(struct lyd_node_leaf_list *leaf, struct lys_type *type)
Radek Krejci7de36cf2016-09-12 16:18:50 +02006770{
Radek Krejci7de36cf2016-09-12 16:18:50 +02006771 struct unres_data matches;
6772 uint32_t i;
6773
Radek Krejci9b6aad22016-09-20 15:55:51 +02006774 assert(type->base == LY_TYPE_LEAFREF);
6775
6776 /* init */
Radek Krejci7de36cf2016-09-12 16:18:50 +02006777 memset(&matches, 0, sizeof matches);
Radek Krejci7de36cf2016-09-12 16:18:50 +02006778
6779 /* EXIT_FAILURE return keeps leaf->value.lefref NULL, handled later */
Radek Krejci9b6aad22016-09-20 15:55:51 +02006780 if (resolve_path_arg_data((struct lyd_node *)leaf, type->info.lref.path, &matches) == -1) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02006781 return -1;
6782 }
6783
6784 /* check that value matches */
6785 for (i = 0; i < matches.count; ++i) {
Radek Krejci1899d6a2016-11-03 13:48:07 +01006786 /* not that the value is already in canonical form since the parsers does the conversion,
6787 * so we can simply compare just the values */
Radek Krejci7de36cf2016-09-12 16:18:50 +02006788 if (ly_strequal(leaf->value_str, ((struct lyd_node_leaf_list *)matches.node[i])->value_str, 1)) {
Radek Krejci1899d6a2016-11-03 13:48:07 +01006789 /* we have the match */
Radek Krejci7de36cf2016-09-12 16:18:50 +02006790 leaf->value.leafref = matches.node[i];
6791 break;
6792 }
6793 }
6794
6795 free(matches.node);
6796
6797 if (!leaf->value.leafref) {
6798 /* reference not found */
6799 if (type->info.lref.req > -1) {
6800 LOGVAL(LYE_NOLEAFREF, LY_VLOG_LYD, leaf, type->info.lref.path, leaf->value_str);
6801 return EXIT_FAILURE;
6802 } else {
6803 LOGVRB("There is no leafref with the value \"%s\", but it is not required.", leaf->value_str);
6804 }
6805 }
6806
6807 return EXIT_SUCCESS;
6808}
6809
Radek Krejci9ad23f42016-10-31 15:46:52 +01006810API const struct lys_type *
Radek Krejci1899d6a2016-11-03 13:48:07 +01006811lyd_leaf_type(struct lyd_node_leaf_list *leaf, int resolve)
Radek Krejci9b6aad22016-09-20 15:55:51 +02006812{
Radek Krejci9b6aad22016-09-20 15:55:51 +02006813 if (!leaf || !(leaf->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Radek Krejci9ad23f42016-10-31 15:46:52 +01006814 return NULL;
Radek Krejci9b6aad22016-09-20 15:55:51 +02006815 }
Radek Krejci1899d6a2016-11-03 13:48:07 +01006816 if (((struct lys_node_leaf *)leaf->schema)->type.base == LY_TYPE_BITS) {
6817 free(leaf->value.bit);
Radek Krejci9b6aad22016-09-20 15:55:51 +02006818 }
Radek Krejci1899d6a2016-11-03 13:48:07 +01006819 memset(&leaf->value, 0, sizeof leaf->value);
Radek Krejci9b6aad22016-09-20 15:55:51 +02006820
Radek Krejci1899d6a2016-11-03 13:48:07 +01006821 /* resolve */
6822 return lyp_parse_value(&((struct lys_node_leaf *)leaf->schema)->type, (const char **)&leaf->value_str, NULL,
6823 (struct lyd_node *)leaf, resolve ? leaf : NULL, 1, 0);
Radek Krejci9b6aad22016-09-20 15:55:51 +02006824}
6825
6826static int
6827resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type)
6828{
6829 struct lys_type *datatype = NULL;
Radek Krejci9b6aad22016-09-20 15:55:51 +02006830
6831 assert(type->base == LY_TYPE_UNION);
6832
6833 memset(&leaf->value, 0, sizeof leaf->value);
Radek Krejci1899d6a2016-11-03 13:48:07 +01006834 datatype = lyp_parse_value(type, &leaf->value_str, NULL, (struct lyd_node *)leaf, leaf, 1, 0);
Radek Krejci9b6aad22016-09-20 15:55:51 +02006835 if (!datatype) {
6836 /* failure */
6837 LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, (leaf->value_str ? leaf->value_str : ""), leaf->schema->name);
6838 return EXIT_FAILURE;
6839 }
6840
6841 return EXIT_SUCCESS;
6842}
6843
Michal Vasko8bcdf292015-08-19 14:04:43 +02006844/**
6845 * @brief Resolve a single unres data item. Logs directly.
6846 *
Michal Vaskocf024702015-10-08 15:01:42 +02006847 * @param[in] node Data node to resolve.
Michal Vaskocf024702015-10-08 15:01:42 +02006848 * @param[in] type Type of the unresolved item.
Michal Vasko8bcdf292015-08-19 14:04:43 +02006849 *
6850 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
6851 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02006852int
Radek Krejci48464ed2016-03-17 15:44:09 +01006853resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02006854{
Michal Vasko0491ab32015-08-19 14:28:29 +02006855 int rc;
Michal Vasko83a6c462015-10-08 16:43:53 +02006856 struct lyd_node_leaf_list *leaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006857 struct lys_node_leaf *sleaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006858
Michal Vasko83a6c462015-10-08 16:43:53 +02006859 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02006860 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006861
Michal Vaskocf024702015-10-08 15:01:42 +02006862 switch (type) {
6863 case UNRES_LEAFREF:
6864 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Radek Krejci9b6aad22016-09-20 15:55:51 +02006865 return resolve_leafref(leaf, &sleaf->type);
Michal Vasko8bcdf292015-08-19 14:04:43 +02006866
Michal Vaskocf024702015-10-08 15:01:42 +02006867 case UNRES_INSTID:
Radek Krejci7de36cf2016-09-12 16:18:50 +02006868 assert(sleaf->type.base == LY_TYPE_INST);
Radek Krejci00a0e712016-10-26 10:24:46 +02006869 ly_err_clean(1);
Radek Krejci48464ed2016-03-17 15:44:09 +01006870 leaf->value.instance = resolve_instid(node, leaf->value_str);
Radek Krejci40f17b92016-02-03 14:30:43 +01006871 if (!leaf->value.instance) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02006872 if (ly_errno) {
6873 return -1;
6874 } else if (sleaf->type.info.inst.req > -1) {
Michal Vasko6ac68282016-04-11 10:56:47 +02006875 LOGVAL(LYE_NOREQINS, LY_VLOG_LYD, leaf, leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02006876 return EXIT_FAILURE;
6877 } else {
Michal Vasko9925e282016-09-02 12:45:14 +02006878 LOGVRB("There is no instance identifier \"%s\", but it is not required.", leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02006879 }
6880 }
Michal Vaskocf024702015-10-08 15:01:42 +02006881 break;
6882
Radek Krejci7de36cf2016-09-12 16:18:50 +02006883 case UNRES_UNION:
6884 assert(sleaf->type.base == LY_TYPE_UNION);
Radek Krejci9b6aad22016-09-20 15:55:51 +02006885 return resolve_union(leaf, &sleaf->type);
Radek Krejci7de36cf2016-09-12 16:18:50 +02006886
Michal Vaskocf024702015-10-08 15:01:42 +02006887 case UNRES_WHEN:
Radek Krejci46165822016-08-26 14:06:27 +02006888 if ((rc = resolve_when(node, NULL))) {
Michal Vaskocf024702015-10-08 15:01:42 +02006889 return rc;
6890 }
6891 break;
6892
Michal Vaskobf19d252015-10-08 15:39:17 +02006893 case UNRES_MUST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006894 if ((rc = resolve_must(node, 0))) {
6895 return rc;
6896 }
6897 break;
6898
6899 case UNRES_MUST_INOUT:
6900 if ((rc = resolve_must(node, 1))) {
Michal Vaskobf19d252015-10-08 15:39:17 +02006901 return rc;
6902 }
6903 break;
6904
Michal Vaskocf024702015-10-08 15:01:42 +02006905 default:
Michal Vasko8bcdf292015-08-19 14:04:43 +02006906 LOGINT;
6907 return -1;
6908 }
6909
6910 return EXIT_SUCCESS;
6911}
6912
6913/**
Radek Krejci0b7704f2016-03-18 12:16:14 +01006914 * @brief add data unres item
Michal Vasko8bcdf292015-08-19 14:04:43 +02006915 *
6916 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02006917 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02006918 *
Radek Krejci0b7704f2016-03-18 12:16:14 +01006919 * @return 0 on success, -1 on error.
Michal Vasko8bcdf292015-08-19 14:04:43 +02006920 */
6921int
Radek Krejci0b7704f2016-03-18 12:16:14 +01006922unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02006923{
Radek Krejci03b71f72016-03-16 11:10:09 +01006924 assert(unres && node);
Michal Vaskoc4280842016-04-19 16:10:42 +02006925 assert((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)
Radek Krejcibacc7442016-10-27 13:39:56 +02006926 || (type == UNRES_MUST_INOUT) || (type == UNRES_UNION));
Michal Vasko8bcdf292015-08-19 14:04:43 +02006927
Radek Krejci03b71f72016-03-16 11:10:09 +01006928 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01006929 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
6930 if (!unres->node) {
6931 LOGMEM;
6932 return -1;
6933 }
Michal Vaskocf024702015-10-08 15:01:42 +02006934 unres->node[unres->count - 1] = node;
Michal Vasko253035f2015-12-17 16:58:13 +01006935 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
6936 if (!unres->type) {
6937 LOGMEM;
6938 return -1;
6939 }
Michal Vaskocf024702015-10-08 15:01:42 +02006940 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006941
Radek Krejci0b7704f2016-03-18 12:16:14 +01006942 if (type == UNRES_WHEN) {
6943 /* remove previous result */
6944 node->when_status = LYD_WHEN;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006945 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006946
6947 return EXIT_SUCCESS;
6948}
6949
6950/**
6951 * @brief Resolve every unres data item in the structure. Logs directly.
6952 *
Radek Krejci082c84f2016-10-17 16:33:06 +02006953 * If options includes LYD_OPT_TRUSTED, the data are considered trusted (when, must conditions are not expected,
6954 * unresolved leafrefs/instids are accepted).
6955 *
6956 * If options includes LYD_OPT_NOAUTODEL, the false resulting when condition on non-default nodes, the error is raised.
6957 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006958 * @param[in] unres Unres data structure to use.
Radek Krejci082c84f2016-10-17 16:33:06 +02006959 * @param[in,out] root Root node of the data tree, can be changed due to autodeletion.
6960 * @param[in] options Data options as described above.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006961 *
6962 * @return EXIT_SUCCESS on success, -1 on error.
6963 */
6964int
Radek Krejci082c84f2016-10-17 16:33:06 +02006965resolve_unres_data(struct unres_data *unres, struct lyd_node **root, int options)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006966{
Radek Krejci0c0086a2016-03-24 15:20:28 +01006967 uint32_t i, j, first = 1, resolved = 0, del_items = 0, when_stmt = 0;
Radek Krejci010e54b2016-03-15 09:40:34 +01006968 int rc, progress;
Radek Krejci0b7704f2016-03-18 12:16:14 +01006969 struct lyd_node *parent;
Radek Krejci7de36cf2016-09-12 16:18:50 +02006970 struct lyd_node_leaf_list *leaf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006971
Radek Krejci082c84f2016-10-17 16:33:06 +02006972 assert(root);
Radek Krejci03b71f72016-03-16 11:10:09 +01006973 assert(unres);
Radek Krejci03b71f72016-03-16 11:10:09 +01006974
6975 if (!unres->count) {
6976 return EXIT_SUCCESS;
6977 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006978
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02006979 LOGVRB("Resolving unresolved data nodes and their constraints...");
Radek Krejci010e54b2016-03-15 09:40:34 +01006980 ly_vlog_hide(1);
6981
Radek Krejci0b7704f2016-03-18 12:16:14 +01006982 /* when-stmt first */
Radek Krejci010e54b2016-03-15 09:40:34 +01006983 do {
Radek Krejci00a0e712016-10-26 10:24:46 +02006984 ly_err_clean(1);
Radek Krejci010e54b2016-03-15 09:40:34 +01006985 progress = 0;
Michal Vasko6df94132016-09-22 11:08:09 +02006986 for (i = 0; i < unres->count; i++) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006987 if (unres->type[i] != UNRES_WHEN) {
6988 continue;
6989 }
Radek Krejci082c84f2016-10-17 16:33:06 +02006990 assert(!(options & LYD_OPT_TRUSTED));
Radek Krejci0c0086a2016-03-24 15:20:28 +01006991 if (first) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006992 /* count when-stmt nodes in unres list */
6993 when_stmt++;
6994 }
6995
6996 /* resolve when condition only when all parent when conditions are already resolved */
6997 for (parent = unres->node[i]->parent;
6998 parent && LYD_WHEN_DONE(parent->when_status);
6999 parent = parent->parent) {
7000 if (!parent->parent && (parent->when_status & LYD_WHEN_FALSE)) {
7001 /* the parent node was already unlinked, do not resolve this node,
7002 * it will be removed anyway, so just mark it as resolved
7003 */
7004 unres->node[i]->when_status |= LYD_WHEN_FALSE;
7005 unres->type[i] = UNRES_RESOLVED;
7006 resolved++;
7007 break;
7008 }
7009 }
7010 if (parent) {
7011 continue;
7012 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007013
Radek Krejci48464ed2016-03-17 15:44:09 +01007014 rc = resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01007015 if (!rc) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007016 if (unres->node[i]->when_status & LYD_WHEN_FALSE) {
Radek Krejci082c84f2016-10-17 16:33:06 +02007017 if ((options & LYD_OPT_NOAUTODEL) && !unres->node[i]->dflt) {
Radek Krejci03b71f72016-03-16 11:10:09 +01007018 /* false when condition */
7019 ly_vlog_hide(0);
Radek Krejci2467a492016-10-24 15:16:59 +02007020 ly_err_repeat();
Radek Krejci03b71f72016-03-16 11:10:09 +01007021 return -1;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007022 } /* follows else */
7023
Radek Krejci0c0086a2016-03-24 15:20:28 +01007024 /* only unlink now, the subtree can contain another nodes stored in the unres list */
7025 /* if it has parent non-presence containers that would be empty, we should actually
7026 * remove the container
7027 */
Radek Krejci2537fd32016-09-07 16:22:41 +02007028 for (parent = unres->node[i];
7029 parent->parent && parent->parent->schema->nodetype == LYS_CONTAINER;
7030 parent = parent->parent) {
7031 if (((struct lys_node_container *)parent->parent->schema)->presence) {
7032 /* presence container */
7033 break;
Radek Krejci0c0086a2016-03-24 15:20:28 +01007034 }
Radek Krejci2537fd32016-09-07 16:22:41 +02007035 if (parent->next || parent->prev != parent) {
7036 /* non empty (the child we are in and we are going to remove is not the only child) */
7037 break;
7038 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007039 }
Radek Krejci2537fd32016-09-07 16:22:41 +02007040 unres->node[i] = parent;
Radek Krejci0c0086a2016-03-24 15:20:28 +01007041
Radek Krejci0b7704f2016-03-18 12:16:14 +01007042 /* auto-delete */
7043 LOGVRB("auto-delete node \"%s\" due to when condition (%s)", ly_errpath(),
7044 ((struct lys_node_leaf *)unres->node[i]->schema)->when->cond);
Radek Krejci0c0086a2016-03-24 15:20:28 +01007045 if (*root && *root == unres->node[i]) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007046 *root = (*root)->next;
Radek Krejci03b71f72016-03-16 11:10:09 +01007047 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007048
Radek Krejci0b7704f2016-03-18 12:16:14 +01007049 lyd_unlink(unres->node[i]);
7050 unres->type[i] = UNRES_DELETE;
7051 del_items++;
Radek Krejci51fd8162016-03-24 15:49:51 +01007052
7053 /* update the rest of unres items */
7054 for (j = 0; j < unres->count; j++) {
Radek Krejci3db819b2016-03-24 16:29:48 +01007055 if (unres->type[j] == UNRES_RESOLVED || unres->type[j] == UNRES_DELETE) {
Radek Krejci51fd8162016-03-24 15:49:51 +01007056 continue;
7057 }
7058
7059 /* test if the node is in subtree to be deleted */
7060 for (parent = unres->node[j]; parent; parent = parent->parent) {
7061 if (parent == unres->node[i]) {
7062 /* yes, it is */
7063 unres->type[j] = UNRES_RESOLVED;
7064 resolved++;
7065 break;
7066 }
7067 }
7068 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007069 } else {
7070 unres->type[i] = UNRES_RESOLVED;
Radek Krejci03b71f72016-03-16 11:10:09 +01007071 }
Radek Krejci00a0e712016-10-26 10:24:46 +02007072 ly_err_clean(1);
Radek Krejci010e54b2016-03-15 09:40:34 +01007073 resolved++;
7074 progress = 1;
7075 } else if (rc == -1) {
7076 ly_vlog_hide(0);
Michal Vasko76e73402016-08-24 16:00:13 +02007077 /* print only this last error */
7078 resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01007079 return -1;
Radek Krejci2467a492016-10-24 15:16:59 +02007080 } /* else forward reference */
Radek Krejci010e54b2016-03-15 09:40:34 +01007081 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007082 first = 0;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007083 } while (progress && resolved < when_stmt);
Radek Krejci010e54b2016-03-15 09:40:34 +01007084
Radek Krejci0b7704f2016-03-18 12:16:14 +01007085 /* do we have some unresolved when-stmt? */
Radek Krejcid940d732016-03-24 16:02:28 +01007086 if (when_stmt > resolved) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007087 ly_vlog_hide(0);
Radek Krejci2467a492016-10-24 15:16:59 +02007088 ly_err_repeat();
Radek Krejci0b7704f2016-03-18 12:16:14 +01007089 return -1;
7090 }
7091
7092 for (i = 0; del_items && i < unres->count; i++) {
7093 /* we had some when-stmt resulted to false, so now we have to sanitize the unres list */
7094 if (unres->type[i] != UNRES_DELETE) {
7095 continue;
7096 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007097 if (!unres->node[i]) {
7098 unres->type[i] = UNRES_RESOLVED;
7099 del_items--;
7100 continue;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007101 }
7102
7103 /* really remove the complete subtree */
7104 lyd_free(unres->node[i]);
7105 unres->type[i] = UNRES_RESOLVED;
7106 del_items--;
7107 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007108
7109 /* rest */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007110 for (i = 0; i < unres->count; ++i) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007111 if (unres->type[i] == UNRES_RESOLVED) {
7112 continue;
7113 }
Radek Krejci082c84f2016-10-17 16:33:06 +02007114 assert(!(options & LYD_OPT_TRUSTED) || ((unres->type[i] != UNRES_MUST) && (unres->type[i] != UNRES_MUST_INOUT)));
Radek Krejci010e54b2016-03-15 09:40:34 +01007115
Radek Krejci48464ed2016-03-17 15:44:09 +01007116 rc = resolve_unres_data_item(unres->node[i], unres->type[i]);
Michal Vasko6df94132016-09-22 11:08:09 +02007117 if (rc == -1) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007118 ly_vlog_hide(0);
Michal Vasko96b846c2016-05-18 13:28:58 +02007119 /* print only this last error */
7120 resolve_unres_data_item(unres->node[i], unres->type[i]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007121 return -1;
Radek Krejci082c84f2016-10-17 16:33:06 +02007122 } 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 +02007123 unres->type[i] = UNRES_RESOLVED;
7124 resolved++;
Radek Krejci082c84f2016-10-17 16:33:06 +02007125 if (options & LYD_OPT_TRUSTED) {
Michal Vasko6df94132016-09-22 11:08:09 +02007126 /* accept it in this case */
7127 if (unres->type[i] == UNRES_LEAFREF) {
7128 LOGVRB("Leafref \"%s\" with value \"%s\" failed to be resolved.",
7129 ((struct lys_node_leaf *)unres->node[i]->schema)->type.info.lref.path,
7130 ((struct lyd_node_leaf_list *)unres->node[i])->value_str);
7131 } else {
7132 LOGVRB("Instance identifier \"%s\" failed to be resolved.",
7133 ((struct lyd_node_leaf_list *)unres->node[i])->value_str);
7134 }
7135 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007136 }
7137 }
7138
Radek Krejci010e54b2016-03-15 09:40:34 +01007139 ly_vlog_hide(0);
7140 if (resolved < unres->count) {
7141 /* try to resolve the unresolved data again, it will not resolve anything, but it will print
7142 * all the validation errors
7143 */
7144 for (i = 0; i < unres->count; ++i) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02007145 if (unres->type[i] == UNRES_UNION) {
7146 /* does not make sense to print specific errors for all
7147 * the data types, just print that the value is invalid */
7148 leaf = (struct lyd_node_leaf_list *)unres->node[i];
7149 LOGVAL(LYE_INVAL, LY_VLOG_LYD, unres->node[i], (leaf->value_str ? leaf->value_str : ""),
7150 leaf->schema->name);
7151 } else if (unres->type[i] != UNRES_RESOLVED) {
7152 resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01007153 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007154 }
7155 return -1;
7156 }
7157
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02007158 LOGVRB("All data nodes and constraints resolved.");
Radek Krejci010e54b2016-03-15 09:40:34 +01007159 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007160 return EXIT_SUCCESS;
7161}