blob: 5642ef3d0932d974756ff09f71ee5a8a21f3040e [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 Krejci2eee5c02016-12-06 19:18:05 +01001613 prefix_mod = lys_implemented_module(prefix_mod);
Radek Krejci0fa54e92016-09-14 14:01:05 +02001614 }
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 Krejci2eee5c02016-12-06 19:18:05 +01001687 aux_mod = lys_implemented_module(start_mod);
Radek Krejcidf46e222016-11-08 11:57:37 +01001688 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) {
Radek Krejci2eee5c02016-12-06 19:18:05 +01001746 aux_mod = lys_implemented_module(aux_mod);
Radek Krejcidf46e222016-11-08 11:57:37 +01001747 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{
Michal Vasko9ba34de2016-12-07 12:21:19 +01002182 const char *name, *value, *key_val;
Michal Vasko22448d32016-03-16 13:17:29 +01002183 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 Vasko9ba34de2016-12-07 12:21:19 +01002186 const struct lys_type *type;
Michal Vasko22448d32016-03-16 13:17:29 +01002187
Radek Krejci61a86c62016-03-24 11:06:44 +01002188 assert(node);
Michal Vasko22448d32016-03-16 13:17:29 +01002189 assert(node->schema->nodetype == LYS_LIST);
2190
Michal Vaskof29903d2016-04-18 13:13:10 +02002191 key = (struct lyd_node_leaf_list *)node->child;
2192 for (i = 0; i < ((struct lys_node_list *)node->schema)->keys_size; ++i) {
2193 if (!key) {
2194 /* invalid data */
2195 LOGINT;
2196 return -1;
2197 }
Michal Vasko22448d32016-03-16 13:17:29 +01002198
Michal Vasko22448d32016-03-16 13:17:29 +01002199 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002200 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, node_name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002201 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002202 }
2203
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002204 if (((r = parse_schema_json_predicate(predicate, &name, &nam_len, &value, &val_len, &has_predicate)) < 1)
2205 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002206 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
Michal Vaskof29903d2016-04-18 13:13:10 +02002207 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002208 }
2209
2210 predicate += r;
2211 *parsed += r;
2212
Michal Vaskof29903d2016-04-18 13:13:10 +02002213 if (strncmp(key->schema->name, name, nam_len) || key->schema->name[nam_len]) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002214 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002215 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002216 }
2217
Michal Vasko9ba34de2016-12-07 12:21:19 +01002218 /* make value canonical */
2219 type = lyd_leaf_type(key, 1);
2220 if ((type->base == LY_TYPE_IDENT)
Michal Vasko6a938d62016-12-21 09:21:30 +01002221 && !strncmp(key->value_str, lyd_node_module(node)->name, strlen(lyd_node_module(node)->name))
2222 && (key->value_str[strlen(lyd_node_module(node)->name)] == ':')) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002223 key_val = key->value_str + strlen(lyd_node_module(node)->name) + 1;
2224 } else {
2225 key_val = key->value_str;
2226 }
2227
Michal Vasko22448d32016-03-16 13:17:29 +01002228 /* value does not match */
Michal Vasko9ba34de2016-12-07 12:21:19 +01002229 if (strncmp(key_val, value, val_len) || key_val[val_len]) {
Michal Vasko22448d32016-03-16 13:17:29 +01002230 return 1;
2231 }
Michal Vaskof29903d2016-04-18 13:13:10 +02002232
2233 key = (struct lyd_node_leaf_list *)key->next;
Michal Vasko22448d32016-03-16 13:17:29 +01002234 }
2235
2236 if (has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002237 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko22448d32016-03-16 13:17:29 +01002238 return -1;
2239 }
2240
2241 return 0;
2242}
2243
Radek Krejci45826012016-08-24 15:07:57 +02002244/**
2245 * @brief get the closest parent of the node (or the node itself) identified by the nodeid (path)
2246 *
2247 * @param[in] nodeid Node data path to find
2248 * @param[in] llist_value If the \p nodeid identifies leaf-list, this is expected value of the leaf-list instance.
2249 * @param[in] options Bitmask of options flags, see @ref pathoptions.
2250 * @param[out] parsed Number of characters processed in \p id
2251 * @return The closes parent (or the node itself) from the path
2252 */
Michal Vasko22448d32016-03-16 13:17:29 +01002253struct lyd_node *
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002254resolve_partial_json_data_nodeid(const char *nodeid, const char *llist_value, struct lyd_node *start, int options,
2255 int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002256{
Michal Vasko10728b52016-04-07 14:26:29 +02002257 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko9ba34de2016-12-07 12:21:19 +01002258 const char *id, *mod_name, *name, *pred_name, *data_val;
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002259 int r, ret, mod_name_len, nam_len, is_relative = -1;
Michal Vasko9ba34de2016-12-07 12:21:19 +01002260 int has_predicate, last_parsed, llval_len, pred_name_len, last_has_pred;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002261 struct lyd_node *sibling, *last_match = NULL;
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002262 struct lyd_node_leaf_list *llist;
Michal Vasko9ba34de2016-12-07 12:21:19 +01002263 const struct lys_type *type;
Michal Vasko22448d32016-03-16 13:17:29 +01002264 const struct lys_module *prefix_mod, *prev_mod;
2265 struct ly_ctx *ctx;
2266
2267 assert(nodeid && start && parsed);
2268
2269 ctx = start->schema->module->ctx;
2270 id = nodeid;
2271
2272 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 +01002273 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002274 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002275 return NULL;
2276 }
2277 id += r;
2278 /* add it to parsed only after the data node was actually found */
2279 last_parsed = r;
2280
2281 if (is_relative) {
Michal Vasko1adc7242016-11-16 11:05:28 +01002282 prev_mod = lyd_node_module(start);
Michal Vasko22448d32016-03-16 13:17:29 +01002283 start = start->child;
2284 } else {
2285 for (; start->parent; start = start->parent);
Michal Vasko1adc7242016-11-16 11:05:28 +01002286 prev_mod = lyd_node_module(start);
Michal Vasko22448d32016-03-16 13:17:29 +01002287 }
2288
2289 while (1) {
2290 LY_TREE_FOR(start, sibling) {
Michal Vasko945b96b2016-10-18 11:49:12 +02002291 /* RPC/action data check, return simply invalid argument, because the data tree is invalid */
Michal Vasko2411b942016-03-23 13:50:03 +01002292 if (lys_parent(sibling->schema)) {
2293 if (options & LYD_PATH_OPT_OUTPUT) {
2294 if (lys_parent(sibling->schema)->nodetype == LYS_INPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002295 LOGERR(LY_EINVAL, "Provided data tree includes some RPC input nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002296 *parsed = -1;
2297 return NULL;
2298 }
2299 } else {
2300 if (lys_parent(sibling->schema)->nodetype == LYS_OUTPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002301 LOGERR(LY_EINVAL, "Provided data tree includes some RPC output nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002302 *parsed = -1;
2303 return NULL;
2304 }
2305 }
2306 }
2307
Michal Vasko22448d32016-03-16 13:17:29 +01002308 /* name match */
2309 if (!strncmp(name, sibling->schema->name, nam_len) && !sibling->schema->name[nam_len]) {
2310
2311 /* module check */
2312 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002313 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko22448d32016-03-16 13:17:29 +01002314 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002315 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002316 return NULL;
2317 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002318
2319 if (ly_buf_used && module_name[0]) {
2320 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2321 }
2322 ly_buf_used++;
2323
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002324 memmove(module_name, mod_name, mod_name_len);
Michal Vasko22448d32016-03-16 13:17:29 +01002325 module_name[mod_name_len] = '\0';
2326 /* will also find an augment module */
2327 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002328
2329 if (buf_backup) {
2330 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002331 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002332 free(buf_backup);
2333 buf_backup = NULL;
2334 }
2335 ly_buf_used--;
2336
Michal Vasko22448d32016-03-16 13:17:29 +01002337 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002338 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2339 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2340 free(str);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002341 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002342 return NULL;
2343 }
2344 } else {
2345 prefix_mod = prev_mod;
2346 }
Michal Vasko1adc7242016-11-16 11:05:28 +01002347 if (prefix_mod != lyd_node_module(sibling)) {
Michal Vasko22448d32016-03-16 13:17:29 +01002348 continue;
2349 }
2350
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002351 /* leaf-list, did we find it with the correct value or not? */
Michal Vasko22448d32016-03-16 13:17:29 +01002352 if (sibling->schema->nodetype == LYS_LEAFLIST) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002353 llist = (struct lyd_node_leaf_list *)sibling;
2354
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002355 last_has_pred = 0;
Michal Vaskof0a50972016-10-19 11:33:55 +02002356 if (has_predicate) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002357 if ((r = parse_schema_json_predicate(id, &pred_name, &pred_name_len, &llist_value, &llval_len, &last_has_pred)) < 1) {
Michal Vaskof0a50972016-10-19 11:33:55 +02002358 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2359 *parsed = -1;
2360 return NULL;
2361 }
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002362 if ((pred_name[0] != '.') || (pred_name_len != 1)) {
2363 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[1], id + 1);
2364 *parsed = -1;
2365 return NULL;
2366 }
Michal Vaskof0a50972016-10-19 11:33:55 +02002367 } else {
2368 r = 0;
2369 if (llist_value) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002370 llval_len = strlen(llist_value);
Michal Vaskof0a50972016-10-19 11:33:55 +02002371 }
2372 }
2373
Michal Vasko9ba34de2016-12-07 12:21:19 +01002374 /* make value canonical */
2375 type = lyd_leaf_type(llist, 1);
2376 if ((type->base == LY_TYPE_IDENT)
Michal Vasko6a938d62016-12-21 09:21:30 +01002377 && !strncmp(llist->value_str, lyd_node_module(sibling)->name, strlen(lyd_node_module(sibling)->name))
2378 && (llist->value_str[strlen(lyd_node_module(sibling)->name)] == ':')) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002379 data_val = llist->value_str + strlen(lyd_node_module(sibling)->name) + 1;
2380 } else {
2381 data_val = llist->value_str;
2382 }
2383
2384 if ((!llist_value && data_val && data_val[0])
2385 || (llist_value && (strncmp(llist_value, data_val, llval_len) || data_val[llval_len]))) {
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002386 continue;
2387 }
Michal Vasko9ba34de2016-12-07 12:21:19 +01002388
Michal Vaskof0a50972016-10-19 11:33:55 +02002389 id += r;
2390 last_parsed += r;
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002391 has_predicate = last_has_pred;
Michal Vaskof0a50972016-10-19 11:33:55 +02002392
Radek Krejci45826012016-08-24 15:07:57 +02002393 } else if (sibling->schema->nodetype == LYS_LIST) {
2394 /* list, we need predicates'n'stuff then */
Michal Vasko22448d32016-03-16 13:17:29 +01002395 r = 0;
2396 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002397 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002398 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002399 return NULL;
2400 }
2401 ret = resolve_partial_json_data_list_predicate(id, name, sibling, &r);
2402 if (ret == -1) {
Michal Vasko238bd2f2016-03-23 09:39:01 +01002403 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002404 return NULL;
2405 } else if (ret == 1) {
2406 /* this list instance does not match */
2407 continue;
2408 }
2409 id += r;
2410 last_parsed += r;
2411 }
2412
2413 *parsed += last_parsed;
2414
2415 /* the result node? */
2416 if (!id[0]) {
2417 return sibling;
2418 }
2419
2420 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002421 if (sibling->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002422 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002423 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002424 return NULL;
2425 }
Michal Vaskoc6c52cf2016-03-29 11:53:04 +02002426 last_match = sibling;
Michal Vaskofc11b682016-11-18 09:52:41 +01002427 prev_mod = lyd_node_module(sibling);
Michal Vasko22448d32016-03-16 13:17:29 +01002428 start = sibling->child;
Michal Vasko22448d32016-03-16 13:17:29 +01002429 break;
2430 }
2431 }
2432
2433 /* no match, return last match */
2434 if (!sibling) {
2435 return last_match;
2436 }
2437
2438 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 +01002439 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002440 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002441 return NULL;
2442 }
2443 id += r;
2444 last_parsed = r;
2445 }
2446
2447 /* cannot get here */
2448 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002449 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002450 return NULL;
2451}
2452
Michal Vasko3edeaf72016-02-11 13:17:43 +01002453/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02002454 * @brief Resolves length or range intervals. Does not log.
Michal Vaskoaeb51802016-04-11 10:58:47 +02002455 * Syntax is assumed to be correct, *ret MUST be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002456 *
Michal Vaskoaeb51802016-04-11 10:58:47 +02002457 * @param[in] str_restr Restriction as a string.
2458 * @param[in] type Type of the restriction.
2459 * @param[out] ret Final interval structure that starts with
2460 * the interval of the initial type, continues with intervals
2461 * of any superior types derived from the initial one, and
2462 * finishes with intervals from our \p type.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002463 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002464 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002465 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002466int
Michal Vaskoaeb51802016-04-11 10:58:47 +02002467resolve_len_ran_interval(const char *str_restr, struct lys_type *type, struct len_ran_intv **ret)
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002468{
2469 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002470 int kind;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002471 int64_t local_smin, local_smax, local_fmin, local_fmax;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002472 uint64_t local_umin, local_umax;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002473 uint8_t local_fdig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002474 const char *seg_ptr, *ptr;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002475 struct len_ran_intv *local_intv = NULL, *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002476
2477 switch (type->base) {
2478 case LY_TYPE_BINARY:
2479 kind = 0;
2480 local_umin = 0;
2481 local_umax = 18446744073709551615UL;
2482
2483 if (!str_restr && type->info.binary.length) {
2484 str_restr = type->info.binary.length->expr;
2485 }
2486 break;
2487 case LY_TYPE_DEC64:
2488 kind = 2;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002489 local_fmin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2490 local_fmax = __INT64_C(9223372036854775807);
2491 local_fdig = type->info.dec64.dig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002492
2493 if (!str_restr && type->info.dec64.range) {
2494 str_restr = type->info.dec64.range->expr;
2495 }
2496 break;
2497 case LY_TYPE_INT8:
2498 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002499 local_smin = __INT64_C(-128);
2500 local_smax = __INT64_C(127);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002501
2502 if (!str_restr && type->info.num.range) {
2503 str_restr = type->info.num.range->expr;
2504 }
2505 break;
2506 case LY_TYPE_INT16:
2507 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002508 local_smin = __INT64_C(-32768);
2509 local_smax = __INT64_C(32767);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002510
2511 if (!str_restr && type->info.num.range) {
2512 str_restr = type->info.num.range->expr;
2513 }
2514 break;
2515 case LY_TYPE_INT32:
2516 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002517 local_smin = __INT64_C(-2147483648);
2518 local_smax = __INT64_C(2147483647);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002519
2520 if (!str_restr && type->info.num.range) {
2521 str_restr = type->info.num.range->expr;
2522 }
2523 break;
2524 case LY_TYPE_INT64:
2525 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002526 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2527 local_smax = __INT64_C(9223372036854775807);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002528
2529 if (!str_restr && type->info.num.range) {
2530 str_restr = type->info.num.range->expr;
2531 }
2532 break;
2533 case LY_TYPE_UINT8:
2534 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002535 local_umin = __UINT64_C(0);
2536 local_umax = __UINT64_C(255);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002537
2538 if (!str_restr && type->info.num.range) {
2539 str_restr = type->info.num.range->expr;
2540 }
2541 break;
2542 case LY_TYPE_UINT16:
2543 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002544 local_umin = __UINT64_C(0);
2545 local_umax = __UINT64_C(65535);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002546
2547 if (!str_restr && type->info.num.range) {
2548 str_restr = type->info.num.range->expr;
2549 }
2550 break;
2551 case LY_TYPE_UINT32:
2552 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002553 local_umin = __UINT64_C(0);
2554 local_umax = __UINT64_C(4294967295);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002555
2556 if (!str_restr && type->info.num.range) {
2557 str_restr = type->info.num.range->expr;
2558 }
2559 break;
2560 case LY_TYPE_UINT64:
2561 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002562 local_umin = __UINT64_C(0);
2563 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002564
2565 if (!str_restr && type->info.num.range) {
2566 str_restr = type->info.num.range->expr;
2567 }
2568 break;
2569 case LY_TYPE_STRING:
2570 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002571 local_umin = __UINT64_C(0);
2572 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002573
2574 if (!str_restr && type->info.str.length) {
2575 str_restr = type->info.str.length->expr;
2576 }
2577 break;
2578 default:
2579 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002580 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002581 }
2582
2583 /* process superior types */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002584 if (type->der) {
2585 if (resolve_len_ran_interval(NULL, &type->der->type, &intv)) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002586 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002587 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02002588 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002589 assert(!intv || (intv->kind == kind));
2590 }
2591
2592 if (!str_restr) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002593 /* we do not have any restriction, return superior ones */
2594 *ret = intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002595 return EXIT_SUCCESS;
2596 }
2597
2598 /* adjust local min and max */
2599 if (intv) {
2600 tmp_intv = intv;
2601
2602 if (kind == 0) {
2603 local_umin = tmp_intv->value.uval.min;
2604 } else if (kind == 1) {
2605 local_smin = tmp_intv->value.sval.min;
2606 } else if (kind == 2) {
2607 local_fmin = tmp_intv->value.fval.min;
2608 }
2609
2610 while (tmp_intv->next) {
2611 tmp_intv = tmp_intv->next;
2612 }
2613
2614 if (kind == 0) {
2615 local_umax = tmp_intv->value.uval.max;
2616 } else if (kind == 1) {
2617 local_smax = tmp_intv->value.sval.max;
2618 } else if (kind == 2) {
2619 local_fmax = tmp_intv->value.fval.max;
2620 }
2621 }
2622
2623 /* finally parse our restriction */
2624 seg_ptr = str_restr;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002625 tmp_intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002626 while (1) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002627 if (!tmp_local_intv) {
2628 assert(!local_intv);
2629 local_intv = malloc(sizeof *local_intv);
2630 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002631 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002632 tmp_local_intv->next = malloc(sizeof *tmp_local_intv);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002633 tmp_local_intv = tmp_local_intv->next;
2634 }
Michal Vasko253035f2015-12-17 16:58:13 +01002635 if (!tmp_local_intv) {
2636 LOGMEM;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002637 goto error;
Michal Vasko253035f2015-12-17 16:58:13 +01002638 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002639
2640 tmp_local_intv->kind = kind;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002641 tmp_local_intv->type = type;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002642 tmp_local_intv->next = NULL;
2643
2644 /* min */
2645 ptr = seg_ptr;
2646 while (isspace(ptr[0])) {
2647 ++ptr;
2648 }
2649 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2650 if (kind == 0) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002651 tmp_local_intv->value.uval.min = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002652 } else if (kind == 1) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002653 tmp_local_intv->value.sval.min = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002654 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002655 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.min)) {
2656 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2657 goto error;
2658 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002659 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002660 } else if (!strncmp(ptr, "min", 3)) {
2661 if (kind == 0) {
2662 tmp_local_intv->value.uval.min = local_umin;
2663 } else if (kind == 1) {
2664 tmp_local_intv->value.sval.min = local_smin;
2665 } else if (kind == 2) {
2666 tmp_local_intv->value.fval.min = local_fmin;
2667 }
2668
2669 ptr += 3;
2670 } else if (!strncmp(ptr, "max", 3)) {
2671 if (kind == 0) {
2672 tmp_local_intv->value.uval.min = local_umax;
2673 } else if (kind == 1) {
2674 tmp_local_intv->value.sval.min = local_smax;
2675 } else if (kind == 2) {
2676 tmp_local_intv->value.fval.min = local_fmax;
2677 }
2678
2679 ptr += 3;
2680 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002681 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002682 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002683 }
2684
2685 while (isspace(ptr[0])) {
2686 ptr++;
2687 }
2688
2689 /* no interval or interval */
2690 if ((ptr[0] == '|') || !ptr[0]) {
2691 if (kind == 0) {
2692 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
2693 } else if (kind == 1) {
2694 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
2695 } else if (kind == 2) {
2696 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
2697 }
2698 } else if (!strncmp(ptr, "..", 2)) {
2699 /* skip ".." */
2700 ptr += 2;
2701 while (isspace(ptr[0])) {
2702 ++ptr;
2703 }
2704
2705 /* max */
2706 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2707 if (kind == 0) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002708 tmp_local_intv->value.uval.max = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002709 } else if (kind == 1) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002710 tmp_local_intv->value.sval.max = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002711 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002712 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.max)) {
2713 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2714 goto error;
2715 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002716 }
2717 } else if (!strncmp(ptr, "max", 3)) {
2718 if (kind == 0) {
2719 tmp_local_intv->value.uval.max = local_umax;
2720 } else if (kind == 1) {
2721 tmp_local_intv->value.sval.max = local_smax;
2722 } else if (kind == 2) {
2723 tmp_local_intv->value.fval.max = local_fmax;
2724 }
2725 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002726 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002727 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002728 }
2729 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002730 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002731 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002732 }
2733
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002734 /* check min and max in correct order*/
2735 if (kind == 0) {
2736 /* current segment */
2737 if (tmp_local_intv->value.uval.min > tmp_local_intv->value.uval.max) {
2738 goto error;
2739 }
2740 if (tmp_local_intv->value.uval.min < local_umin || tmp_local_intv->value.uval.max > local_umax) {
2741 goto error;
2742 }
2743 /* segments sholud be ascending order */
Pavol Vican69f62c92016-08-30 09:06:25 +02002744 if (tmp_intv && (tmp_intv->value.uval.max >= tmp_local_intv->value.uval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002745 goto error;
2746 }
2747 } else if (kind == 1) {
2748 if (tmp_local_intv->value.sval.min > tmp_local_intv->value.sval.max) {
2749 goto error;
2750 }
2751 if (tmp_local_intv->value.sval.min < local_smin || tmp_local_intv->value.sval.max > local_smax) {
2752 goto error;
2753 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002754 if (tmp_intv && (tmp_intv->value.sval.max >= tmp_local_intv->value.sval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002755 goto error;
2756 }
2757 } else if (kind == 2) {
2758 if (tmp_local_intv->value.fval.min > tmp_local_intv->value.fval.max) {
2759 goto error;
2760 }
2761 if (tmp_local_intv->value.fval.min < local_fmin || tmp_local_intv->value.fval.max > local_fmax) {
2762 goto error;
2763 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002764 if (tmp_intv && (tmp_intv->value.fval.max >= tmp_local_intv->value.fval.min)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002765 /* fraction-digits value is always the same (it cannot be changed in derived types) */
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002766 goto error;
2767 }
2768 }
2769
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002770 /* next segment (next OR) */
2771 seg_ptr = strchr(seg_ptr, '|');
2772 if (!seg_ptr) {
2773 break;
2774 }
2775 seg_ptr++;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002776 tmp_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002777 }
2778
2779 /* check local restrictions against superior ones */
2780 if (intv) {
2781 tmp_intv = intv;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002782 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002783
2784 while (tmp_local_intv && tmp_intv) {
2785 /* reuse local variables */
2786 if (kind == 0) {
2787 local_umin = tmp_local_intv->value.uval.min;
2788 local_umax = tmp_local_intv->value.uval.max;
2789
2790 /* it must be in this interval */
2791 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
2792 /* this interval is covered, next one */
2793 if (local_umax <= tmp_intv->value.uval.max) {
2794 tmp_local_intv = tmp_local_intv->next;
2795 continue;
2796 /* ascending order of restrictions -> fail */
2797 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002798 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002799 }
2800 }
2801 } else if (kind == 1) {
2802 local_smin = tmp_local_intv->value.sval.min;
2803 local_smax = tmp_local_intv->value.sval.max;
2804
2805 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
2806 if (local_smax <= tmp_intv->value.sval.max) {
2807 tmp_local_intv = tmp_local_intv->next;
2808 continue;
2809 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002810 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002811 }
2812 }
2813 } else if (kind == 2) {
2814 local_fmin = tmp_local_intv->value.fval.min;
2815 local_fmax = tmp_local_intv->value.fval.max;
2816
Michal Vasko4d1f0482016-09-19 14:35:06 +02002817 if ((dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.min, local_fdig) > -1)
Pavol Vican3c8ee2b2016-09-29 13:18:13 +02002818 && (dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002819 if (dec64cmp(local_fmax, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002820 tmp_local_intv = tmp_local_intv->next;
2821 continue;
2822 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002823 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002824 }
2825 }
2826 }
2827
2828 tmp_intv = tmp_intv->next;
2829 }
2830
2831 /* some interval left uncovered -> fail */
2832 if (tmp_local_intv) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002833 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002834 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002835 }
2836
Michal Vaskoaeb51802016-04-11 10:58:47 +02002837 /* append the local intervals to all the intervals of the superior types, return it all */
2838 if (intv) {
2839 for (tmp_intv = intv; tmp_intv->next; tmp_intv = tmp_intv->next);
2840 tmp_intv->next = local_intv;
2841 } else {
2842 intv = local_intv;
2843 }
2844 *ret = intv;
2845
2846 return EXIT_SUCCESS;
2847
2848error:
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002849 while (intv) {
2850 tmp_intv = intv->next;
2851 free(intv);
2852 intv = tmp_intv;
2853 }
Michal Vaskoaeb51802016-04-11 10:58:47 +02002854 while (local_intv) {
2855 tmp_local_intv = local_intv->next;
2856 free(local_intv);
2857 local_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002858 }
2859
Michal Vaskoaeb51802016-04-11 10:58:47 +02002860 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002861}
2862
Michal Vasko730dfdf2015-08-11 14:48:05 +02002863/**
Michal Vasko01c6fd22016-05-20 11:43:05 +02002864 * @brief Resolve a typedef, return only resolved typedefs if derived. If leafref, it must be
2865 * resolved for this function to return it. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002866 *
2867 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02002868 * @param[in] mod_name Typedef name module name.
2869 * @param[in] module Main module.
2870 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002871 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002872 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002873 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002874 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002875int
Michal Vasko1e62a092015-12-01 12:27:20 +01002876resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
2877 const struct lys_node *parent, struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002878{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002879 int i, j;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002880 struct lys_tpdf *tpdf, *match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002881 int tpdf_size;
2882
Michal Vasko1dca6882015-10-22 14:29:42 +02002883 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002884 /* no prefix, try built-in types */
2885 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
2886 if (!strcmp(ly_types[i].def->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002887 if (ret) {
2888 *ret = ly_types[i].def;
2889 }
2890 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002891 }
2892 }
2893 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02002894 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002895 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02002896 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002897 }
2898 }
2899
Michal Vasko1dca6882015-10-22 14:29:42 +02002900 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002901 /* search in local typedefs */
2902 while (parent) {
2903 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02002904 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02002905 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
2906 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002907 break;
2908
Radek Krejci76512572015-08-04 09:47:08 +02002909 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02002910 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
2911 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002912 break;
2913
Radek Krejci76512572015-08-04 09:47:08 +02002914 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02002915 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
2916 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002917 break;
2918
Radek Krejci76512572015-08-04 09:47:08 +02002919 case LYS_RPC:
Michal Vasko44fb6382016-06-29 11:12:27 +02002920 case LYS_ACTION:
2921 tpdf_size = ((struct lys_node_rpc_action *)parent)->tpdf_size;
2922 tpdf = ((struct lys_node_rpc_action *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002923 break;
2924
Radek Krejci76512572015-08-04 09:47:08 +02002925 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02002926 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
2927 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002928 break;
2929
Radek Krejci76512572015-08-04 09:47:08 +02002930 case LYS_INPUT:
2931 case LYS_OUTPUT:
Michal Vasko44fb6382016-06-29 11:12:27 +02002932 tpdf_size = ((struct lys_node_inout *)parent)->tpdf_size;
2933 tpdf = ((struct lys_node_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002934 break;
2935
2936 default:
Michal Vaskodcf98e62016-05-05 17:53:53 +02002937 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002938 continue;
2939 }
2940
2941 for (i = 0; i < tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002942 if (!strcmp(tpdf[i].name, name) && tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002943 match = &tpdf[i];
2944 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002945 }
2946 }
2947
Michal Vaskodcf98e62016-05-05 17:53:53 +02002948 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002949 }
Radek Krejcic071c542016-01-27 14:57:51 +01002950 } else {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002951 /* get module where to search */
Michal Vaskob6729c62015-10-21 12:09:47 +02002952 module = lys_get_import_module(module, NULL, 0, mod_name, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02002953 if (!module) {
2954 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002955 }
2956 }
2957
2958 /* search in top level typedefs */
2959 for (i = 0; i < module->tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002960 if (!strcmp(module->tpdf[i].name, name) && module->tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002961 match = &module->tpdf[i];
2962 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002963 }
2964 }
2965
2966 /* search in submodules */
Radek Krejcic071c542016-01-27 14:57:51 +01002967 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002968 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002969 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 +02002970 match = &module->inc[i].submodule->tpdf[j];
2971 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002972 }
2973 }
2974 }
2975
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002976 return EXIT_FAILURE;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002977
2978check_leafref:
2979 if (ret) {
2980 *ret = match;
2981 }
2982 if (match->type.base == LY_TYPE_LEAFREF) {
2983 while (!match->type.info.lref.path) {
2984 match = match->type.der;
2985 assert(match);
2986 }
Michal Vasko01c6fd22016-05-20 11:43:05 +02002987 }
2988 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002989}
2990
Michal Vasko1dca6882015-10-22 14:29:42 +02002991/**
2992 * @brief Check the default \p value of the \p type. Logs directly.
2993 *
2994 * @param[in] type Type definition to use.
2995 * @param[in] value Default value to check.
Michal Vasko56826402016-03-02 11:11:37 +01002996 * @param[in] module Type module.
Michal Vasko1dca6882015-10-22 14:29:42 +02002997 *
2998 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
2999 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003000static int
Radek Krejci51673202016-11-01 17:00:32 +01003001check_default(struct lys_type *type, const char **value, struct lys_module *module)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003002{
Radek Krejcibad2f172016-08-02 11:04:15 +02003003 struct lys_tpdf *base_tpdf = NULL;
Michal Vasko1dca6882015-10-22 14:29:42 +02003004 struct lyd_node_leaf_list node;
Radek Krejci51673202016-11-01 17:00:32 +01003005 const char *dflt = NULL;
Radek Krejci37b756f2016-01-18 10:15:03 +01003006 int ret = EXIT_SUCCESS;
Michal Vasko1dca6882015-10-22 14:29:42 +02003007
Radek Krejci51673202016-11-01 17:00:32 +01003008 assert(value);
3009
Radek Krejcic13db382016-08-16 10:52:42 +02003010 if (type->base <= LY_TYPE_DER) {
Michal Vasko478c4652016-07-21 12:55:01 +02003011 /* the type was not resolved yet, nothing to do for now */
3012 return EXIT_FAILURE;
3013 }
3014
Radek Krejci51673202016-11-01 17:00:32 +01003015 dflt = *value;
3016 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003017 /* we do not have a new default value, so is there any to check even, in some base type? */
3018 for (base_tpdf = type->der; base_tpdf->type.der; base_tpdf = base_tpdf->type.der) {
3019 if (base_tpdf->dflt) {
Radek Krejci51673202016-11-01 17:00:32 +01003020 dflt = base_tpdf->dflt;
Michal Vasko478c4652016-07-21 12:55:01 +02003021 break;
3022 }
3023 }
3024
Radek Krejci51673202016-11-01 17:00:32 +01003025 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003026 /* no default value, nothing to check, all is well */
3027 return EXIT_SUCCESS;
3028 }
3029
3030 /* 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)? */
3031 switch (type->base) {
Michal Vasko478c4652016-07-21 12:55:01 +02003032 case LY_TYPE_IDENT:
3033 case LY_TYPE_INST:
3034 case LY_TYPE_LEAFREF:
3035 case LY_TYPE_BOOL:
3036 case LY_TYPE_EMPTY:
3037 /* these have no restrictions, so we would do the exact same work as the unres in the base typedef */
3038 return EXIT_SUCCESS;
Radek Krejcibad2f172016-08-02 11:04:15 +02003039 case LY_TYPE_BITS:
3040 /* the default value must match the restricted list of values, if the type was restricted */
3041 if (type->info.bits.count) {
3042 break;
3043 }
3044 return EXIT_SUCCESS;
3045 case LY_TYPE_ENUM:
3046 /* the default value must match the restricted list of values, if the type was restricted */
3047 if (type->info.enums.count) {
3048 break;
3049 }
3050 return EXIT_SUCCESS;
Michal Vasko478c4652016-07-21 12:55:01 +02003051 case LY_TYPE_DEC64:
3052 if (type->info.dec64.range) {
3053 break;
3054 }
3055 return EXIT_SUCCESS;
3056 case LY_TYPE_BINARY:
3057 if (type->info.binary.length) {
3058 break;
3059 }
3060 return EXIT_SUCCESS;
3061 case LY_TYPE_INT8:
3062 case LY_TYPE_INT16:
3063 case LY_TYPE_INT32:
3064 case LY_TYPE_INT64:
3065 case LY_TYPE_UINT8:
3066 case LY_TYPE_UINT16:
3067 case LY_TYPE_UINT32:
3068 case LY_TYPE_UINT64:
3069 if (type->info.num.range) {
3070 break;
3071 }
3072 return EXIT_SUCCESS;
3073 case LY_TYPE_STRING:
3074 if (type->info.str.length || type->info.str.patterns) {
3075 break;
3076 }
3077 return EXIT_SUCCESS;
3078 case LY_TYPE_UNION:
3079 /* way too much trouble learning whether we need to check the default again, so just do it */
3080 break;
3081 default:
3082 LOGINT;
3083 return -1;
3084 }
Radek Krejci55a161c2016-09-05 17:13:25 +02003085 } else if (type->base == LY_TYPE_EMPTY) {
3086 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "default", type->parent->name);
3087 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"empty\" data type cannot have a default value.");
3088 return -1;
Michal Vasko478c4652016-07-21 12:55:01 +02003089 }
3090
Michal Vasko1dca6882015-10-22 14:29:42 +02003091 /* dummy leaf */
Radek Krejci4fe36bd2016-03-17 16:47:16 +01003092 memset(&node, 0, sizeof node);
Radek Krejci51673202016-11-01 17:00:32 +01003093 node.value_str = dflt;
Michal Vasko1dca6882015-10-22 14:29:42 +02003094 node.value_type = type->base;
Radek Krejci37b756f2016-01-18 10:15:03 +01003095 node.schema = calloc(1, sizeof (struct lys_node_leaf));
Michal Vasko253035f2015-12-17 16:58:13 +01003096 if (!node.schema) {
3097 LOGMEM;
3098 return -1;
3099 }
Radek Krejcibad2f172016-08-02 11:04:15 +02003100 node.schema->name = strdup("fake-default");
Michal Vasko253035f2015-12-17 16:58:13 +01003101 if (!node.schema->name) {
3102 LOGMEM;
Michal Vaskof49eda02016-07-21 12:17:01 +02003103 free(node.schema);
Michal Vasko253035f2015-12-17 16:58:13 +01003104 return -1;
3105 }
Michal Vasko56826402016-03-02 11:11:37 +01003106 node.schema->module = module;
Radek Krejci37b756f2016-01-18 10:15:03 +01003107 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
Michal Vasko1dca6882015-10-22 14:29:42 +02003108
Radek Krejci37b756f2016-01-18 10:15:03 +01003109 if (type->base == LY_TYPE_LEAFREF) {
Michal Vasko1dca6882015-10-22 14:29:42 +02003110 if (!type->info.lref.target) {
3111 ret = EXIT_FAILURE;
3112 goto finish;
3113 }
Radek Krejci51673202016-11-01 17:00:32 +01003114 ret = check_default(&type->info.lref.target->type, &dflt, module);
3115 if (!ret) {
3116 /* adopt possibly changed default value to its canonical form */
3117 if (*value) {
3118 *value = dflt;
3119 }
3120 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003121 } else {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01003122 if (!lyp_parse_value(&((struct lys_node_leaf *)node.schema)->type, &node.value_str, NULL, NULL, &node, 1, 1, 1)) {
Radek Krejci5dca5932016-11-04 14:30:47 +01003123 /* possible forward reference */
3124 ret = 1;
Radek Krejcibad2f172016-08-02 11:04:15 +02003125 if (base_tpdf) {
Radek Krejci9ad23f42016-10-31 15:46:52 +01003126 /* default value is defined in some base typedef */
Radek Krejcibad2f172016-08-02 11:04:15 +02003127 if ((type->base == LY_TYPE_BITS && type->der->type.der) ||
3128 (type->base == LY_TYPE_ENUM && type->der->type.der)) {
3129 /* we have refined bits/enums */
3130 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
3131 "Invalid value \"%s\" of the default statement inherited to \"%s\" from \"%s\" base type.",
Radek Krejci51673202016-11-01 17:00:32 +01003132 dflt, type->parent->name, base_tpdf->name);
Radek Krejcibad2f172016-08-02 11:04:15 +02003133 }
3134 }
Radek Krejci51673202016-11-01 17:00:32 +01003135 } else {
3136 /* success - adopt canonical form from the node into the default value */
3137 if (dflt != node.value_str) {
3138 /* this can happen only if we have non-inherited default value,
3139 * inherited default values are already in canonical form */
3140 assert(dflt == *value);
3141 *value = node.value_str;
3142 }
Michal Vasko3767fb22016-07-21 12:10:57 +02003143 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003144 }
3145
3146finish:
3147 if (node.value_type == LY_TYPE_BITS) {
3148 free(node.value.bit);
3149 }
3150 free((char *)node.schema->name);
3151 free(node.schema);
3152
3153 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003154}
3155
Michal Vasko730dfdf2015-08-11 14:48:05 +02003156/**
3157 * @brief Check a key for mandatory attributes. Logs directly.
3158 *
3159 * @param[in] key The key to check.
3160 * @param[in] flags What flags to check.
3161 * @param[in] list The list of all the keys.
3162 * @param[in] index Index of the key in the key list.
3163 * @param[in] name The name of the keys.
3164 * @param[in] len The name length.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003165 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003166 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003167 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003168static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003169check_key(struct lys_node_list *list, int index, const char *name, int len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003170{
Radek Krejciadb57612016-02-16 13:34:34 +01003171 struct lys_node_leaf *key = list->keys[index];
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003172 char *dup = NULL;
3173 int j;
3174
3175 /* existence */
3176 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02003177 if (name[len] != '\0') {
3178 dup = strdup(name);
Michal Vasko253035f2015-12-17 16:58:13 +01003179 if (!dup) {
3180 LOGMEM;
3181 return -1;
3182 }
Michal Vaskof02e3742015-08-05 16:27:02 +02003183 dup[len] = '\0';
3184 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003185 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003186 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, list, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003187 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003188 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003189 }
3190
3191 /* uniqueness */
3192 for (j = index - 1; j >= 0; j--) {
Radek Krejciadb57612016-02-16 13:34:34 +01003193 if (key == list->keys[j]) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003194 LOGVAL(LYE_KEY_DUP, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003195 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003196 }
3197 }
3198
3199 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02003200 if (key->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003201 LOGVAL(LYE_KEY_NLEAF, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003202 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003203 }
3204
3205 /* type of the leaf is not built-in empty */
Radek Krejcic3738db2016-09-15 15:51:21 +02003206 if (key->type.base == LY_TYPE_EMPTY && key->module->version < 2) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003207 LOGVAL(LYE_KEY_TYPE, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003208 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003209 }
3210
3211 /* config attribute is the same as of the list */
Radek Krejci5c08a992016-11-02 13:30:04 +01003212 if ((key->flags & LYS_CONFIG_MASK) && (list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003213 LOGVAL(LYE_KEY_CONFIG, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003214 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003215 }
3216
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003217 /* key is not placed from augment */
3218 if (key->parent->nodetype == LYS_AUGMENT) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003219 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, key, key->name);
3220 LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key inserted from augment.");
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003221 return -1;
3222 }
3223
Radek Krejci3f21ada2016-08-01 13:34:31 +02003224 /* key is not when/if-feature -conditional */
3225 j = 0;
3226 if (key->when || (key->iffeature_size && (j = 1))) {
3227 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, key, j ? "if-feature" : "when", "leaf");
3228 LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key definition cannot depend on a \"%s\" condition.",
3229 j ? "if-feature" : "when");
Radek Krejci581ce772015-11-10 17:22:40 +01003230 return -1;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003231 }
3232
Michal Vasko0b85aa82016-03-07 14:37:43 +01003233 return EXIT_SUCCESS;
Michal Vasko184521f2015-09-24 13:14:26 +02003234}
Michal Vasko730dfdf2015-08-11 14:48:05 +02003235
3236/**
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003237 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003238 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003239 * @param[in] parent The parent node of the unique structure.
Michal Vasko0b85aa82016-03-07 14:37:43 +01003240 * @param[in] uniq_str_path One path from the unique string.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003241 *
3242 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
3243 */
3244int
Radek Krejcid09d1a52016-08-11 14:05:45 +02003245resolve_unique(struct lys_node *parent, const char *uniq_str_path, uint8_t *trg_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003246{
Radek Krejci581ce772015-11-10 17:22:40 +01003247 int rc;
Michal Vasko1e62a092015-12-01 12:27:20 +01003248 const struct lys_node *leaf = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003249
Radek Krejcif3c71de2016-04-11 12:45:46 +02003250 rc = resolve_descendant_schema_nodeid(uniq_str_path, parent->child, LYS_LEAF, 1, 1, &leaf);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003251 if (rc || !leaf) {
Michal Vasko0b85aa82016-03-07 14:37:43 +01003252 if (rc) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003253 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003254 if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003255 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, parent, uniq_str_path[rc - 1], &uniq_str_path[rc - 1]);
Radek Krejcif3c71de2016-04-11 12:45:46 +02003256 } else if (rc == -2) {
Michal Vaskoc66c6d82016-04-12 11:37:31 +02003257 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Unique argument references list.");
Radek Krejci581ce772015-11-10 17:22:40 +01003258 }
Michal Vasko0b85aa82016-03-07 14:37:43 +01003259 rc = -1;
Michal Vasko0b85aa82016-03-07 14:37:43 +01003260 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01003261 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3262 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target leaf not found.");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003263 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003264 }
Radek Krejci581ce772015-11-10 17:22:40 +01003265 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003266 }
Michal Vasko9bb061b2016-02-12 11:00:19 +01003267 if (leaf->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003268 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3269 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target is not a leaf.");
Radek Krejcid09d1a52016-08-11 14:05:45 +02003270 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003271 }
3272
Radek Krejcicf509982015-12-15 09:22:44 +01003273 /* check status */
Radek Krejci48464ed2016-03-17 15:44:09 +01003274 if (lyp_check_status(parent->flags, parent->module, parent->name, leaf->flags, leaf->module, leaf->name, leaf)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003275 return -1;
3276 }
3277
Radek Krejcid09d1a52016-08-11 14:05:45 +02003278 /* check that all unique's targets are of the same config type */
3279 if (*trg_type) {
3280 if (((*trg_type == 1) && (leaf->flags & LYS_CONFIG_R)) || ((*trg_type == 2) && (leaf->flags & LYS_CONFIG_W))) {
3281 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3282 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent,
3283 "Leaf \"%s\" referenced in unique statement is config %s, but previous referenced leaf is config %s.",
3284 uniq_str_path, *trg_type == 1 ? "false" : "true", *trg_type == 1 ? "true" : "false");
3285 return -1;
3286 }
3287 } else {
3288 /* first unique */
3289 if (leaf->flags & LYS_CONFIG_W) {
3290 *trg_type = 1;
3291 } else {
3292 *trg_type = 2;
3293 }
3294 }
3295
Radek Krejcica7efb72016-01-18 13:06:01 +01003296 /* set leaf's unique flag */
3297 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
3298
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003299 return EXIT_SUCCESS;
3300
3301error:
3302
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003303 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003304}
3305
Radek Krejci0c0086a2016-03-24 15:20:28 +01003306void
Michal Vasko23b61ec2015-08-19 11:19:50 +02003307unres_data_del(struct unres_data *unres, uint32_t i)
3308{
3309 /* there are items after the one deleted */
3310 if (i+1 < unres->count) {
3311 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02003312 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003313
3314 /* deleting the last item */
3315 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02003316 free(unres->node);
3317 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003318 }
3319
3320 /* if there are no items after and it is not the last one, just move the counter */
3321 --unres->count;
3322}
3323
Michal Vasko0491ab32015-08-19 14:28:29 +02003324/**
3325 * @brief Resolve (find) a data node from a specific module. Does not log.
3326 *
3327 * @param[in] mod Module to search in.
3328 * @param[in] name Name of the data node.
3329 * @param[in] nam_len Length of the name.
3330 * @param[in] start Data node to start the search from.
3331 * @param[in,out] parents Resolved nodes. If there are some parents,
3332 * they are replaced (!!) with the resolvents.
3333 *
Michal Vasko2471e7f2016-04-11 11:00:15 +02003334 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko0491ab32015-08-19 14:28:29 +02003335 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003336static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003337resolve_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 +02003338{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003339 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02003340 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003341 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003342
Michal Vasko23b61ec2015-08-19 11:19:50 +02003343 if (!parents->count) {
3344 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003345 parents->node = malloc(sizeof *parents->node);
Michal Vasko253035f2015-12-17 16:58:13 +01003346 if (!parents->node) {
3347 LOGMEM;
Michal Vasko2471e7f2016-04-11 11:00:15 +02003348 return -1;
Michal Vasko253035f2015-12-17 16:58:13 +01003349 }
Michal Vaskocf024702015-10-08 15:01:42 +02003350 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003351 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003352 for (i = 0; i < parents->count;) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02003353 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003354 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003355 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003356 continue;
3357 }
3358 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02003359 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003360 if (node->schema->module == mod && !strncmp(node->schema->name, name, nam_len)
3361 && node->schema->name[nam_len] == '\0') {
3362 /* matching target */
3363 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02003364 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02003365 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003366 flag = 1;
3367 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02003368 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003369 ++parents->count;
Michal Vasko253035f2015-12-17 16:58:13 +01003370 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
3371 if (!parents->node) {
3372 return EXIT_FAILURE;
3373 }
Michal Vaskocf024702015-10-08 15:01:42 +02003374 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003375 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003376 }
3377 }
3378 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003379
3380 if (!flag) {
3381 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003382 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02003383 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003384 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02003385 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003386 }
3387
Michal Vasko0491ab32015-08-19 14:28:29 +02003388 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02003389}
3390
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003391/**
3392 * @brief Resolve (find) a data node. Does not log.
3393 *
Radek Krejci581ce772015-11-10 17:22:40 +01003394 * @param[in] mod_name Module name of the data node.
3395 * @param[in] mod_name_len Length of the module name.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003396 * @param[in] name Name of the data node.
3397 * @param[in] nam_len Length of the name.
3398 * @param[in] start Data node to start the search from.
3399 * @param[in,out] parents Resolved nodes. If there are some parents,
3400 * they are replaced (!!) with the resolvents.
3401 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003402 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003403 */
Radek Krejcic5090c32015-08-12 09:46:19 +02003404static int
Radek Krejci581ce772015-11-10 17:22:40 +01003405resolve_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 +02003406 struct unres_data *parents)
Radek Krejcic5090c32015-08-12 09:46:19 +02003407{
Michal Vasko1e62a092015-12-01 12:27:20 +01003408 const struct lys_module *mod;
Michal Vasko31fc3672015-10-21 12:08:13 +02003409 char *str;
Radek Krejcic5090c32015-08-12 09:46:19 +02003410
Michal Vasko23b61ec2015-08-19 11:19:50 +02003411 assert(start);
3412
Michal Vasko31fc3672015-10-21 12:08:13 +02003413 if (mod_name) {
3414 /* we have mod_name, find appropriate module */
3415 str = strndup(mod_name, mod_name_len);
Michal Vasko253035f2015-12-17 16:58:13 +01003416 if (!str) {
3417 LOGMEM;
3418 return -1;
3419 }
Michal Vasko31fc3672015-10-21 12:08:13 +02003420 mod = ly_ctx_get_module(start->schema->module->ctx, str, NULL);
3421 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02003422 if (!mod) {
3423 /* invalid prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003424 return -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02003425 }
3426 } else {
3427 /* no prefix, module is the same as of current node */
3428 mod = start->schema->module;
3429 }
3430
3431 return resolve_data(mod, name, name_len, start, parents);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003432}
3433
Michal Vasko730dfdf2015-08-11 14:48:05 +02003434/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003435 * @brief Resolve a path predicate (leafref) in JSON data context. Logs directly
Radek Krejci48464ed2016-03-17 15:44:09 +01003436 * only specific errors, general no-resolvent error is left to the caller.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003437 *
Michal Vaskobb211122015-08-19 14:03:11 +02003438 * @param[in] pred Predicate to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003439 * @param[in] node Node from which the predicate is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02003440 * @param[in,out] node_match Nodes satisfying the restriction
3441 * without the predicate. Nodes not
3442 * satisfying the predicate are removed.
Michal Vasko0491ab32015-08-19 14:28:29 +02003443 * @param[out] parsed Number of characters parsed, negative on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003444 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003445 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003446 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003447static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003448resolve_path_predicate_data(const char *pred, struct lyd_node *node, struct unres_data *node_match,
Radek Krejci010e54b2016-03-15 09:40:34 +01003449 int *parsed)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003450{
Michal Vasko730dfdf2015-08-11 14:48:05 +02003451 /* ... /node[source = destination] ... */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003452 struct unres_data source_match, dest_match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003453 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vasko0491ab32015-08-19 14:28:29 +02003454 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed_loc = 0, pke_parsed = 0;
3455 int has_predicate, dest_parent_times, i, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003456 uint32_t j;
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003457 struct lyd_node_leaf_list *leaf_dst, *leaf_src;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003458
3459 source_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003460 source_match.node = malloc(sizeof *source_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003461 if (!source_match.node) {
3462 LOGMEM;
3463 return -1;
3464 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003465 dest_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003466 dest_match.node = malloc(sizeof *dest_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003467 if (!dest_match.node) {
3468 LOGMEM;
3469 return -1;
3470 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003471
3472 do {
3473 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
3474 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003475 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, pred[-i], &pred[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003476 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003477 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003478 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003479 parsed_loc += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003480 pred += i;
3481
Michal Vasko23b61ec2015-08-19 11:19:50 +02003482 for (j = 0; j < node_match->count;) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003483 /* source */
Michal Vaskocf024702015-10-08 15:01:42 +02003484 source_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02003485
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003486 /* must be leaf (key of a list) */
Radek Krejci581ce772015-11-10 17:22:40 +01003487 if ((rc = resolve_data_node(sour_pref, sour_pref_len, source, sour_len, node_match->node[j],
Michal Vaskocf024702015-10-08 15:01:42 +02003488 &source_match)) || (source_match.count != 1) || (source_match.node[0]->schema->nodetype != LYS_LEAF)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003489 i = 0;
3490 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003491 }
3492
3493 /* destination */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003494 dest_match.node[0] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003495 dest_parent_times = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003496 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3497 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003498 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003499 rc = -1;
3500 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003501 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003502 pke_parsed = i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003503 for (i = 0; i < dest_parent_times; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02003504 dest_match.node[0] = dest_match.node[0]->parent;
3505 if (!dest_match.node[0]) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003506 i = 0;
Michal Vasko0491ab32015-08-19 14:28:29 +02003507 rc = EXIT_FAILURE;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003508 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003509 }
3510 }
3511 while (1) {
Radek Krejci581ce772015-11-10 17:22:40 +01003512 if ((rc = resolve_data_node(dest_pref, dest_pref_len, dest, dest_len, dest_match.node[0],
Michal Vasko0491ab32015-08-19 14:28:29 +02003513 &dest_match)) || (dest_match.count != 1)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003514 i = 0;
3515 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003516 }
3517
3518 if (pke_len == pke_parsed) {
3519 break;
3520 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003521 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 +02003522 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003523 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003524 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003525 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003526 }
3527 pke_parsed += i;
3528 }
3529
3530 /* check match between source and destination nodes */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003531 leaf_dst = (struct lyd_node_leaf_list *)dest_match.node[0];
3532 while (leaf_dst->value_type == LY_TYPE_LEAFREF) {
3533 leaf_dst = (struct lyd_node_leaf_list *)leaf_dst->value.leafref;
3534 }
3535 leaf_src = (struct lyd_node_leaf_list *)source_match.node[0];
3536 while (leaf_src->value_type == LY_TYPE_LEAFREF) {
3537 leaf_src = (struct lyd_node_leaf_list *)leaf_src->value.leafref;
3538 }
3539 if (leaf_src->value_type != leaf_dst->value_type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003540 goto remove_leafref;
3541 }
3542
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003543 if (!ly_strequal(leaf_src->value_str, leaf_dst->value_str, 1)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003544 goto remove_leafref;
3545 }
3546
3547 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003548 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003549 continue;
3550
3551remove_leafref:
3552 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003553 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003554 }
3555 } while (has_predicate);
3556
Michal Vaskocf024702015-10-08 15:01:42 +02003557 free(source_match.node);
3558 free(dest_match.node);
Michal Vasko0491ab32015-08-19 14:28:29 +02003559 if (parsed) {
3560 *parsed = parsed_loc;
3561 }
3562 return EXIT_SUCCESS;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003563
3564error:
3565
3566 if (source_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003567 free(source_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003568 }
3569 if (dest_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003570 free(dest_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003571 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003572 if (parsed) {
3573 *parsed = -parsed_loc+i;
3574 }
3575 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003576}
3577
Michal Vasko730dfdf2015-08-11 14:48:05 +02003578/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003579 * @brief Resolve a path (leafref) in JSON data context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003580 *
Michal Vaskocf024702015-10-08 15:01:42 +02003581 * @param[in] node Leafref data node.
Michal Vasko23b61ec2015-08-19 11:19:50 +02003582 * @param[in] path Path of the leafref.
Radek Krejci48464ed2016-03-17 15:44:09 +01003583 * @param[out] ret Matching nodes. Expects an empty, but allocated structure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003584 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003585 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003586 */
Michal Vasko184521f2015-09-24 13:14:26 +02003587static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003588resolve_path_arg_data(struct lyd_node *node, const char *path, struct unres_data *ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003589{
Radek Krejci71b795b2015-08-10 16:20:39 +02003590 struct lyd_node *data = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003591 const char *prefix, *name;
Michal Vasko0491ab32015-08-19 14:28:29 +02003592 int pref_len, nam_len, has_predicate, parent_times, i, parsed, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003593 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003594
Michal Vaskocf024702015-10-08 15:01:42 +02003595 assert(node && path && ret && !ret->count);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003596
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003597 parent_times = 0;
Michal Vaskod9173342015-08-17 14:35:36 +02003598 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003599
3600 /* searching for nodeset */
3601 do {
Radek Krejcif7ed4c32016-10-27 16:20:03 +02003602 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 +01003603 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path[-i], &path[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003604 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003605 goto error;
3606 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003607 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003608 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003609
Michal Vasko23b61ec2015-08-19 11:19:50 +02003610 if (!ret->count) {
Michal Vaskobfd98e62016-09-02 09:50:05 +02003611 if (parent_times > 0) {
3612 data = node;
3613 for (i = 1; i < parent_times; ++i) {
3614 data = data->parent;
Michal Vasko253035f2015-12-17 16:58:13 +01003615 }
Michal Vaskobfd98e62016-09-02 09:50:05 +02003616 } else if (!parent_times) {
3617 data = node->child;
3618 } else {
3619 /* absolute path */
3620 for (data = node; data->parent; data = data->parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003621 }
3622
Michal Vaskobfd98e62016-09-02 09:50:05 +02003623 /* we may still be parsing it and the pointer is not correct yet */
3624 if (data->prev) {
3625 while (data->prev->next) {
3626 data = data->prev;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003627 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003628 }
3629 }
3630
3631 /* node identifier */
Radek Krejci581ce772015-11-10 17:22:40 +01003632 if ((rc = resolve_data_node(prefix, pref_len, name, nam_len, data, ret))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003633 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003634 LOGVAL(LYE_INELEM_LEN, LY_VLOG_LYD, node, nam_len, name);
Michal Vasko184521f2015-09-24 13:14:26 +02003635 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003636 goto error;
3637 }
3638
3639 if (has_predicate) {
3640 /* we have predicate, so the current results must be lists */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003641 for (j = 0; j < ret->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02003642 if (ret->node[j]->schema->nodetype == LYS_LIST &&
3643 ((struct lys_node_list *)ret->node[0]->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003644 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003645 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003646 continue;
3647 }
3648
3649 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003650 unres_data_del(ret, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003651 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003652 if ((rc = resolve_path_predicate_data(path, node, ret, &i))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003653 if (rc == -1) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003654 LOGVAL(LYE_NORESOLV, LY_VLOG_LYD, node, "leafref", path);
Michal Vasko184521f2015-09-24 13:14:26 +02003655 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003656 goto error;
3657 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003658 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003659 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003660
Michal Vasko23b61ec2015-08-19 11:19:50 +02003661 if (!ret->count) {
Michal Vasko0491ab32015-08-19 14:28:29 +02003662 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003663 goto error;
3664 }
3665 }
3666 } while (path[0] != '\0');
3667
Michal Vaskof02e3742015-08-05 16:27:02 +02003668 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003669
3670error:
3671
Michal Vaskocf024702015-10-08 15:01:42 +02003672 free(ret->node);
3673 ret->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003674 ret->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003675
Michal Vasko0491ab32015-08-19 14:28:29 +02003676 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003677}
3678
Michal Vaskoe27516a2016-10-10 17:55:31 +00003679static int
3680resolve_path_arg_schema_valid_dep_flag(const struct lys_node *op_node, const struct lys_node *first_node, int abs_path)
3681{
3682 int dep1, dep2;
3683 const struct lys_node *node;
3684
3685 if (lys_parent(op_node)) {
3686 /* inner operation (notif/action) */
3687 if (abs_path) {
3688 return 1;
3689 } else {
3690 /* compare depth of both nodes */
3691 for (dep1 = 0, node = op_node; lys_parent(node); node = lys_parent(node));
3692 for (dep2 = 0, node = first_node; lys_parent(node); node = lys_parent(node));
3693 if ((dep2 > dep1) || ((dep2 == dep1) && (op_node != first_node))) {
3694 return 1;
3695 }
3696 }
3697 } else {
3698 /* top-level operation (notif/rpc) */
3699 if (op_node != first_node) {
3700 return 1;
3701 }
3702 }
3703
3704 return 0;
3705}
3706
Michal Vasko730dfdf2015-08-11 14:48:05 +02003707/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003708 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003709 *
Michal Vaskobb211122015-08-19 14:03:11 +02003710 * @param[in] path Path to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003711 * @param[in] context_node Predicate context node (where the predicate is placed).
3712 * @param[in] parent Path context node (where the path begins/is placed).
Michal Vaskoe27516a2016-10-10 17:55:31 +00003713 * @param[in] op_node Optional node if the leafref is in an operation (action/rpc/notif).
Michal Vasko730dfdf2015-08-11 14:48:05 +02003714 *
Michal Vasko184521f2015-09-24 13:14:26 +02003715 * @return 0 on forward reference, otherwise the number
3716 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003717 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003718 */
Michal Vasko1f76a282015-08-04 16:16:53 +02003719static int
Radek Krejciadb57612016-02-16 13:34:34 +01003720resolve_path_predicate_schema(const char *path, const struct lys_node *context_node,
Michal Vaskoe27516a2016-10-10 17:55:31 +00003721 struct lys_node *parent, const struct lys_node *op_node)
Michal Vasko1f76a282015-08-04 16:16:53 +02003722{
Michal Vasko1e62a092015-12-01 12:27:20 +01003723 const struct lys_node *src_node, *dst_node;
Michal Vasko1f76a282015-08-04 16:16:53 +02003724 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vaskof9b35d92016-10-21 15:19:30 +02003725 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, pke_parsed, parsed = 0;
3726 int has_predicate, dest_parent_times, i, rc, first_iter;
Michal Vasko1f76a282015-08-04 16:16:53 +02003727
3728 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02003729 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02003730 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003731 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003732 return -parsed+i;
3733 }
3734 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003735 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02003736
Michal Vasko58090902015-08-13 14:04:15 +02003737 /* source (must be leaf) */
Michal Vasko36cbaa42015-12-14 13:15:48 +01003738 if (!sour_pref) {
Radek Krejciadb57612016-02-16 13:34:34 +01003739 sour_pref = context_node->module->name;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003740 }
Radek Krejciadb57612016-02-16 13:34:34 +01003741 rc = lys_get_sibling(context_node->child, sour_pref, sour_pref_len, source, sour_len,
Michal Vasko59ad4582016-09-16 13:15:41 +02003742 LYS_LEAF | LYS_LEAFLIST | LYS_AUGMENT, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003743 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003744 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02003745 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003746 }
3747
3748 /* destination */
Michal Vaskof9b35d92016-10-21 15:19:30 +02003749 dest_parent_times = 0;
3750 pke_parsed = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003751 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3752 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003753 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 +02003754 return -parsed;
3755 }
3756 pke_parsed += i;
3757
Radek Krejciadb57612016-02-16 13:34:34 +01003758 for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
Michal Vaskofbaead72016-10-07 10:54:48 +02003759 /* path is supposed to be evaluated in data tree, so we have to skip
3760 * all schema nodes that cannot be instantiated in data tree */
3761 for (dst_node = lys_parent(dst_node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003762 dst_node && !(dst_node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Michal Vaskofbaead72016-10-07 10:54:48 +02003763 dst_node = lys_parent(dst_node));
3764
Michal Vasko1f76a282015-08-04 16:16:53 +02003765 if (!dst_node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003766 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003767 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003768 }
3769 }
Michal Vaskoe27516a2016-10-10 17:55:31 +00003770 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003771 while (1) {
Michal Vasko36cbaa42015-12-14 13:15:48 +01003772 if (!dest_pref) {
3773 dest_pref = dst_node->module->name;
3774 }
3775 rc = lys_get_sibling(dst_node->child, dest_pref, dest_pref_len, dest, dest_len,
Michal Vasko165dc4a2015-10-23 09:44:27 +02003776 LYS_CONTAINER | LYS_LIST | LYS_LEAF | LYS_AUGMENT, &dst_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003777 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003778 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003779 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003780 }
3781
Michal Vaskoe27516a2016-10-10 17:55:31 +00003782 if (first_iter) {
3783 if (resolve_path_arg_schema_valid_dep_flag(op_node, dst_node, 0)) {
3784 parent->flags |= LYS_VALID_DEP;
3785 }
3786 first_iter = 0;
3787 }
3788
Michal Vasko1f76a282015-08-04 16:16:53 +02003789 if (pke_len == pke_parsed) {
3790 break;
3791 }
3792
3793 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
3794 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003795 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent,
Radek Krejciadb57612016-02-16 13:34:34 +01003796 (path_key_expr+pke_parsed)[-i], (path_key_expr+pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003797 return -parsed;
3798 }
3799 pke_parsed += i;
3800 }
3801
3802 /* check source - dest match */
Michal Vasko59ad4582016-09-16 13:15:41 +02003803 if (dst_node->nodetype != src_node->nodetype) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003804 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko59ad4582016-09-16 13:15:41 +02003805 LOGVAL(LYE_SPEC, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "Destination node is not a %s, but a %s.",
3806 strnodetype(src_node->nodetype), strnodetype(dst_node->nodetype));
Michal Vasko184521f2015-09-24 13:14:26 +02003807 return -parsed;
3808 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003809 } while (has_predicate);
3810
3811 return parsed;
3812}
3813
Michal Vasko730dfdf2015-08-11 14:48:05 +02003814/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003815 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003816 *
Michal Vaskobb211122015-08-19 14:03:11 +02003817 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003818 * @param[in] parent_node Parent of the leafref.
Radek Krejci2f12f852016-01-08 12:59:57 +01003819 * @param[in] parent_tpdf Flag if the parent node is actually typedef, in that case the path
3820 * has to contain absolute path
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003821 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003822 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003823 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003824 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003825static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003826resolve_path_arg_schema(const char *path, struct lys_node *parent, int parent_tpdf,
Michal Vasko36cbaa42015-12-14 13:15:48 +01003827 const struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02003828{
Michal Vaskoe27516a2016-10-10 17:55:31 +00003829 const struct lys_node *node, *op_node = NULL;
Radek Krejci990af1f2016-11-09 13:53:36 +01003830 const struct lys_module *mod;
3831 struct lys_module *mod_start;
Michal Vasko1f76a282015-08-04 16:16:53 +02003832 const char *id, *prefix, *name;
3833 int pref_len, nam_len, parent_times, has_predicate;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003834 int i, first_iter, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02003835
Michal Vasko184521f2015-09-24 13:14:26 +02003836 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003837 parent_times = 0;
3838 id = path;
3839
Michal Vaskoe27516a2016-10-10 17:55:31 +00003840 /* find operation schema we are in, if applicable */
Michal Vaskoe9914d12016-10-07 14:32:37 +02003841 if (!parent_tpdf) {
Michal Vaskoe27516a2016-10-10 17:55:31 +00003842 for (op_node = lys_parent(parent);
3843 op_node && !(op_node->nodetype & (LYS_ACTION | LYS_NOTIF | LYS_RPC));
3844 op_node = lys_parent(op_node));
Michal Vaskoe9914d12016-10-07 14:32:37 +02003845 }
3846
Radek Krejci990af1f2016-11-09 13:53:36 +01003847 mod_start = lys_node_module(parent);
Michal Vasko1f76a282015-08-04 16:16:53 +02003848 do {
Radek Krejci990af1f2016-11-09 13:53:36 +01003849 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 +01003850 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 +02003851 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003852 }
3853 id += i;
3854
Michal Vasko184521f2015-09-24 13:14:26 +02003855 if (first_iter) {
Michal Vasko1f76a282015-08-04 16:16:53 +02003856 if (parent_times == -1) {
Radek Krejcic071c542016-01-27 14:57:51 +01003857 /* resolve prefix of the module */
Radek Krejci990af1f2016-11-09 13:53:36 +01003858 mod = prefix ? lys_get_import_module(mod_start, NULL, 0, prefix, pref_len) : mod_start;
3859 if (!mod) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003860 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3861 "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003862 return EXIT_FAILURE;
Michal Vasko58090902015-08-13 14:04:15 +02003863 }
Radek Krejci990af1f2016-11-09 13:53:36 +01003864 if (!mod->implemented) {
Radek Krejci2eee5c02016-12-06 19:18:05 +01003865 mod = lys_implemented_module(mod);
Radek Krejci990af1f2016-11-09 13:53:36 +01003866 if (!mod->implemented) {
3867 /* make the found module implemented */
3868 if (lys_set_implemented(mod)) {
3869 return EXIT_FAILURE;
3870 }
3871 }
3872 }
3873 /* get start node */
3874 if (!mod->data) {
3875 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3876 "leafref", path);
3877 return EXIT_FAILURE;
3878 }
3879 node = mod->data;
3880
Michal Vasko1f76a282015-08-04 16:16:53 +02003881 } else if (parent_times > 0) {
Radek Krejci2f12f852016-01-08 12:59:57 +01003882 if (parent_tpdf) {
3883 /* the path is not allowed to contain relative path since we are in top level typedef */
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003884 LOGVAL(LYE_NORESOLV, 0, NULL, "leafref", path);
Radek Krejci2f12f852016-01-08 12:59:57 +01003885 return -1;
3886 }
3887
Michal Vasko94458082016-10-07 14:34:36 +02003888 /* we are looking for a sibling of a node, node it's parent (that is why parent_times - 1) */
3889 for (i = 0, node = parent; i < parent_times - 1; i++) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02003890 /* path is supposed to be evaluated in data tree, so we have to skip
3891 * all schema nodes that cannot be instantiated in data tree */
3892 for (node = lys_parent(node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003893 node && !(node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Radek Krejci3a5501d2016-07-18 22:03:34 +02003894 node = lys_parent(node));
3895
Michal Vasko1f76a282015-08-04 16:16:53 +02003896 if (!node) {
Michal Vaskoe9914d12016-10-07 14:32:37 +02003897 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003898 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003899 }
3900 }
Radek Krejci990af1f2016-11-09 13:53:36 +01003901
3902 /* now we have to check that if we are going into a node from a different module,
3903 * the module is implemented (so its augments are applied) */
3904 mod = prefix ? lys_get_import_module(mod_start, NULL, 0, prefix, pref_len) : mod_start;
3905 if (!mod) {
3906 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
3907 return EXIT_FAILURE;
3908 }
3909 if (!mod->implemented) {
Radek Krejci2eee5c02016-12-06 19:18:05 +01003910 mod = lys_implemented_module(mod);
Radek Krejci990af1f2016-11-09 13:53:36 +01003911 if (!mod->implemented) {
3912 /* make the found module implemented */
3913 if (lys_set_implemented(mod)) {
3914 return EXIT_FAILURE;
3915 }
3916 }
3917 }
Michal Vaskoe01eca52015-08-13 14:42:02 +02003918 } else {
3919 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003920 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003921 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003922 } else {
Radek Krejci990af1f2016-11-09 13:53:36 +01003923 /* we have to first check that the module we are going into is implemented */
3924 mod = prefix ? lys_get_import_module(mod_start, NULL, 0, prefix, pref_len) : mod_start;
3925 if (!mod) {
3926 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
3927 return EXIT_FAILURE;
3928 }
3929 if (!mod->implemented) {
Radek Krejci2eee5c02016-12-06 19:18:05 +01003930 mod = lys_implemented_module(mod);
Radek Krejci990af1f2016-11-09 13:53:36 +01003931 if (!mod->implemented) {
3932 /* make the found module implemented */
3933 if (lys_set_implemented(mod)) {
3934 return EXIT_FAILURE;
3935 }
3936 }
3937 }
3938
Michal Vasko7dc71d02016-03-15 10:42:28 +01003939 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02003940 if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko2f5aceb2016-03-22 10:24:14 +01003941 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 +01003942 return -1;
3943 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003944 node = node->child;
Radek Krejci43ccc4c2016-10-18 20:40:06 +02003945 if (!node) {
3946 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3947 "leafref", path);
3948 return EXIT_FAILURE;
3949 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003950 }
3951
Michal Vasko4f0dad02016-02-15 14:08:23 +01003952 if (!prefix) {
Radek Krejci990af1f2016-11-09 13:53:36 +01003953 prefix = mod_start->name;
Michal Vasko4f0dad02016-02-15 14:08:23 +01003954 }
3955
Michal Vasko36cbaa42015-12-14 13:15:48 +01003956 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 +02003957 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003958 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko7a55bea2016-05-02 14:51:20 +02003959 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003960 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003961
Michal Vaskoe27516a2016-10-10 17:55:31 +00003962 if (first_iter) {
3963 /* set external dependency flag, we can decide based on the first found node */
3964 if (!parent_tpdf && op_node && parent_times &&
3965 resolve_path_arg_schema_valid_dep_flag(op_node, node, (parent_times == -1 ? 1 : 0))) {
3966 parent->flags |= LYS_VALID_DEP;
3967 }
3968 first_iter = 0;
3969 }
3970
Michal Vasko1f76a282015-08-04 16:16:53 +02003971 if (has_predicate) {
3972 /* we have predicate, so the current result must be list */
3973 if (node->nodetype != LYS_LIST) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003974 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003975 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003976 }
3977
Michal Vaskoe27516a2016-10-10 17:55:31 +00003978 i = resolve_path_predicate_schema(id, node, parent, op_node);
Radek Krejci27fe55e2016-09-13 17:13:35 +02003979 if (i <= 0) {
3980 if (i == 0) {
3981 return EXIT_FAILURE;
3982 } else { /* i < 0 */
3983 return -1;
3984 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003985 }
3986 id += i;
Michal Vaskof9b35d92016-10-21 15:19:30 +02003987 has_predicate = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003988 }
3989 } while (id[0]);
3990
Michal Vaskoca917682016-07-25 11:00:37 +02003991 /* the target must be leaf or leaf-list (in YANG 1.1 only) */
Radek Krejci2a5a9602016-11-04 10:21:13 +01003992 if ((node->nodetype != LYS_LEAF) && (node->nodetype != LYS_LEAFLIST)) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003993 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Radek Krejcid47daf62016-08-22 16:23:38 +02003994 LOGVAL(LYE_SPEC, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
Radek Krejci2a5a9602016-11-04 10:21:13 +01003995 "Leafref target \"%s\" is not a leaf nor a leaf-list.", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003996 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02003997 }
3998
Radek Krejcicf509982015-12-15 09:22:44 +01003999 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01004000 if (lyp_check_status(parent->flags, parent->module, parent->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01004001 node->flags, node->module, node->name, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01004002 return -1;
4003 }
4004
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004005 if (ret) {
4006 *ret = node;
4007 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02004008
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004009 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02004010}
4011
Michal Vasko730dfdf2015-08-11 14:48:05 +02004012/**
Michal Vaskof39142b2015-10-21 11:40:05 +02004013 * @brief Resolve instance-identifier predicate in JSON data format.
4014 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004015 *
Michal Vaskobb211122015-08-19 14:03:11 +02004016 * @param[in] pred Predicate to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004017 * @param[in,out] node_match Nodes matching the restriction without
4018 * the predicate. Nodes not satisfying
4019 * the predicate are removed.
4020 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004021 * @return Number of characters successfully parsed,
4022 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004023 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004024static int
Michal Vaskof39142b2015-10-21 11:40:05 +02004025resolve_predicate(const char *pred, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004026{
Michal Vasko730dfdf2015-08-11 14:48:05 +02004027 /* ... /node[target = value] ... */
Michal Vaskob2f40be2016-09-08 16:03:48 +02004028 struct lyd_node *target;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004029 const char *model, *name, *value;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004030 int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed, pred_iter, k;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004031 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004032
Michal Vasko1f2cc332015-08-19 11:18:32 +02004033 assert(pred && node_match->count);
4034
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004035 idx = -1;
4036 parsed = 0;
4037
Michal Vaskob2f40be2016-09-08 16:03:48 +02004038 pred_iter = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004039 do {
Michal Vaskof39142b2015-10-21 11:40:05 +02004040 if ((i = parse_predicate(pred, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004041 return -parsed+i;
4042 }
4043 parsed += i;
4044 pred += i;
4045
4046 if (isdigit(name[0])) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004047 /* pos */
4048 assert(!value);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004049 idx = atoi(name);
Michal Vaskob2f40be2016-09-08 16:03:48 +02004050 } else if (name[0] != '.') {
4051 /* list keys */
4052 if (pred_iter < 0) {
4053 pred_iter = 1;
4054 } else {
4055 ++pred_iter;
4056 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004057 }
4058
Michal Vaskof2f28a12016-09-09 12:43:06 +02004059 for (cur_idx = 1, j = 0; j < node_match->count; ++cur_idx) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004060 /* target */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004061 if (name[0] == '.') {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004062 /* leaf-list value */
Michal Vaskocf024702015-10-08 15:01:42 +02004063 if (node_match->node[j]->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004064 goto remove_instid;
4065 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004066
4067 target = node_match->node[j];
4068 /* check the value */
4069 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
4070 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
4071 goto remove_instid;
4072 }
4073
4074 } else if (!value) {
4075 /* keyless list position */
4076 if ((node_match->node[j]->schema->nodetype != LYS_LIST)
4077 || ((struct lys_node_list *)node_match->node[j]->schema)->keys) {
4078 goto remove_instid;
4079 }
4080
4081 if (idx != cur_idx) {
4082 goto remove_instid;
4083 }
4084
4085 } else {
4086 /* list key value */
Michal Vaskocf024702015-10-08 15:01:42 +02004087 if (node_match->node[j]->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004088 goto remove_instid;
4089 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004090
4091 /* key module must match the list module */
4092 if (strncmp(node_match->node[j]->schema->module->name, model, mod_len)
4093 || node_match->node[j]->schema->module->name[mod_len]) {
4094 goto remove_instid;
4095 }
4096 /* find the key leaf */
Michal Vasko045182c2016-09-09 12:44:07 +02004097 for (k = 1, target = node_match->node[j]->child; target && (k < pred_iter); k++, target = target->next);
Michal Vaskob2f40be2016-09-08 16:03:48 +02004098 if (!target) {
4099 goto remove_instid;
4100 }
4101 if ((struct lys_node_leaf *)target->schema !=
4102 ((struct lys_node_list *)node_match->node[j]->schema)->keys[pred_iter - 1]) {
4103 goto remove_instid;
4104 }
4105
4106 /* check the value */
4107 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
4108 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
4109 goto remove_instid;
4110 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004111 }
4112
Michal Vaskob2f40be2016-09-08 16:03:48 +02004113 /* instid is ok, continue check with the next one */
Michal Vasko1f2cc332015-08-19 11:18:32 +02004114 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004115 continue;
4116
4117remove_instid:
Michal Vaskob2f40be2016-09-08 16:03:48 +02004118 /* does not fulfill conditions, remove instid record */
Michal Vasko1f2cc332015-08-19 11:18:32 +02004119 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004120 }
4121 } while (has_predicate);
4122
Michal Vaskob2f40be2016-09-08 16:03:48 +02004123 /* check that all list keys were specified */
4124 if ((pred_iter > 0) && node_match->count) {
Michal Vasko045182c2016-09-09 12:44:07 +02004125 j = 0;
4126 while (j < node_match->count) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004127 assert(node_match->node[j]->schema->nodetype == LYS_LIST);
4128 if (pred_iter < ((struct lys_node_list *)node_match->node[j]->schema)->keys_size) {
4129 /* not enough predicates, just remove the list instance */
4130 unres_data_del(node_match, j);
Michal Vasko045182c2016-09-09 12:44:07 +02004131 } else {
4132 ++j;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004133 }
4134 }
4135
4136 if (!node_match->count) {
4137 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier is missing some list keys.");
4138 }
4139 }
4140
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004141 return parsed;
4142}
4143
Michal Vasko730dfdf2015-08-11 14:48:05 +02004144/**
Michal Vaskof39142b2015-10-21 11:40:05 +02004145 * @brief Resolve instance-identifier in JSON data format. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004146 *
Radek Krejciadb57612016-02-16 13:34:34 +01004147 * @param[in] data Data node where the path is used
Michal Vasko730dfdf2015-08-11 14:48:05 +02004148 * @param[in] path Instance-identifier node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004149 *
Radek Krejcic5090c32015-08-12 09:46:19 +02004150 * @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 +02004151 */
Radek Krejci1899d6a2016-11-03 13:48:07 +01004152struct lyd_node *
Radek Krejci48464ed2016-03-17 15:44:09 +01004153resolve_instid(struct lyd_node *data, const char *path)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004154{
Radek Krejcic5090c32015-08-12 09:46:19 +02004155 int i = 0, j;
4156 struct lyd_node *result = NULL;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004157 const struct lys_module *mod;
Radek Krejcic5090c32015-08-12 09:46:19 +02004158 struct ly_ctx *ctx = data->schema->module->ctx;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004159 const char *model, *name;
Radek Krejcic5090c32015-08-12 09:46:19 +02004160 char *str;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004161 int mod_len, name_len, has_predicate;
4162 struct unres_data node_match;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004163
4164 memset(&node_match, 0, sizeof node_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004165
Radek Krejcic5090c32015-08-12 09:46:19 +02004166 /* we need root to resolve absolute path */
4167 for (; data->parent; data = data->parent);
Michal Vaskodb9323c2015-10-16 10:32:44 +02004168 /* we're still parsing it and the pointer is not correct yet */
Michal Vasko0491ab32015-08-19 14:28:29 +02004169 if (data->prev) {
4170 for (; data->prev->next; data = data->prev);
4171 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004172
Radek Krejcic5090c32015-08-12 09:46:19 +02004173 /* search for the instance node */
4174 while (path[i]) {
Michal Vaskof39142b2015-10-21 11:40:05 +02004175 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
Radek Krejcic5090c32015-08-12 09:46:19 +02004176 if (j <= 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004177 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004178 goto error;
4179 }
Radek Krejcic5090c32015-08-12 09:46:19 +02004180 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02004181
Michal Vaskob2f40be2016-09-08 16:03:48 +02004182 str = strndup(model, mod_len);
4183 if (!str) {
4184 LOGMEM;
4185 goto error;
Radek Krejcic5090c32015-08-12 09:46:19 +02004186 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004187 mod = ly_ctx_get_module(ctx, str, NULL);
4188 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02004189
Michal Vasko1f2cc332015-08-19 11:18:32 +02004190 if (resolve_data(mod, name, name_len, data, &node_match)) {
Radek Krejcic5090c32015-08-12 09:46:19 +02004191 /* no instance exists */
4192 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004193 }
4194
4195 if (has_predicate) {
4196 /* we have predicate, so the current results must be list or leaf-list */
Michal Vaskof39142b2015-10-21 11:40:05 +02004197 j = resolve_predicate(&path[i], &node_match);
Radek Krejcic5090c32015-08-12 09:46:19 +02004198 if (j < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004199 LOGVAL(LYE_INPRED, LY_VLOG_LYD, data, &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004200 goto error;
4201 }
Michal Vasko1f2cc332015-08-19 11:18:32 +02004202 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02004203
Michal Vasko1f2cc332015-08-19 11:18:32 +02004204 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02004205 /* no instance exists */
4206 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004207 }
4208 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004209 }
4210
Michal Vasko1f2cc332015-08-19 11:18:32 +02004211 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02004212 /* no instance exists */
4213 return NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02004214 } else if (node_match.count > 1) {
Radek Krejcic5090c32015-08-12 09:46:19 +02004215 /* instance identifier must resolve to a single node */
Radek Krejci48464ed2016-03-17 15:44:09 +01004216 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
Michal Vaskod6adbaa2016-04-11 11:01:09 +02004217 goto error;
Radek Krejcic5090c32015-08-12 09:46:19 +02004218 } else {
4219 /* we have required result, remember it and cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02004220 result = node_match.node[0];
4221 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02004222 return result;
4223 }
4224
4225error:
Radek Krejcic5090c32015-08-12 09:46:19 +02004226 /* cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02004227 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02004228 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004229}
4230
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004231int
4232lys_check_xpath(struct lys_node *node, int check_place)
Michal Vasko9e635ac2016-10-17 11:44:09 +02004233{
4234 struct lys_node *parent, *elem;
4235 struct lyxp_set set;
4236 uint32_t i;
4237 int rc;
4238
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004239 if (check_place) {
4240 parent = node;
4241 while (parent) {
4242 if (parent->nodetype == LYS_GROUPING) {
4243 /* unresolved grouping, skip for now (will be checked later) */
Michal Vasko9e635ac2016-10-17 11:44:09 +02004244 return EXIT_SUCCESS;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004245 }
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004246 if (parent->nodetype == LYS_AUGMENT) {
4247 if (!((struct lys_node_augment *)parent)->target) {
Radek Krejcidf46e222016-11-08 11:57:37 +01004248 /* unresolved augment */
4249 if (parent->module->implemented) {
4250 /* skip for now (will be checked later) */
4251 return EXIT_FAILURE;
4252 } else {
4253 /* not implemented augment, skip resolving */
4254 return EXIT_SUCCESS;
4255 }
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004256 } else {
4257 parent = ((struct lys_node_augment *)parent)->target;
4258 continue;
4259 }
4260 }
4261 parent = parent->parent;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004262 }
Michal Vasko9e635ac2016-10-17 11:44:09 +02004263 }
4264
4265 rc = lyxp_node_atomize(node, &set);
4266 if (rc) {
4267 return rc;
4268 }
4269
4270 for (parent = node; parent && !(parent->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); parent = lys_parent(parent));
4271
4272 for (i = 0; i < set.used; ++i) {
4273 /* skip roots'n'stuff */
4274 if (set.val.snodes[i].type == LYXP_NODE_ELEM) {
4275 /* XPath expression cannot reference "lower" status than the node that has the definition */
4276 if (lyp_check_status(node->flags, lys_node_module(node), node->name, set.val.snodes[i].snode->flags,
4277 lys_node_module(set.val.snodes[i].snode), set.val.snodes[i].snode->name, node)) {
4278 return -1;
4279 }
4280
4281 if (parent) {
4282 for (elem = set.val.snodes[i].snode; elem && (elem != parent); elem = lys_parent(elem));
4283 if (!elem) {
4284 /* not in node's RPC or notification subtree, set the flag */
4285 node->flags |= LYS_VALID_DEP;
4286 break;
4287 }
4288 }
4289 }
4290 }
4291
4292 free(set.val.snodes);
4293 return EXIT_SUCCESS;
4294}
4295
Radek Krejcif71f48f2016-10-25 16:37:24 +02004296static int
4297check_leafref_config(struct lys_node_leaf *leaf, struct lys_type *type)
4298{
4299 int i;
4300
4301 if (type->base == LY_TYPE_LEAFREF) {
4302 if ((leaf->flags & LYS_CONFIG_W) && type->info.lref.target && (type->info.lref.target->flags & LYS_CONFIG_R)) {
4303 LOGVAL(LYE_SPEC, LY_VLOG_LYS, leaf, "The %s is config but refers to a non-config %s.",
4304 strnodetype(leaf->nodetype), strnodetype(type->info.lref.target->nodetype));
4305 return -1;
4306 }
4307 /* we can skip the test in case the leafref is not yet resolved. In that case the test is done in the time
4308 * of leafref resolving (lys_leaf_add_leafref_target()) */
4309 } else if (type->base == LY_TYPE_UNION) {
4310 for (i = 0; i < type->info.uni.count; i++) {
4311 if (check_leafref_config(leaf, &type->info.uni.types[i])) {
4312 return -1;
4313 }
4314 }
4315 }
4316 return 0;
4317}
4318
Michal Vasko9e635ac2016-10-17 11:44:09 +02004319/**
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004320 * @brief Passes config flag down to children, skips nodes without config flags.
4321 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004322 *
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004323 * @param[in] node Siblings and their children to have flags changed.
Michal Vaskoe022a562016-09-27 14:24:15 +02004324 * @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 +02004325 * @param[in] flags Flags to assign to all the nodes.
Radek Krejcib3142312016-11-09 11:04:12 +01004326 * @param[in,out] unres List of unresolved items.
Michal Vaskoa86508c2016-08-26 14:30:19 +02004327 *
4328 * @return 0 on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004329 */
Michal Vaskoa86508c2016-08-26 14:30:19 +02004330static int
Radek Krejcib3142312016-11-09 11:04:12 +01004331inherit_config_flag(struct lys_node *node, int flags, int clear, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004332{
Radek Krejcif71f48f2016-10-25 16:37:24 +02004333 struct lys_node_leaf *leaf;
4334
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004335 assert(!(flags ^ (flags & LYS_CONFIG_MASK)));
Radek Krejci1d82ef62015-08-07 14:44:40 +02004336 LY_TREE_FOR(node, node) {
Radek Krejcib3142312016-11-09 11:04:12 +01004337 if (lys_has_xpath(node) && unres_schema_add_node(node->module, unres, node, UNRES_XPATH, NULL) == -1) {
Michal Vasko9e635ac2016-10-17 11:44:09 +02004338 return -1;
4339 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004340 if (clear) {
4341 node->flags &= ~LYS_CONFIG_MASK;
Michal Vaskoc2a8d362016-09-29 08:50:13 +02004342 node->flags &= ~LYS_CONFIG_SET;
Michal Vaskoe022a562016-09-27 14:24:15 +02004343 } else {
4344 if (node->flags & LYS_CONFIG_SET) {
4345 /* skip nodes with an explicit config value */
4346 if ((flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
4347 LOGVAL(LYE_INARG, LY_VLOG_LYS, node, "true", "config");
4348 LOGVAL(LYE_SPEC, LY_VLOG_LYS, node, "State nodes cannot have configuration nodes as children.");
4349 return -1;
4350 }
4351 continue;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004352 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004353
4354 if (!(node->nodetype & (LYS_USES | LYS_GROUPING))) {
4355 node->flags = (node->flags & ~LYS_CONFIG_MASK) | flags;
4356 /* check that configuration lists have keys */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004357 if ((node->nodetype == LYS_LIST) && (node->flags & LYS_CONFIG_W)
4358 && !((struct lys_node_list *)node)->keys_size) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004359 LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_LYS, node, "key", "list");
4360 return -1;
4361 }
4362 }
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004363 }
Radek Krejcibf2abff2016-08-23 15:51:52 +02004364 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Radek Krejcib3142312016-11-09 11:04:12 +01004365 if (inherit_config_flag(node->child, flags, clear, unres)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004366 return -1;
4367 }
Radek Krejcif71f48f2016-10-25 16:37:24 +02004368 } else if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
4369 leaf = (struct lys_node_leaf *)node;
4370 if (check_leafref_config(leaf, &leaf->type)) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02004371 return -1;
4372 }
4373 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004374 }
Michal Vaskoa86508c2016-08-26 14:30:19 +02004375
4376 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004377}
4378
Michal Vasko730dfdf2015-08-11 14:48:05 +02004379/**
Michal Vasko7178e692016-02-12 15:58:05 +01004380 * @brief Resolve augment target. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004381 *
Michal Vaskobb211122015-08-19 14:03:11 +02004382 * @param[in] aug Augment to use.
Michal Vasko3edeaf72016-02-11 13:17:43 +01004383 * @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 +01004384 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004385 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004386 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004387 */
Michal Vasko7178e692016-02-12 15:58:05 +01004388static int
Radek Krejcib3142312016-11-09 11:04:12 +01004389resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004390{
Michal Vaskoe022a562016-09-27 14:24:15 +02004391 int rc, clear_config;
Michal Vasko1d87a922015-08-21 12:57:16 +02004392 struct lys_node *sub;
Pavol Vican47319932016-08-29 09:14:47 +02004393 const struct lys_node *aug_target, *parent;
Radek Krejci27fe55e2016-09-13 17:13:35 +02004394 struct lys_module *mod;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004395
Michal Vasko15b36692016-08-26 15:29:54 +02004396 assert(aug && !aug->target);
Radek Krejcidf46e222016-11-08 11:57:37 +01004397 mod = lys_main_module(aug->module);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004398
Michal Vasko15b36692016-08-26 15:29:54 +02004399 /* resolve target node */
Radek Krejcidf46e222016-11-08 11:57:37 +01004400 rc = resolve_augment_schema_nodeid(aug->target_name, siblings, (siblings ? NULL : aug->module), mod->implemented, &aug_target);
Michal Vasko15b36692016-08-26 15:29:54 +02004401 if (rc == -1) {
4402 return -1;
Radek Krejci5fb4c382016-11-28 09:21:42 +01004403 } else if (rc > 0) {
Michal Vasko15b36692016-08-26 15:29:54 +02004404 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, aug, aug->target_name[rc - 1], &aug->target_name[rc - 1]);
4405 return -1;
Radek Krejci5fb4c382016-11-28 09:21:42 +01004406 } else if (rc == 0 && aug->target) {
4407 /* augment was resolved as a side effect of setting module implemented when
4408 * resolving augment schema nodeid, so we are done here */
4409 return 0;
Michal Vasko15b36692016-08-26 15:29:54 +02004410 }
Radek Krejcidf46e222016-11-08 11:57:37 +01004411 if (!aug_target && mod->implemented) {
Michal Vasko15b36692016-08-26 15:29:54 +02004412 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
4413 return EXIT_FAILURE;
4414 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02004415 /* check that we want to connect augment into its target */
Radek Krejci27fe55e2016-09-13 17:13:35 +02004416 if (!mod->implemented) {
4417 /* it must be augment only to the same module,
4418 * otherwise we do not apply augment in not-implemented
4419 * module. If the module is set to be implemented in future,
4420 * the augment is being resolved and checked again */
Radek Krejcidf46e222016-11-08 11:57:37 +01004421 if (!aug_target) {
4422 /* target was not even resolved */
4423 return EXIT_SUCCESS;
4424 }
4425 /* target was resolved, but it may refer another module */
4426 for (sub = (struct lys_node *)aug_target; sub; sub = lys_parent(sub)) {
Radek Krejci27fe55e2016-09-13 17:13:35 +02004427 if (lys_node_module(sub) != mod) {
4428 /* this is not an implemented module and the augment
4429 * target some other module, so avoid its connecting
4430 * to the target */
4431 return EXIT_SUCCESS;
4432 }
4433 }
4434 }
4435
Michal Vasko15b36692016-08-26 15:29:54 +02004436 if (!aug->child) {
4437 /* nothing to do */
4438 LOGWRN("Augment \"%s\" without children.", aug->target_name);
Radek Krejci27fe55e2016-09-13 17:13:35 +02004439 goto success;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004440 }
4441
Michal Vaskod58d5962016-03-02 14:29:41 +01004442 /* check for mandatory nodes - if the target node is in another module
4443 * the added nodes cannot be mandatory
4444 */
Michal Vasko15b36692016-08-26 15:29:54 +02004445 if (!aug->parent && (lys_node_module((struct lys_node *)aug) != lys_node_module(aug_target))
Radek Krejcidf24cbe2016-11-08 11:55:51 +01004446 && (rc = lyp_check_mandatory_augment(aug, aug_target))) {
Radek Krejcie00d2312016-08-12 15:27:49 +02004447 return rc;
Michal Vaskod58d5962016-03-02 14:29:41 +01004448 }
4449
Michal Vasko07e89ef2016-03-03 13:28:57 +01004450 /* check augment target type and then augment nodes type */
Michal Vasko15b36692016-08-26 15:29:54 +02004451 if (aug_target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF)) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004452 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004453 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES | LYS_CHOICE))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004454 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4455 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko15b36692016-08-26 15:29:54 +02004456 strnodetype(aug_target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004457 return -1;
4458 }
4459 }
Michal Vasko15b36692016-08-26 15:29:54 +02004460 } else if (aug_target->nodetype == LYS_CHOICE) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004461 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004462 if (!(sub->nodetype & (LYS_CASE | LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004463 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4464 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko15b36692016-08-26 15:29:54 +02004465 strnodetype(aug_target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004466 return -1;
4467 }
4468 }
4469 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01004470 LOGVAL(LYE_INARG, LY_VLOG_LYS, aug, aug->target_name, "target-node");
Michal Vasko15b36692016-08-26 15:29:54 +02004471 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Invalid augment target node type \"%s\".", strnodetype(aug_target->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004472 return -1;
4473 }
4474
Radek Krejcic071c542016-01-27 14:57:51 +01004475 /* check identifier uniqueness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02004476 LY_TREE_FOR(aug->child, sub) {
Michal Vasko15b36692016-08-26 15:29:54 +02004477 if (lys_check_id(sub, (struct lys_node *)aug_target, NULL)) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02004478 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02004479 }
4480 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004481
Michal Vasko15b36692016-08-26 15:29:54 +02004482 /* finally reconnect augmenting data into the target - add them to the target child list,
4483 * by setting aug->target we know the augment is fully resolved now */
4484 aug->target = (struct lys_node *)aug_target;
4485 if (aug->target->child) {
4486 sub = aug->target->child->prev; /* remember current target's last node */
4487 sub->next = aug->child; /* connect augmenting data after target's last node */
4488 aug->target->child->prev = aug->child->prev; /* new target's last node is last augmenting node */
4489 aug->child->prev = sub; /* finish connecting of both child lists */
4490 } else {
4491 aug->target->child = aug->child;
4492 }
4493
Michal Vasko9e635ac2016-10-17 11:44:09 +02004494 /* inherit config information from actual parent */
4495 for(parent = aug_target; parent && !(parent->nodetype & (LYS_NOTIF | LYS_INPUT | LYS_OUTPUT | LYS_RPC)); parent = lys_parent(parent));
4496 clear_config = (parent) ? 1 : 0;
4497 LY_TREE_FOR(aug->child, sub) {
Radek Krejcib3142312016-11-09 11:04:12 +01004498 if (inherit_config_flag(sub, aug_target->flags & LYS_CONFIG_MASK, clear_config, unres)) {
Michal Vasko9e635ac2016-10-17 11:44:09 +02004499 return -1;
4500 }
4501 }
4502
Radek Krejci27fe55e2016-09-13 17:13:35 +02004503success:
4504 if (mod->implemented) {
4505 /* make target modules also implemented */
4506 for (sub = aug->target; sub; sub = lys_parent(sub)) {
4507 if (lys_set_implemented(sub->module)) {
4508 return -1;
4509 }
4510 }
4511 }
4512
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004513 return EXIT_SUCCESS;
4514}
4515
Michal Vasko730dfdf2015-08-11 14:48:05 +02004516/**
Pavol Vican855ca622016-09-05 13:07:54 +02004517 * @brief Resolve (find) choice default case. Does not log.
4518 *
4519 * @param[in] choic Choice to use.
4520 * @param[in] dflt Name of the default case.
4521 *
4522 * @return Pointer to the default node or NULL.
4523 */
4524static struct lys_node *
4525resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
4526{
4527 struct lys_node *child, *ret;
4528
4529 LY_TREE_FOR(choic->child, child) {
4530 if (child->nodetype == LYS_USES) {
4531 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
4532 if (ret) {
4533 return ret;
4534 }
4535 }
4536
4537 if (ly_strequal(child->name, dflt, 1) && (child->nodetype & (LYS_ANYDATA | LYS_CASE
Radek Krejci2f792db2016-09-12 10:52:33 +02004538 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE))) {
Pavol Vican855ca622016-09-05 13:07:54 +02004539 return child;
4540 }
4541 }
4542
4543 return NULL;
4544}
4545
4546/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02004547 * @brief Resolve uses, apply augments, refines. Logs directly.
4548 *
Michal Vaskobb211122015-08-19 14:03:11 +02004549 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004550 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004551 *
Michal Vaskodef0db12015-10-07 13:22:48 +02004552 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004553 */
Michal Vasko184521f2015-09-24 13:14:26 +02004554static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004555resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004556{
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004557 struct ly_ctx *ctx = uses->module->ctx; /* shortcut */
Pavol Vican855ca622016-09-05 13:07:54 +02004558 struct lys_node *node = NULL, *next, *iter, **refine_nodes = NULL;
Pavol Vican55abd332016-07-12 15:54:49 +02004559 struct lys_node *node_aux, *parent, *tmp;
Radek Krejci200bf712016-08-16 17:11:04 +02004560 struct lys_node_leaflist *llist;
4561 struct lys_node_leaf *leaf;
Radek Krejci76512572015-08-04 09:47:08 +02004562 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004563 struct lys_restr *must, **old_must;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004564 struct lys_iffeature *iff, **old_iff;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004565 int i, j, k, rc;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004566 uint8_t size, *old_size;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004567 unsigned int usize, usize1, usize2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004568
Michal Vasko71e1aa82015-08-12 12:17:51 +02004569 assert(uses->grp);
Michal Vaskoe7708512016-03-11 10:26:55 +01004570 /* HACK just check that the grouping is resolved */
Michal Vaskodef0db12015-10-07 13:22:48 +02004571 assert(!uses->grp->nacm);
Michal Vasko71e1aa82015-08-12 12:17:51 +02004572
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004573 if (!uses->grp->child) {
4574 /* grouping without children, warning was already displayed */
4575 return EXIT_SUCCESS;
4576 }
4577
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004578 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01004579 LY_TREE_FOR(uses->grp->child, node_aux) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004580 node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, uses->nacm, unres, 0);
Michal Vasko1e62a092015-12-01 12:27:20 +01004581 if (!node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004582 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, uses->grp->name, "uses");
4583 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Copying data from grouping failed.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004584 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004585 }
Pavol Vican55abd332016-07-12 15:54:49 +02004586 /* test the name of siblings */
4587 LY_TREE_FOR((uses->parent) ? uses->parent->child : lys_main_module(uses->module)->data, tmp) {
Pavol Vican2510ddc2016-07-18 16:23:44 +02004588 if (!(tmp->nodetype & (LYS_USES | LYS_GROUPING | LYS_CASE)) && ly_strequal(tmp->name, node_aux->name, 1)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004589 goto fail;
Pavol Vican55abd332016-07-12 15:54:49 +02004590 }
4591 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004592 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004593
Michal Vaskodef0db12015-10-07 13:22:48 +02004594 /* we managed to copy the grouping, the rest must be possible to resolve */
4595
Pavol Vican855ca622016-09-05 13:07:54 +02004596 if (uses->refine_size) {
4597 refine_nodes = malloc(uses->refine_size * sizeof *refine_nodes);
4598 if (!refine_nodes) {
4599 LOGMEM;
4600 goto fail;
4601 }
4602 }
4603
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004604 /* apply refines */
4605 for (i = 0; i < uses->refine_size; i++) {
4606 rfn = &uses->refine[i];
Michal Vasko3edeaf72016-02-11 13:17:43 +01004607 rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child, LYS_NO_RPC_NOTIF_NODE,
Radek Krejcif3c71de2016-04-11 12:45:46 +02004608 1, 0, (const struct lys_node **)&node);
Michal Vasko9bb061b2016-02-12 11:00:19 +01004609 if (rc || !node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004610 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004611 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004612 }
4613
Radek Krejci1d82ef62015-08-07 14:44:40 +02004614 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004615 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
4616 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Refine substatements not applicable to the target-node.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004617 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004618 }
Pavol Vican855ca622016-09-05 13:07:54 +02004619 refine_nodes[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004620
4621 /* description on any nodetype */
4622 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004623 lydict_remove(ctx, node->dsc);
4624 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004625 }
4626
4627 /* reference on any nodetype */
4628 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004629 lydict_remove(ctx, node->ref);
4630 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004631 }
4632
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004633 /* config on any nodetype,
4634 * in case of notification or rpc/action, the config is not applicable (there is no config status) */
4635 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004636 node->flags &= ~LYS_CONFIG_MASK;
4637 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004638 }
4639
4640 /* default value ... */
Radek Krejci200bf712016-08-16 17:11:04 +02004641 if (rfn->dflt_size) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004642 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004643 /* leaf */
Radek Krejci200bf712016-08-16 17:11:04 +02004644 leaf = (struct lys_node_leaf *)node;
4645
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004646 /* replace default value */
Radek Krejci200bf712016-08-16 17:11:04 +02004647 lydict_remove(ctx, leaf->dflt);
4648 leaf->dflt = lydict_insert(ctx, rfn->dflt[0], 0);
4649
4650 /* check the default value */
Radek Krejci51673202016-11-01 17:00:32 +01004651 if (unres_schema_add_node(leaf->module, unres, &leaf->type, UNRES_TYPE_DFLT,
4652 (struct lys_node *)(&leaf->dflt)) == -1) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004653 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004654 }
Radek Krejci200bf712016-08-16 17:11:04 +02004655 } else if (node->nodetype == LYS_LEAFLIST) {
4656 /* leaf-list */
4657 llist = (struct lys_node_leaflist *)node;
4658
4659 /* remove complete set of defaults in target */
4660 for (i = 0; i < llist->dflt_size; i++) {
4661 lydict_remove(ctx, llist->dflt[i]);
4662 }
4663 free(llist->dflt);
4664
4665 /* copy the default set from refine */
4666 llist->dflt_size = rfn->dflt_size;
4667 llist->dflt = malloc(llist->dflt_size * sizeof *llist->dflt);
4668 for (i = 0; i < llist->dflt_size; i++) {
4669 llist->dflt[i] = lydict_insert(ctx, rfn->dflt[i], 0);
4670 }
4671
4672 /* check default value */
4673 for (i = 0; i < llist->dflt_size; i++) {
Radek Krejci51673202016-11-01 17:00:32 +01004674 if (unres_schema_add_node(llist->module, unres, &llist->type, UNRES_TYPE_DFLT,
4675 (struct lys_node *)(&llist->dflt[i])) == -1) {
Pavol Vican855ca622016-09-05 13:07:54 +02004676 goto fail;
Radek Krejci200bf712016-08-16 17:11:04 +02004677 }
4678 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004679 }
4680 }
4681
4682 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02004683 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004684 if (node->nodetype & (LYS_LEAF | LYS_ANYDATA | LYS_CHOICE)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004685 /* remove current value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004686 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004687
4688 /* set new value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004689 node->flags |= (rfn->flags & LYS_MAND_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004690 }
Pavol Vican855ca622016-09-05 13:07:54 +02004691 if (rfn->flags & LYS_MAND_TRUE) {
4692 /* check if node has default value */
4693 if ((node->nodetype & LYS_LEAF) && ((struct lys_node_leaf *)node)->dflt) {
4694 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"mandatory\" statement is forbidden on leaf with \"default\".");
4695 goto fail;
4696 }
4697 if ((node->nodetype & LYS_CHOICE) && ((struct lys_node_choice *)node)->dflt) {
4698 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"mandatory\" statement is forbidden on choices with \"default\".");
4699 goto fail;
4700 }
4701 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004702 }
4703
4704 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004705 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
4706 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
4707 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004708 }
4709
4710 /* min/max-elements on list or leaf-list */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004711 if (node->nodetype == LYS_LIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004712 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004713 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004714 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004715 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004716 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004717 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02004718 } else if (node->nodetype == LYS_LEAFLIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004719 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004720 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004721 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004722 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004723 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004724 }
4725 }
4726
4727 /* must in leaf, leaf-list, list, container or anyxml */
4728 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004729 switch (node->nodetype) {
4730 case LYS_LEAF:
4731 old_size = &((struct lys_node_leaf *)node)->must_size;
4732 old_must = &((struct lys_node_leaf *)node)->must;
4733 break;
4734 case LYS_LEAFLIST:
4735 old_size = &((struct lys_node_leaflist *)node)->must_size;
4736 old_must = &((struct lys_node_leaflist *)node)->must;
4737 break;
4738 case LYS_LIST:
4739 old_size = &((struct lys_node_list *)node)->must_size;
4740 old_must = &((struct lys_node_list *)node)->must;
4741 break;
4742 case LYS_CONTAINER:
4743 old_size = &((struct lys_node_container *)node)->must_size;
4744 old_must = &((struct lys_node_container *)node)->must;
4745 break;
4746 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02004747 case LYS_ANYDATA:
4748 old_size = &((struct lys_node_anydata *)node)->must_size;
4749 old_must = &((struct lys_node_anydata *)node)->must;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004750 break;
4751 default:
4752 LOGINT;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004753 goto fail;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004754 }
4755
4756 size = *old_size + rfn->must_size;
4757 must = realloc(*old_must, size * sizeof *rfn->must);
4758 if (!must) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004759 LOGMEM;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004760 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004761 }
Pavol Vican855ca622016-09-05 13:07:54 +02004762 for (k = 0, j = *old_size; k < rfn->must_size; k++, j++) {
4763 must[j].expr = lydict_insert(ctx, rfn->must[k].expr, 0);
4764 must[j].dsc = lydict_insert(ctx, rfn->must[k].dsc, 0);
4765 must[j].ref = lydict_insert(ctx, rfn->must[k].ref, 0);
4766 must[j].eapptag = lydict_insert(ctx, rfn->must[k].eapptag, 0);
4767 must[j].emsg = lydict_insert(ctx, rfn->must[k].emsg, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004768 }
4769
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004770 *old_must = must;
4771 *old_size = size;
Michal Vasko508a50d2016-09-07 14:50:33 +02004772
4773 /* check XPath dependencies again */
4774 if (unres_schema_add_node(node->module, unres, node, UNRES_XPATH, NULL) == -1) {
4775 goto fail;
4776 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004777 }
Radek Krejci363bd4a2016-07-29 14:30:20 +02004778
4779 /* if-feature in leaf, leaf-list, list, container or anyxml */
4780 if (rfn->iffeature_size) {
4781 old_size = &node->iffeature_size;
4782 old_iff = &node->iffeature;
4783
4784 size = *old_size + rfn->iffeature_size;
4785 iff = realloc(*old_iff, size * sizeof *rfn->iffeature);
4786 if (!iff) {
4787 LOGMEM;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004788 goto fail;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004789 }
Pavol Vican855ca622016-09-05 13:07:54 +02004790 for (k = 0, j = *old_size; k < rfn->iffeature_size; k++, j++) {
4791 resolve_iffeature_getsizes(&rfn->iffeature[k], &usize1, &usize2);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004792 if (usize1) {
4793 /* there is something to duplicate */
4794 /* duplicate compiled expression */
4795 usize = (usize1 / 4) + (usize1 % 4) ? 1 : 0;
4796 iff[j].expr = malloc(usize * sizeof *iff[j].expr);
Pavol Vican855ca622016-09-05 13:07:54 +02004797 memcpy(iff[j].expr, rfn->iffeature[k].expr, usize * sizeof *iff[j].expr);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004798
4799 /* duplicate list of feature pointers */
Pavol Vican855ca622016-09-05 13:07:54 +02004800 iff[j].features = malloc(usize2 * sizeof *iff[k].features);
4801 memcpy(iff[j].features, rfn->iffeature[k].features, usize2 * sizeof *iff[j].features);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004802 }
4803 }
4804
4805 *old_iff = iff;
4806 *old_size = size;
4807 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004808 }
4809
4810 /* apply augments */
4811 for (i = 0; i < uses->augment_size; i++) {
Radek Krejcib3142312016-11-09 11:04:12 +01004812 rc = resolve_augment(&uses->augment[i], uses->child, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004813 if (rc) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004814 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004815 }
4816 }
4817
Pavol Vican855ca622016-09-05 13:07:54 +02004818 /* check refines */
4819 for (i = 0; i < uses->refine_size; i++) {
4820 node = refine_nodes[i];
4821 rfn = &uses->refine[i];
4822
4823 /* config on any nodetype */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004824 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Pavol Vican855ca622016-09-05 13:07:54 +02004825 for (parent = lys_parent(node); parent && parent->nodetype == LYS_USES; parent = lys_parent(parent));
Radek Krejci5c08a992016-11-02 13:30:04 +01004826 if (parent && parent->nodetype != LYS_GROUPING && (parent->flags & LYS_CONFIG_MASK) &&
Pavol Vican855ca622016-09-05 13:07:54 +02004827 ((parent->flags & LYS_CONFIG_MASK) != (rfn->flags & LYS_CONFIG_MASK)) &&
4828 (rfn->flags & LYS_CONFIG_W)) {
4829 /* setting config true under config false is prohibited */
4830 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
4831 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4832 "changing config from 'false' to 'true' is prohibited while "
4833 "the target's parent is still config 'false'.");
4834 goto fail;
4835 }
4836
4837 /* inherit config change to the target children */
4838 LY_TREE_DFS_BEGIN(node->child, next, iter) {
4839 if (rfn->flags & LYS_CONFIG_W) {
4840 if (iter->flags & LYS_CONFIG_SET) {
4841 /* config is set explicitely, go to next sibling */
4842 next = NULL;
4843 goto nextsibling;
4844 }
4845 } else { /* LYS_CONFIG_R */
4846 if ((iter->flags & LYS_CONFIG_SET) && (iter->flags & LYS_CONFIG_W)) {
4847 /* error - we would have config data under status data */
4848 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
4849 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4850 "changing config from 'true' to 'false' is prohibited while the target "
4851 "has still a children with explicit config 'true'.");
4852 goto fail;
4853 }
4854 }
4855 /* change config */
4856 iter->flags &= ~LYS_CONFIG_MASK;
4857 iter->flags |= (rfn->flags & LYS_CONFIG_MASK);
4858
4859 /* select next iter - modified LY_TREE_DFS_END */
4860 if (iter->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
4861 next = NULL;
4862 } else {
4863 next = iter->child;
4864 }
4865nextsibling:
4866 if (!next) {
4867 /* try siblings */
4868 next = iter->next;
4869 }
4870 while (!next) {
4871 /* parent is already processed, go to its sibling */
4872 iter = lys_parent(iter);
4873
4874 /* no siblings, go back through parents */
4875 if (iter == node) {
4876 /* we are done, no next element to process */
4877 break;
4878 }
4879 next = iter->next;
4880 }
4881 }
4882 }
4883
4884 /* default value */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004885 if (rfn->dflt_size) {
4886 if (node->nodetype == LYS_CHOICE) {
4887 /* choice */
4888 ((struct lys_node_choice *)node)->dflt = resolve_choice_dflt((struct lys_node_choice *)node,
4889 rfn->dflt[0]);
4890 if (!((struct lys_node_choice *)node)->dflt) {
4891 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->dflt[0], "default");
4892 goto fail;
4893 }
4894 if (lyp_check_mandatory_choice(node)) {
4895 goto fail;
4896 }
Pavol Vican855ca622016-09-05 13:07:54 +02004897 }
4898 }
4899
4900 /* min/max-elements on list or leaf-list */
4901 if (node->nodetype == LYS_LIST) {
4902 if (((struct lys_node_list *)node)->min > ((struct lys_node_list *)node)->max) {
4903 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
4904 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "\"min-elements\" is bigger than \"max-elements\".");
4905 goto fail;
4906 }
4907 } else if (node->nodetype == LYS_LEAFLIST) {
4908 if (((struct lys_node_leaflist *)node)->min > ((struct lys_node_leaflist *)node)->max) {
4909 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
4910 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "\"min-elements\" is bigger than \"max-elements\".");
4911 goto fail;
4912 }
4913 }
4914
4915 /* additional checks */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004916 /* default value with mandatory/min-elements */
Pavol Vican855ca622016-09-05 13:07:54 +02004917 if (node->nodetype == LYS_LEAFLIST) {
4918 llist = (struct lys_node_leaflist *)node;
4919 if (llist->dflt_size && llist->min) {
4920 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, rfn->dflt_size ? "default" : "min-elements", "refine");
4921 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
4922 "The \"min-elements\" statement with non-zero value is forbidden on leaf-lists with the \"default\" statement.");
4923 goto fail;
4924 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004925 } else if (node->nodetype == LYS_LEAF) {
4926 leaf = (struct lys_node_leaf *)node;
4927 if (leaf->dflt && (leaf->flags & LYS_MAND_TRUE)) {
4928 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, rfn->dflt_size ? "default" : "mandatory", "refine");
4929 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
4930 "The \"mandatory\" statement is forbidden on leafs with the \"default\" statement.");
4931 goto fail;
4932 }
Pavol Vican855ca622016-09-05 13:07:54 +02004933 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004934
Pavol Vican855ca622016-09-05 13:07:54 +02004935 /* check for mandatory node in default case, first find the closest parent choice to the changed node */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004936 if ((rfn->flags & LYS_MAND_TRUE) || rfn->mod.list.min) {
Pavol Vican855ca622016-09-05 13:07:54 +02004937 for (parent = node->parent;
4938 parent && !(parent->nodetype & (LYS_CHOICE | LYS_GROUPING | LYS_ACTION | LYS_USES));
4939 parent = parent->parent) {
4940 if (parent->nodetype == LYS_CONTAINER && ((struct lys_node_container *)parent)->presence) {
4941 /* stop also on presence containers */
4942 break;
4943 }
4944 }
4945 /* and if it is a choice with the default case, check it for presence of a mandatory node in it */
4946 if (parent && parent->nodetype == LYS_CHOICE && ((struct lys_node_choice *)parent)->dflt) {
4947 if (lyp_check_mandatory_choice(parent)) {
4948 goto fail;
4949 }
4950 }
4951 }
4952 }
4953 free(refine_nodes);
4954
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004955 return EXIT_SUCCESS;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004956
4957fail:
4958 LY_TREE_FOR_SAFE(uses->child, next, iter) {
4959 lys_node_free(iter, NULL, 0);
4960 }
Pavol Vican855ca622016-09-05 13:07:54 +02004961 free(refine_nodes);
Michal Vaskoa86508c2016-08-26 14:30:19 +02004962 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004963}
4964
Radek Krejci018f1f52016-08-03 16:01:20 +02004965static int
4966identity_backlink_update(struct lys_ident *der, struct lys_ident *base)
4967{
4968 int i;
4969
4970 assert(der && base);
4971
Radek Krejci018f1f52016-08-03 16:01:20 +02004972 if (!base->der) {
Radek Krejci85a54be2016-10-20 12:39:56 +02004973 /* create a set for backlinks if it does not exist */
4974 base->der = ly_set_new();
Radek Krejci018f1f52016-08-03 16:01:20 +02004975 }
Radek Krejci85a54be2016-10-20 12:39:56 +02004976 /* store backlink */
4977 ly_set_add(base->der, der, LY_SET_OPT_USEASLIST);
Radek Krejci018f1f52016-08-03 16:01:20 +02004978
Radek Krejci85a54be2016-10-20 12:39:56 +02004979 /* do it recursively */
Radek Krejci018f1f52016-08-03 16:01:20 +02004980 for (i = 0; i < base->base_size; i++) {
4981 if (identity_backlink_update(der, base->base[i])) {
4982 return EXIT_FAILURE;
4983 }
4984 }
4985
4986 return EXIT_SUCCESS;
4987}
4988
Michal Vasko730dfdf2015-08-11 14:48:05 +02004989/**
4990 * @brief Resolve base identity recursively. Does not log.
4991 *
4992 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004993 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004994 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004995 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004996 *
Radek Krejci219fa612016-08-15 10:36:51 +02004997 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on crucial error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004998 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004999static int
Michal Vasko1e62a092015-12-01 12:27:20 +01005000resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Radek Krejci018f1f52016-08-03 16:01:20 +02005001 struct unres_schema *unres, struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005002{
Michal Vaskof02e3742015-08-05 16:27:02 +02005003 uint32_t i, j;
Radek Krejci018f1f52016-08-03 16:01:20 +02005004 struct lys_ident *base = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005005
Radek Krejcicf509982015-12-15 09:22:44 +01005006 assert(ret);
5007
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005008 /* search module */
5009 for (i = 0; i < module->ident_size; i++) {
5010 if (!strcmp(basename, module->ident[i].name)) {
5011
5012 if (!ident) {
5013 /* just search for type, so do not modify anything, just return
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005014 * the base identity pointer */
Radek Krejcicf509982015-12-15 09:22:44 +01005015 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005016 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005017 }
5018
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005019 base = &module->ident[i];
5020 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005021 }
5022 }
5023
5024 /* search submodules */
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005025 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
5026 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
5027 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005028
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005029 if (!ident) {
5030 *ret = &module->inc[j].submodule->ident[i];
5031 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005032 }
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005033
5034 base = &module->inc[j].submodule->ident[i];
5035 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005036 }
5037 }
5038 }
5039
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005040matchfound:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005041 /* we found it somewhere */
Radek Krejcibabbff82016-02-19 13:31:37 +01005042 if (base) {
Radek Krejci018f1f52016-08-03 16:01:20 +02005043 /* is it already completely resolved? */
5044 for (i = 0; i < unres->count; i++) {
Radek Krejciba7b1cc2016-08-08 13:44:43 +02005045 if ((unres->item[i] == base) && (unres->type[i] == UNRES_IDENT)) {
Radek Krejci018f1f52016-08-03 16:01:20 +02005046 /* identity found, but not yet resolved, so do not return it in *res and try it again later */
5047
5048 /* simple check for circular reference,
5049 * the complete check is done as a side effect of using only completely
5050 * resolved identities (previous check of unres content) */
5051 if (ly_strequal((const char *)unres->str_snode[i], ident->name, 1)) {
5052 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, basename, "base");
5053 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Circular reference of \"%s\" identity.", basename);
Radek Krejci219fa612016-08-15 10:36:51 +02005054 return -1;
Radek Krejci018f1f52016-08-03 16:01:20 +02005055 }
5056
Radek Krejci06f64ed2016-08-15 11:07:44 +02005057 return EXIT_FAILURE;
Radek Krejcibabbff82016-02-19 13:31:37 +01005058 }
5059 }
Radek Krejci018f1f52016-08-03 16:01:20 +02005060
Radek Krejcibabbff82016-02-19 13:31:37 +01005061 /* checks done, store the result */
Radek Krejci018f1f52016-08-03 16:01:20 +02005062 *ret = base;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02005063 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005064 }
5065
Radek Krejci219fa612016-08-15 10:36:51 +02005066 /* base not found (maybe a forward reference) */
5067 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005068}
5069
Michal Vasko730dfdf2015-08-11 14:48:05 +02005070/**
5071 * @brief Resolve base identity. Logs directly.
5072 *
5073 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02005074 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005075 * @param[in] basename Base name of the identity.
Radek Krejcibabbff82016-02-19 13:31:37 +01005076 * @param[in] parent Either "type" or "identity".
Radek Krejcicf509982015-12-15 09:22:44 +01005077 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005078 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005079 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005080 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005081static int
Michal Vaskof2d43962016-09-02 11:10:16 +02005082resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char *parent,
Radek Krejci018f1f52016-08-03 16:01:20 +02005083 struct lys_type *type, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005084{
5085 const char *name;
Radek Krejci219fa612016-08-15 10:36:51 +02005086 int mod_name_len = 0, rc;
Radek Krejcicf509982015-12-15 09:22:44 +01005087 struct lys_ident *target, **ret;
Radek Krejci4372b4e2016-04-14 17:42:16 +02005088 uint16_t flags;
Radek Krejcicf509982015-12-15 09:22:44 +01005089 struct lys_module *mod;
5090
5091 assert((ident && !type) || (!ident && type));
5092
5093 if (!type) {
5094 /* have ident to resolve */
5095 ret = &target;
5096 flags = ident->flags;
5097 mod = ident->module;
5098 } else {
5099 /* have type to fill */
Michal Vaskof2d43962016-09-02 11:10:16 +02005100 ++type->info.ident.count;
5101 type->info.ident.ref = ly_realloc(type->info.ident.ref, type->info.ident.count * sizeof *type->info.ident.ref);
5102 if (!type->info.ident.ref) {
5103 LOGMEM;
5104 return -1;
5105 }
5106
5107 ret = &type->info.ident.ref[type->info.ident.count - 1];
Radek Krejcicf509982015-12-15 09:22:44 +01005108 flags = type->parent->flags;
5109 mod = type->parent->module;
5110 }
Michal Vaskof2006002016-04-21 16:28:15 +02005111 *ret = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005112
5113 /* search for the base identity */
5114 name = strchr(basename, ':');
5115 if (name) {
5116 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02005117 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005118 name++;
5119
Michal Vasko2d851a92015-10-20 16:16:36 +02005120 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005121 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02005122 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005123 }
5124 } else {
5125 name = basename;
5126 }
5127
Radek Krejcic071c542016-01-27 14:57:51 +01005128 /* get module where to search */
5129 module = lys_get_import_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len);
5130 if (!module) {
5131 /* identity refers unknown data model */
Radek Krejci02a04992016-03-17 16:06:37 +01005132 LOGVAL(LYE_INMOD, LY_VLOG_NONE, NULL, basename);
Radek Krejcic071c542016-01-27 14:57:51 +01005133 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005134 }
5135
Radek Krejcic071c542016-01-27 14:57:51 +01005136 /* search in the identified module ... */
Radek Krejci219fa612016-08-15 10:36:51 +02005137 rc = resolve_base_ident_sub(module, ident, name, unres, ret);
5138 if (!rc) {
5139 assert(*ret);
5140
5141 /* check status */
5142 if (lyp_check_status(flags, mod, ident ? ident->name : "of type",
5143 (*ret)->flags, (*ret)->module, (*ret)->name, NULL)) {
5144 rc = -1;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02005145 } else {
5146 if (ident) {
5147 ident->base[ident->base_size++] = *ret;
5148
5149 /* maintain backlinks to the derived identities */
5150 rc = identity_backlink_update(ident, *ret) ? -1 : EXIT_SUCCESS;
5151 }
Radek Krejci219fa612016-08-15 10:36:51 +02005152 }
5153 } else if (rc == EXIT_FAILURE) {
5154 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, parent, basename);
Pavol Vican053a2882016-09-05 14:40:33 +02005155 if (type) {
5156 --type->info.ident.count;
5157 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005158 }
5159
Radek Krejci219fa612016-08-15 10:36:51 +02005160 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005161}
5162
Michal Vasko730dfdf2015-08-11 14:48:05 +02005163/**
Michal Vaskof39142b2015-10-21 11:40:05 +02005164 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005165 *
Michal Vaskof2d43962016-09-02 11:10:16 +02005166 * @param[in] type Identityref type.
Michal Vaskofb0873c2015-08-21 09:00:07 +02005167 * @param[in] ident_name Identityref name.
Radek Krejciadb57612016-02-16 13:34:34 +01005168 * @param[in] node Node where the identityref is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02005169 *
5170 * @return Pointer to the identity resolvent, NULL on error.
5171 */
Radek Krejcia52656e2015-08-05 13:41:50 +02005172struct lys_ident *
Michal Vaskof2d43962016-09-02 11:10:16 +02005173resolve_identref(struct lys_type *type, const char *ident_name, struct lyd_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005174{
Radek Krejci639491e2016-12-05 13:30:42 +01005175 const char *mod_name, *name, *mod_name_iter;
Radek Krejci85a54be2016-10-20 12:39:56 +02005176 int mod_name_len, rc, i;
5177 unsigned int u;
Michal Vaskof2d43962016-09-02 11:10:16 +02005178 struct lys_ident *der, *cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005179
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005180 assert(type && ident_name && node);
5181
Michal Vaskof2d43962016-09-02 11:10:16 +02005182 if (!type || (!type->info.ident.count && !type->der) || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005183 return NULL;
5184 }
5185
Michal Vaskoc633ca02015-08-21 14:03:51 +02005186 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, NULL);
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005187 if (rc < 1) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005188 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005189 return NULL;
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005190 } else if (rc < (signed)strlen(ident_name)) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005191 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[rc], &ident_name[rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005192 return NULL;
5193 }
Radek Krejcif32c5f62016-12-05 09:27:38 +01005194 if (!mod_name) {
5195 /* no prefix, identity must be defined in the same module as node */
Radek Krejci639491e2016-12-05 13:30:42 +01005196 mod_name = lys_main_module(node->schema->module)->name;
Radek Krejcif32c5f62016-12-05 09:27:38 +01005197 mod_name_len = strlen(mod_name);
5198 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02005199
Michal Vaskof2d43962016-09-02 11:10:16 +02005200 /* go through all the bases in all the derived types */
5201 while (type->der) {
5202 for (i = 0; i < type->info.ident.count; ++i) {
5203 cur = type->info.ident.ref[i];
Radek Krejci639491e2016-12-05 13:30:42 +01005204 mod_name_iter = lys_main_module(cur->module)->name;
Radek Krejcif32c5f62016-12-05 09:27:38 +01005205 if (!strcmp(cur->name, name) &&
Radek Krejci639491e2016-12-05 13:30:42 +01005206 !strncmp(mod_name_iter, mod_name, mod_name_len) && !mod_name_iter[mod_name_len]) {
Michal Vaskof2d43962016-09-02 11:10:16 +02005207 goto match;
5208 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02005209
Radek Krejci85a54be2016-10-20 12:39:56 +02005210 if (cur->der) {
5211 /* there are also some derived identities */
5212 for (u = 0; u < cur->der->number; u++) {
5213 der = (struct lys_ident *)cur->der->set.g[u]; /* shortcut */
Radek Krejci639491e2016-12-05 13:30:42 +01005214 mod_name_iter = lys_main_module(der->module)->name;
Radek Krejci85a54be2016-10-20 12:39:56 +02005215 if (!strcmp(der->name, name) &&
Radek Krejci639491e2016-12-05 13:30:42 +01005216 !strncmp(mod_name_iter, mod_name, mod_name_len) && !mod_name_iter[mod_name_len]) {
Radek Krejci85a54be2016-10-20 12:39:56 +02005217 /* we have match */
5218 cur = der;
5219 goto match;
5220 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005221 }
5222 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005223 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005224 type = &type->der->type;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005225 }
5226
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005227 LOGVAL(LYE_INRESOLV, LY_VLOG_LYD, node, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005228 return NULL;
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005229
5230match:
Michal Vaskof2d43962016-09-02 11:10:16 +02005231 for (i = 0; i < cur->iffeature_size; i++) {
5232 if (!resolve_iffeature(&cur->iffeature[i])) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005233 LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, cur->name, node->schema->name);
5234 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, "Identity \"%s\" is disabled by its if-feature condition.", cur->name);
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005235 return NULL;
5236 }
5237 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005238 return cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005239}
5240
Michal Vasko730dfdf2015-08-11 14:48:05 +02005241/**
Michal Vaskobb211122015-08-19 14:03:11 +02005242 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005243 *
Michal Vaskobb211122015-08-19 14:03:11 +02005244 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005245 * @param[in] unres Specific unres item.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005246 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005247 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005248 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005249static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005250resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005251{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005252 int rc;
Radek Krejci010e54b2016-03-15 09:40:34 +01005253 struct lys_node *par_grp;
Michal Vaskoe91afce2015-08-12 12:21:00 +02005254
Radek Krejci010e54b2016-03-15 09:40:34 +01005255 /* HACK: when a grouping has uses inside, all such uses have to be resolved before the grouping itself
5256 * is used in some uses. When we see such a uses, the grouping's nacm member (not used in grouping)
5257 * is used to store number of so far unresolved uses. The grouping cannot be used unless the nacm
5258 * value is decreased back to 0. To remember that the uses already increased grouping's nacm, the
5259 * LYS_USESGRP flag is used. */
Michal Vaskodcf98e62016-05-05 17:53:53 +02005260 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 +02005261
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005262 if (!uses->grp) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01005263 rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
5264 if (rc == -1) {
Michal Vasko92981a62016-10-14 10:25:16 +02005265 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005266 return -1;
5267 } else if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005268 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005269 return -1;
5270 } else if (!uses->grp) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005271 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005272 /* hack - in contrast to lys_node, lys_node_grp has bigger nacm field
5273 * (and smaller flags - it uses only a limited set of flags)
5274 */
5275 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci010e54b2016-03-15 09:40:34 +01005276 uses->flags |= LYS_USESGRP;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005277 }
Michal Vasko92981a62016-10-14 10:25:16 +02005278 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005279 return EXIT_FAILURE;
Michal Vasko12e30842015-08-04 11:54:00 +02005280 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005281 }
5282
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005283 if (uses->grp->nacm) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005284 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005285 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci010e54b2016-03-15 09:40:34 +01005286 uses->flags |= LYS_USESGRP;
Radek Krejcie00d2312016-08-12 15:27:49 +02005287 } else {
5288 /* instantiate grouping only when it is completely resolved */
5289 uses->grp = NULL;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005290 }
Michal Vasko92981a62016-10-14 10:25:16 +02005291 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005292 return EXIT_FAILURE;
5293 }
5294
Radek Krejci48464ed2016-03-17 15:44:09 +01005295 rc = resolve_uses(uses, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005296 if (!rc) {
5297 /* decrease unres count only if not first try */
Radek Krejci010e54b2016-03-15 09:40:34 +01005298 if (par_grp && (uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005299 if (!((struct lys_node_grp *)par_grp)->nacm) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005300 LOGINT;
5301 return -1;
5302 }
Radek Krejci4372b4e2016-04-14 17:42:16 +02005303 ((struct lys_node_grp *)par_grp)->nacm--;
Radek Krejci010e54b2016-03-15 09:40:34 +01005304 uses->flags &= ~LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005305 }
Radek Krejcicf509982015-12-15 09:22:44 +01005306
5307 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005308 if (lyp_check_status(uses->flags, uses->module, "of uses",
Radek Krejciadb57612016-02-16 13:34:34 +01005309 uses->grp->flags, uses->grp->module, uses->grp->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005310 (struct lys_node *)uses)) {
Radek Krejcicf509982015-12-15 09:22:44 +01005311 return -1;
5312 }
5313
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005314 return EXIT_SUCCESS;
5315 }
5316
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005317 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005318}
5319
Michal Vasko730dfdf2015-08-11 14:48:05 +02005320/**
Michal Vasko9957e592015-08-17 15:04:09 +02005321 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005322 *
Michal Vaskobb211122015-08-19 14:03:11 +02005323 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005324 * @param[in] keys_str Keys node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005325 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005326 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005327 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005328static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005329resolve_list_keys(struct lys_node_list *list, const char *keys_str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005330{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005331 int i, len, rc;
Michal Vasko4f0dad02016-02-15 14:08:23 +01005332 const char *value;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005333
5334 for (i = 0; i < list->keys_size; ++i) {
Radek Krejci5c08a992016-11-02 13:30:04 +01005335 if (!list->child) {
5336 /* no child, possible forward reference */
5337 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
5338 return EXIT_FAILURE;
5339 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005340 /* get the key name */
5341 if ((value = strpbrk(keys_str, " \t\n"))) {
5342 len = value - keys_str;
5343 while (isspace(value[0])) {
5344 value++;
5345 }
5346 } else {
5347 len = strlen(keys_str);
5348 }
5349
Radek Krejcic4283442016-04-22 09:19:27 +02005350 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 +02005351 if (rc) {
Michal Vasko7a55bea2016-05-02 14:51:20 +02005352 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
5353 return EXIT_FAILURE;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005354 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005355
Radek Krejci48464ed2016-03-17 15:44:09 +01005356 if (check_key(list, i, keys_str, len)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005357 /* check_key logs */
5358 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005359 }
5360
Radek Krejcicf509982015-12-15 09:22:44 +01005361 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005362 if (lyp_check_status(list->flags, list->module, list->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005363 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
5364 (struct lys_node *)list->keys[i])) {
Radek Krejcicf509982015-12-15 09:22:44 +01005365 return -1;
5366 }
5367
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005368 /* prepare for next iteration */
5369 while (value && isspace(value[0])) {
5370 value++;
5371 }
5372 keys_str = value;
5373 }
5374
Michal Vaskof02e3742015-08-05 16:27:02 +02005375 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005376}
5377
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005378/**
Michal Vaskobf19d252015-10-08 15:39:17 +02005379 * @brief Resolve (check) all must conditions of \p node.
5380 * Logs directly.
5381 *
5382 * @param[in] node Data node with optional must statements.
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005383 * @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 +02005384 *
5385 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
5386 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005387static int
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005388resolve_must(struct lyd_node *node, int inout_parent)
Michal Vaskof02e3742015-08-05 16:27:02 +02005389{
Michal Vaskobf19d252015-10-08 15:39:17 +02005390 uint8_t i, must_size;
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005391 struct lys_node *schema;
Michal Vaskobf19d252015-10-08 15:39:17 +02005392 struct lys_restr *must;
5393 struct lyxp_set set;
5394
5395 assert(node);
5396 memset(&set, 0, sizeof set);
5397
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005398 if (inout_parent) {
5399 for (schema = lys_parent(node->schema);
5400 schema && (schema->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES));
5401 schema = lys_parent(schema));
5402 if (!schema || !(schema->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5403 LOGINT;
5404 return -1;
5405 }
5406 must_size = ((struct lys_node_inout *)schema)->must_size;
5407 must = ((struct lys_node_inout *)schema)->must;
5408
5409 /* context node is the RPC/action */
5410 node = node->parent;
5411 if (!(node->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
5412 LOGINT;
5413 return -1;
5414 }
5415 } else {
5416 switch (node->schema->nodetype) {
5417 case LYS_CONTAINER:
5418 must_size = ((struct lys_node_container *)node->schema)->must_size;
5419 must = ((struct lys_node_container *)node->schema)->must;
5420 break;
5421 case LYS_LEAF:
5422 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
5423 must = ((struct lys_node_leaf *)node->schema)->must;
5424 break;
5425 case LYS_LEAFLIST:
5426 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
5427 must = ((struct lys_node_leaflist *)node->schema)->must;
5428 break;
5429 case LYS_LIST:
5430 must_size = ((struct lys_node_list *)node->schema)->must_size;
5431 must = ((struct lys_node_list *)node->schema)->must;
5432 break;
5433 case LYS_ANYXML:
5434 case LYS_ANYDATA:
5435 must_size = ((struct lys_node_anydata *)node->schema)->must_size;
5436 must = ((struct lys_node_anydata *)node->schema)->must;
5437 break;
5438 case LYS_NOTIF:
5439 must_size = ((struct lys_node_notif *)node->schema)->must_size;
5440 must = ((struct lys_node_notif *)node->schema)->must;
5441 break;
5442 default:
5443 must_size = 0;
5444 break;
5445 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005446 }
5447
5448 for (i = 0; i < must_size; ++i) {
Michal Vaskoa59495d2016-08-22 09:18:58 +02005449 if (lyxp_eval(must[i].expr, node, LYXP_NODE_ELEM, &set, LYXP_MUST)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02005450 return -1;
5451 }
5452
Michal Vasko944a5642016-03-21 11:48:58 +01005453 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, LYXP_MUST);
Michal Vaskobf19d252015-10-08 15:39:17 +02005454
Michal Vasko8146d4c2016-05-09 15:50:29 +02005455 if (!set.val.bool) {
Michal Vasko6ac68282016-04-11 10:56:47 +02005456 LOGVAL(LYE_NOMUST, LY_VLOG_LYD, node, must[i].expr);
5457 if (must[i].emsg) {
5458 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, must[i].emsg);
5459 }
5460 if (must[i].eapptag) {
5461 strncpy(((struct ly_err *)&ly_errno)->apptag, must[i].eapptag, LY_APPTAG_LEN - 1);
5462 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005463 return 1;
5464 }
5465 }
5466
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005467 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02005468}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005469
Michal Vaskobf19d252015-10-08 15:39:17 +02005470/**
Michal Vasko508a50d2016-09-07 14:50:33 +02005471 * @brief Resolve (find) when condition schema context node. Does not log.
5472 *
5473 * @param[in] schema Schema node with the when condition.
5474 * @param[out] ctx_snode When schema context node.
5475 * @param[out] ctx_snode_type Schema context node type.
5476 */
5477void
5478resolve_when_ctx_snode(const struct lys_node *schema, struct lys_node **ctx_snode, enum lyxp_node_type *ctx_snode_type)
5479{
5480 const struct lys_node *sparent;
5481
5482 /* find a not schema-only node */
5483 *ctx_snode_type = LYXP_NODE_ELEM;
5484 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
5485 if (schema->nodetype == LYS_AUGMENT) {
5486 sparent = ((struct lys_node_augment *)schema)->target;
5487 } else {
5488 sparent = schema->parent;
5489 }
5490 if (!sparent) {
5491 /* context node is the document root (fake root in our case) */
5492 if (schema->flags & LYS_CONFIG_W) {
5493 *ctx_snode_type = LYXP_NODE_ROOT_CONFIG;
5494 } else {
Michal Vaskob94a5e42016-09-08 14:01:56 +02005495 *ctx_snode_type = LYXP_NODE_ROOT;
Michal Vasko508a50d2016-09-07 14:50:33 +02005496 }
Michal Vasko2d2aec12016-09-08 11:42:50 +02005497 /* we need the first top-level sibling, but no uses or groupings */
Michal Vaskob94a5e42016-09-08 14:01:56 +02005498 schema = lys_getnext(NULL, NULL, lys_node_module(schema), 0);
Michal Vasko508a50d2016-09-07 14:50:33 +02005499 break;
5500 }
5501 schema = sparent;
5502 }
5503
5504 *ctx_snode = (struct lys_node *)schema;
5505}
5506
5507/**
Michal Vaskocf024702015-10-08 15:01:42 +02005508 * @brief Resolve (find) when condition context node. Does not log.
5509 *
5510 * @param[in] node Data node, whose conditional definition is being decided.
Michal Vasko508a50d2016-09-07 14:50:33 +02005511 * @param[in] schema Schema node with the when condition.
Michal Vaskoa59495d2016-08-22 09:18:58 +02005512 * @param[out] ctx_node Context node.
5513 * @param[out] ctx_node_type Context node type.
Michal Vaskocf024702015-10-08 15:01:42 +02005514 *
Michal Vaskoa59495d2016-08-22 09:18:58 +02005515 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vaskocf024702015-10-08 15:01:42 +02005516 */
Michal Vaskoa59495d2016-08-22 09:18:58 +02005517static int
5518resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema, struct lyd_node **ctx_node,
5519 enum lyxp_node_type *ctx_node_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005520{
Michal Vaskocf024702015-10-08 15:01:42 +02005521 struct lyd_node *parent;
5522 struct lys_node *sparent;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005523 enum lyxp_node_type node_type;
Michal Vaskocf024702015-10-08 15:01:42 +02005524 uint16_t i, data_depth, schema_depth;
5525
Michal Vasko508a50d2016-09-07 14:50:33 +02005526 resolve_when_ctx_snode(schema, &schema, &node_type);
Michal Vaskocf024702015-10-08 15:01:42 +02005527
Michal Vaskofe989752016-09-08 08:47:26 +02005528 if (node_type == LYXP_NODE_ELEM) {
5529 /* standard element context node */
5530 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
5531 for (sparent = schema, schema_depth = 0;
5532 sparent;
5533 sparent = (sparent->nodetype == LYS_AUGMENT ? ((struct lys_node_augment *)sparent)->target : sparent->parent)) {
5534 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_NOTIF | LYS_RPC)) {
5535 ++schema_depth;
5536 }
Michal Vaskocf024702015-10-08 15:01:42 +02005537 }
Michal Vaskofe989752016-09-08 08:47:26 +02005538 if (data_depth < schema_depth) {
5539 return -1;
5540 }
Michal Vaskocf024702015-10-08 15:01:42 +02005541
Michal Vasko956e8542016-08-26 09:43:35 +02005542 /* find the corresponding data node */
5543 for (i = 0; i < data_depth - schema_depth; ++i) {
5544 node = node->parent;
5545 }
Michal Vaskoa59495d2016-08-22 09:18:58 +02005546 if (node->schema != schema) {
5547 return -1;
5548 }
Michal Vaskofe989752016-09-08 08:47:26 +02005549 } else {
5550 /* root context node */
5551 while (node->parent) {
5552 node = node->parent;
5553 }
5554 while (node->prev->next) {
5555 node = node->prev;
5556 }
Michal Vaskocf024702015-10-08 15:01:42 +02005557 }
5558
Michal Vaskoa59495d2016-08-22 09:18:58 +02005559 *ctx_node = node;
5560 *ctx_node_type = node_type;
5561 return EXIT_SUCCESS;
Michal Vaskocf024702015-10-08 15:01:42 +02005562}
5563
Michal Vasko76c3bd32016-08-24 16:02:52 +02005564/**
5565 * @brief Temporarily unlink nodes as per YANG 1.1 RFC section 7.21.5 for when XPath evaluation.
5566 * The context nodes is adjusted if needed.
5567 *
5568 * @param[in] snode Schema node, whose children instances need to be unlinked.
5569 * @param[in,out] node Data siblings where to look for the children of \p snode. If it is unlinked,
5570 * it is moved to point to another sibling still in the original tree.
5571 * @param[in,out] ctx_node When context node, adjusted if needed.
5572 * @param[in] ctx_node_type Context node type, just for information to detect invalid situations.
5573 * @param[out] unlinked_nodes Unlinked siblings. Can be safely appended to \p node afterwards.
5574 * Ordering may change, but there will be no semantic change.
5575 *
5576 * @return EXIT_SUCCESS on success, -1 on error.
5577 */
5578static int
5579resolve_when_unlink_nodes(struct lys_node *snode, struct lyd_node **node, struct lyd_node **ctx_node,
5580 enum lyxp_node_type ctx_node_type, struct lyd_node **unlinked_nodes)
5581{
5582 struct lyd_node *next, *elem;
5583
5584 switch (snode->nodetype) {
5585 case LYS_AUGMENT:
5586 case LYS_USES:
5587 case LYS_CHOICE:
5588 case LYS_CASE:
5589 LY_TREE_FOR(snode->child, snode) {
5590 if (resolve_when_unlink_nodes(snode, node, ctx_node, ctx_node_type, unlinked_nodes)) {
5591 return -1;
5592 }
5593 }
5594 break;
5595 case LYS_CONTAINER:
5596 case LYS_LIST:
5597 case LYS_LEAF:
5598 case LYS_LEAFLIST:
5599 case LYS_ANYXML:
5600 case LYS_ANYDATA:
5601 LY_TREE_FOR_SAFE(lyd_first_sibling(*node), next, elem) {
5602 if (elem->schema == snode) {
5603
5604 if (elem == *ctx_node) {
5605 /* We are going to unlink our context node! This normally cannot happen,
5606 * but we use normal top-level data nodes for faking a document root node,
5607 * so if this is the context node, we just use the next top-level node.
5608 * Additionally, it can even happen that there are no top-level data nodes left,
5609 * all were unlinked, so in this case we pass NULL as the context node/data tree,
5610 * lyxp_eval() can handle this special situation.
5611 */
5612 if (ctx_node_type == LYXP_NODE_ELEM) {
5613 LOGINT;
5614 return -1;
5615 }
5616
5617 if (elem->prev == elem) {
5618 /* unlinking last top-level element, use an empty data tree */
5619 *ctx_node = NULL;
5620 } else {
5621 /* in this case just use the previous/last top-level data node */
5622 *ctx_node = elem->prev;
5623 }
5624 } else if (elem == *node) {
5625 /* We are going to unlink the currently processed node. This does not matter that
5626 * much, but we would lose access to the original data tree, so just move our
5627 * pointer somewhere still inside it.
5628 */
5629 if ((*node)->prev != *node) {
5630 *node = (*node)->prev;
5631 } else {
5632 /* the processed node with sibings were all unlinked, oh well */
5633 *node = NULL;
5634 }
5635 }
5636
5637 /* temporarily unlink the node */
5638 lyd_unlink(elem);
5639 if (*unlinked_nodes) {
5640 if (lyd_insert_after(*unlinked_nodes, elem)) {
5641 LOGINT;
5642 return -1;
5643 }
5644 } else {
5645 *unlinked_nodes = elem;
5646 }
5647
5648 if (snode->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_ANYDATA)) {
5649 /* there can be only one instance */
5650 break;
5651 }
5652 }
5653 }
5654 break;
5655 default:
5656 LOGINT;
5657 return -1;
5658 }
5659
5660 return EXIT_SUCCESS;
5661}
5662
5663/**
5664 * @brief Relink the unlinked nodes back.
5665 *
5666 * @param[in] node Data node to link the nodes back to. It can actually be the adjusted context node,
5667 * we simply need a sibling from the original data tree.
5668 * @param[in] unlinked_nodes Unlinked nodes to relink to \p node.
5669 * @param[in] ctx_node_type Context node type to distinguish between \p node being the parent
5670 * or the sibling of \p unlinked_nodes.
5671 *
5672 * @return EXIT_SUCCESS on success, -1 on error.
5673 */
5674static int
5675resolve_when_relink_nodes(struct lyd_node *node, struct lyd_node *unlinked_nodes, enum lyxp_node_type ctx_node_type)
5676{
5677 struct lyd_node *elem;
5678
5679 LY_TREE_FOR_SAFE(unlinked_nodes, unlinked_nodes, elem) {
Michal Vaskode1feeb2016-12-20 14:48:42 +01005680 lyd_unlink(elem);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005681 if (ctx_node_type == LYXP_NODE_ELEM) {
5682 if (lyd_insert(node, elem)) {
5683 return -1;
5684 }
5685 } else {
5686 if (lyd_insert_after(node, elem)) {
5687 return -1;
5688 }
5689 }
5690 }
5691
5692 return EXIT_SUCCESS;
5693}
5694
Radek Krejci03b71f72016-03-16 11:10:09 +01005695int
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005696resolve_applies_must(const struct lyd_node *node)
Radek Krejci01696bf2016-03-18 13:19:36 +01005697{
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005698 int ret = 0;
5699 uint8_t must_size;
5700 struct lys_node *schema, *iter;
Radek Krejci46165822016-08-26 14:06:27 +02005701
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005702 assert(node);
5703
5704 schema = node->schema;
5705
5706 /* their own must */
Radek Krejci46165822016-08-26 14:06:27 +02005707 switch (schema->nodetype) {
Radek Krejci01696bf2016-03-18 13:19:36 +01005708 case LYS_CONTAINER:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005709 must_size = ((struct lys_node_container *)schema)->must_size;
5710 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005711 case LYS_LEAF:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005712 must_size = ((struct lys_node_leaf *)schema)->must_size;
5713 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005714 case LYS_LEAFLIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005715 must_size = ((struct lys_node_leaflist *)schema)->must_size;
5716 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005717 case LYS_LIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005718 must_size = ((struct lys_node_list *)schema)->must_size;
5719 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005720 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02005721 case LYS_ANYDATA:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005722 must_size = ((struct lys_node_anydata *)schema)->must_size;
5723 break;
5724 case LYS_NOTIF:
5725 must_size = ((struct lys_node_notif *)schema)->must_size;
5726 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005727 default:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005728 must_size = 0;
5729 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005730 }
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005731
5732 if (must_size) {
5733 ++ret;
5734 }
5735
5736 /* schema may be a direct data child of input/output with must (but it must be first, it needs to be evaluated only once) */
5737 if (!node->prev->next) {
5738 for (iter = lys_parent(schema); iter && (iter->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES)); iter = lys_parent(iter));
5739 if (iter && (iter->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5740 ret += 0x2;
5741 }
5742 }
5743
5744 return ret;
Radek Krejci01696bf2016-03-18 13:19:36 +01005745}
5746
5747int
Radek Krejci46165822016-08-26 14:06:27 +02005748resolve_applies_when(const struct lys_node *schema, int mode, const struct lys_node *stop)
Radek Krejci03b71f72016-03-16 11:10:09 +01005749{
Radek Krejci46165822016-08-26 14:06:27 +02005750 const struct lys_node *parent;
Radek Krejci03b71f72016-03-16 11:10:09 +01005751
Radek Krejci46165822016-08-26 14:06:27 +02005752 assert(schema);
Radek Krejci03b71f72016-03-16 11:10:09 +01005753
Radek Krejci46165822016-08-26 14:06:27 +02005754 if (!(schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)schema)->when)) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005755 return 1;
5756 }
5757
Radek Krejci46165822016-08-26 14:06:27 +02005758 parent = schema;
Radek Krejci03b71f72016-03-16 11:10:09 +01005759 goto check_augment;
5760
Radek Krejci46165822016-08-26 14:06:27 +02005761 while (parent) {
5762 /* stop conditions */
5763 if (!mode) {
5764 /* stop on node that can be instantiated in data tree */
5765 if (!(parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
5766 break;
5767 }
5768 } else {
5769 /* stop on the specified node */
5770 if (parent == stop) {
5771 break;
5772 }
5773 }
5774
5775 if (((const struct lys_node_uses *)parent)->when) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005776 return 1;
5777 }
5778check_augment:
5779
5780 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) &&
Radek Krejci46165822016-08-26 14:06:27 +02005781 (((const struct lys_node_augment *)parent->parent)->when))) {
Michal Vaskoe3655562016-08-24 15:56:17 +02005782 return 1;
Radek Krejci03b71f72016-03-16 11:10:09 +01005783 }
5784 parent = lys_parent(parent);
5785 }
5786
5787 return 0;
5788}
5789
Michal Vaskocf024702015-10-08 15:01:42 +02005790/**
5791 * @brief Resolve (check) all when conditions relevant for \p node.
5792 * Logs directly.
5793 *
5794 * @param[in] node Data node, whose conditional reference, if such, is being decided.
Michal Vaskocf024702015-10-08 15:01:42 +02005795 *
Radek Krejci03b71f72016-03-16 11:10:09 +01005796 * @return
5797 * -1 - error, ly_errno is set
5798 * 0 - true "when" statement
Radek Krejci46165822016-08-26 14:06:27 +02005799 * 0, ly_vecode = LYVE_NOWHEN - false "when" statement
Radek Krejci03b71f72016-03-16 11:10:09 +01005800 * 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 +02005801 */
Radek Krejci46165822016-08-26 14:06:27 +02005802int
5803resolve_when(struct lyd_node *node, int *result)
Michal Vaskocf024702015-10-08 15:01:42 +02005804{
Michal Vasko76c3bd32016-08-24 16:02:52 +02005805 struct lyd_node *ctx_node = NULL, *unlinked_nodes, *tmp_node;
Michal Vasko90fc2a32016-08-24 15:58:58 +02005806 struct lys_node *sparent;
Michal Vaskocf024702015-10-08 15:01:42 +02005807 struct lyxp_set set;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005808 enum lyxp_node_type ctx_node_type;
Radek Krejci51093642016-03-29 10:14:59 +02005809 int rc = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02005810
5811 assert(node);
5812 memset(&set, 0, sizeof set);
5813
5814 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)node->schema)->when)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005815 /* make the node dummy for the evaluation */
5816 node->validity |= LYD_VAL_INUSE;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005817 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 +02005818 node->validity &= ~LYD_VAL_INUSE;
Radek Krejci03b71f72016-03-16 11:10:09 +01005819 if (rc) {
5820 if (rc == 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005821 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005822 }
Radek Krejci51093642016-03-29 10:14:59 +02005823 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005824 }
5825
Radek Krejci03b71f72016-03-16 11:10:09 +01005826 /* set boolean result of the condition */
Michal Vasko944a5642016-03-21 11:48:58 +01005827 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02005828 if (!set.val.bool) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005829 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci0b7704f2016-03-18 12:16:14 +01005830 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02005831 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005832 }
Radek Krejci51093642016-03-29 10:14:59 +02005833
5834 /* free xpath set content */
5835 lyxp_set_cast(&set, LYXP_SET_EMPTY, node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005836 }
5837
Michal Vasko90fc2a32016-08-24 15:58:58 +02005838 sparent = node->schema;
Michal Vaskocf024702015-10-08 15:01:42 +02005839 goto check_augment;
5840
5841 /* check when in every schema node that affects node */
Michal Vasko90fc2a32016-08-24 15:58:58 +02005842 while (sparent && (sparent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
5843 if (((struct lys_node_uses *)sparent)->when) {
Michal Vaskocf024702015-10-08 15:01:42 +02005844 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005845 rc = resolve_when_ctx_node(node, sparent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02005846 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02005847 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02005848 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005849 }
5850 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02005851
5852 unlinked_nodes = NULL;
5853 /* we do not want our node pointer to change */
5854 tmp_node = node;
5855 rc = resolve_when_unlink_nodes(sparent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
5856 if (rc) {
5857 goto cleanup;
5858 }
5859
5860 rc = lyxp_eval(((struct lys_node_uses *)sparent)->when->cond, ctx_node, ctx_node_type, &set, LYXP_WHEN);
5861
5862 if (unlinked_nodes && ctx_node) {
5863 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
5864 rc = -1;
5865 goto cleanup;
5866 }
5867 }
5868
Radek Krejci03b71f72016-03-16 11:10:09 +01005869 if (rc) {
5870 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005871 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005872 }
Radek Krejci51093642016-03-29 10:14:59 +02005873 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005874 }
5875
Michal Vasko944a5642016-03-21 11:48:58 +01005876 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02005877 if (!set.val.bool) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005878 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Radek Krejci0b7704f2016-03-18 12:16:14 +01005879 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02005880 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005881 }
Radek Krejci51093642016-03-29 10:14:59 +02005882
5883 /* free xpath set content */
5884 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005885 }
5886
5887check_augment:
Michal Vasko90fc2a32016-08-24 15:58:58 +02005888 if ((sparent->parent && (sparent->parent->nodetype == LYS_AUGMENT) && (((struct lys_node_augment *)sparent->parent)->when))) {
Michal Vaskocf024702015-10-08 15:01:42 +02005889 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005890 rc = resolve_when_ctx_node(node, sparent->parent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02005891 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02005892 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02005893 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005894 }
5895 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02005896
5897 unlinked_nodes = NULL;
5898 tmp_node = node;
5899 rc = resolve_when_unlink_nodes(sparent->parent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
5900 if (rc) {
5901 goto cleanup;
5902 }
5903
5904 rc = lyxp_eval(((struct lys_node_augment *)sparent->parent)->when->cond, ctx_node, ctx_node_type, &set, LYXP_WHEN);
5905
5906 /* reconnect nodes, if ctx_node is NULL then all the nodes were unlinked, but linked together,
5907 * so the tree did not actually change and there is nothing for us to do
5908 */
5909 if (unlinked_nodes && ctx_node) {
5910 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
5911 rc = -1;
5912 goto cleanup;
5913 }
5914 }
5915
Radek Krejci03b71f72016-03-16 11:10:09 +01005916 if (rc) {
5917 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005918 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005919 }
Radek Krejci51093642016-03-29 10:14:59 +02005920 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005921 }
5922
Michal Vasko944a5642016-03-21 11:48:58 +01005923 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, LYXP_WHEN);
Michal Vaskocf024702015-10-08 15:01:42 +02005924
Michal Vasko8146d4c2016-05-09 15:50:29 +02005925 if (!set.val.bool) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005926 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Radek Krejci0b7704f2016-03-18 12:16:14 +01005927 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02005928 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005929 }
Radek Krejci51093642016-03-29 10:14:59 +02005930
5931 /* free xpath set content */
5932 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005933 }
5934
Michal Vasko90fc2a32016-08-24 15:58:58 +02005935 sparent = lys_parent(sparent);
Michal Vaskocf024702015-10-08 15:01:42 +02005936 }
5937
Radek Krejci0b7704f2016-03-18 12:16:14 +01005938 node->when_status |= LYD_WHEN_TRUE;
Radek Krejci03b71f72016-03-16 11:10:09 +01005939
Radek Krejci51093642016-03-29 10:14:59 +02005940cleanup:
Radek Krejci51093642016-03-29 10:14:59 +02005941 /* free xpath set content */
5942 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node ? ctx_node : node, 0);
5943
Radek Krejci46165822016-08-26 14:06:27 +02005944 if (result) {
5945 if (node->when_status & LYD_WHEN_TRUE) {
5946 *result = 1;
5947 } else {
5948 *result = 0;
5949 }
5950 }
5951
Radek Krejci51093642016-03-29 10:14:59 +02005952 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005953}
5954
Radek Krejcicbb473e2016-09-16 14:48:32 +02005955static int
5956check_leafref_features(struct lys_type *type)
5957{
5958 struct lys_node *iter;
5959 struct ly_set *src_parents, *trg_parents, *features;
5960 unsigned int i, j, size, x;
5961 int ret = EXIT_SUCCESS;
5962
5963 assert(type->parent);
5964
5965 src_parents = ly_set_new();
5966 trg_parents = ly_set_new();
5967 features = ly_set_new();
5968
5969 /* get parents chain of source (leafref) */
5970 for (iter = (struct lys_node *)type->parent; iter; iter = iter->parent) {
5971 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
5972 continue;
5973 }
5974 ly_set_add(src_parents, iter, LY_SET_OPT_USEASLIST);
5975 }
5976 /* get parents chain of target */
5977 for (iter = (struct lys_node *)type->info.lref.target; iter; iter = iter->parent) {
5978 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
5979 continue;
5980 }
5981 ly_set_add(trg_parents, iter, LY_SET_OPT_USEASLIST);
5982 }
5983
5984 /* compare the features used in if-feature statements in the rest of both
5985 * chains of parents. The set of features used for target must be a subset
5986 * of features used for the leafref. This is not a perfect, we should compare
5987 * the truth tables but it could require too much resources, so we simplify that */
5988 for (i = 0; i < src_parents->number; i++) {
5989 iter = src_parents->set.s[i]; /* shortcut */
5990 if (!iter->iffeature_size) {
5991 continue;
5992 }
5993 for (j = 0; j < iter->iffeature_size; j++) {
5994 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
5995 for (; size; size--) {
5996 if (!iter->iffeature[j].features[size - 1]) {
5997 /* not yet resolved feature, postpone this check */
5998 ret = EXIT_FAILURE;
5999 goto cleanup;
6000 }
6001 ly_set_add(features, iter->iffeature[j].features[size - 1], 0);
6002 }
6003 }
6004 }
6005 x = features->number;
6006 for (i = 0; i < trg_parents->number; i++) {
6007 iter = trg_parents->set.s[i]; /* shortcut */
6008 if (!iter->iffeature_size) {
6009 continue;
6010 }
6011 for (j = 0; j < iter->iffeature_size; j++) {
6012 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
6013 for (; size; size--) {
6014 if (!iter->iffeature[j].features[size - 1]) {
6015 /* not yet resolved feature, postpone this check */
6016 ret = EXIT_FAILURE;
6017 goto cleanup;
6018 }
6019 if ((unsigned int)ly_set_add(features, iter->iffeature[j].features[size - 1], 0) >= x) {
6020 /* the feature is not present in features set of target's parents chain */
6021 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, type->parent, "leafref", type->info.lref.path);
6022 LOGVAL(LYE_SPEC, LY_VLOG_LYS, type->parent,
6023 "Leafref is not conditional based on \"%s\" feature as its target.",
6024 iter->iffeature[j].features[size - 1]->name);
6025 ret = -1;
6026 goto cleanup;
6027 }
6028 }
6029 }
6030 }
6031
6032cleanup:
6033 ly_set_free(features);
6034 ly_set_free(src_parents);
6035 ly_set_free(trg_parents);
6036
6037 return ret;
6038}
6039
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006040/**
Michal Vaskobb211122015-08-19 14:03:11 +02006041 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006042 *
6043 * @param[in] mod Main module.
6044 * @param[in] item Item to resolve. Type determined by \p type.
6045 * @param[in] type Type of the unresolved item.
6046 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02006047 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006048 *
6049 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
6050 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006051static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006052resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Radek Krejci48464ed2016-03-17 15:44:09 +01006053 struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006054{
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006055 /* has_str - whether the str_snode is a string in a dictionary that needs to be freed */
Radek Krejcic79c6b12016-07-26 15:11:49 +02006056 int rc = -1, has_str = 0, tpdf_flag = 0, i, k;
6057 unsigned int j;
Radek Krejcic13db382016-08-16 10:52:42 +02006058 struct lys_node *node, *par_grp;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006059 const char *expr;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006060
Radek Krejcic79c6b12016-07-26 15:11:49 +02006061 struct ly_set *refs, *procs;
6062 struct lys_feature *ref, *feat;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006063 struct lys_ident *ident;
6064 struct lys_type *stype;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006065 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01006066 struct lyxml_elem *yin;
Pavol Vicana0e4e672016-02-24 12:20:04 +01006067 struct yang_type *yang;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006068 struct unres_list_uniq *unique_info;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006069 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006070
6071 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006072 case UNRES_IDENT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006073 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006074 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006075 ident = item;
6076
Radek Krejci018f1f52016-08-03 16:01:20 +02006077 rc = resolve_base_ident(mod, ident, expr, "identity", NULL, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006078 break;
6079 case UNRES_TYPE_IDENTREF:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006080 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006081 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006082 stype = item;
6083
Radek Krejci018f1f52016-08-03 16:01:20 +02006084 rc = resolve_base_ident(mod, NULL, expr, "type", stype, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006085 break;
6086 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02006087 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006088 stype = item;
6089
Radek Krejci2f12f852016-01-08 12:59:57 +01006090 /* HACK - when there is no parent, we are in top level typedef and in that
6091 * case, the path has to contain absolute path, so we let the resolve_path_arg_schema()
6092 * know it via tpdf_flag */
6093 if (!node) {
Radek Krejci4f78b532016-02-17 13:43:00 +01006094 tpdf_flag = 1;
Radek Krejci2f12f852016-01-08 12:59:57 +01006095 node = (struct lys_node *)stype->parent;
6096 }
6097
Radek Krejci27fe55e2016-09-13 17:13:35 +02006098 if (!lys_node_module(node)->implemented) {
6099 /* not implemented module, don't bother with resolving the leafref
Radek Krejci990af1f2016-11-09 13:53:36 +01006100 * if the module is set to be implemented, the path will be resolved then */
Radek Krejci27fe55e2016-09-13 17:13:35 +02006101 rc = 0;
6102 break;
6103 }
Radek Krejci48464ed2016-03-17 15:44:09 +01006104 rc = resolve_path_arg_schema(stype->info.lref.path, node, tpdf_flag,
Michal Vasko1e62a092015-12-01 12:27:20 +01006105 (const struct lys_node **)&stype->info.lref.target);
Michal Vasko01c6fd22016-05-20 11:43:05 +02006106 if (!tpdf_flag && !rc) {
6107 assert(stype->info.lref.target);
Radek Krejcicbb473e2016-09-16 14:48:32 +02006108 /* check if leafref and its target are under a common if-features */
6109 rc = check_leafref_features(stype);
6110 if (rc) {
6111 break;
6112 }
6113
Radek Krejci46c4cd72016-01-21 15:13:52 +01006114 /* store the backlink from leafref target */
Michal Vasko01c6fd22016-05-20 11:43:05 +02006115 if (lys_leaf_add_leafref_target(stype->info.lref.target, (struct lys_node *)stype->parent)) {
6116 rc = -1;
Radek Krejci46c4cd72016-01-21 15:13:52 +01006117 }
Radek Krejci46c4cd72016-01-21 15:13:52 +01006118 }
6119
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006120 break;
Radek Krejci3a5501d2016-07-18 22:03:34 +02006121 case UNRES_TYPE_DER_TPDF:
6122 tpdf_flag = 1;
6123 /* no break */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006124 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01006125 /* parent */
6126 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006127 stype = item;
6128
Michal Vasko88c29542015-11-27 14:57:53 +01006129 /* HACK type->der is temporarily unparsed type statement */
6130 yin = (struct lyxml_elem *)stype->der;
6131 stype->der = NULL;
6132
Pavol Vicana0e4e672016-02-24 12:20:04 +01006133 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6134 yang = (struct yang_type *)yin;
Radek Krejci3a5501d2016-07-18 22:03:34 +02006135 rc = yang_check_type(mod, node, yang, tpdf_flag, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006136
6137 if (rc) {
Pavol Vican8bd72e42016-08-29 09:53:05 +02006138 /* may try again later */
6139 stype->der = (struct lys_tpdf *)yang;
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006140 } else {
6141 /* we need to always be able to free this, it's safe only in this case */
Pavol Vican5f0316a2016-04-05 21:21:11 +02006142 lydict_remove(mod->ctx, yang->name);
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006143 free(yang);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006144 }
6145
Michal Vasko88c29542015-11-27 14:57:53 +01006146 } else {
Radek Krejci3a5501d2016-07-18 22:03:34 +02006147 rc = fill_yin_type(mod, node, yin, stype, tpdf_flag, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006148 if (!rc) {
6149 /* we need to always be able to free this, it's safe only in this case */
6150 lyxml_free(mod->ctx, yin);
6151 } else {
6152 /* may try again later, put all back how it was */
6153 stype->der = (struct lys_tpdf *)yin;
6154 }
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006155 }
Radek Krejcic13db382016-08-16 10:52:42 +02006156 if (rc == EXIT_SUCCESS) {
Radek Krejci2c2fce82016-08-01 13:52:26 +02006157 /* it does not make sense to have leaf-list of empty type */
6158 if (!tpdf_flag && node->nodetype == LYS_LEAFLIST && stype->base == LY_TYPE_EMPTY) {
6159 LOGWRN("The leaf-list \"%s\" is of \"empty\" type, which does not make sense.", node->name);
6160 }
Radek Krejci9b6aad22016-09-20 15:55:51 +02006161 } else if (rc == EXIT_FAILURE && stype->base != LY_TYPE_ERR) {
Radek Krejcic13db382016-08-16 10:52:42 +02006162 /* forward reference - in case the type is in grouping, we have to make the grouping unusable
6163 * by uses statement until the type is resolved. We do that the same way as uses statements inside
6164 * grouping - the grouping's nacm member (not used un grouping) is used to increase the number of
6165 * 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 +02006166 * 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 +02006167 * of the type's base member. */
6168 for (par_grp = node; par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
6169 if (par_grp) {
6170 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci9b6aad22016-09-20 15:55:51 +02006171 stype->base = LY_TYPE_ERR;
Radek Krejcic13db382016-08-16 10:52:42 +02006172 }
Radek Krejci2c2fce82016-08-01 13:52:26 +02006173 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006174 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006175 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006176 iff_data = str_snode;
6177 rc = resolve_feature(iff_data->fname, strlen(iff_data->fname), iff_data->node, item);
Radek Krejci9ff0a922016-07-14 13:08:05 +02006178 if (!rc) {
6179 /* success */
Radek Krejci9de2c042016-10-19 16:53:06 +02006180 if (iff_data->infeature) {
6181 /* store backlink into the target feature to allow reverse changes in case of changing feature status */
6182 feat = *((struct lys_feature **)item);
6183 if (!feat->depfeatures) {
6184 feat->depfeatures = ly_set_new();
6185 }
Radek Krejci85a54be2016-10-20 12:39:56 +02006186 ly_set_add(feat->depfeatures, iff_data->node, LY_SET_OPT_USEASLIST);
Radek Krejci9de2c042016-10-19 16:53:06 +02006187 }
6188 /* cleanup temporary data */
Radek Krejcicbb473e2016-09-16 14:48:32 +02006189 lydict_remove(mod->ctx, iff_data->fname);
6190 free(iff_data);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006191 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006192 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006193 case UNRES_FEATURE:
6194 feat = (struct lys_feature *)item;
6195
6196 if (feat->iffeature_size) {
6197 refs = ly_set_new();
6198 procs = ly_set_new();
6199 ly_set_add(procs, feat, 0);
6200
6201 while (procs->number) {
6202 ref = procs->set.g[procs->number - 1];
6203 ly_set_rm_index(procs, procs->number - 1);
6204
6205 for (i = 0; i < ref->iffeature_size; i++) {
6206 resolve_iffeature_getsizes(&ref->iffeature[i], NULL, &j);
6207 for (; j > 0 ; j--) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006208 if (ref->iffeature[i].features[j - 1]) {
Radek Krejcic79c6b12016-07-26 15:11:49 +02006209 if (ref->iffeature[i].features[j - 1] == feat) {
6210 LOGVAL(LYE_CIRC_FEATURES, LY_VLOG_NONE, NULL, feat->name);
6211 goto featurecheckdone;
6212 }
6213
6214 if (ref->iffeature[i].features[j - 1]->iffeature_size) {
6215 k = refs->number;
6216 if (ly_set_add(refs, ref->iffeature[i].features[j - 1], 0) == k) {
6217 /* not yet seen feature, add it for processing */
6218 ly_set_add(procs, ref->iffeature[i].features[j - 1], 0);
6219 }
6220 }
6221 } else {
6222 /* forward reference */
6223 rc = EXIT_FAILURE;
6224 goto featurecheckdone;
6225 }
6226 }
6227
6228 }
6229 }
6230 rc = EXIT_SUCCESS;
6231
6232featurecheckdone:
6233 ly_set_free(refs);
6234 ly_set_free(procs);
6235 }
6236
6237 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006238 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006239 rc = resolve_unres_schema_uses(item, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006240 break;
6241 case UNRES_TYPE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006242 stype = item;
6243
Radek Krejci51673202016-11-01 17:00:32 +01006244 rc = check_default(stype, (const char **)str_snode, mod);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006245 break;
6246 case UNRES_CHOICE_DFLT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006247 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006248 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006249 choic = item;
6250
Radek Krejcie00d2312016-08-12 15:27:49 +02006251 if (!choic->dflt) {
6252 choic->dflt = resolve_choice_dflt(choic, expr);
6253 }
Michal Vasko7955b362015-09-04 14:18:15 +02006254 if (choic->dflt) {
Radek Krejcie00d2312016-08-12 15:27:49 +02006255 rc = lyp_check_mandatory_choice((struct lys_node *)choic);
Michal Vasko7955b362015-09-04 14:18:15 +02006256 } else {
6257 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006258 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006259 break;
6260 case UNRES_LIST_KEYS:
Radek Krejci5c08a992016-11-02 13:30:04 +01006261 rc = resolve_list_keys(item, ((struct lys_node_list *)item)->keys_str);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006262 break;
6263 case UNRES_LIST_UNIQ:
Radek Krejcid09d1a52016-08-11 14:05:45 +02006264 unique_info = (struct unres_list_uniq *)item;
6265 rc = resolve_unique(unique_info->list, unique_info->expr, unique_info->trg_type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006266 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006267 case UNRES_AUGMENT:
Radek Krejcib3142312016-11-09 11:04:12 +01006268 rc = resolve_augment(item, NULL, unres);
Michal Vasko7178e692016-02-12 15:58:05 +01006269 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006270 case UNRES_XPATH:
6271 node = (struct lys_node *)item;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02006272 rc = lys_check_xpath(node, 1);
Michal Vasko508a50d2016-09-07 14:50:33 +02006273 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006274 default:
6275 LOGINT;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006276 break;
6277 }
6278
Radek Krejci54081ce2016-08-12 15:21:47 +02006279 if (has_str && !rc) {
6280 /* the string is no more needed in case of success.
6281 * In case of forward reference, we will try to resolve the string later */
Radek Krejci4f78b532016-02-17 13:43:00 +01006282 lydict_remove(mod->ctx, str_snode);
6283 }
6284
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006285 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006286}
6287
Michal Vaskof02e3742015-08-05 16:27:02 +02006288/* logs directly */
6289static void
Radek Krejci48464ed2016-03-17 15:44:09 +01006290print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006291{
Michal Vaskocb34dc62016-05-20 14:38:37 +02006292 struct lyxml_elem *xml;
6293 struct lyxml_attr *attr;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006294 struct unres_iffeat_data *iff_data;
Radek Krejci76e15e12016-06-22 11:02:24 +02006295 const char *type_name = NULL;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006296
Michal Vaskof02e3742015-08-05 16:27:02 +02006297 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02006298 case UNRES_IDENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006299 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identity", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006300 break;
6301 case UNRES_TYPE_IDENTREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006302 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identityref", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006303 break;
6304 case UNRES_TYPE_LEAFREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006305 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "leafref",
6306 ((struct lys_type *)item)->info.lref.path);
Michal Vaskof02e3742015-08-05 16:27:02 +02006307 break;
Radek Krejci3a5501d2016-07-18 22:03:34 +02006308 case UNRES_TYPE_DER_TPDF:
Michal Vaskof02e3742015-08-05 16:27:02 +02006309 case UNRES_TYPE_DER:
Michal Vaskocb34dc62016-05-20 14:38:37 +02006310 xml = (struct lyxml_elem *)((struct lys_type *)item)->der;
6311 if (xml->flags & LY_YANG_STRUCTURE_FLAG) {
6312 type_name = ((struct yang_type *)xml)->name;
6313 } else {
6314 LY_TREE_FOR(xml->attr, attr) {
6315 if ((attr->type == LYXML_ATTR_STD) && !strcmp(attr->name, "name")) {
6316 type_name = attr->value;
6317 break;
6318 }
6319 }
6320 assert(attr);
6321 }
6322 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "derived type", type_name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006323 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006324 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006325 iff_data = str_node;
6326 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "if-feature", iff_data->fname);
Michal Vaskof02e3742015-08-05 16:27:02 +02006327 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006328 case UNRES_FEATURE:
6329 LOGVRB("There are unresolved if-features for \"%s\" feature circular dependency check, it will be attempted later",
6330 ((struct lys_feature *)item)->name);
6331 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006332 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006333 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "uses", ((struct lys_node_uses *)item)->name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006334 break;
6335 case UNRES_TYPE_DFLT:
Radek Krejci2e2de832016-10-13 16:12:26 +02006336 if (str_node) {
6337 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "type default", (char *)str_node);
6338 } /* else no default value in the type itself, but we are checking some restrictions against
6339 * possible default value of some base type. The failure is caused by not resolved base type,
6340 * so it was already reported */
Michal Vaskof02e3742015-08-05 16:27:02 +02006341 break;
6342 case UNRES_CHOICE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006343 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "choice default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006344 break;
6345 case UNRES_LIST_KEYS:
Radek Krejci48464ed2016-03-17 15:44:09 +01006346 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list keys", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006347 break;
6348 case UNRES_LIST_UNIQ:
Radek Krejci48464ed2016-03-17 15:44:09 +01006349 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list unique", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006350 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006351 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006352 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "augment target",
6353 ((struct lys_node_augment *)item)->target_name);
Michal Vasko7178e692016-02-12 15:58:05 +01006354 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006355 case UNRES_XPATH:
Michal Vasko0d198372016-11-16 11:40:03 +01006356 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "XPath expressions of",
6357 ((struct lys_node *)item)->name);
Michal Vasko508a50d2016-09-07 14:50:33 +02006358 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006359 default:
6360 LOGINT;
Michal Vaskof02e3742015-08-05 16:27:02 +02006361 break;
6362 }
6363}
6364
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006365/**
Michal Vaskobb211122015-08-19 14:03:11 +02006366 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006367 *
6368 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006369 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006370 *
Michal Vasko92b8a382015-08-19 14:03:49 +02006371 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006372 */
Michal Vaskof02e3742015-08-05 16:27:02 +02006373int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006374resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02006375{
Radek Krejci010e54b2016-03-15 09:40:34 +01006376 uint32_t i, resolved = 0, unres_count, res_count;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006377 int rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006378
6379 assert(unres);
6380
Michal Vaskoe8734262016-09-29 14:12:06 +02006381 LOGVRB("Resolving \"%s\" unresolved schema nodes and their constraints...", mod->name);
Radek Krejci010e54b2016-03-15 09:40:34 +01006382 ly_vlog_hide(1);
Michal Vasko51054ca2015-08-12 12:20:00 +02006383
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006384 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02006385 do {
Michal Vasko88c29542015-11-27 14:57:53 +01006386 unres_count = 0;
6387 res_count = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02006388
6389 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006390 /* UNRES_TYPE_LEAFREF must be resolved (for storing leafref target pointers);
Radek Krejcic79c6b12016-07-26 15:11:49 +02006391 * if-features are resolved here to make sure that we will have all if-features for
6392 * later check of feature circular dependency */
Radek Krejci018f1f52016-08-03 16:01:20 +02006393 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006394 continue;
6395 }
Radek Krejci018f1f52016-08-03 16:01:20 +02006396 /* processes UNRES_USES, UNRES_IFFEAT, UNRES_TYPE_DER, UNRES_TYPE_DER_TPDF, UNRES_TYPE_LEAFREF,
Radek Krejci818b0c52016-11-09 15:10:51 +01006397 * UNRES_AUGMENT, UNRES_CHOICE_DFLT and UNRES_IDENT */
Michal Vasko51054ca2015-08-12 12:20:00 +02006398
Michal Vasko88c29542015-11-27 14:57:53 +01006399 ++unres_count;
Radek Krejci48464ed2016-03-17 15:44:09 +01006400 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006401 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006402 unres->type[i] = UNRES_RESOLVED;
6403 ++resolved;
Michal Vasko88c29542015-11-27 14:57:53 +01006404 ++res_count;
Michal Vasko89e15322015-08-17 15:46:55 +02006405 } else if (rc == -1) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006406 ly_vlog_hide(0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02006407 /* print the error */
6408 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006409 return -1;
Radek Krejcic2a180f2016-06-22 13:28:16 +02006410 } else {
6411 /* forward reference, erase ly_errno */
Radek Krejci00a0e712016-10-26 10:24:46 +02006412 ly_err_clean(1);
Michal Vasko51054ca2015-08-12 12:20:00 +02006413 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006414 }
Michal Vasko88c29542015-11-27 14:57:53 +01006415 } while (res_count && (res_count < unres_count));
Michal Vasko51054ca2015-08-12 12:20:00 +02006416
Michal Vasko88c29542015-11-27 14:57:53 +01006417 if (res_count < unres_count) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006418 /* just print the errors */
6419 ly_vlog_hide(0);
6420
6421 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006422 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006423 continue;
6424 }
6425 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
6426 }
Michal Vasko92b8a382015-08-19 14:03:49 +02006427 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006428 }
6429
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006430 /* the rest */
6431 for (i = 0; i < unres->count; ++i) {
6432 if (unres->type[i] == UNRES_RESOLVED) {
6433 continue;
6434 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02006435
Radek Krejci48464ed2016-03-17 15:44:09 +01006436 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01006437 if (rc == 0) {
Pavol Vican88e16c92016-09-07 15:41:50 +02006438 if (unres->type[i] == UNRES_LIST_UNIQ) {
6439 /* free the allocated structure */
6440 free(unres->item[i]);
6441 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006442 unres->type[i] = UNRES_RESOLVED;
6443 ++resolved;
6444 } else if (rc == -1) {
6445 ly_vlog_hide(0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02006446 /* print the error */
6447 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
6448 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006449 }
6450 }
6451
Radek Krejci010e54b2016-03-15 09:40:34 +01006452 ly_vlog_hide(0);
6453
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006454 if (resolved < unres->count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006455 /* try to resolve the unresolved nodes again, it will not resolve anything, but it will print
6456 * all the validation errors
6457 */
6458 for (i = 0; i < unres->count; ++i) {
6459 if (unres->type[i] == UNRES_RESOLVED) {
6460 continue;
6461 }
Radek Krejcib3142312016-11-09 11:04:12 +01006462 if (unres->type[i] == UNRES_XPATH) {
6463 /* unresolvable XPaths are actually supposed to be warnings - they may be
6464 * unresolved due to the not implemented target module so it shouldn't avoid
6465 * parsing the module, but we still want to announce some issue here */
6466 ly_vlog_hide(0xff);
6467 }
Radek Krejci48464ed2016-03-17 15:44:09 +01006468 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejcib3142312016-11-09 11:04:12 +01006469 if (unres->type[i] == UNRES_XPATH && *ly_vlog_hide_location() == 0xff) {
6470 unres->type[i] = UNRES_RESOLVED;
6471 resolved++;
6472 ly_vlog_hide(0);
6473 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006474 }
Radek Krejcib3142312016-11-09 11:04:12 +01006475 if (resolved < unres->count) {
6476 return -1;
6477 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006478 }
6479
Michal Vaskoe8734262016-09-29 14:12:06 +02006480 LOGVRB("All \"%s\" schema nodes and constraints resolved.", mod->name);
Radek Krejcic071c542016-01-27 14:57:51 +01006481 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006482 return EXIT_SUCCESS;
6483}
6484
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006485/**
Michal Vaskobb211122015-08-19 14:03:11 +02006486 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006487 *
6488 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006489 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006490 * @param[in] item Item to resolve. Type determined by \p type.
6491 * @param[in] type Type of the unresolved item.
6492 * @param[in] str String argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006493 *
Michal Vasko3767fb22016-07-21 12:10:57 +02006494 * @return EXIT_SUCCESS on success, EXIT_FAILURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006495 */
6496int
Radek Krejci48464ed2016-03-17 15:44:09 +01006497unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
6498 const char *str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006499{
Radek Krejci54081ce2016-08-12 15:21:47 +02006500 int rc;
6501 const char *dictstr;
6502
6503 dictstr = lydict_insert(mod->ctx, str, 0);
6504 rc = unres_schema_add_node(mod, unres, item, type, (struct lys_node *)dictstr);
6505
6506 if (rc == -1) {
6507 lydict_remove(mod->ctx, dictstr);
6508 }
6509 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006510}
6511
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006512/**
Michal Vaskobb211122015-08-19 14:03:11 +02006513 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006514 *
6515 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006516 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006517 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01006518 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006519 * @param[in] snode Schema node argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006520 *
Michal Vasko3767fb22016-07-21 12:10:57 +02006521 * @return EXIT_SUCCESS on success, EXIT_FIALURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006522 */
6523int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006524unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Radek Krejci48464ed2016-03-17 15:44:09 +01006525 struct lys_node *snode)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006526{
Michal Vaskoef486d72016-09-27 12:10:44 +02006527 int rc, log_hidden;
Radek Krejci850a5de2016-11-08 14:06:40 +01006528 uint32_t u;
Michal Vasko88c29542015-11-27 14:57:53 +01006529 struct lyxml_elem *yin;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006530
Michal Vasko9bf425b2015-10-22 11:42:03 +02006531 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
6532 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006533
Radek Krejci850a5de2016-11-08 14:06:40 +01006534 /* check for duplicities in unres */
6535 for (u = 0; u < unres->count; u++) {
6536 if (unres->type[u] == type && unres->item[u] == item &&
6537 unres->str_snode[u] == snode && unres->module[u] == mod) {
6538 /* duplication, will be resolved later */
6539 return EXIT_FAILURE;
6540 }
6541 }
6542
Michal Vaskoef486d72016-09-27 12:10:44 +02006543 if (*ly_vlog_hide_location()) {
6544 log_hidden = 1;
6545 } else {
6546 log_hidden = 0;
6547 ly_vlog_hide(1);
6548 }
Radek Krejci48464ed2016-03-17 15:44:09 +01006549 rc = resolve_unres_schema_item(mod, item, type, snode, unres);
Michal Vaskoef486d72016-09-27 12:10:44 +02006550 if (!log_hidden) {
6551 ly_vlog_hide(0);
6552 }
6553
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006554 if (rc != EXIT_FAILURE) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006555 if (rc == -1 && ly_errno == LY_EVALID) {
Radek Krejci2467a492016-10-24 15:16:59 +02006556 ly_err_repeat();
Radek Krejci010e54b2016-03-15 09:40:34 +01006557 }
Radek Krejcid09d1a52016-08-11 14:05:45 +02006558 if (type == UNRES_LIST_UNIQ) {
6559 /* free the allocated structure */
6560 free(item);
Pavol Vican88e16c92016-09-07 15:41:50 +02006561 } else if (rc == -1 && type == UNRES_IFFEAT) {
6562 /* free the allocated resources */
6563 free(*((char **)item));
6564 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006565 return rc;
Radek Krejcif347abc2016-06-22 10:18:47 +02006566 } else {
6567 /* erase info about validation errors */
Radek Krejci00a0e712016-10-26 10:24:46 +02006568 ly_err_clean(1);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006569 }
6570
Radek Krejci48464ed2016-03-17 15:44:09 +01006571 print_unres_schema_item_fail(item, type, snode);
Michal Vaskof02e3742015-08-05 16:27:02 +02006572
Michal Vasko88c29542015-11-27 14:57:53 +01006573 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
Radek Krejci3a5501d2016-07-18 22:03:34 +02006574 if (type == UNRES_TYPE_DER || type == UNRES_TYPE_DER_TPDF) {
Michal Vasko88c29542015-11-27 14:57:53 +01006575 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
Pavol Vicana0e4e672016-02-24 12:20:04 +01006576 if (!(yin->flags & LY_YANG_STRUCTURE_FLAG)) {
6577 lyxml_unlink_elem(mod->ctx, yin, 1);
6578 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
6579 }
Michal Vasko88c29542015-11-27 14:57:53 +01006580 }
6581
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006582 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01006583 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
6584 if (!unres->item) {
6585 LOGMEM;
6586 return -1;
6587 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006588 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01006589 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
6590 if (!unres->type) {
6591 LOGMEM;
6592 return -1;
6593 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006594 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01006595 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
6596 if (!unres->str_snode) {
6597 LOGMEM;
6598 return -1;
6599 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006600 unres->str_snode[unres->count-1] = snode;
Radek Krejcic071c542016-01-27 14:57:51 +01006601 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
6602 if (!unres->module) {
6603 LOGMEM;
6604 return -1;
6605 }
6606 unres->module[unres->count-1] = mod;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006607
Michal Vasko3767fb22016-07-21 12:10:57 +02006608 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006609}
6610
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006611/**
Michal Vaskobb211122015-08-19 14:03:11 +02006612 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006613 *
6614 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006615 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006616 * @param[in] item Old item to be resolved.
6617 * @param[in] type Type of the old unresolved item.
6618 * @param[in] new_item New item to use in the duplicate.
6619 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02006620 * @return EXIT_SUCCESS on success, EXIT_FAILURE if item is not in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006621 */
Michal Vaskodad19402015-08-06 09:51:53 +02006622int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006623unres_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 +02006624{
6625 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006626 struct unres_list_uniq aux_uniq;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006627 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006628
Michal Vaskocf024702015-10-08 15:01:42 +02006629 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006630
Radek Krejcid09d1a52016-08-11 14:05:45 +02006631 /* hack for UNRES_LIST_UNIQ, which stores multiple items behind its item */
6632 if (type == UNRES_LIST_UNIQ) {
6633 aux_uniq.list = item;
6634 aux_uniq.expr = ((struct unres_list_uniq *)new_item)->expr;
6635 item = &aux_uniq;
6636 }
Michal Vasko878e38d2016-09-05 12:17:53 +02006637 i = unres_schema_find(unres, -1, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006638
6639 if (i == -1) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006640 if (type == UNRES_LIST_UNIQ) {
6641 free(new_item);
6642 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02006643 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006644 }
6645
Radek Krejcic79c6b12016-07-26 15:11:49 +02006646 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT) ||
Radek Krejcib69f3232016-09-16 17:41:07 +02006647 (type == UNRES_FEATURE) || (type == UNRES_LIST_UNIQ)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01006648 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006649 LOGINT;
6650 return -1;
6651 }
Radek Krejcicbb473e2016-09-16 14:48:32 +02006652 } else if (type == UNRES_IFFEAT) {
6653 /* duplicate unres_iffeature_data */
6654 iff_data = malloc(sizeof *iff_data);
6655 iff_data->fname = lydict_insert(mod->ctx, ((struct unres_iffeat_data *)unres->str_snode[i])->fname, 0);
6656 iff_data->node = ((struct unres_iffeat_data *)unres->str_snode[i])->node;
6657 if (unres_schema_add_node(mod, unres, new_item, type, (struct lys_node *)iff_data) == -1) {
6658 LOGINT;
6659 return -1;
6660 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006661 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01006662 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006663 LOGINT;
6664 return -1;
6665 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006666 }
Michal Vaskodad19402015-08-06 09:51:53 +02006667
6668 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006669}
6670
Michal Vaskof02e3742015-08-05 16:27:02 +02006671/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006672int
Michal Vasko878e38d2016-09-05 12:17:53 +02006673unres_schema_find(struct unres_schema *unres, int start_on_backwards, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006674{
Michal Vasko878e38d2016-09-05 12:17:53 +02006675 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006676 struct unres_list_uniq *aux_uniq1, *aux_uniq2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006677
Michal Vasko878e38d2016-09-05 12:17:53 +02006678 if (start_on_backwards > 0) {
6679 i = start_on_backwards;
6680 } else {
6681 i = unres->count - 1;
6682 }
6683 for (; i > -1; i--) {
6684 if (unres->type[i] != type) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006685 continue;
6686 }
6687 if (type != UNRES_LIST_UNIQ) {
Michal Vasko878e38d2016-09-05 12:17:53 +02006688 if (unres->item[i] == item) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006689 break;
6690 }
6691 } else {
6692 aux_uniq1 = (struct unres_list_uniq *)unres->item[i - 1];
6693 aux_uniq2 = (struct unres_list_uniq *)item;
6694 if ((aux_uniq1->list == aux_uniq2->list) && ly_strequal(aux_uniq1->expr, aux_uniq2->expr, 0)) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006695 break;
6696 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006697 }
6698 }
6699
Michal Vasko878e38d2016-09-05 12:17:53 +02006700 return i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006701}
Michal Vasko8bcdf292015-08-19 14:04:43 +02006702
Michal Vaskoede9c472016-06-07 09:38:15 +02006703static void
6704unres_schema_free_item(struct ly_ctx *ctx, struct unres_schema *unres, uint32_t i)
6705{
6706 struct lyxml_elem *yin;
6707 struct yang_type *yang;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006708 struct unres_iffeat_data *iff_data;
Michal Vaskoede9c472016-06-07 09:38:15 +02006709
6710 switch (unres->type[i]) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02006711 case UNRES_TYPE_DER_TPDF:
Michal Vaskoede9c472016-06-07 09:38:15 +02006712 case UNRES_TYPE_DER:
6713 yin = (struct lyxml_elem *)((struct lys_type *)unres->item[i])->der;
6714 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6715 yang =(struct yang_type *)yin;
6716 yang->type->base = yang->base;
6717 lydict_remove(ctx, yang->name);
6718 free(yang);
6719 } else {
6720 lyxml_free(ctx, yin);
6721 }
6722 break;
Pavol Vican88e16c92016-09-07 15:41:50 +02006723 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006724 iff_data = (struct unres_iffeat_data *)unres->str_snode[i];
6725 lydict_remove(ctx, iff_data->fname);
6726 free(unres->str_snode[i]);
Pavol Vican88e16c92016-09-07 15:41:50 +02006727 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02006728 case UNRES_IDENT:
6729 case UNRES_TYPE_IDENTREF:
Michal Vaskoede9c472016-06-07 09:38:15 +02006730 case UNRES_CHOICE_DFLT:
6731 case UNRES_LIST_KEYS:
Michal Vaskoede9c472016-06-07 09:38:15 +02006732 lydict_remove(ctx, (const char *)unres->str_snode[i]);
6733 break;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006734 case UNRES_LIST_UNIQ:
6735 free(unres->item[i]);
6736 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02006737 default:
6738 break;
6739 }
6740 unres->type[i] = UNRES_RESOLVED;
6741}
6742
Michal Vasko88c29542015-11-27 14:57:53 +01006743void
Radek Krejcic071c542016-01-27 14:57:51 +01006744unres_schema_free(struct lys_module *module, struct unres_schema **unres)
Michal Vasko88c29542015-11-27 14:57:53 +01006745{
6746 uint32_t i;
Radek Krejcic071c542016-01-27 14:57:51 +01006747 unsigned int unresolved = 0;
Michal Vasko88c29542015-11-27 14:57:53 +01006748
Radek Krejcic071c542016-01-27 14:57:51 +01006749 if (!unres || !(*unres)) {
6750 return;
Michal Vasko88c29542015-11-27 14:57:53 +01006751 }
6752
Radek Krejcic071c542016-01-27 14:57:51 +01006753 assert(module || (*unres)->count == 0);
6754
6755 for (i = 0; i < (*unres)->count; ++i) {
6756 if ((*unres)->module[i] != module) {
6757 if ((*unres)->type[i] != UNRES_RESOLVED) {
6758 unresolved++;
6759 }
6760 continue;
6761 }
Michal Vaskoede9c472016-06-07 09:38:15 +02006762
6763 /* free heap memory for the specific item */
6764 unres_schema_free_item(module->ctx, *unres, i);
Radek Krejcic071c542016-01-27 14:57:51 +01006765 }
6766
Michal Vaskoede9c472016-06-07 09:38:15 +02006767 /* free it all */
Radek Krejcic071c542016-01-27 14:57:51 +01006768 if (!module || (!unresolved && !module->type)) {
6769 free((*unres)->item);
6770 free((*unres)->type);
6771 free((*unres)->str_snode);
6772 free((*unres)->module);
Radek Krejcic071c542016-01-27 14:57:51 +01006773 free((*unres));
6774 (*unres) = NULL;
6775 }
Michal Vasko88c29542015-11-27 14:57:53 +01006776}
6777
Radek Krejci1899d6a2016-11-03 13:48:07 +01006778int
Radek Krejci9b6aad22016-09-20 15:55:51 +02006779resolve_leafref(struct lyd_node_leaf_list *leaf, struct lys_type *type)
Radek Krejci7de36cf2016-09-12 16:18:50 +02006780{
Radek Krejci7de36cf2016-09-12 16:18:50 +02006781 struct unres_data matches;
6782 uint32_t i;
6783
Radek Krejci9b6aad22016-09-20 15:55:51 +02006784 assert(type->base == LY_TYPE_LEAFREF);
6785
6786 /* init */
Michal Vasko16dc4f32016-12-09 09:43:50 +01006787 leaf->value.leafref = NULL;
Radek Krejci7de36cf2016-09-12 16:18:50 +02006788 memset(&matches, 0, sizeof matches);
Radek Krejci7de36cf2016-09-12 16:18:50 +02006789
6790 /* EXIT_FAILURE return keeps leaf->value.lefref NULL, handled later */
Radek Krejci9b6aad22016-09-20 15:55:51 +02006791 if (resolve_path_arg_data((struct lyd_node *)leaf, type->info.lref.path, &matches) == -1) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02006792 return -1;
6793 }
6794
6795 /* check that value matches */
6796 for (i = 0; i < matches.count; ++i) {
Radek Krejci1899d6a2016-11-03 13:48:07 +01006797 /* not that the value is already in canonical form since the parsers does the conversion,
6798 * so we can simply compare just the values */
Radek Krejci7de36cf2016-09-12 16:18:50 +02006799 if (ly_strequal(leaf->value_str, ((struct lyd_node_leaf_list *)matches.node[i])->value_str, 1)) {
Radek Krejci1899d6a2016-11-03 13:48:07 +01006800 /* we have the match */
Radek Krejci7de36cf2016-09-12 16:18:50 +02006801 leaf->value.leafref = matches.node[i];
6802 break;
6803 }
6804 }
6805
6806 free(matches.node);
6807
6808 if (!leaf->value.leafref) {
6809 /* reference not found */
6810 if (type->info.lref.req > -1) {
6811 LOGVAL(LYE_NOLEAFREF, LY_VLOG_LYD, leaf, type->info.lref.path, leaf->value_str);
6812 return EXIT_FAILURE;
6813 } else {
6814 LOGVRB("There is no leafref with the value \"%s\", but it is not required.", leaf->value_str);
6815 }
6816 }
6817
6818 return EXIT_SUCCESS;
6819}
6820
Radek Krejci9ad23f42016-10-31 15:46:52 +01006821API const struct lys_type *
Radek Krejci1899d6a2016-11-03 13:48:07 +01006822lyd_leaf_type(struct lyd_node_leaf_list *leaf, int resolve)
Radek Krejci9b6aad22016-09-20 15:55:51 +02006823{
Radek Krejci9b6aad22016-09-20 15:55:51 +02006824 if (!leaf || !(leaf->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Radek Krejci9ad23f42016-10-31 15:46:52 +01006825 return NULL;
Radek Krejci9b6aad22016-09-20 15:55:51 +02006826 }
Radek Krejci1899d6a2016-11-03 13:48:07 +01006827 if (((struct lys_node_leaf *)leaf->schema)->type.base == LY_TYPE_BITS) {
6828 free(leaf->value.bit);
Radek Krejci9b6aad22016-09-20 15:55:51 +02006829 }
Radek Krejci1899d6a2016-11-03 13:48:07 +01006830 memset(&leaf->value, 0, sizeof leaf->value);
Radek Krejci9b6aad22016-09-20 15:55:51 +02006831
Radek Krejci1899d6a2016-11-03 13:48:07 +01006832 /* resolve */
6833 return lyp_parse_value(&((struct lys_node_leaf *)leaf->schema)->type, (const char **)&leaf->value_str, NULL,
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01006834 (struct lyd_node *)leaf, leaf, resolve, 1, 0);
Radek Krejci9b6aad22016-09-20 15:55:51 +02006835}
6836
6837static int
6838resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type)
6839{
6840 struct lys_type *datatype = NULL;
Radek Krejci9b6aad22016-09-20 15:55:51 +02006841
6842 assert(type->base == LY_TYPE_UNION);
6843
6844 memset(&leaf->value, 0, sizeof leaf->value);
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01006845 datatype = lyp_parse_value(type, &leaf->value_str, NULL, (struct lyd_node *)leaf, leaf, 1, 1, 0);
Radek Krejci9b6aad22016-09-20 15:55:51 +02006846 if (!datatype) {
6847 /* failure */
6848 LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, (leaf->value_str ? leaf->value_str : ""), leaf->schema->name);
6849 return EXIT_FAILURE;
6850 }
6851
6852 return EXIT_SUCCESS;
6853}
6854
Michal Vasko8bcdf292015-08-19 14:04:43 +02006855/**
6856 * @brief Resolve a single unres data item. Logs directly.
6857 *
Michal Vaskocf024702015-10-08 15:01:42 +02006858 * @param[in] node Data node to resolve.
Michal Vaskocf024702015-10-08 15:01:42 +02006859 * @param[in] type Type of the unresolved item.
Michal Vasko8bcdf292015-08-19 14:04:43 +02006860 *
6861 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
6862 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02006863int
Radek Krejci48464ed2016-03-17 15:44:09 +01006864resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02006865{
Michal Vasko0491ab32015-08-19 14:28:29 +02006866 int rc;
Michal Vasko83a6c462015-10-08 16:43:53 +02006867 struct lyd_node_leaf_list *leaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006868 struct lys_node_leaf *sleaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006869
Michal Vasko83a6c462015-10-08 16:43:53 +02006870 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02006871 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006872
Michal Vaskocf024702015-10-08 15:01:42 +02006873 switch (type) {
6874 case UNRES_LEAFREF:
6875 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Radek Krejci9b6aad22016-09-20 15:55:51 +02006876 return resolve_leafref(leaf, &sleaf->type);
Michal Vasko8bcdf292015-08-19 14:04:43 +02006877
Michal Vaskocf024702015-10-08 15:01:42 +02006878 case UNRES_INSTID:
Radek Krejci7de36cf2016-09-12 16:18:50 +02006879 assert(sleaf->type.base == LY_TYPE_INST);
Radek Krejci00a0e712016-10-26 10:24:46 +02006880 ly_err_clean(1);
Radek Krejci48464ed2016-03-17 15:44:09 +01006881 leaf->value.instance = resolve_instid(node, leaf->value_str);
Radek Krejci40f17b92016-02-03 14:30:43 +01006882 if (!leaf->value.instance) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02006883 if (ly_errno) {
6884 return -1;
6885 } else if (sleaf->type.info.inst.req > -1) {
Michal Vasko6ac68282016-04-11 10:56:47 +02006886 LOGVAL(LYE_NOREQINS, LY_VLOG_LYD, leaf, leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02006887 return EXIT_FAILURE;
6888 } else {
Michal Vasko9925e282016-09-02 12:45:14 +02006889 LOGVRB("There is no instance identifier \"%s\", but it is not required.", leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02006890 }
6891 }
Michal Vaskocf024702015-10-08 15:01:42 +02006892 break;
6893
Radek Krejci7de36cf2016-09-12 16:18:50 +02006894 case UNRES_UNION:
6895 assert(sleaf->type.base == LY_TYPE_UNION);
Radek Krejci9b6aad22016-09-20 15:55:51 +02006896 return resolve_union(leaf, &sleaf->type);
Radek Krejci7de36cf2016-09-12 16:18:50 +02006897
Michal Vaskocf024702015-10-08 15:01:42 +02006898 case UNRES_WHEN:
Radek Krejci46165822016-08-26 14:06:27 +02006899 if ((rc = resolve_when(node, NULL))) {
Michal Vaskocf024702015-10-08 15:01:42 +02006900 return rc;
6901 }
6902 break;
6903
Michal Vaskobf19d252015-10-08 15:39:17 +02006904 case UNRES_MUST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006905 if ((rc = resolve_must(node, 0))) {
6906 return rc;
6907 }
6908 break;
6909
6910 case UNRES_MUST_INOUT:
6911 if ((rc = resolve_must(node, 1))) {
Michal Vaskobf19d252015-10-08 15:39:17 +02006912 return rc;
6913 }
6914 break;
6915
Michal Vaskocf024702015-10-08 15:01:42 +02006916 default:
Michal Vasko8bcdf292015-08-19 14:04:43 +02006917 LOGINT;
6918 return -1;
6919 }
6920
6921 return EXIT_SUCCESS;
6922}
6923
6924/**
Radek Krejci0b7704f2016-03-18 12:16:14 +01006925 * @brief add data unres item
Michal Vasko8bcdf292015-08-19 14:04:43 +02006926 *
6927 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02006928 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02006929 *
Radek Krejci0b7704f2016-03-18 12:16:14 +01006930 * @return 0 on success, -1 on error.
Michal Vasko8bcdf292015-08-19 14:04:43 +02006931 */
6932int
Radek Krejci0b7704f2016-03-18 12:16:14 +01006933unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02006934{
Radek Krejci03b71f72016-03-16 11:10:09 +01006935 assert(unres && node);
Michal Vaskoc4280842016-04-19 16:10:42 +02006936 assert((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)
Radek Krejcibacc7442016-10-27 13:39:56 +02006937 || (type == UNRES_MUST_INOUT) || (type == UNRES_UNION));
Michal Vasko8bcdf292015-08-19 14:04:43 +02006938
Radek Krejci03b71f72016-03-16 11:10:09 +01006939 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01006940 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
6941 if (!unres->node) {
6942 LOGMEM;
6943 return -1;
6944 }
Michal Vaskocf024702015-10-08 15:01:42 +02006945 unres->node[unres->count - 1] = node;
Michal Vasko253035f2015-12-17 16:58:13 +01006946 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
6947 if (!unres->type) {
6948 LOGMEM;
6949 return -1;
6950 }
Michal Vaskocf024702015-10-08 15:01:42 +02006951 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006952
Radek Krejci0b7704f2016-03-18 12:16:14 +01006953 if (type == UNRES_WHEN) {
6954 /* remove previous result */
6955 node->when_status = LYD_WHEN;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006956 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006957
6958 return EXIT_SUCCESS;
6959}
6960
6961/**
6962 * @brief Resolve every unres data item in the structure. Logs directly.
6963 *
Radek Krejci082c84f2016-10-17 16:33:06 +02006964 * If options includes LYD_OPT_TRUSTED, the data are considered trusted (when, must conditions are not expected,
6965 * unresolved leafrefs/instids are accepted).
6966 *
6967 * If options includes LYD_OPT_NOAUTODEL, the false resulting when condition on non-default nodes, the error is raised.
6968 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006969 * @param[in] unres Unres data structure to use.
Radek Krejci082c84f2016-10-17 16:33:06 +02006970 * @param[in,out] root Root node of the data tree, can be changed due to autodeletion.
6971 * @param[in] options Data options as described above.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006972 *
6973 * @return EXIT_SUCCESS on success, -1 on error.
6974 */
6975int
Radek Krejci082c84f2016-10-17 16:33:06 +02006976resolve_unres_data(struct unres_data *unres, struct lyd_node **root, int options)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006977{
Radek Krejci0c0086a2016-03-24 15:20:28 +01006978 uint32_t i, j, first = 1, resolved = 0, del_items = 0, when_stmt = 0;
Radek Krejci010e54b2016-03-15 09:40:34 +01006979 int rc, progress;
Radek Krejci0b7704f2016-03-18 12:16:14 +01006980 struct lyd_node *parent;
Radek Krejci7de36cf2016-09-12 16:18:50 +02006981 struct lyd_node_leaf_list *leaf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006982
Radek Krejci082c84f2016-10-17 16:33:06 +02006983 assert(root);
Radek Krejci03b71f72016-03-16 11:10:09 +01006984 assert(unres);
Radek Krejci03b71f72016-03-16 11:10:09 +01006985
6986 if (!unres->count) {
6987 return EXIT_SUCCESS;
6988 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006989
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02006990 LOGVRB("Resolving unresolved data nodes and their constraints...");
Radek Krejci010e54b2016-03-15 09:40:34 +01006991 ly_vlog_hide(1);
6992
Radek Krejci0b7704f2016-03-18 12:16:14 +01006993 /* when-stmt first */
Radek Krejci010e54b2016-03-15 09:40:34 +01006994 do {
Radek Krejci00a0e712016-10-26 10:24:46 +02006995 ly_err_clean(1);
Radek Krejci010e54b2016-03-15 09:40:34 +01006996 progress = 0;
Michal Vasko6df94132016-09-22 11:08:09 +02006997 for (i = 0; i < unres->count; i++) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006998 if (unres->type[i] != UNRES_WHEN) {
6999 continue;
7000 }
Radek Krejci082c84f2016-10-17 16:33:06 +02007001 assert(!(options & LYD_OPT_TRUSTED));
Radek Krejci0c0086a2016-03-24 15:20:28 +01007002 if (first) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007003 /* count when-stmt nodes in unres list */
7004 when_stmt++;
7005 }
7006
7007 /* resolve when condition only when all parent when conditions are already resolved */
7008 for (parent = unres->node[i]->parent;
7009 parent && LYD_WHEN_DONE(parent->when_status);
7010 parent = parent->parent) {
7011 if (!parent->parent && (parent->when_status & LYD_WHEN_FALSE)) {
7012 /* the parent node was already unlinked, do not resolve this node,
7013 * it will be removed anyway, so just mark it as resolved
7014 */
7015 unres->node[i]->when_status |= LYD_WHEN_FALSE;
7016 unres->type[i] = UNRES_RESOLVED;
7017 resolved++;
7018 break;
7019 }
7020 }
7021 if (parent) {
7022 continue;
7023 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007024
Radek Krejci48464ed2016-03-17 15:44:09 +01007025 rc = resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01007026 if (!rc) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007027 if (unres->node[i]->when_status & LYD_WHEN_FALSE) {
Radek Krejci082c84f2016-10-17 16:33:06 +02007028 if ((options & LYD_OPT_NOAUTODEL) && !unres->node[i]->dflt) {
Radek Krejci03b71f72016-03-16 11:10:09 +01007029 /* false when condition */
7030 ly_vlog_hide(0);
Radek Krejci2467a492016-10-24 15:16:59 +02007031 ly_err_repeat();
Radek Krejci03b71f72016-03-16 11:10:09 +01007032 return -1;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007033 } /* follows else */
7034
Radek Krejci0c0086a2016-03-24 15:20:28 +01007035 /* only unlink now, the subtree can contain another nodes stored in the unres list */
7036 /* if it has parent non-presence containers that would be empty, we should actually
7037 * remove the container
7038 */
Radek Krejci2537fd32016-09-07 16:22:41 +02007039 for (parent = unres->node[i];
7040 parent->parent && parent->parent->schema->nodetype == LYS_CONTAINER;
7041 parent = parent->parent) {
7042 if (((struct lys_node_container *)parent->parent->schema)->presence) {
7043 /* presence container */
7044 break;
Radek Krejci0c0086a2016-03-24 15:20:28 +01007045 }
Radek Krejci2537fd32016-09-07 16:22:41 +02007046 if (parent->next || parent->prev != parent) {
7047 /* non empty (the child we are in and we are going to remove is not the only child) */
7048 break;
7049 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007050 }
Radek Krejci2537fd32016-09-07 16:22:41 +02007051 unres->node[i] = parent;
Radek Krejci0c0086a2016-03-24 15:20:28 +01007052
Radek Krejci0b7704f2016-03-18 12:16:14 +01007053 /* auto-delete */
7054 LOGVRB("auto-delete node \"%s\" due to when condition (%s)", ly_errpath(),
7055 ((struct lys_node_leaf *)unres->node[i]->schema)->when->cond);
Radek Krejci0c0086a2016-03-24 15:20:28 +01007056 if (*root && *root == unres->node[i]) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007057 *root = (*root)->next;
Radek Krejci03b71f72016-03-16 11:10:09 +01007058 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007059
Radek Krejci0b7704f2016-03-18 12:16:14 +01007060 lyd_unlink(unres->node[i]);
7061 unres->type[i] = UNRES_DELETE;
7062 del_items++;
Radek Krejci51fd8162016-03-24 15:49:51 +01007063
7064 /* update the rest of unres items */
7065 for (j = 0; j < unres->count; j++) {
Radek Krejci3db819b2016-03-24 16:29:48 +01007066 if (unres->type[j] == UNRES_RESOLVED || unres->type[j] == UNRES_DELETE) {
Radek Krejci51fd8162016-03-24 15:49:51 +01007067 continue;
7068 }
7069
7070 /* test if the node is in subtree to be deleted */
7071 for (parent = unres->node[j]; parent; parent = parent->parent) {
7072 if (parent == unres->node[i]) {
7073 /* yes, it is */
7074 unres->type[j] = UNRES_RESOLVED;
7075 resolved++;
7076 break;
7077 }
7078 }
7079 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007080 } else {
7081 unres->type[i] = UNRES_RESOLVED;
Radek Krejci03b71f72016-03-16 11:10:09 +01007082 }
Radek Krejci00a0e712016-10-26 10:24:46 +02007083 ly_err_clean(1);
Radek Krejci010e54b2016-03-15 09:40:34 +01007084 resolved++;
7085 progress = 1;
7086 } else if (rc == -1) {
7087 ly_vlog_hide(0);
Michal Vasko76e73402016-08-24 16:00:13 +02007088 /* print only this last error */
7089 resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01007090 return -1;
Radek Krejci2467a492016-10-24 15:16:59 +02007091 } /* else forward reference */
Radek Krejci010e54b2016-03-15 09:40:34 +01007092 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007093 first = 0;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007094 } while (progress && resolved < when_stmt);
Radek Krejci010e54b2016-03-15 09:40:34 +01007095
Radek Krejci0b7704f2016-03-18 12:16:14 +01007096 /* do we have some unresolved when-stmt? */
Radek Krejcid940d732016-03-24 16:02:28 +01007097 if (when_stmt > resolved) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007098 ly_vlog_hide(0);
Radek Krejci2467a492016-10-24 15:16:59 +02007099 ly_err_repeat();
Radek Krejci0b7704f2016-03-18 12:16:14 +01007100 return -1;
7101 }
7102
7103 for (i = 0; del_items && i < unres->count; i++) {
7104 /* we had some when-stmt resulted to false, so now we have to sanitize the unres list */
7105 if (unres->type[i] != UNRES_DELETE) {
7106 continue;
7107 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007108 if (!unres->node[i]) {
7109 unres->type[i] = UNRES_RESOLVED;
7110 del_items--;
7111 continue;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007112 }
7113
7114 /* really remove the complete subtree */
7115 lyd_free(unres->node[i]);
7116 unres->type[i] = UNRES_RESOLVED;
7117 del_items--;
7118 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007119
7120 /* rest */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007121 for (i = 0; i < unres->count; ++i) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007122 if (unres->type[i] == UNRES_RESOLVED) {
7123 continue;
7124 }
Radek Krejci082c84f2016-10-17 16:33:06 +02007125 assert(!(options & LYD_OPT_TRUSTED) || ((unres->type[i] != UNRES_MUST) && (unres->type[i] != UNRES_MUST_INOUT)));
Radek Krejci010e54b2016-03-15 09:40:34 +01007126
Radek Krejci48464ed2016-03-17 15:44:09 +01007127 rc = resolve_unres_data_item(unres->node[i], unres->type[i]);
Michal Vasko6df94132016-09-22 11:08:09 +02007128 if (rc == -1) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007129 ly_vlog_hide(0);
Michal Vasko96b846c2016-05-18 13:28:58 +02007130 /* print only this last error */
7131 resolve_unres_data_item(unres->node[i], unres->type[i]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007132 return -1;
Radek Krejci082c84f2016-10-17 16:33:06 +02007133 } 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 +02007134 unres->type[i] = UNRES_RESOLVED;
7135 resolved++;
Radek Krejci082c84f2016-10-17 16:33:06 +02007136 if (options & LYD_OPT_TRUSTED) {
Michal Vasko6df94132016-09-22 11:08:09 +02007137 /* accept it in this case */
7138 if (unres->type[i] == UNRES_LEAFREF) {
7139 LOGVRB("Leafref \"%s\" with value \"%s\" failed to be resolved.",
7140 ((struct lys_node_leaf *)unres->node[i]->schema)->type.info.lref.path,
7141 ((struct lyd_node_leaf_list *)unres->node[i])->value_str);
7142 } else {
7143 LOGVRB("Instance identifier \"%s\" failed to be resolved.",
7144 ((struct lyd_node_leaf_list *)unres->node[i])->value_str);
7145 }
7146 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007147 }
7148 }
7149
Radek Krejci010e54b2016-03-15 09:40:34 +01007150 ly_vlog_hide(0);
7151 if (resolved < unres->count) {
7152 /* try to resolve the unresolved data again, it will not resolve anything, but it will print
7153 * all the validation errors
7154 */
7155 for (i = 0; i < unres->count; ++i) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02007156 if (unres->type[i] == UNRES_UNION) {
7157 /* does not make sense to print specific errors for all
7158 * the data types, just print that the value is invalid */
7159 leaf = (struct lyd_node_leaf_list *)unres->node[i];
7160 LOGVAL(LYE_INVAL, LY_VLOG_LYD, unres->node[i], (leaf->value_str ? leaf->value_str : ""),
7161 leaf->schema->name);
7162 } else if (unres->type[i] != UNRES_RESOLVED) {
7163 resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01007164 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007165 }
7166 return -1;
7167 }
7168
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02007169 LOGVRB("All data nodes and constraints resolved.");
Radek Krejci010e54b2016-03-15 09:40:34 +01007170 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007171 return EXIT_SUCCESS;
7172}