blob: c371f42c4ad9d481d6cc234ca204b2ccd0ccdc9c [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 Vasko6966ea62016-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;
41 int8_t str_exp, str_dig = -1;
42
43 ptr = *str_num;
44
45 if (ptr[0] == '-') {
46 minus = 1;
47 ++ptr;
48 }
49
Michal Vaskod24dd012016-09-30 12:20:22 +020050 if (!isdigit(ptr[0])) {
51 /* there must be at least one */
52 return 1;
53 }
54
Michal Vasko4d1f0482016-09-19 14:35:06 +020055 for (str_exp = 0; isdigit(ptr[0]) || ((ptr[0] == '.') && (str_dig < 0)); ++ptr) {
56 if (str_exp > 18) {
Michal Vaskod24dd012016-09-30 12:20:22 +020057 return 1;
Michal Vasko4d1f0482016-09-19 14:35:06 +020058 }
59
60 if (ptr[0] == '.') {
61 if (ptr[1] == '.') {
62 /* it's the next interval */
63 break;
64 }
65 ++str_dig;
66 } else {
67 ret = ret * 10 + (ptr[0] - 48);
68 if (str_dig > -1) {
69 ++str_dig;
70 }
71 ++str_exp;
72 }
73 }
Michal Vaskod24dd012016-09-30 12:20:22 +020074 if (str_dig == 0) {
75 /* no digits after '.' */
76 return 1;
77 } else if (str_dig == -1) {
78 /* there are 0 numbers after the floating point */
Michal Vasko4d1f0482016-09-19 14:35:06 +020079 str_dig = 0;
80 }
81
82 /* it's parsed, now adjust the number based on fraction-digits, if needed */
83 if (str_dig < dig) {
84 if ((str_exp - 1) + (dig - str_dig) > 18) {
Michal Vaskod24dd012016-09-30 12:20:22 +020085 return 1;
Michal Vasko4d1f0482016-09-19 14:35:06 +020086 }
87 ret *= dec_pow(dig - str_dig);
88 }
89 if (str_dig > dig) {
Michal Vaskod24dd012016-09-30 12:20:22 +020090 return 1;
Michal Vasko4d1f0482016-09-19 14:35:06 +020091 }
92
93 if (minus) {
94 ret *= -1;
95 }
96 *str_num = ptr;
Michal Vaskod24dd012016-09-30 12:20:22 +020097 *num = ret;
Michal Vasko4d1f0482016-09-19 14:35:06 +020098
Michal Vaskod24dd012016-09-30 12:20:22 +020099 return 0;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200100}
101
102/**
Radek Krejci6dc53a22015-08-17 13:27:59 +0200103 * @brief Parse an identifier.
104 *
105 * ;; An identifier MUST NOT start with (('X'|'x') ('M'|'m') ('L'|'l'))
106 * identifier = (ALPHA / "_")
107 * *(ALPHA / DIGIT / "_" / "-" / ".")
108 *
Michal Vaskobb211122015-08-19 14:03:11 +0200109 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200110 *
111 * @return Number of characters successfully parsed.
112 */
Michal Vasko249e6b52015-08-19 11:08:52 +0200113int
Radek Krejci6dc53a22015-08-17 13:27:59 +0200114parse_identifier(const char *id)
115{
116 int parsed = 0;
117
Michal Vasko1ab90bc2016-03-15 10:40:22 +0100118 assert(id);
119
Radek Krejci6dc53a22015-08-17 13:27:59 +0200120 if (!isalpha(id[0]) && (id[0] != '_')) {
121 return -parsed;
122 }
123
124 ++parsed;
125 ++id;
126
127 while (isalnum(id[0]) || (id[0] == '_') || (id[0] == '-') || (id[0] == '.')) {
128 ++parsed;
129 ++id;
130 }
131
132 return parsed;
133}
134
135/**
136 * @brief Parse a node-identifier.
137 *
Michal Vasko723e50c2015-10-20 15:20:29 +0200138 * node-identifier = [module-name ":"] identifier
Radek Krejci6dc53a22015-08-17 13:27:59 +0200139 *
Michal Vaskobb211122015-08-19 14:03:11 +0200140 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200141 * @param[out] mod_name Points to the module name, NULL if there is not any.
142 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200143 * @param[out] name Points to the node name.
144 * @param[out] nam_len Length of the node name.
145 *
146 * @return Number of characters successfully parsed,
147 * positive on success, negative on failure.
148 */
149static int
Michal Vasko723e50c2015-10-20 15:20:29 +0200150parse_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 +0200151{
152 int parsed = 0, ret;
153
154 assert(id);
Michal Vasko723e50c2015-10-20 15:20:29 +0200155 if (mod_name) {
156 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200157 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200158 if (mod_name_len) {
159 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200160 }
161 if (name) {
162 *name = NULL;
163 }
164 if (nam_len) {
165 *nam_len = 0;
166 }
167
168 if ((ret = parse_identifier(id)) < 1) {
169 return ret;
170 }
171
Michal Vasko723e50c2015-10-20 15:20:29 +0200172 if (mod_name) {
173 *mod_name = id;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200174 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200175 if (mod_name_len) {
176 *mod_name_len = ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200177 }
178
179 parsed += ret;
180 id += ret;
181
182 /* there is prefix */
183 if (id[0] == ':') {
184 ++parsed;
185 ++id;
186
187 /* there isn't */
188 } else {
Michal Vasko723e50c2015-10-20 15:20:29 +0200189 if (name && mod_name) {
190 *name = *mod_name;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200191 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200192 if (mod_name) {
193 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200194 }
195
Michal Vasko723e50c2015-10-20 15:20:29 +0200196 if (nam_len && mod_name_len) {
197 *nam_len = *mod_name_len;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200198 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200199 if (mod_name_len) {
200 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200201 }
202
203 return parsed;
204 }
205
206 /* identifier (node name) */
207 if ((ret = parse_identifier(id)) < 1) {
208 return -parsed+ret;
209 }
210
211 if (name) {
212 *name = id;
213 }
214 if (nam_len) {
215 *nam_len = ret;
216 }
217
218 return parsed+ret;
219}
220
221/**
222 * @brief Parse a path-predicate (leafref).
223 *
224 * path-predicate = "[" *WSP path-equality-expr *WSP "]"
225 * path-equality-expr = node-identifier *WSP "=" *WSP path-key-expr
226 *
Michal Vaskobb211122015-08-19 14:03:11 +0200227 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200228 * @param[out] prefix Points to the prefix, NULL if there is not any.
229 * @param[out] pref_len Length of the prefix, 0 if there is not any.
230 * @param[out] name Points to the node name.
231 * @param[out] nam_len Length of the node name.
232 * @param[out] path_key_expr Points to the path-key-expr.
233 * @param[out] pke_len Length of the path-key-expr.
234 * @param[out] has_predicate Flag to mark whether there is another predicate following.
235 *
236 * @return Number of characters successfully parsed,
237 * positive on success, negative on failure.
238 */
239static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200240parse_path_predicate(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
241 const char **path_key_expr, int *pke_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200242{
243 const char *ptr;
244 int parsed = 0, ret;
245
246 assert(id);
247 if (prefix) {
248 *prefix = NULL;
249 }
250 if (pref_len) {
251 *pref_len = 0;
252 }
253 if (name) {
254 *name = NULL;
255 }
256 if (nam_len) {
257 *nam_len = 0;
258 }
259 if (path_key_expr) {
260 *path_key_expr = NULL;
261 }
262 if (pke_len) {
263 *pke_len = 0;
264 }
265 if (has_predicate) {
266 *has_predicate = 0;
267 }
268
269 if (id[0] != '[') {
270 return -parsed;
271 }
272
273 ++parsed;
274 ++id;
275
276 while (isspace(id[0])) {
277 ++parsed;
278 ++id;
279 }
280
281 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
282 return -parsed+ret;
283 }
284
285 parsed += ret;
286 id += ret;
287
288 while (isspace(id[0])) {
289 ++parsed;
290 ++id;
291 }
292
293 if (id[0] != '=') {
294 return -parsed;
295 }
296
297 ++parsed;
298 ++id;
299
300 while (isspace(id[0])) {
301 ++parsed;
302 ++id;
303 }
304
305 if ((ptr = strchr(id, ']')) == NULL) {
306 return -parsed;
307 }
308
309 --ptr;
310 while (isspace(ptr[0])) {
311 --ptr;
312 }
313 ++ptr;
314
315 ret = ptr-id;
316 if (path_key_expr) {
317 *path_key_expr = id;
318 }
319 if (pke_len) {
320 *pke_len = ret;
321 }
322
323 parsed += ret;
324 id += ret;
325
326 while (isspace(id[0])) {
327 ++parsed;
328 ++id;
329 }
330
331 assert(id[0] == ']');
332
333 if (id[1] == '[') {
334 *has_predicate = 1;
335 }
336
337 return parsed+1;
338}
339
340/**
341 * @brief Parse a path-key-expr (leafref). First call parses "current()", all
342 * the ".." and the first node-identifier, other calls parse a single
343 * node-identifier each.
344 *
345 * path-key-expr = current-function-invocation *WSP "/" *WSP
346 * rel-path-keyexpr
347 * rel-path-keyexpr = 1*(".." *WSP "/" *WSP)
348 * *(node-identifier *WSP "/" *WSP)
349 * node-identifier
350 *
Michal Vaskobb211122015-08-19 14:03:11 +0200351 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200352 * @param[out] prefix Points to the prefix, NULL if there is not any.
353 * @param[out] pref_len Length of the prefix, 0 if there is not any.
354 * @param[out] name Points to the node name.
355 * @param[out] nam_len Length of the node name.
356 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
357 * must not be changed between consecutive calls.
358 * @return Number of characters successfully parsed,
359 * positive on success, negative on failure.
360 */
361static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200362parse_path_key_expr(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
363 int *parent_times)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200364{
365 int parsed = 0, ret, par_times = 0;
366
367 assert(id);
368 assert(parent_times);
369 if (prefix) {
370 *prefix = NULL;
371 }
372 if (pref_len) {
373 *pref_len = 0;
374 }
375 if (name) {
376 *name = NULL;
377 }
378 if (nam_len) {
379 *nam_len = 0;
380 }
381
382 if (!*parent_times) {
383 /* current-function-invocation *WSP "/" *WSP rel-path-keyexpr */
384 if (strncmp(id, "current()", 9)) {
385 return -parsed;
386 }
387
388 parsed += 9;
389 id += 9;
390
391 while (isspace(id[0])) {
392 ++parsed;
393 ++id;
394 }
395
396 if (id[0] != '/') {
397 return -parsed;
398 }
399
400 ++parsed;
401 ++id;
402
403 while (isspace(id[0])) {
404 ++parsed;
405 ++id;
406 }
407
408 /* rel-path-keyexpr */
409 if (strncmp(id, "..", 2)) {
410 return -parsed;
411 }
412 ++par_times;
413
414 parsed += 2;
415 id += 2;
416
417 while (isspace(id[0])) {
418 ++parsed;
419 ++id;
420 }
421 }
422
423 /* 1*(".." *WSP "/" *WSP) *(node-identifier *WSP "/" *WSP) node-identifier
424 *
425 * first parent reference with whitespaces already parsed
426 */
427 if (id[0] != '/') {
428 return -parsed;
429 }
430
431 ++parsed;
432 ++id;
433
434 while (isspace(id[0])) {
435 ++parsed;
436 ++id;
437 }
438
439 while (!strncmp(id, "..", 2) && !*parent_times) {
440 ++par_times;
441
442 parsed += 2;
443 id += 2;
444
445 while (isspace(id[0])) {
446 ++parsed;
447 ++id;
448 }
449
450 if (id[0] != '/') {
451 return -parsed;
452 }
453
454 ++parsed;
455 ++id;
456
457 while (isspace(id[0])) {
458 ++parsed;
459 ++id;
460 }
461 }
462
463 if (!*parent_times) {
464 *parent_times = par_times;
465 }
466
467 /* all parent references must be parsed at this point */
468 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
469 return -parsed+ret;
470 }
471
472 parsed += ret;
473 id += ret;
474
475 return parsed;
476}
477
478/**
479 * @brief Parse path-arg (leafref).
480 *
481 * path-arg = absolute-path / relative-path
482 * absolute-path = 1*("/" (node-identifier *path-predicate))
483 * relative-path = 1*(".." "/") descendant-path
484 *
Michal Vaskobb211122015-08-19 14:03:11 +0200485 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200486 * @param[out] prefix Points to the prefix, NULL if there is not any.
487 * @param[out] pref_len Length of the prefix, 0 if there is not any.
488 * @param[out] name Points to the node name.
489 * @param[out] nam_len Length of the node name.
490 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
491 * must not be changed between consecutive calls. -1 if the
492 * path is relative.
493 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
494 *
495 * @return Number of characters successfully parsed,
496 * positive on success, negative on failure.
497 */
498static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200499parse_path_arg(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len, int *parent_times,
500 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200501{
502 int parsed = 0, ret, par_times = 0;
503
504 assert(id);
505 assert(parent_times);
506 if (prefix) {
507 *prefix = NULL;
508 }
509 if (pref_len) {
510 *pref_len = 0;
511 }
512 if (name) {
513 *name = NULL;
514 }
515 if (nam_len) {
516 *nam_len = 0;
517 }
518 if (has_predicate) {
519 *has_predicate = 0;
520 }
521
522 if (!*parent_times && !strncmp(id, "..", 2)) {
523 ++par_times;
524
525 parsed += 2;
526 id += 2;
527
528 while (!strncmp(id, "/..", 3)) {
529 ++par_times;
530
531 parsed += 3;
532 id += 3;
533 }
534 }
535
536 if (!*parent_times) {
537 if (par_times) {
538 *parent_times = par_times;
539 } else {
540 *parent_times = -1;
541 }
542 }
543
544 if (id[0] != '/') {
545 return -parsed;
546 }
547
548 /* skip '/' */
549 ++parsed;
550 ++id;
551
552 /* node-identifier ([prefix:]identifier) */
553 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
554 return -parsed-ret;
555 }
556
557 parsed += ret;
558 id += ret;
559
560 /* there is no predicate */
561 if ((id[0] == '/') || !id[0]) {
562 return parsed;
563 } else if (id[0] != '[') {
564 return -parsed;
565 }
566
567 if (has_predicate) {
568 *has_predicate = 1;
569 }
570
571 return parsed;
572}
573
574/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200575 * @brief Parse instance-identifier in JSON data format. That means that prefixes
Michal Vaskob2f40be2016-09-08 16:03:48 +0200576 * (which are mandatory for every node-identifier) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200577 *
578 * instance-identifier = 1*("/" (node-identifier *predicate))
579 *
Michal Vaskobb211122015-08-19 14:03:11 +0200580 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200581 * @param[out] model Points to the model name.
582 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200583 * @param[out] name Points to the node name.
584 * @param[out] nam_len Length of the node name.
585 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
586 *
587 * @return Number of characters successfully parsed,
588 * positive on success, negative on failure.
589 */
590static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200591parse_instance_identifier(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
592 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200593{
594 int parsed = 0, ret;
595
Radek Krejci6dc53a22015-08-17 13:27:59 +0200596 if (has_predicate) {
597 *has_predicate = 0;
598 }
599
600 if (id[0] != '/') {
601 return -parsed;
602 }
603
604 ++parsed;
605 ++id;
606
Michal Vaskob2f40be2016-09-08 16:03:48 +0200607 if ((ret = parse_identifier(id)) < 1) {
608 return ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200609 }
610
Michal Vaskob2f40be2016-09-08 16:03:48 +0200611 *model = id;
612 *mod_len = ret;
613
Radek Krejci6dc53a22015-08-17 13:27:59 +0200614 parsed += ret;
615 id += ret;
616
Michal Vaskob2f40be2016-09-08 16:03:48 +0200617 if (id[0] != ':') {
618 return -parsed;
619 }
620
621 ++parsed;
622 ++id;
623
624 if ((ret = parse_identifier(id)) < 1) {
625 return ret;
626 }
627
628 *name = id;
629 *nam_len = ret;
630
631 parsed += ret;
632 id += ret;
633
Radek Krejci4967cb62016-09-14 16:40:28 +0200634 if (id[0] == '[' && has_predicate) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200635 *has_predicate = 1;
636 }
637
638 return parsed;
639}
640
641/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200642 * @brief Parse predicate (instance-identifier) in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200643 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200644 *
645 * predicate = "[" *WSP (predicate-expr / pos) *WSP "]"
646 * predicate-expr = (node-identifier / ".") *WSP "=" *WSP
647 * ((DQUOTE string DQUOTE) /
648 * (SQUOTE string SQUOTE))
649 * pos = non-negative-integer-value
650 *
Michal Vaskobb211122015-08-19 14:03:11 +0200651 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200652 * @param[out] model Points to the model name.
653 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200654 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
655 * @param[out] nam_len Length of the node name.
656 * @param[out] value Value the node-identifier must have (string from the grammar),
657 * NULL if there is not any.
658 * @param[out] val_len Length of the value, 0 if there is not any.
659 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
660 *
661 * @return Number of characters successfully parsed,
662 * positive on success, negative on failure.
663 */
664static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200665parse_predicate(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
666 const char **value, int *val_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200667{
668 const char *ptr;
669 int parsed = 0, ret;
670 char quote;
671
672 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200673 if (model) {
674 *model = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200675 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200676 if (mod_len) {
677 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200678 }
679 if (name) {
680 *name = NULL;
681 }
682 if (nam_len) {
683 *nam_len = 0;
684 }
685 if (value) {
686 *value = NULL;
687 }
688 if (val_len) {
689 *val_len = 0;
690 }
691 if (has_predicate) {
692 *has_predicate = 0;
693 }
694
695 if (id[0] != '[') {
696 return -parsed;
697 }
698
699 ++parsed;
700 ++id;
701
702 while (isspace(id[0])) {
703 ++parsed;
704 ++id;
705 }
706
707 /* pos */
708 if (isdigit(id[0])) {
709 if (name) {
710 *name = id;
711 }
712
713 if (id[0] == '0') {
Michal Vaskof2f28a12016-09-09 12:43:06 +0200714 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200715 }
716
717 while (isdigit(id[0])) {
718 ++parsed;
719 ++id;
720 }
721
722 if (nam_len) {
723 *nam_len = id-(*name);
724 }
725
Michal Vaskof2f28a12016-09-09 12:43:06 +0200726 /* "." or node-identifier */
Radek Krejci6dc53a22015-08-17 13:27:59 +0200727 } else {
Michal Vaskof2f28a12016-09-09 12:43:06 +0200728 if (id[0] == '.') {
729 if (name) {
730 *name = id;
731 }
732 if (nam_len) {
733 *nam_len = 1;
734 }
735
736 ++parsed;
737 ++id;
738
739 } else {
740 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
741 return -parsed+ret;
742 } else if (model && !*model) {
743 return -parsed;
744 }
745
746 parsed += ret;
747 id += ret;
748 }
749
750 while (isspace(id[0])) {
751 ++parsed;
752 ++id;
753 }
754
755 if (id[0] != '=') {
Michal Vasko1f2cc332015-08-19 11:18:32 +0200756 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200757 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200758
Radek Krejci6dc53a22015-08-17 13:27:59 +0200759 ++parsed;
760 ++id;
761
Michal Vaskof2f28a12016-09-09 12:43:06 +0200762 while (isspace(id[0])) {
763 ++parsed;
764 ++id;
765 }
766
767 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
768 if ((id[0] == '\"') || (id[0] == '\'')) {
769 quote = id[0];
770
771 ++parsed;
772 ++id;
773
774 if ((ptr = strchr(id, quote)) == NULL) {
775 return -parsed;
776 }
777 ret = ptr-id;
778
779 if (value) {
780 *value = id;
781 }
782 if (val_len) {
783 *val_len = ret;
784 }
785
786 parsed += ret+1;
787 id += ret+1;
788 } else {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200789 return -parsed;
790 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200791 }
792
793 while (isspace(id[0])) {
794 ++parsed;
795 ++id;
796 }
797
798 if (id[0] != ']') {
799 return -parsed;
800 }
801
802 ++parsed;
803 ++id;
804
805 if ((id[0] == '[') && has_predicate) {
806 *has_predicate = 1;
807 }
808
809 return parsed;
810}
811
812/**
813 * @brief Parse schema-nodeid.
814 *
815 * schema-nodeid = absolute-schema-nodeid /
816 * descendant-schema-nodeid
817 * absolute-schema-nodeid = 1*("/" node-identifier)
Michal Vasko48935352016-03-29 11:52:36 +0200818 * descendant-schema-nodeid = ["." "/"]
Radek Krejci6dc53a22015-08-17 13:27:59 +0200819 * node-identifier
820 * absolute-schema-nodeid
821 *
Michal Vaskobb211122015-08-19 14:03:11 +0200822 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200823 * @param[out] mod_name Points to the module name, NULL if there is not any.
824 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Michal Vasko48935352016-03-29 11:52:36 +0200825 * @param[out] name Points to the node name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200826 * @param[out] nam_len Length of the node name.
827 * @param[out] is_relative Flag to mark whether the nodeid is absolute or descendant. Must be -1
828 * on the first call, must not be changed between consecutive calls.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100829 * @param[out] has_predicate Flag to mark whether there is a predicate specified. It cannot be
830 * based on the grammar, in those cases use NULL.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200831 *
832 * @return Number of characters successfully parsed,
833 * positive on success, negative on failure.
834 */
Michal Vasko22448d32016-03-16 13:17:29 +0100835int
Michal Vasko723e50c2015-10-20 15:20:29 +0200836parse_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 +0100837 int *is_relative, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200838{
839 int parsed = 0, ret;
840
841 assert(id);
842 assert(is_relative);
Michal Vasko723e50c2015-10-20 15:20:29 +0200843 if (mod_name) {
844 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200845 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200846 if (mod_name_len) {
847 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200848 }
849 if (name) {
850 *name = NULL;
851 }
852 if (nam_len) {
853 *nam_len = 0;
854 }
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100855 if (has_predicate) {
856 *has_predicate = 0;
857 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200858
859 if (id[0] != '/') {
860 if (*is_relative != -1) {
861 return -parsed;
862 } else {
863 *is_relative = 1;
864 }
Michal Vasko48935352016-03-29 11:52:36 +0200865 if (!strncmp(id, "./", 2)) {
866 parsed += 2;
867 id += 2;
868 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200869 } else {
870 if (*is_relative == -1) {
871 *is_relative = 0;
872 }
873 ++parsed;
874 ++id;
875 }
876
Michal Vasko723e50c2015-10-20 15:20:29 +0200877 if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200878 return -parsed+ret;
879 }
880
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100881 parsed += ret;
882 id += ret;
883
884 if ((id[0] == '[') && has_predicate) {
885 *has_predicate = 1;
886 }
887
888 return parsed;
889}
890
891/**
892 * @brief Parse schema predicate (special format internally used).
893 *
894 * predicate = "[" *WSP predicate-expr *WSP "]"
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200895 * predicate-expr = "." / identifier / key-with-value
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100896 * key-with-value = identifier *WSP "=" *WSP
897 * ((DQUOTE string DQUOTE) /
898 * (SQUOTE string SQUOTE))
899 *
900 * @param[in] id Identifier to use.
901 * @param[out] name Points to the list key name.
902 * @param[out] nam_len Length of \p name.
Michal Vasko22448d32016-03-16 13:17:29 +0100903 * @param[out] value Points to the key value. If specified, key-with-value is expected.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100904 * @param[out] val_len Length of \p value.
905 * @param[out] has_predicate Flag to mark whether there is another predicate specified.
906 */
Michal Vasko22448d32016-03-16 13:17:29 +0100907int
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200908parse_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 +0100909 int *has_predicate)
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100910{
911 const char *ptr;
912 int parsed = 0, ret;
913 char quote;
914
915 assert(id);
916 if (name) {
917 *name = NULL;
918 }
919 if (nam_len) {
920 *nam_len = 0;
921 }
922 if (value) {
923 *value = NULL;
924 }
925 if (val_len) {
926 *val_len = 0;
927 }
928 if (has_predicate) {
929 *has_predicate = 0;
930 }
931
932 if (id[0] != '[') {
933 return -parsed;
934 }
935
936 ++parsed;
937 ++id;
938
939 while (isspace(id[0])) {
940 ++parsed;
941 ++id;
942 }
943
Michal Vasko22448d32016-03-16 13:17:29 +0100944 /* identifier */
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200945 if (id[0] == '.') {
946 ret = 1;
947 } else if ((ret = parse_identifier(id)) < 1) {
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100948 return -parsed + ret;
949 }
950 if (name) {
951 *name = id;
952 }
953 if (nam_len) {
954 *nam_len = ret;
955 }
956
957 parsed += ret;
958 id += ret;
959
960 while (isspace(id[0])) {
961 ++parsed;
962 ++id;
963 }
964
965 /* there is value as well */
966 if (id[0] == '=') {
967 ++parsed;
968 ++id;
969
970 while (isspace(id[0])) {
971 ++parsed;
972 ++id;
973 }
974
975 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
976 if ((id[0] == '\"') || (id[0] == '\'')) {
977 quote = id[0];
978
979 ++parsed;
980 ++id;
981
982 if ((ptr = strchr(id, quote)) == NULL) {
983 return -parsed;
984 }
985 ret = ptr - id;
986
987 if (value) {
988 *value = id;
989 }
990 if (val_len) {
991 *val_len = ret;
992 }
993
994 parsed += ret + 1;
995 id += ret + 1;
996 } else {
997 return -parsed;
998 }
999
1000 while (isspace(id[0])) {
1001 ++parsed;
1002 ++id;
1003 }
Michal Vasko22448d32016-03-16 13:17:29 +01001004 } else if (value) {
1005 /* if value was expected, it's mandatory */
1006 return -parsed;
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001007 }
1008
1009 if (id[0] != ']') {
1010 return -parsed;
1011 }
1012
1013 ++parsed;
1014 ++id;
1015
1016 if ((id[0] == '[') && has_predicate) {
1017 *has_predicate = 1;
1018 }
1019
1020 return parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +02001021}
1022
1023/**
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001024 * @brief Resolve (find) a feature definition. Logs directly.
1025 *
1026 * @param[in] feat_name Feature name to resolve.
1027 * @param[in] len Length of \p feat_name.
1028 * @param[in] node Node with the if-feature expression.
Radek Krejci9ff0a922016-07-14 13:08:05 +02001029 * @param[out] feature Pointer to be set to point to the feature definition, if feature not found
1030 * (return code 1), the pointer is untouched.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001031 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02001032 * @return 0 on success, 1 on forward reference, -1 on error.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001033 */
1034static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001035resolve_feature(const char *feat_name, uint16_t len, const struct lys_node *node, struct lys_feature **feature)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001036{
1037 char *str;
1038 const char *mod_name, *name;
1039 int mod_name_len, nam_len, i, j;
1040 const struct lys_module *module;
1041
Radek Krejci9ff0a922016-07-14 13:08:05 +02001042 assert(feature);
1043
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001044 /* check prefix */
1045 if ((i = parse_node_identifier(feat_name, &mod_name, &mod_name_len, &name, &nam_len)) < 1) {
1046 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, feat_name[-i], &feat_name[-i]);
1047 return -1;
1048 }
1049
1050 module = lys_get_import_module(lys_node_module(node), NULL, 0, mod_name, mod_name_len);
1051 if (!module) {
1052 /* identity refers unknown data model */
1053 LOGVAL(LYE_INMOD_LEN, LY_VLOG_NONE, NULL, mod_name_len, mod_name);
1054 return -1;
1055 }
1056
Radek Krejci9ff0a922016-07-14 13:08:05 +02001057 if (module != node->module && module == lys_node_module(node)) {
1058 /* first, try to search directly in submodule where the feature was mentioned */
1059 for (j = 0; j < node->module->features_size; j++) {
1060 if (!strncmp(name, node->module->features[j].name, nam_len) && !node->module->features[j].name[nam_len]) {
1061 /* check status */
1062 if (lyp_check_status(node->flags, lys_node_module(node), node->name, node->module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001063 node->module->features[j].module, node->module->features[j].name, NULL)) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001064 return -1;
1065 }
1066 *feature = &node->module->features[j];
1067 return 0;
1068 }
1069 }
1070 }
1071
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001072 /* search in the identified module ... */
1073 for (j = 0; j < module->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001074 if (!strncmp(name, module->features[j].name, nam_len) && !module->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001075 /* check status */
1076 if (lyp_check_status(node->flags, lys_node_module(node), node->name, module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001077 module->features[j].module, module->features[j].name, NULL)) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001078 return -1;
1079 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001080 *feature = &module->features[j];
1081 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001082 }
1083 }
1084 /* ... and all its submodules */
1085 for (i = 0; i < module->inc_size; i++) {
1086 if (!module->inc[i].submodule) {
1087 /* not yet resolved */
1088 continue;
1089 }
1090 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001091 if (!strncmp(name, module->inc[i].submodule->features[j].name, nam_len)
1092 && !module->inc[i].submodule->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001093 /* check status */
1094 if (lyp_check_status(node->flags, lys_node_module(node), node->name,
1095 module->inc[i].submodule->features[j].flags,
1096 module->inc[i].submodule->features[j].module,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001097 module->inc[i].submodule->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->inc[i].submodule->features[j];
1101 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001102 }
1103 }
1104 }
1105
1106 /* not found */
1107 str = strndup(feat_name, len);
1108 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, "feature", str);
1109 free(str);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001110 return 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001111}
1112
Radek Krejci9ff0a922016-07-14 13:08:05 +02001113/*
1114 * @return
Radek Krejci69b8d922016-07-27 13:13:41 +02001115 * - 1 if enabled
1116 * - 0 if disabled
Radek Krejci9ff0a922016-07-14 13:08:05 +02001117 * - -1 if not usable by its if-feature expression
1118 */
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001119static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001120resolve_feature_value(const struct lys_feature *feat)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001121{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001122 int i;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001123
Radek Krejci9ff0a922016-07-14 13:08:05 +02001124 for (i = 0; i < feat->iffeature_size; i++) {
Radek Krejci69b8d922016-07-27 13:13:41 +02001125 if (!resolve_iffeature(&feat->iffeature[i])) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001126 return -1;
1127 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001128 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001129
Radek Krejci69b8d922016-07-27 13:13:41 +02001130 return feat->flags & LYS_FENABLED ? 1 : 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001131}
1132
1133static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001134resolve_iffeature_recursive(struct lys_iffeature *expr, int *index_e, int *index_f)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001135{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001136 uint8_t op;
1137 int rc, a, b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001138
Radek Krejci9ff0a922016-07-14 13:08:05 +02001139 op = iff_getop(expr->expr, *index_e);
1140 (*index_e)++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001141
Radek Krejci9ff0a922016-07-14 13:08:05 +02001142 switch (op) {
1143 case LYS_IFF_F:
1144 /* resolve feature */
1145 return resolve_feature_value(expr->features[(*index_f)++]);
1146 case LYS_IFF_NOT:
1147 rc = resolve_iffeature_recursive(expr, index_e, index_f);
1148 if (rc == -1) {
1149 /* one of the referenced feature is hidden by its if-feature,
1150 * so this if-feature expression is always false */
1151 return -1;
1152 } else {
1153 /* invert result */
1154 return rc ? 0 : 1;
1155 }
1156 case LYS_IFF_AND:
1157 case LYS_IFF_OR:
1158 a = resolve_iffeature_recursive(expr, index_e, index_f);
1159 b = resolve_iffeature_recursive(expr, index_e, index_f);
1160 if (a == -1 || b == -1) {
1161 /* one of the referenced feature is hidden by its if-feature,
1162 * so this if-feature expression is always false */
1163 return -1;
1164 } else if (op == LYS_IFF_AND) {
1165 return a && b;
1166 } else { /* LYS_IFF_OR */
1167 return a || b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001168 }
1169 }
1170
Radek Krejci9ff0a922016-07-14 13:08:05 +02001171 return -1;
1172}
1173
1174int
1175resolve_iffeature(struct lys_iffeature *expr)
1176{
1177 int rc = -1;
1178 int index_e = 0, index_f = 0;
1179
1180 if (expr->expr) {
1181 rc = resolve_iffeature_recursive(expr, &index_e, &index_f);
1182 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001183 return (rc == 1) ? 1 : 0;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001184}
1185
1186struct iff_stack {
1187 int size;
1188 int index; /* first empty item */
1189 uint8_t *stack;
1190};
1191
1192static int
1193iff_stack_push(struct iff_stack *stack, uint8_t value)
1194{
1195 if (stack->index == stack->size) {
1196 stack->size += 4;
1197 stack->stack = ly_realloc(stack->stack, stack->size * sizeof *stack->stack);
1198 if (!stack->stack) {
1199 LOGMEM;
1200 stack->size = 0;
1201 return EXIT_FAILURE;
1202 }
1203 }
1204
1205 stack->stack[stack->index++] = value;
1206 return EXIT_SUCCESS;
1207}
1208
1209static uint8_t
1210iff_stack_pop(struct iff_stack *stack)
1211{
1212 stack->index--;
1213 return stack->stack[stack->index];
1214}
1215
1216static void
1217iff_stack_clean(struct iff_stack *stack)
1218{
1219 stack->size = 0;
1220 free(stack->stack);
1221}
1222
1223static void
1224iff_setop(uint8_t *list, uint8_t op, int pos)
1225{
1226 uint8_t *item;
1227 uint8_t mask = 3;
1228
1229 assert(pos >= 0);
1230 assert(op <= 3); /* max 2 bits */
1231
1232 item = &list[pos / 4];
1233 mask = mask << 2 * (pos % 4);
1234 *item = (*item) & ~mask;
1235 *item = (*item) | (op << 2 * (pos % 4));
1236}
1237
1238uint8_t
1239iff_getop(uint8_t *list, int pos)
1240{
1241 uint8_t *item;
1242 uint8_t mask = 3, result;
1243
1244 assert(pos >= 0);
1245
1246 item = &list[pos / 4];
1247 result = (*item) & (mask << 2 * (pos % 4));
1248 return result >> 2 * (pos % 4);
1249}
1250
1251#define LYS_IFF_LP 0x04 /* ( */
1252#define LYS_IFF_RP 0x08 /* ) */
1253
Radek Krejcicbb473e2016-09-16 14:48:32 +02001254/* internal structure for passing data for UNRES_IFFEAT */
1255struct unres_iffeat_data {
1256 struct lys_node *node;
1257 const char *fname;
Radek Krejci9de2c042016-10-19 16:53:06 +02001258 int infeature;
Radek Krejcicbb473e2016-09-16 14:48:32 +02001259};
1260
Radek Krejci9ff0a922016-07-14 13:08:05 +02001261void
1262resolve_iffeature_getsizes(struct lys_iffeature *iffeat, unsigned int *expr_size, unsigned int *feat_size)
1263{
1264 unsigned int e = 0, f = 0, r = 0;
1265 uint8_t op;
1266
1267 assert(iffeat);
1268
1269 if (!iffeat->expr) {
1270 goto result;
1271 }
1272
1273 do {
1274 op = iff_getop(iffeat->expr, e++);
1275 switch (op) {
1276 case LYS_IFF_NOT:
1277 if (!r) {
1278 r += 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001279 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001280 break;
1281 case LYS_IFF_AND:
1282 case LYS_IFF_OR:
1283 if (!r) {
1284 r += 2;
1285 } else {
1286 r += 1;
1287 }
1288 break;
1289 case LYS_IFF_F:
1290 f++;
1291 if (r) {
1292 r--;
1293 }
1294 break;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001295 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001296 } while(r);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001297
Radek Krejci9ff0a922016-07-14 13:08:05 +02001298result:
1299 if (expr_size) {
1300 *expr_size = e;
1301 }
1302 if (feat_size) {
1303 *feat_size = f;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001304 }
1305}
1306
1307int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001308resolve_iffeature_compile(struct lys_iffeature *iffeat_expr, const char *value, struct lys_node *node,
Radek Krejci9de2c042016-10-19 16:53:06 +02001309 int infeature, struct unres_schema *unres)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001310{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001311 const char *c = value;
1312 int r, rc = EXIT_FAILURE;
Radek Krejci69b8d922016-07-27 13:13:41 +02001313 int i, j, last_not, checkversion = 0;
1314 unsigned int f_size = 0, expr_size = 0, f_exp = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001315 uint8_t op;
1316 struct iff_stack stack = {0, 0, NULL};
Radek Krejcicbb473e2016-09-16 14:48:32 +02001317 struct unres_iffeat_data *iff_data;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001318
Radek Krejci9ff0a922016-07-14 13:08:05 +02001319 assert(c);
1320
1321 if (isspace(c[0])) {
1322 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, c[0], c);
1323 return EXIT_FAILURE;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001324 }
1325
Radek Krejci9ff0a922016-07-14 13:08:05 +02001326 /* pre-parse the expression to get sizes for arrays, also do some syntax checks of the expression */
1327 for (i = j = last_not = 0; c[i]; i++) {
1328 if (c[i] == '(') {
Radek Krejci69b8d922016-07-27 13:13:41 +02001329 checkversion = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001330 j++;
1331 continue;
1332 } else if (c[i] == ')') {
1333 j--;
1334 continue;
1335 } else if (isspace(c[i])) {
1336 continue;
1337 }
1338
1339 if (!strncmp(&c[i], "not", r = 3) || !strncmp(&c[i], "and", r = 3) || !strncmp(&c[i], "or", r = 2)) {
1340 if (c[i + r] == '\0') {
Radek Krejcia98da3f2016-07-27 14:05:22 +02001341 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
Radek Krejci9ff0a922016-07-14 13:08:05 +02001342 return EXIT_FAILURE;
1343 } else if (!isspace(c[i + r])) {
1344 /* feature name starting with the not/and/or */
1345 last_not = 0;
1346 f_size++;
1347 } else if (c[i] == 'n') { /* not operation */
1348 if (last_not) {
1349 /* double not */
1350 expr_size = expr_size - 2;
1351 last_not = 0;
1352 } else {
1353 last_not = 1;
1354 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001355 } else { /* and, or */
1356 f_exp++;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001357 /* not a not operation */
1358 last_not = 0;
1359 }
1360 i += r;
1361 } else {
1362 f_size++;
1363 last_not = 0;
1364 }
1365 expr_size++;
1366
1367 while (!isspace(c[i])) {
1368 if (!c[i] || c[i] == ')') {
1369 i--;
1370 break;
1371 }
1372 i++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001373 }
1374 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001375 if (j || f_exp != f_size) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001376 /* not matching count of ( and ) */
1377 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1378 return EXIT_FAILURE;
1379 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001380
Radek Krejci69b8d922016-07-27 13:13:41 +02001381 if (checkversion || expr_size > 1) {
1382 /* check that we have 1.1 module */
1383 if (node->module->version != 2) {
1384 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1385 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "YANG 1.1 if-feature expression found in 1.0 module.");
1386 return EXIT_FAILURE;
1387 }
1388 }
1389
Radek Krejci9ff0a922016-07-14 13:08:05 +02001390 /* allocate the memory */
1391 iffeat_expr->expr = calloc((j = (expr_size / 4) + ((expr_size % 4) ? 1 : 0)), sizeof *iffeat_expr->expr);
Radek Krejcicbb473e2016-09-16 14:48:32 +02001392 iffeat_expr->features = calloc(f_size, sizeof *iffeat_expr->features);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001393 stack.size = expr_size;
1394 stack.stack = malloc(expr_size * sizeof *stack.stack);
1395 if (!stack.stack || !iffeat_expr->expr || !iffeat_expr->features) {
1396 LOGMEM;
1397 goto error;
1398 }
1399 f_size--; expr_size--; /* used as indexes from now */
1400
1401 for (i--; i >= 0; i--) {
1402 if (c[i] == ')') {
1403 /* push it on stack */
1404 iff_stack_push(&stack, LYS_IFF_RP);
1405 continue;
1406 } else if (c[i] == '(') {
1407 /* pop from the stack into result all operators until ) */
1408 while((op = iff_stack_pop(&stack)) != LYS_IFF_RP) {
1409 iff_setop(iffeat_expr->expr, op, expr_size--);
1410 }
1411 continue;
1412 } else if (isspace(c[i])) {
1413 continue;
1414 }
1415
1416 /* end operator or operand -> find beginning and get what is it */
1417 j = i + 1;
1418 while (i >= 0 && !isspace(c[i]) && c[i] != '(') {
1419 i--;
1420 }
1421 i++; /* get back by one step */
1422
1423 if (!strncmp(&c[i], "not ", 4)) {
1424 if (stack.index && stack.stack[stack.index - 1] == LYS_IFF_NOT) {
1425 /* double not */
1426 iff_stack_pop(&stack);
1427 } else {
1428 /* not has the highest priority, so do not pop from the stack
1429 * as in case of AND and OR */
1430 iff_stack_push(&stack, LYS_IFF_NOT);
1431 }
1432 } else if (!strncmp(&c[i], "and ", 4)) {
1433 /* as for OR - pop from the stack all operators with the same or higher
1434 * priority and store them to the result, then push the AND to the stack */
1435 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_AND) {
1436 op = iff_stack_pop(&stack);
1437 iff_setop(iffeat_expr->expr, op, expr_size--);
1438 }
1439 iff_stack_push(&stack, LYS_IFF_AND);
1440 } else if (!strncmp(&c[i], "or ", 3)) {
1441 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_OR) {
1442 op = iff_stack_pop(&stack);
1443 iff_setop(iffeat_expr->expr, op, expr_size--);
1444 }
1445 iff_stack_push(&stack, LYS_IFF_OR);
1446 } else {
1447 /* feature name, length is j - i */
1448
1449 /* add it to the result */
1450 iff_setop(iffeat_expr->expr, LYS_IFF_F, expr_size--);
1451
1452 /* now get the link to the feature definition. Since it can be
Radek Krejcicbb473e2016-09-16 14:48:32 +02001453 * forward referenced, we have to keep the feature name in auxiliary
1454 * structure passed into unres */
1455 iff_data = malloc(sizeof *iff_data);
1456 iff_data->node = node;
1457 iff_data->fname = lydict_insert(node->module->ctx, &c[i], j - i);
Radek Krejci9de2c042016-10-19 16:53:06 +02001458 iff_data->infeature = infeature;
Radek Krejcicbb473e2016-09-16 14:48:32 +02001459 r = unres_schema_add_node(node->module, unres, &iffeat_expr->features[f_size], UNRES_IFFEAT,
1460 (struct lys_node *)iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001461 f_size--;
1462
1463 if (r == -1) {
Pavol Vican4d084512016-09-29 16:38:12 +02001464 free(iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001465 goto error;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001466 }
1467 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001468 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001469 while (stack.index) {
1470 op = iff_stack_pop(&stack);
1471 iff_setop(iffeat_expr->expr, op, expr_size--);
1472 }
1473
1474 if (++expr_size || ++f_size) {
1475 /* not all expected operators and operands found */
1476 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1477 rc = EXIT_FAILURE;
1478 } else {
1479 rc = EXIT_SUCCESS;
1480 }
1481
1482error:
1483 /* cleanup */
1484 iff_stack_clean(&stack);
1485
1486 return rc;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001487}
1488
1489/**
Michal Vasko3edeaf72016-02-11 13:17:43 +01001490 * @brief Resolve (find) a data node based on a schema-nodeid.
1491 *
1492 * Used for resolving unique statements - so id is expected to be relative and local (without reference to a different
1493 * module).
1494 *
1495 */
1496struct lyd_node *
1497resolve_data_descendant_schema_nodeid(const char *nodeid, struct lyd_node *start)
1498{
1499 char *str, *token, *p;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001500 struct lyd_node *result = NULL, *iter;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001501 const struct lys_node *schema = NULL;
Radek Krejcicc217a62016-04-08 16:58:11 +02001502 int shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001503
1504 assert(nodeid && start);
1505
1506 if (nodeid[0] == '/') {
1507 return NULL;
1508 }
1509
1510 str = p = strdup(nodeid);
1511 if (!str) {
1512 LOGMEM;
1513 return NULL;
1514 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001515
Michal Vasko3edeaf72016-02-11 13:17:43 +01001516 while (p) {
1517 token = p;
1518 p = strchr(p, '/');
1519 if (p) {
1520 *p = '\0';
1521 p++;
1522 }
1523
Radek Krejci5da4eb62016-04-08 14:45:51 +02001524 if (p) {
1525 /* inner node */
Radek Krejcicc217a62016-04-08 16:58:11 +02001526 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema,
Radek Krejcif3c71de2016-04-11 12:45:46 +02001527 LYS_CONTAINER | LYS_CHOICE | LYS_CASE | LYS_LEAF, 0, 0, &schema)
Radek Krejci5da4eb62016-04-08 14:45:51 +02001528 || !schema) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001529 result = NULL;
1530 break;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001531 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001532
Radek Krejci5da4eb62016-04-08 14:45:51 +02001533 if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
1534 continue;
Michal Vaskodcf98e62016-05-05 17:53:53 +02001535 } else if (lys_parent(schema)->nodetype == LYS_CHOICE) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001536 /* shorthand case */
1537 if (!shorthand) {
1538 shorthand = 1;
Michal Vaskodcf98e62016-05-05 17:53:53 +02001539 schema = lys_parent(schema);
Radek Krejcicc217a62016-04-08 16:58:11 +02001540 continue;
1541 } else {
1542 shorthand = 0;
1543 if (schema->nodetype == LYS_LEAF) {
1544 /* should not be here, since we have leaf, which is not a shorthand nor final node */
1545 result = NULL;
1546 break;
1547 }
1548 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001549 }
1550 } else {
1551 /* final node */
Radek Krejcif3c71de2016-04-11 12:45:46 +02001552 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema, LYS_LEAF,
1553 shorthand ? 0 : 1, 0, &schema)
Radek Krejcicc217a62016-04-08 16:58:11 +02001554 || !schema) {
1555 result = NULL;
1556 break;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001557 }
1558 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001559 LY_TREE_FOR(result ? result->child : start, iter) {
1560 if (iter->schema == schema) {
1561 /* move in data tree according to returned schema */
1562 result = iter;
1563 break;
1564 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001565 }
Radek Krejcicc217a62016-04-08 16:58:11 +02001566 if (!iter) {
1567 /* instance not found */
1568 result = NULL;
1569 break;
1570 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001571 }
1572 free(str);
1573
1574 return result;
1575}
1576
Radek Krejcibdf92362016-04-08 14:43:34 +02001577/*
1578 * 0 - ok (done)
1579 * 1 - continue
1580 * 2 - break
1581 * -1 - error
1582 */
1583static int
Radek Krejcicc217a62016-04-08 16:58:11 +02001584schema_nodeid_siblingcheck(const struct lys_node *sibling, int8_t *shorthand, const char *id,
Radek Krejcibdf92362016-04-08 14:43:34 +02001585 const struct lys_module *module, const char *mod_name, int mod_name_len,
Radek Krejci0fa54e92016-09-14 14:01:05 +02001586 int implemented_mod, const struct lys_node **start)
Radek Krejcibdf92362016-04-08 14:43:34 +02001587{
1588 const struct lys_module *prefix_mod;
Radek Krejcicc217a62016-04-08 16:58:11 +02001589 int sh = 0;
Radek Krejcibdf92362016-04-08 14:43:34 +02001590
1591 /* module check */
1592 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Radek Krejci0fa54e92016-09-14 14:01:05 +02001593 if (implemented_mod) {
1594 prefix_mod = lys_get_implemented_module(prefix_mod);
1595 }
Radek Krejcibdf92362016-04-08 14:43:34 +02001596 if (!prefix_mod) {
1597 return -1;
1598 }
1599 if (prefix_mod != lys_node_module(sibling)) {
1600 return 1;
1601 }
1602
1603 /* check for shorthand cases - then 'start' does not change */
Michal Vaskodcf98e62016-05-05 17:53:53 +02001604 if (lys_parent(sibling) && (lys_parent(sibling)->nodetype == LYS_CHOICE) && (sibling->nodetype != LYS_CASE)) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001605 if (*shorthand != -1) {
1606 *shorthand = *shorthand ? 0 : 1;
1607 }
1608 sh = 1;
Radek Krejcibdf92362016-04-08 14:43:34 +02001609 }
1610
1611 /* the result node? */
1612 if (!id[0]) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001613 if (*shorthand == 1) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001614 return 1;
1615 }
1616 return 0;
1617 }
1618
Radek Krejcicc217a62016-04-08 16:58:11 +02001619 if (!sh) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001620 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02001621 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001622 return -1;
1623 }
1624 *start = sibling->child;
1625 }
1626
1627 return 2;
1628}
1629
Michal Vasko3edeaf72016-02-11 13:17:43 +01001630/* start - relative, module - absolute, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1631int
1632resolve_augment_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_module *module,
1633 const struct lys_node **ret)
1634{
1635 const char *name, *mod_name, *id;
1636 const struct lys_node *sibling;
1637 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001638 int8_t shorthand = 0;
Radek Krejci0fa54e92016-09-14 14:01:05 +02001639 int implemented_search = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001640 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcibdf92362016-04-08 14:43:34 +02001641 const struct lys_module *start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001642
1643 assert(nodeid && (start || module) && !(start && module) && ret);
1644
1645 id = nodeid;
1646
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001647 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 +01001648 return ((id - nodeid) - r) + 1;
1649 }
1650 id += r;
1651
1652 if ((is_relative && !start) || (!is_relative && !module)) {
1653 return -1;
1654 }
1655
1656 /* descendant-schema-nodeid */
1657 if (is_relative) {
Michal Vasko4c06fd82016-02-17 13:43:38 +01001658 module = start_mod = start->module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001659
1660 /* absolute-schema-nodeid */
1661 } else {
1662 start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Radek Krejci0fa54e92016-09-14 14:01:05 +02001663 if (start_mod != lys_main_module(module)) {
1664 /* if the submodule augments the mainmodule (or in general a module augments
1665 * itself, we don't want to search for the implemented module but augments
1666 * the module anyway. But when augmenting another module, we need the implemented
1667 * revision of the module if any */
1668 start_mod = lys_get_implemented_module(start_mod);
1669 implemented_search = 1;
1670 }
Michal Vaskoe2905632016-02-11 15:42:24 +01001671 if (!start_mod) {
1672 return -1;
1673 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001674 start = start_mod->data;
1675 }
1676
1677 while (1) {
1678 sibling = NULL;
1679 while ((sibling = lys_getnext(sibling, lys_parent(start), start_mod,
1680 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
1681 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001682 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001683 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len,
1684 implemented_search, &start);
Radek Krejcibdf92362016-04-08 14:43:34 +02001685 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001686 *ret = sibling;
1687 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001688 } else if (r == 1) {
1689 continue;
1690 } else if (r == 2) {
1691 break;
1692 } else {
1693 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001694 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001695 }
1696 }
1697
1698 /* no match */
1699 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001700 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001701 return EXIT_SUCCESS;
1702 }
1703
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001704 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 +01001705 return ((id - nodeid) - r) + 1;
1706 }
1707 id += r;
1708 }
1709
1710 /* cannot get here */
1711 LOGINT;
1712 return -1;
1713}
1714
Radek Krejcif3c71de2016-04-11 12:45:46 +02001715/* unique, refine,
1716 * >0 - unexpected char on position (ret - 1),
1717 * 0 - ok (but ret can still be NULL),
1718 * -1 - error,
1719 * -2 - violated no_innerlist */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001720int
1721resolve_descendant_schema_nodeid(const char *nodeid, const struct lys_node *start, int ret_nodetype,
Radek Krejcif3c71de2016-04-11 12:45:46 +02001722 int check_shorthand, int no_innerlist, const struct lys_node **ret)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001723{
1724 const char *name, *mod_name, *id;
1725 const struct lys_node *sibling;
1726 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001727 int8_t shorthand = check_shorthand ? 0 : -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001728 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcibdf92362016-04-08 14:43:34 +02001729 const struct lys_module *module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001730
1731 assert(nodeid && start && ret);
1732 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1733
1734 id = nodeid;
1735 module = start->module;
1736
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001737 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 +01001738 return ((id - nodeid) - r) + 1;
1739 }
1740 id += r;
1741
1742 if (!is_relative) {
1743 return -1;
1744 }
1745
1746 while (1) {
1747 sibling = NULL;
1748 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
1749 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE))) {
1750 /* name match */
1751 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001752 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len, 0, &start);
Radek Krejcibdf92362016-04-08 14:43:34 +02001753 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001754 if (!(sibling->nodetype & ret_nodetype)) {
1755 /* wrong node type, too bad */
1756 continue;
1757 }
1758 *ret = sibling;
1759 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001760 } else if (r == 1) {
1761 continue;
1762 } else if (r == 2) {
1763 break;
1764 } else {
1765 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001766 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001767 }
1768 }
1769
1770 /* no match */
1771 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001772 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001773 return EXIT_SUCCESS;
Radek Krejcif3c71de2016-04-11 12:45:46 +02001774 } else if (no_innerlist && sibling->nodetype == LYS_LIST) {
1775 *ret = NULL;
1776 return -2;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001777 }
1778
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001779 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 +01001780 return ((id - nodeid) - r) + 1;
1781 }
1782 id += r;
1783 }
1784
1785 /* cannot get here */
1786 LOGINT;
1787 return -1;
1788}
1789
1790/* choice default */
1791int
1792resolve_choice_default_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node **ret)
1793{
1794 /* cannot actually be a path */
1795 if (strchr(nodeid, '/')) {
1796 return -1;
1797 }
1798
Radek Krejcif3c71de2016-04-11 12:45:46 +02001799 return resolve_descendant_schema_nodeid(nodeid, start, LYS_NO_RPC_NOTIF_NODE, 1, 0, ret);
Michal Vasko3edeaf72016-02-11 13:17:43 +01001800}
1801
1802/* uses, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1803static int
1804resolve_uses_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node_grp **ret)
1805{
1806 const struct lys_module *module;
1807 const char *mod_prefix, *name;
1808 int i, mod_prefix_len, nam_len;
1809
1810 /* parse the identifier, it must be parsed on one call */
1811 if (((i = parse_node_identifier(nodeid, &mod_prefix, &mod_prefix_len, &name, &nam_len)) < 1) || nodeid[i]) {
1812 return -i + 1;
1813 }
1814
1815 module = lys_get_import_module(start->module, mod_prefix, mod_prefix_len, NULL, 0);
1816 if (!module) {
1817 return -1;
1818 }
1819 if (module != start->module) {
1820 start = module->data;
1821 }
1822
1823 *ret = lys_find_grouping_up(name, (struct lys_node *)start);
1824
1825 return EXIT_SUCCESS;
1826}
1827
1828int
1829resolve_absolute_schema_nodeid(const char *nodeid, const struct lys_module *module, int ret_nodetype,
1830 const struct lys_node **ret)
1831{
1832 const char *name, *mod_name, *id;
1833 const struct lys_node *sibling, *start;
1834 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001835 int8_t shorthand = 0;
Radek Krejcibdf92362016-04-08 14:43:34 +02001836 const struct lys_module *abs_start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001837
1838 assert(nodeid && module && ret);
1839 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1840
1841 id = nodeid;
1842 start = module->data;
1843
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001844 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 +01001845 return ((id - nodeid) - r) + 1;
1846 }
1847 id += r;
1848
1849 if (is_relative) {
1850 return -1;
1851 }
1852
1853 abs_start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001854 if (!abs_start_mod) {
1855 return -1;
1856 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001857
1858 while (1) {
1859 sibling = NULL;
1860 while ((sibling = lys_getnext(sibling, lys_parent(start), abs_start_mod, LYS_GETNEXT_WITHCHOICE
1861 | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_WITHGROUPING))) {
1862 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001863 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001864 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len, 0, &start);
Radek Krejcibdf92362016-04-08 14:43:34 +02001865 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001866 if (!(sibling->nodetype & ret_nodetype)) {
1867 /* wrong node type, too bad */
1868 continue;
1869 }
1870 *ret = sibling;
1871 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001872 } else if (r == 1) {
1873 continue;
1874 } else if (r == 2) {
1875 break;
1876 } else {
1877 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001878 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001879 }
1880 }
1881
1882 /* no match */
1883 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001884 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001885 return EXIT_SUCCESS;
1886 }
1887
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001888 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 +01001889 return ((id - nodeid) - r) + 1;
1890 }
1891 id += r;
1892 }
1893
1894 /* cannot get here */
1895 LOGINT;
1896 return -1;
1897}
1898
Michal Vaskoe733d682016-03-14 09:08:27 +01001899static int
Michal Vasko3547c532016-03-14 09:40:50 +01001900resolve_json_schema_list_predicate(const char *predicate, const struct lys_node_list *list, int *parsed)
Michal Vaskoe733d682016-03-14 09:08:27 +01001901{
1902 const char *name;
1903 int nam_len, has_predicate, i;
1904
Michal Vasko7b54f7e2016-05-03 15:07:31 +02001905 if (((i = parse_schema_json_predicate(predicate, &name, &nam_len, NULL, NULL, &has_predicate)) < 1)
1906 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001907 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-i], &predicate[-i]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001908 return -1;
1909 }
1910
1911 predicate += i;
1912 *parsed += i;
1913
1914 for (i = 0; i < list->keys_size; ++i) {
1915 if (!strncmp(list->keys[i]->name, name, nam_len) && !list->keys[i]->name[nam_len]) {
1916 break;
1917 }
1918 }
1919
1920 if (i == list->keys_size) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001921 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskoe733d682016-03-14 09:08:27 +01001922 return -1;
1923 }
1924
1925 /* more predicates? */
1926 if (has_predicate) {
Michal Vasko3547c532016-03-14 09:40:50 +01001927 return resolve_json_schema_list_predicate(predicate, list, parsed);
Michal Vaskoe733d682016-03-14 09:08:27 +01001928 }
1929
1930 return 0;
1931}
1932
Michal Vasko8d26e5c2016-09-08 10:03:49 +02001933/* cannot return LYS_GROUPING, LYS_AUGMENT, LYS_USES, logs directly */
Michal Vaskoe733d682016-03-14 09:08:27 +01001934const struct lys_node *
Michal Vasko8d26e5c2016-09-08 10:03:49 +02001935resolve_json_nodeid(const char *nodeid, struct ly_ctx *ctx, const struct lys_node *start)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001936{
Michal Vasko10728b52016-04-07 14:26:29 +02001937 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001938 const char *name, *mod_name, *id;
Michal Vasko3547c532016-03-14 09:40:50 +01001939 const struct lys_node *sibling;
Radek Krejcibdf92362016-04-08 14:43:34 +02001940 int r, nam_len, mod_name_len, is_relative = -1, has_predicate, shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001941 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vaskoe733d682016-03-14 09:08:27 +01001942 const struct lys_module *prefix_mod, *module, *prev_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001943
Michal Vasko3547c532016-03-14 09:40:50 +01001944 assert(nodeid && (ctx || start));
1945 if (!ctx) {
1946 ctx = start->module->ctx;
1947 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001948
1949 id = nodeid;
1950
Michal Vaskoe733d682016-03-14 09:08:27 +01001951 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 +01001952 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001953 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001954 }
1955 id += r;
1956
1957 if (is_relative) {
Michal Vasko3547c532016-03-14 09:40:50 +01001958 assert(start);
1959 start = start->child;
1960 if (!start) {
1961 /* no descendants, fail for sure */
Michal Vasko10728b52016-04-07 14:26:29 +02001962 str = strndup(nodeid, (name + nam_len) - nodeid);
1963 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
1964 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01001965 return NULL;
1966 }
1967 module = start->module;
1968 } else {
1969 if (!mod_name) {
Michal Vasko10728b52016-04-07 14:26:29 +02001970 str = strndup(nodeid, (name + nam_len) - nodeid);
1971 LOGVAL(LYE_PATH_MISSMOD, LY_VLOG_STR, nodeid);
1972 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01001973 return NULL;
Michal Vasko971a3ca2016-04-01 13:09:29 +02001974 } else if (mod_name_len > LY_BUF_SIZE - 1) {
1975 LOGINT;
1976 return NULL;
Michal Vasko3547c532016-03-14 09:40:50 +01001977 }
1978
Michal Vasko971a3ca2016-04-01 13:09:29 +02001979 if (ly_buf_used && module_name[0]) {
1980 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
1981 }
1982 ly_buf_used++;
1983
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02001984 memmove(module_name, mod_name, mod_name_len);
Michal Vasko971a3ca2016-04-01 13:09:29 +02001985 module_name[mod_name_len] = '\0';
1986 module = ly_ctx_get_module(ctx, module_name, NULL);
1987
1988 if (buf_backup) {
1989 /* return previous internal buffer content */
1990 strcpy(module_name, buf_backup);
1991 free(buf_backup);
1992 buf_backup = NULL;
1993 }
1994 ly_buf_used--;
1995
Michal Vasko3547c532016-03-14 09:40:50 +01001996 if (!module) {
Michal Vasko10728b52016-04-07 14:26:29 +02001997 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
1998 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
1999 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002000 return NULL;
2001 }
2002 start = module->data;
2003
2004 /* now it's as if there was no module name */
2005 mod_name = NULL;
2006 mod_name_len = 0;
Michal Vaskoe733d682016-03-14 09:08:27 +01002007 }
2008
Michal Vaskoe733d682016-03-14 09:08:27 +01002009 prev_mod = module;
2010
Michal Vasko3edeaf72016-02-11 13:17:43 +01002011 while (1) {
2012 sibling = NULL;
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002013 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
2014 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002015 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02002016 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002017 /* module check */
2018 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002019 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko8757e7c2016-03-15 10:41:30 +01002020 LOGINT;
2021 return NULL;
2022 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002023
2024 if (ly_buf_used && module_name[0]) {
2025 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2026 }
2027 ly_buf_used++;
2028
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002029 memmove(module_name, mod_name, mod_name_len);
Michal Vasko8757e7c2016-03-15 10:41:30 +01002030 module_name[mod_name_len] = '\0';
2031 /* will also find an augment module */
2032 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002033
2034 if (buf_backup) {
2035 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002036 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002037 free(buf_backup);
2038 buf_backup = NULL;
2039 }
2040 ly_buf_used--;
2041
Michal Vasko3edeaf72016-02-11 13:17:43 +01002042 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002043 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2044 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2045 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002046 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002047 }
2048 } else {
2049 prefix_mod = prev_mod;
2050 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01002051 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002052 continue;
2053 }
2054
Michal Vaskoe733d682016-03-14 09:08:27 +01002055 /* do we have some predicates on it? */
2056 if (has_predicate) {
2057 r = 0;
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002058 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
2059 if ((r = parse_schema_json_predicate(id, NULL, NULL, NULL, NULL, &has_predicate)) < 1) {
2060 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2061 return NULL;
2062 }
2063 } else if (sibling->nodetype == LYS_LIST) {
2064 if (resolve_json_schema_list_predicate(id, (const struct lys_node_list *)sibling, &r)) {
2065 return NULL;
2066 }
2067 } else {
Michal Vasko43c300e2016-03-22 12:54:27 +01002068 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vaskoe733d682016-03-14 09:08:27 +01002069 return NULL;
Michal Vaskoe733d682016-03-14 09:08:27 +01002070 }
2071 id += r;
2072 }
2073
Radek Krejcibdf92362016-04-08 14:43:34 +02002074 /* check for shorthand cases - then 'start' does not change */
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002075 if (lys_parent(sibling) && (lys_parent(sibling)->nodetype == LYS_CHOICE) && (sibling->nodetype != LYS_CASE)) {
Radek Krejcibdf92362016-04-08 14:43:34 +02002076 shorthand = ~shorthand;
2077 }
2078
Michal Vasko3edeaf72016-02-11 13:17:43 +01002079 /* the result node? */
2080 if (!id[0]) {
Radek Krejcibdf92362016-04-08 14:43:34 +02002081 if (shorthand) {
2082 /* wrong path for shorthand */
Michal Vasko025e0452016-05-17 16:14:20 +02002083 str = strndup(nodeid, (name + nam_len) - nodeid);
2084 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
Michal Vasko3c0f9f52016-05-17 16:38:10 +02002085 LOGVAL(LYE_SPEC, LY_VLOG_STR, str, "Schema shorthand case path must include the virtual case statement.");
Radek Krejci9a5fccc2016-05-18 15:44:58 +02002086 free(str);
Michal Vasko025e0452016-05-17 16:14:20 +02002087 return NULL;
Radek Krejcibdf92362016-04-08 14:43:34 +02002088 }
Michal Vaskoe733d682016-03-14 09:08:27 +01002089 return sibling;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002090 }
2091
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002092 if (!shorthand) {
Michal Vasko7dc71d02016-03-15 10:42:28 +01002093 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002094 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002095 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko7dc71d02016-03-15 10:42:28 +01002096 return NULL;
2097 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01002098 start = sibling->child;
2099 }
2100
2101 /* update prev mod */
2102 prev_mod = start->module;
2103 break;
2104 }
2105 }
2106
2107 /* no match */
2108 if (!sibling) {
Michal Vasko10728b52016-04-07 14:26:29 +02002109 str = strndup(nodeid, (name + nam_len) - nodeid);
2110 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
2111 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002112 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002113 }
2114
Michal Vaskoe733d682016-03-14 09:08:27 +01002115 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 +01002116 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002117 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002118 }
2119 id += r;
2120 }
2121
2122 /* cannot get here */
2123 LOGINT;
Michal Vaskoe733d682016-03-14 09:08:27 +01002124 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002125}
2126
Michal Vasko22448d32016-03-16 13:17:29 +01002127static int
2128resolve_partial_json_data_list_predicate(const char *predicate, const char *node_name, struct lyd_node *node, int *parsed)
2129{
2130 const char *name, *value;
2131 int nam_len, val_len, has_predicate = 1, r;
2132 uint16_t i;
Michal Vaskof29903d2016-04-18 13:13:10 +02002133 struct lyd_node_leaf_list *key;
Michal Vasko22448d32016-03-16 13:17:29 +01002134
Radek Krejci61a86c62016-03-24 11:06:44 +01002135 assert(node);
Michal Vasko22448d32016-03-16 13:17:29 +01002136 assert(node->schema->nodetype == LYS_LIST);
2137
Michal Vaskof29903d2016-04-18 13:13:10 +02002138 key = (struct lyd_node_leaf_list *)node->child;
2139 for (i = 0; i < ((struct lys_node_list *)node->schema)->keys_size; ++i) {
2140 if (!key) {
2141 /* invalid data */
2142 LOGINT;
2143 return -1;
2144 }
Michal Vasko22448d32016-03-16 13:17:29 +01002145
Michal Vasko22448d32016-03-16 13:17:29 +01002146 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002147 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, node_name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002148 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002149 }
2150
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002151 if (((r = parse_schema_json_predicate(predicate, &name, &nam_len, &value, &val_len, &has_predicate)) < 1)
2152 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002153 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
Michal Vaskof29903d2016-04-18 13:13:10 +02002154 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002155 }
2156
2157 predicate += r;
2158 *parsed += r;
2159
Michal Vaskof29903d2016-04-18 13:13:10 +02002160 if (strncmp(key->schema->name, name, nam_len) || key->schema->name[nam_len]) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002161 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002162 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002163 }
2164
2165 /* value does not match */
Michal Vaskof29903d2016-04-18 13:13:10 +02002166 if (strncmp(key->value_str, value, val_len) || key->value_str[val_len]) {
Michal Vasko22448d32016-03-16 13:17:29 +01002167 return 1;
2168 }
Michal Vaskof29903d2016-04-18 13:13:10 +02002169
2170 key = (struct lyd_node_leaf_list *)key->next;
Michal Vasko22448d32016-03-16 13:17:29 +01002171 }
2172
2173 if (has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002174 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko22448d32016-03-16 13:17:29 +01002175 return -1;
2176 }
2177
2178 return 0;
2179}
2180
Radek Krejci45826012016-08-24 15:07:57 +02002181/**
2182 * @brief get the closest parent of the node (or the node itself) identified by the nodeid (path)
2183 *
2184 * @param[in] nodeid Node data path to find
2185 * @param[in] llist_value If the \p nodeid identifies leaf-list, this is expected value of the leaf-list instance.
2186 * @param[in] options Bitmask of options flags, see @ref pathoptions.
2187 * @param[out] parsed Number of characters processed in \p id
2188 * @return The closes parent (or the node itself) from the path
2189 */
Michal Vasko22448d32016-03-16 13:17:29 +01002190struct lyd_node *
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002191resolve_partial_json_data_nodeid(const char *nodeid, const char *llist_value, struct lyd_node *start, int options,
2192 int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002193{
Michal Vasko10728b52016-04-07 14:26:29 +02002194 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vaskoee385fa2016-10-19 15:51:36 +02002195 const char *id, *mod_name, *name, *pred_name;
2196 int r, ret, mod_name_len, nam_len, is_relative = -1;
2197 int has_predicate, last_parsed, val_len, pred_name_len, last_has_pred;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002198 struct lyd_node *sibling, *last_match = NULL;
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002199 struct lyd_node_leaf_list *llist;
Michal Vasko22448d32016-03-16 13:17:29 +01002200 const struct lys_module *prefix_mod, *prev_mod;
2201 struct ly_ctx *ctx;
2202
2203 assert(nodeid && start && parsed);
2204
2205 ctx = start->schema->module->ctx;
2206 id = nodeid;
2207
2208 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 +01002209 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002210 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002211 return NULL;
2212 }
2213 id += r;
2214 /* add it to parsed only after the data node was actually found */
2215 last_parsed = r;
2216
2217 if (is_relative) {
2218 prev_mod = start->schema->module;
Michal Vasko22448d32016-03-16 13:17:29 +01002219 start = start->child;
2220 } else {
2221 for (; start->parent; start = start->parent);
Michal Vasko22448d32016-03-16 13:17:29 +01002222 prev_mod = start->schema->module;
2223 }
2224
2225 while (1) {
2226 LY_TREE_FOR(start, sibling) {
Michal Vasko945b96b2016-10-18 11:49:12 +02002227 /* RPC/action data check, return simply invalid argument, because the data tree is invalid */
Michal Vasko2411b942016-03-23 13:50:03 +01002228 if (lys_parent(sibling->schema)) {
2229 if (options & LYD_PATH_OPT_OUTPUT) {
2230 if (lys_parent(sibling->schema)->nodetype == LYS_INPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002231 LOGERR(LY_EINVAL, "Provided data tree includes some RPC input nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002232 *parsed = -1;
2233 return NULL;
2234 }
2235 } else {
2236 if (lys_parent(sibling->schema)->nodetype == LYS_OUTPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002237 LOGERR(LY_EINVAL, "Provided data tree includes some RPC output nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002238 *parsed = -1;
2239 return NULL;
2240 }
2241 }
2242 }
2243
Michal Vasko22448d32016-03-16 13:17:29 +01002244 /* name match */
2245 if (!strncmp(name, sibling->schema->name, nam_len) && !sibling->schema->name[nam_len]) {
2246
2247 /* module check */
2248 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002249 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko22448d32016-03-16 13:17:29 +01002250 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002251 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002252 return NULL;
2253 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002254
2255 if (ly_buf_used && module_name[0]) {
2256 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2257 }
2258 ly_buf_used++;
2259
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002260 memmove(module_name, mod_name, mod_name_len);
Michal Vasko22448d32016-03-16 13:17:29 +01002261 module_name[mod_name_len] = '\0';
2262 /* will also find an augment module */
2263 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002264
2265 if (buf_backup) {
2266 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002267 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002268 free(buf_backup);
2269 buf_backup = NULL;
2270 }
2271 ly_buf_used--;
2272
Michal Vasko22448d32016-03-16 13:17:29 +01002273 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002274 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2275 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2276 free(str);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002277 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002278 return NULL;
2279 }
2280 } else {
2281 prefix_mod = prev_mod;
2282 }
2283 if (prefix_mod != lys_node_module(sibling->schema)) {
2284 continue;
2285 }
2286
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002287 /* leaf-list, did we find it with the correct value or not? */
Michal Vasko22448d32016-03-16 13:17:29 +01002288 if (sibling->schema->nodetype == LYS_LEAFLIST) {
Michal Vaskoee385fa2016-10-19 15:51:36 +02002289 last_has_pred = 0;
Michal Vaskoacb87b62016-10-19 11:33:55 +02002290 if (has_predicate) {
Michal Vaskoee385fa2016-10-19 15:51:36 +02002291 if ((r = parse_schema_json_predicate(id, &pred_name, &pred_name_len, &llist_value, &val_len, &last_has_pred)) < 1) {
Michal Vaskoacb87b62016-10-19 11:33:55 +02002292 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2293 *parsed = -1;
2294 return NULL;
2295 }
Michal Vaskoee385fa2016-10-19 15:51:36 +02002296 if ((pred_name[0] != '.') || (pred_name_len != 1)) {
2297 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[1], id + 1);
2298 *parsed = -1;
2299 return NULL;
2300 }
Michal Vaskoacb87b62016-10-19 11:33:55 +02002301 } else {
2302 r = 0;
2303 if (llist_value) {
2304 val_len = strlen(llist_value);
2305 } else {
2306 val_len = 0;
2307 }
2308 }
2309
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002310 llist = (struct lyd_node_leaf_list *)sibling;
Michal Vaskoacb87b62016-10-19 11:33:55 +02002311 if ((!val_len && llist->value_str && llist->value_str[0])
2312 || (val_len && (strncmp(llist_value, llist->value_str, val_len) || llist->value_str[val_len]))) {
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002313 continue;
2314 }
Michal Vaskoacb87b62016-10-19 11:33:55 +02002315 id += r;
2316 last_parsed += r;
Michal Vaskoee385fa2016-10-19 15:51:36 +02002317 has_predicate = last_has_pred;
Michal Vaskoacb87b62016-10-19 11:33:55 +02002318
Radek Krejci45826012016-08-24 15:07:57 +02002319 } else if (sibling->schema->nodetype == LYS_LIST) {
2320 /* list, we need predicates'n'stuff then */
Michal Vasko22448d32016-03-16 13:17:29 +01002321 r = 0;
2322 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002323 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002324 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002325 return NULL;
2326 }
2327 ret = resolve_partial_json_data_list_predicate(id, name, sibling, &r);
2328 if (ret == -1) {
Michal Vasko238bd2f2016-03-23 09:39:01 +01002329 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002330 return NULL;
2331 } else if (ret == 1) {
2332 /* this list instance does not match */
2333 continue;
2334 }
2335 id += r;
2336 last_parsed += r;
2337 }
2338
2339 *parsed += last_parsed;
2340
2341 /* the result node? */
2342 if (!id[0]) {
2343 return sibling;
2344 }
2345
2346 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002347 if (sibling->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002348 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002349 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002350 return NULL;
2351 }
Michal Vaskoc6c52cf2016-03-29 11:53:04 +02002352 last_match = sibling;
Michal Vasko22448d32016-03-16 13:17:29 +01002353 start = sibling->child;
2354 if (start) {
2355 prev_mod = start->schema->module;
2356 }
2357 break;
2358 }
2359 }
2360
2361 /* no match, return last match */
2362 if (!sibling) {
2363 return last_match;
2364 }
2365
2366 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 +01002367 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002368 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002369 return NULL;
2370 }
2371 id += r;
2372 last_parsed = r;
2373 }
2374
2375 /* cannot get here */
2376 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002377 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002378 return NULL;
2379}
2380
Michal Vasko3edeaf72016-02-11 13:17:43 +01002381/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02002382 * @brief Resolves length or range intervals. Does not log.
Michal Vaskoaeb51802016-04-11 10:58:47 +02002383 * Syntax is assumed to be correct, *ret MUST be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002384 *
Michal Vaskoaeb51802016-04-11 10:58:47 +02002385 * @param[in] str_restr Restriction as a string.
2386 * @param[in] type Type of the restriction.
2387 * @param[out] ret Final interval structure that starts with
2388 * the interval of the initial type, continues with intervals
2389 * of any superior types derived from the initial one, and
2390 * finishes with intervals from our \p type.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002391 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002392 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002393 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002394int
Michal Vaskoaeb51802016-04-11 10:58:47 +02002395resolve_len_ran_interval(const char *str_restr, struct lys_type *type, struct len_ran_intv **ret)
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002396{
2397 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002398 int kind;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002399 int64_t local_smin, local_smax, local_fmin, local_fmax;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002400 uint64_t local_umin, local_umax;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002401 uint8_t local_fdig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002402 const char *seg_ptr, *ptr;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002403 struct len_ran_intv *local_intv = NULL, *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002404
2405 switch (type->base) {
2406 case LY_TYPE_BINARY:
2407 kind = 0;
2408 local_umin = 0;
2409 local_umax = 18446744073709551615UL;
2410
2411 if (!str_restr && type->info.binary.length) {
2412 str_restr = type->info.binary.length->expr;
2413 }
2414 break;
2415 case LY_TYPE_DEC64:
2416 kind = 2;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002417 local_fmin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2418 local_fmax = __INT64_C(9223372036854775807);
2419 local_fdig = type->info.dec64.dig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002420
2421 if (!str_restr && type->info.dec64.range) {
2422 str_restr = type->info.dec64.range->expr;
2423 }
2424 break;
2425 case LY_TYPE_INT8:
2426 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002427 local_smin = __INT64_C(-128);
2428 local_smax = __INT64_C(127);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002429
2430 if (!str_restr && type->info.num.range) {
2431 str_restr = type->info.num.range->expr;
2432 }
2433 break;
2434 case LY_TYPE_INT16:
2435 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002436 local_smin = __INT64_C(-32768);
2437 local_smax = __INT64_C(32767);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002438
2439 if (!str_restr && type->info.num.range) {
2440 str_restr = type->info.num.range->expr;
2441 }
2442 break;
2443 case LY_TYPE_INT32:
2444 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002445 local_smin = __INT64_C(-2147483648);
2446 local_smax = __INT64_C(2147483647);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002447
2448 if (!str_restr && type->info.num.range) {
2449 str_restr = type->info.num.range->expr;
2450 }
2451 break;
2452 case LY_TYPE_INT64:
2453 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002454 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2455 local_smax = __INT64_C(9223372036854775807);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002456
2457 if (!str_restr && type->info.num.range) {
2458 str_restr = type->info.num.range->expr;
2459 }
2460 break;
2461 case LY_TYPE_UINT8:
2462 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002463 local_umin = __UINT64_C(0);
2464 local_umax = __UINT64_C(255);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002465
2466 if (!str_restr && type->info.num.range) {
2467 str_restr = type->info.num.range->expr;
2468 }
2469 break;
2470 case LY_TYPE_UINT16:
2471 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002472 local_umin = __UINT64_C(0);
2473 local_umax = __UINT64_C(65535);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002474
2475 if (!str_restr && type->info.num.range) {
2476 str_restr = type->info.num.range->expr;
2477 }
2478 break;
2479 case LY_TYPE_UINT32:
2480 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002481 local_umin = __UINT64_C(0);
2482 local_umax = __UINT64_C(4294967295);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002483
2484 if (!str_restr && type->info.num.range) {
2485 str_restr = type->info.num.range->expr;
2486 }
2487 break;
2488 case LY_TYPE_UINT64:
2489 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002490 local_umin = __UINT64_C(0);
2491 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002492
2493 if (!str_restr && type->info.num.range) {
2494 str_restr = type->info.num.range->expr;
2495 }
2496 break;
2497 case LY_TYPE_STRING:
2498 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002499 local_umin = __UINT64_C(0);
2500 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002501
2502 if (!str_restr && type->info.str.length) {
2503 str_restr = type->info.str.length->expr;
2504 }
2505 break;
2506 default:
2507 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002508 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002509 }
2510
2511 /* process superior types */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002512 if (type->der) {
2513 if (resolve_len_ran_interval(NULL, &type->der->type, &intv)) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002514 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002515 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02002516 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002517 assert(!intv || (intv->kind == kind));
2518 }
2519
2520 if (!str_restr) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002521 /* we do not have any restriction, return superior ones */
2522 *ret = intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002523 return EXIT_SUCCESS;
2524 }
2525
2526 /* adjust local min and max */
2527 if (intv) {
2528 tmp_intv = intv;
2529
2530 if (kind == 0) {
2531 local_umin = tmp_intv->value.uval.min;
2532 } else if (kind == 1) {
2533 local_smin = tmp_intv->value.sval.min;
2534 } else if (kind == 2) {
2535 local_fmin = tmp_intv->value.fval.min;
2536 }
2537
2538 while (tmp_intv->next) {
2539 tmp_intv = tmp_intv->next;
2540 }
2541
2542 if (kind == 0) {
2543 local_umax = tmp_intv->value.uval.max;
2544 } else if (kind == 1) {
2545 local_smax = tmp_intv->value.sval.max;
2546 } else if (kind == 2) {
2547 local_fmax = tmp_intv->value.fval.max;
2548 }
2549 }
2550
2551 /* finally parse our restriction */
2552 seg_ptr = str_restr;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002553 tmp_intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002554 while (1) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002555 if (!tmp_local_intv) {
2556 assert(!local_intv);
2557 local_intv = malloc(sizeof *local_intv);
2558 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002559 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002560 tmp_local_intv->next = malloc(sizeof *tmp_local_intv);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002561 tmp_local_intv = tmp_local_intv->next;
2562 }
Michal Vasko253035f2015-12-17 16:58:13 +01002563 if (!tmp_local_intv) {
2564 LOGMEM;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002565 goto error;
Michal Vasko253035f2015-12-17 16:58:13 +01002566 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002567
2568 tmp_local_intv->kind = kind;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002569 tmp_local_intv->type = type;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002570 tmp_local_intv->next = NULL;
2571
2572 /* min */
2573 ptr = seg_ptr;
2574 while (isspace(ptr[0])) {
2575 ++ptr;
2576 }
2577 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2578 if (kind == 0) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002579 tmp_local_intv->value.uval.min = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002580 } else if (kind == 1) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002581 tmp_local_intv->value.sval.min = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002582 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002583 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.min)) {
2584 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2585 goto error;
2586 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002587 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002588 } else if (!strncmp(ptr, "min", 3)) {
2589 if (kind == 0) {
2590 tmp_local_intv->value.uval.min = local_umin;
2591 } else if (kind == 1) {
2592 tmp_local_intv->value.sval.min = local_smin;
2593 } else if (kind == 2) {
2594 tmp_local_intv->value.fval.min = local_fmin;
2595 }
2596
2597 ptr += 3;
2598 } else if (!strncmp(ptr, "max", 3)) {
2599 if (kind == 0) {
2600 tmp_local_intv->value.uval.min = local_umax;
2601 } else if (kind == 1) {
2602 tmp_local_intv->value.sval.min = local_smax;
2603 } else if (kind == 2) {
2604 tmp_local_intv->value.fval.min = local_fmax;
2605 }
2606
2607 ptr += 3;
2608 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002609 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002610 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002611 }
2612
2613 while (isspace(ptr[0])) {
2614 ptr++;
2615 }
2616
2617 /* no interval or interval */
2618 if ((ptr[0] == '|') || !ptr[0]) {
2619 if (kind == 0) {
2620 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
2621 } else if (kind == 1) {
2622 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
2623 } else if (kind == 2) {
2624 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
2625 }
2626 } else if (!strncmp(ptr, "..", 2)) {
2627 /* skip ".." */
2628 ptr += 2;
2629 while (isspace(ptr[0])) {
2630 ++ptr;
2631 }
2632
2633 /* max */
2634 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2635 if (kind == 0) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002636 tmp_local_intv->value.uval.max = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002637 } else if (kind == 1) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002638 tmp_local_intv->value.sval.max = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002639 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002640 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.max)) {
2641 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2642 goto error;
2643 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002644 }
2645 } else if (!strncmp(ptr, "max", 3)) {
2646 if (kind == 0) {
2647 tmp_local_intv->value.uval.max = local_umax;
2648 } else if (kind == 1) {
2649 tmp_local_intv->value.sval.max = local_smax;
2650 } else if (kind == 2) {
2651 tmp_local_intv->value.fval.max = local_fmax;
2652 }
2653 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002654 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002655 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002656 }
2657 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002658 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002659 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002660 }
2661
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002662 /* check min and max in correct order*/
2663 if (kind == 0) {
2664 /* current segment */
2665 if (tmp_local_intv->value.uval.min > tmp_local_intv->value.uval.max) {
2666 goto error;
2667 }
2668 if (tmp_local_intv->value.uval.min < local_umin || tmp_local_intv->value.uval.max > local_umax) {
2669 goto error;
2670 }
2671 /* segments sholud be ascending order */
Pavol Vican69f62c92016-08-30 09:06:25 +02002672 if (tmp_intv && (tmp_intv->value.uval.max >= tmp_local_intv->value.uval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002673 goto error;
2674 }
2675 } else if (kind == 1) {
2676 if (tmp_local_intv->value.sval.min > tmp_local_intv->value.sval.max) {
2677 goto error;
2678 }
2679 if (tmp_local_intv->value.sval.min < local_smin || tmp_local_intv->value.sval.max > local_smax) {
2680 goto error;
2681 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002682 if (tmp_intv && (tmp_intv->value.sval.max >= tmp_local_intv->value.sval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002683 goto error;
2684 }
2685 } else if (kind == 2) {
2686 if (tmp_local_intv->value.fval.min > tmp_local_intv->value.fval.max) {
2687 goto error;
2688 }
2689 if (tmp_local_intv->value.fval.min < local_fmin || tmp_local_intv->value.fval.max > local_fmax) {
2690 goto error;
2691 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002692 if (tmp_intv && (tmp_intv->value.fval.max >= tmp_local_intv->value.fval.min)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002693 /* fraction-digits value is always the same (it cannot be changed in derived types) */
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002694 goto error;
2695 }
2696 }
2697
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002698 /* next segment (next OR) */
2699 seg_ptr = strchr(seg_ptr, '|');
2700 if (!seg_ptr) {
2701 break;
2702 }
2703 seg_ptr++;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002704 tmp_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002705 }
2706
2707 /* check local restrictions against superior ones */
2708 if (intv) {
2709 tmp_intv = intv;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002710 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002711
2712 while (tmp_local_intv && tmp_intv) {
2713 /* reuse local variables */
2714 if (kind == 0) {
2715 local_umin = tmp_local_intv->value.uval.min;
2716 local_umax = tmp_local_intv->value.uval.max;
2717
2718 /* it must be in this interval */
2719 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
2720 /* this interval is covered, next one */
2721 if (local_umax <= tmp_intv->value.uval.max) {
2722 tmp_local_intv = tmp_local_intv->next;
2723 continue;
2724 /* ascending order of restrictions -> fail */
2725 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002726 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002727 }
2728 }
2729 } else if (kind == 1) {
2730 local_smin = tmp_local_intv->value.sval.min;
2731 local_smax = tmp_local_intv->value.sval.max;
2732
2733 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
2734 if (local_smax <= tmp_intv->value.sval.max) {
2735 tmp_local_intv = tmp_local_intv->next;
2736 continue;
2737 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002738 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002739 }
2740 }
2741 } else if (kind == 2) {
2742 local_fmin = tmp_local_intv->value.fval.min;
2743 local_fmax = tmp_local_intv->value.fval.max;
2744
Michal Vasko4d1f0482016-09-19 14:35:06 +02002745 if ((dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.min, local_fdig) > -1)
Pavol Vican3c8ee2b2016-09-29 13:18:13 +02002746 && (dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002747 if (dec64cmp(local_fmax, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002748 tmp_local_intv = tmp_local_intv->next;
2749 continue;
2750 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002751 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002752 }
2753 }
2754 }
2755
2756 tmp_intv = tmp_intv->next;
2757 }
2758
2759 /* some interval left uncovered -> fail */
2760 if (tmp_local_intv) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002761 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002762 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002763 }
2764
Michal Vaskoaeb51802016-04-11 10:58:47 +02002765 /* append the local intervals to all the intervals of the superior types, return it all */
2766 if (intv) {
2767 for (tmp_intv = intv; tmp_intv->next; tmp_intv = tmp_intv->next);
2768 tmp_intv->next = local_intv;
2769 } else {
2770 intv = local_intv;
2771 }
2772 *ret = intv;
2773
2774 return EXIT_SUCCESS;
2775
2776error:
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002777 while (intv) {
2778 tmp_intv = intv->next;
2779 free(intv);
2780 intv = tmp_intv;
2781 }
Michal Vaskoaeb51802016-04-11 10:58:47 +02002782 while (local_intv) {
2783 tmp_local_intv = local_intv->next;
2784 free(local_intv);
2785 local_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002786 }
2787
Michal Vaskoaeb51802016-04-11 10:58:47 +02002788 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002789}
2790
Michal Vasko730dfdf2015-08-11 14:48:05 +02002791/**
Michal Vasko01c6fd22016-05-20 11:43:05 +02002792 * @brief Resolve a typedef, return only resolved typedefs if derived. If leafref, it must be
2793 * resolved for this function to return it. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002794 *
2795 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02002796 * @param[in] mod_name Typedef name module name.
2797 * @param[in] module Main module.
2798 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002799 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002800 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002801 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002802 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002803int
Michal Vasko1e62a092015-12-01 12:27:20 +01002804resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
2805 const struct lys_node *parent, struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002806{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002807 int i, j;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002808 struct lys_tpdf *tpdf, *match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002809 int tpdf_size;
2810
Michal Vasko1dca6882015-10-22 14:29:42 +02002811 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002812 /* no prefix, try built-in types */
2813 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
2814 if (!strcmp(ly_types[i].def->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002815 if (ret) {
2816 *ret = ly_types[i].def;
2817 }
2818 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002819 }
2820 }
2821 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02002822 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002823 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02002824 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002825 }
2826 }
2827
Michal Vasko1dca6882015-10-22 14:29:42 +02002828 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002829 /* search in local typedefs */
2830 while (parent) {
2831 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02002832 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02002833 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
2834 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002835 break;
2836
Radek Krejci76512572015-08-04 09:47:08 +02002837 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02002838 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
2839 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002840 break;
2841
Radek Krejci76512572015-08-04 09:47:08 +02002842 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02002843 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
2844 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002845 break;
2846
Radek Krejci76512572015-08-04 09:47:08 +02002847 case LYS_RPC:
Michal Vasko44fb6382016-06-29 11:12:27 +02002848 case LYS_ACTION:
2849 tpdf_size = ((struct lys_node_rpc_action *)parent)->tpdf_size;
2850 tpdf = ((struct lys_node_rpc_action *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002851 break;
2852
Radek Krejci76512572015-08-04 09:47:08 +02002853 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02002854 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
2855 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002856 break;
2857
Radek Krejci76512572015-08-04 09:47:08 +02002858 case LYS_INPUT:
2859 case LYS_OUTPUT:
Michal Vasko44fb6382016-06-29 11:12:27 +02002860 tpdf_size = ((struct lys_node_inout *)parent)->tpdf_size;
2861 tpdf = ((struct lys_node_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002862 break;
2863
2864 default:
Michal Vaskodcf98e62016-05-05 17:53:53 +02002865 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002866 continue;
2867 }
2868
2869 for (i = 0; i < tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002870 if (!strcmp(tpdf[i].name, name) && tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002871 match = &tpdf[i];
2872 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002873 }
2874 }
2875
Michal Vaskodcf98e62016-05-05 17:53:53 +02002876 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002877 }
Radek Krejcic071c542016-01-27 14:57:51 +01002878 } else {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002879 /* get module where to search */
Michal Vaskob6729c62015-10-21 12:09:47 +02002880 module = lys_get_import_module(module, NULL, 0, mod_name, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02002881 if (!module) {
2882 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002883 }
2884 }
2885
2886 /* search in top level typedefs */
2887 for (i = 0; i < module->tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002888 if (!strcmp(module->tpdf[i].name, name) && module->tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002889 match = &module->tpdf[i];
2890 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002891 }
2892 }
2893
2894 /* search in submodules */
Radek Krejcic071c542016-01-27 14:57:51 +01002895 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002896 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002897 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 +02002898 match = &module->inc[i].submodule->tpdf[j];
2899 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002900 }
2901 }
2902 }
2903
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002904 return EXIT_FAILURE;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002905
2906check_leafref:
2907 if (ret) {
2908 *ret = match;
2909 }
2910 if (match->type.base == LY_TYPE_LEAFREF) {
2911 while (!match->type.info.lref.path) {
2912 match = match->type.der;
2913 assert(match);
2914 }
Michal Vasko01c6fd22016-05-20 11:43:05 +02002915 }
2916 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002917}
2918
Michal Vasko1dca6882015-10-22 14:29:42 +02002919/**
2920 * @brief Check the default \p value of the \p type. Logs directly.
2921 *
2922 * @param[in] type Type definition to use.
2923 * @param[in] value Default value to check.
Michal Vasko56826402016-03-02 11:11:37 +01002924 * @param[in] module Type module.
Michal Vasko1dca6882015-10-22 14:29:42 +02002925 *
2926 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
2927 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002928static int
Radek Krejci48464ed2016-03-17 15:44:09 +01002929check_default(struct lys_type *type, const char *value, struct lys_module *module)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002930{
Radek Krejcibad2f172016-08-02 11:04:15 +02002931 struct lys_tpdf *base_tpdf = NULL;
Michal Vasko1dca6882015-10-22 14:29:42 +02002932 struct lyd_node_leaf_list node;
Radek Krejci37b756f2016-01-18 10:15:03 +01002933 int ret = EXIT_SUCCESS;
Michal Vasko1dca6882015-10-22 14:29:42 +02002934
Radek Krejcic13db382016-08-16 10:52:42 +02002935 if (type->base <= LY_TYPE_DER) {
Michal Vasko478c4652016-07-21 12:55:01 +02002936 /* the type was not resolved yet, nothing to do for now */
2937 return EXIT_FAILURE;
2938 }
2939
2940 if (!value) {
2941 /* we do not have a new default value, so is there any to check even, in some base type? */
2942 for (base_tpdf = type->der; base_tpdf->type.der; base_tpdf = base_tpdf->type.der) {
2943 if (base_tpdf->dflt) {
2944 value = base_tpdf->dflt;
2945 break;
2946 }
2947 }
2948
2949 if (!value) {
2950 /* no default value, nothing to check, all is well */
2951 return EXIT_SUCCESS;
2952 }
2953
2954 /* 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)? */
2955 switch (type->base) {
Michal Vasko478c4652016-07-21 12:55:01 +02002956 case LY_TYPE_IDENT:
2957 case LY_TYPE_INST:
2958 case LY_TYPE_LEAFREF:
2959 case LY_TYPE_BOOL:
2960 case LY_TYPE_EMPTY:
2961 /* these have no restrictions, so we would do the exact same work as the unres in the base typedef */
2962 return EXIT_SUCCESS;
Radek Krejcibad2f172016-08-02 11:04:15 +02002963 case LY_TYPE_BITS:
2964 /* the default value must match the restricted list of values, if the type was restricted */
2965 if (type->info.bits.count) {
2966 break;
2967 }
2968 return EXIT_SUCCESS;
2969 case LY_TYPE_ENUM:
2970 /* the default value must match the restricted list of values, if the type was restricted */
2971 if (type->info.enums.count) {
2972 break;
2973 }
2974 return EXIT_SUCCESS;
Michal Vasko478c4652016-07-21 12:55:01 +02002975 case LY_TYPE_DEC64:
2976 if (type->info.dec64.range) {
2977 break;
2978 }
2979 return EXIT_SUCCESS;
2980 case LY_TYPE_BINARY:
2981 if (type->info.binary.length) {
2982 break;
2983 }
2984 return EXIT_SUCCESS;
2985 case LY_TYPE_INT8:
2986 case LY_TYPE_INT16:
2987 case LY_TYPE_INT32:
2988 case LY_TYPE_INT64:
2989 case LY_TYPE_UINT8:
2990 case LY_TYPE_UINT16:
2991 case LY_TYPE_UINT32:
2992 case LY_TYPE_UINT64:
2993 if (type->info.num.range) {
2994 break;
2995 }
2996 return EXIT_SUCCESS;
2997 case LY_TYPE_STRING:
2998 if (type->info.str.length || type->info.str.patterns) {
2999 break;
3000 }
3001 return EXIT_SUCCESS;
3002 case LY_TYPE_UNION:
3003 /* way too much trouble learning whether we need to check the default again, so just do it */
3004 break;
3005 default:
3006 LOGINT;
3007 return -1;
3008 }
Radek Krejci55a161c2016-09-05 17:13:25 +02003009 } else if (type->base == LY_TYPE_EMPTY) {
3010 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "default", type->parent->name);
3011 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"empty\" data type cannot have a default value.");
3012 return -1;
Michal Vasko478c4652016-07-21 12:55:01 +02003013 }
3014
Michal Vasko1dca6882015-10-22 14:29:42 +02003015 /* dummy leaf */
Radek Krejci4fe36bd2016-03-17 16:47:16 +01003016 memset(&node, 0, sizeof node);
Michal Vasko1dca6882015-10-22 14:29:42 +02003017 node.value_str = value;
3018 node.value_type = type->base;
Radek Krejci37b756f2016-01-18 10:15:03 +01003019 node.schema = calloc(1, sizeof (struct lys_node_leaf));
Michal Vasko253035f2015-12-17 16:58:13 +01003020 if (!node.schema) {
3021 LOGMEM;
3022 return -1;
3023 }
Radek Krejcibad2f172016-08-02 11:04:15 +02003024 node.schema->name = strdup("fake-default");
Michal Vasko253035f2015-12-17 16:58:13 +01003025 if (!node.schema->name) {
3026 LOGMEM;
Michal Vaskof49eda02016-07-21 12:17:01 +02003027 free(node.schema);
Michal Vasko253035f2015-12-17 16:58:13 +01003028 return -1;
3029 }
Michal Vasko56826402016-03-02 11:11:37 +01003030 node.schema->module = module;
Radek Krejci37b756f2016-01-18 10:15:03 +01003031 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
Michal Vasko1dca6882015-10-22 14:29:42 +02003032
Radek Krejci37b756f2016-01-18 10:15:03 +01003033 if (type->base == LY_TYPE_LEAFREF) {
Michal Vasko1dca6882015-10-22 14:29:42 +02003034 if (!type->info.lref.target) {
3035 ret = EXIT_FAILURE;
3036 goto finish;
3037 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003038 ret = check_default(&type->info.lref.target->type, value, module);
Michal Vasko1dca6882015-10-22 14:29:42 +02003039
3040 } else if ((type->base == LY_TYPE_INST) || (type->base == LY_TYPE_IDENT)) {
3041 /* it was converted to JSON format before, nothing else sensible we can do */
3042
3043 } else {
Michal Vasko3767fb22016-07-21 12:10:57 +02003044 if (lyp_parse_value(&node, NULL, 1)) {
3045 ret = -1;
Radek Krejcibad2f172016-08-02 11:04:15 +02003046 if (base_tpdf) {
3047 /* default value was is defined in some base typedef */
3048 if ((type->base == LY_TYPE_BITS && type->der->type.der) ||
3049 (type->base == LY_TYPE_ENUM && type->der->type.der)) {
3050 /* we have refined bits/enums */
3051 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
3052 "Invalid value \"%s\" of the default statement inherited to \"%s\" from \"%s\" base type.",
3053 value, type->parent->name, base_tpdf->name);
3054 }
3055 }
Michal Vasko3767fb22016-07-21 12:10:57 +02003056 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003057 }
3058
3059finish:
3060 if (node.value_type == LY_TYPE_BITS) {
3061 free(node.value.bit);
3062 }
3063 free((char *)node.schema->name);
3064 free(node.schema);
3065
3066 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003067}
3068
Michal Vasko730dfdf2015-08-11 14:48:05 +02003069/**
3070 * @brief Check a key for mandatory attributes. Logs directly.
3071 *
3072 * @param[in] key The key to check.
3073 * @param[in] flags What flags to check.
3074 * @param[in] list The list of all the keys.
3075 * @param[in] index Index of the key in the key list.
3076 * @param[in] name The name of the keys.
3077 * @param[in] len The name length.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003078 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003079 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003080 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003081static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003082check_key(struct lys_node_list *list, int index, const char *name, int len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003083{
Radek Krejciadb57612016-02-16 13:34:34 +01003084 struct lys_node_leaf *key = list->keys[index];
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003085 char *dup = NULL;
3086 int j;
3087
3088 /* existence */
3089 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02003090 if (name[len] != '\0') {
3091 dup = strdup(name);
Michal Vasko253035f2015-12-17 16:58:13 +01003092 if (!dup) {
3093 LOGMEM;
3094 return -1;
3095 }
Michal Vaskof02e3742015-08-05 16:27:02 +02003096 dup[len] = '\0';
3097 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003098 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003099 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, list, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003100 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003101 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003102 }
3103
3104 /* uniqueness */
3105 for (j = index - 1; j >= 0; j--) {
Radek Krejciadb57612016-02-16 13:34:34 +01003106 if (key == list->keys[j]) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003107 LOGVAL(LYE_KEY_DUP, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003108 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003109 }
3110 }
3111
3112 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02003113 if (key->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003114 LOGVAL(LYE_KEY_NLEAF, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003115 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003116 }
3117
3118 /* type of the leaf is not built-in empty */
Radek Krejcic3738db2016-09-15 15:51:21 +02003119 if (key->type.base == LY_TYPE_EMPTY && key->module->version < 2) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003120 LOGVAL(LYE_KEY_TYPE, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003121 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003122 }
3123
3124 /* config attribute is the same as of the list */
Radek Krejciadb57612016-02-16 13:34:34 +01003125 if ((list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003126 LOGVAL(LYE_KEY_CONFIG, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003127 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003128 }
3129
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003130 /* key is not placed from augment */
3131 if (key->parent->nodetype == LYS_AUGMENT) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003132 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, key, key->name);
3133 LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key inserted from augment.");
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003134 return -1;
3135 }
3136
Radek Krejci3f21ada2016-08-01 13:34:31 +02003137 /* key is not when/if-feature -conditional */
3138 j = 0;
3139 if (key->when || (key->iffeature_size && (j = 1))) {
3140 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, key, j ? "if-feature" : "when", "leaf");
3141 LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key definition cannot depend on a \"%s\" condition.",
3142 j ? "if-feature" : "when");
Radek Krejci581ce772015-11-10 17:22:40 +01003143 return -1;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003144 }
3145
Michal Vasko0b85aa82016-03-07 14:37:43 +01003146 return EXIT_SUCCESS;
Michal Vasko184521f2015-09-24 13:14:26 +02003147}
Michal Vasko730dfdf2015-08-11 14:48:05 +02003148
3149/**
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003150 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003151 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003152 * @param[in] parent The parent node of the unique structure.
Michal Vasko0b85aa82016-03-07 14:37:43 +01003153 * @param[in] uniq_str_path One path from the unique string.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003154 *
3155 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
3156 */
3157int
Radek Krejcid09d1a52016-08-11 14:05:45 +02003158resolve_unique(struct lys_node *parent, const char *uniq_str_path, uint8_t *trg_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003159{
Radek Krejci581ce772015-11-10 17:22:40 +01003160 int rc;
Michal Vasko1e62a092015-12-01 12:27:20 +01003161 const struct lys_node *leaf = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003162
Radek Krejcif3c71de2016-04-11 12:45:46 +02003163 rc = resolve_descendant_schema_nodeid(uniq_str_path, parent->child, LYS_LEAF, 1, 1, &leaf);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003164 if (rc || !leaf) {
Michal Vasko0b85aa82016-03-07 14:37:43 +01003165 if (rc) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003166 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003167 if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003168 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, parent, uniq_str_path[rc - 1], &uniq_str_path[rc - 1]);
Radek Krejcif3c71de2016-04-11 12:45:46 +02003169 } else if (rc == -2) {
Michal Vaskoc66c6d82016-04-12 11:37:31 +02003170 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Unique argument references list.");
Radek Krejci581ce772015-11-10 17:22:40 +01003171 }
Michal Vasko0b85aa82016-03-07 14:37:43 +01003172 rc = -1;
Michal Vasko0b85aa82016-03-07 14:37:43 +01003173 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01003174 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3175 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target leaf not found.");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003176 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003177 }
Radek Krejci581ce772015-11-10 17:22:40 +01003178 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003179 }
Michal Vasko9bb061b2016-02-12 11:00:19 +01003180 if (leaf->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003181 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3182 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target is not a leaf.");
Radek Krejcid09d1a52016-08-11 14:05:45 +02003183 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003184 }
3185
Radek Krejcicf509982015-12-15 09:22:44 +01003186 /* check status */
Radek Krejci48464ed2016-03-17 15:44:09 +01003187 if (lyp_check_status(parent->flags, parent->module, parent->name, leaf->flags, leaf->module, leaf->name, leaf)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003188 return -1;
3189 }
3190
Radek Krejcid09d1a52016-08-11 14:05:45 +02003191 /* check that all unique's targets are of the same config type */
3192 if (*trg_type) {
3193 if (((*trg_type == 1) && (leaf->flags & LYS_CONFIG_R)) || ((*trg_type == 2) && (leaf->flags & LYS_CONFIG_W))) {
3194 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3195 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent,
3196 "Leaf \"%s\" referenced in unique statement is config %s, but previous referenced leaf is config %s.",
3197 uniq_str_path, *trg_type == 1 ? "false" : "true", *trg_type == 1 ? "true" : "false");
3198 return -1;
3199 }
3200 } else {
3201 /* first unique */
3202 if (leaf->flags & LYS_CONFIG_W) {
3203 *trg_type = 1;
3204 } else {
3205 *trg_type = 2;
3206 }
3207 }
3208
Radek Krejcica7efb72016-01-18 13:06:01 +01003209 /* set leaf's unique flag */
3210 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
3211
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003212 return EXIT_SUCCESS;
3213
3214error:
3215
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003216 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003217}
3218
Radek Krejci0c0086a2016-03-24 15:20:28 +01003219void
Michal Vasko23b61ec2015-08-19 11:19:50 +02003220unres_data_del(struct unres_data *unres, uint32_t i)
3221{
3222 /* there are items after the one deleted */
3223 if (i+1 < unres->count) {
3224 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02003225 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003226
3227 /* deleting the last item */
3228 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02003229 free(unres->node);
3230 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003231 }
3232
3233 /* if there are no items after and it is not the last one, just move the counter */
3234 --unres->count;
3235}
3236
Michal Vasko0491ab32015-08-19 14:28:29 +02003237/**
3238 * @brief Resolve (find) a data node from a specific module. Does not log.
3239 *
3240 * @param[in] mod Module to search in.
3241 * @param[in] name Name of the data node.
3242 * @param[in] nam_len Length of the name.
3243 * @param[in] start Data node to start the search from.
3244 * @param[in,out] parents Resolved nodes. If there are some parents,
3245 * they are replaced (!!) with the resolvents.
3246 *
Michal Vasko2471e7f2016-04-11 11:00:15 +02003247 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko0491ab32015-08-19 14:28:29 +02003248 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003249static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003250resolve_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 +02003251{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003252 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02003253 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003254 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003255
Michal Vasko23b61ec2015-08-19 11:19:50 +02003256 if (!parents->count) {
3257 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003258 parents->node = malloc(sizeof *parents->node);
Michal Vasko253035f2015-12-17 16:58:13 +01003259 if (!parents->node) {
3260 LOGMEM;
Michal Vasko2471e7f2016-04-11 11:00:15 +02003261 return -1;
Michal Vasko253035f2015-12-17 16:58:13 +01003262 }
Michal Vaskocf024702015-10-08 15:01:42 +02003263 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003264 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003265 for (i = 0; i < parents->count;) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02003266 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003267 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003268 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003269 continue;
3270 }
3271 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02003272 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003273 if (node->schema->module == mod && !strncmp(node->schema->name, name, nam_len)
3274 && node->schema->name[nam_len] == '\0') {
3275 /* matching target */
3276 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02003277 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02003278 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003279 flag = 1;
3280 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02003281 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003282 ++parents->count;
Michal Vasko253035f2015-12-17 16:58:13 +01003283 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
3284 if (!parents->node) {
3285 return EXIT_FAILURE;
3286 }
Michal Vaskocf024702015-10-08 15:01:42 +02003287 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003288 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003289 }
3290 }
3291 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003292
3293 if (!flag) {
3294 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003295 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02003296 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003297 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02003298 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003299 }
3300
Michal Vasko0491ab32015-08-19 14:28:29 +02003301 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02003302}
3303
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003304/**
3305 * @brief Resolve (find) a data node. Does not log.
3306 *
Radek Krejci581ce772015-11-10 17:22:40 +01003307 * @param[in] mod_name Module name of the data node.
3308 * @param[in] mod_name_len Length of the module name.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003309 * @param[in] name Name of the data node.
3310 * @param[in] nam_len Length of the name.
3311 * @param[in] start Data node to start the search from.
3312 * @param[in,out] parents Resolved nodes. If there are some parents,
3313 * they are replaced (!!) with the resolvents.
3314 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003315 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003316 */
Radek Krejcic5090c32015-08-12 09:46:19 +02003317static int
Radek Krejci581ce772015-11-10 17:22:40 +01003318resolve_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 +02003319 struct unres_data *parents)
Radek Krejcic5090c32015-08-12 09:46:19 +02003320{
Michal Vasko1e62a092015-12-01 12:27:20 +01003321 const struct lys_module *mod;
Michal Vasko31fc3672015-10-21 12:08:13 +02003322 char *str;
Radek Krejcic5090c32015-08-12 09:46:19 +02003323
Michal Vasko23b61ec2015-08-19 11:19:50 +02003324 assert(start);
3325
Michal Vasko31fc3672015-10-21 12:08:13 +02003326 if (mod_name) {
3327 /* we have mod_name, find appropriate module */
3328 str = strndup(mod_name, mod_name_len);
Michal Vasko253035f2015-12-17 16:58:13 +01003329 if (!str) {
3330 LOGMEM;
3331 return -1;
3332 }
Michal Vasko31fc3672015-10-21 12:08:13 +02003333 mod = ly_ctx_get_module(start->schema->module->ctx, str, NULL);
3334 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02003335 if (!mod) {
3336 /* invalid prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003337 return -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02003338 }
3339 } else {
3340 /* no prefix, module is the same as of current node */
3341 mod = start->schema->module;
3342 }
3343
3344 return resolve_data(mod, name, name_len, start, parents);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003345}
3346
Michal Vasko730dfdf2015-08-11 14:48:05 +02003347/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003348 * @brief Resolve a path predicate (leafref) in JSON data context. Logs directly
Radek Krejci48464ed2016-03-17 15:44:09 +01003349 * only specific errors, general no-resolvent error is left to the caller.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003350 *
Michal Vaskobb211122015-08-19 14:03:11 +02003351 * @param[in] pred Predicate to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003352 * @param[in] node Node from which the predicate is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02003353 * @param[in,out] node_match Nodes satisfying the restriction
3354 * without the predicate. Nodes not
3355 * satisfying the predicate are removed.
Michal Vasko0491ab32015-08-19 14:28:29 +02003356 * @param[out] parsed Number of characters parsed, negative on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003357 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003358 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003359 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003360static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003361resolve_path_predicate_data(const char *pred, struct lyd_node *node, struct unres_data *node_match,
Radek Krejci010e54b2016-03-15 09:40:34 +01003362 int *parsed)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003363{
Michal Vasko730dfdf2015-08-11 14:48:05 +02003364 /* ... /node[source = destination] ... */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003365 struct unres_data source_match, dest_match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003366 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vasko0491ab32015-08-19 14:28:29 +02003367 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed_loc = 0, pke_parsed = 0;
3368 int has_predicate, dest_parent_times, i, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003369 uint32_t j;
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003370 struct lyd_node_leaf_list *leaf_dst, *leaf_src;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003371
3372 source_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003373 source_match.node = malloc(sizeof *source_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003374 if (!source_match.node) {
3375 LOGMEM;
3376 return -1;
3377 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003378 dest_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003379 dest_match.node = malloc(sizeof *dest_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003380 if (!dest_match.node) {
3381 LOGMEM;
3382 return -1;
3383 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003384
3385 do {
3386 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
3387 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003388 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, pred[-i], &pred[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003389 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003390 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003391 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003392 parsed_loc += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003393 pred += i;
3394
Michal Vasko23b61ec2015-08-19 11:19:50 +02003395 for (j = 0; j < node_match->count;) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003396 /* source */
Michal Vaskocf024702015-10-08 15:01:42 +02003397 source_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02003398
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003399 /* must be leaf (key of a list) */
Radek Krejci581ce772015-11-10 17:22:40 +01003400 if ((rc = resolve_data_node(sour_pref, sour_pref_len, source, sour_len, node_match->node[j],
Michal Vaskocf024702015-10-08 15:01:42 +02003401 &source_match)) || (source_match.count != 1) || (source_match.node[0]->schema->nodetype != LYS_LEAF)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003402 i = 0;
3403 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003404 }
3405
3406 /* destination */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003407 dest_match.node[0] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003408 dest_parent_times = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003409 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3410 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003411 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003412 rc = -1;
3413 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003414 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003415 pke_parsed = i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003416 for (i = 0; i < dest_parent_times; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02003417 dest_match.node[0] = dest_match.node[0]->parent;
3418 if (!dest_match.node[0]) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003419 i = 0;
Michal Vasko0491ab32015-08-19 14:28:29 +02003420 rc = EXIT_FAILURE;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003421 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003422 }
3423 }
3424 while (1) {
Radek Krejci581ce772015-11-10 17:22:40 +01003425 if ((rc = resolve_data_node(dest_pref, dest_pref_len, dest, dest_len, dest_match.node[0],
Michal Vasko0491ab32015-08-19 14:28:29 +02003426 &dest_match)) || (dest_match.count != 1)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003427 i = 0;
3428 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003429 }
3430
3431 if (pke_len == pke_parsed) {
3432 break;
3433 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003434 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 +02003435 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003436 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003437 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003438 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003439 }
3440 pke_parsed += i;
3441 }
3442
3443 /* check match between source and destination nodes */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003444 leaf_dst = (struct lyd_node_leaf_list *)dest_match.node[0];
3445 while (leaf_dst->value_type == LY_TYPE_LEAFREF) {
3446 leaf_dst = (struct lyd_node_leaf_list *)leaf_dst->value.leafref;
3447 }
3448 leaf_src = (struct lyd_node_leaf_list *)source_match.node[0];
3449 while (leaf_src->value_type == LY_TYPE_LEAFREF) {
3450 leaf_src = (struct lyd_node_leaf_list *)leaf_src->value.leafref;
3451 }
3452 if (leaf_src->value_type != leaf_dst->value_type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003453 goto remove_leafref;
3454 }
3455
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003456 if (!ly_strequal(leaf_src->value_str, leaf_dst->value_str, 1)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003457 goto remove_leafref;
3458 }
3459
3460 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003461 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003462 continue;
3463
3464remove_leafref:
3465 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003466 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003467 }
3468 } while (has_predicate);
3469
Michal Vaskocf024702015-10-08 15:01:42 +02003470 free(source_match.node);
3471 free(dest_match.node);
Michal Vasko0491ab32015-08-19 14:28:29 +02003472 if (parsed) {
3473 *parsed = parsed_loc;
3474 }
3475 return EXIT_SUCCESS;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003476
3477error:
3478
3479 if (source_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003480 free(source_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003481 }
3482 if (dest_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003483 free(dest_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003484 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003485 if (parsed) {
3486 *parsed = -parsed_loc+i;
3487 }
3488 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003489}
3490
Michal Vasko730dfdf2015-08-11 14:48:05 +02003491/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003492 * @brief Resolve a path (leafref) in JSON data context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003493 *
Michal Vaskocf024702015-10-08 15:01:42 +02003494 * @param[in] node Leafref data node.
Michal Vasko23b61ec2015-08-19 11:19:50 +02003495 * @param[in] path Path of the leafref.
Radek Krejci48464ed2016-03-17 15:44:09 +01003496 * @param[out] ret Matching nodes. Expects an empty, but allocated structure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003497 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003498 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003499 */
Michal Vasko184521f2015-09-24 13:14:26 +02003500static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003501resolve_path_arg_data(struct lyd_node *node, const char *path, struct unres_data *ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003502{
Radek Krejci71b795b2015-08-10 16:20:39 +02003503 struct lyd_node *data = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003504 const char *prefix, *name;
Michal Vasko0491ab32015-08-19 14:28:29 +02003505 int pref_len, nam_len, has_predicate, parent_times, i, parsed, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003506 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003507
Michal Vaskocf024702015-10-08 15:01:42 +02003508 assert(node && path && ret && !ret->count);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003509
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003510 parent_times = 0;
Michal Vaskod9173342015-08-17 14:35:36 +02003511 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003512
3513 /* searching for nodeset */
3514 do {
3515 if ((i = parse_path_arg(path, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003516 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path[-i], &path[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003517 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003518 goto error;
3519 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003520 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003521 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003522
Michal Vasko23b61ec2015-08-19 11:19:50 +02003523 if (!ret->count) {
Michal Vaskobfd98e62016-09-02 09:50:05 +02003524 if (parent_times > 0) {
3525 data = node;
3526 for (i = 1; i < parent_times; ++i) {
3527 data = data->parent;
Michal Vasko253035f2015-12-17 16:58:13 +01003528 }
Michal Vaskobfd98e62016-09-02 09:50:05 +02003529 } else if (!parent_times) {
3530 data = node->child;
3531 } else {
3532 /* absolute path */
3533 for (data = node; data->parent; data = data->parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003534 }
3535
Michal Vaskobfd98e62016-09-02 09:50:05 +02003536 /* we may still be parsing it and the pointer is not correct yet */
3537 if (data->prev) {
3538 while (data->prev->next) {
3539 data = data->prev;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003540 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003541 }
3542 }
3543
3544 /* node identifier */
Radek Krejci581ce772015-11-10 17:22:40 +01003545 if ((rc = resolve_data_node(prefix, pref_len, name, nam_len, data, ret))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003546 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003547 LOGVAL(LYE_INELEM_LEN, LY_VLOG_LYD, node, nam_len, name);
Michal Vasko184521f2015-09-24 13:14:26 +02003548 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003549 goto error;
3550 }
3551
3552 if (has_predicate) {
3553 /* we have predicate, so the current results must be lists */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003554 for (j = 0; j < ret->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02003555 if (ret->node[j]->schema->nodetype == LYS_LIST &&
3556 ((struct lys_node_list *)ret->node[0]->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003557 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003558 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003559 continue;
3560 }
3561
3562 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003563 unres_data_del(ret, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003564 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003565 if ((rc = resolve_path_predicate_data(path, node, ret, &i))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003566 if (rc == -1) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003567 LOGVAL(LYE_NORESOLV, LY_VLOG_LYD, node, "leafref", path);
Michal Vasko184521f2015-09-24 13:14:26 +02003568 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003569 goto error;
3570 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003571 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003572 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003573
Michal Vasko23b61ec2015-08-19 11:19:50 +02003574 if (!ret->count) {
Michal Vasko0491ab32015-08-19 14:28:29 +02003575 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003576 goto error;
3577 }
3578 }
3579 } while (path[0] != '\0');
3580
Michal Vaskof02e3742015-08-05 16:27:02 +02003581 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003582
3583error:
3584
Michal Vaskocf024702015-10-08 15:01:42 +02003585 free(ret->node);
3586 ret->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003587 ret->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003588
Michal Vasko0491ab32015-08-19 14:28:29 +02003589 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003590}
3591
Michal Vaskoe27516a2016-10-10 17:55:31 +00003592static int
3593resolve_path_arg_schema_valid_dep_flag(const struct lys_node *op_node, const struct lys_node *first_node, int abs_path)
3594{
3595 int dep1, dep2;
3596 const struct lys_node *node;
3597
3598 if (lys_parent(op_node)) {
3599 /* inner operation (notif/action) */
3600 if (abs_path) {
3601 return 1;
3602 } else {
3603 /* compare depth of both nodes */
3604 for (dep1 = 0, node = op_node; lys_parent(node); node = lys_parent(node));
3605 for (dep2 = 0, node = first_node; lys_parent(node); node = lys_parent(node));
3606 if ((dep2 > dep1) || ((dep2 == dep1) && (op_node != first_node))) {
3607 return 1;
3608 }
3609 }
3610 } else {
3611 /* top-level operation (notif/rpc) */
3612 if (op_node != first_node) {
3613 return 1;
3614 }
3615 }
3616
3617 return 0;
3618}
3619
Michal Vasko730dfdf2015-08-11 14:48:05 +02003620/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003621 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003622 *
Michal Vaskobb211122015-08-19 14:03:11 +02003623 * @param[in] path Path to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003624 * @param[in] context_node Predicate context node (where the predicate is placed).
3625 * @param[in] parent Path context node (where the path begins/is placed).
Michal Vaskoe27516a2016-10-10 17:55:31 +00003626 * @param[in] op_node Optional node if the leafref is in an operation (action/rpc/notif).
Michal Vasko730dfdf2015-08-11 14:48:05 +02003627 *
Michal Vasko184521f2015-09-24 13:14:26 +02003628 * @return 0 on forward reference, otherwise the number
3629 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003630 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003631 */
Michal Vasko1f76a282015-08-04 16:16:53 +02003632static int
Radek Krejciadb57612016-02-16 13:34:34 +01003633resolve_path_predicate_schema(const char *path, const struct lys_node *context_node,
Michal Vaskoe27516a2016-10-10 17:55:31 +00003634 struct lys_node *parent, const struct lys_node *op_node)
Michal Vasko1f76a282015-08-04 16:16:53 +02003635{
Michal Vasko1e62a092015-12-01 12:27:20 +01003636 const struct lys_node *src_node, *dst_node;
Michal Vasko1f76a282015-08-04 16:16:53 +02003637 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vasko6966ea62016-10-21 15:19:30 +02003638 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, pke_parsed, parsed = 0;
3639 int has_predicate, dest_parent_times, i, rc, first_iter;
Michal Vasko1f76a282015-08-04 16:16:53 +02003640
3641 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02003642 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02003643 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003644 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003645 return -parsed+i;
3646 }
3647 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003648 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02003649
Michal Vasko58090902015-08-13 14:04:15 +02003650 /* source (must be leaf) */
Michal Vasko36cbaa42015-12-14 13:15:48 +01003651 if (!sour_pref) {
Radek Krejciadb57612016-02-16 13:34:34 +01003652 sour_pref = context_node->module->name;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003653 }
Radek Krejciadb57612016-02-16 13:34:34 +01003654 rc = lys_get_sibling(context_node->child, sour_pref, sour_pref_len, source, sour_len,
Michal Vasko59ad4582016-09-16 13:15:41 +02003655 LYS_LEAF | LYS_LEAFLIST | LYS_AUGMENT, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003656 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003657 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02003658 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003659 }
3660
3661 /* destination */
Michal Vasko6966ea62016-10-21 15:19:30 +02003662 dest_parent_times = 0;
3663 pke_parsed = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003664 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3665 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003666 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 +02003667 return -parsed;
3668 }
3669 pke_parsed += i;
3670
Radek Krejciadb57612016-02-16 13:34:34 +01003671 for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
Michal Vaskofbaead72016-10-07 10:54:48 +02003672 /* path is supposed to be evaluated in data tree, so we have to skip
3673 * all schema nodes that cannot be instantiated in data tree */
3674 for (dst_node = lys_parent(dst_node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003675 dst_node && !(dst_node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Michal Vaskofbaead72016-10-07 10:54:48 +02003676 dst_node = lys_parent(dst_node));
3677
Michal Vasko1f76a282015-08-04 16:16:53 +02003678 if (!dst_node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003679 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003680 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003681 }
3682 }
Michal Vaskoe27516a2016-10-10 17:55:31 +00003683 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003684 while (1) {
Michal Vasko36cbaa42015-12-14 13:15:48 +01003685 if (!dest_pref) {
3686 dest_pref = dst_node->module->name;
3687 }
3688 rc = lys_get_sibling(dst_node->child, dest_pref, dest_pref_len, dest, dest_len,
Michal Vasko165dc4a2015-10-23 09:44:27 +02003689 LYS_CONTAINER | LYS_LIST | LYS_LEAF | LYS_AUGMENT, &dst_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003690 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003691 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003692 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003693 }
3694
Michal Vaskoe27516a2016-10-10 17:55:31 +00003695 if (first_iter) {
3696 if (resolve_path_arg_schema_valid_dep_flag(op_node, dst_node, 0)) {
3697 parent->flags |= LYS_VALID_DEP;
3698 }
3699 first_iter = 0;
3700 }
3701
Michal Vasko1f76a282015-08-04 16:16:53 +02003702 if (pke_len == pke_parsed) {
3703 break;
3704 }
3705
3706 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
3707 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003708 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent,
Radek Krejciadb57612016-02-16 13:34:34 +01003709 (path_key_expr+pke_parsed)[-i], (path_key_expr+pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003710 return -parsed;
3711 }
3712 pke_parsed += i;
3713 }
3714
3715 /* check source - dest match */
Michal Vasko59ad4582016-09-16 13:15:41 +02003716 if (dst_node->nodetype != src_node->nodetype) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003717 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko59ad4582016-09-16 13:15:41 +02003718 LOGVAL(LYE_SPEC, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "Destination node is not a %s, but a %s.",
3719 strnodetype(src_node->nodetype), strnodetype(dst_node->nodetype));
Michal Vasko184521f2015-09-24 13:14:26 +02003720 return -parsed;
3721 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003722 } while (has_predicate);
3723
3724 return parsed;
3725}
3726
Michal Vasko730dfdf2015-08-11 14:48:05 +02003727/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003728 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003729 *
Michal Vaskobb211122015-08-19 14:03:11 +02003730 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003731 * @param[in] parent_node Parent of the leafref.
Radek Krejci2f12f852016-01-08 12:59:57 +01003732 * @param[in] parent_tpdf Flag if the parent node is actually typedef, in that case the path
3733 * has to contain absolute path
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003734 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003735 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003736 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003737 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003738static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003739resolve_path_arg_schema(const char *path, struct lys_node *parent, int parent_tpdf,
Michal Vasko36cbaa42015-12-14 13:15:48 +01003740 const struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02003741{
Michal Vaskoe27516a2016-10-10 17:55:31 +00003742 const struct lys_node *node, *op_node = NULL;
Radek Krejci27fe55e2016-09-13 17:13:35 +02003743 const struct lys_module *mod, *mod2;
Michal Vasko1f76a282015-08-04 16:16:53 +02003744 const char *id, *prefix, *name;
3745 int pref_len, nam_len, parent_times, has_predicate;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003746 int i, first_iter, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02003747
Michal Vasko184521f2015-09-24 13:14:26 +02003748 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003749 parent_times = 0;
3750 id = path;
3751
Michal Vaskoe27516a2016-10-10 17:55:31 +00003752 /* find operation schema we are in, if applicable */
Michal Vaskoe9914d12016-10-07 14:32:37 +02003753 if (!parent_tpdf) {
Michal Vaskoe27516a2016-10-10 17:55:31 +00003754 for (op_node = lys_parent(parent);
3755 op_node && !(op_node->nodetype & (LYS_ACTION | LYS_NOTIF | LYS_RPC));
3756 op_node = lys_parent(op_node));
Michal Vaskoe9914d12016-10-07 14:32:37 +02003757 }
3758
Radek Krejci27fe55e2016-09-13 17:13:35 +02003759 mod2 = lys_node_module(parent);
Michal Vasko1f76a282015-08-04 16:16:53 +02003760 do {
3761 if ((i = parse_path_arg(id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003762 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 +02003763 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003764 }
3765 id += i;
3766
Michal Vasko184521f2015-09-24 13:14:26 +02003767 if (first_iter) {
Michal Vasko1f76a282015-08-04 16:16:53 +02003768 if (parent_times == -1) {
Radek Krejcic071c542016-01-27 14:57:51 +01003769 /* resolve prefix of the module */
Radek Krejciadb57612016-02-16 13:34:34 +01003770 mod = lys_get_import_module(parent->module, NULL, 0, prefix, pref_len);
Radek Krejci0fa54e92016-09-14 14:01:05 +02003771 mod = lys_get_implemented_module(mod);
Radek Krejcic071c542016-01-27 14:57:51 +01003772 /* get start node */
3773 node = mod ? mod->data : NULL;
Michal Vasko58090902015-08-13 14:04:15 +02003774 if (!node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003775 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3776 "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003777 return EXIT_FAILURE;
Michal Vasko58090902015-08-13 14:04:15 +02003778 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003779 } else if (parent_times > 0) {
Radek Krejci2f12f852016-01-08 12:59:57 +01003780 if (parent_tpdf) {
3781 /* the path is not allowed to contain relative path since we are in top level typedef */
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003782 LOGVAL(LYE_NORESOLV, 0, NULL, "leafref", path);
Radek Krejci2f12f852016-01-08 12:59:57 +01003783 return -1;
3784 }
3785
Michal Vasko94458082016-10-07 14:34:36 +02003786 /* we are looking for a sibling of a node, node it's parent (that is why parent_times - 1) */
3787 for (i = 0, node = parent; i < parent_times - 1; i++) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02003788 /* path is supposed to be evaluated in data tree, so we have to skip
3789 * all schema nodes that cannot be instantiated in data tree */
3790 for (node = lys_parent(node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003791 node && !(node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Radek Krejci3a5501d2016-07-18 22:03:34 +02003792 node = lys_parent(node));
3793
Michal Vasko1f76a282015-08-04 16:16:53 +02003794 if (!node) {
Michal Vaskoe9914d12016-10-07 14:32:37 +02003795 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003796 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003797 }
3798 }
Michal Vaskoe01eca52015-08-13 14:42:02 +02003799 } else {
3800 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003801 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003802 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003803 } else {
Michal Vasko7dc71d02016-03-15 10:42:28 +01003804 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02003805 if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko2f5aceb2016-03-22 10:24:14 +01003806 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 +01003807 return -1;
3808 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003809 node = node->child;
Radek Krejci6892c272016-10-18 20:40:06 +02003810 if (!node) {
3811 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3812 "leafref", path);
3813 return EXIT_FAILURE;
3814 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003815 }
3816
Michal Vasko4f0dad02016-02-15 14:08:23 +01003817 if (!prefix) {
Radek Krejciadb57612016-02-16 13:34:34 +01003818 prefix = lys_node_module(parent)->name;
Michal Vasko4f0dad02016-02-15 14:08:23 +01003819 }
3820
Michal Vasko36cbaa42015-12-14 13:15:48 +01003821 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 +02003822 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003823 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko7a55bea2016-05-02 14:51:20 +02003824 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003825 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003826
Michal Vaskoe27516a2016-10-10 17:55:31 +00003827 if (first_iter) {
3828 /* set external dependency flag, we can decide based on the first found node */
3829 if (!parent_tpdf && op_node && parent_times &&
3830 resolve_path_arg_schema_valid_dep_flag(op_node, node, (parent_times == -1 ? 1 : 0))) {
3831 parent->flags |= LYS_VALID_DEP;
3832 }
3833 first_iter = 0;
3834 }
3835
Michal Vasko1f76a282015-08-04 16:16:53 +02003836 if (has_predicate) {
3837 /* we have predicate, so the current result must be list */
3838 if (node->nodetype != LYS_LIST) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003839 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003840 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003841 }
3842
Michal Vaskoe27516a2016-10-10 17:55:31 +00003843 i = resolve_path_predicate_schema(id, node, parent, op_node);
Radek Krejci27fe55e2016-09-13 17:13:35 +02003844 if (i <= 0) {
3845 if (i == 0) {
3846 return EXIT_FAILURE;
3847 } else { /* i < 0 */
3848 return -1;
3849 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003850 }
3851 id += i;
Michal Vasko6966ea62016-10-21 15:19:30 +02003852 has_predicate = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003853 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02003854 mod = lys_node_module(node);
3855 if (!mod->implemented && mod != mod2) {
3856 /* set the module implemented */
3857 if (lys_set_implemented(mod)) {
3858 return -1;
3859 }
3860 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003861 } while (id[0]);
3862
Michal Vaskoca917682016-07-25 11:00:37 +02003863 /* the target must be leaf or leaf-list (in YANG 1.1 only) */
3864 if ((node->nodetype != LYS_LEAF) && ((lys_node_module(parent)->version != 2) || (node->nodetype != LYS_LEAFLIST))) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003865 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Radek Krejcid47daf62016-08-22 16:23:38 +02003866 LOGVAL(LYE_SPEC, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3867 "Leafref target \"%s\" is not a leaf%s.", path,
3868 lys_node_module(parent)->version != 2 ? "" : " nor a leaf-list");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003869 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02003870 }
3871
Radek Krejcicf509982015-12-15 09:22:44 +01003872 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01003873 if (lyp_check_status(parent->flags, parent->module, parent->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01003874 node->flags, node->module, node->name, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003875 return -1;
3876 }
3877
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003878 if (ret) {
3879 *ret = node;
3880 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02003881
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003882 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02003883}
3884
Michal Vasko730dfdf2015-08-11 14:48:05 +02003885/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003886 * @brief Resolve instance-identifier predicate in JSON data format.
3887 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003888 *
Michal Vaskobb211122015-08-19 14:03:11 +02003889 * @param[in] pred Predicate to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003890 * @param[in,out] node_match Nodes matching the restriction without
3891 * the predicate. Nodes not satisfying
3892 * the predicate are removed.
3893 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003894 * @return Number of characters successfully parsed,
3895 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003896 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003897static int
Michal Vaskof39142b2015-10-21 11:40:05 +02003898resolve_predicate(const char *pred, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003899{
Michal Vasko730dfdf2015-08-11 14:48:05 +02003900 /* ... /node[target = value] ... */
Michal Vaskob2f40be2016-09-08 16:03:48 +02003901 struct lyd_node *target;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003902 const char *model, *name, *value;
Michal Vaskob2f40be2016-09-08 16:03:48 +02003903 int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed, pred_iter, k;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003904 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003905
Michal Vasko1f2cc332015-08-19 11:18:32 +02003906 assert(pred && node_match->count);
3907
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003908 idx = -1;
3909 parsed = 0;
3910
Michal Vaskob2f40be2016-09-08 16:03:48 +02003911 pred_iter = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003912 do {
Michal Vaskof39142b2015-10-21 11:40:05 +02003913 if ((i = parse_predicate(pred, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003914 return -parsed+i;
3915 }
3916 parsed += i;
3917 pred += i;
3918
3919 if (isdigit(name[0])) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02003920 /* pos */
3921 assert(!value);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003922 idx = atoi(name);
Michal Vaskob2f40be2016-09-08 16:03:48 +02003923 } else if (name[0] != '.') {
3924 /* list keys */
3925 if (pred_iter < 0) {
3926 pred_iter = 1;
3927 } else {
3928 ++pred_iter;
3929 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003930 }
3931
Michal Vaskof2f28a12016-09-09 12:43:06 +02003932 for (cur_idx = 1, j = 0; j < node_match->count; ++cur_idx) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003933 /* target */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003934 if (name[0] == '.') {
Michal Vaskob2f40be2016-09-08 16:03:48 +02003935 /* leaf-list value */
Michal Vaskocf024702015-10-08 15:01:42 +02003936 if (node_match->node[j]->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003937 goto remove_instid;
3938 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02003939
3940 target = node_match->node[j];
3941 /* check the value */
3942 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
3943 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
3944 goto remove_instid;
3945 }
3946
3947 } else if (!value) {
3948 /* keyless list position */
3949 if ((node_match->node[j]->schema->nodetype != LYS_LIST)
3950 || ((struct lys_node_list *)node_match->node[j]->schema)->keys) {
3951 goto remove_instid;
3952 }
3953
3954 if (idx != cur_idx) {
3955 goto remove_instid;
3956 }
3957
3958 } else {
3959 /* list key value */
Michal Vaskocf024702015-10-08 15:01:42 +02003960 if (node_match->node[j]->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003961 goto remove_instid;
3962 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02003963
3964 /* key module must match the list module */
3965 if (strncmp(node_match->node[j]->schema->module->name, model, mod_len)
3966 || node_match->node[j]->schema->module->name[mod_len]) {
3967 goto remove_instid;
3968 }
3969 /* find the key leaf */
Michal Vasko045182c2016-09-09 12:44:07 +02003970 for (k = 1, target = node_match->node[j]->child; target && (k < pred_iter); k++, target = target->next);
Michal Vaskob2f40be2016-09-08 16:03:48 +02003971 if (!target) {
3972 goto remove_instid;
3973 }
3974 if ((struct lys_node_leaf *)target->schema !=
3975 ((struct lys_node_list *)node_match->node[j]->schema)->keys[pred_iter - 1]) {
3976 goto remove_instid;
3977 }
3978
3979 /* check the value */
3980 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
3981 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
3982 goto remove_instid;
3983 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003984 }
3985
Michal Vaskob2f40be2016-09-08 16:03:48 +02003986 /* instid is ok, continue check with the next one */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003987 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003988 continue;
3989
3990remove_instid:
Michal Vaskob2f40be2016-09-08 16:03:48 +02003991 /* does not fulfill conditions, remove instid record */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003992 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003993 }
3994 } while (has_predicate);
3995
Michal Vaskob2f40be2016-09-08 16:03:48 +02003996 /* check that all list keys were specified */
3997 if ((pred_iter > 0) && node_match->count) {
Michal Vasko045182c2016-09-09 12:44:07 +02003998 j = 0;
3999 while (j < node_match->count) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004000 assert(node_match->node[j]->schema->nodetype == LYS_LIST);
4001 if (pred_iter < ((struct lys_node_list *)node_match->node[j]->schema)->keys_size) {
4002 /* not enough predicates, just remove the list instance */
4003 unres_data_del(node_match, j);
Michal Vasko045182c2016-09-09 12:44:07 +02004004 } else {
4005 ++j;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004006 }
4007 }
4008
4009 if (!node_match->count) {
4010 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier is missing some list keys.");
4011 }
4012 }
4013
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004014 return parsed;
4015}
4016
Michal Vasko730dfdf2015-08-11 14:48:05 +02004017/**
Michal Vaskof39142b2015-10-21 11:40:05 +02004018 * @brief Resolve instance-identifier in JSON data format. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004019 *
Radek Krejciadb57612016-02-16 13:34:34 +01004020 * @param[in] data Data node where the path is used
Michal Vasko730dfdf2015-08-11 14:48:05 +02004021 * @param[in] path Instance-identifier node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004022 *
Radek Krejcic5090c32015-08-12 09:46:19 +02004023 * @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 +02004024 */
Michal Vasko184521f2015-09-24 13:14:26 +02004025static struct lyd_node *
Radek Krejci48464ed2016-03-17 15:44:09 +01004026resolve_instid(struct lyd_node *data, const char *path)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004027{
Radek Krejcic5090c32015-08-12 09:46:19 +02004028 int i = 0, j;
4029 struct lyd_node *result = NULL;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004030 const struct lys_module *mod;
Radek Krejcic5090c32015-08-12 09:46:19 +02004031 struct ly_ctx *ctx = data->schema->module->ctx;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004032 const char *model, *name;
Radek Krejcic5090c32015-08-12 09:46:19 +02004033 char *str;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004034 int mod_len, name_len, has_predicate;
4035 struct unres_data node_match;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004036
4037 memset(&node_match, 0, sizeof node_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004038
Radek Krejcic5090c32015-08-12 09:46:19 +02004039 /* we need root to resolve absolute path */
4040 for (; data->parent; data = data->parent);
Michal Vaskodb9323c2015-10-16 10:32:44 +02004041 /* we're still parsing it and the pointer is not correct yet */
Michal Vasko0491ab32015-08-19 14:28:29 +02004042 if (data->prev) {
4043 for (; data->prev->next; data = data->prev);
4044 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004045
Radek Krejcic5090c32015-08-12 09:46:19 +02004046 /* search for the instance node */
4047 while (path[i]) {
Michal Vaskof39142b2015-10-21 11:40:05 +02004048 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
Radek Krejcic5090c32015-08-12 09:46:19 +02004049 if (j <= 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004050 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004051 goto error;
4052 }
Radek Krejcic5090c32015-08-12 09:46:19 +02004053 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02004054
Michal Vaskob2f40be2016-09-08 16:03:48 +02004055 str = strndup(model, mod_len);
4056 if (!str) {
4057 LOGMEM;
4058 goto error;
Radek Krejcic5090c32015-08-12 09:46:19 +02004059 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004060 mod = ly_ctx_get_module(ctx, str, NULL);
4061 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02004062
Michal Vasko1f2cc332015-08-19 11:18:32 +02004063 if (resolve_data(mod, name, name_len, data, &node_match)) {
Radek Krejcic5090c32015-08-12 09:46:19 +02004064 /* no instance exists */
4065 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004066 }
4067
4068 if (has_predicate) {
4069 /* we have predicate, so the current results must be list or leaf-list */
Michal Vaskof39142b2015-10-21 11:40:05 +02004070 j = resolve_predicate(&path[i], &node_match);
Radek Krejcic5090c32015-08-12 09:46:19 +02004071 if (j < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004072 LOGVAL(LYE_INPRED, LY_VLOG_LYD, data, &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004073 goto error;
4074 }
Michal Vasko1f2cc332015-08-19 11:18:32 +02004075 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02004076
Michal Vasko1f2cc332015-08-19 11:18:32 +02004077 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02004078 /* no instance exists */
4079 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004080 }
4081 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004082 }
4083
Michal Vasko1f2cc332015-08-19 11:18:32 +02004084 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02004085 /* no instance exists */
4086 return NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02004087 } else if (node_match.count > 1) {
Radek Krejcic5090c32015-08-12 09:46:19 +02004088 /* instance identifier must resolve to a single node */
Radek Krejci48464ed2016-03-17 15:44:09 +01004089 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
Michal Vaskod6adbaa2016-04-11 11:01:09 +02004090 goto error;
Radek Krejcic5090c32015-08-12 09:46:19 +02004091 } else {
4092 /* we have required result, remember it and cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02004093 result = node_match.node[0];
4094 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02004095 return result;
4096 }
4097
4098error:
Radek Krejcic5090c32015-08-12 09:46:19 +02004099 /* cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02004100 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02004101 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004102}
4103
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004104int
4105lys_check_xpath(struct lys_node *node, int check_place)
Michal Vasko9e635ac2016-10-17 11:44:09 +02004106{
4107 struct lys_node *parent, *elem;
4108 struct lyxp_set set;
4109 uint32_t i;
4110 int rc;
4111
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004112 if (check_place) {
4113 parent = node;
4114 while (parent) {
4115 if (parent->nodetype == LYS_GROUPING) {
4116 /* unresolved grouping, skip for now (will be checked later) */
Michal Vasko9e635ac2016-10-17 11:44:09 +02004117 return EXIT_SUCCESS;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004118 }
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004119 if (parent->nodetype == LYS_AUGMENT) {
4120 if (!((struct lys_node_augment *)parent)->target) {
4121 /* uresolved augment, skip for now (will be checked later) */
4122 return EXIT_SUCCESS;
4123 } else {
4124 parent = ((struct lys_node_augment *)parent)->target;
4125 continue;
4126 }
4127 }
4128 parent = parent->parent;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004129 }
Michal Vasko9e635ac2016-10-17 11:44:09 +02004130 }
4131
4132 rc = lyxp_node_atomize(node, &set);
4133 if (rc) {
4134 return rc;
4135 }
4136
4137 for (parent = node; parent && !(parent->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); parent = lys_parent(parent));
4138
4139 for (i = 0; i < set.used; ++i) {
4140 /* skip roots'n'stuff */
4141 if (set.val.snodes[i].type == LYXP_NODE_ELEM) {
4142 /* XPath expression cannot reference "lower" status than the node that has the definition */
4143 if (lyp_check_status(node->flags, lys_node_module(node), node->name, set.val.snodes[i].snode->flags,
4144 lys_node_module(set.val.snodes[i].snode), set.val.snodes[i].snode->name, node)) {
4145 return -1;
4146 }
4147
4148 if (parent) {
4149 for (elem = set.val.snodes[i].snode; elem && (elem != parent); elem = lys_parent(elem));
4150 if (!elem) {
4151 /* not in node's RPC or notification subtree, set the flag */
4152 node->flags |= LYS_VALID_DEP;
4153 break;
4154 }
4155 }
4156 }
4157 }
4158
4159 free(set.val.snodes);
4160 return EXIT_SUCCESS;
4161}
4162
4163/**
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004164 * @brief Passes config flag down to children, skips nodes without config flags.
4165 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004166 *
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004167 * @param[in] node Siblings and their children to have flags changed.
Michal Vaskoe022a562016-09-27 14:24:15 +02004168 * @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 +02004169 * @param[in] flags Flags to assign to all the nodes.
Michal Vaskoa86508c2016-08-26 14:30:19 +02004170 *
4171 * @return 0 on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004172 */
Michal Vaskoa86508c2016-08-26 14:30:19 +02004173static int
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004174inherit_config_flag(struct lys_node *node, int flags, int clear)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004175{
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004176 assert(!(flags ^ (flags & LYS_CONFIG_MASK)));
Radek Krejci1d82ef62015-08-07 14:44:40 +02004177 LY_TREE_FOR(node, node) {
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004178 if (lys_check_xpath(node, 0)) {
Michal Vasko9e635ac2016-10-17 11:44:09 +02004179 return -1;
4180 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004181 if (clear) {
4182 node->flags &= ~LYS_CONFIG_MASK;
Michal Vaskoc2a8d362016-09-29 08:50:13 +02004183 node->flags &= ~LYS_CONFIG_SET;
Michal Vaskoe022a562016-09-27 14:24:15 +02004184 } else {
4185 if (node->flags & LYS_CONFIG_SET) {
4186 /* skip nodes with an explicit config value */
4187 if ((flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
4188 LOGVAL(LYE_INARG, LY_VLOG_LYS, node, "true", "config");
4189 LOGVAL(LYE_SPEC, LY_VLOG_LYS, node, "State nodes cannot have configuration nodes as children.");
4190 return -1;
4191 }
4192 continue;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004193 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004194
4195 if (!(node->nodetype & (LYS_USES | LYS_GROUPING))) {
4196 node->flags = (node->flags & ~LYS_CONFIG_MASK) | flags;
4197 /* check that configuration lists have keys */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004198 if ((node->nodetype == LYS_LIST) && (node->flags & LYS_CONFIG_W)
4199 && !((struct lys_node_list *)node)->keys_size) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004200 LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_LYS, node, "key", "list");
4201 return -1;
4202 }
4203 }
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004204 }
Radek Krejcibf2abff2016-08-23 15:51:52 +02004205 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004206 if (inherit_config_flag(node->child, flags, clear)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004207 return -1;
4208 }
Radek Krejci3a5501d2016-07-18 22:03:34 +02004209 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004210 }
Michal Vaskoa86508c2016-08-26 14:30:19 +02004211
4212 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004213}
4214
Michal Vasko730dfdf2015-08-11 14:48:05 +02004215/**
Michal Vasko7178e692016-02-12 15:58:05 +01004216 * @brief Resolve augment target. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004217 *
Michal Vaskobb211122015-08-19 14:03:11 +02004218 * @param[in] aug Augment to use.
Michal Vasko3edeaf72016-02-11 13:17:43 +01004219 * @param[in] siblings Nodes where to start the search in. If set, uses augment, if not, standalone augment.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004220 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004221 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004222 */
Michal Vasko7178e692016-02-12 15:58:05 +01004223static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004224resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004225{
Michal Vaskoe022a562016-09-27 14:24:15 +02004226 int rc, clear_config;
Michal Vasko1d87a922015-08-21 12:57:16 +02004227 struct lys_node *sub;
Pavol Vican47319932016-08-29 09:14:47 +02004228 const struct lys_node *aug_target, *parent;
Radek Krejci27fe55e2016-09-13 17:13:35 +02004229 struct lys_module *mod;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004230
Michal Vasko15b36692016-08-26 15:29:54 +02004231 assert(aug && !aug->target);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004232
Michal Vasko15b36692016-08-26 15:29:54 +02004233 /* resolve target node */
4234 rc = resolve_augment_schema_nodeid(aug->target_name, siblings, (siblings ? NULL : aug->module), &aug_target);
4235 if (rc == -1) {
4236 return -1;
4237 }
4238 if (rc > 0) {
4239 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, aug, aug->target_name[rc - 1], &aug->target_name[rc - 1]);
4240 return -1;
4241 }
4242 if (!aug_target) {
4243 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
4244 return EXIT_FAILURE;
4245 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004246
Radek Krejci27fe55e2016-09-13 17:13:35 +02004247 /* check that we want to connect augment into its target */
4248 mod = lys_main_module(aug->module);
4249 if (!mod->implemented) {
4250 /* it must be augment only to the same module,
4251 * otherwise we do not apply augment in not-implemented
4252 * module. If the module is set to be implemented in future,
4253 * the augment is being resolved and checked again */
4254 for (sub = aug->target; sub; sub = lys_parent(sub)) {
4255 if (lys_node_module(sub) != mod) {
4256 /* this is not an implemented module and the augment
4257 * target some other module, so avoid its connecting
4258 * to the target */
4259 return EXIT_SUCCESS;
4260 }
4261 }
4262 }
4263
Michal Vasko15b36692016-08-26 15:29:54 +02004264 if (!aug->child) {
4265 /* nothing to do */
4266 LOGWRN("Augment \"%s\" without children.", aug->target_name);
Radek Krejci27fe55e2016-09-13 17:13:35 +02004267 goto success;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004268 }
4269
Michal Vaskod58d5962016-03-02 14:29:41 +01004270 /* check for mandatory nodes - if the target node is in another module
4271 * the added nodes cannot be mandatory
4272 */
Michal Vasko15b36692016-08-26 15:29:54 +02004273 if (!aug->parent && (lys_node_module((struct lys_node *)aug) != lys_node_module(aug_target))
Radek Krejcie00d2312016-08-12 15:27:49 +02004274 && (rc = lyp_check_mandatory_augment(aug))) {
4275 return rc;
Michal Vaskod58d5962016-03-02 14:29:41 +01004276 }
4277
Michal Vasko07e89ef2016-03-03 13:28:57 +01004278 /* check augment target type and then augment nodes type */
Michal Vasko15b36692016-08-26 15:29:54 +02004279 if (aug_target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF)) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004280 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004281 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES | LYS_CHOICE))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004282 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4283 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko15b36692016-08-26 15:29:54 +02004284 strnodetype(aug_target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004285 return -1;
4286 }
4287 }
Michal Vasko15b36692016-08-26 15:29:54 +02004288 } else if (aug_target->nodetype == LYS_CHOICE) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004289 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004290 if (!(sub->nodetype & (LYS_CASE | LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004291 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4292 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko15b36692016-08-26 15:29:54 +02004293 strnodetype(aug_target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004294 return -1;
4295 }
4296 }
4297 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01004298 LOGVAL(LYE_INARG, LY_VLOG_LYS, aug, aug->target_name, "target-node");
Michal Vasko15b36692016-08-26 15:29:54 +02004299 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Invalid augment target node type \"%s\".", strnodetype(aug_target->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004300 return -1;
4301 }
4302
Radek Krejcic071c542016-01-27 14:57:51 +01004303 /* check identifier uniqueness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02004304 LY_TREE_FOR(aug->child, sub) {
Michal Vasko15b36692016-08-26 15:29:54 +02004305 if (lys_check_id(sub, (struct lys_node *)aug_target, NULL)) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02004306 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02004307 }
4308 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004309
Michal Vasko15b36692016-08-26 15:29:54 +02004310 /* finally reconnect augmenting data into the target - add them to the target child list,
4311 * by setting aug->target we know the augment is fully resolved now */
4312 aug->target = (struct lys_node *)aug_target;
4313 if (aug->target->child) {
4314 sub = aug->target->child->prev; /* remember current target's last node */
4315 sub->next = aug->child; /* connect augmenting data after target's last node */
4316 aug->target->child->prev = aug->child->prev; /* new target's last node is last augmenting node */
4317 aug->child->prev = sub; /* finish connecting of both child lists */
4318 } else {
4319 aug->target->child = aug->child;
4320 }
4321
Michal Vasko9e635ac2016-10-17 11:44:09 +02004322 /* inherit config information from actual parent */
4323 for(parent = aug_target; parent && !(parent->nodetype & (LYS_NOTIF | LYS_INPUT | LYS_OUTPUT | LYS_RPC)); parent = lys_parent(parent));
4324 clear_config = (parent) ? 1 : 0;
4325 LY_TREE_FOR(aug->child, sub) {
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004326 if (inherit_config_flag(sub, aug_target->flags & LYS_CONFIG_MASK, clear_config)) {
Michal Vasko9e635ac2016-10-17 11:44:09 +02004327 return -1;
4328 }
4329 }
4330
Radek Krejci27fe55e2016-09-13 17:13:35 +02004331success:
4332 if (mod->implemented) {
4333 /* make target modules also implemented */
4334 for (sub = aug->target; sub; sub = lys_parent(sub)) {
4335 if (lys_set_implemented(sub->module)) {
4336 return -1;
4337 }
4338 }
4339 }
4340
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004341 return EXIT_SUCCESS;
4342}
4343
Michal Vasko730dfdf2015-08-11 14:48:05 +02004344/**
Pavol Vican855ca622016-09-05 13:07:54 +02004345 * @brief Resolve (find) choice default case. Does not log.
4346 *
4347 * @param[in] choic Choice to use.
4348 * @param[in] dflt Name of the default case.
4349 *
4350 * @return Pointer to the default node or NULL.
4351 */
4352static struct lys_node *
4353resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
4354{
4355 struct lys_node *child, *ret;
4356
4357 LY_TREE_FOR(choic->child, child) {
4358 if (child->nodetype == LYS_USES) {
4359 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
4360 if (ret) {
4361 return ret;
4362 }
4363 }
4364
4365 if (ly_strequal(child->name, dflt, 1) && (child->nodetype & (LYS_ANYDATA | LYS_CASE
Radek Krejci2f792db2016-09-12 10:52:33 +02004366 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE))) {
Pavol Vican855ca622016-09-05 13:07:54 +02004367 return child;
4368 }
4369 }
4370
4371 return NULL;
4372}
4373
4374/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02004375 * @brief Resolve uses, apply augments, refines. Logs directly.
4376 *
Michal Vaskobb211122015-08-19 14:03:11 +02004377 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004378 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004379 *
Michal Vaskodef0db12015-10-07 13:22:48 +02004380 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004381 */
Michal Vasko184521f2015-09-24 13:14:26 +02004382static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004383resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004384{
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004385 struct ly_ctx *ctx = uses->module->ctx; /* shortcut */
Pavol Vican855ca622016-09-05 13:07:54 +02004386 struct lys_node *node = NULL, *next, *iter, **refine_nodes = NULL;
Pavol Vican55abd332016-07-12 15:54:49 +02004387 struct lys_node *node_aux, *parent, *tmp;
Radek Krejci200bf712016-08-16 17:11:04 +02004388 struct lys_node_leaflist *llist;
4389 struct lys_node_leaf *leaf;
Radek Krejci76512572015-08-04 09:47:08 +02004390 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004391 struct lys_restr *must, **old_must;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004392 struct lys_iffeature *iff, **old_iff;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004393 int i, j, k, rc;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004394 uint8_t size, *old_size;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004395 unsigned int usize, usize1, usize2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004396
Michal Vasko71e1aa82015-08-12 12:17:51 +02004397 assert(uses->grp);
Michal Vaskoe7708512016-03-11 10:26:55 +01004398 /* HACK just check that the grouping is resolved */
Michal Vaskodef0db12015-10-07 13:22:48 +02004399 assert(!uses->grp->nacm);
Michal Vasko71e1aa82015-08-12 12:17:51 +02004400
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004401 if (!uses->grp->child) {
4402 /* grouping without children, warning was already displayed */
4403 return EXIT_SUCCESS;
4404 }
4405
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004406 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01004407 LY_TREE_FOR(uses->grp->child, node_aux) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004408 node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, uses->nacm, unres, 0);
Michal Vasko1e62a092015-12-01 12:27:20 +01004409 if (!node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004410 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, uses->grp->name, "uses");
4411 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Copying data from grouping failed.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004412 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004413 }
Pavol Vican55abd332016-07-12 15:54:49 +02004414 /* test the name of siblings */
4415 LY_TREE_FOR((uses->parent) ? uses->parent->child : lys_main_module(uses->module)->data, tmp) {
Pavol Vican2510ddc2016-07-18 16:23:44 +02004416 if (!(tmp->nodetype & (LYS_USES | LYS_GROUPING | LYS_CASE)) && ly_strequal(tmp->name, node_aux->name, 1)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004417 goto fail;
Pavol Vican55abd332016-07-12 15:54:49 +02004418 }
4419 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004420 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004421
Michal Vaskodef0db12015-10-07 13:22:48 +02004422 /* we managed to copy the grouping, the rest must be possible to resolve */
4423
Pavol Vican855ca622016-09-05 13:07:54 +02004424 if (uses->refine_size) {
4425 refine_nodes = malloc(uses->refine_size * sizeof *refine_nodes);
4426 if (!refine_nodes) {
4427 LOGMEM;
4428 goto fail;
4429 }
4430 }
4431
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004432 /* apply refines */
4433 for (i = 0; i < uses->refine_size; i++) {
4434 rfn = &uses->refine[i];
Michal Vasko3edeaf72016-02-11 13:17:43 +01004435 rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child, LYS_NO_RPC_NOTIF_NODE,
Radek Krejcif3c71de2016-04-11 12:45:46 +02004436 1, 0, (const struct lys_node **)&node);
Michal Vasko9bb061b2016-02-12 11:00:19 +01004437 if (rc || !node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004438 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004439 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004440 }
4441
Radek Krejci1d82ef62015-08-07 14:44:40 +02004442 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004443 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
4444 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Refine substatements not applicable to the target-node.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004445 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004446 }
Pavol Vican855ca622016-09-05 13:07:54 +02004447 refine_nodes[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004448
4449 /* description on any nodetype */
4450 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004451 lydict_remove(ctx, node->dsc);
4452 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004453 }
4454
4455 /* reference on any nodetype */
4456 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004457 lydict_remove(ctx, node->ref);
4458 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004459 }
4460
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004461 /* config on any nodetype,
4462 * in case of notification or rpc/action, the config is not applicable (there is no config status) */
4463 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004464 node->flags &= ~LYS_CONFIG_MASK;
4465 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004466 }
4467
4468 /* default value ... */
Radek Krejci200bf712016-08-16 17:11:04 +02004469 if (rfn->dflt_size) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004470 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004471 /* leaf */
Radek Krejci200bf712016-08-16 17:11:04 +02004472 leaf = (struct lys_node_leaf *)node;
4473
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004474 /* replace default value */
Radek Krejci200bf712016-08-16 17:11:04 +02004475 lydict_remove(ctx, leaf->dflt);
4476 leaf->dflt = lydict_insert(ctx, rfn->dflt[0], 0);
4477
4478 /* check the default value */
4479 if (unres_schema_add_str(leaf->module, unres, &leaf->type, UNRES_TYPE_DFLT, leaf->dflt) == -1) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004480 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004481 }
Radek Krejci200bf712016-08-16 17:11:04 +02004482 } else if (node->nodetype == LYS_LEAFLIST) {
4483 /* leaf-list */
4484 llist = (struct lys_node_leaflist *)node;
4485
4486 /* remove complete set of defaults in target */
4487 for (i = 0; i < llist->dflt_size; i++) {
4488 lydict_remove(ctx, llist->dflt[i]);
4489 }
4490 free(llist->dflt);
4491
4492 /* copy the default set from refine */
4493 llist->dflt_size = rfn->dflt_size;
4494 llist->dflt = malloc(llist->dflt_size * sizeof *llist->dflt);
4495 for (i = 0; i < llist->dflt_size; i++) {
4496 llist->dflt[i] = lydict_insert(ctx, rfn->dflt[i], 0);
4497 }
4498
4499 /* check default value */
4500 for (i = 0; i < llist->dflt_size; i++) {
4501 if (unres_schema_add_str(llist->module, unres, &llist->type, UNRES_TYPE_DFLT, llist->dflt[i]) == -1) {
Pavol Vican855ca622016-09-05 13:07:54 +02004502 goto fail;
Radek Krejci200bf712016-08-16 17:11:04 +02004503 }
4504 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004505 }
4506 }
4507
4508 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02004509 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004510 if (node->nodetype & (LYS_LEAF | LYS_ANYDATA | LYS_CHOICE)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004511 /* remove current value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004512 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004513
4514 /* set new value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004515 node->flags |= (rfn->flags & LYS_MAND_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004516 }
Pavol Vican855ca622016-09-05 13:07:54 +02004517 if (rfn->flags & LYS_MAND_TRUE) {
4518 /* check if node has default value */
4519 if ((node->nodetype & LYS_LEAF) && ((struct lys_node_leaf *)node)->dflt) {
4520 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"mandatory\" statement is forbidden on leaf with \"default\".");
4521 goto fail;
4522 }
4523 if ((node->nodetype & LYS_CHOICE) && ((struct lys_node_choice *)node)->dflt) {
4524 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"mandatory\" statement is forbidden on choices with \"default\".");
4525 goto fail;
4526 }
4527 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004528 }
4529
4530 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004531 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
4532 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
4533 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004534 }
4535
4536 /* min/max-elements on list or leaf-list */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004537 if (node->nodetype == LYS_LIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004538 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004539 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004540 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004541 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004542 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004543 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02004544 } else if (node->nodetype == LYS_LEAFLIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004545 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004546 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004547 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004548 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004549 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004550 }
4551 }
4552
4553 /* must in leaf, leaf-list, list, container or anyxml */
4554 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004555 switch (node->nodetype) {
4556 case LYS_LEAF:
4557 old_size = &((struct lys_node_leaf *)node)->must_size;
4558 old_must = &((struct lys_node_leaf *)node)->must;
4559 break;
4560 case LYS_LEAFLIST:
4561 old_size = &((struct lys_node_leaflist *)node)->must_size;
4562 old_must = &((struct lys_node_leaflist *)node)->must;
4563 break;
4564 case LYS_LIST:
4565 old_size = &((struct lys_node_list *)node)->must_size;
4566 old_must = &((struct lys_node_list *)node)->must;
4567 break;
4568 case LYS_CONTAINER:
4569 old_size = &((struct lys_node_container *)node)->must_size;
4570 old_must = &((struct lys_node_container *)node)->must;
4571 break;
4572 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02004573 case LYS_ANYDATA:
4574 old_size = &((struct lys_node_anydata *)node)->must_size;
4575 old_must = &((struct lys_node_anydata *)node)->must;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004576 break;
4577 default:
4578 LOGINT;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004579 goto fail;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004580 }
4581
4582 size = *old_size + rfn->must_size;
4583 must = realloc(*old_must, size * sizeof *rfn->must);
4584 if (!must) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004585 LOGMEM;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004586 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004587 }
Pavol Vican855ca622016-09-05 13:07:54 +02004588 for (k = 0, j = *old_size; k < rfn->must_size; k++, j++) {
4589 must[j].expr = lydict_insert(ctx, rfn->must[k].expr, 0);
4590 must[j].dsc = lydict_insert(ctx, rfn->must[k].dsc, 0);
4591 must[j].ref = lydict_insert(ctx, rfn->must[k].ref, 0);
4592 must[j].eapptag = lydict_insert(ctx, rfn->must[k].eapptag, 0);
4593 must[j].emsg = lydict_insert(ctx, rfn->must[k].emsg, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004594 }
4595
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004596 *old_must = must;
4597 *old_size = size;
Michal Vasko508a50d2016-09-07 14:50:33 +02004598
4599 /* check XPath dependencies again */
4600 if (unres_schema_add_node(node->module, unres, node, UNRES_XPATH, NULL) == -1) {
4601 goto fail;
4602 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004603 }
Radek Krejci363bd4a2016-07-29 14:30:20 +02004604
4605 /* if-feature in leaf, leaf-list, list, container or anyxml */
4606 if (rfn->iffeature_size) {
4607 old_size = &node->iffeature_size;
4608 old_iff = &node->iffeature;
4609
4610 size = *old_size + rfn->iffeature_size;
4611 iff = realloc(*old_iff, size * sizeof *rfn->iffeature);
4612 if (!iff) {
4613 LOGMEM;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004614 goto fail;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004615 }
Pavol Vican855ca622016-09-05 13:07:54 +02004616 for (k = 0, j = *old_size; k < rfn->iffeature_size; k++, j++) {
4617 resolve_iffeature_getsizes(&rfn->iffeature[k], &usize1, &usize2);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004618 if (usize1) {
4619 /* there is something to duplicate */
4620 /* duplicate compiled expression */
4621 usize = (usize1 / 4) + (usize1 % 4) ? 1 : 0;
4622 iff[j].expr = malloc(usize * sizeof *iff[j].expr);
Pavol Vican855ca622016-09-05 13:07:54 +02004623 memcpy(iff[j].expr, rfn->iffeature[k].expr, usize * sizeof *iff[j].expr);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004624
4625 /* duplicate list of feature pointers */
Pavol Vican855ca622016-09-05 13:07:54 +02004626 iff[j].features = malloc(usize2 * sizeof *iff[k].features);
4627 memcpy(iff[j].features, rfn->iffeature[k].features, usize2 * sizeof *iff[j].features);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004628 }
4629 }
4630
4631 *old_iff = iff;
4632 *old_size = size;
4633 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004634 }
4635
4636 /* apply augments */
4637 for (i = 0; i < uses->augment_size; i++) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004638 rc = resolve_augment(&uses->augment[i], uses->child);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004639 if (rc) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004640 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004641 }
4642 }
4643
Pavol Vican855ca622016-09-05 13:07:54 +02004644 /* check refines */
4645 for (i = 0; i < uses->refine_size; i++) {
4646 node = refine_nodes[i];
4647 rfn = &uses->refine[i];
4648
4649 /* config on any nodetype */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004650 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Pavol Vican855ca622016-09-05 13:07:54 +02004651 for (parent = lys_parent(node); parent && parent->nodetype == LYS_USES; parent = lys_parent(parent));
4652 if (parent && parent->nodetype != LYS_GROUPING &&
4653 ((parent->flags & LYS_CONFIG_MASK) != (rfn->flags & LYS_CONFIG_MASK)) &&
4654 (rfn->flags & LYS_CONFIG_W)) {
4655 /* setting config true under config false is prohibited */
4656 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
4657 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4658 "changing config from 'false' to 'true' is prohibited while "
4659 "the target's parent is still config 'false'.");
4660 goto fail;
4661 }
4662
4663 /* inherit config change to the target children */
4664 LY_TREE_DFS_BEGIN(node->child, next, iter) {
4665 if (rfn->flags & LYS_CONFIG_W) {
4666 if (iter->flags & LYS_CONFIG_SET) {
4667 /* config is set explicitely, go to next sibling */
4668 next = NULL;
4669 goto nextsibling;
4670 }
4671 } else { /* LYS_CONFIG_R */
4672 if ((iter->flags & LYS_CONFIG_SET) && (iter->flags & LYS_CONFIG_W)) {
4673 /* error - we would have config data under status data */
4674 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
4675 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4676 "changing config from 'true' to 'false' is prohibited while the target "
4677 "has still a children with explicit config 'true'.");
4678 goto fail;
4679 }
4680 }
4681 /* change config */
4682 iter->flags &= ~LYS_CONFIG_MASK;
4683 iter->flags |= (rfn->flags & LYS_CONFIG_MASK);
4684
4685 /* select next iter - modified LY_TREE_DFS_END */
4686 if (iter->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
4687 next = NULL;
4688 } else {
4689 next = iter->child;
4690 }
4691nextsibling:
4692 if (!next) {
4693 /* try siblings */
4694 next = iter->next;
4695 }
4696 while (!next) {
4697 /* parent is already processed, go to its sibling */
4698 iter = lys_parent(iter);
4699
4700 /* no siblings, go back through parents */
4701 if (iter == node) {
4702 /* we are done, no next element to process */
4703 break;
4704 }
4705 next = iter->next;
4706 }
4707 }
4708 }
4709
4710 /* default value */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004711 if (rfn->dflt_size) {
4712 if (node->nodetype == LYS_CHOICE) {
4713 /* choice */
4714 ((struct lys_node_choice *)node)->dflt = resolve_choice_dflt((struct lys_node_choice *)node,
4715 rfn->dflt[0]);
4716 if (!((struct lys_node_choice *)node)->dflt) {
4717 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->dflt[0], "default");
4718 goto fail;
4719 }
4720 if (lyp_check_mandatory_choice(node)) {
4721 goto fail;
4722 }
Pavol Vican855ca622016-09-05 13:07:54 +02004723 }
4724 }
4725
4726 /* min/max-elements on list or leaf-list */
4727 if (node->nodetype == LYS_LIST) {
4728 if (((struct lys_node_list *)node)->min > ((struct lys_node_list *)node)->max) {
4729 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
4730 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "\"min-elements\" is bigger than \"max-elements\".");
4731 goto fail;
4732 }
4733 } else if (node->nodetype == LYS_LEAFLIST) {
4734 if (((struct lys_node_leaflist *)node)->min > ((struct lys_node_leaflist *)node)->max) {
4735 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
4736 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "\"min-elements\" is bigger than \"max-elements\".");
4737 goto fail;
4738 }
4739 }
4740
4741 /* additional checks */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004742 /* default value with mandatory/min-elements */
Pavol Vican855ca622016-09-05 13:07:54 +02004743 if (node->nodetype == LYS_LEAFLIST) {
4744 llist = (struct lys_node_leaflist *)node;
4745 if (llist->dflt_size && llist->min) {
4746 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, rfn->dflt_size ? "default" : "min-elements", "refine");
4747 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
4748 "The \"min-elements\" statement with non-zero value is forbidden on leaf-lists with the \"default\" statement.");
4749 goto fail;
4750 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004751 } else if (node->nodetype == LYS_LEAF) {
4752 leaf = (struct lys_node_leaf *)node;
4753 if (leaf->dflt && (leaf->flags & LYS_MAND_TRUE)) {
4754 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, rfn->dflt_size ? "default" : "mandatory", "refine");
4755 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
4756 "The \"mandatory\" statement is forbidden on leafs with the \"default\" statement.");
4757 goto fail;
4758 }
Pavol Vican855ca622016-09-05 13:07:54 +02004759 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004760
Pavol Vican855ca622016-09-05 13:07:54 +02004761 /* check for mandatory node in default case, first find the closest parent choice to the changed node */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004762 if ((rfn->flags & LYS_MAND_TRUE) || rfn->mod.list.min) {
Pavol Vican855ca622016-09-05 13:07:54 +02004763 for (parent = node->parent;
4764 parent && !(parent->nodetype & (LYS_CHOICE | LYS_GROUPING | LYS_ACTION | LYS_USES));
4765 parent = parent->parent) {
4766 if (parent->nodetype == LYS_CONTAINER && ((struct lys_node_container *)parent)->presence) {
4767 /* stop also on presence containers */
4768 break;
4769 }
4770 }
4771 /* and if it is a choice with the default case, check it for presence of a mandatory node in it */
4772 if (parent && parent->nodetype == LYS_CHOICE && ((struct lys_node_choice *)parent)->dflt) {
4773 if (lyp_check_mandatory_choice(parent)) {
4774 goto fail;
4775 }
4776 }
4777 }
4778 }
4779 free(refine_nodes);
4780
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004781 return EXIT_SUCCESS;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004782
4783fail:
4784 LY_TREE_FOR_SAFE(uses->child, next, iter) {
4785 lys_node_free(iter, NULL, 0);
4786 }
Pavol Vican855ca622016-09-05 13:07:54 +02004787 free(refine_nodes);
Michal Vaskoa86508c2016-08-26 14:30:19 +02004788 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004789}
4790
Radek Krejci018f1f52016-08-03 16:01:20 +02004791static int
4792identity_backlink_update(struct lys_ident *der, struct lys_ident *base)
4793{
4794 int i;
4795
4796 assert(der && base);
4797
Radek Krejci018f1f52016-08-03 16:01:20 +02004798 if (!base->der) {
Radek Krejci85a54be2016-10-20 12:39:56 +02004799 /* create a set for backlinks if it does not exist */
4800 base->der = ly_set_new();
Radek Krejci018f1f52016-08-03 16:01:20 +02004801 }
Radek Krejci85a54be2016-10-20 12:39:56 +02004802 /* store backlink */
4803 ly_set_add(base->der, der, LY_SET_OPT_USEASLIST);
Radek Krejci018f1f52016-08-03 16:01:20 +02004804
Radek Krejci85a54be2016-10-20 12:39:56 +02004805 /* do it recursively */
Radek Krejci018f1f52016-08-03 16:01:20 +02004806 for (i = 0; i < base->base_size; i++) {
4807 if (identity_backlink_update(der, base->base[i])) {
4808 return EXIT_FAILURE;
4809 }
4810 }
4811
4812 return EXIT_SUCCESS;
4813}
4814
Michal Vasko730dfdf2015-08-11 14:48:05 +02004815/**
4816 * @brief Resolve base identity recursively. Does not log.
4817 *
4818 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004819 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004820 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004821 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004822 *
Radek Krejci219fa612016-08-15 10:36:51 +02004823 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on crucial error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004824 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004825static int
Michal Vasko1e62a092015-12-01 12:27:20 +01004826resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Radek Krejci018f1f52016-08-03 16:01:20 +02004827 struct unres_schema *unres, struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004828{
Michal Vaskof02e3742015-08-05 16:27:02 +02004829 uint32_t i, j;
Radek Krejci018f1f52016-08-03 16:01:20 +02004830 struct lys_ident *base = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004831
Radek Krejcicf509982015-12-15 09:22:44 +01004832 assert(ret);
4833
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004834 /* search module */
4835 for (i = 0; i < module->ident_size; i++) {
4836 if (!strcmp(basename, module->ident[i].name)) {
4837
4838 if (!ident) {
4839 /* just search for type, so do not modify anything, just return
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004840 * the base identity pointer */
Radek Krejcicf509982015-12-15 09:22:44 +01004841 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004842 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004843 }
4844
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004845 base = &module->ident[i];
4846 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004847 }
4848 }
4849
4850 /* search submodules */
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004851 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
4852 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
4853 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004854
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004855 if (!ident) {
4856 *ret = &module->inc[j].submodule->ident[i];
4857 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004858 }
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004859
4860 base = &module->inc[j].submodule->ident[i];
4861 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004862 }
4863 }
4864 }
4865
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004866matchfound:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004867 /* we found it somewhere */
Radek Krejcibabbff82016-02-19 13:31:37 +01004868 if (base) {
Radek Krejci018f1f52016-08-03 16:01:20 +02004869 /* is it already completely resolved? */
4870 for (i = 0; i < unres->count; i++) {
Radek Krejciba7b1cc2016-08-08 13:44:43 +02004871 if ((unres->item[i] == base) && (unres->type[i] == UNRES_IDENT)) {
Radek Krejci018f1f52016-08-03 16:01:20 +02004872 /* identity found, but not yet resolved, so do not return it in *res and try it again later */
4873
4874 /* simple check for circular reference,
4875 * the complete check is done as a side effect of using only completely
4876 * resolved identities (previous check of unres content) */
4877 if (ly_strequal((const char *)unres->str_snode[i], ident->name, 1)) {
4878 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, basename, "base");
4879 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Circular reference of \"%s\" identity.", basename);
Radek Krejci219fa612016-08-15 10:36:51 +02004880 return -1;
Radek Krejci018f1f52016-08-03 16:01:20 +02004881 }
4882
Radek Krejci06f64ed2016-08-15 11:07:44 +02004883 return EXIT_FAILURE;
Radek Krejcibabbff82016-02-19 13:31:37 +01004884 }
4885 }
Radek Krejci018f1f52016-08-03 16:01:20 +02004886
Radek Krejcibabbff82016-02-19 13:31:37 +01004887 /* checks done, store the result */
Radek Krejci018f1f52016-08-03 16:01:20 +02004888 *ret = base;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02004889 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004890 }
4891
Radek Krejci219fa612016-08-15 10:36:51 +02004892 /* base not found (maybe a forward reference) */
4893 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004894}
4895
Michal Vasko730dfdf2015-08-11 14:48:05 +02004896/**
4897 * @brief Resolve base identity. Logs directly.
4898 *
4899 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004900 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004901 * @param[in] basename Base name of the identity.
Radek Krejcibabbff82016-02-19 13:31:37 +01004902 * @param[in] parent Either "type" or "identity".
Radek Krejcicf509982015-12-15 09:22:44 +01004903 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004904 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004905 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004906 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004907static int
Michal Vaskof2d43962016-09-02 11:10:16 +02004908resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char *parent,
Radek Krejci018f1f52016-08-03 16:01:20 +02004909 struct lys_type *type, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004910{
4911 const char *name;
Radek Krejci219fa612016-08-15 10:36:51 +02004912 int mod_name_len = 0, rc;
Radek Krejcicf509982015-12-15 09:22:44 +01004913 struct lys_ident *target, **ret;
Radek Krejci4372b4e2016-04-14 17:42:16 +02004914 uint16_t flags;
Radek Krejcicf509982015-12-15 09:22:44 +01004915 struct lys_module *mod;
4916
4917 assert((ident && !type) || (!ident && type));
4918
4919 if (!type) {
4920 /* have ident to resolve */
4921 ret = &target;
4922 flags = ident->flags;
4923 mod = ident->module;
4924 } else {
4925 /* have type to fill */
Michal Vaskof2d43962016-09-02 11:10:16 +02004926 ++type->info.ident.count;
4927 type->info.ident.ref = ly_realloc(type->info.ident.ref, type->info.ident.count * sizeof *type->info.ident.ref);
4928 if (!type->info.ident.ref) {
4929 LOGMEM;
4930 return -1;
4931 }
4932
4933 ret = &type->info.ident.ref[type->info.ident.count - 1];
Radek Krejcicf509982015-12-15 09:22:44 +01004934 flags = type->parent->flags;
4935 mod = type->parent->module;
4936 }
Michal Vaskof2006002016-04-21 16:28:15 +02004937 *ret = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004938
4939 /* search for the base identity */
4940 name = strchr(basename, ':');
4941 if (name) {
4942 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02004943 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004944 name++;
4945
Michal Vasko2d851a92015-10-20 16:16:36 +02004946 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004947 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02004948 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004949 }
4950 } else {
4951 name = basename;
4952 }
4953
Radek Krejcic071c542016-01-27 14:57:51 +01004954 /* get module where to search */
4955 module = lys_get_import_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len);
4956 if (!module) {
4957 /* identity refers unknown data model */
Radek Krejci02a04992016-03-17 16:06:37 +01004958 LOGVAL(LYE_INMOD, LY_VLOG_NONE, NULL, basename);
Radek Krejcic071c542016-01-27 14:57:51 +01004959 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004960 }
4961
Radek Krejcic071c542016-01-27 14:57:51 +01004962 /* search in the identified module ... */
Radek Krejci219fa612016-08-15 10:36:51 +02004963 rc = resolve_base_ident_sub(module, ident, name, unres, ret);
4964 if (!rc) {
4965 assert(*ret);
4966
4967 /* check status */
4968 if (lyp_check_status(flags, mod, ident ? ident->name : "of type",
4969 (*ret)->flags, (*ret)->module, (*ret)->name, NULL)) {
4970 rc = -1;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02004971 } else {
4972 if (ident) {
4973 ident->base[ident->base_size++] = *ret;
4974
4975 /* maintain backlinks to the derived identities */
4976 rc = identity_backlink_update(ident, *ret) ? -1 : EXIT_SUCCESS;
4977 }
Radek Krejci219fa612016-08-15 10:36:51 +02004978 }
4979 } else if (rc == EXIT_FAILURE) {
4980 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, parent, basename);
Pavol Vican053a2882016-09-05 14:40:33 +02004981 if (type) {
4982 --type->info.ident.count;
4983 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004984 }
4985
Radek Krejci219fa612016-08-15 10:36:51 +02004986 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004987}
4988
Michal Vasko730dfdf2015-08-11 14:48:05 +02004989/**
Michal Vaskof39142b2015-10-21 11:40:05 +02004990 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004991 *
Michal Vaskof2d43962016-09-02 11:10:16 +02004992 * @param[in] type Identityref type.
Michal Vaskofb0873c2015-08-21 09:00:07 +02004993 * @param[in] ident_name Identityref name.
Radek Krejciadb57612016-02-16 13:34:34 +01004994 * @param[in] node Node where the identityref is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02004995 *
4996 * @return Pointer to the identity resolvent, NULL on error.
4997 */
Radek Krejcia52656e2015-08-05 13:41:50 +02004998struct lys_ident *
Michal Vaskof2d43962016-09-02 11:10:16 +02004999resolve_identref(struct lys_type *type, const char *ident_name, struct lyd_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005000{
Michal Vaskoc633ca02015-08-21 14:03:51 +02005001 const char *mod_name, *name;
Radek Krejci85a54be2016-10-20 12:39:56 +02005002 int mod_name_len, rc, i;
5003 unsigned int u;
Michal Vaskof2d43962016-09-02 11:10:16 +02005004 struct lys_ident *der, *cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005005
Michal Vaskof2d43962016-09-02 11:10:16 +02005006 if (!type || (!type->info.ident.count && !type->der) || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005007 return NULL;
5008 }
5009
Michal Vaskoc633ca02015-08-21 14:03:51 +02005010 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, NULL);
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005011 if (rc < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005012 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005013 return NULL;
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005014 } else if (rc < (signed)strlen(ident_name)) {
Radek Krejci02a04992016-03-17 16:06:37 +01005015 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[rc], &ident_name[rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005016 return NULL;
5017 }
5018
Michal Vaskof2d43962016-09-02 11:10:16 +02005019 /* go through all the bases in all the derived types */
5020 while (type->der) {
5021 for (i = 0; i < type->info.ident.count; ++i) {
5022 cur = type->info.ident.ref[i];
5023 if (!strcmp(cur->name, name) && (!mod_name
5024 || (!strncmp(cur->module->name, mod_name, mod_name_len) && !cur->module->name[mod_name_len]))) {
5025 goto match;
5026 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02005027
Radek Krejci85a54be2016-10-20 12:39:56 +02005028 if (cur->der) {
5029 /* there are also some derived identities */
5030 for (u = 0; u < cur->der->number; u++) {
5031 der = (struct lys_ident *)cur->der->set.g[u]; /* shortcut */
5032 if (!strcmp(der->name, name) &&
5033 (!mod_name || (!strncmp(der->module->name, mod_name, mod_name_len) && !der->module->name[mod_name_len]))) {
5034 /* we have match */
5035 cur = der;
5036 goto match;
5037 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005038 }
5039 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005040 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005041 type = &type->der->type;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005042 }
5043
Radek Krejci48464ed2016-03-17 15:44:09 +01005044 LOGVAL(LYE_INRESOLV, LY_VLOG_LYD, node, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005045 return NULL;
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005046
5047match:
Michal Vaskof2d43962016-09-02 11:10:16 +02005048 for (i = 0; i < cur->iffeature_size; i++) {
5049 if (!resolve_iffeature(&cur->iffeature[i])) {
5050 LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, cur->name, node->schema->name);
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005051 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, "Identity \"%s\" is disabled by its if-feature condition.",
Michal Vaskof2d43962016-09-02 11:10:16 +02005052 cur->name);
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005053 return NULL;
5054 }
5055 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005056 return cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005057}
5058
Michal Vasko730dfdf2015-08-11 14:48:05 +02005059/**
Michal Vaskobb211122015-08-19 14:03:11 +02005060 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005061 *
Michal Vaskobb211122015-08-19 14:03:11 +02005062 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005063 * @param[in] unres Specific unres item.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005064 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005065 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005066 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005067static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005068resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005069{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005070 int rc;
Radek Krejci010e54b2016-03-15 09:40:34 +01005071 struct lys_node *par_grp;
Michal Vaskoe91afce2015-08-12 12:21:00 +02005072
Radek Krejci010e54b2016-03-15 09:40:34 +01005073 /* HACK: when a grouping has uses inside, all such uses have to be resolved before the grouping itself
5074 * is used in some uses. When we see such a uses, the grouping's nacm member (not used in grouping)
5075 * is used to store number of so far unresolved uses. The grouping cannot be used unless the nacm
5076 * value is decreased back to 0. To remember that the uses already increased grouping's nacm, the
5077 * LYS_USESGRP flag is used. */
Michal Vaskodcf98e62016-05-05 17:53:53 +02005078 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 +02005079
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005080 if (!uses->grp) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01005081 rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
5082 if (rc == -1) {
Michal Vasko92981a62016-10-14 10:25:16 +02005083 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005084 return -1;
5085 } else if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005086 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005087 return -1;
5088 } else if (!uses->grp) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005089 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005090 /* hack - in contrast to lys_node, lys_node_grp has bigger nacm field
5091 * (and smaller flags - it uses only a limited set of flags)
5092 */
5093 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci010e54b2016-03-15 09:40:34 +01005094 uses->flags |= LYS_USESGRP;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005095 }
Michal Vasko92981a62016-10-14 10:25:16 +02005096 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005097 return EXIT_FAILURE;
Michal Vasko12e30842015-08-04 11:54:00 +02005098 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005099 }
5100
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005101 if (uses->grp->nacm) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005102 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005103 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci010e54b2016-03-15 09:40:34 +01005104 uses->flags |= LYS_USESGRP;
Radek Krejcie00d2312016-08-12 15:27:49 +02005105 } else {
5106 /* instantiate grouping only when it is completely resolved */
5107 uses->grp = NULL;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005108 }
Michal Vasko92981a62016-10-14 10:25:16 +02005109 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005110 return EXIT_FAILURE;
5111 }
5112
Radek Krejci48464ed2016-03-17 15:44:09 +01005113 rc = resolve_uses(uses, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005114 if (!rc) {
5115 /* decrease unres count only if not first try */
Radek Krejci010e54b2016-03-15 09:40:34 +01005116 if (par_grp && (uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005117 if (!((struct lys_node_grp *)par_grp)->nacm) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005118 LOGINT;
5119 return -1;
5120 }
Radek Krejci4372b4e2016-04-14 17:42:16 +02005121 ((struct lys_node_grp *)par_grp)->nacm--;
Radek Krejci010e54b2016-03-15 09:40:34 +01005122 uses->flags &= ~LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005123 }
Radek Krejcicf509982015-12-15 09:22:44 +01005124
5125 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005126 if (lyp_check_status(uses->flags, uses->module, "of uses",
Radek Krejciadb57612016-02-16 13:34:34 +01005127 uses->grp->flags, uses->grp->module, uses->grp->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005128 (struct lys_node *)uses)) {
Radek Krejcicf509982015-12-15 09:22:44 +01005129 return -1;
5130 }
5131
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005132 return EXIT_SUCCESS;
5133 }
5134
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005135 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005136}
5137
Michal Vasko730dfdf2015-08-11 14:48:05 +02005138/**
Michal Vasko9957e592015-08-17 15:04:09 +02005139 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005140 *
Michal Vaskobb211122015-08-19 14:03:11 +02005141 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005142 * @param[in] keys_str Keys node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005143 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005144 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005145 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005146static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005147resolve_list_keys(struct lys_node_list *list, const char *keys_str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005148{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005149 int i, len, rc;
Michal Vasko4f0dad02016-02-15 14:08:23 +01005150 const char *value;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005151
5152 for (i = 0; i < list->keys_size; ++i) {
5153 /* get the key name */
5154 if ((value = strpbrk(keys_str, " \t\n"))) {
5155 len = value - keys_str;
5156 while (isspace(value[0])) {
5157 value++;
5158 }
5159 } else {
5160 len = strlen(keys_str);
5161 }
5162
Radek Krejcic4283442016-04-22 09:19:27 +02005163 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 +02005164 if (rc) {
Michal Vasko7a55bea2016-05-02 14:51:20 +02005165 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
5166 return EXIT_FAILURE;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005167 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005168
Radek Krejci48464ed2016-03-17 15:44:09 +01005169 if (check_key(list, i, keys_str, len)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005170 /* check_key logs */
5171 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005172 }
5173
Radek Krejcicf509982015-12-15 09:22:44 +01005174 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005175 if (lyp_check_status(list->flags, list->module, list->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005176 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
5177 (struct lys_node *)list->keys[i])) {
Radek Krejcicf509982015-12-15 09:22:44 +01005178 return -1;
5179 }
5180
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005181 /* prepare for next iteration */
5182 while (value && isspace(value[0])) {
5183 value++;
5184 }
5185 keys_str = value;
5186 }
5187
Michal Vaskof02e3742015-08-05 16:27:02 +02005188 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005189}
5190
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005191/**
Michal Vaskobf19d252015-10-08 15:39:17 +02005192 * @brief Resolve (check) all must conditions of \p node.
5193 * Logs directly.
5194 *
5195 * @param[in] node Data node with optional must statements.
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005196 * @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 +02005197 *
5198 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
5199 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005200static int
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005201resolve_must(struct lyd_node *node, int inout_parent)
Michal Vaskof02e3742015-08-05 16:27:02 +02005202{
Michal Vaskobf19d252015-10-08 15:39:17 +02005203 uint8_t i, must_size;
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005204 struct lys_node *schema;
Michal Vaskobf19d252015-10-08 15:39:17 +02005205 struct lys_restr *must;
5206 struct lyxp_set set;
5207
5208 assert(node);
5209 memset(&set, 0, sizeof set);
5210
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005211 if (inout_parent) {
5212 for (schema = lys_parent(node->schema);
5213 schema && (schema->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES));
5214 schema = lys_parent(schema));
5215 if (!schema || !(schema->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5216 LOGINT;
5217 return -1;
5218 }
5219 must_size = ((struct lys_node_inout *)schema)->must_size;
5220 must = ((struct lys_node_inout *)schema)->must;
5221
5222 /* context node is the RPC/action */
5223 node = node->parent;
5224 if (!(node->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
5225 LOGINT;
5226 return -1;
5227 }
5228 } else {
5229 switch (node->schema->nodetype) {
5230 case LYS_CONTAINER:
5231 must_size = ((struct lys_node_container *)node->schema)->must_size;
5232 must = ((struct lys_node_container *)node->schema)->must;
5233 break;
5234 case LYS_LEAF:
5235 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
5236 must = ((struct lys_node_leaf *)node->schema)->must;
5237 break;
5238 case LYS_LEAFLIST:
5239 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
5240 must = ((struct lys_node_leaflist *)node->schema)->must;
5241 break;
5242 case LYS_LIST:
5243 must_size = ((struct lys_node_list *)node->schema)->must_size;
5244 must = ((struct lys_node_list *)node->schema)->must;
5245 break;
5246 case LYS_ANYXML:
5247 case LYS_ANYDATA:
5248 must_size = ((struct lys_node_anydata *)node->schema)->must_size;
5249 must = ((struct lys_node_anydata *)node->schema)->must;
5250 break;
5251 case LYS_NOTIF:
5252 must_size = ((struct lys_node_notif *)node->schema)->must_size;
5253 must = ((struct lys_node_notif *)node->schema)->must;
5254 break;
5255 default:
5256 must_size = 0;
5257 break;
5258 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005259 }
5260
5261 for (i = 0; i < must_size; ++i) {
Michal Vaskoa59495d2016-08-22 09:18:58 +02005262 if (lyxp_eval(must[i].expr, node, LYXP_NODE_ELEM, &set, LYXP_MUST)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02005263 return -1;
5264 }
5265
Michal Vasko944a5642016-03-21 11:48:58 +01005266 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, LYXP_MUST);
Michal Vaskobf19d252015-10-08 15:39:17 +02005267
Michal Vasko8146d4c2016-05-09 15:50:29 +02005268 if (!set.val.bool) {
Michal Vasko6ac68282016-04-11 10:56:47 +02005269 LOGVAL(LYE_NOMUST, LY_VLOG_LYD, node, must[i].expr);
5270 if (must[i].emsg) {
5271 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, must[i].emsg);
5272 }
5273 if (must[i].eapptag) {
5274 strncpy(((struct ly_err *)&ly_errno)->apptag, must[i].eapptag, LY_APPTAG_LEN - 1);
5275 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005276 return 1;
5277 }
5278 }
5279
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005280 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02005281}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005282
Michal Vaskobf19d252015-10-08 15:39:17 +02005283/**
Michal Vasko508a50d2016-09-07 14:50:33 +02005284 * @brief Resolve (find) when condition schema context node. Does not log.
5285 *
5286 * @param[in] schema Schema node with the when condition.
5287 * @param[out] ctx_snode When schema context node.
5288 * @param[out] ctx_snode_type Schema context node type.
5289 */
5290void
5291resolve_when_ctx_snode(const struct lys_node *schema, struct lys_node **ctx_snode, enum lyxp_node_type *ctx_snode_type)
5292{
5293 const struct lys_node *sparent;
5294
5295 /* find a not schema-only node */
5296 *ctx_snode_type = LYXP_NODE_ELEM;
5297 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
5298 if (schema->nodetype == LYS_AUGMENT) {
5299 sparent = ((struct lys_node_augment *)schema)->target;
5300 } else {
5301 sparent = schema->parent;
5302 }
5303 if (!sparent) {
5304 /* context node is the document root (fake root in our case) */
5305 if (schema->flags & LYS_CONFIG_W) {
5306 *ctx_snode_type = LYXP_NODE_ROOT_CONFIG;
5307 } else {
Michal Vaskob94a5e42016-09-08 14:01:56 +02005308 *ctx_snode_type = LYXP_NODE_ROOT;
Michal Vasko508a50d2016-09-07 14:50:33 +02005309 }
Michal Vasko2d2aec12016-09-08 11:42:50 +02005310 /* we need the first top-level sibling, but no uses or groupings */
Michal Vaskob94a5e42016-09-08 14:01:56 +02005311 schema = lys_getnext(NULL, NULL, lys_node_module(schema), 0);
Michal Vasko508a50d2016-09-07 14:50:33 +02005312 break;
5313 }
5314 schema = sparent;
5315 }
5316
5317 *ctx_snode = (struct lys_node *)schema;
5318}
5319
5320/**
Michal Vaskocf024702015-10-08 15:01:42 +02005321 * @brief Resolve (find) when condition context node. Does not log.
5322 *
5323 * @param[in] node Data node, whose conditional definition is being decided.
Michal Vasko508a50d2016-09-07 14:50:33 +02005324 * @param[in] schema Schema node with the when condition.
Michal Vaskoa59495d2016-08-22 09:18:58 +02005325 * @param[out] ctx_node Context node.
5326 * @param[out] ctx_node_type Context node type.
Michal Vaskocf024702015-10-08 15:01:42 +02005327 *
Michal Vaskoa59495d2016-08-22 09:18:58 +02005328 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vaskocf024702015-10-08 15:01:42 +02005329 */
Michal Vaskoa59495d2016-08-22 09:18:58 +02005330static int
5331resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema, struct lyd_node **ctx_node,
5332 enum lyxp_node_type *ctx_node_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005333{
Michal Vaskocf024702015-10-08 15:01:42 +02005334 struct lyd_node *parent;
5335 struct lys_node *sparent;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005336 enum lyxp_node_type node_type;
Michal Vaskocf024702015-10-08 15:01:42 +02005337 uint16_t i, data_depth, schema_depth;
5338
Michal Vasko508a50d2016-09-07 14:50:33 +02005339 resolve_when_ctx_snode(schema, &schema, &node_type);
Michal Vaskocf024702015-10-08 15:01:42 +02005340
Michal Vaskofe989752016-09-08 08:47:26 +02005341 if (node_type == LYXP_NODE_ELEM) {
5342 /* standard element context node */
5343 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
5344 for (sparent = schema, schema_depth = 0;
5345 sparent;
5346 sparent = (sparent->nodetype == LYS_AUGMENT ? ((struct lys_node_augment *)sparent)->target : sparent->parent)) {
5347 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_NOTIF | LYS_RPC)) {
5348 ++schema_depth;
5349 }
Michal Vaskocf024702015-10-08 15:01:42 +02005350 }
Michal Vaskofe989752016-09-08 08:47:26 +02005351 if (data_depth < schema_depth) {
5352 return -1;
5353 }
Michal Vaskocf024702015-10-08 15:01:42 +02005354
Michal Vasko956e8542016-08-26 09:43:35 +02005355 /* find the corresponding data node */
5356 for (i = 0; i < data_depth - schema_depth; ++i) {
5357 node = node->parent;
5358 }
Michal Vaskoa59495d2016-08-22 09:18:58 +02005359 if (node->schema != schema) {
5360 return -1;
5361 }
Michal Vaskofe989752016-09-08 08:47:26 +02005362 } else {
5363 /* root context node */
5364 while (node->parent) {
5365 node = node->parent;
5366 }
5367 while (node->prev->next) {
5368 node = node->prev;
5369 }
Michal Vaskocf024702015-10-08 15:01:42 +02005370 }
5371
Michal Vaskoa59495d2016-08-22 09:18:58 +02005372 *ctx_node = node;
5373 *ctx_node_type = node_type;
5374 return EXIT_SUCCESS;
Michal Vaskocf024702015-10-08 15:01:42 +02005375}
5376
Michal Vasko76c3bd32016-08-24 16:02:52 +02005377/**
5378 * @brief Temporarily unlink nodes as per YANG 1.1 RFC section 7.21.5 for when XPath evaluation.
5379 * The context nodes is adjusted if needed.
5380 *
5381 * @param[in] snode Schema node, whose children instances need to be unlinked.
5382 * @param[in,out] node Data siblings where to look for the children of \p snode. If it is unlinked,
5383 * it is moved to point to another sibling still in the original tree.
5384 * @param[in,out] ctx_node When context node, adjusted if needed.
5385 * @param[in] ctx_node_type Context node type, just for information to detect invalid situations.
5386 * @param[out] unlinked_nodes Unlinked siblings. Can be safely appended to \p node afterwards.
5387 * Ordering may change, but there will be no semantic change.
5388 *
5389 * @return EXIT_SUCCESS on success, -1 on error.
5390 */
5391static int
5392resolve_when_unlink_nodes(struct lys_node *snode, struct lyd_node **node, struct lyd_node **ctx_node,
5393 enum lyxp_node_type ctx_node_type, struct lyd_node **unlinked_nodes)
5394{
5395 struct lyd_node *next, *elem;
5396
5397 switch (snode->nodetype) {
5398 case LYS_AUGMENT:
5399 case LYS_USES:
5400 case LYS_CHOICE:
5401 case LYS_CASE:
5402 LY_TREE_FOR(snode->child, snode) {
5403 if (resolve_when_unlink_nodes(snode, node, ctx_node, ctx_node_type, unlinked_nodes)) {
5404 return -1;
5405 }
5406 }
5407 break;
5408 case LYS_CONTAINER:
5409 case LYS_LIST:
5410 case LYS_LEAF:
5411 case LYS_LEAFLIST:
5412 case LYS_ANYXML:
5413 case LYS_ANYDATA:
5414 LY_TREE_FOR_SAFE(lyd_first_sibling(*node), next, elem) {
5415 if (elem->schema == snode) {
5416
5417 if (elem == *ctx_node) {
5418 /* We are going to unlink our context node! This normally cannot happen,
5419 * but we use normal top-level data nodes for faking a document root node,
5420 * so if this is the context node, we just use the next top-level node.
5421 * Additionally, it can even happen that there are no top-level data nodes left,
5422 * all were unlinked, so in this case we pass NULL as the context node/data tree,
5423 * lyxp_eval() can handle this special situation.
5424 */
5425 if (ctx_node_type == LYXP_NODE_ELEM) {
5426 LOGINT;
5427 return -1;
5428 }
5429
5430 if (elem->prev == elem) {
5431 /* unlinking last top-level element, use an empty data tree */
5432 *ctx_node = NULL;
5433 } else {
5434 /* in this case just use the previous/last top-level data node */
5435 *ctx_node = elem->prev;
5436 }
5437 } else if (elem == *node) {
5438 /* We are going to unlink the currently processed node. This does not matter that
5439 * much, but we would lose access to the original data tree, so just move our
5440 * pointer somewhere still inside it.
5441 */
5442 if ((*node)->prev != *node) {
5443 *node = (*node)->prev;
5444 } else {
5445 /* the processed node with sibings were all unlinked, oh well */
5446 *node = NULL;
5447 }
5448 }
5449
5450 /* temporarily unlink the node */
5451 lyd_unlink(elem);
5452 if (*unlinked_nodes) {
5453 if (lyd_insert_after(*unlinked_nodes, elem)) {
5454 LOGINT;
5455 return -1;
5456 }
5457 } else {
5458 *unlinked_nodes = elem;
5459 }
5460
5461 if (snode->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_ANYDATA)) {
5462 /* there can be only one instance */
5463 break;
5464 }
5465 }
5466 }
5467 break;
5468 default:
5469 LOGINT;
5470 return -1;
5471 }
5472
5473 return EXIT_SUCCESS;
5474}
5475
5476/**
5477 * @brief Relink the unlinked nodes back.
5478 *
5479 * @param[in] node Data node to link the nodes back to. It can actually be the adjusted context node,
5480 * we simply need a sibling from the original data tree.
5481 * @param[in] unlinked_nodes Unlinked nodes to relink to \p node.
5482 * @param[in] ctx_node_type Context node type to distinguish between \p node being the parent
5483 * or the sibling of \p unlinked_nodes.
5484 *
5485 * @return EXIT_SUCCESS on success, -1 on error.
5486 */
5487static int
5488resolve_when_relink_nodes(struct lyd_node *node, struct lyd_node *unlinked_nodes, enum lyxp_node_type ctx_node_type)
5489{
5490 struct lyd_node *elem;
5491
5492 LY_TREE_FOR_SAFE(unlinked_nodes, unlinked_nodes, elem) {
5493 if (ctx_node_type == LYXP_NODE_ELEM) {
5494 if (lyd_insert(node, elem)) {
5495 return -1;
5496 }
5497 } else {
5498 if (lyd_insert_after(node, elem)) {
5499 return -1;
5500 }
5501 }
5502 }
5503
5504 return EXIT_SUCCESS;
5505}
5506
Radek Krejci03b71f72016-03-16 11:10:09 +01005507int
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005508resolve_applies_must(const struct lyd_node *node)
Radek Krejci01696bf2016-03-18 13:19:36 +01005509{
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005510 int ret = 0;
5511 uint8_t must_size;
5512 struct lys_node *schema, *iter;
Radek Krejci46165822016-08-26 14:06:27 +02005513
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005514 assert(node);
5515
5516 schema = node->schema;
5517
5518 /* their own must */
Radek Krejci46165822016-08-26 14:06:27 +02005519 switch (schema->nodetype) {
Radek Krejci01696bf2016-03-18 13:19:36 +01005520 case LYS_CONTAINER:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005521 must_size = ((struct lys_node_container *)schema)->must_size;
5522 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005523 case LYS_LEAF:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005524 must_size = ((struct lys_node_leaf *)schema)->must_size;
5525 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005526 case LYS_LEAFLIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005527 must_size = ((struct lys_node_leaflist *)schema)->must_size;
5528 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005529 case LYS_LIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005530 must_size = ((struct lys_node_list *)schema)->must_size;
5531 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005532 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02005533 case LYS_ANYDATA:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005534 must_size = ((struct lys_node_anydata *)schema)->must_size;
5535 break;
5536 case LYS_NOTIF:
5537 must_size = ((struct lys_node_notif *)schema)->must_size;
5538 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005539 default:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005540 must_size = 0;
5541 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005542 }
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005543
5544 if (must_size) {
5545 ++ret;
5546 }
5547
5548 /* schema may be a direct data child of input/output with must (but it must be first, it needs to be evaluated only once) */
5549 if (!node->prev->next) {
5550 for (iter = lys_parent(schema); iter && (iter->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES)); iter = lys_parent(iter));
5551 if (iter && (iter->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5552 ret += 0x2;
5553 }
5554 }
5555
5556 return ret;
Radek Krejci01696bf2016-03-18 13:19:36 +01005557}
5558
5559int
Radek Krejci46165822016-08-26 14:06:27 +02005560resolve_applies_when(const struct lys_node *schema, int mode, const struct lys_node *stop)
Radek Krejci03b71f72016-03-16 11:10:09 +01005561{
Radek Krejci46165822016-08-26 14:06:27 +02005562 const struct lys_node *parent;
Radek Krejci03b71f72016-03-16 11:10:09 +01005563
Radek Krejci46165822016-08-26 14:06:27 +02005564 assert(schema);
Radek Krejci03b71f72016-03-16 11:10:09 +01005565
Radek Krejci46165822016-08-26 14:06:27 +02005566 if (!(schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)schema)->when)) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005567 return 1;
5568 }
5569
Radek Krejci46165822016-08-26 14:06:27 +02005570 parent = schema;
Radek Krejci03b71f72016-03-16 11:10:09 +01005571 goto check_augment;
5572
Radek Krejci46165822016-08-26 14:06:27 +02005573 while (parent) {
5574 /* stop conditions */
5575 if (!mode) {
5576 /* stop on node that can be instantiated in data tree */
5577 if (!(parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
5578 break;
5579 }
5580 } else {
5581 /* stop on the specified node */
5582 if (parent == stop) {
5583 break;
5584 }
5585 }
5586
5587 if (((const struct lys_node_uses *)parent)->when) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005588 return 1;
5589 }
5590check_augment:
5591
5592 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) &&
Radek Krejci46165822016-08-26 14:06:27 +02005593 (((const struct lys_node_augment *)parent->parent)->when))) {
Michal Vaskoe3655562016-08-24 15:56:17 +02005594 return 1;
Radek Krejci03b71f72016-03-16 11:10:09 +01005595 }
5596 parent = lys_parent(parent);
5597 }
5598
5599 return 0;
5600}
5601
Michal Vaskocf024702015-10-08 15:01:42 +02005602/**
5603 * @brief Resolve (check) all when conditions relevant for \p node.
5604 * Logs directly.
5605 *
5606 * @param[in] node Data node, whose conditional reference, if such, is being decided.
Michal Vaskocf024702015-10-08 15:01:42 +02005607 *
Radek Krejci03b71f72016-03-16 11:10:09 +01005608 * @return
5609 * -1 - error, ly_errno is set
5610 * 0 - true "when" statement
Radek Krejci46165822016-08-26 14:06:27 +02005611 * 0, ly_vecode = LYVE_NOWHEN - false "when" statement
Radek Krejci03b71f72016-03-16 11:10:09 +01005612 * 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 +02005613 */
Radek Krejci46165822016-08-26 14:06:27 +02005614int
5615resolve_when(struct lyd_node *node, int *result)
Michal Vaskocf024702015-10-08 15:01:42 +02005616{
Michal Vasko76c3bd32016-08-24 16:02:52 +02005617 struct lyd_node *ctx_node = NULL, *unlinked_nodes, *tmp_node;
Michal Vasko90fc2a32016-08-24 15:58:58 +02005618 struct lys_node *sparent;
Michal Vaskocf024702015-10-08 15:01:42 +02005619 struct lyxp_set set;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005620 enum lyxp_node_type ctx_node_type;
Radek Krejci51093642016-03-29 10:14:59 +02005621 int rc = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02005622
5623 assert(node);
5624 memset(&set, 0, sizeof set);
5625
5626 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)node->schema)->when)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005627 /* make the node dummy for the evaluation */
5628 node->validity |= LYD_VAL_INUSE;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005629 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 +02005630 node->validity &= ~LYD_VAL_INUSE;
Radek Krejci03b71f72016-03-16 11:10:09 +01005631 if (rc) {
5632 if (rc == 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005633 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005634 }
Radek Krejci51093642016-03-29 10:14:59 +02005635 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005636 }
5637
Radek Krejci03b71f72016-03-16 11:10:09 +01005638 /* set boolean result of the condition */
Michal Vasko944a5642016-03-21 11:48:58 +01005639 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02005640 if (!set.val.bool) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005641 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci0b7704f2016-03-18 12:16:14 +01005642 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02005643 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005644 }
Radek Krejci51093642016-03-29 10:14:59 +02005645
5646 /* free xpath set content */
5647 lyxp_set_cast(&set, LYXP_SET_EMPTY, node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005648 }
5649
Michal Vasko90fc2a32016-08-24 15:58:58 +02005650 sparent = node->schema;
Michal Vaskocf024702015-10-08 15:01:42 +02005651 goto check_augment;
5652
5653 /* check when in every schema node that affects node */
Michal Vasko90fc2a32016-08-24 15:58:58 +02005654 while (sparent && (sparent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
5655 if (((struct lys_node_uses *)sparent)->when) {
Michal Vaskocf024702015-10-08 15:01:42 +02005656 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005657 rc = resolve_when_ctx_node(node, sparent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02005658 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02005659 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02005660 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005661 }
5662 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02005663
5664 unlinked_nodes = NULL;
5665 /* we do not want our node pointer to change */
5666 tmp_node = node;
5667 rc = resolve_when_unlink_nodes(sparent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
5668 if (rc) {
5669 goto cleanup;
5670 }
5671
5672 rc = lyxp_eval(((struct lys_node_uses *)sparent)->when->cond, ctx_node, ctx_node_type, &set, LYXP_WHEN);
5673
5674 if (unlinked_nodes && ctx_node) {
5675 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
5676 rc = -1;
5677 goto cleanup;
5678 }
5679 }
5680
Radek Krejci03b71f72016-03-16 11:10:09 +01005681 if (rc) {
5682 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005683 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005684 }
Radek Krejci51093642016-03-29 10:14:59 +02005685 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005686 }
5687
Michal Vasko944a5642016-03-21 11:48:58 +01005688 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02005689 if (!set.val.bool) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005690 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Radek Krejci0b7704f2016-03-18 12:16:14 +01005691 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02005692 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005693 }
Radek Krejci51093642016-03-29 10:14:59 +02005694
5695 /* free xpath set content */
5696 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005697 }
5698
5699check_augment:
Michal Vasko90fc2a32016-08-24 15:58:58 +02005700 if ((sparent->parent && (sparent->parent->nodetype == LYS_AUGMENT) && (((struct lys_node_augment *)sparent->parent)->when))) {
Michal Vaskocf024702015-10-08 15:01:42 +02005701 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005702 rc = resolve_when_ctx_node(node, sparent->parent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02005703 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02005704 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02005705 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005706 }
5707 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02005708
5709 unlinked_nodes = NULL;
5710 tmp_node = node;
5711 rc = resolve_when_unlink_nodes(sparent->parent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
5712 if (rc) {
5713 goto cleanup;
5714 }
5715
5716 rc = lyxp_eval(((struct lys_node_augment *)sparent->parent)->when->cond, ctx_node, ctx_node_type, &set, LYXP_WHEN);
5717
5718 /* reconnect nodes, if ctx_node is NULL then all the nodes were unlinked, but linked together,
5719 * so the tree did not actually change and there is nothing for us to do
5720 */
5721 if (unlinked_nodes && ctx_node) {
5722 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
5723 rc = -1;
5724 goto cleanup;
5725 }
5726 }
5727
Radek Krejci03b71f72016-03-16 11:10:09 +01005728 if (rc) {
5729 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005730 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005731 }
Radek Krejci51093642016-03-29 10:14:59 +02005732 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005733 }
5734
Michal Vasko944a5642016-03-21 11:48:58 +01005735 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, LYXP_WHEN);
Michal Vaskocf024702015-10-08 15:01:42 +02005736
Michal Vasko8146d4c2016-05-09 15:50:29 +02005737 if (!set.val.bool) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005738 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Radek Krejci0b7704f2016-03-18 12:16:14 +01005739 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02005740 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005741 }
Radek Krejci51093642016-03-29 10:14:59 +02005742
5743 /* free xpath set content */
5744 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005745 }
5746
Michal Vasko90fc2a32016-08-24 15:58:58 +02005747 sparent = lys_parent(sparent);
Michal Vaskocf024702015-10-08 15:01:42 +02005748 }
5749
Radek Krejci0b7704f2016-03-18 12:16:14 +01005750 node->when_status |= LYD_WHEN_TRUE;
Radek Krejci03b71f72016-03-16 11:10:09 +01005751
Radek Krejci51093642016-03-29 10:14:59 +02005752cleanup:
Radek Krejci51093642016-03-29 10:14:59 +02005753 /* free xpath set content */
5754 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node ? ctx_node : node, 0);
5755
Radek Krejci46165822016-08-26 14:06:27 +02005756 if (result) {
5757 if (node->when_status & LYD_WHEN_TRUE) {
5758 *result = 1;
5759 } else {
5760 *result = 0;
5761 }
5762 }
5763
Radek Krejci51093642016-03-29 10:14:59 +02005764 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005765}
5766
Radek Krejcicbb473e2016-09-16 14:48:32 +02005767static int
5768check_leafref_features(struct lys_type *type)
5769{
5770 struct lys_node *iter;
5771 struct ly_set *src_parents, *trg_parents, *features;
5772 unsigned int i, j, size, x;
5773 int ret = EXIT_SUCCESS;
5774
5775 assert(type->parent);
5776
5777 src_parents = ly_set_new();
5778 trg_parents = ly_set_new();
5779 features = ly_set_new();
5780
5781 /* get parents chain of source (leafref) */
5782 for (iter = (struct lys_node *)type->parent; iter; iter = iter->parent) {
5783 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
5784 continue;
5785 }
5786 ly_set_add(src_parents, iter, LY_SET_OPT_USEASLIST);
5787 }
5788 /* get parents chain of target */
5789 for (iter = (struct lys_node *)type->info.lref.target; iter; iter = iter->parent) {
5790 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
5791 continue;
5792 }
5793 ly_set_add(trg_parents, iter, LY_SET_OPT_USEASLIST);
5794 }
5795
5796 /* compare the features used in if-feature statements in the rest of both
5797 * chains of parents. The set of features used for target must be a subset
5798 * of features used for the leafref. This is not a perfect, we should compare
5799 * the truth tables but it could require too much resources, so we simplify that */
5800 for (i = 0; i < src_parents->number; i++) {
5801 iter = src_parents->set.s[i]; /* shortcut */
5802 if (!iter->iffeature_size) {
5803 continue;
5804 }
5805 for (j = 0; j < iter->iffeature_size; j++) {
5806 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
5807 for (; size; size--) {
5808 if (!iter->iffeature[j].features[size - 1]) {
5809 /* not yet resolved feature, postpone this check */
5810 ret = EXIT_FAILURE;
5811 goto cleanup;
5812 }
5813 ly_set_add(features, iter->iffeature[j].features[size - 1], 0);
5814 }
5815 }
5816 }
5817 x = features->number;
5818 for (i = 0; i < trg_parents->number; i++) {
5819 iter = trg_parents->set.s[i]; /* shortcut */
5820 if (!iter->iffeature_size) {
5821 continue;
5822 }
5823 for (j = 0; j < iter->iffeature_size; j++) {
5824 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
5825 for (; size; size--) {
5826 if (!iter->iffeature[j].features[size - 1]) {
5827 /* not yet resolved feature, postpone this check */
5828 ret = EXIT_FAILURE;
5829 goto cleanup;
5830 }
5831 if ((unsigned int)ly_set_add(features, iter->iffeature[j].features[size - 1], 0) >= x) {
5832 /* the feature is not present in features set of target's parents chain */
5833 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, type->parent, "leafref", type->info.lref.path);
5834 LOGVAL(LYE_SPEC, LY_VLOG_LYS, type->parent,
5835 "Leafref is not conditional based on \"%s\" feature as its target.",
5836 iter->iffeature[j].features[size - 1]->name);
5837 ret = -1;
5838 goto cleanup;
5839 }
5840 }
5841 }
5842 }
5843
5844cleanup:
5845 ly_set_free(features);
5846 ly_set_free(src_parents);
5847 ly_set_free(trg_parents);
5848
5849 return ret;
5850}
5851
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005852/**
Michal Vaskobb211122015-08-19 14:03:11 +02005853 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005854 *
5855 * @param[in] mod Main module.
5856 * @param[in] item Item to resolve. Type determined by \p type.
5857 * @param[in] type Type of the unresolved item.
5858 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02005859 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005860 *
5861 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
5862 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005863static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02005864resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Radek Krejci48464ed2016-03-17 15:44:09 +01005865 struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005866{
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005867 /* has_str - whether the str_snode is a string in a dictionary that needs to be freed */
Radek Krejcic79c6b12016-07-26 15:11:49 +02005868 int rc = -1, has_str = 0, tpdf_flag = 0, i, k;
5869 unsigned int j;
Radek Krejcic13db382016-08-16 10:52:42 +02005870 struct lys_node *node, *par_grp;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005871 const char *expr;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005872
Radek Krejcic79c6b12016-07-26 15:11:49 +02005873 struct ly_set *refs, *procs;
5874 struct lys_feature *ref, *feat;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005875 struct lys_ident *ident;
5876 struct lys_type *stype;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005877 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01005878 struct lyxml_elem *yin;
Pavol Vicana0e4e672016-02-24 12:20:04 +01005879 struct yang_type *yang;
Radek Krejcid09d1a52016-08-11 14:05:45 +02005880 struct unres_list_uniq *unique_info;
Radek Krejcicbb473e2016-09-16 14:48:32 +02005881 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005882
5883 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005884 case UNRES_IDENT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005885 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01005886 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005887 ident = item;
5888
Radek Krejci018f1f52016-08-03 16:01:20 +02005889 rc = resolve_base_ident(mod, ident, expr, "identity", NULL, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005890 break;
5891 case UNRES_TYPE_IDENTREF:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005892 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01005893 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005894 stype = item;
5895
Radek Krejci018f1f52016-08-03 16:01:20 +02005896 rc = resolve_base_ident(mod, NULL, expr, "type", stype, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005897 break;
5898 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02005899 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005900 stype = item;
5901
Radek Krejci2f12f852016-01-08 12:59:57 +01005902 /* HACK - when there is no parent, we are in top level typedef and in that
5903 * case, the path has to contain absolute path, so we let the resolve_path_arg_schema()
5904 * know it via tpdf_flag */
5905 if (!node) {
Radek Krejci4f78b532016-02-17 13:43:00 +01005906 tpdf_flag = 1;
Radek Krejci2f12f852016-01-08 12:59:57 +01005907 node = (struct lys_node *)stype->parent;
5908 }
5909
Radek Krejci27fe55e2016-09-13 17:13:35 +02005910 if (!lys_node_module(node)->implemented) {
5911 /* not implemented module, don't bother with resolving the leafref
5912 * if the module is set to be implemented, tha path will be resolved then */
5913 rc = 0;
5914 break;
5915 }
Radek Krejci48464ed2016-03-17 15:44:09 +01005916 rc = resolve_path_arg_schema(stype->info.lref.path, node, tpdf_flag,
Michal Vasko1e62a092015-12-01 12:27:20 +01005917 (const struct lys_node **)&stype->info.lref.target);
Michal Vasko01c6fd22016-05-20 11:43:05 +02005918 if (!tpdf_flag && !rc) {
5919 assert(stype->info.lref.target);
Radek Krejcicbb473e2016-09-16 14:48:32 +02005920 /* check if leafref and its target are under a common if-features */
5921 rc = check_leafref_features(stype);
5922 if (rc) {
5923 break;
5924 }
5925
Radek Krejci46c4cd72016-01-21 15:13:52 +01005926 /* store the backlink from leafref target */
Michal Vasko01c6fd22016-05-20 11:43:05 +02005927 if (lys_leaf_add_leafref_target(stype->info.lref.target, (struct lys_node *)stype->parent)) {
5928 rc = -1;
Radek Krejci46c4cd72016-01-21 15:13:52 +01005929 }
Radek Krejci46c4cd72016-01-21 15:13:52 +01005930 }
5931
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005932 break;
Radek Krejci3a5501d2016-07-18 22:03:34 +02005933 case UNRES_TYPE_DER_TPDF:
5934 tpdf_flag = 1;
5935 /* no break */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005936 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01005937 /* parent */
5938 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005939 stype = item;
5940
Michal Vasko88c29542015-11-27 14:57:53 +01005941 /* HACK type->der is temporarily unparsed type statement */
5942 yin = (struct lyxml_elem *)stype->der;
5943 stype->der = NULL;
5944
Pavol Vicana0e4e672016-02-24 12:20:04 +01005945 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
5946 yang = (struct yang_type *)yin;
Radek Krejci3a5501d2016-07-18 22:03:34 +02005947 rc = yang_check_type(mod, node, yang, tpdf_flag, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01005948
5949 if (rc) {
Pavol Vican8bd72e42016-08-29 09:53:05 +02005950 /* may try again later */
5951 stype->der = (struct lys_tpdf *)yang;
Pavol Vicand01d8ae2016-03-01 10:45:59 +01005952 } else {
5953 /* we need to always be able to free this, it's safe only in this case */
Pavol Vican5f0316a2016-04-05 21:21:11 +02005954 lydict_remove(mod->ctx, yang->name);
Pavol Vicand01d8ae2016-03-01 10:45:59 +01005955 free(yang);
Pavol Vicana0e4e672016-02-24 12:20:04 +01005956 }
5957
Michal Vasko88c29542015-11-27 14:57:53 +01005958 } else {
Radek Krejci3a5501d2016-07-18 22:03:34 +02005959 rc = fill_yin_type(mod, node, yin, stype, tpdf_flag, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01005960 if (!rc) {
5961 /* we need to always be able to free this, it's safe only in this case */
5962 lyxml_free(mod->ctx, yin);
5963 } else {
5964 /* may try again later, put all back how it was */
5965 stype->der = (struct lys_tpdf *)yin;
5966 }
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005967 }
Radek Krejcic13db382016-08-16 10:52:42 +02005968 if (rc == EXIT_SUCCESS) {
Radek Krejci2c2fce82016-08-01 13:52:26 +02005969 /* it does not make sense to have leaf-list of empty type */
5970 if (!tpdf_flag && node->nodetype == LYS_LEAFLIST && stype->base == LY_TYPE_EMPTY) {
5971 LOGWRN("The leaf-list \"%s\" is of \"empty\" type, which does not make sense.", node->name);
5972 }
Radek Krejci9b6aad22016-09-20 15:55:51 +02005973 } else if (rc == EXIT_FAILURE && stype->base != LY_TYPE_ERR) {
Radek Krejcic13db382016-08-16 10:52:42 +02005974 /* forward reference - in case the type is in grouping, we have to make the grouping unusable
5975 * by uses statement until the type is resolved. We do that the same way as uses statements inside
5976 * grouping - the grouping's nacm member (not used un grouping) is used to increase the number of
5977 * 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 +02005978 * 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 +02005979 * of the type's base member. */
5980 for (par_grp = node; par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
5981 if (par_grp) {
5982 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci9b6aad22016-09-20 15:55:51 +02005983 stype->base = LY_TYPE_ERR;
Radek Krejcic13db382016-08-16 10:52:42 +02005984 }
Radek Krejci2c2fce82016-08-01 13:52:26 +02005985 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005986 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005987 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02005988 iff_data = str_snode;
5989 rc = resolve_feature(iff_data->fname, strlen(iff_data->fname), iff_data->node, item);
Radek Krejci9ff0a922016-07-14 13:08:05 +02005990 if (!rc) {
5991 /* success */
Radek Krejci9de2c042016-10-19 16:53:06 +02005992 if (iff_data->infeature) {
5993 /* store backlink into the target feature to allow reverse changes in case of changing feature status */
5994 feat = *((struct lys_feature **)item);
5995 if (!feat->depfeatures) {
5996 feat->depfeatures = ly_set_new();
5997 }
Radek Krejci85a54be2016-10-20 12:39:56 +02005998 ly_set_add(feat->depfeatures, iff_data->node, LY_SET_OPT_USEASLIST);
Radek Krejci9de2c042016-10-19 16:53:06 +02005999 }
6000 /* cleanup temporary data */
Radek Krejcicbb473e2016-09-16 14:48:32 +02006001 lydict_remove(mod->ctx, iff_data->fname);
6002 free(iff_data);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006003 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006004 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006005 case UNRES_FEATURE:
6006 feat = (struct lys_feature *)item;
6007
6008 if (feat->iffeature_size) {
6009 refs = ly_set_new();
6010 procs = ly_set_new();
6011 ly_set_add(procs, feat, 0);
6012
6013 while (procs->number) {
6014 ref = procs->set.g[procs->number - 1];
6015 ly_set_rm_index(procs, procs->number - 1);
6016
6017 for (i = 0; i < ref->iffeature_size; i++) {
6018 resolve_iffeature_getsizes(&ref->iffeature[i], NULL, &j);
6019 for (; j > 0 ; j--) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006020 if (ref->iffeature[i].features[j - 1]) {
Radek Krejcic79c6b12016-07-26 15:11:49 +02006021 if (ref->iffeature[i].features[j - 1] == feat) {
6022 LOGVAL(LYE_CIRC_FEATURES, LY_VLOG_NONE, NULL, feat->name);
6023 goto featurecheckdone;
6024 }
6025
6026 if (ref->iffeature[i].features[j - 1]->iffeature_size) {
6027 k = refs->number;
6028 if (ly_set_add(refs, ref->iffeature[i].features[j - 1], 0) == k) {
6029 /* not yet seen feature, add it for processing */
6030 ly_set_add(procs, ref->iffeature[i].features[j - 1], 0);
6031 }
6032 }
6033 } else {
6034 /* forward reference */
6035 rc = EXIT_FAILURE;
6036 goto featurecheckdone;
6037 }
6038 }
6039
6040 }
6041 }
6042 rc = EXIT_SUCCESS;
6043
6044featurecheckdone:
6045 ly_set_free(refs);
6046 ly_set_free(procs);
6047 }
6048
6049 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006050 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006051 rc = resolve_unres_schema_uses(item, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006052 break;
6053 case UNRES_TYPE_DFLT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006054 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006055 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006056 stype = item;
6057
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006058 rc = check_default(stype, expr, mod);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006059 break;
6060 case UNRES_CHOICE_DFLT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006061 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006062 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006063 choic = item;
6064
Radek Krejcie00d2312016-08-12 15:27:49 +02006065 if (!choic->dflt) {
6066 choic->dflt = resolve_choice_dflt(choic, expr);
6067 }
Michal Vasko7955b362015-09-04 14:18:15 +02006068 if (choic->dflt) {
Radek Krejcie00d2312016-08-12 15:27:49 +02006069 rc = lyp_check_mandatory_choice((struct lys_node *)choic);
Michal Vasko7955b362015-09-04 14:18:15 +02006070 } else {
6071 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006072 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006073 break;
6074 case UNRES_LIST_KEYS:
Radek Krejci4f78b532016-02-17 13:43:00 +01006075 has_str = 1;
Radek Krejci48464ed2016-03-17 15:44:09 +01006076 rc = resolve_list_keys(item, str_snode);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006077 break;
6078 case UNRES_LIST_UNIQ:
Radek Krejcid09d1a52016-08-11 14:05:45 +02006079 unique_info = (struct unres_list_uniq *)item;
6080 rc = resolve_unique(unique_info->list, unique_info->expr, unique_info->trg_type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006081 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006082 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006083 rc = resolve_augment(item, NULL);
Michal Vasko7178e692016-02-12 15:58:05 +01006084 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006085 case UNRES_XPATH:
6086 node = (struct lys_node *)item;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02006087 rc = lys_check_xpath(node, 1);
Michal Vasko508a50d2016-09-07 14:50:33 +02006088 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006089 default:
6090 LOGINT;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006091 break;
6092 }
6093
Radek Krejci54081ce2016-08-12 15:21:47 +02006094 if (has_str && !rc) {
6095 /* the string is no more needed in case of success.
6096 * In case of forward reference, we will try to resolve the string later */
Radek Krejci4f78b532016-02-17 13:43:00 +01006097 lydict_remove(mod->ctx, str_snode);
6098 }
6099
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006100 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006101}
6102
Michal Vaskof02e3742015-08-05 16:27:02 +02006103/* logs directly */
6104static void
Radek Krejci48464ed2016-03-17 15:44:09 +01006105print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006106{
Michal Vaskocb34dc62016-05-20 14:38:37 +02006107 struct lyxml_elem *xml;
6108 struct lyxml_attr *attr;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006109 struct unres_iffeat_data *iff_data;
Radek Krejci76e15e12016-06-22 11:02:24 +02006110 const char *type_name = NULL;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006111
Michal Vaskof02e3742015-08-05 16:27:02 +02006112 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02006113 case UNRES_IDENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006114 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identity", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006115 break;
6116 case UNRES_TYPE_IDENTREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006117 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identityref", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006118 break;
6119 case UNRES_TYPE_LEAFREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006120 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "leafref",
6121 ((struct lys_type *)item)->info.lref.path);
Michal Vaskof02e3742015-08-05 16:27:02 +02006122 break;
Radek Krejci3a5501d2016-07-18 22:03:34 +02006123 case UNRES_TYPE_DER_TPDF:
Michal Vaskof02e3742015-08-05 16:27:02 +02006124 case UNRES_TYPE_DER:
Michal Vaskocb34dc62016-05-20 14:38:37 +02006125 xml = (struct lyxml_elem *)((struct lys_type *)item)->der;
6126 if (xml->flags & LY_YANG_STRUCTURE_FLAG) {
6127 type_name = ((struct yang_type *)xml)->name;
6128 } else {
6129 LY_TREE_FOR(xml->attr, attr) {
6130 if ((attr->type == LYXML_ATTR_STD) && !strcmp(attr->name, "name")) {
6131 type_name = attr->value;
6132 break;
6133 }
6134 }
6135 assert(attr);
6136 }
6137 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "derived type", type_name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006138 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006139 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006140 iff_data = str_node;
6141 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "if-feature", iff_data->fname);
Michal Vaskof02e3742015-08-05 16:27:02 +02006142 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006143 case UNRES_FEATURE:
6144 LOGVRB("There are unresolved if-features for \"%s\" feature circular dependency check, it will be attempted later",
6145 ((struct lys_feature *)item)->name);
6146 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006147 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006148 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "uses", ((struct lys_node_uses *)item)->name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006149 break;
6150 case UNRES_TYPE_DFLT:
Radek Krejci2e2de832016-10-13 16:12:26 +02006151 if (str_node) {
6152 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "type default", (char *)str_node);
6153 } /* else no default value in the type itself, but we are checking some restrictions against
6154 * possible default value of some base type. The failure is caused by not resolved base type,
6155 * so it was already reported */
Michal Vaskof02e3742015-08-05 16:27:02 +02006156 break;
6157 case UNRES_CHOICE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006158 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "choice default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006159 break;
6160 case UNRES_LIST_KEYS:
Radek Krejci48464ed2016-03-17 15:44:09 +01006161 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list keys", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006162 break;
6163 case UNRES_LIST_UNIQ:
Radek Krejci48464ed2016-03-17 15:44:09 +01006164 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list unique", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006165 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006166 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006167 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "augment target",
6168 ((struct lys_node_augment *)item)->target_name);
Michal Vasko7178e692016-02-12 15:58:05 +01006169 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006170 case UNRES_XPATH:
6171 LOGVRB("Resolving %s \"%s\" with the context node \"%s\" failed, it will be attempted later.", "XPath",
6172 (char *)str_node, ((struct lys_node *)item)->name);
6173 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006174 default:
6175 LOGINT;
Michal Vaskof02e3742015-08-05 16:27:02 +02006176 break;
6177 }
6178}
6179
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006180/**
Michal Vaskobb211122015-08-19 14:03:11 +02006181 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006182 *
6183 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006184 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006185 *
Michal Vasko92b8a382015-08-19 14:03:49 +02006186 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006187 */
Michal Vaskof02e3742015-08-05 16:27:02 +02006188int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006189resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02006190{
Radek Krejci010e54b2016-03-15 09:40:34 +01006191 uint32_t i, resolved = 0, unres_count, res_count;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006192 int rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006193
6194 assert(unres);
6195
Michal Vaskoe8734262016-09-29 14:12:06 +02006196 LOGVRB("Resolving \"%s\" unresolved schema nodes and their constraints...", mod->name);
Radek Krejci010e54b2016-03-15 09:40:34 +01006197 ly_vlog_hide(1);
Michal Vasko51054ca2015-08-12 12:20:00 +02006198
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006199 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02006200 do {
Michal Vasko88c29542015-11-27 14:57:53 +01006201 unres_count = 0;
6202 res_count = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02006203
6204 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006205 /* UNRES_TYPE_LEAFREF must be resolved (for storing leafref target pointers);
Radek Krejcic79c6b12016-07-26 15:11:49 +02006206 * if-features are resolved here to make sure that we will have all if-features for
6207 * later check of feature circular dependency */
Radek Krejci018f1f52016-08-03 16:01:20 +02006208 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006209 continue;
6210 }
Radek Krejci018f1f52016-08-03 16:01:20 +02006211 /* processes UNRES_USES, UNRES_IFFEAT, UNRES_TYPE_DER, UNRES_TYPE_DER_TPDF, UNRES_TYPE_LEAFREF,
Radek Krejcie00d2312016-08-12 15:27:49 +02006212 * UNRES_CHOICE_DFLT and UNRES_IDENT */
Michal Vasko51054ca2015-08-12 12:20:00 +02006213
Michal Vasko88c29542015-11-27 14:57:53 +01006214 ++unres_count;
Radek Krejci48464ed2016-03-17 15:44:09 +01006215 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006216 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006217 unres->type[i] = UNRES_RESOLVED;
6218 ++resolved;
Michal Vasko88c29542015-11-27 14:57:53 +01006219 ++res_count;
Michal Vasko89e15322015-08-17 15:46:55 +02006220 } else if (rc == -1) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006221 ly_vlog_hide(0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02006222 /* print the error */
6223 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006224 return -1;
Radek Krejcic2a180f2016-06-22 13:28:16 +02006225 } else {
6226 /* forward reference, erase ly_errno */
Radek Krejci2467a492016-10-24 15:16:59 +02006227 ly_err_clean();
Michal Vasko51054ca2015-08-12 12:20:00 +02006228 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006229 }
Michal Vasko88c29542015-11-27 14:57:53 +01006230 } while (res_count && (res_count < unres_count));
Michal Vasko51054ca2015-08-12 12:20:00 +02006231
Michal Vasko88c29542015-11-27 14:57:53 +01006232 if (res_count < unres_count) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006233 /* just print the errors */
6234 ly_vlog_hide(0);
6235
6236 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006237 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006238 continue;
6239 }
6240 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
6241 }
Michal Vasko92b8a382015-08-19 14:03:49 +02006242 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006243 }
6244
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006245 /* the rest */
6246 for (i = 0; i < unres->count; ++i) {
6247 if (unres->type[i] == UNRES_RESOLVED) {
6248 continue;
6249 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02006250
Radek Krejci48464ed2016-03-17 15:44:09 +01006251 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01006252 if (rc == 0) {
Pavol Vican88e16c92016-09-07 15:41:50 +02006253 if (unres->type[i] == UNRES_LIST_UNIQ) {
6254 /* free the allocated structure */
6255 free(unres->item[i]);
6256 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006257 unres->type[i] = UNRES_RESOLVED;
6258 ++resolved;
6259 } else if (rc == -1) {
6260 ly_vlog_hide(0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02006261 /* print the error */
6262 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
6263 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006264 }
6265 }
6266
Radek Krejci010e54b2016-03-15 09:40:34 +01006267 ly_vlog_hide(0);
6268
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006269 if (resolved < unres->count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006270 /* try to resolve the unresolved nodes again, it will not resolve anything, but it will print
6271 * all the validation errors
6272 */
6273 for (i = 0; i < unres->count; ++i) {
6274 if (unres->type[i] == UNRES_RESOLVED) {
6275 continue;
6276 }
Radek Krejci48464ed2016-03-17 15:44:09 +01006277 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01006278 }
Michal Vasko92b8a382015-08-19 14:03:49 +02006279 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006280 }
6281
Michal Vaskoe8734262016-09-29 14:12:06 +02006282 LOGVRB("All \"%s\" schema nodes and constraints resolved.", mod->name);
Radek Krejcic071c542016-01-27 14:57:51 +01006283 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006284 return EXIT_SUCCESS;
6285}
6286
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006287/**
Michal Vaskobb211122015-08-19 14:03:11 +02006288 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006289 *
6290 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006291 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006292 * @param[in] item Item to resolve. Type determined by \p type.
6293 * @param[in] type Type of the unresolved item.
6294 * @param[in] str String argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006295 *
Michal Vasko3767fb22016-07-21 12:10:57 +02006296 * @return EXIT_SUCCESS on success, EXIT_FAILURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006297 */
6298int
Radek Krejci48464ed2016-03-17 15:44:09 +01006299unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
6300 const char *str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006301{
Radek Krejci54081ce2016-08-12 15:21:47 +02006302 int rc;
6303 const char *dictstr;
6304
6305 dictstr = lydict_insert(mod->ctx, str, 0);
6306 rc = unres_schema_add_node(mod, unres, item, type, (struct lys_node *)dictstr);
6307
6308 if (rc == -1) {
6309 lydict_remove(mod->ctx, dictstr);
6310 }
6311 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006312}
6313
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006314/**
Michal Vaskobb211122015-08-19 14:03:11 +02006315 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006316 *
6317 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006318 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006319 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01006320 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006321 * @param[in] snode Schema node argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006322 *
Michal Vasko3767fb22016-07-21 12:10:57 +02006323 * @return EXIT_SUCCESS on success, EXIT_FIALURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006324 */
6325int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006326unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Radek Krejci48464ed2016-03-17 15:44:09 +01006327 struct lys_node *snode)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006328{
Michal Vaskoef486d72016-09-27 12:10:44 +02006329 int rc, log_hidden;
Michal Vasko88c29542015-11-27 14:57:53 +01006330 struct lyxml_elem *yin;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006331
Michal Vasko9bf425b2015-10-22 11:42:03 +02006332 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
6333 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006334
Michal Vaskoef486d72016-09-27 12:10:44 +02006335 if (*ly_vlog_hide_location()) {
6336 log_hidden = 1;
6337 } else {
6338 log_hidden = 0;
6339 ly_vlog_hide(1);
6340 }
Radek Krejci48464ed2016-03-17 15:44:09 +01006341 rc = resolve_unres_schema_item(mod, item, type, snode, unres);
Michal Vaskoef486d72016-09-27 12:10:44 +02006342 if (!log_hidden) {
6343 ly_vlog_hide(0);
6344 }
6345
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006346 if (rc != EXIT_FAILURE) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006347 if (rc == -1 && ly_errno == LY_EVALID) {
Radek Krejci2467a492016-10-24 15:16:59 +02006348 ly_err_repeat();
Radek Krejci010e54b2016-03-15 09:40:34 +01006349 }
Radek Krejcid09d1a52016-08-11 14:05:45 +02006350 if (type == UNRES_LIST_UNIQ) {
6351 /* free the allocated structure */
6352 free(item);
Pavol Vican88e16c92016-09-07 15:41:50 +02006353 } else if (rc == -1 && type == UNRES_IFFEAT) {
6354 /* free the allocated resources */
6355 free(*((char **)item));
6356 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006357 return rc;
Radek Krejcif347abc2016-06-22 10:18:47 +02006358 } else {
6359 /* erase info about validation errors */
Radek Krejci2467a492016-10-24 15:16:59 +02006360 ly_err_clean();
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006361 }
6362
Radek Krejci48464ed2016-03-17 15:44:09 +01006363 print_unres_schema_item_fail(item, type, snode);
Michal Vaskof02e3742015-08-05 16:27:02 +02006364
Michal Vasko88c29542015-11-27 14:57:53 +01006365 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
Radek Krejci3a5501d2016-07-18 22:03:34 +02006366 if (type == UNRES_TYPE_DER || type == UNRES_TYPE_DER_TPDF) {
Michal Vasko88c29542015-11-27 14:57:53 +01006367 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
Pavol Vicana0e4e672016-02-24 12:20:04 +01006368 if (!(yin->flags & LY_YANG_STRUCTURE_FLAG)) {
6369 lyxml_unlink_elem(mod->ctx, yin, 1);
6370 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
6371 }
Michal Vasko88c29542015-11-27 14:57:53 +01006372 }
6373
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006374 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01006375 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
6376 if (!unres->item) {
6377 LOGMEM;
6378 return -1;
6379 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006380 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01006381 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
6382 if (!unres->type) {
6383 LOGMEM;
6384 return -1;
6385 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006386 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01006387 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
6388 if (!unres->str_snode) {
6389 LOGMEM;
6390 return -1;
6391 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006392 unres->str_snode[unres->count-1] = snode;
Radek Krejcic071c542016-01-27 14:57:51 +01006393 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
6394 if (!unres->module) {
6395 LOGMEM;
6396 return -1;
6397 }
6398 unres->module[unres->count-1] = mod;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006399
Michal Vasko3767fb22016-07-21 12:10:57 +02006400 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006401}
6402
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006403/**
Michal Vaskobb211122015-08-19 14:03:11 +02006404 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006405 *
6406 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006407 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006408 * @param[in] item Old item to be resolved.
6409 * @param[in] type Type of the old unresolved item.
6410 * @param[in] new_item New item to use in the duplicate.
6411 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02006412 * @return EXIT_SUCCESS on success, EXIT_FAILURE if item is not in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006413 */
Michal Vaskodad19402015-08-06 09:51:53 +02006414int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006415unres_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 +02006416{
6417 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006418 struct unres_list_uniq aux_uniq;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006419 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006420
Michal Vaskocf024702015-10-08 15:01:42 +02006421 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006422
Radek Krejcid09d1a52016-08-11 14:05:45 +02006423 /* hack for UNRES_LIST_UNIQ, which stores multiple items behind its item */
6424 if (type == UNRES_LIST_UNIQ) {
6425 aux_uniq.list = item;
6426 aux_uniq.expr = ((struct unres_list_uniq *)new_item)->expr;
6427 item = &aux_uniq;
6428 }
Michal Vasko878e38d2016-09-05 12:17:53 +02006429 i = unres_schema_find(unres, -1, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006430
6431 if (i == -1) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006432 if (type == UNRES_LIST_UNIQ) {
6433 free(new_item);
6434 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02006435 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006436 }
6437
Radek Krejcic79c6b12016-07-26 15:11:49 +02006438 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT) ||
Radek Krejcib69f3232016-09-16 17:41:07 +02006439 (type == UNRES_FEATURE) || (type == UNRES_LIST_UNIQ)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01006440 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006441 LOGINT;
6442 return -1;
6443 }
Radek Krejcicbb473e2016-09-16 14:48:32 +02006444 } else if (type == UNRES_IFFEAT) {
6445 /* duplicate unres_iffeature_data */
6446 iff_data = malloc(sizeof *iff_data);
6447 iff_data->fname = lydict_insert(mod->ctx, ((struct unres_iffeat_data *)unres->str_snode[i])->fname, 0);
6448 iff_data->node = ((struct unres_iffeat_data *)unres->str_snode[i])->node;
6449 if (unres_schema_add_node(mod, unres, new_item, type, (struct lys_node *)iff_data) == -1) {
6450 LOGINT;
6451 return -1;
6452 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006453 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01006454 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006455 LOGINT;
6456 return -1;
6457 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006458 }
Michal Vaskodad19402015-08-06 09:51:53 +02006459
6460 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006461}
6462
Michal Vaskof02e3742015-08-05 16:27:02 +02006463/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006464int
Michal Vasko878e38d2016-09-05 12:17:53 +02006465unres_schema_find(struct unres_schema *unres, int start_on_backwards, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006466{
Michal Vasko878e38d2016-09-05 12:17:53 +02006467 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006468 struct unres_list_uniq *aux_uniq1, *aux_uniq2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006469
Michal Vasko878e38d2016-09-05 12:17:53 +02006470 if (start_on_backwards > 0) {
6471 i = start_on_backwards;
6472 } else {
6473 i = unres->count - 1;
6474 }
6475 for (; i > -1; i--) {
6476 if (unres->type[i] != type) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006477 continue;
6478 }
6479 if (type != UNRES_LIST_UNIQ) {
Michal Vasko878e38d2016-09-05 12:17:53 +02006480 if (unres->item[i] == item) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006481 break;
6482 }
6483 } else {
6484 aux_uniq1 = (struct unres_list_uniq *)unres->item[i - 1];
6485 aux_uniq2 = (struct unres_list_uniq *)item;
6486 if ((aux_uniq1->list == aux_uniq2->list) && ly_strequal(aux_uniq1->expr, aux_uniq2->expr, 0)) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006487 break;
6488 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006489 }
6490 }
6491
Michal Vasko878e38d2016-09-05 12:17:53 +02006492 return i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006493}
Michal Vasko8bcdf292015-08-19 14:04:43 +02006494
Michal Vaskoede9c472016-06-07 09:38:15 +02006495static void
6496unres_schema_free_item(struct ly_ctx *ctx, struct unres_schema *unres, uint32_t i)
6497{
6498 struct lyxml_elem *yin;
6499 struct yang_type *yang;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006500 struct unres_iffeat_data *iff_data;
Michal Vaskoede9c472016-06-07 09:38:15 +02006501
6502 switch (unres->type[i]) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02006503 case UNRES_TYPE_DER_TPDF:
Michal Vaskoede9c472016-06-07 09:38:15 +02006504 case UNRES_TYPE_DER:
6505 yin = (struct lyxml_elem *)((struct lys_type *)unres->item[i])->der;
6506 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6507 yang =(struct yang_type *)yin;
6508 yang->type->base = yang->base;
6509 lydict_remove(ctx, yang->name);
6510 free(yang);
6511 } else {
6512 lyxml_free(ctx, yin);
6513 }
6514 break;
Pavol Vican88e16c92016-09-07 15:41:50 +02006515 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006516 iff_data = (struct unres_iffeat_data *)unres->str_snode[i];
6517 lydict_remove(ctx, iff_data->fname);
6518 free(unres->str_snode[i]);
Pavol Vican88e16c92016-09-07 15:41:50 +02006519 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02006520 case UNRES_IDENT:
6521 case UNRES_TYPE_IDENTREF:
Michal Vaskoede9c472016-06-07 09:38:15 +02006522 case UNRES_TYPE_DFLT:
6523 case UNRES_CHOICE_DFLT:
6524 case UNRES_LIST_KEYS:
Michal Vaskoede9c472016-06-07 09:38:15 +02006525 lydict_remove(ctx, (const char *)unres->str_snode[i]);
6526 break;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006527 case UNRES_LIST_UNIQ:
6528 free(unres->item[i]);
6529 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02006530 default:
6531 break;
6532 }
6533 unres->type[i] = UNRES_RESOLVED;
6534}
6535
Michal Vasko88c29542015-11-27 14:57:53 +01006536void
Radek Krejcic071c542016-01-27 14:57:51 +01006537unres_schema_free(struct lys_module *module, struct unres_schema **unres)
Michal Vasko88c29542015-11-27 14:57:53 +01006538{
6539 uint32_t i;
Radek Krejcic071c542016-01-27 14:57:51 +01006540 unsigned int unresolved = 0;
Michal Vasko88c29542015-11-27 14:57:53 +01006541
Radek Krejcic071c542016-01-27 14:57:51 +01006542 if (!unres || !(*unres)) {
6543 return;
Michal Vasko88c29542015-11-27 14:57:53 +01006544 }
6545
Radek Krejcic071c542016-01-27 14:57:51 +01006546 assert(module || (*unres)->count == 0);
6547
6548 for (i = 0; i < (*unres)->count; ++i) {
6549 if ((*unres)->module[i] != module) {
6550 if ((*unres)->type[i] != UNRES_RESOLVED) {
6551 unresolved++;
6552 }
6553 continue;
6554 }
Michal Vaskoede9c472016-06-07 09:38:15 +02006555
6556 /* free heap memory for the specific item */
6557 unres_schema_free_item(module->ctx, *unres, i);
Radek Krejcic071c542016-01-27 14:57:51 +01006558 }
6559
Michal Vaskoede9c472016-06-07 09:38:15 +02006560 /* free it all */
Radek Krejcic071c542016-01-27 14:57:51 +01006561 if (!module || (!unresolved && !module->type)) {
6562 free((*unres)->item);
6563 free((*unres)->type);
6564 free((*unres)->str_snode);
6565 free((*unres)->module);
Radek Krejcic071c542016-01-27 14:57:51 +01006566 free((*unres));
6567 (*unres) = NULL;
6568 }
Michal Vasko88c29542015-11-27 14:57:53 +01006569}
6570
Radek Krejci7de36cf2016-09-12 16:18:50 +02006571static int
Radek Krejci9b6aad22016-09-20 15:55:51 +02006572resolve_leafref(struct lyd_node_leaf_list *leaf, struct lys_type *type)
Radek Krejci7de36cf2016-09-12 16:18:50 +02006573{
Radek Krejci7de36cf2016-09-12 16:18:50 +02006574 struct unres_data matches;
6575 uint32_t i;
6576
Radek Krejci9b6aad22016-09-20 15:55:51 +02006577 assert(type->base == LY_TYPE_LEAFREF);
6578
6579 /* init */
Radek Krejci7de36cf2016-09-12 16:18:50 +02006580 memset(&matches, 0, sizeof matches);
Radek Krejci7de36cf2016-09-12 16:18:50 +02006581
6582 /* EXIT_FAILURE return keeps leaf->value.lefref NULL, handled later */
Radek Krejci9b6aad22016-09-20 15:55:51 +02006583 if (resolve_path_arg_data((struct lyd_node *)leaf, type->info.lref.path, &matches) == -1) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02006584 return -1;
6585 }
6586
6587 /* check that value matches */
6588 for (i = 0; i < matches.count; ++i) {
6589 if (ly_strequal(leaf->value_str, ((struct lyd_node_leaf_list *)matches.node[i])->value_str, 1)) {
6590 leaf->value.leafref = matches.node[i];
6591 break;
6592 }
6593 }
6594
6595 free(matches.node);
6596
6597 if (!leaf->value.leafref) {
6598 /* reference not found */
6599 if (type->info.lref.req > -1) {
6600 LOGVAL(LYE_NOLEAFREF, LY_VLOG_LYD, leaf, type->info.lref.path, leaf->value_str);
6601 return EXIT_FAILURE;
6602 } else {
6603 LOGVRB("There is no leafref with the value \"%s\", but it is not required.", leaf->value_str);
6604 }
6605 }
6606
6607 return EXIT_SUCCESS;
6608}
6609
Radek Krejci9b6aad22016-09-20 15:55:51 +02006610API LY_DATA_TYPE
6611lyd_leaf_type(const struct lyd_node_leaf_list *leaf)
6612{
6613 struct lyd_node *node;
6614 struct lys_type *type, *type_iter;
6615 lyd_val value;
6616 int f = 0, r;
6617
6618 if (!leaf || !(leaf->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
6619 return LY_TYPE_ERR;
6620 }
6621
6622 if (leaf->value_type > 0 && (leaf->value_type & LY_DATA_TYPE_MASK) != LY_TYPE_UNION &&
6623 (leaf->value_type & LY_DATA_TYPE_MASK) != LY_TYPE_LEAFREF) {
6624 /* we can get the type directly from the data node (it was already resolved) */
6625 return leaf->value_type & LY_DATA_TYPE_MASK;
6626 }
6627
6628 /* init */
6629 type = &((struct lys_node_leaf *)leaf->schema)->type;
6630 value = leaf->value;
6631 ly_vlog_hide(1);
6632
6633 /* resolve until we get the real data type */
6634 while (1) {
6635 /* get the correct data type from schema */
6636 switch (type->base) {
6637 case LY_TYPE_LEAFREF:
6638 type = &type->info.lref.target->type;
6639 break; /* continue in while loop */
6640 case LY_TYPE_UNION:
6641 type_iter = NULL;
6642 while ((type_iter = lyp_get_next_union_type(type, type_iter, &f))) {
6643 if (type_iter->base == LY_TYPE_LEAFREF) {
6644 if (type_iter->info.lref.req == -1) {
6645 /* target not required, so it always succeeds */
6646 break;
6647 } else {
6648 /* try to resolve leafref */
6649 memset(&((struct lyd_node_leaf_list *)leaf)->value, 0, sizeof leaf->value);
6650 r = resolve_leafref((struct lyd_node_leaf_list *)leaf, type_iter);
6651 /* revert leaf's content affected by resolve_leafref */
6652 ((struct lyd_node_leaf_list *)leaf)->value = value;
6653 if (!r) {
6654 /* success, we can continue with the leafref type */
6655 break;
6656 }
6657 }
6658 } else if (type_iter->base == LY_TYPE_INST) {
6659 if (type_iter->info.inst.req == -1) {
6660 /* target not required, so it always succeeds */
6661 return LY_TYPE_INST;
6662 } else {
6663 /* try to resolve instance-identifier */
Radek Krejci2467a492016-10-24 15:16:59 +02006664 ly_err_clean();
Radek Krejci9b6aad22016-09-20 15:55:51 +02006665 node = resolve_instid((struct lyd_node *)leaf, leaf->value_str);
6666 if (!ly_errno && node) {
6667 /* the real type is instance-identifier */
6668 return LY_TYPE_INST;
6669 }
6670 }
6671 } else {
6672 r = lyp_parse_value_type((struct lyd_node_leaf_list *)leaf, type_iter, 1);
6673 /* revert leaf's content affected by resolve_leafref */
6674 ((struct lyd_node_leaf_list *)leaf)->value = value;
6675 if (!r) {
6676 /* we have the real type */
6677 return type_iter->base;
6678 }
6679 }
6680 f = 0;
6681 }
6682 /* erase ly_errno and ly_vecode */
Radek Krejci2467a492016-10-24 15:16:59 +02006683 ly_err_clean();
Radek Krejci9b6aad22016-09-20 15:55:51 +02006684
6685 if (!type_iter) {
6686 LOGERR(LY_EINVAL, "Unable to get type from union \"%s\" with no valid type.", type->parent->name)
6687 return LY_TYPE_ERR;
6688 }
6689 type = type_iter;
6690 break;
6691 default:
6692 /* we have the real type */
6693 ly_vlog_hide(0);
6694 return type->base;
6695 }
6696 }
6697
6698 ly_vlog_hide(0);
6699 return LY_TYPE_ERR;
6700}
6701
6702static int
6703resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type)
6704{
6705 struct lys_type *datatype = NULL;
6706 int f = 0;
6707
6708 assert(type->base == LY_TYPE_UNION);
6709
6710 memset(&leaf->value, 0, sizeof leaf->value);
6711 while ((datatype = lyp_get_next_union_type(type, datatype, &f))) {
6712 leaf->value_type = datatype->base;
6713
6714 if (datatype->base == LY_TYPE_LEAFREF) {
6715 /* try to resolve leafref */
6716 if (!resolve_leafref(leaf, datatype)) {
6717 /* success */
6718 break;
6719 }
6720 } else if (datatype->base == LY_TYPE_INST) {
6721 /* try to resolve instance-identifier */
Radek Krejci2467a492016-10-24 15:16:59 +02006722 ly_err_clean();
Radek Krejci9b6aad22016-09-20 15:55:51 +02006723 leaf->value.instance = resolve_instid((struct lyd_node *)leaf, leaf->value_str);
6724 if (!ly_errno && (leaf->value.instance || datatype->info.inst.req == -1)) {
6725 /* success */
6726 break;
6727 }
6728 } else {
6729 if (!lyp_parse_value_type(leaf, datatype, 1)) {
6730 /* success */
6731 break;
6732 }
6733 }
6734 f = 0;
6735 }
6736 /* erase ly_errno and ly_vecode */
Radek Krejci2467a492016-10-24 15:16:59 +02006737 ly_err_clean();
Radek Krejci9b6aad22016-09-20 15:55:51 +02006738
6739 if (!datatype) {
6740 /* failure */
6741 LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, (leaf->value_str ? leaf->value_str : ""), leaf->schema->name);
6742 return EXIT_FAILURE;
6743 }
6744
6745 return EXIT_SUCCESS;
6746}
6747
Michal Vasko8bcdf292015-08-19 14:04:43 +02006748/**
6749 * @brief Resolve a single unres data item. Logs directly.
6750 *
Michal Vaskocf024702015-10-08 15:01:42 +02006751 * @param[in] node Data node to resolve.
Michal Vaskocf024702015-10-08 15:01:42 +02006752 * @param[in] type Type of the unresolved item.
Michal Vasko8bcdf292015-08-19 14:04:43 +02006753 *
6754 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
6755 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02006756int
Radek Krejci48464ed2016-03-17 15:44:09 +01006757resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02006758{
Michal Vasko0491ab32015-08-19 14:28:29 +02006759 int rc;
Michal Vasko83a6c462015-10-08 16:43:53 +02006760 struct lyd_node_leaf_list *leaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006761 struct lys_node_leaf *sleaf;
Michal Vaskoc4280842016-04-19 16:10:42 +02006762 struct lyd_node *parent;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006763
Michal Vasko83a6c462015-10-08 16:43:53 +02006764 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02006765 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006766
Michal Vaskocf024702015-10-08 15:01:42 +02006767 switch (type) {
6768 case UNRES_LEAFREF:
6769 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Radek Krejci9b6aad22016-09-20 15:55:51 +02006770 return resolve_leafref(leaf, &sleaf->type);
Michal Vasko8bcdf292015-08-19 14:04:43 +02006771
Michal Vaskocf024702015-10-08 15:01:42 +02006772 case UNRES_INSTID:
Radek Krejci7de36cf2016-09-12 16:18:50 +02006773 assert(sleaf->type.base == LY_TYPE_INST);
Radek Krejci2467a492016-10-24 15:16:59 +02006774 ly_err_clean();
Radek Krejci48464ed2016-03-17 15:44:09 +01006775 leaf->value.instance = resolve_instid(node, leaf->value_str);
Radek Krejci40f17b92016-02-03 14:30:43 +01006776 if (!leaf->value.instance) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02006777 if (ly_errno) {
6778 return -1;
6779 } else if (sleaf->type.info.inst.req > -1) {
Michal Vasko6ac68282016-04-11 10:56:47 +02006780 LOGVAL(LYE_NOREQINS, LY_VLOG_LYD, leaf, leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02006781 return EXIT_FAILURE;
6782 } else {
Michal Vasko9925e282016-09-02 12:45:14 +02006783 LOGVRB("There is no instance identifier \"%s\", but it is not required.", leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02006784 }
6785 }
Michal Vaskocf024702015-10-08 15:01:42 +02006786 break;
6787
Radek Krejci7de36cf2016-09-12 16:18:50 +02006788 case UNRES_UNION:
6789 assert(sleaf->type.base == LY_TYPE_UNION);
Radek Krejci9b6aad22016-09-20 15:55:51 +02006790 return resolve_union(leaf, &sleaf->type);
Radek Krejci7de36cf2016-09-12 16:18:50 +02006791
Michal Vaskocf024702015-10-08 15:01:42 +02006792 case UNRES_WHEN:
Radek Krejci46165822016-08-26 14:06:27 +02006793 if ((rc = resolve_when(node, NULL))) {
Michal Vaskocf024702015-10-08 15:01:42 +02006794 return rc;
6795 }
6796 break;
6797
Michal Vaskobf19d252015-10-08 15:39:17 +02006798 case UNRES_MUST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006799 if ((rc = resolve_must(node, 0))) {
6800 return rc;
6801 }
6802 break;
6803
6804 case UNRES_MUST_INOUT:
6805 if ((rc = resolve_must(node, 1))) {
Michal Vaskobf19d252015-10-08 15:39:17 +02006806 return rc;
6807 }
6808 break;
6809
Michal Vaskoc4280842016-04-19 16:10:42 +02006810 case UNRES_EMPTYCONT:
6811 do {
6812 parent = node->parent;
6813 lyd_free(node);
6814 node = parent;
6815 } while (node && (node->schema->nodetype == LYS_CONTAINER) && !node->child
6816 && !((struct lys_node_container *)node->schema)->presence);
6817 break;
6818
Michal Vaskocf024702015-10-08 15:01:42 +02006819 default:
Michal Vasko8bcdf292015-08-19 14:04:43 +02006820 LOGINT;
6821 return -1;
6822 }
6823
6824 return EXIT_SUCCESS;
6825}
6826
6827/**
Radek Krejci0b7704f2016-03-18 12:16:14 +01006828 * @brief add data unres item
Michal Vasko8bcdf292015-08-19 14:04:43 +02006829 *
6830 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02006831 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02006832 *
Radek Krejci0b7704f2016-03-18 12:16:14 +01006833 * @return 0 on success, -1 on error.
Michal Vasko8bcdf292015-08-19 14:04:43 +02006834 */
6835int
Radek Krejci0b7704f2016-03-18 12:16:14 +01006836unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02006837{
Radek Krejci03b71f72016-03-16 11:10:09 +01006838 assert(unres && node);
Michal Vaskoc4280842016-04-19 16:10:42 +02006839 assert((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006840 || (type == UNRES_MUST_INOUT) || (type == UNRES_UNION) || (type == UNRES_EMPTYCONT));
Michal Vasko8bcdf292015-08-19 14:04:43 +02006841
Radek Krejci03b71f72016-03-16 11:10:09 +01006842 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01006843 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
6844 if (!unres->node) {
6845 LOGMEM;
6846 return -1;
6847 }
Michal Vaskocf024702015-10-08 15:01:42 +02006848 unres->node[unres->count - 1] = node;
Michal Vasko253035f2015-12-17 16:58:13 +01006849 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
6850 if (!unres->type) {
6851 LOGMEM;
6852 return -1;
6853 }
Michal Vaskocf024702015-10-08 15:01:42 +02006854 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006855
Radek Krejci0b7704f2016-03-18 12:16:14 +01006856 if (type == UNRES_WHEN) {
6857 /* remove previous result */
6858 node->when_status = LYD_WHEN;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006859 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006860
6861 return EXIT_SUCCESS;
6862}
6863
6864/**
6865 * @brief Resolve every unres data item in the structure. Logs directly.
6866 *
Radek Krejci082c84f2016-10-17 16:33:06 +02006867 * If options includes LYD_OPT_TRUSTED, the data are considered trusted (when, must conditions are not expected,
6868 * unresolved leafrefs/instids are accepted).
6869 *
6870 * If options includes LYD_OPT_NOAUTODEL, the false resulting when condition on non-default nodes, the error is raised.
6871 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006872 * @param[in] unres Unres data structure to use.
Radek Krejci082c84f2016-10-17 16:33:06 +02006873 * @param[in,out] root Root node of the data tree, can be changed due to autodeletion.
6874 * @param[in] options Data options as described above.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006875 *
6876 * @return EXIT_SUCCESS on success, -1 on error.
6877 */
6878int
Radek Krejci082c84f2016-10-17 16:33:06 +02006879resolve_unres_data(struct unres_data *unres, struct lyd_node **root, int options)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006880{
Radek Krejci0c0086a2016-03-24 15:20:28 +01006881 uint32_t i, j, first = 1, resolved = 0, del_items = 0, when_stmt = 0;
Radek Krejci010e54b2016-03-15 09:40:34 +01006882 int rc, progress;
Radek Krejci0b7704f2016-03-18 12:16:14 +01006883 struct lyd_node *parent;
Radek Krejci7de36cf2016-09-12 16:18:50 +02006884 struct lyd_node_leaf_list *leaf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006885
Radek Krejci082c84f2016-10-17 16:33:06 +02006886 assert(root);
Radek Krejci03b71f72016-03-16 11:10:09 +01006887 assert(unres);
Radek Krejci03b71f72016-03-16 11:10:09 +01006888
6889 if (!unres->count) {
6890 return EXIT_SUCCESS;
6891 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006892
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02006893 LOGVRB("Resolving unresolved data nodes and their constraints...");
Radek Krejci010e54b2016-03-15 09:40:34 +01006894 ly_vlog_hide(1);
6895
Radek Krejci0b7704f2016-03-18 12:16:14 +01006896 /* when-stmt first */
Radek Krejci010e54b2016-03-15 09:40:34 +01006897 do {
Radek Krejci2467a492016-10-24 15:16:59 +02006898 ly_err_clean();
Radek Krejci010e54b2016-03-15 09:40:34 +01006899 progress = 0;
Michal Vasko6df94132016-09-22 11:08:09 +02006900 for (i = 0; i < unres->count; i++) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006901 if (unres->type[i] != UNRES_WHEN) {
6902 continue;
6903 }
Radek Krejci082c84f2016-10-17 16:33:06 +02006904 assert(!(options & LYD_OPT_TRUSTED));
Radek Krejci0c0086a2016-03-24 15:20:28 +01006905 if (first) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006906 /* count when-stmt nodes in unres list */
6907 when_stmt++;
6908 }
6909
6910 /* resolve when condition only when all parent when conditions are already resolved */
6911 for (parent = unres->node[i]->parent;
6912 parent && LYD_WHEN_DONE(parent->when_status);
6913 parent = parent->parent) {
6914 if (!parent->parent && (parent->when_status & LYD_WHEN_FALSE)) {
6915 /* the parent node was already unlinked, do not resolve this node,
6916 * it will be removed anyway, so just mark it as resolved
6917 */
6918 unres->node[i]->when_status |= LYD_WHEN_FALSE;
6919 unres->type[i] = UNRES_RESOLVED;
6920 resolved++;
6921 break;
6922 }
6923 }
6924 if (parent) {
6925 continue;
6926 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006927
Radek Krejci48464ed2016-03-17 15:44:09 +01006928 rc = resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01006929 if (!rc) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006930 if (unres->node[i]->when_status & LYD_WHEN_FALSE) {
Radek Krejci082c84f2016-10-17 16:33:06 +02006931 if ((options & LYD_OPT_NOAUTODEL) && !unres->node[i]->dflt) {
Radek Krejci03b71f72016-03-16 11:10:09 +01006932 /* false when condition */
6933 ly_vlog_hide(0);
Radek Krejci2467a492016-10-24 15:16:59 +02006934 ly_err_repeat();
Radek Krejci03b71f72016-03-16 11:10:09 +01006935 return -1;
Radek Krejci0b7704f2016-03-18 12:16:14 +01006936 } /* follows else */
6937
Radek Krejci0c0086a2016-03-24 15:20:28 +01006938 /* only unlink now, the subtree can contain another nodes stored in the unres list */
6939 /* if it has parent non-presence containers that would be empty, we should actually
6940 * remove the container
6941 */
Radek Krejci2537fd32016-09-07 16:22:41 +02006942 for (parent = unres->node[i];
6943 parent->parent && parent->parent->schema->nodetype == LYS_CONTAINER;
6944 parent = parent->parent) {
6945 if (((struct lys_node_container *)parent->parent->schema)->presence) {
6946 /* presence container */
6947 break;
Radek Krejci0c0086a2016-03-24 15:20:28 +01006948 }
Radek Krejci2537fd32016-09-07 16:22:41 +02006949 if (parent->next || parent->prev != parent) {
6950 /* non empty (the child we are in and we are going to remove is not the only child) */
6951 break;
6952 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01006953 }
Radek Krejci2537fd32016-09-07 16:22:41 +02006954 unres->node[i] = parent;
Radek Krejci0c0086a2016-03-24 15:20:28 +01006955
Radek Krejci0b7704f2016-03-18 12:16:14 +01006956 /* auto-delete */
6957 LOGVRB("auto-delete node \"%s\" due to when condition (%s)", ly_errpath(),
6958 ((struct lys_node_leaf *)unres->node[i]->schema)->when->cond);
Radek Krejci0c0086a2016-03-24 15:20:28 +01006959 if (*root && *root == unres->node[i]) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006960 *root = (*root)->next;
Radek Krejci03b71f72016-03-16 11:10:09 +01006961 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01006962
Radek Krejci0b7704f2016-03-18 12:16:14 +01006963 lyd_unlink(unres->node[i]);
6964 unres->type[i] = UNRES_DELETE;
6965 del_items++;
Radek Krejci51fd8162016-03-24 15:49:51 +01006966
6967 /* update the rest of unres items */
6968 for (j = 0; j < unres->count; j++) {
Radek Krejci3db819b2016-03-24 16:29:48 +01006969 if (unres->type[j] == UNRES_RESOLVED || unres->type[j] == UNRES_DELETE) {
Radek Krejci51fd8162016-03-24 15:49:51 +01006970 continue;
6971 }
6972
6973 /* test if the node is in subtree to be deleted */
6974 for (parent = unres->node[j]; parent; parent = parent->parent) {
6975 if (parent == unres->node[i]) {
6976 /* yes, it is */
6977 unres->type[j] = UNRES_RESOLVED;
6978 resolved++;
6979 break;
6980 }
6981 }
6982 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01006983 } else {
6984 unres->type[i] = UNRES_RESOLVED;
Radek Krejci03b71f72016-03-16 11:10:09 +01006985 }
Radek Krejci2467a492016-10-24 15:16:59 +02006986 ly_err_clean();
Radek Krejci010e54b2016-03-15 09:40:34 +01006987 resolved++;
6988 progress = 1;
6989 } else if (rc == -1) {
6990 ly_vlog_hide(0);
Michal Vasko76e73402016-08-24 16:00:13 +02006991 /* print only this last error */
6992 resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01006993 return -1;
Radek Krejci2467a492016-10-24 15:16:59 +02006994 } /* else forward reference */
Radek Krejci010e54b2016-03-15 09:40:34 +01006995 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01006996 first = 0;
Radek Krejci0b7704f2016-03-18 12:16:14 +01006997 } while (progress && resolved < when_stmt);
Radek Krejci010e54b2016-03-15 09:40:34 +01006998
Radek Krejci0b7704f2016-03-18 12:16:14 +01006999 /* do we have some unresolved when-stmt? */
Radek Krejcid940d732016-03-24 16:02:28 +01007000 if (when_stmt > resolved) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007001 ly_vlog_hide(0);
Radek Krejci2467a492016-10-24 15:16:59 +02007002 ly_err_repeat();
Radek Krejci0b7704f2016-03-18 12:16:14 +01007003 return -1;
7004 }
7005
7006 for (i = 0; del_items && i < unres->count; i++) {
7007 /* we had some when-stmt resulted to false, so now we have to sanitize the unres list */
7008 if (unres->type[i] != UNRES_DELETE) {
7009 continue;
7010 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007011 if (!unres->node[i]) {
7012 unres->type[i] = UNRES_RESOLVED;
7013 del_items--;
7014 continue;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007015 }
7016
7017 /* really remove the complete subtree */
7018 lyd_free(unres->node[i]);
7019 unres->type[i] = UNRES_RESOLVED;
7020 del_items--;
7021 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007022
7023 /* rest */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007024 for (i = 0; i < unres->count; ++i) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007025 if (unres->type[i] == UNRES_RESOLVED) {
7026 continue;
7027 }
Radek Krejci082c84f2016-10-17 16:33:06 +02007028 assert(!(options & LYD_OPT_TRUSTED) || ((unres->type[i] != UNRES_MUST) && (unres->type[i] != UNRES_MUST_INOUT)));
Radek Krejci010e54b2016-03-15 09:40:34 +01007029
Radek Krejci48464ed2016-03-17 15:44:09 +01007030 rc = resolve_unres_data_item(unres->node[i], unres->type[i]);
Michal Vasko6df94132016-09-22 11:08:09 +02007031 if (rc == -1) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007032 ly_vlog_hide(0);
Michal Vasko96b846c2016-05-18 13:28:58 +02007033 /* print only this last error */
7034 resolve_unres_data_item(unres->node[i], unres->type[i]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007035 return -1;
Radek Krejci082c84f2016-10-17 16:33:06 +02007036 } 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 +02007037 unres->type[i] = UNRES_RESOLVED;
7038 resolved++;
Radek Krejci082c84f2016-10-17 16:33:06 +02007039 if (options & LYD_OPT_TRUSTED) {
Michal Vasko6df94132016-09-22 11:08:09 +02007040 /* accept it in this case */
7041 if (unres->type[i] == UNRES_LEAFREF) {
7042 LOGVRB("Leafref \"%s\" with value \"%s\" failed to be resolved.",
7043 ((struct lys_node_leaf *)unres->node[i]->schema)->type.info.lref.path,
7044 ((struct lyd_node_leaf_list *)unres->node[i])->value_str);
7045 } else {
7046 LOGVRB("Instance identifier \"%s\" failed to be resolved.",
7047 ((struct lyd_node_leaf_list *)unres->node[i])->value_str);
7048 }
7049 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007050 }
7051 }
7052
Radek Krejci010e54b2016-03-15 09:40:34 +01007053 ly_vlog_hide(0);
7054 if (resolved < unres->count) {
7055 /* try to resolve the unresolved data again, it will not resolve anything, but it will print
7056 * all the validation errors
7057 */
7058 for (i = 0; i < unres->count; ++i) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02007059 if (unres->type[i] == UNRES_UNION) {
7060 /* does not make sense to print specific errors for all
7061 * the data types, just print that the value is invalid */
7062 leaf = (struct lyd_node_leaf_list *)unres->node[i];
7063 LOGVAL(LYE_INVAL, LY_VLOG_LYD, unres->node[i], (leaf->value_str ? leaf->value_str : ""),
7064 leaf->schema->name);
7065 } else if (unres->type[i] != UNRES_RESOLVED) {
7066 resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01007067 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007068 }
7069 return -1;
7070 }
7071
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02007072 LOGVRB("All data nodes and constraints resolved.");
Radek Krejci010e54b2016-03-15 09:40:34 +01007073 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007074 return EXIT_SUCCESS;
7075}